2022-03-03 07:44:41 +00:00
|
|
|
package xunlei
|
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
2022-03-17 13:13:13 +00:00
|
|
|
"net/http"
|
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-28 15:15:37 +00:00
|
|
|
var xunleiClient = resty.New().
|
|
|
|
SetHeaders(map[string]string{
|
|
|
|
"Accept": "application/json;charset=UTF-8",
|
|
|
|
}).
|
|
|
|
SetTimeout(base.DefaultTimeout)
|
2022-03-03 07:44:41 +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{
|
|
|
|
Client: xunleiClient,
|
|
|
|
driverID: getDriverID(account.Username),
|
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-28 15:15:37 +00:00
|
|
|
driverID string
|
|
|
|
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 {
|
|
|
|
req := CaptchaTokenRequest{
|
2022-03-03 07:44:41 +00:00
|
|
|
Action: action,
|
2022-04-28 15:15:37 +00:00
|
|
|
CaptchaToken: c.captchaToken,
|
2022-03-03 07:44:41 +00:00
|
|
|
ClientID: CLIENT_ID,
|
2022-04-28 15:15:37 +00:00
|
|
|
DeviceID: c.driverID,
|
|
|
|
Meta: meta,
|
2022-03-03 07:44:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
var e Erron
|
|
|
|
var resp CaptchaTokenResponse
|
|
|
|
_, err := xunleiClient.R().
|
2022-04-28 15:15:37 +00:00
|
|
|
SetBody(&req).
|
2022-03-03 07:44:41 +00:00
|
|
|
SetError(&e).
|
|
|
|
SetResult(&resp).
|
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-28 15:15:37 +00:00
|
|
|
if e.ErrorCode != 0 || e.ErrorMsg != "" {
|
|
|
|
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-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
|
|
|
|
2022-03-17 13:13:13 +00:00
|
|
|
url := XLUSER_API_URL + "/auth/signin"
|
2022-04-28 15:15:37 +00:00
|
|
|
err = c.requestCaptchaToken(getAction(http.MethodPost, url), map[string]string{"username": account.Username})
|
2022-03-03 07:44:41 +00:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
var e Erron
|
|
|
|
var resp TokenResponse
|
|
|
|
_, err = xunleiClient.R().
|
|
|
|
SetResult(&resp).
|
|
|
|
SetError(&e).
|
2022-04-28 15:15:37 +00:00
|
|
|
SetBody(&SignInRequest{
|
|
|
|
CaptchaToken: c.captchaToken,
|
|
|
|
ClientID: CLIENT_ID,
|
|
|
|
ClientSecret: CLIENT_SECRET,
|
|
|
|
Username: account.Username,
|
|
|
|
Password: account.Password,
|
|
|
|
}).
|
2022-03-03 07:44:41 +00:00
|
|
|
Post(url)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2022-04-28 15:15:37 +00:00
|
|
|
if e.ErrorCode != 0 || e.ErrorMsg != "" {
|
|
|
|
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()
|
|
|
|
|
|
|
|
ctime := time.Now().UnixMilli()
|
|
|
|
return c.requestCaptchaToken(action, map[string]string{
|
|
|
|
"captcha_sign": captchaSign(c.driverID, ctime),
|
|
|
|
"client_version": CLIENT_VERSION,
|
|
|
|
"package_name": PACKAGE_NAME,
|
|
|
|
"timestamp": fmt.Sprint(ctime),
|
|
|
|
"user_id": c.userID,
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
// 刷新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
|
|
|
|
_, err := xunleiClient.R().
|
|
|
|
SetError(&e).
|
|
|
|
SetResult(&resp).
|
|
|
|
SetBody(&base.Json{
|
|
|
|
"grant_type": "refresh_token",
|
|
|
|
"refresh_token": c.refreshToken,
|
|
|
|
"client_id": CLIENT_ID,
|
|
|
|
"client_secret": CLIENT_SECRET,
|
|
|
|
}).
|
|
|
|
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
|
|
|
|
}
|
|
|
|
if e.ErrorCode != 0 || e.ErrorMsg != "" {
|
|
|
|
return &e
|
2022-03-03 07:44:41 +00:00
|
|
|
}
|
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-03-03 07:44:41 +00:00
|
|
|
req := xunleiClient.R().
|
2022-03-17 13:13:13 +00:00
|
|
|
SetHeaders(map[string]string{
|
2022-04-28 15:15:37 +00:00
|
|
|
"X-Device-Id": c.driverID,
|
|
|
|
"Authorization": c.token,
|
|
|
|
"X-Captcha-Token": c.captchaToken,
|
2022-03-17 13:13:13 +00:00
|
|
|
}).
|
2022-03-03 07:44:41 +00:00
|
|
|
SetQueryParam("client_id", CLIENT_ID)
|
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 {
|
2022-04-18 10:29:21 +00:00
|
|
|
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
|
|
|
|
case 4122, 4121: // token过期
|
|
|
|
if err = c.RefreshToken(); err == nil {
|
|
|
|
break
|
2022-04-18 10:29:21 +00:00
|
|
|
}
|
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
|
|
|
}
|