Skip to content

Commit 5a4ed12

Browse files
authored
Merge pull request #60 from Cloxl/feat/err-msg-in-backend
feat(cursor): improve account switch & machine reset handling
2 parents 7c9930c + 5e222d0 commit 5a4ed12

3 files changed

Lines changed: 140 additions & 72 deletions

File tree

src-tauri/src/api/endpoints.rs

Lines changed: 61 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,53 @@ use std::env;
1010
use tauri::State;
1111
use tracing::error;
1212

13+
/// 通用API响应处理函数,处理成功和失败情况
14+
async fn handle_api_response<T: serde::de::DeserializeOwned>(
15+
response: reqwest::Response,
16+
error_context: &str
17+
) -> Result<ApiResponse<T>, String> {
18+
// 获取响应文本
19+
let response_text = response.text().await.map_err(|e| {
20+
error!(target: "api", "获取{}响应文本失败 - 错误: {}", error_context, e);
21+
e.to_string()
22+
})?;
23+
24+
// 尝试解析为基本JSON格式以获取status和msg
25+
let api_response: serde_json::Value = serde_json::from_str(&response_text).map_err(|e| {
26+
error!(target: "api", "解析{}响应JSON失败 - 错误: {}", error_context, e);
27+
e.to_string()
28+
})?;
29+
30+
// 提取status和msg
31+
let status = api_response["status"].as_i64().unwrap_or(500) as i32;
32+
let msg = api_response["msg"].as_str().unwrap_or("未知错误").to_string();
33+
34+
// 如果status不是200,直接返回错误响应
35+
if status != 200 {
36+
return Ok(ApiResponse {
37+
status,
38+
msg,
39+
data: None,
40+
code: api_response["code"].as_str().map(String::from),
41+
});
42+
}
43+
44+
// 成功情况,尝试解析为完整类型
45+
match serde_json::from_str::<ApiResponse<T>>(&response_text) {
46+
Ok(typed_response) => Ok(typed_response),
47+
Err(e) => {
48+
error!(target: "api", "解析{}响应为完整类型失败 - 错误: {}", error_context, e);
49+
// 即使解析失败,依然返回成功状态但data为None
50+
Ok(ApiResponse {
51+
status,
52+
msg,
53+
data: None,
54+
code: api_response["code"].as_str().map(String::from),
55+
})
56+
}
57+
}
58+
}
59+
1360
// Bug报告请求结构
1461
#[derive(Serialize, Deserialize)]
1562
pub struct BugReportRequest {
@@ -42,10 +89,7 @@ pub async fn check_user(
4289
e.to_string()
4390
})?;
4491

45-
response.json().await.map_err(|e| {
46-
error!(target: "api", "解析检查用户响应失败 - 错误: {}", e);
47-
e.to_string()
48-
})
92+
handle_api_response(response, "检查用户").await
4993
}
5094

5195
/// 发送验证码
@@ -65,10 +109,7 @@ pub async fn send_code(
65109
e.to_string()
66110
})?;
67111

68-
response.json().await.map_err(|e| {
69-
error!(target: "api", "解析发送验证码响应失败 - 错误: {}", e);
70-
e.to_string()
71-
})
112+
handle_api_response(response, "发送验证码").await
72113
}
73114

74115
/// 注册用户
@@ -94,15 +135,7 @@ pub async fn register(
94135
e.to_string()
95136
})?;
96137

97-
let response_text = response.text().await.map_err(|e| {
98-
error!(target: "api", "获取注册响应文本失败 - 错误: {}", e);
99-
e.to_string()
100-
})?;
101-
102-
serde_json::from_str(&response_text).map_err(|e| {
103-
error!(target: "api", "解析注册响应失败 - 错误: {}", e);
104-
e.to_string()
105-
})
138+
handle_api_response(response, "注册用户").await
106139
}
107140

108141
/// 用户登录
@@ -127,10 +160,7 @@ pub async fn login(
127160
e.to_string()
128161
})?;
129162

130-
response.json().await.map_err(|e| {
131-
error!(target: "api", "解析登录响应失败 - 错误: {}", e);
132-
e.to_string()
133-
})
163+
handle_api_response(response, "登录").await
134164
}
135165

136166
/// 获取用户信息
@@ -145,10 +175,7 @@ pub async fn get_user_info(client: State<'_, ApiClient>) -> Result<ApiResponse<U
145175
e.to_string()
146176
})?;
147177

148-
response.json().await.map_err(|e| {
149-
error!(target: "api", "解析用户信息响应失败 - 错误: {}", e);
150-
e.to_string()
151-
})
178+
handle_api_response(response, "获取用户信息").await
152179
}
153180

154181
/// 激活账户
@@ -167,10 +194,7 @@ pub async fn activate(
167194
e.to_string()
168195
})?;
169196

170-
response.json().await.map_err(|e| {
171-
error!(target: "api", "解析激活账户响应失败 - 错误: {}", e);
172-
e.to_string()
173-
})
197+
handle_api_response(response, "激活账户").await
174198
}
175199

176200
/// 修改密码
@@ -193,10 +217,8 @@ pub async fn change_password(
193217
error!(target: "api", "修改密码请求失败 - 错误: {}", e);
194218
e.to_string()
195219
})?;
196-
response.json().await.map_err(|e| {
197-
error!(target: "api", "解析修改密码响应失败 - 错误: {}", e);
198-
e.to_string()
199-
})
220+
221+
handle_api_response(response, "修改密码").await
200222
}
201223

202224
/// 获取账户信息
@@ -226,14 +248,12 @@ pub async fn get_account(
226248
e.to_string()
227249
})?;
228250

229-
let response: ApiResponse<AccountPoolInfo> = response.json().await.map_err(|e| {
230-
error!(target: "api", "解析账户信息响应失败 - 错误: {}", e);
231-
e.to_string()
232-
})?;
251+
// 使用通用函数处理API响应
252+
let api_response = handle_api_response::<AccountPoolInfo>(response, "获取账户信息").await?;
233253

234254
// 如果获取成功且有账户信息,将token保存到历史记录
235-
if response.status == 200 && response.data.is_some() {
236-
let account_info = &response.data.as_ref().unwrap().account_info;
255+
if api_response.status == 200 && api_response.data.is_some() {
256+
let account_info = &api_response.data.as_ref().unwrap().account_info;
237257
if !account_info.account.is_empty() && !account_info.token.is_empty() {
238258
// 获取当前机器码
239259
use crate::cursor_reset::get_machine_ids;
@@ -260,7 +280,7 @@ pub async fn get_account(
260280
}
261281
}
262282

263-
Ok(response)
283+
Ok(api_response)
264284
}
265285

266286
/// 获取 Cursor 使用情况
@@ -359,10 +379,7 @@ pub async fn reset_password(
359379
e.to_string()
360380
})?;
361381

362-
response.json().await.map_err(|e| {
363-
error!(target: "api", "解析重置密码响应失败 - 错误: {}", e);
364-
e.to_string()
365-
})
382+
handle_api_response(response, "重置密码").await
366383
}
367384

368385
/// 报告错误

src/stores/cursor.ts

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -303,11 +303,17 @@ export const useCursorStore = defineStore('cursor', () => {
303303
// 检查 Cursor 是否在运行
304304
await ensureCursorNotRunning(forceKill)
305305

306+
// 保存原始机器码,以便失败时恢复
307+
const originalMachineId = machineCode.value
308+
309+
let machineResetSuccess = false
310+
306311
// 先重置机器码
307312
try {
308313
await resetMachine({
309314
forceKill,
310315
})
316+
machineResetSuccess = true
311317
} catch (error) {
312318
await Logger.error('一键换号时重置机器码失败')
313319
throw error
@@ -319,6 +325,21 @@ export const useCursorStore = defineStore('cursor', () => {
319325
await Logger.info('一键换号完成')
320326
} catch (error) {
321327
await Logger.error('一键换号时切换账户失败')
328+
329+
// 机器码重置成功 但账户切换失败 恢复原始机器码
330+
if (machineResetSuccess && originalMachineId) {
331+
try {
332+
await resetMachineId({
333+
forceKill,
334+
machineId: originalMachineId,
335+
})
336+
await Logger.info('恢复原始机器码成功')
337+
await fetchMachineIds() // 刷新机器码信息
338+
} catch (restoreError) {
339+
await Logger.error(`恢复原始机器码失败: ${restoreError}`)
340+
}
341+
}
342+
322343
throw error
323344
}
324345

src/views/DashboardView.vue

Lines changed: 58 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -352,53 +352,65 @@
352352
}
353353
354354
// 修改账户切换执行函数
355-
const executeAccountSwitch = async (force_kill: boolean = false) => {
355+
const executeAccountSwitch = async (force_kill: boolean = false): Promise<boolean> => {
356356
try {
357-
await cursorStore.switchCursorAccount(undefined, undefined, force_kill)
358-
message.success(i18n.value.dashboard.accountChangeSuccess)
357+
const result = await cursorStore.switchCursorAccount(undefined, undefined, force_kill)
359358
360-
// 发送通知
361-
await notificationStore.notify({
362-
title: 'Cursor Pool',
363-
body: i18n.value.dashboard.accountChangeSuccess,
364-
})
359+
// 只有当操作成功时才显示成功消息和刷新数据
360+
if (result === true) {
361+
message.success(i18n.value.dashboard.accountChangeSuccess)
365362
366-
await fetchUserInfo()
367-
updateLocalViewState()
363+
// 发送通知
364+
await notificationStore.notify({
365+
title: 'Cursor Pool',
366+
body: i18n.value.dashboard.accountChangeSuccess,
367+
})
368+
369+
await fetchUserInfo()
370+
updateLocalViewState()
371+
return true
372+
}
373+
return false
368374
} catch (error) {
369375
console.error('账户切换失败:', error)
370376
message.error(
371377
error instanceof Error ? error.message : i18n.value.dashboard.accountChangeFailed,
372378
)
379+
return false
373380
}
374381
}
375382
376383
// 修改一键切换执行函数
377-
const executeQuickChange = async (force_kill: boolean = false) => {
384+
const executeQuickChange = async (force_kill: boolean = false): Promise<boolean> => {
378385
try {
379-
await cursorStore.quickChange(undefined, undefined, force_kill)
380-
message.success(i18n.value.dashboard.changeSuccess)
386+
const result = await cursorStore.quickChange(undefined, undefined, force_kill)
381387
382-
// 发送通知
383-
await notificationStore.notify({
384-
title: 'Cursor Pool',
385-
body: i18n.value.dashboard.changeSuccess,
386-
})
388+
// 只有当操作成功时才显示成功消息和刷新数据
389+
if (result === true) {
390+
message.success(i18n.value.dashboard.changeSuccess)
387391
388-
await fetchUserInfo()
392+
// 发送通知
393+
await notificationStore.notify({
394+
title: 'Cursor Pool',
395+
body: i18n.value.dashboard.changeSuccess,
396+
})
389397
390-
// 更新视图状态
391-
updateLocalViewState()
398+
await fetchUserInfo()
399+
updateLocalViewState()
400+
return true
401+
}
402+
return false
392403
} catch (error) {
393404
const errorMsg = error instanceof Error ? error.message : String(error)
394405
if (errorMsg === 'Cursor进程正在运行, 请先关闭Cursor') {
395406
showCursorRunningModal.value = true
396407
pendingForceKillAction.value = {
397408
type: 'quick',
398409
}
399-
return
410+
return false
400411
}
401412
message.error(error instanceof Error ? error.message : i18n.value.dashboard.changeFailed)
413+
return false
402414
}
403415
}
404416
@@ -451,14 +463,32 @@
451463
operationMessage = i18n.value.dashboard.machineChangeSuccess
452464
} else if (pendingForceKillAction.value.type === 'account') {
453465
message.loading('正在切换账户...', { duration: 0 })
454-
await executeAccountSwitch(true)
455-
operationSuccess = true
456-
operationMessage = i18n.value.dashboard.accountChangeSuccess
466+
try {
467+
const success = await executeAccountSwitch(true)
468+
if (success) {
469+
operationSuccess = true
470+
operationMessage = i18n.value.dashboard.accountChangeSuccess
471+
}
472+
} catch (error) {
473+
console.error('强制切换账户失败:', error)
474+
message.destroyAll()
475+
message.error(error instanceof Error ? error.message : String(error))
476+
return
477+
}
457478
} else if (pendingForceKillAction.value.type === 'quick') {
458479
message.loading('正在一键切换...', { duration: 0 })
459-
await executeQuickChange(true)
460-
operationSuccess = true
461-
operationMessage = i18n.value.dashboard.changeSuccess
480+
try {
481+
const success = await executeQuickChange(true)
482+
if (success) {
483+
operationSuccess = true
484+
operationMessage = i18n.value.dashboard.changeSuccess
485+
}
486+
} catch (error) {
487+
console.error('强制一键切换失败:', error)
488+
message.destroyAll()
489+
message.error(error instanceof Error ? error.message : String(error))
490+
return
491+
}
462492
} else if (pendingForceKillAction.value.type === 'hook') {
463493
message.loading('正在注入...', {
464494
duration: 0,

0 commit comments

Comments
 (0)