From ced61da33afa324e3baa126c7fb7ba1347d82e54 Mon Sep 17 00:00:00 2001 From: Xhofe Date: Thu, 31 Mar 2022 20:43:17 +0800 Subject: [PATCH] feat: virtual path --- bootstrap/account.go | 4 +- drivers/alidrive/driver.go | 12 +-- drivers/operate/operate.go | 4 + model/account.go | 145 ++++++++++++++++++++++-------- server/common/common.go | 23 +---- server/common/files.go | 37 ++++++++ server/controllers/account.go | 10 ++- server/controllers/file/folder.go | 38 +++----- server/controllers/path.go | 42 ++------- server/webdav/file.go | 23 ++--- 10 files changed, 204 insertions(+), 134 deletions(-) create mode 100644 server/common/files.go diff --git a/bootstrap/account.go b/bootstrap/account.go index b5d8ea97..8766e43a 100644 --- a/bootstrap/account.go +++ b/bootstrap/account.go @@ -3,6 +3,7 @@ package bootstrap import ( "github.com/Xhofe/alist/conf" "github.com/Xhofe/alist/drivers/base" + "github.com/Xhofe/alist/drivers/operate" "github.com/Xhofe/alist/model" log "github.com/sirupsen/logrus" ) @@ -20,7 +21,8 @@ func InitAccounts() { log.Errorf("no [%s] driver", account.Type) } else { log.Infof("start init account: [%s], type: [%s]", account.Name, account.Type) - err := driver.Save(&accounts[i], nil) + //err := driver.Save(&accounts[i], nil) + err := operate.Save(driver, &accounts[i], nil) if err != nil { log.Errorf("init account [%s] error:[%s]", account.Name, err.Error()) } else { diff --git a/drivers/alidrive/driver.go b/drivers/alidrive/driver.go index 8ef0c7b0..a2a4ad7b 100644 --- a/drivers/alidrive/driver.go +++ b/drivers/alidrive/driver.go @@ -94,15 +94,15 @@ func (driver AliDrive) Save(account *model.Account, old *model.Account) error { log.Debugf("user info: %+v", resp) account.DriveId = resp["default_drive_id"].(string) cronId, err := conf.Cron.AddFunc("@every 2h", func() { - name := account.Name - log.Debugf("ali account name: %s", name) - newAccount, ok := model.GetAccount(name) + id := account.ID + log.Debugf("ali account id: %d", id) + newAccount, err := model.GetAccountById(id) log.Debugf("ali account: %+v", newAccount) - if !ok { + if err != nil { return } - err = driver.RefreshToken(&newAccount) - _ = model.SaveAccount(&newAccount) + err = driver.RefreshToken(newAccount) + _ = model.SaveAccount(newAccount) }) if err != nil { return err diff --git a/drivers/operate/operate.go b/drivers/operate/operate.go index 3c9dcc35..63782614 100644 --- a/drivers/operate/operate.go +++ b/drivers/operate/operate.go @@ -8,6 +8,10 @@ import ( "runtime/debug" ) +func Save(driver base.Driver, account, old *model.Account) error { + return driver.Save(account, old) +} + func Path(driver base.Driver, account *model.Account, path string) (*model.File, []model.File, error) { return driver.Path(path, account) } diff --git a/model/account.go b/model/account.go index dc44c69c..5c69c6be 100644 --- a/model/account.go +++ b/model/account.go @@ -2,6 +2,7 @@ package model import ( "github.com/Xhofe/alist/conf" + "github.com/Xhofe/alist/utils" log "github.com/sirupsen/logrus" "strings" "sync" @@ -97,6 +98,7 @@ func RegisterAccount(account Account) { accountsMap[account.Name] = account } +// GetAccount 根据名称获取账号(不包含负载均衡账号) 用于定时任务更新账号 func GetAccount(name string) (Account, bool) { if len(accountsMap) == 1 { for _, v := range accountsMap { @@ -107,25 +109,28 @@ func GetAccount(name string) (Account, bool) { return account, ok } -func GetAccountsByName(name string) []Account { - accounts := make([]Account, 0) - if AccountsCount() == 1 { - account, _ := GetAccount("") - accounts = append(accounts, account) - return accounts - } - for _, v := range accountsMap { - if v.Name == name || strings.HasPrefix(v.Name, name+balance) { - accounts = append(accounts, v) - } - } - return accounts -} +// GetAccountsByName 根据名称获取账号(包含负载均衡账号) +//func GetAccountsByName(name string) []Account { +// accounts := make([]Account, 0) +// if AccountsCount() == 1 { +// for _, v := range accountsMap { +// accounts = append(accounts, v) +// } +// return accounts +// } +// for _, v := range accountsMap { +// if v.Name == name || strings.HasPrefix(v.Name, name+balance) { +// accounts = append(accounts, v) +// } +// } +// return accounts +//} var balanceMap sync.Map +// GetBalancedAccount 根据名称获取账号,负载均衡之后的 func GetBalancedAccount(name string) (Account, bool) { - accounts := GetAccountsByName(name) + accounts := GetAccountsByPath(name) accountNum := len(accounts) switch accountNum { case 0: @@ -147,6 +152,7 @@ func GetBalancedAccount(name string) (Account, bool) { } } +// GetAccountById 根据id获取账号,用于更新账号 func GetAccountById(id uint) (*Account, error) { var account Account account.ID = id @@ -156,27 +162,29 @@ func GetAccountById(id uint) (*Account, error) { return &account, nil } -func GetAccountFiles() ([]File, error) { - files := make([]File, 0) - var accounts []Account - if err := conf.DB.Order(columnName("index")).Find(&accounts).Error; err != nil { - return nil, err - } - for _, v := range accounts { - if strings.Contains(v.Name, balance) { - continue - } - files = append(files, File{ - Name: v.Name, - Size: 0, - Driver: v.Type, - Type: conf.FOLDER, - UpdatedAt: v.UpdatedAt, - }) - } - return files, nil -} +// GetAccountFiles 获取账号虚拟文件(去除负载均衡) +//func GetAccountFiles() ([]File, error) { +// files := make([]File, 0) +// var accounts []Account +// if err := conf.DB.Order(columnName("index")).Find(&accounts).Error; err != nil { +// return nil, err +// } +// for _, v := range accounts { +// if strings.Contains(v.Name, balance) { +// continue +// } +// files = append(files, File{ +// Name: v.Name, +// Size: 0, +// Driver: v.Type, +// Type: conf.FOLDER, +// UpdatedAt: v.UpdatedAt, +// }) +// } +// return files, nil +//} +// GetAccounts 获取所有账号 func GetAccounts() ([]Account, error) { var accounts []Account if err := conf.DB.Order(columnName("index")).Find(&accounts).Error; err != nil { @@ -184,3 +192,70 @@ func GetAccounts() ([]Account, error) { } return accounts, nil } + +// GetAccountsByPath 根据路径获取账号,最长匹配,未负载均衡 +// 如有账号: /a/b,/a/c,/a/d/e,/a/d/e.balance +// GetAccountsByPath(/a/d/e/f) => /a/d/e,/a/d/e.balance +func GetAccountsByPath(path string) []Account { + accounts := make([]Account, 0) + curSlashCount := 0 + for _, v := range accountsMap { + name := utils.ParsePath(v.Name) + bIndex := strings.LastIndex(name, balance) + if bIndex != -1 { + name = v.Name[:bIndex] + } + // 不是这个账号 + if path != name && !strings.HasPrefix(path, name+"/") { + continue + } + slashCount := strings.Count(name, "/") + // 不是最长匹配 + if slashCount < curSlashCount { + continue + } + if slashCount > curSlashCount { + accounts = accounts[:0] + curSlashCount = slashCount + } + accounts = append(accounts, v) + } + return accounts +} + +// GetAccountFilesByPath 根据路径获取账号虚拟文件 +// 如有账号: /a/b,/a/c,/a/d/e,/a/b.balance1,/av +// GetAccountFilesByPath(/a) => b,c,d +func GetAccountFilesByPath(prefix string) ([]File, error) { + files := make([]File, 0) + var accounts []Account + if err := conf.DB.Order(columnName("index")).Find(&accounts).Error; err != nil { + return nil, err + } + prefix = utils.ParsePath(prefix) + set := make(map[string]interface{}) + for _, v := range accounts { + // 负载均衡账号 + if strings.Contains(v.Name, balance) { + continue + } + full := utils.ParsePath(v.Name) + // 不是以prefix为前缀 + if !strings.HasPrefix(full, prefix+"/") && prefix != "/" { + continue + } + name := strings.Split(strings.TrimPrefix(strings.TrimPrefix(full, prefix), "/"), "/")[0] + if _, ok := set[name]; ok { + continue + } + files = append(files, File{ + Name: name, + Size: 0, + Driver: v.Type, + Type: conf.FOLDER, + UpdatedAt: v.UpdatedAt, + }) + set[name] = nil + } + return files, nil +} diff --git a/server/common/common.go b/server/common/common.go index 8abc1984..ff4c7ea4 100644 --- a/server/common/common.go +++ b/server/common/common.go @@ -1,7 +1,6 @@ package common import ( - "errors" "fmt" "github.com/Xhofe/alist/drivers/base" "github.com/Xhofe/alist/model" @@ -25,30 +24,16 @@ type PathReq struct { } func ParsePath(rawPath string) (*model.Account, string, base.Driver, error) { - var path, name string - switch model.AccountsCount() { - case 0: - return nil, "", nil, fmt.Errorf("no accounts,please add one first") - case 1: - path = rawPath - break - default: - if path == "/" { - return nil, "", nil, errors.New("can't operate root of multiple accounts") - } - paths := strings.Split(rawPath, "/") - path = "/" + strings.Join(paths[2:], "/") - name = paths[1] - } - account, ok := model.GetBalancedAccount(name) + rawPath = utils.ParsePath(rawPath) + account, ok := model.GetBalancedAccount(rawPath) if !ok { - return nil, "", nil, fmt.Errorf("no [%s] account", name) + return nil, "", nil, fmt.Errorf("path not found") } driver, ok := base.GetDriver(account.Type) if !ok { return nil, "", nil, fmt.Errorf("no [%s] driver", account.Type) } - return &account, path, driver, nil + return &account, strings.TrimPrefix(rawPath, utils.ParsePath(account.Name)), driver, nil } func ErrorResp(c *gin.Context, err error, code int) { diff --git a/server/common/files.go b/server/common/files.go new file mode 100644 index 00000000..e051732b --- /dev/null +++ b/server/common/files.go @@ -0,0 +1,37 @@ +package common + +import ( + "github.com/Xhofe/alist/drivers/base" + "github.com/Xhofe/alist/drivers/operate" + "github.com/Xhofe/alist/model" +) + +func Path(rawPath string) (*model.File, []model.File, *model.Account, base.Driver, string, error) { + account, path, driver, err := ParsePath(rawPath) + if err != nil { + if err.Error() == "path not found" { + accountFiles, err := model.GetAccountFilesByPath(rawPath) + if err != nil { + return nil, nil, nil, nil, "", err + } + if len(accountFiles) != 0 { + return nil, accountFiles, nil, nil, path, nil + } + } + return nil, nil, nil, nil, "", err + } + file, files, err := operate.Path(driver, account, path) + if err != nil { + return nil, nil, nil, nil, "", err + } + if file != nil { + return file, nil, account, driver, path, nil + } else { + accountFiles, err := model.GetAccountFilesByPath(rawPath) + if err != nil { + return nil, nil, nil, nil, "", err + } + files = append(files, accountFiles...) + return nil, files, account, driver, path, nil + } +} diff --git a/server/controllers/account.go b/server/controllers/account.go index 44ef55d9..a705f4c7 100644 --- a/server/controllers/account.go +++ b/server/controllers/account.go @@ -3,6 +3,7 @@ package controllers import ( "fmt" "github.com/Xhofe/alist/drivers/base" + "github.com/Xhofe/alist/drivers/operate" "github.com/Xhofe/alist/model" "github.com/Xhofe/alist/server/common" "github.com/gin-gonic/gin" @@ -37,7 +38,8 @@ func CreateAccount(c *gin.Context) { common.ErrorResp(c, err, 500) } else { log.Debugf("new account: %+v", req) - err = driver.Save(&req, nil) + //err = driver.Save(&req, nil) + err = operate.Save(driver, &req, nil) if err != nil { common.ErrorResp(c, err, 500) return @@ -71,7 +73,8 @@ func SaveAccount(c *gin.Context) { common.ErrorResp(c, err, 500) } else { log.Debugf("save account: %+v", req) - err = driver.Save(&req, old) + //err = driver.Save(&req, old) + err = operate.Save(driver, &req, nil) if err != nil { common.ErrorResp(c, err, 500) return @@ -93,7 +96,8 @@ func DeleteAccount(c *gin.Context) { } else { driver, ok := base.GetDriver(account.Type) if ok { - _ = driver.Save(nil, account) + //_ = driver.Save(nil, account) + _ = operate.Save(driver, nil, account) } else { log.Errorf("no driver: %s", account.Type) } diff --git a/server/controllers/file/folder.go b/server/controllers/file/folder.go index 293beebb..ada34bd4 100644 --- a/server/controllers/file/folder.go +++ b/server/controllers/file/folder.go @@ -1,7 +1,6 @@ package file import ( - "github.com/Xhofe/alist/drivers/operate" "github.com/Xhofe/alist/model" "github.com/Xhofe/alist/server/common" "github.com/gin-gonic/gin" @@ -18,31 +17,18 @@ func Folder(c *gin.Context) { return } var files = make([]model.File, 0) - var err error - if model.AccountsCount() > 1 && (req.Path == "/" || req.Path == "") { - files, err = model.GetAccountFiles() - if err != nil { - common.ErrorResp(c, err, 500) - return - } - } else { - account, path, driver, err := common.ParsePath(req.Path) - if err != nil { - common.ErrorResp(c, err, 500) - return - } - file, rawFiles, err := operate.Path(driver, account, path) - if err != nil { - common.ErrorResp(c, err, 500) - return - } - if file != nil { - common.ErrorStrResp(c, "Not folder", 400) - } - for _, file := range rawFiles { - if file.IsDir() { - files = append(files, file) - } + _, rawFiles, _, _, _, err := common.Path(req.Path) + if err != nil { + common.ErrorResp(c, err, 500) + return + } + if rawFiles == nil { + common.ErrorStrResp(c, "not a folder", 400) + return + } + for _, file := range rawFiles { + if file.IsDir() { + files = append(files, file) } } c.JSON(200, common.Resp{ diff --git a/server/controllers/path.go b/server/controllers/path.go index d3cc026c..f3580748 100644 --- a/server/controllers/path.go +++ b/server/controllers/path.go @@ -5,7 +5,6 @@ import ( "fmt" "github.com/Xhofe/alist/conf" "github.com/Xhofe/alist/drivers/base" - "github.com/Xhofe/alist/drivers/operate" "github.com/Xhofe/alist/model" "github.com/Xhofe/alist/server/common" "github.com/Xhofe/alist/utils" @@ -79,39 +78,12 @@ func Path(c *gin.Context) { if meta != nil && meta.Upload { upload = true } - if model.AccountsCount() > 1 && (req.Path == "/" || req.Path == "") { - files, err := model.GetAccountFiles() - if err != nil { - common.ErrorResp(c, err, 500) - return - } - if !ok { - files = common.Hide(meta, files) - } - c.JSON(200, common.Resp{ - Code: 200, - Message: "success", - Data: PathResp{ - Type: "folder", - Meta: Meta{ - Driver: "root", - }, - Files: files, - }, - }) - return - } err := CheckPagination(&req) if err != nil { common.ErrorResp(c, err, 400) return } - account, path, driver, err := common.ParsePath(req.Path) - if err != nil { - common.ErrorResp(c, err, 500) - return - } - file, files, err := operate.Path(driver, account, path) + file, files, account, driver, path, err := common.Path(req.Path) if err != nil { common.ErrorResp(c, err, 500) return @@ -147,10 +119,14 @@ func Path(c *gin.Context) { if !ok { files = common.Hide(meta, files) } - if driver.Config().LocalSort { - model.SortFiles(files, account) + driverName := "root" + if driver != nil { + if driver.Config().LocalSort { + model.SortFiles(files, account) + } + model.ExtractFolder(files, account) + driverName = driver.Config().Name } - model.ExtractFolder(files, account) total, files := Pagination(files, &req) c.JSON(200, common.Resp{ Code: 200, @@ -158,7 +134,7 @@ func Path(c *gin.Context) { Data: PathResp{ Type: "folder", Meta: Meta{ - Driver: driver.Config().Name, + Driver: driverName, Upload: upload, Total: total, }, diff --git a/server/webdav/file.go b/server/webdav/file.go index bf8d8d53..5a61d421 100644 --- a/server/webdav/file.go +++ b/server/webdav/file.go @@ -50,17 +50,18 @@ func (fs *FileSystem) File(rawPath string) (*model.File, error) { func (fs *FileSystem) Files(ctx context.Context, rawPath string) ([]model.File, error) { rawPath = utils.ParsePath(rawPath) - var files []model.File - var err error - if model.AccountsCount() > 1 && rawPath == "/" { - files, err = model.GetAccountFiles() - } else { - account, path_, driver, err := common.ParsePath(rawPath) - if err != nil { - return nil, err - } - files, err = operate.Files(driver, account, path_) - } + //var files []model.File + //var err error + //if model.AccountsCount() > 1 && rawPath == "/" { + // files, err = model.GetAccountFilesByPath("/") + //} else { + // account, path_, driver, err := common.ParsePath(rawPath) + // if err != nil { + // return nil, err + // } + // files, err = operate.Files(driver, account, path_) + //} + _, files, _, _, _, err := common.Path(rawPath) if err != nil { return nil, err }