fix(xunlei):download link speed limit
This commit is contained in:
parent
75c98429bf
commit
11830bb51c
@ -7,6 +7,7 @@ import (
|
|||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/Xhofe/alist/conf"
|
"github.com/Xhofe/alist/conf"
|
||||||
@ -15,6 +16,7 @@ import (
|
|||||||
"github.com/Xhofe/alist/utils"
|
"github.com/Xhofe/alist/utils"
|
||||||
"github.com/aliyun/aliyun-oss-go-sdk/oss"
|
"github.com/aliyun/aliyun-oss-go-sdk/oss"
|
||||||
"github.com/go-resty/resty/v2"
|
"github.com/go-resty/resty/v2"
|
||||||
|
"github.com/google/uuid"
|
||||||
)
|
)
|
||||||
|
|
||||||
type XunLeiCloud struct{}
|
type XunLeiCloud struct{}
|
||||||
@ -46,11 +48,65 @@ func (driver XunLeiCloud) Items() []base.Item {
|
|||||||
Required: true,
|
Required: true,
|
||||||
Description: "account password",
|
Description: "account password",
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
Name: "captcha_token",
|
||||||
|
Label: "verified captcha token",
|
||||||
|
Type: base.TypeString,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
Name: "root_folder",
|
Name: "root_folder",
|
||||||
Label: "root folder file_id",
|
Label: "root folder file_id",
|
||||||
Type: base.TypeString,
|
Type: base.TypeString,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
Name: "client_version",
|
||||||
|
Label: "client version",
|
||||||
|
Default: "7.43.0.7998",
|
||||||
|
Type: base.TypeString,
|
||||||
|
Required: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "client_id",
|
||||||
|
Label: "client id",
|
||||||
|
Default: "Xp6vsxz_7IYVw2BB",
|
||||||
|
Type: base.TypeString,
|
||||||
|
Required: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "client_secret",
|
||||||
|
Label: "client secret",
|
||||||
|
Default: "Xp6vsy4tN9toTVdMSpomVdXpRmES",
|
||||||
|
Type: base.TypeString,
|
||||||
|
Required: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "algorithms",
|
||||||
|
Label: "algorithms",
|
||||||
|
Default: "hrVPGbeqYPs+CIscj05VpAtjalzY5yjpvlMS8bEo,DrI0uTP,HHK0VXyMgY0xk2K0o,BBaXsExvL3GadmIacjWv7ISUJp3ifAwqbJumu,5toJ7ejB+bh1,5LsZTFAFjgvFvIl1URBgOAJ,QcJ5Ry+,hYgZVz8r7REROaCYfd9,zw6gXgkk/8TtGrmx6EGfekPESLnbZfDFwqR,gtSwLnMBa8h12nF3DU6+LwEQPHxd,fMG8TvtAYbCkxuEbIm0Xi/Lb7Z",
|
||||||
|
Type: base.TypeString,
|
||||||
|
Required: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "package_name",
|
||||||
|
Label: "package name",
|
||||||
|
Default: "com.xunlei.downloadprovider",
|
||||||
|
Type: base.TypeString,
|
||||||
|
Required: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "user_agent",
|
||||||
|
Label: "user agent",
|
||||||
|
Default: "ANDROID-com.xunlei.downloadprovider/7.43.0.7998 netWorkType/WIFI appid/40 deviceName/Samsung_Sm-g9810 deviceModel/SM-G9810 OSVersion/7.1.2 protocolVersion/301 platformVersion/10 sdkVersion/220200 Oauth2Client/0.9 (Linux 4_0_9+) (JAVA 0)",
|
||||||
|
Type: base.TypeString,
|
||||||
|
Required: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "device_id",
|
||||||
|
Label: "device id",
|
||||||
|
Default: utils.GetMD5Encode(uuid.NewString()),
|
||||||
|
Type: base.TypeString,
|
||||||
|
Required: false,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -58,10 +114,18 @@ func (driver XunLeiCloud) Save(account *model.Account, old *model.Account) error
|
|||||||
if account == nil {
|
if account == nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
client := GetClient(account)
|
client := GetClient(account)
|
||||||
|
// 指定验证通过的captchaToken
|
||||||
|
if client.captchaToken != "" {
|
||||||
|
client.captchaToken = account.CaptchaToken
|
||||||
|
account.CaptchaToken = ""
|
||||||
|
}
|
||||||
|
|
||||||
if client.token == "" {
|
if client.token == "" {
|
||||||
return client.Login(account)
|
return client.Login(account)
|
||||||
}
|
}
|
||||||
|
|
||||||
account.Status = "work"
|
account.Status = "work"
|
||||||
model.SaveAccount(account)
|
model.SaveAccount(account)
|
||||||
return nil
|
return nil
|
||||||
@ -105,6 +169,7 @@ func (driver XunLeiCloud) Files(path string, account *model.Account) ([]model.Fi
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
time.Sleep(time.Millisecond * 400)
|
||||||
files := make([]model.File, 0)
|
files := make([]model.File, 0)
|
||||||
for {
|
for {
|
||||||
var fileList FileList
|
var fileList FileList
|
||||||
@ -161,7 +226,9 @@ func (driver XunLeiCloud) Link(args base.Args, account *model.Account) (*base.Li
|
|||||||
return nil, base.ErrNotFile
|
return nil, base.ErrNotFile
|
||||||
}
|
}
|
||||||
var lFile Files
|
var lFile Files
|
||||||
_, err = GetClient(account).Request("GET", FILE_API_URL+"/"+file.Id, func(r *resty.Request) {
|
clinet := GetClient(account)
|
||||||
|
_, err = clinet.Request("GET", FILE_API_URL+"/{fileID}", func(r *resty.Request) {
|
||||||
|
r.SetPathParam("fileID", file.Id)
|
||||||
r.SetQueryParam("with_audit", "true")
|
r.SetQueryParam("with_audit", "true")
|
||||||
r.SetResult(&lFile)
|
r.SetResult(&lFile)
|
||||||
}, account)
|
}, account)
|
||||||
@ -170,7 +237,7 @@ func (driver XunLeiCloud) Link(args base.Args, account *model.Account) (*base.Li
|
|||||||
}
|
}
|
||||||
return &base.Link{
|
return &base.Link{
|
||||||
Headers: []base.Header{
|
Headers: []base.Header{
|
||||||
{Name: "User-Agent", Value: base.UserAgent},
|
{Name: "User-Agent", Value: clinet.userAgent},
|
||||||
},
|
},
|
||||||
Url: lFile.WebContentLink,
|
Url: lFile.WebContentLink,
|
||||||
}, nil
|
}, nil
|
||||||
@ -201,7 +268,8 @@ func (driver XunLeiCloud) Rename(src string, dst string, account *model.Account)
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
_, err = GetClient(account).Request("PATCH", FILE_API_URL+"/"+srcFile.Id, func(r *resty.Request) {
|
_, err = GetClient(account).Request("PATCH", FILE_API_URL+"/{fileID}", func(r *resty.Request) {
|
||||||
|
r.SetPathParam("fileID", srcFile.Id)
|
||||||
r.SetBody(&base.Json{"name": filepath.Base(dst)})
|
r.SetBody(&base.Json{"name": filepath.Base(dst)})
|
||||||
}, account)
|
}, account)
|
||||||
return err
|
return err
|
||||||
@ -270,7 +338,8 @@ func (driver XunLeiCloud) Delete(path string, account *model.Account) error {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
_, err = GetClient(account).Request("PATCH", FILE_API_URL+"/"+srcFile.Id+"/trash", func(r *resty.Request) {
|
_, err = GetClient(account).Request("PATCH", FILE_API_URL+"/{fileID}/trash", func(r *resty.Request) {
|
||||||
|
r.SetPathParam("fileID", srcFile.Id)
|
||||||
r.SetBody(&base.Json{})
|
r.SetBody(&base.Json{})
|
||||||
}, account)
|
}, account)
|
||||||
return err
|
return err
|
||||||
@ -318,6 +387,7 @@ func (driver XunLeiCloud) Upload(file *model.FileStream, account *model.Account)
|
|||||||
|
|
||||||
param := resp.Resumable.Params
|
param := resp.Resumable.Params
|
||||||
if resp.UploadType == UPLOAD_TYPE_RESUMABLE {
|
if resp.UploadType == UPLOAD_TYPE_RESUMABLE {
|
||||||
|
param.Endpoint = strings.TrimLeft(param.Endpoint, param.Bucket+".")
|
||||||
client, err := oss.New(param.Endpoint, param.AccessKeyID, param.AccessKeySecret, oss.SecurityToken(param.SecurityToken), oss.EnableMD5(true))
|
client, err := oss.New(param.Endpoint, param.AccessKeyID, param.AccessKeySecret, oss.SecurityToken(param.SecurityToken), oss.EnableMD5(true))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@ -331,7 +401,6 @@ func (driver XunLeiCloud) Upload(file *model.FileStream, account *model.Account)
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
time.Sleep(time.Millisecond * 200)
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -12,6 +12,10 @@ type Erron struct {
|
|||||||
// ErrorDetails interface{} `json:"error_details"`
|
// ErrorDetails interface{} `json:"error_details"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (e *Erron) HasError() bool {
|
||||||
|
return e.ErrorCode != 0 || e.ErrorMsg != "" || e.ErrorDescription != ""
|
||||||
|
}
|
||||||
|
|
||||||
func (e *Erron) Error() string {
|
func (e *Erron) Error() string {
|
||||||
return fmt.Sprintf("ErrorCode: %d ,Error: %s ,ErrorDescription: %s ", e.ErrorCode, e.ErrorMsg, e.ErrorDescription)
|
return fmt.Sprintf("ErrorCode: %d ,Error: %s ,ErrorDescription: %s ", e.ErrorCode, e.ErrorMsg, e.ErrorDescription)
|
||||||
}
|
}
|
||||||
@ -25,7 +29,7 @@ type CaptchaTokenRequest struct {
|
|||||||
ClientID string `json:"client_id"`
|
ClientID string `json:"client_id"`
|
||||||
DeviceID string `json:"device_id"`
|
DeviceID string `json:"device_id"`
|
||||||
Meta map[string]string `json:"meta"`
|
Meta map[string]string `json:"meta"`
|
||||||
//RedirectUri string `json:"redirect_uri"`
|
RedirectUri string `json:"redirect_uri"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type CaptchaTokenResponse struct {
|
type CaptchaTokenResponse struct {
|
||||||
@ -173,9 +177,3 @@ type UploadTaskResponse struct {
|
|||||||
|
|
||||||
File Files `json:"file"`
|
File Files `json:"file"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type Tasks struct {
|
|
||||||
Tasks []interface{}
|
|
||||||
NextPageToken string `json:"next_page_token"`
|
|
||||||
//ExpiresIn int64 `json:"expires_in"`
|
|
||||||
}
|
|
||||||
|
@ -3,41 +3,10 @@ package xunlei
|
|||||||
import (
|
import (
|
||||||
"crypto/sha1"
|
"crypto/sha1"
|
||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
"fmt"
|
|
||||||
"io"
|
"io"
|
||||||
"net"
|
|
||||||
"net/url"
|
"net/url"
|
||||||
|
|
||||||
"github.com/Xhofe/alist/utils"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
|
||||||
// 小米浏览器
|
|
||||||
CLIENT_ID = "X7MtiU0Gb5YqWv-6"
|
|
||||||
CLIENT_SECRET = "84MYEih3Eeu2HF4RrGce3Q"
|
|
||||||
CLIENT_VERSION = "5.1.0.51045"
|
|
||||||
|
|
||||||
ALG_VERSION = "1"
|
|
||||||
PACKAGE_NAME = "com.xunlei.xcloud.lib"
|
|
||||||
)
|
|
||||||
|
|
||||||
var Algorithms = []string{
|
|
||||||
"",
|
|
||||||
"BXza40wm+P4zw8rEFpHA",
|
|
||||||
"UfZLfKfYRmKTA0",
|
|
||||||
"OMBGVt/9Wcaln1XaBz",
|
|
||||||
"Jn217F4rk5FPPWyhoeV",
|
|
||||||
"w5OwkGo0pGpb0Xe/XZ5T3",
|
|
||||||
"5guM3DNiY4F78x49zQ97q75",
|
|
||||||
"QXwn4D2j884wJgrYXjGClM/IVrJX",
|
|
||||||
"NXBRosYvbHIm6w8vEB",
|
|
||||||
"2kZ8Ie1yW2ib4O2iAkNpJobP",
|
|
||||||
"11CoVJJQEc",
|
|
||||||
"xf3QWysVwnVsNv5DCxU+cgNT1rK",
|
|
||||||
"9eEfKkrqkfw",
|
|
||||||
"T78dnANexYRbiZy",
|
|
||||||
}
|
|
||||||
|
|
||||||
const (
|
const (
|
||||||
API_URL = "https://api-pan.xunlei.com/drive/v1"
|
API_URL = "https://api-pan.xunlei.com/drive/v1"
|
||||||
FILE_API_URL = API_URL + "/files"
|
FILE_API_URL = API_URL + "/files"
|
||||||
@ -45,9 +14,8 @@ const (
|
|||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
FOLDER = "drive#folder"
|
FOLDER = "drive#folder"
|
||||||
FILE = "drive#file"
|
FILE = "drive#file"
|
||||||
|
|
||||||
RESUMABLE = "drive#resumable"
|
RESUMABLE = "drive#resumable"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -58,18 +26,9 @@ const (
|
|||||||
UPLOAD_TYPE_URL = "UPLOAD_TYPE_URL"
|
UPLOAD_TYPE_URL = "UPLOAD_TYPE_URL"
|
||||||
)
|
)
|
||||||
|
|
||||||
// 验证码签名
|
|
||||||
func captchaSign(driverID string, time int64) string {
|
|
||||||
str := fmt.Sprint(CLIENT_ID, CLIENT_VERSION, PACKAGE_NAME, driverID, time)
|
|
||||||
for _, algorithm := range Algorithms {
|
|
||||||
str = utils.GetMD5Encode(str + algorithm)
|
|
||||||
}
|
|
||||||
return ALG_VERSION + "." + str
|
|
||||||
}
|
|
||||||
|
|
||||||
func getAction(method string, u string) string {
|
func getAction(method string, u string) string {
|
||||||
c, _ := url.Parse(u)
|
c, _ := url.Parse(u)
|
||||||
return fmt.Sprint(method, ":", c.Path)
|
return method + ":" + c.Path
|
||||||
}
|
}
|
||||||
|
|
||||||
// 计算文件Gcid
|
// 计算文件Gcid
|
||||||
@ -102,13 +61,3 @@ func getGcid(r io.Reader, size int64) (string, error) {
|
|||||||
}
|
}
|
||||||
return hex.EncodeToString(hash1.Sum(nil)), nil
|
return hex.EncodeToString(hash1.Sum(nil)), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// 获取driverID
|
|
||||||
func getDriverID(username string) string {
|
|
||||||
interfaces, _ := net.Interfaces()
|
|
||||||
str := username
|
|
||||||
for _, inter := range interfaces {
|
|
||||||
str += inter.HardwareAddr.String()
|
|
||||||
}
|
|
||||||
return utils.GetMD5Encode(str)
|
|
||||||
}
|
|
||||||
|
@ -3,6 +3,7 @@ package xunlei
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
@ -13,12 +14,7 @@ import (
|
|||||||
log "github.com/sirupsen/logrus"
|
log "github.com/sirupsen/logrus"
|
||||||
)
|
)
|
||||||
|
|
||||||
var xunleiClient = resty.New().
|
// 缓存登录状态
|
||||||
SetHeaders(map[string]string{
|
|
||||||
"Accept": "application/json;charset=UTF-8",
|
|
||||||
}).
|
|
||||||
SetTimeout(base.DefaultTimeout)
|
|
||||||
|
|
||||||
var userClients sync.Map
|
var userClients sync.Map
|
||||||
|
|
||||||
func GetClient(account *model.Account) *Client {
|
func GetClient(account *model.Account) *Client {
|
||||||
@ -27,8 +23,15 @@ func GetClient(account *model.Account) *Client {
|
|||||||
}
|
}
|
||||||
|
|
||||||
client := &Client{
|
client := &Client{
|
||||||
Client: xunleiClient,
|
Client: base.RestyClient,
|
||||||
driverID: getDriverID(account.Username),
|
|
||||||
|
clientID: account.ClientId,
|
||||||
|
clientSecret: account.ClientSecret,
|
||||||
|
clientVersion: account.ClientVersion,
|
||||||
|
packageName: account.PackageName,
|
||||||
|
algorithms: strings.Split(account.Algorithms, ","),
|
||||||
|
userAgent: account.UserAgent,
|
||||||
|
deviceID: account.DeviceId,
|
||||||
}
|
}
|
||||||
userClients.Store(account.Username, client)
|
userClients.Store(account.Username, client)
|
||||||
return client
|
return client
|
||||||
@ -38,7 +41,14 @@ type Client struct {
|
|||||||
*resty.Client
|
*resty.Client
|
||||||
sync.Mutex
|
sync.Mutex
|
||||||
|
|
||||||
driverID string
|
clientID string
|
||||||
|
clientSecret string
|
||||||
|
clientVersion string
|
||||||
|
packageName string
|
||||||
|
algorithms []string
|
||||||
|
userAgent string
|
||||||
|
deviceID string
|
||||||
|
|
||||||
captchaToken string
|
captchaToken string
|
||||||
|
|
||||||
token string
|
token string
|
||||||
@ -48,25 +58,26 @@ type Client struct {
|
|||||||
|
|
||||||
// 请求验证码token
|
// 请求验证码token
|
||||||
func (c *Client) requestCaptchaToken(action string, meta map[string]string) error {
|
func (c *Client) requestCaptchaToken(action string, meta map[string]string) error {
|
||||||
req := CaptchaTokenRequest{
|
param := CaptchaTokenRequest{
|
||||||
Action: action,
|
Action: action,
|
||||||
CaptchaToken: c.captchaToken,
|
CaptchaToken: c.captchaToken,
|
||||||
ClientID: CLIENT_ID,
|
ClientID: c.clientID,
|
||||||
DeviceID: c.driverID,
|
DeviceID: c.deviceID,
|
||||||
Meta: meta,
|
Meta: meta,
|
||||||
|
RedirectUri: "xlaccsdk01://xunlei.com/callback?state=harbor",
|
||||||
}
|
}
|
||||||
|
|
||||||
var e Erron
|
var e Erron
|
||||||
var resp CaptchaTokenResponse
|
var resp CaptchaTokenResponse
|
||||||
_, err := xunleiClient.R().
|
_, err := c.Client.R().
|
||||||
SetBody(&req).
|
SetBody(¶m).
|
||||||
SetError(&e).
|
SetError(&e).
|
||||||
SetResult(&resp).
|
SetResult(&resp).
|
||||||
Post(XLUSER_API_URL + "/shield/captcha/init")
|
Post(XLUSER_API_URL + "/shield/captcha/init")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if e.ErrorCode != 0 || e.ErrorMsg != "" {
|
if e.HasError() {
|
||||||
return &e
|
return &e
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -81,6 +92,15 @@ func (c *Client) requestCaptchaToken(action string, meta map[string]string) erro
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 验证码签名
|
||||||
|
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
|
||||||
|
}
|
||||||
|
|
||||||
// 登录
|
// 登录
|
||||||
func (c *Client) Login(account *model.Account) (err error) {
|
func (c *Client) Login(account *model.Account) (err error) {
|
||||||
c.Lock()
|
c.Lock()
|
||||||
@ -103,13 +123,13 @@ func (c *Client) Login(account *model.Account) (err error) {
|
|||||||
|
|
||||||
var e Erron
|
var e Erron
|
||||||
var resp TokenResponse
|
var resp TokenResponse
|
||||||
_, err = xunleiClient.R().
|
_, err = c.Client.R().
|
||||||
SetResult(&resp).
|
SetResult(&resp).
|
||||||
SetError(&e).
|
SetError(&e).
|
||||||
SetBody(&SignInRequest{
|
SetBody(&SignInRequest{
|
||||||
CaptchaToken: c.captchaToken,
|
CaptchaToken: c.captchaToken,
|
||||||
ClientID: CLIENT_ID,
|
ClientID: c.clientID,
|
||||||
ClientSecret: CLIENT_SECRET,
|
ClientSecret: c.clientSecret,
|
||||||
Username: account.Username,
|
Username: account.Username,
|
||||||
Password: account.Password,
|
Password: account.Password,
|
||||||
}).
|
}).
|
||||||
@ -118,7 +138,7 @@ func (c *Client) Login(account *model.Account) (err error) {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if e.ErrorCode != 0 || e.ErrorMsg != "" {
|
if e.HasError() {
|
||||||
return &e
|
return &e
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -137,14 +157,15 @@ func (c *Client) RefreshCaptchaToken(action string) error {
|
|||||||
c.Lock()
|
c.Lock()
|
||||||
defer c.Unlock()
|
defer c.Unlock()
|
||||||
|
|
||||||
ctime := time.Now().UnixMilli()
|
timestamp := fmt.Sprint(time.Now().UnixMilli())
|
||||||
return c.requestCaptchaToken(action, map[string]string{
|
param := map[string]string{
|
||||||
"captcha_sign": captchaSign(c.driverID, ctime),
|
"client_version": c.clientVersion,
|
||||||
"client_version": CLIENT_VERSION,
|
"package_name": c.packageName,
|
||||||
"package_name": PACKAGE_NAME,
|
|
||||||
"timestamp": fmt.Sprint(ctime),
|
|
||||||
"user_id": c.userID,
|
"user_id": c.userID,
|
||||||
})
|
"captcha_sign": c.captchaSign(timestamp),
|
||||||
|
"timestamp": timestamp,
|
||||||
|
}
|
||||||
|
return c.requestCaptchaToken(action, param)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 刷新token
|
// 刷新token
|
||||||
@ -154,22 +175,27 @@ func (c *Client) RefreshToken() error {
|
|||||||
|
|
||||||
var e Erron
|
var e Erron
|
||||||
var resp TokenResponse
|
var resp TokenResponse
|
||||||
_, err := xunleiClient.R().
|
_, err := c.Client.R().
|
||||||
SetError(&e).
|
SetError(&e).
|
||||||
SetResult(&resp).
|
SetResult(&resp).
|
||||||
SetBody(&base.Json{
|
SetBody(&base.Json{
|
||||||
"grant_type": "refresh_token",
|
"grant_type": "refresh_token",
|
||||||
"refresh_token": c.refreshToken,
|
"refresh_token": c.refreshToken,
|
||||||
"client_id": CLIENT_ID,
|
"client_id": c.clientID,
|
||||||
"client_secret": CLIENT_SECRET,
|
"client_secret": c.clientSecret,
|
||||||
}).
|
}).
|
||||||
Post(XLUSER_API_URL + "/auth/token")
|
Post(XLUSER_API_URL + "/auth/token")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if e.ErrorCode != 0 || e.ErrorMsg != "" {
|
if e.HasError() {
|
||||||
return &e
|
return &e
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if resp.RefreshToken == "" {
|
||||||
|
return base.ErrEmptyToken
|
||||||
|
}
|
||||||
|
|
||||||
c.token = resp.TokenType + " " + resp.AccessToken
|
c.token = resp.TokenType + " " + resp.AccessToken
|
||||||
c.refreshToken = resp.RefreshToken
|
c.refreshToken = resp.RefreshToken
|
||||||
c.userID = resp.UserID
|
c.userID = resp.UserID
|
||||||
@ -178,13 +204,14 @@ func (c *Client) RefreshToken() error {
|
|||||||
|
|
||||||
func (c *Client) Request(method string, url string, callback func(*resty.Request), account *model.Account) (*resty.Response, error) {
|
func (c *Client) Request(method string, url string, callback func(*resty.Request), account *model.Account) (*resty.Response, error) {
|
||||||
c.Lock()
|
c.Lock()
|
||||||
req := xunleiClient.R().
|
req := c.Client.R().
|
||||||
SetHeaders(map[string]string{
|
SetHeaders(map[string]string{
|
||||||
"X-Device-Id": c.driverID,
|
"X-Device-Id": c.deviceID,
|
||||||
"Authorization": c.token,
|
"Authorization": c.token,
|
||||||
"X-Captcha-Token": c.captchaToken,
|
"X-Captcha-Token": c.captchaToken,
|
||||||
}).
|
"User-Agent": c.userAgent,
|
||||||
SetQueryParam("client_id", CLIENT_ID)
|
"client_id": c.clientID,
|
||||||
|
})
|
||||||
if callback != nil {
|
if callback != nil {
|
||||||
callback(req)
|
callback(req)
|
||||||
}
|
}
|
||||||
@ -205,7 +232,7 @@ func (c *Client) Request(method string, url string, callback func(*resty.Request
|
|||||||
switch e.ErrorCode {
|
switch e.ErrorCode {
|
||||||
case 0:
|
case 0:
|
||||||
return res, nil
|
return res, nil
|
||||||
case 4122, 4121: // token过期
|
case 4122, 4121, 10: // token过期
|
||||||
if err = c.RefreshToken(); err == nil {
|
if err = c.RefreshToken(); err == nil {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
@ -50,6 +50,13 @@ type Account struct {
|
|||||||
CustomHost string `json:"custom_host"`
|
CustomHost string `json:"custom_host"`
|
||||||
ExtractFolder string `json:"extract_folder"`
|
ExtractFolder string `json:"extract_folder"`
|
||||||
Bool1 bool `json:"bool_1"`
|
Bool1 bool `json:"bool_1"`
|
||||||
|
// for xunlei
|
||||||
|
Algorithms string `json:"algorithms"`
|
||||||
|
ClientVersion string `json:"client_version"`
|
||||||
|
PackageName string `json:"package_name"`
|
||||||
|
UserAgent string `json:"user_agent"`
|
||||||
|
CaptchaToken string `json:"captcha_token"`
|
||||||
|
DeviceId string `json:"device_id"`
|
||||||
}
|
}
|
||||||
|
|
||||||
var accountsMap = make(map[string]Account)
|
var accountsMap = make(map[string]Account)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user