From 2d94f956a1c68882e9c2222c01bac6bf426026a7 Mon Sep 17 00:00:00 2001 From: bel Date: Sun, 29 Dec 2019 14:22:49 -0700 Subject: [PATCH] add rclone --- db_test.go | 17 ++++++++ rclone.go | 118 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 135 insertions(+) create mode 100755 rclone.go diff --git a/db_test.go b/db_test.go index 6f1a49d..964d3b1 100755 --- a/db_test.go +++ b/db_test.go @@ -156,6 +156,23 @@ func TestImplementations(t *testing.T) { t.Log("$MINIO not set. Skipping") } + f, err := ioutil.TempFile(os.TempDir(), "rclone.conf.*") + if err != nil { + t.Fatal(err) + } + defer os.Remove(f.Name()) + f.Write([]byte(` +[local] +type = local + `)) + f.Close() + rclone, err := NewRClone(f.Name(), "local:/tmp") + if err != nil { + t.Errorf("cannot make rclone: %v", err) + } else { + cases = append(cases, rclone) + } + validKey := "key" validValue := []byte("value") diff --git a/rclone.go b/rclone.go new file mode 100755 index 0000000..e9a5206 --- /dev/null +++ b/rclone.go @@ -0,0 +1,118 @@ +package storage + +import ( + "bytes" + "io/ioutil" + "os" + "path" + "time" + + "github.com/ncw/rclone/fs" + "github.com/ncw/rclone/fs/config" + "github.com/ncw/rclone/fs/object" + + _ "github.com/ncw/rclone/backend/drive" + _ "github.com/ncw/rclone/backend/local" + _ "github.com/ncw/rclone/backend/s3" +) + +type RClone struct { + ns string +} + +func NewRClone(rclone string, ns ...string) (*RClone, error) { + namespace := path.Join(ns...) + _, err := os.Stat(rclone) + if err == nil { + os.Setenv("RCLONE_CONFIG", rclone) + config.ConfigPath = rclone + config.LoadConfig() + } + return &RClone{ + ns: namespace, + }, err +} + +func (rc *RClone) Get(key string, ns ...string) ([]byte, error) { + namespace := resolveNamespace(ns) + namespace = path.Join(rc.ns, namespace) + key = path.Join(namespace, key) + f, err := fs.NewFs(path.Dir(key)) + if err != nil { + return nil, err + } + obj, err := f.NewObject(path.Base(key)) + if err != nil { + return nil, err + } + r, err := obj.Open() + if err != nil { + return nil, err + } + return ioutil.ReadAll(r) +} + +func (rc *RClone) Set(key string, value []byte, ns ...string) error { + if len(value) == 0 { + return rc.Del(key, ns...) + } + namespace := resolveNamespace(ns) + namespace = path.Join(rc.ns, namespace) + key = path.Join(namespace, key) + f, err := fs.NewFs(path.Dir(key)) + if err != nil { + return err + } + obj := object.NewStaticObjectInfo(path.Base(key), time.Now(), 0, true, nil, f) + _, err = f.Put(bytes.NewReader(value), obj) + return err +} + +func (rc *RClone) Del(key string, ns ...string) error { + namespace := resolveNamespace(ns) + namespace = path.Join(rc.ns, namespace) + key = path.Join(namespace, key) + f, err := fs.NewFs(path.Dir(key)) + if err != nil { + return err + } + obj, err := f.NewObject(path.Base(key)) + if err == fs.ErrorObjectNotFound { + return nil + } + if err != nil { + return nil + } + return obj.Remove() +} + +func (rc *RClone) Close() error { + return nil +} + +func (rc *RClone) List(ns []string, limits ...string) ([]string, error) { + namespace := path.Join(resolveNamespace(ns)) + namespace = path.Join(rc.ns, namespace) + limits = resolveLimits(limits) + + f, err := fs.NewFs(namespace) + if err != nil { + return nil, err + } + entries, err := f.List("") + if err != nil { + return nil, err + } + names := make([]string, 0) + for _, entry := range entries { + name := entry.Remote() + if rc.inRange(name, limits[0], limits[1]) { + names = append(names, name) + } + } + return names, nil +} + +func (rc *RClone) inRange(k, start, stop string) bool { + return k != "" && k >= start && k <= stop +}