新增快手平台和对应的接口
This commit is contained in:
@@ -3,13 +3,16 @@ package sync
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"crypto/md5"
|
||||
"crypto/rand"
|
||||
"encoding/hex"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"math/big"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"sort"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
@@ -24,8 +27,9 @@ type ApiResult struct {
|
||||
|
||||
// ApiClient 通用 API 客户端
|
||||
type ApiClient struct {
|
||||
config *PlatformConfig
|
||||
client *http.Client
|
||||
config *PlatformConfig
|
||||
client *http.Client
|
||||
rateLimiter <-chan time.Time // 限流 ticker
|
||||
}
|
||||
|
||||
// NewApiClient 创建客户端
|
||||
@@ -34,10 +38,17 @@ func NewApiClient(config *PlatformConfig) *ApiClient {
|
||||
if config.RequestTimeoutMs > 0 {
|
||||
timeout = time.Duration(config.RequestTimeoutMs) * time.Millisecond
|
||||
}
|
||||
return &ApiClient{
|
||||
ac := &ApiClient{
|
||||
config: config,
|
||||
client: &http.Client{Timeout: timeout},
|
||||
}
|
||||
// 初始化限流
|
||||
if config.RateLimitPerMinute > 0 {
|
||||
interval := time.Minute / time.Duration(config.RateLimitPerMinute)
|
||||
ac.rateLimiter = time.Tick(interval)
|
||||
logrus.Infof("限流已启用: %d 次/分钟, 间隔 %v", config.RateLimitPerMinute, interval)
|
||||
}
|
||||
return ac
|
||||
}
|
||||
|
||||
// Get 发送 GET 请求(无参数)
|
||||
@@ -85,6 +96,15 @@ func (c *ApiClient) doRequest(ctx context.Context, method, path string, body int
|
||||
}
|
||||
|
||||
func (c *ApiClient) execute(ctx context.Context, method, path string, body interface{}, paramsInQuery bool) (*ApiResult, error) {
|
||||
// 限流等待
|
||||
if c.rateLimiter != nil {
|
||||
select {
|
||||
case <-c.rateLimiter:
|
||||
case <-ctx.Done():
|
||||
return nil, ctx.Err()
|
||||
}
|
||||
}
|
||||
|
||||
start := time.Now()
|
||||
fullURL := c.config.GetApiUrl(path)
|
||||
|
||||
@@ -104,6 +124,8 @@ func (c *ApiClient) execute(ctx context.Context, method, path string, body inter
|
||||
}
|
||||
}
|
||||
|
||||
// 计算签名并追加(如快手 API 的 MD5 签名)
|
||||
fullURL = c.applySignature(fullURL, body, paramsInQuery)
|
||||
logrus.Infof("请求 URL: %s", fullURL)
|
||||
|
||||
req, err := http.NewRequestWithContext(ctx, method, fullURL, reqBody)
|
||||
@@ -192,6 +214,7 @@ func (c *ApiClient) applyAuthURL(rawURL string) string {
|
||||
for k, v := range eq {
|
||||
val := fmt.Sprintf("%v", v)
|
||||
val = strings.ReplaceAll(val, "{timestamp}", fmt.Sprintf("%d", time.Now().Unix()))
|
||||
val = strings.ReplaceAll(val, "{timestamp_ms}", fmt.Sprintf("%d", time.Now().UnixMilli()))
|
||||
val = strings.ReplaceAll(val, "{nonce}", generateNonce())
|
||||
extraParams[k] = val
|
||||
}
|
||||
@@ -250,3 +273,58 @@ func generateNonce() string {
|
||||
r, _ := rand.Int(rand.Reader, big.NewInt(10000))
|
||||
return fmt.Sprintf("%012d%04d", nanoPart, r.Int64())
|
||||
}
|
||||
|
||||
// applySignature 计算签名并追加到 URL(支持快手等平台的 MD5 签名)
|
||||
func (c *ApiClient) applySignature(rawURL string, body interface{}, paramsInQuery bool) string {
|
||||
cfg := c.config.AuthConfig
|
||||
if cfg == nil {
|
||||
return rawURL
|
||||
}
|
||||
|
||||
signAlgo, _ := cfg["sign_algorithm"].(string)
|
||||
if signAlgo == "" {
|
||||
return rawURL
|
||||
}
|
||||
appSecret, _ := cfg["app_secret"].(string)
|
||||
if appSecret == "" && c.config.AppSecret != "" {
|
||||
appSecret = c.config.AppSecret
|
||||
}
|
||||
if appSecret == "" {
|
||||
return rawURL
|
||||
}
|
||||
|
||||
parsed, _ := url.Parse(rawURL)
|
||||
q := parsed.Query()
|
||||
|
||||
// 收集所有参数并按 key 排序
|
||||
keys := make([]string, 0, len(q))
|
||||
for k := range q {
|
||||
if k == "sign" {
|
||||
continue
|
||||
}
|
||||
keys = append(keys, k)
|
||||
}
|
||||
sort.Strings(keys)
|
||||
|
||||
var signStr string
|
||||
for _, k := range keys {
|
||||
signStr += k + "=" + q.Get(k) + "&"
|
||||
}
|
||||
signStr += "key=" + appSecret
|
||||
|
||||
var sign string
|
||||
switch signAlgo {
|
||||
case "md5":
|
||||
h := md5.Sum([]byte(signStr))
|
||||
sign = hex.EncodeToString(h[:])
|
||||
case "md5_upper":
|
||||
h := md5.Sum([]byte(signStr))
|
||||
sign = strings.ToUpper(hex.EncodeToString(h[:]))
|
||||
default:
|
||||
return rawURL
|
||||
}
|
||||
|
||||
q.Set("sign", sign)
|
||||
parsed.RawQuery = q.Encode()
|
||||
return parsed.String()
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user