alist/drivers/xunlei/xunlei.go

283 lines
5.9 KiB
Go
Raw Normal View History

2022-03-03 07:44:41 +00:00
package xunlei
import (
"fmt"
2022-03-17 13:13:13 +00:00
"net/http"
2022-04-30 13:35:54 +00:00
"strings"
2022-03-03 07:44:41 +00:00
"sync"
"time"
"github.com/Xhofe/alist/drivers/base"
"github.com/Xhofe/alist/model"
"github.com/Xhofe/alist/utils"
"github.com/go-resty/resty/v2"
log "github.com/sirupsen/logrus"
)
2022-04-30 13:35:54 +00:00
// 缓存登录状态
2022-04-28 15:15:37 +00:00
var userClients sync.Map
2022-03-03 07:44:41 +00:00
2022-04-28 15:15:37 +00:00
func GetClient(account *model.Account) *Client {
if v, ok := userClients.Load(account.Username); ok {
return v.(*Client)
2022-03-03 07:44:41 +00:00
}
2022-04-28 15:15:37 +00:00
client := &Client{
2022-04-30 13:35:54 +00:00
Client: base.RestyClient,
clientID: account.ClientId,
clientSecret: account.ClientSecret,
clientVersion: account.ClientVersion,
packageName: account.PackageName,
algorithms: strings.Split(account.Algorithms, ","),
userAgent: account.UserAgent,
deviceID: account.DeviceId,
2022-03-03 07:44:41 +00:00
}
2022-04-28 15:15:37 +00:00
userClients.Store(account.Username, client)
return client
2022-03-03 07:44:41 +00:00
}
2022-04-28 15:15:37 +00:00
type Client struct {
*resty.Client
sync.Mutex
2022-03-03 07:44:41 +00:00
2022-04-30 13:35:54 +00:00
clientID string
clientSecret string
clientVersion string
packageName string
algorithms []string
userAgent string
deviceID string
2022-04-28 15:15:37 +00:00
captchaToken string
2022-03-03 07:44:41 +00:00
2022-04-28 15:15:37 +00:00
token string
refreshToken string
userID string
2022-03-03 07:44:41 +00:00
}
2022-04-28 15:15:37 +00:00
// 请求验证码token
func (c *Client) requestCaptchaToken(action string, meta map[string]string) error {
2022-04-30 13:35:54 +00:00
param := CaptchaTokenRequest{
2022-03-03 07:44:41 +00:00
Action: action,
2022-04-28 15:15:37 +00:00
CaptchaToken: c.captchaToken,
2022-04-30 13:35:54 +00:00
ClientID: c.clientID,
DeviceID: c.deviceID,
2022-04-28 15:15:37 +00:00
Meta: meta,
2022-04-30 13:35:54 +00:00
RedirectUri: "xlaccsdk01://xunlei.com/callback?state=harbor",
2022-03-03 07:44:41 +00:00
}
var e Erron
var resp CaptchaTokenResponse
2022-04-30 13:35:54 +00:00
_, err := c.Client.R().
SetBody(&param).
2022-03-03 07:44:41 +00:00
SetError(&e).
SetResult(&resp).
SetHeader("X-Device-Id", c.deviceID).
SetQueryParam("client_id", c.clientID).
2022-03-17 13:13:13 +00:00
Post(XLUSER_API_URL + "/shield/captcha/init")
2022-03-03 07:44:41 +00:00
if err != nil {
2022-04-28 15:15:37 +00:00
return err
2022-03-03 07:44:41 +00:00
}
2022-04-30 13:35:54 +00:00
if e.HasError() {
2022-04-28 15:15:37 +00:00
return &e
2022-03-03 07:44:41 +00:00
}
2022-04-28 15:15:37 +00:00
2022-03-03 07:44:41 +00:00
if resp.Url != "" {
2022-04-28 15:15:37 +00:00
return fmt.Errorf("need verify:%s", resp.Url)
2022-03-03 07:44:41 +00:00
}
2022-04-28 15:15:37 +00:00
if resp.CaptchaToken == "" {
return fmt.Errorf("empty captchaToken")
}
c.captchaToken = resp.CaptchaToken
return nil
2022-03-03 07:44:41 +00:00
}
2022-04-30 13:35:54 +00:00
// 验证码签名
func (c *Client) captchaSign(time string) string {
str := fmt.Sprint(c.clientID, c.clientVersion, c.packageName, c.deviceID, time)
for _, algorithm := range c.algorithms {
str = utils.GetMD5Encode(str + algorithm)
}
return "1." + str
}
2022-04-28 15:15:37 +00:00
// 登录
func (c *Client) Login(account *model.Account) (err error) {
c.Lock()
defer c.Unlock()
2022-03-03 07:44:41 +00:00
2022-04-28 15:15:37 +00:00
defer func() {
if err != nil {
account.Status = err.Error()
} else {
account.Status = "work"
}
model.SaveAccount(account)
}()
2022-03-03 07:44:41 +00:00
meta := make(map[string]string)
if strings.Contains(account.Username, "@") {
meta["email"] = account.Username
} else if len(account.Username) >= 11 {
if !strings.Contains(account.Username, "+") {
account.Username = "+86 " + account.Username
}
meta["phone_number"] = account.Username
} else {
meta["username"] = account.Username
}
2022-03-17 13:13:13 +00:00
url := XLUSER_API_URL + "/auth/signin"
err = c.requestCaptchaToken(getAction(http.MethodPost, url), meta)
2022-03-03 07:44:41 +00:00
if err != nil {
return err
}
var e Erron
var resp TokenResponse
2022-04-30 13:35:54 +00:00
_, err = c.Client.R().
2022-03-03 07:44:41 +00:00
SetResult(&resp).
SetError(&e).
2022-04-28 15:15:37 +00:00
SetBody(&SignInRequest{
CaptchaToken: c.captchaToken,
2022-04-30 13:35:54 +00:00
ClientID: c.clientID,
ClientSecret: c.clientSecret,
2022-04-28 15:15:37 +00:00
Username: account.Username,
Password: account.Password,
}).
SetHeader("X-Device-Id", c.deviceID).
SetQueryParam("client_id", c.clientID).
2022-03-03 07:44:41 +00:00
Post(url)
if err != nil {
return err
}
2022-04-30 13:35:54 +00:00
if e.HasError() {
2022-04-28 15:15:37 +00:00
return &e
}
if resp.RefreshToken == "" {
return base.ErrEmptyToken
2022-03-03 07:44:41 +00:00
}
2022-04-28 15:15:37 +00:00
c.token = resp.Token()
c.refreshToken = resp.RefreshToken
c.userID = resp.UserID
2022-03-03 07:44:41 +00:00
return nil
}
2022-04-28 15:15:37 +00:00
// 刷新验证码token
func (c *Client) RefreshCaptchaToken(action string) error {
c.Lock()
defer c.Unlock()
2022-04-30 13:35:54 +00:00
timestamp := fmt.Sprint(time.Now().UnixMilli())
param := map[string]string{
"client_version": c.clientVersion,
"package_name": c.packageName,
2022-04-28 15:15:37 +00:00
"user_id": c.userID,
2022-04-30 13:35:54 +00:00
"captcha_sign": c.captchaSign(timestamp),
"timestamp": timestamp,
}
return c.requestCaptchaToken(action, param)
2022-04-28 15:15:37 +00:00
}
// 刷新token
func (c *Client) RefreshToken() error {
c.Lock()
defer c.Unlock()
2022-03-03 07:44:41 +00:00
2022-04-28 15:15:37 +00:00
var e Erron
var resp TokenResponse
2022-04-30 13:35:54 +00:00
_, err := c.Client.R().
2022-04-28 15:15:37 +00:00
SetError(&e).
SetResult(&resp).
SetBody(&base.Json{
"grant_type": "refresh_token",
"refresh_token": c.refreshToken,
2022-04-30 13:35:54 +00:00
"client_id": c.clientID,
"client_secret": c.clientSecret,
2022-04-28 15:15:37 +00:00
}).
SetHeader("X-Device-Id", c.deviceID).
SetQueryParam("client_id", c.clientID).
2022-04-28 15:15:37 +00:00
Post(XLUSER_API_URL + "/auth/token")
2022-03-03 07:44:41 +00:00
if err != nil {
2022-04-28 15:15:37 +00:00
return err
}
2022-04-30 13:35:54 +00:00
if e.HasError() {
2022-04-28 15:15:37 +00:00
return &e
2022-03-03 07:44:41 +00:00
}
2022-04-30 13:35:54 +00:00
if resp.RefreshToken == "" {
return base.ErrEmptyToken
}
2022-04-28 15:15:37 +00:00
c.token = resp.TokenType + " " + resp.AccessToken
c.refreshToken = resp.RefreshToken
c.userID = resp.UserID
return nil
}
2022-03-17 13:13:13 +00:00
2022-04-28 15:15:37 +00:00
func (c *Client) Request(method string, url string, callback func(*resty.Request), account *model.Account) (*resty.Response, error) {
c.Lock()
2022-04-30 13:35:54 +00:00
req := c.Client.R().
2022-03-17 13:13:13 +00:00
SetHeaders(map[string]string{
2022-04-30 13:35:54 +00:00
"X-Device-Id": c.deviceID,
2022-04-28 15:15:37 +00:00
"Authorization": c.token,
"X-Captcha-Token": c.captchaToken,
2022-04-30 13:35:54 +00:00
"User-Agent": c.userAgent,
"client_id": c.clientID,
}).
SetQueryParam("client_id", c.clientID)
2022-04-28 15:15:37 +00:00
if callback != nil {
callback(req)
2022-03-03 07:44:41 +00:00
}
2022-04-28 15:15:37 +00:00
c.Unlock()
2022-03-03 07:44:41 +00:00
2022-04-28 15:15:37 +00:00
res, err := req.Execute(method, url)
2022-03-03 07:44:41 +00:00
if err != nil {
2022-03-17 13:13:13 +00:00
return nil, err
2022-03-03 07:44:41 +00:00
}
2022-03-17 13:13:13 +00:00
log.Debug(res.String())
2022-03-03 07:44:41 +00:00
2022-03-17 13:13:13 +00:00
var e Erron
2022-04-28 15:15:37 +00:00
if err = utils.Json.Unmarshal(res.Body(), &e); err != nil {
return nil, err
}
2022-04-28 15:15:37 +00:00
// 处理错误
2022-03-03 07:44:41 +00:00
switch e.ErrorCode {
2022-04-28 15:15:37 +00:00
case 0:
return res, nil
2022-04-30 13:35:54 +00:00
case 4122, 4121, 10: // token过期
2022-04-28 15:15:37 +00:00
if err = c.RefreshToken(); err == nil {
break
}
2022-03-03 07:44:41 +00:00
fallthrough
2022-04-28 15:15:37 +00:00
case 16: // 登录失效
if err = c.Login(account); err != nil {
return nil, err
}
case 9: // 验证码token过期
if err = c.RefreshCaptchaToken(getAction(method, url)); err != nil {
return nil, err
2022-03-17 13:13:13 +00:00
}
2022-03-03 07:44:41 +00:00
default:
2022-04-28 15:15:37 +00:00
return nil, &e
2022-03-03 07:44:41 +00:00
}
2022-04-28 15:15:37 +00:00
return c.Request(method, url, callback, account)
2022-03-03 07:44:41 +00:00
}
2022-05-12 11:15:39 +00:00
func (c *Client) UpdateCaptchaToken(captchaToken string) bool {
c.Lock()
defer c.Unlock()
if captchaToken != "" {
c.captchaToken = captchaToken
return true
}
return false
}