package gpaste 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) dst, err := os.Create(path) if err != nil { return err } defer dst.Close() if _, err := io.Copy(dst, f.Body); err != nil { return err } s.metadata[f.ID] = metadata if err := s.writeMetadata(); err != nil { delete(s.metadata, f.ID) return err } 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) f, err := os.Open(path) if err != nil { return nil, err } metadata.Body = f 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 } delete(s.metadata, id) return nil } func (s *FSFileStore) List() ([]string, error) { var results []string for k := range s.metadata { results = append(results, k) } return results, nil } func (s *FSFileStore) writeMetadata() error { path := filepath.Join(s.dir, "metadata.json") 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 } return nil } func (s *FSFileStore) readMetadata() error { path := filepath.Join(s.dir, "metadata.json") 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 } return nil }