alist/drivers/misskey/util.go

257 lines
6.3 KiB
Go

package misskey
import (
"bytes"
"context"
"errors"
"io"
"time"
"github.com/go-resty/resty/v2"
"github.com/alist-org/alist/v3/drivers/base"
"github.com/alist-org/alist/v3/internal/driver"
"github.com/alist-org/alist/v3/internal/errs"
"github.com/alist-org/alist/v3/internal/model"
"github.com/alist-org/alist/v3/pkg/utils"
)
// Base layer methods
func (d *Misskey) request(path, method string, callback base.ReqCallback, resp interface{}) error {
url := d.Endpoint + "/api/drive" + path
req := base.RestyClient.R()
req.SetAuthToken(d.AccessToken).SetHeader("Content-Type", "application/json")
if callback != nil {
callback(req)
} else {
req.SetBody("{}")
}
req.SetResult(resp)
// 启用调试模式
req.EnableTrace()
response, err := req.Execute(method, url)
if err != nil {
return err
}
if !response.IsSuccess() {
return errors.New(response.String())
}
return nil
}
func (d *Misskey) getThumb(ctx context.Context, obj model.Obj) (io.Reader, error) {
// TODO return the thumb of obj, optional
return nil, errs.NotImplement
}
func setBody(body interface{}) base.ReqCallback {
return func(req *resty.Request) {
req.SetBody(body)
}
}
func handleFolderId(dir model.Obj) interface{} {
if dir.GetID() == "" {
return nil
}
return dir.GetID()
}
// API layer methods
func (d *Misskey) getFiles(dir model.Obj) ([]model.Obj, error) {
var files []MFile
var body map[string]string
if dir.GetPath() != "/" {
body = map[string]string{"folderId": dir.GetID()}
} else {
body = map[string]string{}
}
err := d.request("/files", "POST", setBody(body), &files)
if err != nil {
return []model.Obj{}, err
}
return utils.SliceConvert(files, func(src MFile) (model.Obj, error) {
return mFile2Object(src), nil
})
}
func (d *Misskey) getFolders(dir model.Obj) ([]model.Obj, error) {
var folders []MFolder
var body map[string]string
if dir.GetPath() != "/" {
body = map[string]string{"folderId": dir.GetID()}
} else {
body = map[string]string{}
}
err := d.request("/folders", "POST", setBody(body), &folders)
if err != nil {
return []model.Obj{}, err
}
return utils.SliceConvert(folders, func(src MFolder) (model.Obj, error) {
return mFolder2Object(src), nil
})
}
func (d *Misskey) list(dir model.Obj) ([]model.Obj, error) {
files, _ := d.getFiles(dir)
folders, _ := d.getFolders(dir)
return append(files, folders...), nil
}
func (d *Misskey) link(file model.Obj) (*model.Link, error) {
var mFile MFile
err := d.request("/files/show", "POST", setBody(map[string]string{"fileId": file.GetID()}), &mFile)
if err != nil {
return nil, err
}
return &model.Link{
URL: mFile.URL,
}, nil
}
func (d *Misskey) makeDir(parentDir model.Obj, dirName string) (model.Obj, error) {
var folder MFolder
err := d.request("/folders/create", "POST", setBody(map[string]interface{}{"parentId": handleFolderId(parentDir), "name": dirName}), &folder)
if err != nil {
return nil, err
}
return mFolder2Object(folder), nil
}
func (d *Misskey) move(srcObj, dstDir model.Obj) (model.Obj, error) {
if srcObj.IsDir() {
var folder MFolder
err := d.request("/folders/update", "POST", setBody(map[string]interface{}{"folderId": srcObj.GetID(), "parentId": handleFolderId(dstDir)}), &folder)
return mFolder2Object(folder), err
} else {
var file MFile
err := d.request("/files/update", "POST", setBody(map[string]interface{}{"fileId": srcObj.GetID(), "folderId": handleFolderId(dstDir)}), &file)
return mFile2Object(file), err
}
}
func (d *Misskey) rename(srcObj model.Obj, newName string) (model.Obj, error) {
if srcObj.IsDir() {
var folder MFolder
err := d.request("/folders/update", "POST", setBody(map[string]string{"folderId": srcObj.GetID(), "name": newName}), &folder)
return mFolder2Object(folder), err
} else {
var file MFile
err := d.request("/files/update", "POST", setBody(map[string]string{"fileId": srcObj.GetID(), "name": newName}), &file)
return mFile2Object(file), err
}
}
func (d *Misskey) copy(srcObj, dstDir model.Obj) (model.Obj, error) {
if srcObj.IsDir() {
folder, err := d.makeDir(dstDir, srcObj.GetName())
if err != nil {
return nil, err
}
list, err := d.list(srcObj)
if err != nil {
return nil, err
}
for _, obj := range list {
_, err := d.copy(obj, folder)
if err != nil {
return nil, err
}
}
return folder, nil
} else {
var file MFile
url, err := d.link(srcObj)
if err != nil {
return nil, err
}
err = d.request("/files/upload-from-url", "POST", setBody(map[string]interface{}{"url": url.URL, "folderId": handleFolderId(dstDir)}), &file)
if err != nil {
return nil, err
}
return mFile2Object(file), nil
}
}
func (d *Misskey) remove(obj model.Obj) error {
if obj.IsDir() {
err := d.request("/folders/delete", "POST", setBody(map[string]string{"folderId": obj.GetID()}), nil)
return err
} else {
err := d.request("/files/delete", "POST", setBody(map[string]string{"fileId": obj.GetID()}), nil)
return err
}
}
func (d *Misskey) put(dstDir model.Obj, stream model.FileStreamer, up driver.UpdateProgress) (model.Obj, error) {
var file MFile
fileContent, err := io.ReadAll(stream)
if err != nil {
return nil, err
}
req := base.RestyClient.R().
SetFileReader("file", stream.GetName(), io.NopCloser(bytes.NewReader(fileContent))).
SetFormData(map[string]string{
"folderId": handleFolderId(dstDir).(string),
"name": stream.GetName(),
"comment": "",
"isSensitive": "false",
"force": "false",
}).
SetResult(&file).SetAuthToken(d.AccessToken)
resp, err := req.Post(d.Endpoint + "/api/drive/files/create")
if err != nil {
return nil, err
}
if !resp.IsSuccess() {
return nil, errors.New(resp.String())
}
return mFile2Object(file), nil
}
func mFile2Object(file MFile) *model.ObjThumbURL {
ctime, err := time.Parse(time.RFC3339, file.CreatedAt)
if err != nil {
ctime = time.Time{}
}
return &model.ObjThumbURL{
Object: model.Object{
ID: file.ID,
Name: file.Name,
Ctime: ctime,
IsFolder: false,
Size: file.Size,
},
Thumbnail: model.Thumbnail{
Thumbnail: file.ThumbnailURL,
},
Url: model.Url{
Url: file.URL,
},
}
}
func mFolder2Object(folder MFolder) *model.Object {
ctime, err := time.Parse(time.RFC3339, folder.CreatedAt)
if err != nil {
ctime = time.Time{}
}
return &model.Object{
ID: folder.ID,
Name: folder.Name,
Ctime: ctime,
IsFolder: true,
}
}