package syncstore import ( "encoding/json" "fmt" "io/ioutil" "os" "path/filepath" ) type FSStore struct { path string } func NewFSStore(path string) (*FSStore, error) { p, err := filepath.Abs(path) if err != nil { return nil, err } err = os.MkdirAll(p, 0700) if err != nil { return nil, err } var s = new(FSStore) s.path = p return s, nil } func (drv *FSStore) storePath(id string) string { return filepath.Join(drv.path, id[0:3], fmt.Sprintf("%s.json", id)) } func (drv *FSStore) RawSave(s *Blob) error { body, err := json.Marshal(s) if err != nil { return err } filename := drv.storePath(s.ID) dirname := filepath.Dir(filename) err = os.Mkdir(dirname, 0700) if err != nil && !os.IsExist(err) { return err } f, err := os.CreateTemp(dirname, "tmp-"+s.ID+".*") if err != nil { return err } tempname := f.Name() _, err = f.Write(body) err2 := f.Close() if err != nil { _ = os.Remove(f.Name()) return err } if err2 != nil { return err2 } return os.Rename(tempname, filename) } func (drv *FSStore) RawLoad(id string) (*Blob, error) { body, err := ioutil.ReadFile(drv.storePath(id)) if err != nil { if os.IsNotExist(err) { return nil, SyncNotFoundError } return nil, err } s := new(Blob) err = json.Unmarshal(body, s) return s, err } func (drv *FSStore) Exists(id string) bool { st, err := os.Stat(drv.storePath(id)) if err != nil { return false } return (!st.IsDir()) && (st.Size() > 0) }