package api import ( "encoding/json" "fmt" "net/http" "strconv" "strings" "codex-pool/internal/database" "codex-pool/internal/logger" "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, "方法不允许") } } // HandleCodexProxyStats 获取代理池统计 func HandleCodexProxyStats(w http.ResponseWriter, r *http.Request) { if r.Method != http.MethodGet { Error(w, http.StatusMethodNotAllowed, "仅支持 GET") return } if database.Instance == nil { Error(w, http.StatusInternalServerError, "数据库未初始化") return } stats := database.Instance.GetCodexProxyStats() Success(w, stats) } // 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 { logger.Error(fmt.Sprintf("批量添加代理失败: %v", err), "", "proxy-pool") Error(w, http.StatusInternalServerError, "批量添加代理失败: "+err.Error()) return } logger.Success(fmt.Sprintf("批量添加代理: %d/%d 个成功", count, len(validProxies)), "", "proxy-pool") 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") { logger.Warning(fmt.Sprintf("代理已存在: %s", getProxyDisplay(proxyURL)), "", "proxy-pool") Error(w, http.StatusConflict, "代理地址已存在") return } logger.Error(fmt.Sprintf("添加代理失败: %v", err), "", "proxy-pool") Error(w, http.StatusInternalServerError, "添加代理失败: "+err.Error()) return } logger.Success(fmt.Sprintf("添加代理: %s (ID: %d)", getProxyDisplay(proxyURL), id), "", "proxy-pool") 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 { logger.Error(fmt.Sprintf("清空代理池失败: %v", err), "", "proxy-pool") Error(w, http.StatusInternalServerError, "清空代理失败: "+err.Error()) return } logger.Success("已清空所有代理", "", "proxy-pool") 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 { logger.Error(fmt.Sprintf("删除代理失败 (ID: %d): %v", id, err), "", "proxy-pool") Error(w, http.StatusInternalServerError, "删除代理失败: "+err.Error()) return } logger.Info(fmt.Sprintf("删除代理 (ID: %d)", id), "", "proxy-pool") 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 { logger.Error(fmt.Sprintf("切换代理状态失败 (ID: %d): %v", id, err), "", "proxy-pool") Error(w, http.StatusInternalServerError, "切换代理状态失败: "+err.Error()) return } logger.Info(fmt.Sprintf("切换代理状态 (ID: %d)", id), "", "proxy-pool") 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 } proxyDisplay := getProxyDisplay(targetProxy.ProxyURL) logger.Status(fmt.Sprintf("测试代理中: %s", proxyDisplay), "", "proxy-pool") // 执行测试 result, err := proxyutil.TestProxy(targetProxy.ProxyURL) if err != nil { database.Instance.UpdateCodexProxyTestResult(id, "", false) logger.Error(fmt.Sprintf("测试代理失败: %s - %v", proxyDisplay, err), "", "proxy-pool") Error(w, http.StatusInternalServerError, "测试过程出错: "+err.Error()) return } // 更新数据库 err = database.Instance.UpdateCodexProxyTestResult(id, result.Location, result.Success) if err != nil { Error(w, http.StatusInternalServerError, "更新测试结果失败") return } if result.Success { logger.Success(fmt.Sprintf("测试代理成功: %s -> %s (%s)", proxyDisplay, result.IP, result.Location), "", "proxy-pool") } else { logger.Error(fmt.Sprintf("测试代理失败: %s - %s", proxyDisplay, result.Error), "", "proxy-pool") } Success(w, result) }