重构: 巨函数拆分 + 清理历史标记注释 + custom_prompt/停止按钮/tunnel 改进

This commit is contained in:
lxy
2026-07-31 21:36:12 +08:00
parent 365af554da
commit bd9031d35d
73 changed files with 1421 additions and 1064 deletions
+36 -18
View File
@@ -292,20 +292,14 @@ pub fn run() {
Err(e) => tracing::warn!("[tunnel] 连接 relay 失败(非阻断,supervisor 将重试): {}", e),
}
// ── supervisor:断线自动重连(根治 device 离线) ──
// df-tunnel 无内置 auto-reconnect(tunnel.rs:332 注释留外层 supervisor)。
// 桌面端进程重启 / 网络断 / relay 重启 → device 离线 → miniapp 命令 delivered=0
// → 点发无响应。supervisor 轮询 is_connected,断开则用保存参数指数退避重连,
// 复用同一 on_command 回调(逻辑不变)。task 永驻(supervisor 生命周期 = 应用生命周期)。
// supervisor:轮询 is_connected,断开则重连
// 连接被拒(relay 未部署)→300s+INFO;其他错误→2s-60s WARN
let mut backoff = std::time::Duration::from_secs(2);
let mut last_was_refused = false;
loop {
tokio::time::sleep(std::time::Duration::from_secs(5)).await;
if !state.tunnel.is_connected() {
tracing::info!(
"[tunnel-supervisor] 检测到断开,尝试重连 url={} device_id={}",
relay_url,
device_id
);
tracing::info!("[tunnel-supervisor] 断线重连 url={relay_url} device_id={device_id}");
match state
.tunnel
.connect(&relay_url, &device_id, &token, on_command.clone())
@@ -314,24 +308,39 @@ pub fn run() {
Ok(()) => {
tracing::info!("[tunnel-supervisor] 重连成功,退避重置");
backoff = std::time::Duration::from_secs(2);
last_was_refused = false;
}
Err(e) => {
tracing::warn!(
error = %e,
backoff_secs = backoff.as_secs(),
"[tunnel-supervisor] 重连失败,退避后重试"
);
tokio::time::sleep(backoff).await;
// 指数退避上限 60s,防网络长故障时高频重连打 relay
backoff = (backoff * 2).min(std::time::Duration::from_secs(60));
let refused = is_connection_refused(&e);
if refused {
// relay 未运行:INFO + 300s 退避,不刷 WARN
if !last_was_refused {
tracing::info!("[tunnel-supervisor] relay 未运行({e}),300s 后轻量探测");
last_was_refused = true;
}
// 300s 退避(避免空转刷屏,relay 未运行时一直保持此间隔)
tokio::time::sleep(std::time::Duration::from_secs(300)).await;
} else {
tracing::warn!("[tunnel-supervisor] 重连失败 {e},退避 {backoff_secs}s", backoff_secs = backoff.as_secs());
tokio::time::sleep(backoff).await;
// 指数退避上限 60s,防网络长故障时高频重连打 relay
backoff = (backoff * 2).min(std::time::Duration::from_secs(60));
last_was_refused = false;
}
}
}
} else if last_was_refused {
last_was_refused = false;
}
}
});
Ok(())
})
// 辅助函数 is_connection_refused 在文件尾部
// 判断 TunnelError 是否为连接被拒(relay 未运行)。
// 匹配 WS connect_async 产生的 IO error:ECONNREFUSED(Win:10061,Unix:111)。
// 被拒 → relay 未部署,用长退避避免刷屏;其他错误(超时/DNS/网络瞬断)走指数退避。
.invoke_handler(tauri::generate_handler![
// 项目
commands::project::list_projects,
@@ -500,3 +509,12 @@ pub fn run() {
.run(tauri::generate_context!())
.expect("error while running tauri application");
}
/// 判断 TunnelError 是否为连接被拒(匹配 ECONNREFUSED 各平台表述)
fn is_connection_refused(e: &df_tunnel::TunnelError) -> bool {
let msg = e.to_string().to_lowercase();
msg.contains("refused")
|| msg.contains("10061")
|| msg.contains("积极拒绝")
|| msg.contains("actively refused")
}