/** * API 客户端 * 封装与后端的 HTTP 通信 */ import * as vscode from "vscode"; import * as https from "https"; import * as http from "http"; import { URL } from "url"; import { getApiUrl, getConfig } from "../config/settings"; import type { ToolCallResult, AnswerRequest, ToolResultResponse, AnswerResponse, ToolConfirmResponse, UserInfoResponse, InvitationVerifyRequest, InvitationVerifyResponse, InvitationStatusResponse, } from "../types/api"; /** * HTTP 请求选项 */ interface RequestOptions { method: "GET" | "POST" | "PUT" | "DELETE"; headers?: Record; body?: unknown; timeout?: number; } /** * 获取当前登录的 Token */ async function getAuthToken(): Promise { try { const session = await vscode.authentication.getSession("iccoder", [], { silent: true, }); return session?.accessToken; } catch { return undefined; } } /** * 发送 HTTP 请求 */ async function request(path: string, options: RequestOptions): Promise { const url = new URL(getApiUrl(path)); const { timeout } = getConfig(); // 自动获取 Token const token = await getAuthToken(); const isHttps = url.protocol === "https:"; const httpModule = isHttps ? https : http; const requestOptions: http.RequestOptions = { hostname: url.hostname, port: url.port || (isHttps ? 443 : 80), path: url.pathname + url.search, method: options.method, headers: { "Content-Type": "application/json", ...(token ? { Authorization: `Bearer ${token}` } : {}), ...options.headers, }, timeout: options.timeout || timeout, }; console.log("[HTTP] 请求详情:", { url: url.toString(), method: options.method, headers: requestOptions.headers, hasToken: !!token, body: options.body, }); return new Promise((resolve, reject) => { const req = httpModule.request(requestOptions, (res) => { let data = ""; // console.log('[HTTP] 响应状态码:', res.statusCode); // console.log('[HTTP] 响应头:', res.headers); res.on("data", (chunk) => { data += chunk; }); res.on("end", () => { console.log("[HTTP] 响应体:", data); try { const json = JSON.parse(data); // console.log('[HTTP] 解析后的响应:', JSON.stringify(json, null, 2)); if (res.statusCode && res.statusCode >= 200 && res.statusCode < 300) { console.log("[HTTP] 请求成功"); resolve(json as T); } else { console.error("[HTTP] 请求失败:", { statusCode: res.statusCode, error: json.error, message: json.message, msg: json.msg, }); reject( new Error( json.error || json.message || json.msg || `HTTP ${res.statusCode}`, ), ); } } catch (e) { // console.error('[HTTP] 解析响应失败:', e); // console.error('[HTTP] 原始响应:', data); reject(new Error(`解析响应失败: ${data}`)); } }); }); req.on("error", (error) => { // console.error('[HTTP] 请求错误:', error); reject(error); }); req.on("timeout", () => { // console.error('[HTTP] 请求超时'); req.destroy(); reject(new Error("请求超时")); }); if (options.body) { const bodyStr = JSON.stringify(options.body); // console.log('[HTTP] 发送请求体:', bodyStr); req.write(bodyStr); } req.end(); // console.log('[HTTP] 请求已发送'); }); } /** * 提交工具执行结果 * POST /api/tool/result */ export async function submitToolResult( result: ToolCallResult, ): Promise { console.log(`[API] 提交工具结果: callId=${result.id}`); return request("/api/tool/result", { method: "POST", body: result, }); } /** * 提交用户回答 * POST /api/task/answer */ export async function submitAnswer( answer: AnswerRequest, ): Promise { console.log(`[API] 提交用户回答: askId=${answer.askId}`); return request("/api/task/answer", { method: "POST", body: answer, }); } /** * 提交工具确认响应(Ask 模式) * POST /api/tool/confirm */ export async function submitToolConfirm( response: ToolConfirmResponse, ): Promise { console.log( `[API] 提交工具确认: confirmId=${response.confirmId}, approved=${response.approved}`, ); return request("/api/tool/confirm", { method: "POST", body: response, }); } /** * 健康检查 * GET /api/dialog/health */ export async function healthCheck(): Promise<{ status: string }> { return request<{ status: string }>("/api/dialog/health", { method: "GET", timeout: 5000, }); } /** * 停止对话请求 */ export interface StopDialogRequest { taskId: string; } /** * 停止对话响应 */ export interface StopDialogResponse { success: boolean; taskId: string; message?: string; error?: string; } /** * 停止对话 * POST /api/dialog/stop */ export async function stopDialog(taskId: string): Promise { console.log(`[API] 停止对话: taskId=${taskId}`); return request("/api/dialog/stop", { method: "POST", body: { taskId }, }); } /** 压缩对话响应 */ export interface CompactDialogResponse { success: boolean; taskId: string; message?: string; error?: string; } /** * 手动压缩对话历史 * POST /api/dialog/compact */ export async function compactDialog( taskId: string, ): Promise { console.log(`[API] 压缩对话: taskId=${taskId}`); return request("/api/dialog/compact", { method: "POST", body: { taskId }, }); } /** * 创建成功的工具结果 */ export function createSuccessResult(id: number, text: string): ToolCallResult { return { jsonrpc: "2.0", id, result: { content: [{ type: "text", text }], isError: false, }, }; } /** * 创建业务错误的工具结果(如编译失败) */ export function createBusinessErrorResult( id: number, errorMessage: string, ): ToolCallResult { return { jsonrpc: "2.0", id, result: { content: [{ type: "text", text: errorMessage }], isError: true, }, }; } /** * 创建系统错误的工具结果 */ export function createSystemErrorResult( id: number, code: number, message: string, ): ToolCallResult { return { jsonrpc: "2.0", id, error: { code, message }, }; } /** * 获取用户信息 * GET /system/user/getInfo */ export async function getUserInfo(): Promise { console.log("[API] 获取用户信息"); return request("/system/user/getInfo", { method: "GET", }); } /** 余额查询响应 */ export interface CreditBalanceResponse { success: boolean; balance?: number; error?: string; } /** * 查询用户资源点余额 * GET /api/dialog/balance?userId=xxx */ export async function getCreditBalance( userId: string, ): Promise { console.log("[API] 查询余额: userId=", userId); return request( `/api/dialog/balance?userId=${userId}`, { method: "GET", timeout: 5000, }, ); } /** * 验证邀请码 * POST /api/invitation/verify */ export async function verifyInvitationCode( code: string, ): Promise { // console.log('[API] 验证邀请码 - 开始'); console.log("[API] 邀请码:", code); const body: InvitationVerifyRequest = { code }; console.log("[API] 请求体:", JSON.stringify(body)); try { const response = await request( "/api/invitation/verify", { method: "POST", body, }, ); console.log("[API] 验证邀请码 - 响应:", JSON.stringify(response)); return response; } catch (error) { console.error("[API] 验证邀请码 - 错误:", error); throw error; } } /** * 查询邀请码验证状态 * GET /api/invitation/status */ export async function checkInvitationStatus(): Promise { console.log("[API] 查询邀请码验证状态"); return request("/api/invitation/status", { method: "GET", }); } /** * 重置邀请码验证状态(退出登录时调用) * POST /api/invitation/reset */ export async function resetInvitationVerification(): Promise<{ code: number; msg: string; }> { console.log("[API] 重置邀请码验证状态"); try { const response = await request<{ code: number; msg: string }>( "/api/invitation/reset", { method: "POST", }, ); console.log("[API] 重置邀请码验证状态 - 响应:", JSON.stringify(response)); return response; } catch (error) { console.warn("[API] 重置邀请码验证状态 - 错误:", error); // 即使失败也不影响退出登录流程 throw error; } }