117 lines
2.7 KiB
Go
117 lines
2.7 KiB
Go
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
|
|
}
|