瀏覽代碼

V1.0.5.B 首发版本 - buff扫货Runner功能增强

Made-with: Cursor
wuzilong 6 月之前
父節點
當前提交
1c4c8fe5a0
共有 2 個文件被更改,包括 153 次插入 和 1 次删除
  1. 152 0
      client-tauri/src-tauri/src/commands/buff_sweep_runner.rs
  2. 1 1
      client-tauri/src/views/HomeView.vue

+ 152 - 0
client-tauri/src-tauri/src/commands/buff_sweep_runner.rs

@@ -417,6 +417,126 @@ async fn log_api_call_error(
         steam_account, api_name, method, url, response_status.as_u16(), elapsed_ms
         steam_account, api_name, method, url, response_status.as_u16(), elapsed_ms
     );
     );
     error!("{}", log_msg);
     error!("{}", log_msg);
+
+    // 同时写入 error 文件(包含完整详细信息)
+    log_api_error_to_error_file(
+        sweep_file,
+        request_id_fallback,
+        steam_account,
+        api_name,
+        method,
+        url,
+        headers,
+        form_params,
+        Some(response_status),
+        Some(response_body),
+        None,
+        elapsed_ms,
+    ).await;
+}
+
+/// 将 Steam API 调用错误详细记录到 {sweep_request_id}-error.txt 文件
+/// 包含:时间戳、账号、API名称、URL、请求头、请求体、响应状态、响应体、耗时
+/// 注意:只记录失败/错误的调用,成功的不记录
+async fn log_api_error_to_error_file(
+    sweep_file: Option<&SweepShared>,
+    request_id_fallback: i64,
+    steam_account: &str,
+    api_name: &str,
+    method: &str,
+    url: &str,
+    headers: &HeaderMap,
+    form_params: Option<&[(String, String)]>,
+    response_status: Option<reqwest::StatusCode>,
+    response_body: Option<&str>,
+    error_msg: Option<&str>,
+    elapsed_ms: u64,
+) {
+    let rid = sweep_file.map(|s| s.sweep_request_id).unwrap_or(request_id_fallback);
+    if rid <= 0 {
+        return;
+    }
+
+    // 构建详细日志JSON
+    let headers_json = serde_json::to_value(headers.iter().map(|(k, v)| {
+        (k.as_str().to_string(), v.to_str().unwrap_or("").to_string())
+    }).collect::<HashMap<_, _>>()).unwrap_or(Value::Null);
+
+    let form_json: Value = match form_params {
+        Some(form) => {
+            serde_json::to_value(form.iter().map(|(k, v)| (k.clone(), v.clone())).collect::<Vec<_>>()).unwrap_or(Value::Null)
+        }
+        None => Value::Null,
+    };
+
+    let status_str = response_status
+        .map(|s| s.as_u16().to_string())
+        .unwrap_or_else(|| "N/A".to_string());
+
+    let body_str = response_body
+        .map(|s| {
+            let trimmed = s.trim();
+            if trimmed.is_empty() {
+                "(空响应)".to_string()
+            } else {
+                trimmed.to_string()
+            }
+        })
+        .unwrap_or_else(|| "(无响应体)".to_string());
+
+    let err_str = error_msg.unwrap_or("").to_string();
+
+    // 生成 ISO 格式时间戳
+    let timestamp_iso = chrono::Local::now().format("%Y-%m-%dT%H:%M:%S%.3f").to_string();
+
+    // 构建完整的错误详情
+    let error_detail = json!({
+        "created_at": sweep_api_ts(),
+        "timestamp_iso": timestamp_iso,
+        "sweep_request_id": rid,
+        "steam_account": steam_account,
+        "api_name": api_name,
+        "method": method,
+        "url": url,
+        "request_headers": headers_json,
+        "request_body": form_json,
+        "response_status": status_str,
+        "response_body": body_str,
+        "error_message": err_str,
+        "elapsed_ms": elapsed_ms,
+        "summary": format!(
+            "[API-ERROR] {} {} -> {} ({}ms) | account={} | {}",
+            method,
+            api_name,
+            status_str,
+            elapsed_ms,
+            steam_account,
+            if err_str.is_empty() { "OK".to_string() } else { format!("ERR: {}", err_str) }
+        ),
+    });
+
+    // 获取 steam-msg 目录并写入 error 文件
+    if let Ok(steam_msg_dir) = get_steam_msg_dir() {
+        let error_file_path = steam_msg_dir.join(format!("{}-error.txt", rid));
+
+        // 构建带分隔符的日志条目
+        let log_line = serde_json::to_string(&error_detail).unwrap_or_else(|_| "{}".to_string());
+
+        // 追加写入 error 文件
+        if let Err(e) = std::fs::OpenOptions::new()
+            .create(true)
+            .append(true)
+            .open(&error_file_path)
+            .and_then(|mut f| {
+                use std::io::Write;
+                writeln!(f, "{}", log_line)
+            })
+        {
+            error!("[ERROR-LOG] 写入 error 文件失败: {}", e);
+        } else {
+            info!("[ERROR-LOG] 已记录错误到 error 文件: {}", error_file_path.display());
+        }
+    }
 }
 }
 
 
 /// 扫货文件日志中的饰品维度前缀(与产品文案一致)。
 /// 扫货文件日志中的饰品维度前缀(与产品文案一致)。
@@ -1236,6 +1356,22 @@ async fn http_get_steam(
                     }
                     }
                 }
                 }
 
 
+                // 同时写入 error 文件(包含完整详细信息)
+                log_api_error_to_error_file(
+                    sweep_file,
+                    rid,
+                    account_name,
+                    label,
+                    "GET",
+                    url,
+                    &headers_for_log,
+                    None,
+                    None,
+                    None,
+                    Some(&last_err),
+                    elapsed_ms,
+                ).await;
+
                 let need_retry = attempt < retry_times
                 let need_retry = attempt < retry_times
                     && is_proxy_related_failure(None, Some(&last_err), None);
                     && is_proxy_related_failure(None, Some(&last_err), None);
                 if !need_retry {
                 if !need_retry {
@@ -1442,6 +1578,22 @@ async fn http_post_form_steam(
                     }
                     }
                 }
                 }
 
 
+                // 同时写入 error 文件(包含完整详细信息)
+                log_api_error_to_error_file(
+                    sweep_file,
+                    rid,
+                    account_name,
+                    label,
+                    "POST",
+                    url,
+                    &headers_for_log,
+                    Some(form),
+                    None,
+                    None,
+                    Some(&last_err),
+                    elapsed_ms,
+                ).await;
+
                 let need_retry = attempt < retry_times;
                 let need_retry = attempt < retry_times;
                 if !need_retry {
                 if !need_retry {
                     return Err(last_err);
                     return Err(last_err);

+ 1 - 1
client-tauri/src/views/HomeView.vue

@@ -66,7 +66,7 @@
               </a-menu-item>
               </a-menu-item>
               <a-menu-divider />
               <a-menu-divider />
               <a-menu-item key="version" disabled style="color: #999; cursor: default;">
               <a-menu-item key="version" disabled style="color: #999; cursor: default;">
-                <span style="font-size: 12px;">版本 V1.0.4.B</span>
+                <span style="font-size: 12px;">版本 V1.0.5.B</span>
               </a-menu-item>
               </a-menu-item>
               <a-menu-item key="logout">
               <a-menu-item key="logout">
                 <LogoutOutlined /> 退出登录
                 <LogoutOutlined /> 退出登录