Files
dygou_go/internal/activity/activity.go
T
yml2213 3ae9cb4a42 重构: 活动热切换并发安全 + 代码清理优化
- 活动切换并发安全:App/Scheduler 增加 client/cfg 读写锁与快照访问,
  支持运行中热替换客户端,切换活动不再静默覆盖用户自定义 timeApiUrl
- 启动失败时写入崩溃日志文件便于事后排查
- 前端类型声明从 Wails 自动生成的绑定派生,避免手写契约漂移
- 提取 parseAccountFile 消除 ExportAccounts/OrganizeAccounts 重复解析逻辑
- 删除 utils 中未使用的 ReadJSON/WriteJSON/WriteError 及空目录 internal/app
- gofmt 统一格式化(activity/types/scheduler 字段对齐)
- 新增 logger/seckill/utils 单元测试
- 清理 git 中遗留产物(frontend/app.js、yml.txt、其他日志/)并补全 .gitignore
2026-07-29 12:33:16 +08:00

121 lines
4.7 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package activity
import "douyu_go/internal/constants"
// Activity 描述一个斗鱼手册活动的全部接口参数。
//
// 不同活动(精英手册 / 电竞手册)的 manualID、roomID、actAlias 以及接口路径段都不同,
// 集中在这里可以让调度核心逻辑保持活动无关,新增活动只需在 registry 中加一项。
//
// 注意:peacematch 的 exchange / preExchange / batchExchangeLimit / storedetail 端点
// 没有出现在抓包里,这里按 peace 的 1:1 路径映射推断(storehome、exchangeList 已验证
// 确实落在 peacematch 路径下)。若实际抢购报错,优先核对这几个端点。
type Activity struct {
ID string // 注册表 key,例如 "peace" / "peacematch"
DisplayName string // 前端展示名
ManualID string
RoomID string
ActAlias string
BaseURL string
ShopReferer string
StoreHomeURL string
CSRFURL string
BatchLimitURL string
PreExchangeURL string
ExchangeURL string
ExchangeListURL string
BindInfoURL string
ScoreURL string
ScoreMethod string // "POST" 或 "GET"
// UseCTN 为 true 时(电竞手册),兑换接口用 ctn(acf_ccn) 鉴权而非 csrfToken:
// - 表单发 ctn 字段(值=acf_ccn),不发 csrfToken
// - cvl_csrf_token 只放 Cookie 头
// - 跳过 batchExchangeLimit / preExchange(Python 实现直接调 exchange)
// - Content-Type 用 application/x-www-form-urlencoded
UseCTN bool
CTNURL string // 获取 acf_ccn 的接口(UseCTN=true 时必填)
}
const douyuBase = constants.BaseURL
// peace 精英手册(旧活动,ActAlias=20260120QYOOB)。
var peace = &Activity{
ID: "peace",
DisplayName: "精英手册",
ManualID: "G4KA4Qnz4LDp7",
RoomID: "9263298",
ActAlias: "20260120QYOOB",
BaseURL: douyuBase,
ShopReferer: douyuBase + "/pages/live-peace-handbook/web/shop?ditchname=pass0&roomId=9263298",
StoreHomeURL: douyuBase + "/wgapi/ordnc/activity/peace/storehome?manualID=G4KA4Qnz4LDp7&rid=9263298",
CSRFURL: douyuBase + "/japi/carnival/nc/common/generateCsrf",
BatchLimitURL: douyuBase + "/wgapi/ordnc/activity/peace/batchExchangeLimit",
PreExchangeURL: douyuBase + "/wgapi/ordnc/activity/peace/preExchange",
ExchangeURL: douyuBase + "/wgapi/ordnc/activity/peace/exchange",
ExchangeListURL: douyuBase + "/wgapi/ordnc/activity/peace/exchangeList?manualID=G4KA4Qnz4LDp7&limit=100&offset=0",
BindInfoURL: douyuBase + "/japi/carnivalApi/v2/tencent/bindInfo?actAlias=20260120QYOOB",
ScoreURL: douyuBase + "/japi/oms/web/peace/credit/balance",
ScoreMethod: "POST",
UseCTN: false,
}
// peacematch 电竞手册(新活动,ActAlias=20260226ZMGDG)。
// 数据来源:/Users/yml/Desktop/抓包/douyu/7.29/电竞手册-基础信息.har 及 7.28 系列抓包。
var peacematch = &Activity{
ID: "peacematch",
DisplayName: "电竞手册",
ManualID: "1W0yGkOdDbAXb",
RoomID: "9263298",
ActAlias: "20260226ZMGDG",
BaseURL: douyuBase,
ShopReferer: douyuBase + "/pages/live-peace-pel/web/shop?roomId=9263298&isAnchorSide=0",
StoreHomeURL: douyuBase + "/wgapi/ordnc/activity/peacematch/storehome?manualID=1W0yGkOdDbAXb&rid=9263298",
// generateCsrf 为嘉年华平台级接口,抓包未单独出现,沿用 peace 同款端点。
CSRFURL: douyuBase + "/japi/carnival/nc/common/generateCsrf",
// 以下 4 个兑换类端点未在抓包中捕获,按 peace 的 1:1 路径映射推断,待实跑验证。
BatchLimitURL: douyuBase + "/wgapi/ordnc/activity/peacematch/batchExchangeLimit",
PreExchangeURL: douyuBase + "/wgapi/ordnc/activity/peacematch/preExchange",
ExchangeURL: douyuBase + "/wgapi/ordnc/activity/peacematch/exchange",
ExchangeListURL: douyuBase + "/wgapi/ordnc/activity/peacematch/exchangeList?manualID=1W0yGkOdDbAXb&limit=100&offset=0",
BindInfoURL: douyuBase + "/wgapi/ordnc/live/memberthird/tencent/bindInfo?actAlias=20260226ZMGDG",
ScoreURL: douyuBase + "/wgapi/ordnc/activity/peacematch/score/balance",
ScoreMethod: "GET",
UseCTN: true,
CTNURL: douyuBase + "/curl/csrfNlApi/getCsrfCookie",
}
var registry = map[string]*Activity{
peace.ID: peace,
peacematch.ID: peacematch,
}
// DefaultActivityID 默认活动,新分支默认启用「电竞手册」。
const DefaultActivityID = "peacematch"
// List 返回所有注册活动,按注册顺序(精英手册在前)。
func List() []*Activity {
return []*Activity{peace, peacematch}
}
// Get 按 ID 获取活动;不存在时返回 nil。
func Get(id string) *Activity {
if id == "" {
return nil
}
return registry[id]
}
// Default 返回默认活动。
func Default() *Activity {
if a := registry[DefaultActivityID]; a != nil {
return a
}
return peace
}