跳转到主要内容

Documentation Index

Fetch the complete documentation index at: https://docs.liandanxia.io/llms.txt

Use this file to discover all available pages before exploring further.

API KEY / 邀请码 / 支付 代码定位

模块一:API KEY

文件名:middleware/auth.go
func TokenAuth() func(c *gin.Context) {
	return func(c *gin.Context) {
		if strings.Contains(c.Request.URL.Path, "/v1/messages") || strings.Contains(c.Request.URL.Path, "/v1/models") {
			anthropicKey := c.Request.Header.Get("x-api-key")
			if anthropicKey != "" {
				c.Request.Header.Set("Authorization", "Bearer "+anthropicKey)
			}
		}
		...
		token, err := model.ValidateUserToken(key)
		...
	}
}
作用:统一提取并兼容多种来源的 API Key(Authorization/x-api-key/x-goog-api-key/query key/WebSocket 协议头),最终走 ValidateUserToken 做用户令牌校验和权限控制。 文件名:model/token.go
type Token struct {
	UserId     int    `json:"user_id" gorm:"index"`
	Key        string `json:"key" gorm:"type:char(48);uniqueIndex"`
	RemainQuota int   `json:"remain_quota" gorm:"default:0"`
	Status     int    `json:"status" gorm:"default:1"`
	...
}

func ValidateUserToken(key string) (token *Token, err error) {
	if key == "" {
		return nil, errors.New("未提供令牌")
	}
	token, err = GetTokenByKey(key, false)
	...
	if !token.UnlimitedQuota && token.RemainQuota <= 0 {
		...
		return token, errors.New("该令牌额度已用尽")
	}
	return token, nil
}
作用:定义用户 API Token 数据模型(密钥、状态、额度、过期时间等),并负责 API Key 合法性与可用性校验(存在性、状态、过期、余额)。 文件名:controller/token.go
func AddToken(c *gin.Context) {
	token := model.Token{}
	err := c.ShouldBindJSON(&token)
	...
	key, err := common.GenerateKey()
	...
	cleanToken := model.Token{...
		Key: key,
		...
	}
	err = cleanToken.Insert()
	...
}
作用:用户侧 API Key 生命周期管理入口(创建/查询/搜索/删除等);创建时生成新 key 并持久化。 文件名:router/api-router.go
tokenRoute := apiRouter.Group("/token")
tokenRoute.Use(middleware.UserAuth())
{
	tokenRoute.GET("/", controller.GetAllTokens)
	tokenRoute.GET("/search", middleware.SearchRateLimit(), controller.SearchTokens)
	tokenRoute.GET("/:id", controller.GetToken)
	tokenRoute.POST("/", controller.AddToken)
	tokenRoute.PUT("/", controller.UpdateToken)
	tokenRoute.DELETE("/:id", controller.DeleteToken)
}
作用:暴露用户 API Key 管理接口路由。 文件名:model/channel.go
type Channel struct {
	Key string `json:"key" gorm:"not null"`
	ChannelInfo ChannelInfo `json:"channel_info" gorm:"type:json"`
}

func (channel *Channel) GetNextEnabledKey() (string, int, *types.NewAPIError) {
	if !channel.ChannelInfo.IsMultiKey {
		return channel.Key, 0, nil
	}
	...
}
作用:定义上游渠道 API Key(单 key / 多 key)以及多 key 轮询、随机、可用性选择逻辑。 文件名:relay/channel/api_request.go
func applyHeaderOverridePlaceholders(template string, c *gin.Context, apiKey string) (string, bool, error) {
	...
	if strings.Contains(template, "{api_key}") {
		template = strings.ReplaceAll(template, "{api_key}", apiKey)
	}
	...
}
作用:在转发到上游时,把渠道 API Key 注入 Header 覆盖模板(例如 {api_key} 占位符),实现各渠道鉴权头适配。

模块二:邀请码

文件名:model/user.go
type User struct {
	AffCode   string `json:"aff_code" gorm:"type:varchar(32);column:aff_code;uniqueIndex"`
	AffCount  int    `json:"aff_count" gorm:"type:int;default:0;column:aff_count"`
	AffQuota  int    `json:"aff_quota" gorm:"type:int;default:0;column:aff_quota"`
	InviterId int    `json:"inviter_id" gorm:"type:int;column:inviter_id;index"`
}

func GetUserIdByAffCode(affCode string) (int, error) {
	...
	err := DB.Select("id").First(&user, "aff_code = ?", affCode).Error
	return user.Id, err
}

func inviteUser(inviterId int) (err error) {
	...
	user.AffCount++
	user.AffQuota += common.QuotaForInviter
	...
}
作用:邀请码核心数据模型与奖励结算逻辑(邀请码反查邀请人、邀请人数统计、邀请奖励额度累加)。 文件名:model/user.go
func (user *User) Insert(inviterId int) error {
	...
	user.AffCode = common.GetRandomString(4)
	...
	if inviterId != 0 {
		if common.QuotaForInvitee > 0 {
			_ = IncreaseUserQuota(user.Id, common.QuotaForInvitee, true)
		}
		if common.QuotaForInviter > 0 {
			_ = inviteUser(inviterId)
		}
	}
	return nil
}
作用:用户注册时生成邀请码;若通过邀请码注册,则给被邀请人和邀请人分别发放奖励。 文件名:controller/user.go
func GetAffCode(c *gin.Context) {
	...
	if user.AffCode == "" {
		user.AffCode = common.GetRandomString(4)
		_ = user.Update(false)
	}
	c.JSON(http.StatusOK, gin.H{"data": user.AffCode})
}

func TransferAffQuota(c *gin.Context) {
	...
	err = user.TransferAffQuotaToQuota(tran.Quota)
	...
}
作用:提供邀请码查询/生成接口,以及“邀请额度转账户额度”接口。 文件名:router/api-router.go
selfRoute.GET("/aff", controller.GetAffCode)
selfRoute.POST("/aff_transfer", controller.TransferAffQuota)
作用:对外暴露邀请体系 API 路由。 文件名:web/src/components/auth/RegisterForm.jsx
let affCode = new URLSearchParams(window.location.search).get('aff');
if (affCode) {
  localStorage.setItem('aff', affCode);
}
...
if (!affCode) {
  affCode = localStorage.getItem('aff');
}
inputs.aff_code = affCode;
const res = await API.post(`/api/user/register?turnstile=${turnstileToken}`, inputs);
作用:前端注册页读取 URL 中 aff 参数并随注册请求提交,实现邀请关系绑定。 文件名:web/src/components/topup/index.jsx
const getAffLink = async () => {
  const res = await API.get('/api/user/aff');
  if (success) {
    let link = `${window.location.origin}/register?aff=${data}`;
    setAffLink(link);
  }
};

const transfer = async () => {
  const res = await API.post(`/api/user/aff_transfer`, { quota: transferAmount });
  ...
};
作用:前端“充值/邀请”页面展示邀请链接,并支持邀请额度划转。

模块三:支付相关

文件名:router/api-router.go
apiRouter.POST("/stripe/webhook", controller.StripeWebhook)
apiRouter.POST("/creem/webhook", controller.CreemWebhook)
...
userRoute.POST("/epay/notify", controller.EpayNotify)
userRoute.GET("/epay/notify", controller.EpayNotify)
...
selfRoute.POST("/pay", controller.RequestEpay)
selfRoute.POST("/stripe/pay", controller.RequestStripePay)
selfRoute.POST("/creem/pay", controller.RequestCreemPay)
selfRoute.GET("/topup/info", controller.GetTopUpInfo)
selfRoute.POST("/topup", controller.TopUp)
作用:定义全部充值支付入口与回调入口(易支付/Stripe/Creem),包含下单、金额计算、Webhook 回调。 文件名:model/topup.go
type TopUp struct {
	UserId        int
	Amount        int64
	Money         float64
	TradeNo       string
	PaymentMethod string
	Status        string
}

func Recharge(referenceId string, customerId string) (err error) {
	...
	if topUp.Status != common.TopUpStatusPending {
		return errors.New("充值订单状态错误")
	}
	topUp.Status = common.TopUpStatusSuccess
	...
	err = tx.Model(&User{}).Where("id = ?", topUp.UserId).Updates(... "quota": gorm.Expr("quota + ?", quota)).Error
	...
}
作用:支付订单模型与充值入账核心事务(防重复处理、更新订单状态、增加用户额度)。 文件名:controller/topup.go
func RequestEpay(c *gin.Context) {
	...
	uri, params, err := client.Purchase(&epay.PurchaseArgs{...})
	...
	topUp := &model.TopUp{...
		Status: "pending",
	}
	err = topUp.Insert()
	...
}

func EpayNotify(c *gin.Context) {
	...
	verifyInfo, err := client.Verify(params)
	...
	if verifyInfo.TradeStatus == epay.StatusTradeSuccess {
		LockOrder(verifyInfo.ServiceTradeNo)
		defer UnlockOrder(verifyInfo.ServiceTradeNo)
		topUp := model.GetTopUpByTradeNo(verifyInfo.ServiceTradeNo)
		...
		err = model.IncreaseUserQuota(topUp.UserId, quotaToAdd, true)
	}
}
作用:易支付下单与异步回调处理(签名校验、订单加锁幂等、成功后加额度)。 文件名:controller/topup_stripe.go
func (*StripeAdaptor) RequestPay(c *gin.Context, req *StripePayRequest) {
	...
	payLink, err := genStripeLink(referenceId, user.StripeCustomer, user.Email, req.Amount, req.SuccessURL, req.CancelURL)
	...
	topUp := &model.TopUp{...
		PaymentMethod: PaymentMethodStripe,
		Status:        common.TopUpStatusPending,
	}
	...
}

func StripeWebhook(c *gin.Context) {
	payload, _ := io.ReadAll(c.Request.Body)
	event, err := webhook.ConstructEventWithOptions(payload, signature, endpointSecret, ...)
	...
}
作用:Stripe 支付链接创建与 Webhook 验签/事件处理。 文件名:controller/topup_creem.go
func RequestCreemPay(c *gin.Context) {
	...
	err = c.ShouldBindJSON(&req)
	...
	creemAdaptor.RequestPay(c, &req)
}

// CreemWebhookEvent ...
作用:Creem 下单入口与 webhook 事件结构解析,配合后续回调处理完成订单入账。 文件名:web/src/components/topup/index.jsx
const onlineTopUp = async () => {
  ...
  if (payWay === 'stripe') {
    res = await API.post('/api/user/stripe/pay', {...});
  } else {
    res = await API.post('/api/user/pay', {...});
  }
  ...
  if (payWay === 'stripe') {
    window.open(data.pay_link, '_blank');
  } else {
    // 提交表单到三方支付
    form.submit();
  }
};
作用:前端统一支付提交流程(按支付渠道调用不同接口并跳转支付页)。 文件名:web/src/components/topup/modals/PaymentConfirmModal.jsx
<Modal
  title={t('充值确认')}
  onOk={onlineTopUp}
>
  ...
  <Text>{t('支付方式')}</Text>
</Modal>
作用:支付确认弹窗,承接最终支付动作触发。