diff --git a/config/config.go b/config/config.go index 092884c..2c74c4a 100644 --- a/config/config.go +++ b/config/config.go @@ -15,18 +15,25 @@ type Config struct { S3 struct { Bucket string } + + FileStorage struct { + Directory string + } } // Load parses arguments / ENV variable to load configuration func Load() *Config { cfg := &Config{} - pflag.StringVar(&cfg.Storage, "storage", "s3", "Storage engine to use") + pflag.StringVar(&cfg.Storage, "storage", "s3", "Storage engine to use (s3, file)") pflag.StringVar(&cfg.BaseURL, "baseurl", os.Getenv("BASE_URL"), "The Base-URL the application is running on for example https://mondash.org") pflag.StringVar(&cfg.APIToken, "api-token", os.Getenv("API_TOKEN"), "API Token used for the /welcome dashboard (you can choose your own)") // S3 pflag.StringVar(&cfg.S3.Bucket, "s3Bucket", os.Getenv("S3Bucket"), "Bucket to use for S3 storage") + // FileStorage + pflag.StringVar(&cfg.FileStorage.Directory, "fileDirectory", "./", "Directory to use for plain text storage") + pflag.Parse() return cfg } diff --git a/storage/adapter.go b/storage/adapter.go index e55c0e5..fe5ac54 100644 --- a/storage/adapter.go +++ b/storage/adapter.go @@ -14,23 +14,34 @@ type Storage interface { Exists(dashboardID string) (bool, error) } -// NotFoundError is a named error for more simple determination which +// AdapterNotFoundError is a named error for more simple determination which // type of error is thrown -type NotFoundError struct { +type AdapterNotFoundError struct { Name string } -func (e NotFoundError) Error() string { +func (e AdapterNotFoundError) Error() string { return fmt.Sprintf("Storage '%s' not found.", e.Name) } +// DashboardNotFoundError signalizes the requested dashboard could not be found +type DashboardNotFoundError struct { + DashboardID string +} + +func (e DashboardNotFoundError) Error() string { + return fmt.Sprintf("Dashboard with ID '%s' was not found.", e.DashboardID) +} + // GetStorage acts as a storage factory providing the storage named by input // name parameter func GetStorage(cfg *config.Config) (Storage, error) { switch cfg.Storage { case "s3": return NewS3Storage(cfg), nil + case "file": + return NewFileStorage(cfg), nil } - return nil, NotFoundError{cfg.Storage} + return nil, AdapterNotFoundError{cfg.Storage} } diff --git a/storage/file.go b/storage/file.go new file mode 100644 index 0000000..b1dfe2a --- /dev/null +++ b/storage/file.go @@ -0,0 +1,74 @@ +package storage // import "github.com/Luzifer/mondash/storage" + +import ( + "fmt" + "io/ioutil" + "os" + "path" + + "github.com/Luzifer/mondash/config" +) + +// FileStorage is a storage adapter storing the data into single local files +type FileStorage struct { + cfg *config.Config +} + +// NewFileStorage instanciates a new FileStorage +func NewFileStorage(cfg *config.Config) *FileStorage { + // Create directory if not exists + if _, err := os.Stat(cfg.FileStorage.Directory); os.IsNotExist(err) { + if err := os.MkdirAll(cfg.FileStorage.Directory, 0700); err != nil { + fmt.Printf("Could not create storage directory '%s'", cfg.FileStorage.Directory) + os.Exit(1) + } + } + + return &FileStorage{ + cfg: cfg, + } +} + +// Put writes the given data to FS +func (f *FileStorage) Put(dashboardID string, data []byte) error { + err := ioutil.WriteFile(f.getFilePath(dashboardID), data, 0600) + + return err +} + +// Get loads the data for the given dashboard from FS +func (f *FileStorage) Get(dashboardID string) ([]byte, error) { + data, err := ioutil.ReadFile(f.getFilePath(dashboardID)) + if err != nil { + return nil, DashboardNotFoundError{dashboardID} + } + + return data, nil +} + +// Delete deletes the given dashboard from FS +func (f *FileStorage) Delete(dashboardID string) error { + if exists, err := f.Exists(dashboardID); err != nil || !exists { + if err != nil { + return err + } + return DashboardNotFoundError{dashboardID} + } + + return os.Remove(f.getFilePath(dashboardID)) +} + +// Exists checks for the existence of the given dashboard +func (f *FileStorage) Exists(dashboardID string) (bool, error) { + if _, err := os.Stat(f.getFilePath(dashboardID)); err != nil { + if os.IsNotExist(err) { + return false, nil + } + return false, err + } + return true, nil +} + +func (f *FileStorage) getFilePath(dashboardID string) string { + return path.Join(f.cfg.FileStorage.Directory, dashboardID+".txt") +}