From a4a873974841323354773ed04dace92a8d36af56 Mon Sep 17 00:00:00 2001 From: Noah Hsu Date: Sun, 4 Sep 2022 13:03:10 +0800 Subject: [PATCH] feat: add `upyun-uss` driver --- drivers/all.go | 1 + drivers/s3/meta.go | 5 +- drivers/uss/driver.go | 147 ++++++++++++++++++++++++++++++++++++++++++ drivers/uss/meta.go | 29 +++++++++ drivers/uss/types.go | 1 + drivers/uss/util.go | 13 ++++ go.mod | 1 + go.sum | 2 + 8 files changed, 197 insertions(+), 2 deletions(-) create mode 100644 drivers/uss/driver.go create mode 100644 drivers/uss/meta.go create mode 100644 drivers/uss/types.go create mode 100644 drivers/uss/util.go diff --git a/drivers/all.go b/drivers/all.go index 4d4a39e3e2c..8a91e5828d7 100644 --- a/drivers/all.go +++ b/drivers/all.go @@ -13,6 +13,7 @@ import ( _ "github.com/alist-org/alist/v3/drivers/s3" _ "github.com/alist-org/alist/v3/drivers/sftp" _ "github.com/alist-org/alist/v3/drivers/teambition" + _ "github.com/alist-org/alist/v3/drivers/uss" _ "github.com/alist-org/alist/v3/drivers/virtual" ) diff --git a/drivers/s3/meta.go b/drivers/s3/meta.go index 782d81ec2fb..c483738657d 100644 --- a/drivers/s3/meta.go +++ b/drivers/s3/meta.go @@ -20,8 +20,9 @@ type Addition struct { } var config = driver.Config{ - Name: "S3", - LocalSort: true, + Name: "S3", + LocalSort: true, + CheckStatus: true, } func New() driver.Driver { diff --git a/drivers/uss/driver.go b/drivers/uss/driver.go new file mode 100644 index 00000000000..e5fe406329c --- /dev/null +++ b/drivers/uss/driver.go @@ -0,0 +1,147 @@ +package uss + +import ( + "context" + "fmt" + "net/url" + "path" + "strings" + "time" + + "github.com/alist-org/alist/v3/internal/driver" + "github.com/alist-org/alist/v3/internal/errs" + "github.com/alist-org/alist/v3/internal/model" + "github.com/alist-org/alist/v3/pkg/utils" + "github.com/upyun/go-sdk/v3/upyun" +) + +type USS struct { + model.Storage + Addition + client *upyun.UpYun +} + +func (d *USS) Config() driver.Config { + return config +} + +func (d *USS) GetAddition() driver.Additional { + return d.Addition +} + +func (d *USS) Init(ctx context.Context, storage model.Storage) error { + d.Storage = storage + err := utils.Json.UnmarshalFromString(d.Storage.Addition, &d.Addition) + if err != nil { + return err + } + d.client = upyun.NewUpYun(&upyun.UpYunConfig{ + Bucket: d.Bucket, + Operator: d.OperatorName, + Password: d.OperatorPassword, + }) + return nil +} + +func (d *USS) Drop(ctx context.Context) error { + return nil +} + +func (d *USS) List(ctx context.Context, dir model.Obj, args model.ListArgs) ([]model.Obj, error) { + prefix := getKey(dir.GetPath(), true) + objsChan := make(chan *upyun.FileInfo, 10) + var err error + defer close(objsChan) + go func() { + err = d.client.List(&upyun.GetObjectsConfig{ + Path: prefix, + ObjectsChan: objsChan, + MaxListObjects: 0, + MaxListLevel: 1, + }) + }() + if err != nil { + return nil, err + } + res := make([]model.Obj, 0) + for obj := range objsChan { + t := obj.Time + f := model.Object{ + Name: obj.Name, + Size: obj.Size, + Modified: t, + IsFolder: obj.IsDir, + } + res = append(res, &f) + } + return res, err +} + +//func (d *USS) Get(ctx context.Context, path string) (model.Obj, error) { +// // this is optional +// return nil, errs.NotImplement +//} + +func (d *USS) Link(ctx context.Context, file model.Obj, args model.LinkArgs) (*model.Link, error) { + key := getKey(file.GetPath(), false) + host := d.CustomHost + if host == "" { + host = d.Endpoint + } + if strings.Contains(host, "://") { + host = "https://" + host + } + u := fmt.Sprintf("%s/%s", host, key) + downExp := time.Hour * time.Duration(d.SignURLExpire) + expireAt := time.Now().Add(downExp).Unix() + upd := url.QueryEscape(path.Base(file.GetPath())) + signStr := strings.Join([]string{d.OperatorPassword, fmt.Sprint(expireAt), fmt.Sprintf("/%s", key)}, "&") + upt := utils.GetMD5Encode(signStr)[12:20] + fmt.Sprint(expireAt) + link := fmt.Sprintf("%s?_upd=%s&_upt=%s", u, upd, upt) + return &model.Link{URL: link}, nil +} + +func (d *USS) MakeDir(ctx context.Context, parentDir model.Obj, dirName string) error { + return d.client.Mkdir(getKey(path.Join(parentDir.GetPath(), dirName), true)) +} + +func (d *USS) Move(ctx context.Context, srcObj, dstDir model.Obj) error { + return d.client.Move(&upyun.MoveObjectConfig{ + SrcPath: getKey(srcObj.GetPath(), srcObj.IsDir()), + DestPath: getKey(path.Join(dstDir.GetPath(), srcObj.GetName()), srcObj.IsDir()), + }) +} + +func (d *USS) Rename(ctx context.Context, srcObj model.Obj, newName string) error { + return d.client.Move(&upyun.MoveObjectConfig{ + SrcPath: getKey(srcObj.GetPath(), srcObj.IsDir()), + DestPath: getKey(path.Join(path.Dir(srcObj.GetPath()), newName), srcObj.IsDir()), + }) +} + +func (d *USS) Copy(ctx context.Context, srcObj, dstDir model.Obj) error { + return d.client.Copy(&upyun.CopyObjectConfig{ + SrcPath: getKey(srcObj.GetPath(), srcObj.IsDir()), + DestPath: getKey(path.Join(dstDir.GetPath(), srcObj.GetName()), srcObj.IsDir()), + }) +} + +func (d *USS) Remove(ctx context.Context, obj model.Obj) error { + return d.client.Delete(&upyun.DeleteObjectConfig{ + Path: getKey(obj.GetPath(), obj.IsDir()), + Async: false, + }) +} + +func (d *USS) Put(ctx context.Context, dstDir model.Obj, stream model.FileStreamer, up driver.UpdateProgress) error { + return d.client.Put(&upyun.PutObjectConfig{ + Path: getKey(path.Join(dstDir.GetPath(), stream.GetName()), false), + Reader: stream, + }) +} + +func (d *USS) Other(ctx context.Context, args model.OtherArgs) (interface{}, error) { + return nil, errs.NotSupport +} + +var _ driver.Driver = (*USS)(nil) diff --git a/drivers/uss/meta.go b/drivers/uss/meta.go new file mode 100644 index 00000000000..4108c814a3a --- /dev/null +++ b/drivers/uss/meta.go @@ -0,0 +1,29 @@ +package uss + +import ( + "github.com/alist-org/alist/v3/internal/driver" + "github.com/alist-org/alist/v3/internal/op" +) + +type Addition struct { + driver.RootFolderPath + Bucket string `json:"bucket" required:"true"` + Endpoint string `json:"endpoint" required:"true"` + OperatorName string `json:"operator_name" required:"true"` + OperatorPassword string `json:"operator_password" required:"true"` + CustomHost string `json:"custom_host"` + SignURLExpire int `json:"sign_url_expire" type:"number" default:"4"` +} + +var config = driver.Config{ + Name: "USS", + LocalSort: true, +} + +func New() driver.Driver { + return &USS{} +} + +func init() { + op.RegisterDriver(config, New) +} diff --git a/drivers/uss/types.go b/drivers/uss/types.go new file mode 100644 index 00000000000..169aaba047c --- /dev/null +++ b/drivers/uss/types.go @@ -0,0 +1 @@ +package uss diff --git a/drivers/uss/util.go b/drivers/uss/util.go new file mode 100644 index 00000000000..8b57a0b04a0 --- /dev/null +++ b/drivers/uss/util.go @@ -0,0 +1,13 @@ +package uss + +import "strings" + +// do others that not defined in Driver interface + +func getKey(path string, dir bool) string { + path = strings.TrimPrefix(path, "/") + if dir { + path += "/" + } + return path +} diff --git a/go.mod b/go.mod index 8abb7577f0d..a036a98fa73 100644 --- a/go.mod +++ b/go.mod @@ -59,6 +59,7 @@ require ( github.com/pkg/sftp v1.13.5 // indirect github.com/spf13/pflag v1.0.5 // indirect github.com/ugorji/go/codec v1.2.7 // indirect + github.com/upyun/go-sdk/v3 v3.0.3 // indirect golang.org/x/crypto v0.0.0-20220829220503-c86fa9a7ed90 // indirect golang.org/x/image v0.0.0-20220722155232-062f8c9fd539 // indirect golang.org/x/net v0.0.0-20220826154423-83b083e8dc8b // indirect diff --git a/go.sum b/go.sum index 810bc50747c..f0cdaf37335 100644 --- a/go.sum +++ b/go.sum @@ -219,6 +219,8 @@ github.com/ugorji/go v1.2.7/go.mod h1:nF9osbDWLy6bDVv/Rtoh6QgnvNDpmCalQV5urGCCS6 github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY= github.com/ugorji/go/codec v1.2.7 h1:YPXUKf7fYbp/y8xloBqZOw2qaVggbfwMlI8WM3wZUJ0= github.com/ugorji/go/codec v1.2.7/go.mod h1:WGN1fab3R1fzQlVQTkfxVtIBhWDRqOviHU95kRgeqEY= +github.com/upyun/go-sdk/v3 v3.0.3 h1:2wUkNk2fyJReMYHMvJyav050D83rYwSjN7mEPR0Pp8Q= +github.com/upyun/go-sdk/v3 v3.0.3/go.mod h1:P/SnuuwhrIgAVRd/ZpzDWqCsBAf/oHg7UggbAxyZa0E= github.com/winfsp/cgofuse v1.5.0 h1:MsBP7Mi/LiJf/7/F3O/7HjjR009ds6KCdqXzKpZSWxI= github.com/winfsp/cgofuse v1.5.0/go.mod h1:h3awhoUOcn2VYVKCwDaYxSLlZwnyK+A8KaDoLUp2lbU= github.com/zenazn/goji v0.9.0/go.mod h1:7S9M489iMyHBNxwZnk9/EHS098H4/F6TATF2mIxtB1Q=