package storage import ( "errors" "io/ioutil" "os" "path/filepath" "strings" "sync" "git.eeqj.de/sneak/feta/toot" ) // TootStorageBackend is the interface to which storage backends must // conform for storing toots type TootStorageBackend interface { TootExists(t toot.Toot) bool StoreToot(t toot.Toot) error StoreToots(tc []*toot.Toot) error } type TootDBStorage struct { db string } // TootFSStorage is a TootStorageBackend that writes to the local // filesystem. type TootFSStorage struct { root string } // NewTootFSStorage returns a *TootFSStorage for writing toots to the // local filesystem func NewTootFSStorage(root string) *TootFSStorage { ts := new(TootFSStorage) ts.root = root return ts } // StoreToots writes a slice of pointers to toots to disk func (ts *TootFSStorage) StoreToots(tc []*toot.Toot) error { var returnErrors []string for _, item := range tc { err := ts.StoreToot(*item) if err != nil { returnErrors = append(returnErrors, err.Error()) continue } } if len(returnErrors) == 0 { return nil } return errors.New(strings.Join(returnErrors, "; ")) } // TootExists checks to see if we have already written a toot to disk or // not. Note that the ingester de-dupes with a table in memory so that this // will only really get used on app restarts func (ts *TootFSStorage) TootExists(t toot.Toot) bool { path := t.DiskStoragePath() full := ts.root + "/" + path _, err := os.Stat(full) if os.IsNotExist(err) { return false } return true } // StoreToot writes a single toot to disk func (ts *TootFSStorage) StoreToot(t toot.Toot) error { path := t.DiskStoragePath() full := ts.root + "/" + path dir := filepath.Dir(full) err := os.MkdirAll(dir, 0755) if err != nil { return err } return ioutil.WriteFile(full, t.Original, 0644) } // TootMemoryStorage is a TootStorageBackend that just stores all ingested // toots in ram forever until the computer fills up and catches fire and explodes type TootMemoryStorage struct { sync.Mutex toots map[toot.Hash]toot.Toot //maxSize uint // FIXME support eviction } // NewTootMemoryStorage returns a *TootMemoryStorage for storing toots in // ram forever func NewTootMemoryStorage() *TootMemoryStorage { ts := new(TootMemoryStorage) ts.toots = make(map[toot.Hash]toot.Toot) return ts } // StoreToot saves a single toot into an in-memory hashtable func (ts *TootMemoryStorage) StoreToot(t toot.Toot) { if ts.TootExists(t) { return } ts.Lock() defer ts.Unlock() ts.toots[t.Hash] = t return } // TootExists checks to see if we have a toot in memory already func (ts *TootMemoryStorage) TootExists(t toot.Toot) bool { ts.Lock() defer ts.Unlock() if _, ok := ts.toots[t.Hash]; ok { //this syntax is so gross return true } return false }