diff options
Diffstat (limited to 'internal/storage')
-rw-r--r-- | internal/storage/inmem.go | 24 | ||||
-rw-r--r-- | internal/storage/local.go | 53 | ||||
-rw-r--r-- | internal/storage/mock_Storage.go | 37 | ||||
-rw-r--r-- | internal/storage/storage.go | 6 |
4 files changed, 118 insertions, 2 deletions
diff --git a/internal/storage/inmem.go b/internal/storage/inmem.go index 25432fbaa..2d88189db 100644 --- a/internal/storage/inmem.go +++ b/internal/storage/inmem.go @@ -7,25 +7,49 @@ import ( "github.com/superseriousbusiness/gotosocial/internal/config" ) +// NewInMem returns an in-memory implementation of the Storage interface. +// This is good for testing and whatnot but ***SHOULD ABSOLUTELY NOT EVER +// BE USED IN A PRODUCTION SETTING***, because A) everything will be wiped out +// if you restart the server and B) if you store lots of images your RAM use +// will absolutely go through the roof. func NewInMem(c *config.Config, log *logrus.Logger) (Storage, error) { return &inMemStorage{ stored: make(map[string][]byte), + log: log, }, nil } type inMemStorage struct { stored map[string][]byte + log *logrus.Logger } func (s *inMemStorage) StoreFileAt(path string, data []byte) error { + l := s.log.WithField("func", "StoreFileAt") + l.Debugf("storing at path %s", path) s.stored[path] = data return nil } func (s *inMemStorage) RetrieveFileFrom(path string) ([]byte, error) { + l := s.log.WithField("func", "RetrieveFileFrom") + l.Debugf("retrieving from path %s", path) d, ok := s.stored[path] if !ok { return nil, fmt.Errorf("no data found at path %s", path) } return d, nil } + +func (s *inMemStorage) ListKeys() ([]string, error) { + keys := []string{} + for k := range s.stored { + keys = append(keys, k) + } + return keys, nil +} + +func (s *inMemStorage) RemoveFileAt(path string) error { + delete(s.stored, path) + return nil +} diff --git a/internal/storage/local.go b/internal/storage/local.go index 29461d5d4..3b64524f6 100644 --- a/internal/storage/local.go +++ b/internal/storage/local.go @@ -1,21 +1,70 @@ package storage import ( + "fmt" + "os" + "path/filepath" + "strings" + "github.com/sirupsen/logrus" "github.com/superseriousbusiness/gotosocial/internal/config" ) +// NewLocal returns an implementation of the Storage interface that uses +// the local filesystem for storing and retrieving files, attachments, etc. func NewLocal(c *config.Config, log *logrus.Logger) (Storage, error) { - return &localStorage{}, nil + return &localStorage{ + config: c, + log: log, + }, nil } type localStorage struct { + config *config.Config + log *logrus.Logger } func (s *localStorage) StoreFileAt(path string, data []byte) error { + l := s.log.WithField("func", "StoreFileAt") + l.Debugf("storing at path %s", path) + components := strings.Split(path, "/") + dir := strings.Join(components[0:len(components)-1], "/") + if err := os.MkdirAll(dir, 0777); err != nil { + return fmt.Errorf("error writing file at %s: %s", path, err) + } + if err := os.WriteFile(path, data, 0777); err != nil { + return fmt.Errorf("error writing file at %s: %s", path, err) + } return nil } func (s *localStorage) RetrieveFileFrom(path string) ([]byte, error) { - return nil, nil + l := s.log.WithField("func", "RetrieveFileFrom") + l.Debugf("retrieving from path %s", path) + b, err := os.ReadFile(path) + if err != nil { + return nil, fmt.Errorf("error reading file at %s: %s", path, err) + } + return b, nil +} + +func (s *localStorage) ListKeys() ([]string, error) { + keys := []string{} + err := filepath.Walk(s.config.StorageConfig.BasePath, func(path string, info os.FileInfo, err error) error { + if err != nil { + return err + } + if !info.IsDir() { + keys = append(keys, path) + } + return nil + }) + if err != nil { + return nil, err + } + return keys, nil +} + +func (s *localStorage) RemoveFileAt(path string) error { + return os.Remove(path) } diff --git a/internal/storage/mock_Storage.go b/internal/storage/mock_Storage.go index 865d52205..2444f030a 100644 --- a/internal/storage/mock_Storage.go +++ b/internal/storage/mock_Storage.go @@ -9,6 +9,43 @@ type MockStorage struct { mock.Mock } +// ListKeys provides a mock function with given fields: +func (_m *MockStorage) ListKeys() ([]string, error) { + ret := _m.Called() + + var r0 []string + if rf, ok := ret.Get(0).(func() []string); ok { + r0 = rf() + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).([]string) + } + } + + var r1 error + if rf, ok := ret.Get(1).(func() error); ok { + r1 = rf() + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// RemoveFileAt provides a mock function with given fields: path +func (_m *MockStorage) RemoveFileAt(path string) error { + ret := _m.Called(path) + + var r0 error + if rf, ok := ret.Get(0).(func(string) error); ok { + r0 = rf(path) + } else { + r0 = ret.Error(0) + } + + return r0 +} + // RetrieveFileFrom provides a mock function with given fields: path func (_m *MockStorage) RetrieveFileFrom(path string) ([]byte, error) { ret := _m.Called(path) diff --git a/internal/storage/storage.go b/internal/storage/storage.go index fa884ed07..409c90b37 100644 --- a/internal/storage/storage.go +++ b/internal/storage/storage.go @@ -16,9 +16,15 @@ along with this program. If not, see <http://www.gnu.org/licenses/>. */ +// Package storage contains an interface and implementations for storing and retrieving files and attachments. package storage +// Storage is an interface for storing and retrieving blobs +// such as images, videos, and any other attachments/documents +// that shouldn't be stored in a database. type Storage interface { StoreFileAt(path string, data []byte) error RetrieveFileFrom(path string) ([]byte, error) + ListKeys() ([]string, error) + RemoveFileAt(path string) error } |