go-platform/controllers/api_getcard.go
2026-06-02 23:44:44 +08:00

215 lines
6.2 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 controllers
import (
"fmt"
"time"
"server/models"
"github.com/beego/beego/v2/client/orm"
beego "github.com/beego/beego/v2/server/web"
)
// ApiGetCardController 对外提卡接口(无需登录)
// GET /api/getcard?type=xianyu&module=cursor
type ApiGetCardController struct {
beego.Controller
}
// validPlatformTypes 支持的来源平台
var validPlatformTypes = map[string]bool{
"xianyu": true,
"pinduoduo": true,
"jingdong": true,
"douyin": true,
"local": true,
}
// validModules 支持的号池模块
var validModules = map[string]bool{
"cursor": true,
"windsurf": true,
"krio": true,
}
func (c *ApiGetCardController) cardErr(_ int, _ int, msg string) {
c.Ctx.Output.SetStatus(200)
c.Ctx.Output.Header("Content-Type", "text/plain; charset=utf-8")
_ = c.Ctx.Output.Body([]byte("error:" + msg))
}
func (c *ApiGetCardController) cardOK(text string) {
c.Ctx.Output.SetStatus(200)
c.Ctx.Output.Header("Content-Type", "text/plain; charset=utf-8")
_ = c.Ctx.Output.Body([]byte(text))
}
// GetCard 提取一张卡(不可重复提取)
// GET /api/getcard?type=xianyu&module=cursor&data_type=tk
//
// 参数:
// - type (必填) 来源平台xianyu / taobao / pinduoduo / jingdong / local
// - module (必填) 号池模块cursor / windsurf / krio
// - data_type (可选) 账号类型account / tk / account_tk不传则取任意未提取的
func (c *ApiGetCardController) GetCard() {
platform := c.GetString("type")
module := c.GetString("module")
dataType := c.GetString("data_type")
// 参数校验
if platform == "" {
c.cardErr(400, 400, "缺少参数 type来源平台")
return
}
if !validPlatformTypes[platform] {
c.cardErr(400, 400, fmt.Sprintf("不支持的平台类型: %s支持: xianyu/taobao/pinduoduo/jingdong/local", platform))
return
}
if module == "" {
c.cardErr(400, 400, "缺少参数 module号池模块")
return
}
if !validModules[module] {
c.cardErr(400, 400, fmt.Sprintf("不支持的模块: %s支持: cursor/windsurf/krio", module))
return
}
if dataType != "" && !isValidPoolType(dataType) {
c.cardErr(400, 400, "data_type 不合法,支持: account/tk/account_tk")
return
}
now := time.Now()
switch module {
case "cursor":
c.extractCursor(platform, dataType, now)
case "windsurf":
c.extractWindsurf(platform, dataType, now)
case "krio":
c.extractKrio(platform, dataType, now)
}
}
func (c *ApiGetCardController) extractCursor(platform, dataType string, now time.Time) {
c.extractWithProbe("cursor", platform, dataType, now, func() (uint64, *string, *string, string, string, *int8, error) {
var row models.PlatformAccountPoolCursor
qs := models.Orm.QueryTable(new(models.PlatformAccountPoolCursor)).
Filter("is_extracted", 0).
Filter("delete_time__isnull", true)
if dataType != "" {
qs = qs.Filter("data_type", dataType)
}
if err := qs.OrderBy("id").One(&row); err != nil {
return 0, nil, nil, "", "", nil, err
}
return row.ID, &row.Account, &row.Password, row.Token, row.DataType, row.IsUsed, nil
})
}
func (c *ApiGetCardController) extractWindsurf(platform, dataType string, now time.Time) {
c.extractWithProbe("windsurf", platform, dataType, now, func() (uint64, *string, *string, string, string, *int8, error) {
var row models.PlatformAccountPoolWindsurf
qs := models.Orm.QueryTable(new(models.PlatformAccountPoolWindsurf)).
Filter("is_extracted", 0).
Filter("delete_time__isnull", true)
if dataType != "" {
qs = qs.Filter("data_type", dataType)
}
if err := qs.OrderBy("id").One(&row); err != nil {
return 0, nil, nil, "", "", nil, err
}
return row.ID, &row.Account, &row.Password, row.Token, row.DataType, nil, nil
})
}
func (c *ApiGetCardController) extractKrio(platform, dataType string, now time.Time) {
c.extractWithProbe("krio", platform, dataType, now, func() (uint64, *string, *string, string, string, *int8, error) {
var row models.PlatformAccountPoolKiro
qs := models.Orm.QueryTable(new(models.PlatformAccountPoolKiro)).
Filter("is_extracted", 0).
Filter("delete_time__isnull", true)
if dataType != "" {
qs = qs.Filter("data_type", dataType)
}
if err := qs.OrderBy("id").One(&row); err != nil {
return 0, nil, nil, "", "", nil, err
}
return row.ID, &row.Account, &row.Password, row.Token, row.DataType, nil, nil
})
}
type poolRowFetcher func() (id uint64, account, password *string, token, rowDataType string, isUsed *int8, err error)
// extractWithProbe 按 id 顺序提取并探测 Token 可用性;不可用则标记已提取并继续下一条。
func (c *ApiGetCardController) extractWithProbe(
module, platform, dataType string,
now time.Time,
fetch poolRowFetcher,
) {
for {
id, account, password, token, rowDataType, isUsed, err := fetch()
if err != nil {
if err == orm.ErrNoRows {
c.cardErr(404, 404, "暂无可用卡密")
} else {
c.cardErr(500, 500, "查询失败")
}
return
}
tableName := poolTableName(module)
if tableName == "" {
c.cardErr(500, 500, "无效模块")
return
}
_, err = models.Orm.QueryTable(tableName).
Filter("id", id).
Update(map[string]interface{}{
"is_extracted": 1,
"extracted_time": now,
"extracted_platform": platform,
"update_time": now,
})
if err != nil {
c.cardErr(500, 500, "提取失败")
return
}
// 已有探测结论:可用则直接返回,不可用则继续下一条。
if known, available := poolIsUsedAvailable(isUsed); known {
if available {
c.cardOK(buildCardResult(account, password, token, rowDataType))
return
}
continue
}
if !poolProbeToken(module, rowDataType, token, id) {
continue
}
c.cardOK(buildCardResult(account, password, token, rowDataType))
return
}
}
// buildCardResult 根据账号类型返回格式化字符串
func buildCardResult(account, password *string, token string, dataType string) string {
acc := ""
pwd := ""
if account != nil {
acc = *account
}
if password != nil {
pwd = *password
}
switch dataType {
case "account":
return fmt.Sprintf("账号:%s / 密码:%s", acc, pwd)
case "account_tk":
return fmt.Sprintf("账号:%s / 密码:%s / Token%s", acc, pwd, token)
default: // tk
return token
}
}