// Package database простейшая БД которая позволяет только два действия: // // 1. сохранить некую строку - `Append(string) error` // 2. ответить на вопрос сохранялась ли уже когда либо эта строка - // `Exists(string) bool` // // Нужна для дедупликации публикуемых записей package database import ( "bytes" "fmt" "os" "sync" ) type DB struct { fp *os.File cache map[string]struct{} mu *sync.RWMutex } func New(path string) (*DB, error) { cache, _ := os.ReadFile(path) // Ignore if no DB file fp, err := os.OpenFile(path, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0o644) if err != nil { return nil, fmt.Errorf("failed open db file for write: %w", err) } db := &DB{ fp: fp, cache: map[string]struct{}{}, mu: &sync.RWMutex{}, } for part := range bytes.SplitSeq(cache, []byte("\n")) { db.cache[string(part)] = struct{}{} } return db, nil } func (d *DB) Close() error { return d.fp.Close() } func (d *DB) Exists(s string) bool { d.mu.RLock() defer d.mu.RUnlock() _, ok := d.cache[s] return ok } func (d *DB) Append(s string) error { d.mu.Lock() defer d.mu.Unlock() if d.Exists(s) { return nil } d.cache[s] = struct{}{} _, err := fmt.Fprintln(d.fp, s) return err }