mirror of https://github.com/Xhofe/alist
🚧 aliyundrive webdav write
parent
1779617cb9
commit
28998d6f8c
|
@ -52,7 +52,7 @@ func (driver Cloud189) FormatFile(file *Cloud189File) *model.File {
|
|||
//func (c Cloud189) GetFile(path string, account *model.Account) (*Cloud189File, error) {
|
||||
// dir, name := filepath.Split(path)
|
||||
// dir = utils.ParsePath(dir)
|
||||
// _, _, err := c.Path(dir, account)
|
||||
// _, _, err := c.ParentPath(dir, account)
|
||||
// if err != nil {
|
||||
// return nil, err
|
||||
// }
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package alidrive
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"github.com/Xhofe/alist/conf"
|
||||
"github.com/Xhofe/alist/drivers/base"
|
||||
|
@ -9,6 +10,7 @@ import (
|
|||
"github.com/go-resty/resty/v2"
|
||||
log "github.com/sirupsen/logrus"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
|
@ -156,6 +158,81 @@ func (driver AliDrive) RefreshToken(account *model.Account) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func (driver AliDrive) Rename(fileId, name string, account *model.Account) error {
|
||||
var resp base.Json
|
||||
var e AliRespError
|
||||
_, err := aliClient.R().SetResult(&resp).SetError(&e).
|
||||
SetHeader("authorization", "Bearer\t"+account.AccessToken).
|
||||
SetBody(base.Json{
|
||||
"check_name_mode": "refuse",
|
||||
"drive_id": account.DriveId,
|
||||
"file_id": fileId,
|
||||
"name": name,
|
||||
}).Post("https://api.aliyundrive.com/v3/file/update")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if e.Code != "" {
|
||||
if e.Code == "AccessTokenInvalid" {
|
||||
err = driver.RefreshToken(account)
|
||||
if err != nil {
|
||||
return err
|
||||
} else {
|
||||
_ = model.SaveAccount(account)
|
||||
return driver.Rename(fileId, name, account)
|
||||
}
|
||||
}
|
||||
return fmt.Errorf("%s", e.Message)
|
||||
}
|
||||
if resp["name"] == name {
|
||||
return nil
|
||||
}
|
||||
return fmt.Errorf("%+v", resp)
|
||||
}
|
||||
|
||||
func (driver AliDrive) Batch(srcId,dstId string, account *model.Account) error {
|
||||
var e AliRespError
|
||||
res, err := aliClient.R().SetError(&e).
|
||||
SetHeader("authorization", "Bearer\t"+account.AccessToken).
|
||||
SetBody(base.Json{
|
||||
"requests": []base.Json{
|
||||
{
|
||||
"headers": base.Json{
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
"method":"POST",
|
||||
"id":srcId,
|
||||
"body":base.Json{
|
||||
"drive_id": account.DriveId,
|
||||
"file_id":srcId,
|
||||
"to_drive_id":account.DriveId,
|
||||
"to_parent_file_id":dstId,
|
||||
},
|
||||
},
|
||||
},
|
||||
"resource": "file",
|
||||
}).Post("https://api.aliyundrive.com/v3/batch")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if e.Code != "" {
|
||||
if e.Code == "AccessTokenInvalid" {
|
||||
err = driver.RefreshToken(account)
|
||||
if err != nil {
|
||||
return err
|
||||
} else {
|
||||
_ = model.SaveAccount(account)
|
||||
return driver.Batch(srcId, dstId, account)
|
||||
}
|
||||
}
|
||||
return fmt.Errorf("%s", e.Message)
|
||||
}
|
||||
if strings.Contains(res.String(), `"status":200`) {
|
||||
return nil
|
||||
}
|
||||
return errors.New(res.String())
|
||||
}
|
||||
|
||||
func init() {
|
||||
base.RegisterDriver(&AliDrive{})
|
||||
aliClient.
|
||||
|
|
|
@ -9,6 +9,7 @@ import (
|
|||
"github.com/gin-gonic/gin"
|
||||
"github.com/robfig/cron/v3"
|
||||
log "github.com/sirupsen/logrus"
|
||||
"math"
|
||||
"path/filepath"
|
||||
)
|
||||
|
||||
|
@ -130,7 +131,7 @@ func (driver AliDrive) File(path string, account *model.Account) (*model.File, e
|
|||
func (driver AliDrive) Files(path string, account *model.Account) ([]model.File, error) {
|
||||
path = utils.ParsePath(path)
|
||||
var rawFiles []AliFile
|
||||
cache, err := conf.Cache.Get(conf.Ctx, fmt.Sprintf("%s%s", account.Name, path))
|
||||
cache, err := base.GetCache(path, account)
|
||||
if err == nil {
|
||||
rawFiles, _ = cache.([]AliFile)
|
||||
} else {
|
||||
|
@ -143,7 +144,7 @@ func (driver AliDrive) Files(path string, account *model.Account) ([]model.File,
|
|||
return nil, err
|
||||
}
|
||||
if len(rawFiles) > 0 {
|
||||
_ = conf.Cache.Set(conf.Ctx, fmt.Sprintf("%s%s", account.Name, path), rawFiles, nil)
|
||||
_ = base.SetCache(path, rawFiles, account)
|
||||
}
|
||||
}
|
||||
files := make([]model.File, 0)
|
||||
|
@ -249,22 +250,151 @@ func (driver AliDrive) Preview(path string, account *model.Account) (interface{}
|
|||
}
|
||||
|
||||
func (driver AliDrive) MakeDir(path string, account *model.Account) error {
|
||||
return base.ErrNotImplement
|
||||
dir, name := filepath.Split(path)
|
||||
parentFile, err := driver.File(dir, account)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !parentFile.IsDir() {
|
||||
return base.ErrNotFolder
|
||||
}
|
||||
var resp base.Json
|
||||
var e AliRespError
|
||||
_, err = aliClient.R().SetResult(&resp).SetError(&e).
|
||||
SetHeader("authorization", "Bearer\t"+account.AccessToken).
|
||||
SetBody(base.Json{
|
||||
"check_name_mode": "refuse",
|
||||
"drive_id": account.DriveId,
|
||||
"name": name,
|
||||
"parent_file_id": parentFile.Id,
|
||||
"type": "folder",
|
||||
}).Post("https://api.aliyundrive.com/adrive/v2/file/createWithFolders")
|
||||
if e.Code != "" {
|
||||
if e.Code == "AccessTokenInvalid" {
|
||||
err = driver.RefreshToken(account)
|
||||
if err != nil {
|
||||
return err
|
||||
} else {
|
||||
_ = model.SaveAccount(account)
|
||||
return driver.MakeDir(path, account)
|
||||
}
|
||||
}
|
||||
return fmt.Errorf("%s", e.Message)
|
||||
}
|
||||
if resp["file_name"] == name {
|
||||
_ = base.DeleteCache(dir, account)
|
||||
return nil
|
||||
}
|
||||
return fmt.Errorf("%+v", resp)
|
||||
}
|
||||
|
||||
func (driver AliDrive) Move(src string, dst string, account *model.Account) error {
|
||||
return base.ErrNotImplement
|
||||
srcDir, _ := filepath.Split(src)
|
||||
dstDir, dstName := filepath.Split(dst)
|
||||
srcFile, err := driver.File(src, account)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// rename
|
||||
if srcDir == dstDir {
|
||||
err = driver.Rename(srcFile.Id, dstName, account)
|
||||
} else {
|
||||
// move
|
||||
dstDirFile, err := driver.File(dstDir, account)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = driver.Batch(srcFile.Id, dstDirFile.Id, account)
|
||||
}
|
||||
if err != nil {
|
||||
_ = base.DeleteCache(srcDir, account)
|
||||
_ = base.DeleteCache(dstDir, account)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (driver AliDrive) Copy(src string, dst string, account *model.Account) error {
|
||||
return base.ErrNotImplement
|
||||
return base.ErrNotSupport
|
||||
}
|
||||
|
||||
func (driver AliDrive) Delete(path string, account *model.Account) error {
|
||||
return base.ErrNotImplement
|
||||
file, err := driver.File(path, account)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
var resp base.Json
|
||||
var e AliRespError
|
||||
_, err = aliClient.R().SetResult(&resp).SetError(&e).
|
||||
SetHeader("authorization", "Bearer\t"+account.AccessToken).
|
||||
SetBody(base.Json{
|
||||
"drive_id": account.DriveId,
|
||||
"file_id": file.Id,
|
||||
}).Post("https://api.aliyundrive.com/v2/recyclebin/trash")
|
||||
if e.Code != "" {
|
||||
if e.Code == "AccessTokenInvalid" {
|
||||
err = driver.RefreshToken(account)
|
||||
if err != nil {
|
||||
return err
|
||||
} else {
|
||||
_ = model.SaveAccount(account)
|
||||
return driver.Delete(path, account)
|
||||
}
|
||||
}
|
||||
return fmt.Errorf("%s", e.Message)
|
||||
}
|
||||
if resp["file_id"] == file.Id {
|
||||
_ = base.DeleteCache(utils.Dir(path), account)
|
||||
return nil
|
||||
}
|
||||
return fmt.Errorf("%+v", resp)
|
||||
}
|
||||
|
||||
type UploadResp struct {
|
||||
}
|
||||
|
||||
func (driver AliDrive) Upload(file *model.FileStream, account *model.Account) error {
|
||||
const DEFAULT int64 = 10485760
|
||||
var count = math.Ceil(float64(file.GetSize()) / float64(DEFAULT))
|
||||
//var finish int64 = 0
|
||||
parentFile, err := driver.File(file.ParentPath, account)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
var resp UploadResp
|
||||
var e AliRespError
|
||||
partInfoList := make([]base.Json, 0)
|
||||
for i := 0; i < int(count); i++ {
|
||||
partInfoList = append(partInfoList, base.Json{
|
||||
"part_number": i + 1,
|
||||
})
|
||||
}
|
||||
_, err = aliClient.R().SetResult(&resp).SetError(&e).
|
||||
SetHeader("authorization", "Bearer\t"+account.AccessToken).
|
||||
SetBody(base.Json{
|
||||
"check_name_mode": "auto_rename",
|
||||
// content_hash
|
||||
"content_hash_name": "none",
|
||||
"drive_id": account.DriveId,
|
||||
"name": file.GetFileName(),
|
||||
"parent_file_id": parentFile.Id,
|
||||
"part_info_list": partInfoList,
|
||||
//proof_code
|
||||
"proof_version": "v1",
|
||||
"size": file.GetSize(),
|
||||
"type": "file",
|
||||
}).Post("https://api.aliyundrive.com/v2/recyclebin/trash")
|
||||
if e.Code != "" {
|
||||
if e.Code == "AccessTokenInvalid" {
|
||||
err = driver.RefreshToken(account)
|
||||
if err != nil {
|
||||
return err
|
||||
} else {
|
||||
_ = model.SaveAccount(account)
|
||||
return driver.Upload(file, account)
|
||||
}
|
||||
}
|
||||
return fmt.Errorf("%s", e.Message)
|
||||
}
|
||||
return base.ErrNotImplement
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,25 @@
|
|||
package base
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/Xhofe/alist/conf"
|
||||
"github.com/Xhofe/alist/model"
|
||||
"github.com/Xhofe/alist/utils"
|
||||
)
|
||||
|
||||
func KeyCache(path string, account *model.Account) string {
|
||||
path = utils.ParsePath(path)
|
||||
return fmt.Sprintf("%s%s", account.Name, path)
|
||||
}
|
||||
|
||||
func SetCache(path string, obj interface{}, account *model.Account) error {
|
||||
return conf.Cache.Set(conf.Ctx, KeyCache(path, account), obj, nil)
|
||||
}
|
||||
|
||||
func GetCache(path string, account *model.Account) (interface{}, error) {
|
||||
return conf.Cache.Get(conf.Ctx, fmt.Sprintf("%s%s", KeyCache(path, account)))
|
||||
}
|
||||
|
||||
func DeleteCache(path string, account *model.Account) error {
|
||||
return conf.Cache.Delete(conf.Ctx, fmt.Sprintf("%s%s", KeyCache(path, account)))
|
||||
}
|
|
@ -41,11 +41,6 @@ type Item struct {
|
|||
Description string `json:"description"`
|
||||
}
|
||||
|
||||
type TokenResp struct {
|
||||
AccessToken string `json:"access_token"`
|
||||
RefreshToken string `json:"refresh_token"`
|
||||
}
|
||||
|
||||
var driversMap = map[string]Driver{}
|
||||
|
||||
func RegisterDriver(driver Driver) {
|
||||
|
@ -68,14 +63,14 @@ func GetDrivers() map[string][]Item {
|
|||
{
|
||||
Name: "proxy",
|
||||
Label: "proxy",
|
||||
Type: "bool",
|
||||
Type: TypeBool,
|
||||
Required: true,
|
||||
Description: "allow proxy",
|
||||
},
|
||||
{
|
||||
Name: "webdav_proxy",
|
||||
Label: "webdav proxy",
|
||||
Type: "bool",
|
||||
Type: TypeBool,
|
||||
Required: true,
|
||||
Description: "Transfer the WebDAV of this account through the server",
|
||||
},
|
||||
|
@ -85,8 +80,6 @@ func GetDrivers() map[string][]Item {
|
|||
return res
|
||||
}
|
||||
|
||||
type Json map[string]interface{}
|
||||
|
||||
var NoRedirectClient *resty.Client
|
||||
|
||||
func init() {
|
||||
|
|
|
@ -1,12 +1,15 @@
|
|||
package base
|
||||
|
||||
import "fmt"
|
||||
import (
|
||||
"errors"
|
||||
)
|
||||
|
||||
var (
|
||||
ErrPathNotFound = fmt.Errorf("path not found")
|
||||
ErrNotFile = fmt.Errorf("not file")
|
||||
ErrNotImplement = fmt.Errorf("not implement")
|
||||
ErrNotSupport = fmt.Errorf("not support")
|
||||
ErrPathNotFound = errors.New("path not found")
|
||||
ErrNotFile = errors.New("not file")
|
||||
ErrNotImplement = errors.New("not implement")
|
||||
ErrNotSupport = errors.New("not support")
|
||||
ErrNotFolder = errors.New("not a folder")
|
||||
)
|
||||
|
||||
const (
|
||||
|
@ -15,3 +18,10 @@ const (
|
|||
TypeBool = "bool"
|
||||
TypeNumber = "number"
|
||||
)
|
||||
|
||||
type Json map[string]interface{}
|
||||
|
||||
type TokenResp struct {
|
||||
AccessToken string `json:"access_token"`
|
||||
RefreshToken string `json:"refresh_token"`
|
||||
}
|
||||
|
|
|
@ -134,7 +134,7 @@ func (driver GoogleDrive) GetFiles(id string, account *model.Account) ([]GoogleF
|
|||
//func (driver GoogleDrive) GetFile(path string, account *model.Account) (*GoogleFile, error) {
|
||||
// dir, name := filepath.Split(path)
|
||||
// dir = utils.ParsePath(dir)
|
||||
// _, _, err := driver.Path(dir, account)
|
||||
// _, _, err := driver.ParentPath(dir, account)
|
||||
// if err != nil {
|
||||
// return nil, err
|
||||
// }
|
||||
|
|
|
@ -204,8 +204,8 @@ func (driver Native) Delete(path string, account *model.Account) error {
|
|||
}
|
||||
|
||||
func (driver Native) Upload(file *model.FileStream, account *model.Account) error {
|
||||
fullPath := filepath.Join(account.RootFolder, file.Path, file.Name)
|
||||
_, err := driver.File(filepath.Join(file.Path,file.Name), account)
|
||||
fullPath := filepath.Join(account.RootFolder, file.ParentPath, file.Name)
|
||||
_, err := driver.File(filepath.Join(file.ParentPath,file.Name), account)
|
||||
if err == nil {
|
||||
// TODO overwrite?
|
||||
}
|
||||
|
|
|
@ -5,7 +5,7 @@ import "io"
|
|||
type FileStream struct {
|
||||
File io.ReadCloser
|
||||
Size uint64
|
||||
Path string
|
||||
ParentPath string
|
||||
Name string
|
||||
MIMEType string
|
||||
}
|
||||
|
@ -30,6 +30,6 @@ func (file FileStream) GetFileName() string {
|
|||
return file.Name
|
||||
}
|
||||
|
||||
func (file FileStream) GetPath() string {
|
||||
return file.Path
|
||||
func (file FileStream) GetParentPath() string {
|
||||
return file.ParentPath
|
||||
}
|
|
@ -11,7 +11,7 @@ import (
|
|||
)
|
||||
|
||||
type PathReq struct {
|
||||
Path string `json:"Path"`
|
||||
Path string `json:"ParentPath"`
|
||||
Password string `json:"Password"`
|
||||
}
|
||||
|
||||
|
|
|
@ -23,16 +23,16 @@ import (
|
|||
type FileSystem struct{}
|
||||
|
||||
func ParsePath(rawPath string) (*model.Account, string, base.Driver, error) {
|
||||
var path, name string
|
||||
var internalPath, name string
|
||||
switch model.AccountsCount() {
|
||||
case 0:
|
||||
return nil, "", nil, fmt.Errorf("no accounts,please add one first")
|
||||
case 1:
|
||||
path = rawPath
|
||||
internalPath = rawPath
|
||||
break
|
||||
default:
|
||||
paths := strings.Split(rawPath, "/")
|
||||
path = "/" + strings.Join(paths[2:], "/")
|
||||
internalPath = "/" + strings.Join(paths[2:], "/")
|
||||
name = paths[1]
|
||||
}
|
||||
account, ok := model.GetAccount(name)
|
||||
|
@ -43,7 +43,7 @@ func ParsePath(rawPath string) (*model.Account, string, base.Driver, error) {
|
|||
if !ok {
|
||||
return nil, "", nil, fmt.Errorf("no [%s] driver", account.Type)
|
||||
}
|
||||
return &account, path, driver, nil
|
||||
return &account, internalPath, driver, nil
|
||||
}
|
||||
|
||||
func (fs *FileSystem) File(rawPath string) (*model.File, error) {
|
||||
|
@ -164,7 +164,7 @@ func (fs *FileSystem) Upload(ctx context.Context, r *http.Request, rawPath strin
|
|||
File: r.Body,
|
||||
Size: fileSize,
|
||||
Name: fileName,
|
||||
Path: filePath,
|
||||
ParentPath: filePath,
|
||||
}
|
||||
return driver.Upload(&fileData, account)
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue