zencoder / internal /handler /external.go
wzxwhxcz's picture
Upload 9 files
3516e13 verified
package handler
import (
"fmt"
"log"
"net/http"
"strings"
"time"
"github.com/gin-gonic/gin"
"zencoder-2api/internal/database"
"zencoder-2api/internal/model"
"zencoder-2api/internal/service"
)
type ExternalHandler struct{}
func NewExternalHandler() *ExternalHandler {
return &ExternalHandler{}
}
// ExternalTokenRequest 外部API提交token请求结构
type ExternalTokenRequest struct {
AccessToken string `json:"access_token"` // OAuth获取的access_token
RefreshToken string `json:"refresh_token"` // OAuth获取的refresh_token
Proxy string `json:"proxy"` // 可选的代理设置
}
// ExternalTokenResponse 外部API响应结构
type ExternalTokenResponse struct {
Success bool `json:"success"`
Message string `json:"message"`
Account *model.Account `json:"account,omitempty"`
Error string `json:"error,omitempty"`
}
// SubmitTokens 外部API接口:接收OAuth token信息并生成账号记录
func (h *ExternalHandler) SubmitTokens(c *gin.Context) {
var req ExternalTokenRequest
if err := c.ShouldBindJSON(&req); err != nil {
c.JSON(http.StatusBadRequest, ExternalTokenResponse{
Success: false,
Error: "请求格式错误: " + err.Error(),
})
return
}
// 验证必要字段
if req.AccessToken == "" && req.RefreshToken == "" {
c.JSON(http.StatusBadRequest, ExternalTokenResponse{
Success: false,
Error: "必须提供 access_token 或 refresh_token",
})
return
}
log.Printf("[外部API] 收到token提交请求,access_token长度: %d, refresh_token长度: %d",
len(req.AccessToken), len(req.RefreshToken))
// 优先使用 access_token,如果同时提供了两个字段
var masterToken string
if req.AccessToken != "" {
// 直接使用提供的 access_token
masterToken = req.AccessToken
log.Printf("[外部API] 使用提供的 access_token")
} else {
// 使用 refresh_token 获取 access_token
tokenResp, err := service.RefreshAccessToken(req.RefreshToken, req.Proxy)
if err != nil {
c.JSON(http.StatusBadRequest, ExternalTokenResponse{
Success: false,
Error: "RefreshToken 无效: " + err.Error(),
})
return
}
masterToken = tokenResp.AccessToken
log.Printf("[外部API] 通过 RefreshToken 获取了 access_token")
}
log.Printf("[外部API] 开始生成账号凭证")
// 生成凭证
cred, err := service.GenerateCredential(masterToken)
if err != nil {
c.JSON(http.StatusInternalServerError, ExternalTokenResponse{
Success: false,
Error: fmt.Sprintf("生成失败: %v", err),
})
return
}
log.Printf("[外部API] 凭证生成成功: ClientID=%s", cred.ClientID)
// 创建账号
account := model.Account{
ClientID: cred.ClientID,
ClientSecret: cred.Secret,
Proxy: req.Proxy,
IsActive: true,
Status: "normal",
}
// 使用生成的client_id和client_secret获取token,带重试机制
// 使用OAuth client credentials方式刷新token,使用 https://fe.zencoder.ai/oauth/token
maxRetries := 3
retryDelay := 2 * time.Second
var lastErr error
for attempt := 1; attempt <= maxRetries; attempt++ {
log.Printf("[外部API] 尝试获取token,第 %d/%d 次", attempt, maxRetries)
if _, err := service.RefreshToken(&account); err != nil {
lastErr = err
log.Printf("[外部API] 第 %d 次获取token失败: %v", attempt, err)
if attempt < maxRetries {
log.Printf("[外部API] 等待 %v 后重试", retryDelay)
time.Sleep(retryDelay)
continue
}
} else {
log.Printf("[外部API] 第 %d 次获取token成功", attempt)
lastErr = nil
break
}
}
if lastErr != nil {
c.JSON(http.StatusBadRequest, ExternalTokenResponse{
Success: false,
Error: fmt.Sprintf("认证失败(重试 %d 次后): %v", maxRetries, lastErr),
})
return
}
// 解析 Token 获取详细信息
if payload, err := service.ParseJWT(account.AccessToken); err == nil {
account.Email = payload.Email
account.SubscriptionStartDate = service.GetSubscriptionDate(payload)
if payload.Expiration > 0 {
account.TokenExpiry = time.Unix(payload.Expiration, 0)
}
plan := payload.CustomClaims.Plan
if plan != "" {
plan = strings.ToUpper(plan[:1]) + plan[1:]
}
if plan != "" {
account.PlanType = model.PlanType(plan)
}
}
if account.PlanType == "" {
account.PlanType = model.PlanFree
}
// 检查是否已存在
var existing model.Account
var count int64
database.GetDB().Model(&model.Account{}).Where("client_id = ?", account.ClientID).Count(&count)
if count > 0 {
// 获取现有账号
database.GetDB().Where("client_id = ?", account.ClientID).First(&existing)
// 更新现有账号
existing.AccessToken = account.AccessToken
existing.TokenExpiry = account.TokenExpiry
existing.PlanType = account.PlanType
existing.Email = account.Email
existing.SubscriptionStartDate = account.SubscriptionStartDate
existing.IsActive = true
existing.Status = "normal" // 重新激活
existing.ClientSecret = account.ClientSecret
if account.Proxy != "" {
existing.Proxy = account.Proxy
}
if err := database.GetDB().Save(&existing).Error; err != nil {
c.JSON(http.StatusInternalServerError, ExternalTokenResponse{
Success: false,
Error: fmt.Sprintf("更新失败: %v", err),
})
return
}
log.Printf("[外部API] 账号更新成功: ClientID=%s, Email=%s, Plan=%s", existing.ClientID, existing.Email, existing.PlanType)
c.JSON(http.StatusOK, ExternalTokenResponse{
Success: true,
Message: "账号更新成功",
Account: &existing,
})
} else {
// 创建新账号
if err := database.GetDB().Create(&account).Error; err != nil {
c.JSON(http.StatusInternalServerError, ExternalTokenResponse{
Success: false,
Error: fmt.Sprintf("创建失败: %v", err),
})
return
}
log.Printf("[外部API] 新账号创建成功: ClientID=%s, Email=%s, Plan=%s", account.ClientID, account.Email, account.PlanType)
c.JSON(http.StatusCreated, ExternalTokenResponse{
Success: true,
Message: "账号创建成功",
Account: &account,
})
}
}