From db1f8dcbbc044c9e83e61f1fecdd3ac36e75133f Mon Sep 17 00:00:00 2001 From: iven Date: Sat, 11 Apr 2026 02:54:23 +0800 Subject: [PATCH] =?UTF-8?q?feat(desktop):=20Gateway=20URL=20=E9=85=8D?= =?UTF-8?q?=E7=BD=AE=E5=8C=96=20+=20Rust=20panic=20hook=20=E5=B4=A9?= =?UTF-8?q?=E6=BA=83=E6=8A=A5=E5=91=8A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - api-urls.ts: GATEWAY_URLS 读 VITE_GATEWAY_HTTP/WS env - gateway-storage.ts: DEFAULT_GATEWAY_URL 读 VITE_GATEWAY_WS env - lib.rs: 添加 tracing_subscriber 初始化 + panic::set_hook 崩溃时自动写入 crash-reports/ 目录供诊断 - Cargo.toml: 添加 tracing-subscriber workspace 依赖 --- desktop/src-tauri/Cargo.toml | 1 + desktop/src-tauri/src/lib.rs | 39 ++++++++++++++++++++++++++++++ desktop/src/constants/api-urls.ts | 4 +-- desktop/src/lib/gateway-storage.ts | 2 +- 4 files changed, 43 insertions(+), 3 deletions(-) diff --git a/desktop/src-tauri/Cargo.toml b/desktop/src-tauri/Cargo.toml index 7485168..73de985 100644 --- a/desktop/src-tauri/Cargo.toml +++ b/desktop/src-tauri/Cargo.toml @@ -63,6 +63,7 @@ dashmap = { workspace = true } uuid = { workspace = true } base64 = { workspace = true } tracing = { workspace = true } +tracing-subscriber = { workspace = true } secrecy = { workspace = true } # Browser automation (existing) diff --git a/desktop/src-tauri/src/lib.rs b/desktop/src-tauri/src/lib.rs index f92fe40..7bd5c2f 100644 --- a/desktop/src-tauri/src/lib.rs +++ b/desktop/src-tauri/src/lib.rs @@ -49,6 +49,45 @@ mod dev_server; #[cfg_attr(mobile, tauri::mobile_entry_point)] pub fn run() { + // Initialize tracing subscriber for structured logging + tracing_subscriber::fmt() + .with_env_filter( + tracing_subscriber::EnvFilter::try_from_default_env() + .unwrap_or_else(|_| tracing_subscriber::EnvFilter::new("info")), + ) + .with_thread_ids(true) + .with_file(true) + .with_line_number(true) + .init(); + + // Install panic hook to capture crash info for diagnostics + std::panic::set_hook(Box::new(|info| { + let location = info.location().map(|l| format!("{}:{}", l.file(), l.line())) + .unwrap_or_else(|| "unknown".into()); + let payload = if let Some(s) = info.payload().downcast_ref::<&str>() { + s.to_string() + } else if let Some(s) = info.payload().downcast_ref::() { + s.clone() + } else { + "unknown panic payload".into() + }; + tracing::error!(location = %location, payload = %payload, "PANIC — application crashed"); + + // Write crash log to disk for post-mortem analysis + if let Some(app_dir) = dirs::data_local_dir() + .or_else(|| dirs::data_dir()) + { + let crash_dir = app_dir.join("zclaw").join("crash-reports"); + let _ = std::fs::create_dir_all(&crash_dir); + let timestamp = chrono::Local::now().format("%Y%m%d_%H%M%S"); + let crash_file = crash_dir.join(format!("crash_{}.log", timestamp)); + let _ = std::fs::write(&crash_file, format!( + "ZCLAW Crash Report\n==================\nTime: {}\nLocation: {}\nPayload: {}\n\n{:?}", + chrono::Local::now().to_rfc3339(), location, payload, info, + )); + } + })); + // Start development server when dev-server feature is enabled #[cfg(feature = "dev-server")] { diff --git a/desktop/src/constants/api-urls.ts b/desktop/src/constants/api-urls.ts index 230ec08..48b0718 100644 --- a/desktop/src/constants/api-urls.ts +++ b/desktop/src/constants/api-urls.ts @@ -50,8 +50,8 @@ export const LLM_PROVIDER_URLS = { * ZCLAW Gateway default URLs */ export const GATEWAY_URLS = { - DEFAULT_HTTP: 'http://127.0.0.1:50051', - DEFAULT_WS: 'ws://127.0.0.1:50051/ws', + DEFAULT_HTTP: import.meta.env.VITE_GATEWAY_HTTP || 'http://127.0.0.1:50051', + DEFAULT_WS: import.meta.env.VITE_GATEWAY_WS || 'ws://127.0.0.1:50051/ws', FALLBACK_HTTP: 'http://127.0.0.1:4200', FALLBACK_WS: 'ws://127.0.0.1:4200/ws', } as const; diff --git a/desktop/src/lib/gateway-storage.ts b/desktop/src/lib/gateway-storage.ts index f43d7ab..2903f32 100644 --- a/desktop/src/lib/gateway-storage.ts +++ b/desktop/src/lib/gateway-storage.ts @@ -48,7 +48,7 @@ export function isLocalhost(url: string): boolean { // ZCLAW endpoints (port 50051 - actual running port) // Note: REST API uses relative path to leverage Vite proxy for CORS bypass -export const DEFAULT_GATEWAY_URL = `${DEFAULT_WS_PROTOCOL}127.0.0.1:50051/ws`; +export const DEFAULT_GATEWAY_URL = import.meta.env.VITE_GATEWAY_WS || `${DEFAULT_WS_PROTOCOL}127.0.0.1:50051/ws`; export const REST_API_URL = ''; // Empty = use relative path (Vite proxy) export const FALLBACK_GATEWAY_URLS = [ DEFAULT_GATEWAY_URL,