GetConfig 从不把 rock_configs.base_url 回写到客户端,main.go 又硬编码了 https://0666.pro,导致后台改上游地址「保存那一刻生效、进程重启后失效」, 数据库里的值被静默忽略且无任何提示。 - 新增 model.RockDefaultBaseURL 统一默认值来源 - 新增 RockService.ApplyConfigToClient,启动时把 DB 地址同步到客户端 - UpdateConfig 改用 client.SetBaseURL 立即生效,不再直接写字段 - RockClient.baseURL 原为裸字段,被 HTTP 请求线程与库存巡检 goroutine 并发 读写(数据竞争),改为 sync.RWMutex 保护并新增 BaseURL/SetBaseURL - ClaimTokens/RefreshToken/RedeemSkin 的 Origin/Referer 跟随配置地址 - 空值回落默认地址,末尾斜杠自动裁剪 为保持该提交可编译,同一次改动把 rock_service.go(1177 行)按域拆分为 8 个文件(最大 221 行):rock_service / rock_bindlink / rock_stock / rock_assign / rock_bindcheck / rock_redeem / rock_recover / rock_snapshot。 35 个声明块全部有归属,无遗漏无重复;迁移文件 012 受 checksum 保护故未改动。 验证:TestRockServiceBaseURLFromConfig 覆盖「改地址→立即生效→重启→仍生效」; 并发用例在 -race 下通过;全量测试通过。
78 lines
2.2 KiB
Go
78 lines
2.2 KiB
Go
package service
|
|
|
|
import (
|
|
"context"
|
|
"strings"
|
|
"time"
|
|
|
|
"affiliate_dash/internal/model"
|
|
)
|
|
|
|
type rockRefreshCacheItem struct {
|
|
response *RockRefreshResponse
|
|
cachedAt time.Time
|
|
}
|
|
|
|
// 腾讯活动链接按生成时间签名。同一提货号过期后重取链接,不另发新号。
|
|
const rockBindLinkMaxAge = 8 * time.Minute
|
|
|
|
type rockBindLinkCacheItem struct {
|
|
bindURL string
|
|
qrURL string
|
|
cachedAt time.Time
|
|
}
|
|
|
|
func (s *RockService) rememberBindLink(tokenID uint, bindURL, qrURL string) {
|
|
bindURL = strings.TrimSpace(bindURL)
|
|
if s == nil || tokenID == 0 || bindURL == "" {
|
|
return
|
|
}
|
|
qrURL = strings.TrimSpace(qrURL)
|
|
if qrURL == "" {
|
|
qrURL = qrCodeURL(bindURL)
|
|
}
|
|
s.bindLinkCache.Store(tokenID, rockBindLinkCacheItem{
|
|
bindURL: bindURL,
|
|
qrURL: qrURL,
|
|
cachedAt: time.Now(),
|
|
})
|
|
}
|
|
|
|
// freshBindLink 只为仍在扫码的同一提货号重取活动链接。过期前复用缓存,避免每轮轮询都打 0666。
|
|
func (s *RockService) freshBindLink(ctx context.Context, tokenID uint, orderNo string) (string, string) {
|
|
if s == nil || s.client == nil || tokenID == 0 {
|
|
return "", ""
|
|
}
|
|
var token model.RockToken
|
|
if err := s.db.WithContext(ctx).First(&token, tokenID).Error; err != nil {
|
|
return "", ""
|
|
}
|
|
if token.Status != model.RockStatusUsing || strings.TrimSpace(token.RedeemCode) == "" {
|
|
return "", ""
|
|
}
|
|
if orderNo = strings.TrimSpace(orderNo); orderNo != "" && token.AssignedOrderNo != "" && token.AssignedOrderNo != orderNo {
|
|
return "", ""
|
|
}
|
|
if item, ok := s.bindLinkCache.Load(token.ID); ok {
|
|
cached := item.(rockBindLinkCacheItem)
|
|
if cached.bindURL != "" && time.Since(cached.cachedAt) < rockBindLinkMaxAge {
|
|
return cached.bindURL, cached.qrURL
|
|
}
|
|
}
|
|
detail, err := s.client.GetRedeemDetail(ctx, token.RedeemCode)
|
|
if err != nil || detail == nil || strings.TrimSpace(detail.BindURL) == "" {
|
|
if item, ok := s.bindLinkCache.Load(token.ID); ok {
|
|
cached := item.(rockBindLinkCacheItem)
|
|
return cached.bindURL, cached.qrURL
|
|
}
|
|
return "", ""
|
|
}
|
|
bindURL := strings.TrimSpace(detail.BindURL)
|
|
qrURL := strings.TrimSpace(detail.QRURL)
|
|
s.rememberBindLink(token.ID, bindURL, qrURL)
|
|
if qrURL == "" {
|
|
qrURL = qrCodeURL(bindURL)
|
|
}
|
|
return bindURL, qrURL
|
|
}
|