Files
dygou_go/internal/app/app_seckill.go
T

126 lines
4.2 KiB
Go

package app
import (
"time"
"douyu_go/internal/constants"
"douyu_go/internal/logger"
"douyu_go/internal/types"
"douyu_go/internal/utils"
)
const seckillStateEvent = "seckill:state"
// StartSeckill 立即启动抢购。
func (a *App) StartSeckill(accountProducts map[string]string) types.MessageResult {
// 兼容旧前端/旧构建:和平小店只能走 livebuy 专用链路,不能进入 CSRF 兑换流程。
if a.getClient().Activity.IsXiaodian {
return a.startXiaodianSeckill(types.FixedSeckillRequest{
AccountProducts: accountProducts,
}, "和平小店抢购已启动")
}
if len(accountProducts) == 0 {
return types.MessageResult{Error: "请选择账号和商品"}
}
if !a.scheduler.TryStartRun() {
return types.MessageResult{Error: "抢购任务正在运行,请勿重复提交"}
}
go a.scheduler.RunNow(utils.CloneStringMap(accountProducts))
return types.MessageResult{Success: true, Msg: "抢购已启动"}
}
// StartXiaodianSeckill 启动和平小店专用次数/间隔抢购。
func (a *App) StartXiaodianSeckill(req types.FixedSeckillRequest) types.MessageResult {
return a.startXiaodianSeckill(req, "和平小店抢购已启动")
}
// StopSeckill 停止当前正在运行的抢购任务。
func (a *App) StopSeckill() types.MessageResult {
if !a.scheduler.StopRun() {
return types.MessageResult{Success: true, Msg: "当前没有正在运行的抢购任务"}
}
return types.MessageResult{Success: true, Msg: "已发送停止指令"}
}
// GetSeckillStatus 返回当前抢购运行状态。
func (a *App) GetSeckillStatus() types.SimpleResult {
return types.SimpleResult{Success: a.scheduler.IsRunning()}
}
// StartFixedSeckill 启动和平小店固定次数/间隔抢购。
func (a *App) StartFixedSeckill(req types.FixedSeckillRequest) types.MessageResult {
return a.startXiaodianSeckill(req, "固定次数抢购已启动")
}
func (a *App) startXiaodianSeckill(req types.FixedSeckillRequest, message string) types.MessageResult {
if !a.getClient().Activity.IsXiaodian {
return types.MessageResult{Error: "固定次数抢购仅支持和平小店"}
}
if len(req.AccountProducts) == 0 {
return types.MessageResult{Error: "请选择账号和商品"}
}
if req.Attempts < 1 || req.Attempts > 100000 {
return types.MessageResult{Error: "抢购次数需在 1-100000 之间"}
}
if req.DelayMs < 0 || req.DelayMs > 60000 {
return types.MessageResult{Error: "抢购间隔需在 0-60000 毫秒之间"}
}
if !a.scheduler.TryStartRun() {
return types.MessageResult{Error: "抢购任务正在运行,请勿重复提交"}
}
go a.scheduler.RunXiaodian(utils.CloneStringMap(req.AccountProducts), req.Attempts, req.DelayMs)
return types.MessageResult{Success: true, Msg: message}
}
// SetSchedule 设置定时抢购。
func (a *App) SetSchedule(req types.SeckillRequest) (types.ScheduleResult, error) {
return a.scheduler.ScheduleRun(req)
}
// CancelSchedule 取消未触发的定时抢购。
func (a *App) CancelSchedule() types.CancelScheduleResult {
stopped := a.scheduler.CancelSchedule()
return types.CancelScheduleResult{Success: true, Stopped: stopped}
}
// GetResults 返回当前抢购结果。
func (a *App) GetResults() map[string]string {
return a.scheduler.Results()
}
// GetLogs 返回后端内存日志,支持增量获取。
func (a *App) GetLogs(since int64) types.LogsResult {
entries := a.logStore.Since(since)
nextSince := since
if len(entries) > 0 {
nextSince = entries[len(entries)-1].ID
}
return types.LogsResult{
Success: true,
Logs: entries,
Since: nextSince,
File: a.logStore.FilePath(),
}
}
// GetTime 返回服务端时间和本地时间。
func (a *App) GetTime() types.TimeResult {
serverTime, err := a.getClient().ServerTime()
source := "currentTime"
if err != nil {
source = "localFallback"
logger.LogEvent("时间", "warn", "时间接口降级: %v", err)
}
return types.TimeResult{
ServerTime: serverTime.In(constants.CST).Format("2006-01-02 15:04:05.000"),
LocalTime: time.Now().In(constants.CST).Format("2006-01-02 15:04:05.000"),
Source: source,
}
}
// ClearResults 清空抢购结果。
func (a *App) ClearResults() types.SimpleResult {
a.scheduler.ClearResults()
return types.SimpleResult{Success: true}
}