72 lines
1.7 KiB
Go
72 lines
1.7 KiB
Go
|
|
package fadada
|
|||
|
|
|
|||
|
|
import (
|
|||
|
|
"fmt"
|
|||
|
|
"strconv"
|
|||
|
|
"sync"
|
|||
|
|
"time"
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
// tokenCache accessToken 内存缓存(官方有效期约 2 小时)
|
|||
|
|
type tokenCache struct {
|
|||
|
|
mu sync.Mutex
|
|||
|
|
token string
|
|||
|
|
expiresAt time.Time
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
func (c *tokenCache) get() (string, bool) {
|
|||
|
|
c.mu.Lock()
|
|||
|
|
defer c.mu.Unlock()
|
|||
|
|
if c.token == "" || time.Now().After(c.expiresAt) {
|
|||
|
|
return "", false
|
|||
|
|
}
|
|||
|
|
return c.token, true
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
func (c *tokenCache) set(token string, ttl time.Duration) {
|
|||
|
|
c.mu.Lock()
|
|||
|
|
defer c.mu.Unlock()
|
|||
|
|
c.token = token
|
|||
|
|
c.expiresAt = time.Now().Add(ttl)
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// ensureAccessToken 获取可用 accessToken,过期前自动刷新
|
|||
|
|
func (c *Client) ensureAccessToken() (string, error) {
|
|||
|
|
if token, ok := c.tokenCache.get(); ok {
|
|||
|
|
return token, nil
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
c.tokenMu.Lock()
|
|||
|
|
defer c.tokenMu.Unlock()
|
|||
|
|
|
|||
|
|
if token, ok := c.tokenCache.get(); ok {
|
|||
|
|
return token, nil
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
res, err := c.http.PostToken(pathGetAccessToken)
|
|||
|
|
if err != nil {
|
|||
|
|
return "", err
|
|||
|
|
}
|
|||
|
|
if res.Code != "" && res.Code != successCode {
|
|||
|
|
return "", fmt.Errorf("获取法大大 accessToken 失败: code=%s msg=%s requestId=%s", res.Code, res.Msg, res.RequestID)
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
var data accessTokenData
|
|||
|
|
if err := decodeData(res.Data, &data); err != nil {
|
|||
|
|
return "", fmt.Errorf("解析 accessToken 失败: %w", err)
|
|||
|
|
}
|
|||
|
|
if data.AccessToken == "" {
|
|||
|
|
return "", fmt.Errorf("获取法大大 accessToken 失败: 响应为空 code=%s msg=%s", res.Code, res.Msg)
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
ttl := 2*time.Hour - 5*time.Minute
|
|||
|
|
if expiresIn, err := strconv.Atoi(data.ExpiresIn); err == nil && expiresIn > 0 {
|
|||
|
|
ttl = time.Duration(expiresIn)*time.Second - 5*time.Minute
|
|||
|
|
if ttl < time.Minute {
|
|||
|
|
ttl = time.Minute
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
c.tokenCache.set(data.AccessToken, ttl)
|
|||
|
|
return data.AccessToken, nil
|
|||
|
|
}
|