Files
huya-go/internal/sniper/category.go
T
yml2213 6e5beac151 refactor(sniper): 对齐 dygou_go 调度架构,增加双时间日志并解耦预热
- 抢购调度重构:参考 dygou_go 将 sniper 拆分为独立子模块(runner/run_control/retry/exchange/classify/config/summary/category/helpers);移除全局自适应降速与轮次上限,采用账号独立循环、统一账号级退避、单请求并发闸门与首发错峰
- 预热与建连优化:默认关闭预热(避免单账号超时连坐整机开抢),开启时转为后台非阻塞协程;WebSocket 握手超时从 10s 降至 1500ms
- 双时间日志:logger 增加 SetServerOffset,校准后日志前缀自动渲染「本地时间(H虎牙估算时间)」,实现跨机器绝对毫秒对齐
- 默认配置调优:版本提升至 v0.5.0,默认线程调为 2(缓解多实例并发限流),前端自动平滑迁移
- 验证方式:go test ./... -count=1 全通,npm run build 构建正常,单测覆盖双时间与预热配置
2026-10-17 18:29:17 +08:00

88 lines
2.3 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 sniper
import (
"fmt"
"strconv"
"strings"
)
// TargetSummary 把目标列表渲染成「13437(冠军之刃)」这样的单行摘要,供启动日志使用。
//
// 2026-10-16 的复盘正卡在「日志里没有目标 pid」:三台机器都只记了 sid 与 targets=1,
// 看不出各自打的是哪个奖品,也就无法解释为什么一台售罄、另一台库存完好。
func TargetSummary(targets []Target) string {
parts := make([]string, 0, len(targets))
for _, target := range targets {
name := strings.TrimSpace(target.Name)
switch {
case target.PID > 0 && name != "":
parts = append(parts, fmt.Sprintf("%d(%s)", target.PID, name))
case target.PID > 0:
parts = append(parts, strconv.FormatInt(int64(target.PID), 10))
case name != "":
parts = append(parts, name)
case target.Auto:
parts = append(parts, "自动选择")
}
}
if len(parts) == 0 {
return "未指定"
}
return strings.Join(parts, ",")
}
// CategoryLabel 返回结局分类的中文短标签,供任务结束时的结局日志使用。
func CategoryLabel(category string) string {
switch category {
case CategorySuccess:
return "已抢到"
case CategorySoldOut:
return "售罄"
case CategoryTooFrequent:
return "被限流"
case CategoryNotOpen:
return "未开放"
case CategoryNotEnough:
return "积分不足"
case CategoryAlreadyDone:
return "已兑换过"
case CategoryOffShelf:
return "已下架"
case CategorySessionLost:
return "会话失效"
case CategoryProtocol:
return "协议异常"
case CategoryCondition:
return "条件未达成"
case CategoryNotFound:
return "未匹配到奖品"
case CategoryError:
return "请求异常"
default:
return "失败"
}
}
// CategoryText 把类目限制渲染成日志文案(空串表示不限类目)。
func CategoryText(category string) string {
key := strings.TrimSpace(category)
if key == "" {
return "不限"
}
return key
}
// LogLevelForCategory 把结果分类映射成日志等级,供界面按等级高亮与筛选。
func LogLevelForCategory(category string) string {
switch category {
case CategorySuccess:
return "success"
case CategoryError, CategoryProtocol:
return "error"
case CategoryFailed, CategoryTooFrequent, CategoryCondition, CategorySessionLost:
return "warn"
default:
return "info"
}
}