Spaces:
Sleeping
Sleeping
File size: 6,098 Bytes
1de7911 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 |
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,
})
}
} |