补全过滤入口与直接兑换,优化兑换分类和 WSS 建连

- GUI 接线 Exchange 绑定:新增「直接兑换」按钮,结果带 category/message 并进入结果面板
- 补 -max-price/-min-left(CLI 与 GUI 设置),Target 的价格与库存过滤不再悬空
- 删除死代码 sendUpdateUserInfo 及其请求结构体(浏览器流程不含该帧)
- ClassifyExchange 改为多路判定:合并 msg/actPreCondition/exchangeInfo 文案,status=200 且有 orderId 视为成功,新增 condition 分类(precondition 门禁)
- WSS 建连改为锁外 dial、锁内注册,同 uid 并发调用共享一次握手
- 默认传输层统一为 http(CLI/GUI/README),.gitignore 忽略 .DS_Store
- 同步 Wails 依赖升级(2.12.0 -> 2.15.0)并重新生成前端绑定
This commit is contained in:
yml2213
2026-10-13 19:57:08 +08:00
parent 72d59670d4
commit e8bb4eb571
13 changed files with 411 additions and 120 deletions
+21 -6
View File
@@ -48,6 +48,8 @@ type Config struct {
PID int32 `json:"pid"`
Name string `json:"name"`
TargetText string `json:"targetText"`
MaxPrice int64 `json:"maxPrice"`
MinLeft int64 `json:"minLeft"`
CookieText string `json:"cookieText"`
SelectedAccountLines []int `json:"selectedAccountLines"`
Loops int `json:"loops"`
@@ -103,9 +105,11 @@ type RecordResult struct {
}
type ExchangeResult struct {
UID int64 `json:"uid"`
Resp *huya.ScoreExchangePrizeResp `json:"resp,omitempty"`
Error string `json:"error,omitempty"`
UID int64 `json:"uid"`
Resp *huya.ScoreExchangePrizeResp `json:"resp,omitempty"`
Category string `json:"category,omitempty"`
Message string `json:"message,omitempty"`
Error string `json:"error,omitempty"`
}
type MonitorState struct {
@@ -138,7 +142,7 @@ func (a *App) Shutdown(ctx context.Context) {
func (a *App) DefaultConfig() Config {
return Config{
Transport: "wss",
Transport: "http",
WSSHost: huya.DefaultWSSHost,
SID: 2203,
Loops: 20,
@@ -296,7 +300,13 @@ func (a *App) Exchange(cfg Config) ([]ExchangeResult, error) {
ctx, cancel := requestContext(cfg.TimeoutSec)
defer cancel()
resp, err := client.ScoreExchangePrize(ctx, account.UID, account.Cookie, cfg.SID, cfg.PID)
results[i] = ExchangeResult{UID: account.UID, Resp: resp, Error: errorString(err)}
results[i] = ExchangeResult{
UID: account.UID,
Resp: resp,
Category: sniper.ClassifyExchange(resp, err),
Message: sniper.ExchangeMessage(resp),
Error: errorString(err),
}
})
a.addLog("info", "直接兑换完成: sid=%d pid=%d accounts=%d", cfg.SID, cfg.PID, len(accounts))
return results, nil
@@ -530,7 +540,7 @@ func (a *App) emit(event string, data any) {
func normalizeConfig(cfg Config) Config {
if strings.TrimSpace(cfg.Transport) == "" {
cfg.Transport = "wss"
cfg.Transport = "http"
}
if strings.TrimSpace(cfg.WSSHost) == "" {
cfg.WSSHost = huya.DefaultWSSHost
@@ -582,6 +592,11 @@ func parseTargets(cfg Config) []sniper.Target {
}
targets = append(targets, sniper.Target{Name: item})
}
// 价格/库存过滤对所有目标统一生效,避免逐处重复赋值。
for i := range targets {
targets[i].MaxPrice = cfg.MaxPrice
targets[i].MinLeft = cfg.MinLeft
}
return targets
}
+32
View File
@@ -98,3 +98,35 @@ func TestAddLogDoesNotBlockWhenQueueIsFull(t *testing.T) {
t.Fatalf("droppedLogs = %d, want 1", dropped)
}
}
func TestParseTargetsAppliesPriceAndInventoryFilters(t *testing.T) {
targets := parseTargets(Config{
PID: 12889,
Name: "小黄鸭",
TargetText: "13001\nauto",
AutoSelect: true,
MaxPrice: 1000,
MinLeft: 2,
})
if len(targets) != 4 {
t.Fatalf("targets=%d, want 4", len(targets))
}
for _, target := range targets {
if target.MaxPrice != 1000 {
t.Fatalf("target %+v maxPrice=%d, want 1000", target, target.MaxPrice)
}
if target.MinLeft != 2 {
t.Fatalf("target %+v minLeft=%d, want 2", target, target.MinLeft)
}
}
}
func TestParseTargetsWithoutFiltersKeepsZeroValues(t *testing.T) {
targets := parseTargets(Config{PID: 12889})
if len(targets) != 1 {
t.Fatalf("targets=%d, want 1", len(targets))
}
if targets[0].MaxPrice != 0 || targets[0].MinLeft != 0 {
t.Fatalf("unexpected filters: %+v", targets[0])
}
}