Files
codexautopool/backend/internal/api/codex_proxy.go

231 lines
5.8 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 api
import (
"encoding/json"
"net/http"
"strconv"
"strings"
"codex-pool/internal/database"
"codex-pool/internal/proxyutil"
)
// HandleCodexProxies 处理代理池请求
func HandleCodexProxies(w http.ResponseWriter, r *http.Request) {
switch r.Method {
case http.MethodGet:
listCodexProxies(w, r)
case http.MethodPost:
if strings.HasSuffix(r.URL.Path, "/test") {
testCodexProxy(w, r)
return
}
addCodexProxy(w, r)
case http.MethodDelete:
deleteCodexProxy(w, r)
case http.MethodPut:
toggleCodexProxy(w, r)
default:
Error(w, http.StatusMethodNotAllowed, "方法不允许")
}
}
// listCodexProxies 获取代理列表
func listCodexProxies(w http.ResponseWriter, r *http.Request) {
proxies, err := database.Instance.GetCodexProxies()
if err != nil {
Error(w, http.StatusInternalServerError, "获取代理列表失败: "+err.Error())
return
}
stats := database.Instance.GetCodexProxyStats()
Success(w, map[string]interface{}{
"proxies": proxies,
"stats": stats,
})
}
// AddProxyRequest 添加代理请求
type AddProxyRequest struct {
ProxyURL string `json:"proxy_url"`
Description string `json:"description"`
Proxies []string `json:"proxies"` // 批量添加
}
// addCodexProxy 添加代理
func addCodexProxy(w http.ResponseWriter, r *http.Request) {
var req AddProxyRequest
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
Error(w, http.StatusBadRequest, "请求参数错误")
return
}
// 批量添加
if len(req.Proxies) > 0 {
// 过滤空行和格式化
var validProxies []string
for _, p := range req.Proxies {
p = strings.TrimSpace(p)
if p != "" {
// 如果没有协议前缀,自动添加 http://
if !strings.HasPrefix(p, "http://") && !strings.HasPrefix(p, "https://") && !strings.HasPrefix(p, "socks5://") {
p = "http://" + p
}
validProxies = append(validProxies, p)
}
}
if len(validProxies) == 0 {
Error(w, http.StatusBadRequest, "没有有效的代理地址")
return
}
count, err := database.Instance.AddCodexProxies(validProxies)
if err != nil {
Error(w, http.StatusInternalServerError, "批量添加代理失败: "+err.Error())
return
}
Success(w, map[string]interface{}{
"added": count,
"total": len(validProxies),
"message": "批量添加成功",
})
return
}
// 单个添加
if req.ProxyURL == "" {
Error(w, http.StatusBadRequest, "代理地址不能为空")
return
}
proxyURL := strings.TrimSpace(req.ProxyURL)
if !strings.HasPrefix(proxyURL, "http://") && !strings.HasPrefix(proxyURL, "https://") && !strings.HasPrefix(proxyURL, "socks5://") {
proxyURL = "http://" + proxyURL
}
id, err := database.Instance.AddCodexProxy(proxyURL, req.Description)
if err != nil {
if strings.Contains(err.Error(), "UNIQUE constraint failed") {
Error(w, http.StatusConflict, "代理地址已存在")
return
}
Error(w, http.StatusInternalServerError, "添加代理失败: "+err.Error())
return
}
Success(w, map[string]interface{}{
"id": id,
"message": "添加成功",
})
}
// deleteCodexProxy 删除代理
func deleteCodexProxy(w http.ResponseWriter, r *http.Request) {
idStr := r.URL.Query().Get("id")
if idStr == "" {
// 如果没有 id 参数,检查是否要清空所有
if r.URL.Query().Get("all") == "true" {
err := database.Instance.ClearCodexProxies()
if err != nil {
Error(w, http.StatusInternalServerError, "清空代理失败: "+err.Error())
return
}
Success(w, map[string]string{"message": "已清空所有代理"})
return
}
Error(w, http.StatusBadRequest, "缺少代理 ID")
return
}
id, err := strconv.ParseInt(idStr, 10, 64)
if err != nil {
Error(w, http.StatusBadRequest, "无效的代理 ID")
return
}
if err := database.Instance.DeleteCodexProxy(id); err != nil {
Error(w, http.StatusInternalServerError, "删除代理失败: "+err.Error())
return
}
Success(w, map[string]string{"message": "删除成功"})
}
// toggleCodexProxy 切换代理启用状态
func toggleCodexProxy(w http.ResponseWriter, r *http.Request) {
idStr := r.URL.Query().Get("id")
if idStr == "" {
Error(w, http.StatusBadRequest, "缺少代理 ID")
return
}
id, err := strconv.ParseInt(idStr, 10, 64)
if err != nil {
Error(w, http.StatusBadRequest, "无效的代理 ID")
return
}
if err := database.Instance.ToggleCodexProxy(id); err != nil {
Error(w, http.StatusInternalServerError, "切换代理状态失败: "+err.Error())
return
}
Success(w, map[string]string{"message": "状态已切换"})
}
// testCodexProxy 测试代理连通性
func testCodexProxy(w http.ResponseWriter, r *http.Request) {
idStr := r.URL.Query().Get("id")
if idStr == "" {
Error(w, http.StatusBadRequest, "缺少代理 ID")
return
}
id, err := strconv.ParseInt(idStr, 10, 64)
if err != nil {
Error(w, http.StatusBadRequest, "无效的代理 ID")
return
}
// 获取代理详情
proxies, err := database.Instance.GetCodexProxies()
if err != nil {
Error(w, http.StatusInternalServerError, "获取代理失败")
return
}
var targetProxy *database.CodexProxy
for _, p := range proxies {
if p.ID == id {
targetProxy = &p
break
}
}
if targetProxy == nil {
Error(w, http.StatusNotFound, "未找到代理")
return
}
// 执行测试 (异步执行以防前端超时,但用户想要同步结果,所以这里同步执行)
// 因为是在管理后台点击15s 超时是可以接受的
result, err := proxyutil.TestProxy(targetProxy.ProxyURL)
if err != nil {
database.Instance.UpdateCodexProxyTestResult(id, "", false)
Error(w, http.StatusInternalServerError, "测试过程出错: "+err.Error())
return
}
// 更新数据库
err = database.Instance.UpdateCodexProxyTestResult(id, result.Location, result.Success)
if err != nil {
Error(w, http.StatusInternalServerError, "更新测试结果失败")
return
}
Success(w, result)
}