2025-06-17 18:38:25 +08:00
|
|
|
|
package _123_open
|
|
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
"encoding/json"
|
|
|
|
|
"errors"
|
|
|
|
|
"net/http"
|
|
|
|
|
"strconv"
|
|
|
|
|
"time"
|
|
|
|
|
|
2025-07-01 09:54:50 +08:00
|
|
|
|
"github.com/OpenListTeam/OpenList/v4/drivers/base"
|
|
|
|
|
"github.com/OpenListTeam/OpenList/v4/internal/op"
|
2025-06-17 18:38:25 +08:00
|
|
|
|
"github.com/go-resty/resty/v2"
|
|
|
|
|
log "github.com/sirupsen/logrus"
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
var ( //不同情况下获取的AccessTokenQPS限制不同 如下模块化易于拓展
|
|
|
|
|
Api = "https://open-api.123pan.com"
|
|
|
|
|
|
|
|
|
|
AccessToken = InitApiInfo(Api+"/api/v1/access_token", 1)
|
|
|
|
|
RefreshToken = InitApiInfo(Api+"/api/v1/oauth2/access_token", 1)
|
|
|
|
|
UserInfo = InitApiInfo(Api+"/api/v1/user/info", 1)
|
|
|
|
|
FileList = InitApiInfo(Api+"/api/v2/file/list", 4)
|
|
|
|
|
DownloadInfo = InitApiInfo(Api+"/api/v1/file/download_info", 0)
|
|
|
|
|
Mkdir = InitApiInfo(Api+"/upload/v1/file/mkdir", 2)
|
|
|
|
|
Move = InitApiInfo(Api+"/api/v1/file/move", 1)
|
|
|
|
|
Rename = InitApiInfo(Api+"/api/v1/file/name", 1)
|
|
|
|
|
Trash = InitApiInfo(Api+"/api/v1/file/trash", 2)
|
|
|
|
|
UploadCreate = InitApiInfo(Api+"/upload/v1/file/create", 2)
|
|
|
|
|
UploadUrl = InitApiInfo(Api+"/upload/v1/file/get_upload_url", 0)
|
|
|
|
|
UploadComplete = InitApiInfo(Api+"/upload/v1/file/upload_complete", 0)
|
|
|
|
|
UploadAsync = InitApiInfo(Api+"/upload/v1/file/upload_async_result", 1)
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
func (d *Open123) Request(apiInfo *ApiInfo, method string, callback base.ReqCallback, resp interface{}) ([]byte, error) {
|
|
|
|
|
retryToken := true
|
|
|
|
|
for {
|
|
|
|
|
req := base.RestyClient.R()
|
|
|
|
|
req.SetHeaders(map[string]string{
|
|
|
|
|
"authorization": "Bearer " + d.AccessToken,
|
|
|
|
|
"platform": "open_platform",
|
|
|
|
|
"Content-Type": "application/json",
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
if callback != nil {
|
|
|
|
|
callback(req)
|
|
|
|
|
}
|
|
|
|
|
if resp != nil {
|
|
|
|
|
req.SetResult(resp)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
log.Debugf("API: %s, QPS: %d, NowLen: %d", apiInfo.url, apiInfo.qps, apiInfo.NowLen())
|
|
|
|
|
|
|
|
|
|
apiInfo.Require()
|
|
|
|
|
defer apiInfo.Release()
|
|
|
|
|
res, err := req.Execute(method, apiInfo.url)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
body := res.Body()
|
|
|
|
|
|
|
|
|
|
// 解析为通用响应
|
|
|
|
|
var baseResp BaseResp
|
|
|
|
|
if err = json.Unmarshal(body, &baseResp); err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if baseResp.Code == 0 {
|
|
|
|
|
return body, nil
|
|
|
|
|
} else if baseResp.Code == 401 && retryToken {
|
|
|
|
|
retryToken = false
|
|
|
|
|
if err := d.flushAccessToken(); err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
} else if baseResp.Code == 429 {
|
|
|
|
|
time.Sleep(500 * time.Millisecond)
|
|
|
|
|
log.Warningf("API: %s, QPS: %d, 请求太频繁,对应API提示过多请减小QPS", apiInfo.url, apiInfo.qps)
|
|
|
|
|
} else {
|
|
|
|
|
return nil, errors.New(baseResp.Message)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (d *Open123) flushAccessToken() error {
|
|
|
|
|
if d.Addition.ClientID != "" {
|
|
|
|
|
if d.Addition.ClientSecret != "" {
|
|
|
|
|
var resp AccessTokenResp
|
|
|
|
|
_, err := d.Request(AccessToken, http.MethodPost, func(req *resty.Request) {
|
|
|
|
|
req.SetBody(base.Json{
|
|
|
|
|
"clientID": d.ClientID,
|
|
|
|
|
"clientSecret": d.ClientSecret,
|
|
|
|
|
})
|
|
|
|
|
}, &resp)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
d.AccessToken = resp.Data.AccessToken
|
|
|
|
|
op.MustSaveDriverStorage(d)
|
|
|
|
|
} else if d.Addition.RefreshToken != "" {
|
|
|
|
|
var resp RefreshTokenResp
|
|
|
|
|
_, err := d.Request(RefreshToken, http.MethodPost, func(req *resty.Request) {
|
|
|
|
|
req.SetQueryParam("client_id", d.ClientID)
|
|
|
|
|
req.SetQueryParam("grant_type", "refresh_token")
|
|
|
|
|
req.SetQueryParam("refresh_token", d.Addition.RefreshToken)
|
|
|
|
|
}, &resp)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
d.AccessToken = resp.AccessToken
|
|
|
|
|
d.RefreshToken = resp.RefreshToken
|
|
|
|
|
op.MustSaveDriverStorage(d)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (d *Open123) getUserInfo() (*UserInfoResp, error) {
|
|
|
|
|
var resp UserInfoResp
|
|
|
|
|
|
|
|
|
|
if _, err := d.Request(UserInfo, http.MethodGet, nil, &resp); err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return &resp, nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (d *Open123) getFiles(parentFileId int64, limit int, lastFileId int64) (*FileListResp, error) {
|
|
|
|
|
var resp FileListResp
|
|
|
|
|
|
|
|
|
|
_, err := d.Request(FileList, http.MethodGet, func(req *resty.Request) {
|
|
|
|
|
req.SetQueryParams(
|
|
|
|
|
map[string]string{
|
|
|
|
|
"parentFileId": strconv.FormatInt(parentFileId, 10),
|
|
|
|
|
"limit": strconv.Itoa(limit),
|
|
|
|
|
"lastFileId": strconv.FormatInt(lastFileId, 10),
|
|
|
|
|
"trashed": "false",
|
|
|
|
|
"searchMode": "",
|
|
|
|
|
"searchData": "",
|
|
|
|
|
})
|
|
|
|
|
}, &resp)
|
|
|
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return &resp, nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (d *Open123) getDownloadInfo(fileId int64) (*DownloadInfoResp, error) {
|
|
|
|
|
var resp DownloadInfoResp
|
|
|
|
|
|
|
|
|
|
_, err := d.Request(DownloadInfo, http.MethodGet, func(req *resty.Request) {
|
|
|
|
|
req.SetQueryParams(map[string]string{
|
|
|
|
|
"fileId": strconv.FormatInt(fileId, 10),
|
|
|
|
|
})
|
|
|
|
|
}, &resp)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return &resp, nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (d *Open123) mkdir(parentID int64, name string) error {
|
|
|
|
|
_, err := d.Request(Mkdir, http.MethodPost, func(req *resty.Request) {
|
|
|
|
|
req.SetBody(base.Json{
|
|
|
|
|
"parentID": strconv.FormatInt(parentID, 10),
|
|
|
|
|
"name": name,
|
|
|
|
|
})
|
|
|
|
|
}, nil)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (d *Open123) move(fileID, toParentFileID int64) error {
|
|
|
|
|
_, err := d.Request(Move, http.MethodPost, func(req *resty.Request) {
|
|
|
|
|
req.SetBody(base.Json{
|
|
|
|
|
"fileIDs": []int64{fileID},
|
|
|
|
|
"toParentFileID": toParentFileID,
|
|
|
|
|
})
|
|
|
|
|
}, nil)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (d *Open123) rename(fileId int64, fileName string) error {
|
|
|
|
|
_, err := d.Request(Rename, http.MethodPut, func(req *resty.Request) {
|
|
|
|
|
req.SetBody(base.Json{
|
|
|
|
|
"fileId": fileId,
|
|
|
|
|
"fileName": fileName,
|
|
|
|
|
})
|
|
|
|
|
}, nil)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (d *Open123) trash(fileId int64) error {
|
|
|
|
|
_, err := d.Request(Trash, http.MethodPost, func(req *resty.Request) {
|
|
|
|
|
req.SetBody(base.Json{
|
|
|
|
|
"fileIDs": []int64{fileId},
|
|
|
|
|
})
|
|
|
|
|
}, nil)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return nil
|
|
|
|
|
}
|