diff --git a/src/services/apiClient.ts b/src/services/apiClient.ts index 12db482..466034e 100644 --- a/src/services/apiClient.ts +++ b/src/services/apiClient.ts @@ -2,18 +2,28 @@ * 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'; +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'; + method: "GET" | "POST" | "PUT" | "DELETE"; headers?: Record; body?: unknown; timeout?: number; @@ -24,7 +34,9 @@ interface RequestOptions { */ async function getAuthToken(): Promise { try { - const session = await vscode.authentication.getSession('iccoder', [], { silent: true }); + const session = await vscode.authentication.getSession("iccoder", [], { + silent: true, + }); return session?.accessToken; } catch { return undefined; @@ -41,7 +53,7 @@ async function request(path: string, options: RequestOptions): Promise { // 自动获取 Token const token = await getAuthToken(); - const isHttps = url.protocol === 'https:'; + const isHttps = url.protocol === "https:"; const httpModule = isHttps ? https : http; const requestOptions: http.RequestOptions = { @@ -50,49 +62,84 @@ async function request(path: string, options: RequestOptions): Promise { path: url.pathname + url.search, method: options.method, headers: { - 'Content-Type': 'application/json', - ...(token ? { 'Authorization': `Bearer ${token}` } : {}), - ...options.headers + "Content-Type": "application/json", + ...(token ? { Authorization: `Bearer ${token}` } : {}), + ...options.headers, }, - timeout: options.timeout || timeout + 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 = ''; + let data = ""; - res.on('data', (chunk) => { + // console.log('[HTTP] 响应状态码:', res.statusCode); + // console.log('[HTTP] 响应头:', res.headers); + + res.on("data", (chunk) => { data += chunk; }); - res.on('end', () => { + 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 { - reject(new Error(json.error || json.message || `HTTP ${res.statusCode}`)); + 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) => { + req.on("error", (error) => { + // console.error('[HTTP] 请求错误:', error); reject(error); }); - req.on('timeout', () => { + req.on("timeout", () => { + // console.error('[HTTP] 请求超时'); req.destroy(); - reject(new Error('请求超时')); + reject(new Error("请求超时")); }); if (options.body) { - req.write(JSON.stringify(options.body)); + const bodyStr = JSON.stringify(options.body); + // console.log('[HTTP] 发送请求体:', bodyStr); + req.write(bodyStr); } req.end(); + // console.log('[HTTP] 请求已发送'); }); } @@ -100,11 +147,13 @@ async function request(path: string, options: RequestOptions): Promise { * 提交工具执行结果 * POST /api/tool/result */ -export async function submitToolResult(result: ToolCallResult): Promise { +export async function submitToolResult( + result: ToolCallResult, +): Promise { console.log(`[API] 提交工具结果: callId=${result.id}`); - return request('/api/tool/result', { - method: 'POST', - body: result + return request("/api/tool/result", { + method: "POST", + body: result, }); } @@ -112,11 +161,13 @@ export async function submitToolResult(result: ToolCallResult): Promise { +export async function submitAnswer( + answer: AnswerRequest, +): Promise { console.log(`[API] 提交用户回答: askId=${answer.askId}`); - return request('/api/task/answer', { - method: 'POST', - body: answer + return request("/api/task/answer", { + method: "POST", + body: answer, }); } @@ -124,11 +175,15 @@ export async function submitAnswer(answer: AnswerRequest): Promise { - console.log(`[API] 提交工具确认: confirmId=${response.confirmId}, approved=${response.approved}`); - return request('/api/tool/confirm', { - method: 'POST', - body: response +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, }); } @@ -137,9 +192,9 @@ export async function submitToolConfirm(response: ToolConfirmResponse): Promise< * GET /api/dialog/health */ export async function healthCheck(): Promise<{ status: string }> { - return request<{ status: string }>('/api/dialog/health', { - method: 'GET', - timeout: 5000 + return request<{ status: string }>("/api/dialog/health", { + method: "GET", + timeout: 5000, }); } @@ -166,9 +221,9 @@ export interface StopDialogResponse { */ export async function stopDialog(taskId: string): Promise { console.log(`[API] 停止对话: taskId=${taskId}`); - return request('/api/dialog/stop', { - method: 'POST', - body: { taskId } + return request("/api/dialog/stop", { + method: "POST", + body: { taskId }, }); } @@ -184,11 +239,13 @@ export interface CompactDialogResponse { * 手动压缩对话历史 * POST /api/dialog/compact */ -export async function compactDialog(taskId: string): Promise { +export async function compactDialog( + taskId: string, +): Promise { console.log(`[API] 压缩对话: taskId=${taskId}`); - return request('/api/dialog/compact', { - method: 'POST', - body: { taskId } + return request("/api/dialog/compact", { + method: "POST", + body: { taskId }, }); } @@ -197,37 +254,44 @@ export async function compactDialog(taskId: string): Promise { - console.log('[API] 获取用户信息'); - return request('/system/user/getInfo', { - method: 'GET' + console.log("[API] 获取用户信息"); + return request("/system/user/getInfo", { + method: "GET", }); } @@ -253,25 +317,45 @@ export interface CreditBalanceResponse { * 查询用户资源点余额 * 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 - }); +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] 验证邀请码'); +export async function verifyInvitationCode( + code: string, +): Promise { + // console.log('[API] 验证邀请码 - 开始'); + console.log("[API] 邀请码:", code); const body: InvitationVerifyRequest = { code }; - return request('/api/invitation/verify', { - method: 'POST', - body - }); + 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; + } } /** @@ -279,8 +363,8 @@ export async function verifyInvitationCode(code: string): Promise { - console.log('[API] 查询邀请码验证状态'); - return request('/api/invitation/status', { - method: 'GET' + console.log("[API] 查询邀请码验证状态"); + return request("/api/invitation/status", { + method: "GET", }); } diff --git a/src/services/invitationService.ts b/src/services/invitationService.ts index 94435ca..fe5cdc2 100644 --- a/src/services/invitationService.ts +++ b/src/services/invitationService.ts @@ -1,8 +1,8 @@ /** * 邀请码验证服务 */ -import * as vscode from 'vscode'; -import { verifyInvitationCode, checkInvitationStatus } from './apiClient'; +import * as vscode from "vscode"; +import { verifyInvitationCode, checkInvitationStatus } from "./apiClient"; /** * 邀请码验证服务类 @@ -13,34 +13,51 @@ export class InvitationService { */ static async isVerified(context: vscode.ExtensionContext): Promise { // 【临时】使用本地验证,不调用后端 - const localVerified = context.globalState.get('invitationCodeVerified'); + const localVerified = context.globalState.get( + "invitationCodeVerified", + ); return localVerified || false; } /** * 验证邀请码 */ - static async verifyCode(code: string): Promise<{ success: boolean; message: string }> { + static async verifyCode( + code: string, + ): Promise<{ success: boolean; message: string }> { try { - console.log('[InvitationService] 验证邀请码:', code); + // console.log('[InvitationService] ========== 开始验证邀请码 =========='); + // console.log('[InvitationService] 邀请码:', code); + // console.log('[InvitationService] 邀请码长度:', code.length); + const response = await verifyInvitationCode(code); + // console.log('[InvitationService] 收到响应:', JSON.stringify(response, null, 2)); + // console.log('[InvitationService] 响应代码:', response.code); + // console.log('[InvitationService] 响应消息:', response.msg); + // console.log('[InvitationService] 验证结果:', response.data?.verified); + if (response.code === 200 && response.data?.verified) { + console.log("[InvitationService] ✓ 验证成功"); return { success: true, - message: response.msg || '验证成功' + message: response.msg || "验证成功", }; } else { + console.log("[InvitationService] ✗ 验证失败"); return { success: false, - message: response.msg || '验证失败' + message: response.msg || "验证失败", }; } } catch (error: any) { - console.error('[InvitationService] 验证邀请码失败:', error); + // console.error('[InvitationService] ========== 验证邀请码异常 =========='); + // console.error('[InvitationService] 错误类型:', error.constructor.name); + // console.error('[InvitationService] 错误消息:', error.message); + // console.error('[InvitationService] 错误堆栈:', error.stack); return { success: false, - message: error.message || '网络连接失败,请检查网络后重试' + message: error.message || "网络连接失败,请检查网络后重试", }; } } @@ -51,20 +68,25 @@ export class InvitationService { static async saveVerificationStatus( context: vscode.ExtensionContext, code: string, - verifiedTime?: string + verifiedTime?: string, ): Promise { - await context.globalState.update('invitationCodeVerified', true); - await context.globalState.update('invitationCode', code); - await context.globalState.update('invitationVerifiedTime', verifiedTime || new Date().toISOString()); + await context.globalState.update("invitationCodeVerified", true); + await context.globalState.update("invitationCode", code); + await context.globalState.update( + "invitationVerifiedTime", + verifiedTime || new Date().toISOString(), + ); } /** * 清除验证状态(用于退出登录或更换邀请码) */ - static async clearVerificationStatus(context: vscode.ExtensionContext): Promise { - await context.globalState.update('invitationCodeVerified', undefined); - await context.globalState.update('invitationCode', undefined); - await context.globalState.update('invitationVerifiedTime', undefined); + static async clearVerificationStatus( + context: vscode.ExtensionContext, + ): Promise { + await context.globalState.update("invitationCodeVerified", undefined); + await context.globalState.update("invitationCode", undefined); + await context.globalState.update("invitationVerifiedTime", undefined); } /** @@ -72,18 +94,18 @@ export class InvitationService { */ static async showInputDialog(): Promise { const code = await vscode.window.showInputBox({ - prompt: '请输入邀请码以继续使用 IC Coder', - placeHolder: '例如:INVITE2024ABC', + prompt: "请输入邀请码以继续使用 IC Coder", + placeHolder: "例如:INVITE2024ABC", ignoreFocusOut: true, validateInput: (value) => { if (!value || value.trim().length === 0) { - return '邀请码不能为空'; + return "邀请码不能为空"; } if (value.trim().length < 6) { - return '邀请码格式不正确'; + return "邀请码格式不正确"; } return null; - } + }, }); return code?.trim();