131 lines
3.1 KiB
Go
131 lines
3.1 KiB
Go
package sniper
|
|
|
|
import (
|
|
"context"
|
|
"strings"
|
|
"sync"
|
|
"time"
|
|
|
|
"huya-go/internal/huya"
|
|
)
|
|
|
|
type Account struct {
|
|
UID int64 `json:"uid"`
|
|
Cookie string `json:"-"`
|
|
}
|
|
|
|
type Target struct {
|
|
PID int32 `json:"pid"`
|
|
Name string `json:"name"`
|
|
}
|
|
|
|
type Config struct {
|
|
SID int32
|
|
Loops int
|
|
Delay time.Duration
|
|
Concurrency int
|
|
StopAfterSuccess bool
|
|
}
|
|
|
|
type Result struct {
|
|
Loop int `json:"loop"`
|
|
UID int64 `json:"uid"`
|
|
Action string `json:"action"`
|
|
Prize *huya.PrizeInfo `json:"prize,omitempty"`
|
|
Exchange *huya.ScoreExchangePrizeResp `json:"exchange,omitempty"`
|
|
Error string `json:"error,omitempty"`
|
|
}
|
|
|
|
type Runner struct {
|
|
Client huya.ActivityClient
|
|
}
|
|
|
|
func (r *Runner) Run(ctx context.Context, accounts []Account, target Target, cfg Config, emit func(Result)) error {
|
|
if cfg.Loops <= 0 {
|
|
cfg.Loops = 1
|
|
}
|
|
if cfg.Delay <= 0 {
|
|
cfg.Delay = 150 * time.Millisecond
|
|
}
|
|
if cfg.Concurrency <= 0 {
|
|
cfg.Concurrency = 1
|
|
}
|
|
var client huya.ActivityClient = r.Client
|
|
if client == nil {
|
|
client = huya.NewHTTPClient(nil)
|
|
}
|
|
|
|
ctx, cancel := context.WithCancel(ctx)
|
|
defer cancel()
|
|
|
|
for loop := 1; loop <= cfg.Loops; loop++ {
|
|
if ctx.Err() != nil {
|
|
return ctx.Err()
|
|
}
|
|
sem := make(chan struct{}, cfg.Concurrency)
|
|
var wg sync.WaitGroup
|
|
for _, account := range accounts {
|
|
account := account
|
|
wg.Add(1)
|
|
go func() {
|
|
defer wg.Done()
|
|
select {
|
|
case sem <- struct{}{}:
|
|
defer func() { <-sem }()
|
|
case <-ctx.Done():
|
|
return
|
|
}
|
|
result := r.tryAccount(ctx, client, account, target, cfg.SID, loop)
|
|
if emit != nil {
|
|
emit(result)
|
|
}
|
|
if cfg.StopAfterSuccess && result.Exchange != nil && result.Exchange.Success() {
|
|
cancel()
|
|
}
|
|
}()
|
|
}
|
|
wg.Wait()
|
|
if ctx.Err() != nil {
|
|
return ctx.Err()
|
|
}
|
|
if loop < cfg.Loops {
|
|
timer := time.NewTimer(cfg.Delay)
|
|
select {
|
|
case <-timer.C:
|
|
case <-ctx.Done():
|
|
timer.Stop()
|
|
return ctx.Err()
|
|
}
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (r *Runner) tryAccount(ctx context.Context, client huya.ActivityClient, account Account, target Target, sid int32, loop int) Result {
|
|
list, err := client.GetActPrizeList(ctx, account.UID, account.Cookie, sid)
|
|
if err != nil {
|
|
return Result{Loop: loop, UID: account.UID, Action: "list_error", Error: err.Error()}
|
|
}
|
|
prize := matchPrize(list.Prizes, target)
|
|
if prize == nil {
|
|
return Result{Loop: loop, UID: account.UID, Action: "not_found"}
|
|
}
|
|
exchange, err := client.ScoreExchangePrize(ctx, account.UID, account.Cookie, sid, int32(prize.ID))
|
|
if err != nil {
|
|
return Result{Loop: loop, UID: account.UID, Action: "exchange_error", Prize: prize, Error: err.Error()}
|
|
}
|
|
return Result{Loop: loop, UID: account.UID, Action: "exchange", Prize: prize, Exchange: exchange}
|
|
}
|
|
|
|
func matchPrize(prizes []huya.PrizeInfo, target Target) *huya.PrizeInfo {
|
|
for i := range prizes {
|
|
if target.PID > 0 && int32(prizes[i].ID) == target.PID {
|
|
return &prizes[i]
|
|
}
|
|
if target.PID == 0 && target.Name != "" && strings.Contains(prizes[i].Name, target.Name) {
|
|
return &prizes[i]
|
|
}
|
|
}
|
|
return nil
|
|
}
|