diff options
| author | 2021-04-19 19:42:19 +0200 | |
|---|---|---|
| committer | 2021-04-19 19:42:19 +0200 | |
| commit | 32c5fd987a06e11b14a4247d13187657c14adedd (patch) | |
| tree | f5b787ca0f020bea5fd020925e52d3592a77a6ad /internal/storage | |
| parent | Api/v1/accounts (#8) (diff) | |
| download | gotosocial-32c5fd987a06e11b14a4247d13187657c14adedd.tar.xz | |
Api/v1/statuses (#11)
This PR adds:
Statuses
    New status creation.
    View existing status
    Delete a status
    Fave a status
    Unfave a status
    See who's faved a status
Media
    Upload media attachment and store/retrieve it
    Upload custom emoji and store/retrieve it
Fileserver
    Serve files from storage
Testing
    Test models, testrig -- run a GTS test instance and play around with it.
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  } | 
