package storage import ( "bytes" "errors" "io" "io/ioutil" "gitea.inhome.blapointe.com/local/logb" "gitea.inhome.blapointe.com/local/storage/resolve" "os" "path" "path/filepath" "strings" ) const ( fileExt = ".file" ) type Files struct { root string } func NewFiles(root string) (*Files, error) { _, err := os.Stat(path.Dir(root)) if err != nil { return nil, err } root, err = filepath.Abs(root) if err != nil { return nil, err } return &Files{ root: root, }, os.MkdirAll(root, os.ModePerm) } func (b *Files) Namespaces() ([][]string, error) { return nil, errors.New("not impl") } func (b *Files) List(ns []string, limits ...string) ([]string, error) { namespace := resolve.Namespace(ns) limits = resolve.Limits(limits) files := make([]string, 0) err := filepath.Walk(b.root, func(p string, info os.FileInfo, err error) error { if err != nil { return err } if info.IsDir() { return nil } if !strings.HasPrefix(strings.TrimPrefix(p, b.root+"/"), namespace+"/") { return nil } filedir := path.Join(b.root, namespace) file := strings.TrimPrefix(p, filedir+"/") file = strings.TrimSuffix(file, fileExt) if file >= limits[0] && file <= limits[1] { files = append(files, file) } return nil }) return files, err /* */ } func (b *Files) Get(key string, ns ...string) ([]byte, error) { r, err := b.GetStream(key, ns...) if err != nil { return nil, err } return ioutil.ReadAll(r) } func (b *Files) GetStream(key string, ns ...string) (io.Reader, error) { namespace := resolve.Namespace(ns) path := path.Join(b.root, namespace, key) r, err := os.Open(path + fileExt) if os.IsNotExist(err) { logb.Warnf("does not exist: %q + %q from key=%q ns=%v namespace=%q, trying %q instead", path, fileExt, key, ns, namespace, path) r, err = os.Open(path) } if os.IsNotExist(err) { return nil, ErrNotFound } return r, err } func (b *Files) Set(key string, value []byte, ns ...string) error { r := bytes.NewReader(value) if value == nil { return b.Del(key, ns...) } return b.SetStream(key, r, ns...) } func (b *Files) Del(key string, ns ...string) error { namespace := resolve.Namespace(ns) key += fileExt dir := path.Join(b.root, namespace, path.Dir(key)) path := path.Join(dir, path.Base(key)) err := os.Remove(path) if os.IsNotExist(err) { err = nil } return err } func (b *Files) SetStream(key string, r io.Reader, ns ...string) error { namespace := resolve.Namespace(ns) key += fileExt dir := path.Join(b.root, namespace, path.Dir(key)) path := path.Join(dir, path.Base(key)) if r == nil { err := os.Remove(path) if os.IsNotExist(err) { err = nil } return err } if err := os.MkdirAll(dir, os.ModePerm); err != nil { logb.Warnf("failed mkdir: %v", err) return err } f, err := os.Create(path) if err != nil { logb.Warnf("failed create: %v: path=%q, dir=%q, ns=%q", err, path, dir, namespace) return err } defer f.Close() _, err = io.Copy(f, r) if err != nil { logb.Warnf("failed copy: %v", err) return err } return nil } func (b *Files) Close() error { return nil }