From 0a50fbd08002685b15efe3a852a92a3475c2d100 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BE=AE=E5=87=89?= <927625802@qq.com> Date: Thu, 28 Oct 2021 22:50:09 +0800 Subject: [PATCH] :sparkles: ali path and link --- bootstrap/cache.go | 12 ++-- bootstrap/model.go | 4 +- drivers/alidrive.go | 156 ++++++++++++++++++++++++++++++++++++++------ go.mod | 6 +- go.sum | 2 - main.go | 3 +- main_test.go | 12 ++++ model/account.go | 2 +- model/meta.go | 12 ++++ server/common.go | 2 +- server/down.go | 14 +++- server/path.go | 14 +++- utils/file.go | 9 +++ 13 files changed, 207 insertions(+), 41 deletions(-) create mode 100644 main_test.go diff --git a/bootstrap/cache.go b/bootstrap/cache.go index 380a6911..2ea7efd6 100644 --- a/bootstrap/cache.go +++ b/bootstrap/cache.go @@ -2,9 +2,9 @@ package bootstrap import ( "github.com/Xhofe/alist/conf" - "github.com/allegro/bigcache/v3" "github.com/eko/gocache/v2/cache" "github.com/eko/gocache/v2/store" + goCache "github.com/patrickmn/go-cache" log "github.com/sirupsen/logrus" "time" ) @@ -12,9 +12,7 @@ import ( // InitCache init cache func InitCache() { log.Infof("init cache...") - bigCacheConfig := bigcache.DefaultConfig(60 * time.Minute) - bigCacheConfig.HardMaxCacheSize = 512 - bigCacheClient, _ := bigcache.NewBigCache(bigCacheConfig) - bigCacheStore := store.NewBigcache(bigCacheClient, nil) - conf.Cache = cache.New(bigCacheStore) -} \ No newline at end of file + goCacheClient := goCache.New(60*time.Minute, 120*time.Minute) + goCacheStore := store.NewGoCache(goCacheClient, nil) + conf.Cache = cache.New(goCacheStore) +} diff --git a/bootstrap/model.go b/bootstrap/model.go index 1addce13..8c93e76e 100644 --- a/bootstrap/model.go +++ b/bootstrap/model.go @@ -67,7 +67,7 @@ func InitModel() { log.Fatalf("not supported database type: %s", config.Type) } log.Infof("auto migrate model") - err := conf.DB.AutoMigrate(&model.SettingItem{}, &model.Account{}) + err := conf.DB.AutoMigrate(&model.SettingItem{}, &model.Account{},&model.Meta{}) if err != nil { log.Fatalf("failed to auto migrate") } @@ -87,7 +87,7 @@ func initAccounts() { model.RegisterAccount(account) driver, ok := drivers.GetDriver(account.Type) if !ok { - log.Error("no [%s] driver", driver) + log.Errorf("no [%s] driver", driver) } else { err := driver.Save(&account, nil) if err != nil { diff --git a/drivers/alidrive.go b/drivers/alidrive.go index 0814a316..6681eb93 100644 --- a/drivers/alidrive.go +++ b/drivers/alidrive.go @@ -8,6 +8,7 @@ import ( "github.com/go-resty/resty/v2" "github.com/robfig/cron/v3" log "github.com/sirupsen/logrus" + "path/filepath" "time" ) @@ -29,17 +30,23 @@ type AliRespError struct { Message string `json:"message"` } +type AliFiles struct { + Items []AliFile `json:"items"` + NextMarker string `json:"next_marker"` +} + type AliFile struct { - DriveId string `json:"drive_id"` - CreatedAt *time.Time `json:"created_at"` - FileExtension string `json:"file_extension"` - FileId string `json:"file_id"` - Name string `json:"name"` - ParentFileId string `json:"parent_file_id"` - UpdatedAt *time.Time `json:"updated_at"` - Size int64 `json:"size"` - //Thumbnail string `json:"thumbnail"` - Url string `json:"url"` + DriveId string `json:"drive_id"` + CreatedAt *time.Time `json:"created_at"` + FileExtension string `json:"file_extension"` + FileId string `json:"file_id"` + Type string `json:"type"` + Name string `json:"name"` + ParentFileId string `json:"parent_file_id"` + UpdatedAt *time.Time `json:"updated_at"` + Size int64 `json:"size"` + Thumbnail string `json:"thumbnail"` + Url string `json:"url"` } func AliToFile(file AliFile) *model.File { @@ -51,31 +58,135 @@ func AliToFile(file AliFile) *model.File { } } +func (a AliDrive) GetFiles(fileId string, account *model.Account) ([]AliFile, error) { + marker := "first" + res := make([]AliFile, 0) + for marker != "" { + if marker == "first" { + marker = "" + } + var resp AliFiles + var e AliRespError + _, err := aliClient.R(). + SetResult(&resp). + SetError(&e). + SetHeader("authorization", "Bearer\t"+account.AccessToken). + SetBody(JsonStr(Json{ + "drive_id": account.DriveId, + "fields": "*", + "image_thumbnail_process": "image/resize,w_50", + "image_url_process": "image/resize,w_1920/format,jpeg", + "limit": account.Limit, + "marker": marker, + "order_by": account.OrderBy, + "order_direction": account.OrderDirection, + "parent_file_id": fileId, + "video_thumbnail_process": "video/snapshot,t_0,f_jpg,w_50", + })).Post("https://api.aliyundrive.com/v2/file/list") + if err != nil { + return nil, err + } + if e.Code != "" { + return nil, fmt.Errorf("%s", e.Message) + } + marker = resp.NextMarker + res = append(res, resp.Items...) + } + return res, nil +} + // path: /aaa/bbb func (a AliDrive) Path(path string, account *model.Account) (*model.File, []*model.File, error) { + path = utils.ParsePath(path) + log.Debugf("ali path: %s", path) cache, err := conf.Cache.Get(conf.Ctx, path) if err == nil { - file,ok := cache.(AliFile) + file, ok := cache.(AliFile) if ok { return AliToFile(file), nil, nil - }else { - files,_ := cache.([]AliFile) - res := make([]*model.File,0) - for _,file = range files{ + } else { + files, _ := cache.([]AliFile) + res := make([]*model.File, 0) + for _, file = range files { res = append(res, AliToFile(file)) } return nil, res, nil } - }else { + } else { + fileId := account.RootFolder if path != "/" { - + dir, name := filepath.Split(path) + dir = utils.ParsePath(dir) + _, _, err = a.Path(dir, account) + if err != nil { + return nil, nil, err + } + parentFiles_, _ := conf.Cache.Get(conf.Ctx, dir) + parentFiles, _ := parentFiles_.([]AliFile) + found := false + for _, file := range parentFiles { + if file.Name == name { + found = true + if file.Type == "file" { + return AliToFile(file), nil, nil + } else { + fileId = file.FileId + break + } + } + } + if !found { + return nil, nil, fmt.Errorf("path not found") + } } + files, err := a.GetFiles(fileId, account) + if err != nil { + return nil, nil, err + } + _ = conf.Cache.Set(conf.Ctx, path, files, nil) + res := make([]*model.File, 0) + for _, file := range files { + res = append(res, AliToFile(file)) + } + return nil, res, nil } - panic("implement me") } func (a AliDrive) Link(path string, account *model.Account) (string, error) { - panic("implement me") + dir, name := filepath.Split(path) + dir = utils.ParsePath(dir) + _, _, err := a.Path(dir, account) + if err != nil { + return "", err + } + parentFiles_, _ := conf.Cache.Get(conf.Ctx, dir) + parentFiles, _ := parentFiles_.([]AliFile) + for _, file := range parentFiles { + if file.Name == name { + if file.Type == "file" { + var resp Json + var e AliRespError + _, err = aliClient.R().SetResult(&resp). + SetError(&e). + SetHeader("authorization", "Bearer\t"+account.AccessToken). + SetBody(Json{ + "drive_id": account.DriveId, + "file_id": file.FileId, + "expire_sec": 14400, + }).Post("https://api.aliyundrive.com/v2/file/get_download_url") + if err != nil { + return "", err + } + if e.Code != "" { + return "", fmt.Errorf("%s",e.Message) + } + return resp["url"].(string), nil + } else { + return "", fmt.Errorf("can't down folder") + } + } + } + return "", fmt.Errorf("path not found") } type AliTokenResp struct { @@ -111,6 +222,13 @@ func (a AliDrive) Save(account *model.Account, old *model.Account) error { if err != nil { return err } + var resp Json + _, _ = aliClient.R().SetResult(&resp). + SetBody("{}"). + SetHeader("authorization", "Bearer\t"+access). + Post("https://api.aliyundrive.com/v2/user/get") + log.Debugf("user info: %+v", resp) + account.DriveId = resp["default_drive_id"].(string) account.RefreshToken, account.AccessToken = refresh, access cronId, err := conf.Cron.AddFunc("@every 2h", func() { name := account.Name diff --git a/go.mod b/go.mod index dc60a7dd..b87b99eb 100644 --- a/go.mod +++ b/go.mod @@ -3,10 +3,12 @@ module github.com/Xhofe/alist go 1.17 require ( - github.com/allegro/bigcache/v3 v3.0.1 github.com/eko/gocache/v2 v2.1.0 github.com/go-playground/validator/v10 v10.9.0 + github.com/go-resty/resty/v2 v2.6.0 github.com/gofiber/fiber/v2 v2.20.2 + github.com/patrickmn/go-cache v2.1.0+incompatible + github.com/robfig/cron/v3 v3.0.0 github.com/sirupsen/logrus v1.8.1 gorm.io/driver/mysql v1.1.2 gorm.io/driver/postgres v1.1.2 @@ -25,7 +27,6 @@ require ( github.com/go-playground/locales v0.14.0 // indirect github.com/go-playground/universal-translator v0.18.0 // indirect github.com/go-redis/redis/v8 v8.9.0 // indirect - github.com/go-resty/resty/v2 v2.6.0 // indirect github.com/go-sql-driver/mysql v1.6.0 // indirect github.com/golang/protobuf v1.4.3 // indirect github.com/jackc/chunkreader/v2 v2.0.1 // indirect @@ -47,7 +48,6 @@ require ( github.com/prometheus/client_model v0.2.0 // indirect github.com/prometheus/common v0.18.0 // indirect github.com/prometheus/procfs v0.6.0 // indirect - github.com/robfig/cron/v3 v3.0.0 // indirect github.com/spf13/cast v1.3.1 // indirect github.com/valyala/bytebufferpool v1.0.0 // indirect github.com/valyala/fasthttp v1.31.0 // indirect diff --git a/go.sum b/go.sum index 65161dbb..a36891ba 100644 --- a/go.sum +++ b/go.sum @@ -22,8 +22,6 @@ github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRF github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho= github.com/allegro/bigcache/v2 v2.2.5 h1:mRc8r6GQjuJsmSKQNPsR5jQVXc8IJ1xsW5YXUYMLfqI= github.com/allegro/bigcache/v2 v2.2.5/go.mod h1:FppZsIO+IZk7gCuj5FiIDHGygD9xvWQcqg1uIPMb6tY= -github.com/allegro/bigcache/v3 v3.0.1 h1:Q4Xl3chywXuJNOw7NV+MeySd3zGQDj4KCpkCg0te8mc= -github.com/allegro/bigcache/v3 v3.0.1/go.mod h1:aPyh7jEvrog9zAwx5N7+JUQX5dZTSGpxF1LAR4dr35I= github.com/andybalholm/brotli v1.0.2/go.mod h1:loMXtMfwqflxFJPmdbJO0a3KNoPuLBgiu3qAvBg8x/Y= github.com/andybalholm/brotli v1.0.3 h1:fpcw+r1N1h0Poc1F/pHbW40cUm/lMEQslZtCkBQ0UnM= github.com/andybalholm/brotli v1.0.3/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig= diff --git a/main.go b/main.go index ef9e272d..48f0a6ca 100644 --- a/main.go +++ b/main.go @@ -13,7 +13,7 @@ import ( "net/http" ) -func init() { +func Init() { flag.StringVar(&conf.ConfigFile, "conf", "config.json", "config file") flag.BoolVar(&conf.Debug,"debug",false,"start with debug mode") flag.Parse() @@ -25,6 +25,7 @@ func init() { } func main() { + Init() app := fiber.New() app.Use("/",filesystem.New(filesystem.Config{ Root: http.FS(public.Public), diff --git a/main_test.go b/main_test.go new file mode 100644 index 00000000..ae4bb2fb --- /dev/null +++ b/main_test.go @@ -0,0 +1,12 @@ +package main + +import ( + "fmt" + "net/url" + "testing" +) + +func TestUrl(t *testing.T) { + s,_ := url.QueryUnescape("/ali/%E7%8C%AA%E5%A4%B4%E7%9A%84%E6%96%87%E4%BB%B6%5B%E5%98%BF%E5%98%BF%5D/%E9%82%B9%E9%82%B9%E7%9A%84%E6%96%87%E4%BB%B6/%E6%A1%8C%E9%9D%A2%E5%A3%81%E7%BA%B8/v2-e8f266ba17ae387eefed1cb22b2b5e4e_r.jpg") + fmt.Print(s) +} \ No newline at end of file diff --git a/model/account.go b/model/account.go index 76b7f6a6..c9a51efb 100644 --- a/model/account.go +++ b/model/account.go @@ -15,6 +15,7 @@ type Account struct { Status string CronId int DriveId string + Limit int `json:"limit"` OrderBy string `json:"order_by"` OrderDirection string `json:"order_direction"` } @@ -79,4 +80,3 @@ func GetAccounts() []*Account { } return accounts } - diff --git a/model/meta.go b/model/meta.go index ba12755d..a446434f 100644 --- a/model/meta.go +++ b/model/meta.go @@ -1,8 +1,20 @@ package model +import "github.com/Xhofe/alist/conf" + type Meta struct { Path string `json:"path" gorm:"primaryKey"` Password string `json:"password"` Hide bool `json:"hide"` Ignore bool `json:"ignore"` } + +func GetMetaByPath(path string) (*Meta,error) { + var meta Meta + meta.Path = path + err := conf.DB.First(&meta).Error + if err != nil { + return nil, err + } + return &meta, nil +} \ No newline at end of file diff --git a/server/common.go b/server/common.go index eb6d1d36..8c24c0b7 100644 --- a/server/common.go +++ b/server/common.go @@ -27,7 +27,7 @@ func ParsePath(rawPath string) (*model.Account,string,drivers.Driver,error) { break default: paths := strings.Split(rawPath,"/") - path = strings.Join(paths[2:],"/") + path = "/" + strings.Join(paths[2:],"/") name = paths[1] } account,ok := model.GetAccount(name) diff --git a/server/down.go b/server/down.go index ffbcca0e..b1004088 100644 --- a/server/down.go +++ b/server/down.go @@ -1,9 +1,19 @@ package server -import "github.com/gofiber/fiber/v2" +import ( + "github.com/Xhofe/alist/utils" + "github.com/gofiber/fiber/v2" + log "github.com/sirupsen/logrus" + "net/url" +) func Down(ctx *fiber.Ctx) error { - rawPath := ctx.Params("*") + rawPath, err:= url.QueryUnescape(ctx.Params("*")) + if err != nil { + return ErrorResp(ctx,err,500) + } + rawPath = utils.ParsePath(rawPath) + log.Debugf("down: %s",rawPath) account, path, driver, err := ParsePath(rawPath) if err != nil { return ErrorResp(ctx, err, 500) diff --git a/server/path.go b/server/path.go index 47e87283..cb7dccfd 100644 --- a/server/path.go +++ b/server/path.go @@ -1,9 +1,11 @@ package server import ( + "fmt" "github.com/Xhofe/alist/model" + "github.com/Xhofe/alist/utils" "github.com/gofiber/fiber/v2" - "strings" + log "github.com/sirupsen/logrus" ) type PathReq struct { @@ -16,8 +18,14 @@ func Path(ctx *fiber.Ctx) error { if err := ctx.BodyParser(&req); err != nil { return ErrorResp(ctx, err, 400) } - if !strings.HasPrefix(req.Path, "/") { - req.Path = "/"+req.Path + req.Path = utils.ParsePath(req.Path) + log.Debugf("path: %s",req.Path) + meta, err := model.GetMetaByPath(req.Path) + if err == nil { + if meta.Password != "" && meta.Password!= req.Password { + return ErrorResp(ctx,fmt.Errorf("wrong password"),401) + } + // TODO hide or ignore? } if model.AccountsCount() > 1 && req.Path == "/" { return ctx.JSON(Resp{ diff --git a/utils/file.go b/utils/file.go index 8701ef99..9ccff801 100644 --- a/utils/file.go +++ b/utils/file.go @@ -7,6 +7,7 @@ import ( "io/ioutil" "os" "path/filepath" + "strings" ) // Exists determine whether the file exists @@ -75,4 +76,12 @@ func WriteToJson(src string, conf interface{}) bool { return false } return true +} + +func ParsePath(path string) string { + path = strings.TrimRight(path, "/") + if !strings.HasPrefix(path, "/") { + path = "/" + path + } + return path } \ No newline at end of file