2022-01-20 02:40:32 +00:00
|
|
|
package files
|
2022-01-19 00:03:24 +00:00
|
|
|
|
|
|
|
import (
|
|
|
|
"encoding/json"
|
|
|
|
"fmt"
|
|
|
|
"io"
|
|
|
|
"os"
|
|
|
|
"path/filepath"
|
|
|
|
)
|
|
|
|
|
|
|
|
type FSFileStore struct {
|
|
|
|
dir string
|
|
|
|
metadata map[string]*File
|
|
|
|
}
|
|
|
|
|
|
|
|
func NewFSFileStore(dir string) (*FSFileStore, error) {
|
|
|
|
s := &FSFileStore{
|
|
|
|
dir: dir,
|
|
|
|
metadata: make(map[string]*File),
|
|
|
|
}
|
|
|
|
|
|
|
|
err := s.readMetadata()
|
|
|
|
|
|
|
|
return s, err
|
|
|
|
}
|
|
|
|
func (s *FSFileStore) Store(f *File) error {
|
|
|
|
defer f.Body.Close()
|
|
|
|
|
|
|
|
metadata := &File{
|
|
|
|
ID: f.ID,
|
|
|
|
OriginalFilename: f.OriginalFilename,
|
|
|
|
MaxViews: f.MaxViews,
|
|
|
|
ExpiresOn: f.ExpiresOn,
|
|
|
|
}
|
|
|
|
|
|
|
|
path := filepath.Join(s.dir, f.ID)
|
2022-01-24 19:25:52 +00:00
|
|
|
|
2022-01-19 00:03:24 +00:00
|
|
|
dst, err := os.Create(path)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
defer dst.Close()
|
|
|
|
|
2022-01-24 14:52:15 +00:00
|
|
|
n, err := io.Copy(dst, f.Body)
|
|
|
|
if err != nil {
|
2022-01-19 00:03:24 +00:00
|
|
|
return err
|
|
|
|
}
|
2022-01-24 19:25:52 +00:00
|
|
|
|
2022-01-19 00:03:24 +00:00
|
|
|
s.metadata[f.ID] = metadata
|
2022-01-24 14:52:15 +00:00
|
|
|
s.metadata[f.ID].FileSize = n
|
2022-01-24 19:25:52 +00:00
|
|
|
|
2022-01-19 00:03:24 +00:00
|
|
|
if err := s.writeMetadata(); err != nil {
|
|
|
|
delete(s.metadata, f.ID)
|
|
|
|
return err
|
|
|
|
}
|
2022-01-24 19:25:52 +00:00
|
|
|
|
2022-01-19 00:03:24 +00:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *FSFileStore) Get(id string) (*File, error) {
|
|
|
|
metadata, ok := s.metadata[id]
|
|
|
|
if !ok {
|
|
|
|
return nil, fmt.Errorf("no such item")
|
|
|
|
}
|
|
|
|
|
|
|
|
path := filepath.Join(s.dir, id)
|
2022-01-24 19:25:52 +00:00
|
|
|
|
2022-01-19 00:03:24 +00:00
|
|
|
f, err := os.Open(path)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2022-01-24 19:25:52 +00:00
|
|
|
|
2022-01-19 00:03:24 +00:00
|
|
|
metadata.Body = f
|
2022-01-24 19:25:52 +00:00
|
|
|
|
2022-01-19 00:03:24 +00:00
|
|
|
return metadata, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *FSFileStore) Delete(id string) error {
|
|
|
|
path := filepath.Join(s.dir, id)
|
|
|
|
if err := os.Remove(path); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2022-01-24 19:25:52 +00:00
|
|
|
|
2022-01-19 00:03:24 +00:00
|
|
|
delete(s.metadata, id)
|
2022-01-24 19:25:52 +00:00
|
|
|
|
2022-01-19 00:03:24 +00:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *FSFileStore) List() ([]string, error) {
|
2022-01-24 19:25:52 +00:00
|
|
|
results := make([]string, 0, len(s.metadata))
|
2022-01-19 00:03:24 +00:00
|
|
|
for k := range s.metadata {
|
|
|
|
results = append(results, k)
|
|
|
|
}
|
2022-01-24 19:25:52 +00:00
|
|
|
|
2022-01-19 00:03:24 +00:00
|
|
|
return results, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *FSFileStore) writeMetadata() error {
|
|
|
|
path := filepath.Join(s.dir, "metadata.json")
|
2022-01-24 19:25:52 +00:00
|
|
|
|
2022-01-19 00:03:24 +00:00
|
|
|
f, err := os.Create(path)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
defer f.Close()
|
|
|
|
|
|
|
|
encoder := json.NewEncoder(f)
|
|
|
|
if err := encoder.Encode(s.metadata); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2022-01-24 19:25:52 +00:00
|
|
|
|
2022-01-19 00:03:24 +00:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *FSFileStore) readMetadata() error {
|
|
|
|
path := filepath.Join(s.dir, "metadata.json")
|
2022-01-24 19:25:52 +00:00
|
|
|
|
2022-01-19 00:03:24 +00:00
|
|
|
f, err := os.Open(path)
|
|
|
|
if err != nil {
|
|
|
|
// TODO: Handle errors better
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
defer f.Close()
|
|
|
|
|
|
|
|
decoder := json.NewDecoder(f)
|
|
|
|
if err := decoder.Decode(&s.metadata); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2022-01-24 19:25:52 +00:00
|
|
|
|
2022-01-19 00:03:24 +00:00
|
|
|
return nil
|
|
|
|
}
|