Files
dygou_go/types.go
T
2026-06-19 23:22:20 +08:00

211 lines
4.1 KiB
Go

package main
import (
"encoding/json"
"io"
"net/http"
"sync"
"time"
"github.com/golang/freetype/truetype"
)
type Config struct {
TimeAPIURL string `json:"timeApiUrl"`
}
type appPaths struct {
ConfigFile string
AccountFile string
LogDir string
SuccessDir string
FontFiles []string
}
type TraceConfig struct {
Enabled bool
MaxBodyBytes int
}
type Account struct {
Name string `json:"name"`
Password string `json:"password"`
Cookie string `json:"cookie"`
}
type Product struct {
CommodityID string `json:"commodityId"`
CommodityName string `json:"commodityName"`
Score int `json:"score"`
Count int `json:"count"`
Pic string `json:"pic"`
Status int `json:"status"`
OpenStatus int `json:"openStatus"`
StoreStatus int `json:"storeStatus"`
TimeLimited int `json:"timeLimited"`
CountLimited int `json:"countLimited"`
EliteLimited int `json:"eliteLimited"`
}
type ProductPayload struct {
Success bool `json:"success"`
Source string `json:"source"`
Products []Product `json:"products"`
Count int `json:"count"`
FetchedAt string `json:"fetchedAt"`
AgeSecond int `json:"ageSecond"`
Stale bool `json:"stale"`
}
type AccountView struct {
Index int `json:"index"`
Name string `json:"name"`
Cookie string `json:"cookie"`
}
type SeckillRequest struct {
AccountProducts map[string]string `json:"accountProducts"`
TargetTime string `json:"targetTime"`
Advance int `json:"advance"`
}
type APIResponse struct {
Error int `json:"error"`
Msg string `json:"msg"`
Data json.RawMessage `json:"data"`
}
type LogEntry struct {
ID int64 `json:"id"`
Time string `json:"time"`
Level string `json:"level"`
Category string `json:"category"`
Message string `json:"message"`
}
type appState struct {
config Config
paths appPaths
client *DouyuClient
logs *memoryLogStore
trace *traceRecorder
accountsMu sync.RWMutex
accounts []Account
productsMu sync.RWMutex
products []Product
productsAt time.Time
resultsMu sync.RWMutex
results map[string]string
scheduleMu sync.Mutex
schedule *time.Timer
warmupSchedule *time.Timer
resyncSchedule *time.Timer
warmupsMu sync.RWMutex
warmups map[string]WarmupData
fontMu sync.Mutex
font *truetype.Font
}
type DouyuClient struct {
httpClient *http.Client
timeAPIURL string
trace *traceRecorder
}
type traceRecorder struct {
enabled bool
maxBodyBytes int
writer *asyncLogWriter
filePath string
seq uint64
}
type asyncLogWriter struct {
dst io.Writer
ch chan []byte
wg sync.WaitGroup
closed uint32
dropped uint64
}
type ExchangeAttempt struct {
Account Account
Product Product
Index int
}
type ExchangeResult struct {
OK bool
Account string
Product string
Attempt int
RoleName string
Message string
}
type TimeSample struct {
ServerTime time.Time
LocalTime time.Time
RTT time.Duration
Offset time.Duration
ErrorBound time.Duration
RawCurrentTime int64
Samples int
Source string
Fallback bool
}
type TimeCalibration struct {
Offset time.Duration
ErrorBound time.Duration
RTT time.Duration
Samples int
CreatedAt time.Time
Source string
Fallback bool
}
func (c TimeCalibration) EstimatedServerNow() time.Time {
if c.CreatedAt.IsZero() {
return time.Now().UTC()
}
return time.Now().Add(c.Offset).UTC()
}
func (c TimeCalibration) IsZero() bool {
return c.CreatedAt.IsZero()
}
type WarmupData struct {
CSRF string
RoleName string
CreatedAt time.Time
}
// EstimatedServerNow 根据采样偏移估算当前斗鱼时间。
func (t TimeSample) EstimatedServerNow() time.Time {
if t.LocalTime.IsZero() {
return t.ServerTime
}
return time.Now().Add(t.Offset).UTC()
}
type memoryLogStore struct {
mu sync.RWMutex
nextID int64
max int
filePath string
entries []LogEntry
}
var state = &appState{
config: Config{TimeAPIURL: defaultTimeAPI},
results: make(map[string]string),
}