alist/drivers/alidrive/driver.go

484 lines
12 KiB
Go
Raw Normal View History

2021-12-06 07:55:05 +00:00
package alidrive
2021-11-27 11:40:36 +00:00
import (
"bytes"
"errors"
2021-11-27 11:40:36 +00:00
"fmt"
"github.com/Xhofe/alist/conf"
2021-12-06 07:55:05 +00:00
"github.com/Xhofe/alist/drivers/base"
2021-11-27 11:40:36 +00:00
"github.com/Xhofe/alist/model"
"github.com/Xhofe/alist/utils"
"github.com/gin-gonic/gin"
"github.com/robfig/cron/v3"
log "github.com/sirupsen/logrus"
"io"
"math"
"net/http"
2021-11-27 11:40:36 +00:00
"path/filepath"
)
type AliDrive struct{}
2021-12-06 07:55:05 +00:00
func (driver AliDrive) Config() base.DriverConfig {
return base.DriverConfig{
Name: "AliDrive",
2021-11-29 08:42:46 +00:00
OnlyProxy: false,
}
}
2021-12-06 07:55:05 +00:00
func (driver AliDrive) Items() []base.Item {
return []base.Item{
2021-11-27 11:40:36 +00:00
{
2021-12-06 07:55:05 +00:00
Name: "order_by",
Label: "order_by",
Type: base.TypeSelect,
Values: "name,size,updated_at,created_at",
2021-11-27 11:40:36 +00:00
Required: false,
},
{
2021-12-06 07:55:05 +00:00
Name: "order_direction",
Label: "order_direction",
Type: base.TypeSelect,
Values: "ASC,DESC",
2021-11-27 11:40:36 +00:00
Required: false,
},
{
Name: "refresh_token",
Label: "refresh token",
2021-12-06 07:55:05 +00:00
Type: base.TypeString,
2021-11-27 11:40:36 +00:00
Required: true,
},
{
Name: "root_folder",
Label: "root folder file_id",
2021-12-06 07:55:05 +00:00
Type: base.TypeString,
2021-11-27 11:40:36 +00:00
Required: false,
},
{
Name: "limit",
Label: "limit",
2021-12-06 07:55:05 +00:00
Type: base.TypeNumber,
2021-11-27 11:40:36 +00:00
Required: false,
Description: ">0 and <=200",
},
}
}
func (driver AliDrive) Save(account *model.Account, old *model.Account) error {
if old != nil {
conf.Cron.Remove(cron.EntryID(old.CronId))
}
if account.RootFolder == "" {
account.RootFolder = "root"
}
if account.Limit == 0 {
account.Limit = 200
}
err := driver.RefreshToken(account)
if err != nil {
return err
}
2021-12-06 07:55:05 +00:00
var resp base.Json
2021-11-27 11:40:36 +00:00
_, _ = aliClient.R().SetResult(&resp).
SetBody("{}").
SetHeader("authorization", "Bearer\t"+account.AccessToken).
Post("https://api.aliyundrive.com/v2/user/get")
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)
log.Debugf("ali account: %+v", newAccount)
if !ok {
return
}
err = driver.RefreshToken(&newAccount)
_ = model.SaveAccount(&newAccount)
})
if err != nil {
return err
}
account.CronId = int(cronId)
err = model.SaveAccount(account)
if err != nil {
return err
}
return nil
}
func (driver AliDrive) File(path string, account *model.Account) (*model.File, error) {
path = utils.ParsePath(path)
if path == "/" {
return &model.File{
Id: account.RootFolder,
Name: account.Name,
Size: 0,
Type: conf.FOLDER,
2021-11-30 01:37:51 +00:00
Driver: driver.Config().Name,
2021-11-27 11:40:36 +00:00
UpdatedAt: account.UpdatedAt,
}, nil
}
dir, name := filepath.Split(path)
files, err := driver.Files(dir, account)
if err != nil {
return nil, err
}
for _, file := range files {
if file.Name == name {
return &file, nil
}
}
2021-12-06 07:55:05 +00:00
return nil, base.ErrPathNotFound
2021-11-27 11:40:36 +00:00
}
func (driver AliDrive) Files(path string, account *model.Account) ([]model.File, error) {
path = utils.ParsePath(path)
var rawFiles []AliFile
cache, err := base.GetCache(path, account)
2021-11-27 11:40:36 +00:00
if err == nil {
rawFiles, _ = cache.([]AliFile)
} else {
file, err := driver.File(path, account)
if err != nil {
return nil, err
}
rawFiles, err = driver.GetFiles(file.Id, account)
if err != nil {
return nil, err
}
if len(rawFiles) > 0 {
_ = base.SetCache(path, rawFiles, account)
2021-11-27 11:40:36 +00:00
}
}
files := make([]model.File, 0)
for _, file := range rawFiles {
files = append(files, *driver.FormatFile(&file))
}
return files, nil
}
2021-12-09 11:24:34 +00:00
func (driver AliDrive) Link(path string, account *model.Account) (*base.Link, error) {
2021-11-27 11:40:36 +00:00
file, err := driver.File(path, account)
if err != nil {
2021-12-09 11:24:34 +00:00
return nil, err
2021-11-27 11:40:36 +00:00
}
2021-12-06 07:55:05 +00:00
var resp base.Json
2021-11-27 11:40:36 +00:00
var e AliRespError
_, err = aliClient.R().SetResult(&resp).
SetError(&e).
SetHeader("authorization", "Bearer\t"+account.AccessToken).
2021-12-06 07:55:05 +00:00
SetBody(base.Json{
2021-11-27 11:40:36 +00:00
"drive_id": account.DriveId,
"file_id": file.Id,
"expire_sec": 14400,
}).Post("https://api.aliyundrive.com/v2/file/get_download_url")
if err != nil {
2021-12-09 11:24:34 +00:00
return nil, err
2021-11-27 11:40:36 +00:00
}
if e.Code != "" {
if e.Code == "AccessTokenInvalid" {
err = driver.RefreshToken(account)
if err != nil {
2021-12-09 11:24:34 +00:00
return nil, err
2021-11-27 11:40:36 +00:00
} else {
_ = model.SaveAccount(account)
return driver.Link(path, account)
}
}
2021-12-09 11:24:34 +00:00
return nil, fmt.Errorf("%s", e.Message)
2021-11-27 11:40:36 +00:00
}
2021-12-09 11:24:34 +00:00
return &base.Link{
Url: resp["url"].(string),
}, nil
2021-11-27 11:40:36 +00:00
}
func (driver AliDrive) Path(path string, account *model.Account) (*model.File, []model.File, error) {
path = utils.ParsePath(path)
log.Debugf("ali path: %s", path)
file, err := driver.File(path, account)
if err != nil {
return nil, nil, err
}
2021-12-09 11:24:34 +00:00
if !file.IsDir() {
link, err := driver.Link(path, account)
if err != nil {
return nil, nil, err
}
file.Url = link.Url
2021-11-27 11:40:36 +00:00
return file, nil, nil
}
files, err := driver.Files(path, account)
if err != nil {
return nil, nil, err
}
return nil, files, nil
}
func (driver AliDrive) Proxy(c *gin.Context, account *model.Account) {
c.Request.Header.Del("Origin")
c.Request.Header.Set("Referer", "https://www.aliyundrive.com/")
}
func (driver AliDrive) Preview(path string, account *model.Account) (interface{}, error) {
file, err := driver.GetFile(path, account)
if err != nil {
return nil, err
}
// office
2021-12-06 07:55:05 +00:00
var resp base.Json
2021-11-27 11:40:36 +00:00
var e AliRespError
var url string
2021-12-06 07:55:05 +00:00
req := base.Json{
2021-11-27 11:40:36 +00:00
"drive_id": account.DriveId,
"file_id": file.FileId,
}
switch file.Category {
case "doc":
{
url = "https://api.aliyundrive.com/v2/file/get_office_preview_url"
req["access_token"] = account.AccessToken
}
case "video":
{
url = "https://api.aliyundrive.com/v2/file/get_video_preview_play_info"
req["category"] = "live_transcoding"
}
default:
2021-12-06 07:55:05 +00:00
return nil, base.ErrNotSupport
2021-11-27 11:40:36 +00:00
}
_, err = aliClient.R().SetResult(&resp).SetError(&e).
SetHeader("authorization", "Bearer\t"+account.AccessToken).
SetBody(req).Post(url)
if err != nil {
return nil, err
}
if e.Code != "" {
return nil, fmt.Errorf("%s", e.Message)
}
return resp, nil
}
2021-12-05 07:22:19 +00:00
func (driver AliDrive) MakeDir(path string, account *model.Account) error {
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)
2021-12-05 07:22:19 +00:00
}
func (driver AliDrive) Move(src string, dst string, account *model.Account) error {
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
2021-12-05 07:22:19 +00:00
}
func (driver AliDrive) Copy(src string, dst string, account *model.Account) error {
return base.ErrNotSupport
2021-12-05 07:22:19 +00:00
}
func (driver AliDrive) Delete(path string, account *model.Account) error {
file, err := driver.File(path, account)
if err != nil {
return err
}
var e AliRespError
res, err := aliClient.R().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 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.Delete(path, account)
}
}
return fmt.Errorf("%s", e.Message)
}
if res.StatusCode() == 204 {
_ = base.DeleteCache(utils.Dir(path), account)
return nil
}
return errors.New(res.String())
}
type UploadResp struct {
FileId string `json:"file_id"`
UploadId string `json:"upload_id"`
PartInfoList []struct {
UploadUrl string `json:"upload_url"`
} `json:"part_info_list"`
2021-12-05 07:22:19 +00:00
}
func (driver AliDrive) Upload(file *model.FileStream, account *model.Account) error {
const DEFAULT uint64 = 10485760
var count = int64(math.Ceil(float64(file.GetSize()) / float64(DEFAULT)))
var finish uint64 = 0
parentFile, err := driver.File(file.ParentPath, account)
if err != nil {
return err
}
2021-12-10 14:24:55 +00:00
if !parentFile.IsDir() {
return base.ErrNotFolder
}
var resp UploadResp
var e AliRespError
partInfoList := make([]base.Json, 0)
var i int64
for i = 0; i < 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/adrive/v2/file/createWithFolders") // /v2/file/create_with_proof
//log.Debugf("%+v\n%+v", resp, e)
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)
}
var byteSize uint64
for i = 0; i < count; i++ {
byteSize = file.GetSize() - finish
if DEFAULT < byteSize {
byteSize = DEFAULT
}
2021-12-09 11:24:34 +00:00
log.Debugf("%d,%d", byteSize, finish)
byteData := make([]byte, byteSize)
n, err := io.ReadFull(file, byteData)
//n, err := file.Read(byteData)
//byteData, err := io.ReadAll(file)
//n := len(byteData)
2021-12-09 11:24:34 +00:00
log.Debug(err, n)
if err != nil {
return err
}
finish += uint64(n)
2021-12-09 11:24:34 +00:00
req, err := http.NewRequest("PUT", resp.PartInfoList[i].UploadUrl, bytes.NewBuffer(byteData))
if err != nil {
return err
}
2021-12-07 12:16:34 +00:00
res, err := base.HttpClient.Do(req)
if err != nil {
return err
}
log.Debugf("%+v", res)
//res, err := base.BaseClient.R().
// SetHeader("Content-Type","").
// SetBody(byteData).Put(resp.PartInfoList[i].UploadUrl)
//if err != nil {
// return err
//}
//log.Debugf("put to %s : %d,%s", resp.PartInfoList[i].UploadUrl, res.StatusCode(),res.String())
}
var resp2 base.Json
2021-12-09 11:24:34 +00:00
_, err = aliClient.R().SetResult(&resp2).SetError(&e).
SetHeader("authorization", "Bearer\t"+account.AccessToken).
SetBody(base.Json{
2021-12-09 11:24:34 +00:00
"drive_id": account.DriveId,
"file_id": resp.FileId,
"upload_id": resp.UploadId,
}).Post("https://api.aliyundrive.com/v2/file/complete")
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)
}
if resp2["file_id"] == resp.FileId {
2021-12-10 14:24:55 +00:00
_ = base.DeleteCache(file.ParentPath, account)
return nil
}
return fmt.Errorf("%+v", resp2)
2021-12-05 07:22:19 +00:00
}
var _ base.Driver = (*AliDrive)(nil)