mirror of https://github.com/Xhofe/alist
feat: virtual path
parent
a0f4383d41
commit
ced61da33a
|
@ -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 {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
145
model/account.go
145
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
|
||||
}
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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
|
||||
}
|
||||
}
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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{
|
||||
|
|
|
@ -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,
|
||||
},
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue