新增: 小程序端跨端AI对话
This commit is contained in:
@@ -105,7 +105,10 @@ pub fn run() {
|
||||
id
|
||||
}
|
||||
};
|
||||
// relay_url:KV 取,无则默认本地(df-miniapp config.ts:33 同源 localhost:8080)。
|
||||
// relay_url:KV 取,无则默认本地(localhost:8080,本地开发 df-relay 默认监听)。
|
||||
// settings value 契约模糊(JSON 序列化带引号或裸值并存,见 SettingsRepo get/set 不解析 JSON):
|
||||
// 统一解析去引号 —— serde_json::from_str 处理 JSON 字符串值,失败(裸值)则 trim 首尾引号兜底,
|
||||
// 确保拿到纯净 URL 供 connect_async(带引号 URL 解析失败致 connect 静默失败,relay 无 device 接入)。
|
||||
let relay_url = state
|
||||
.settings
|
||||
.get("relay_url")
|
||||
@@ -113,6 +116,10 @@ pub fn run() {
|
||||
.ok()
|
||||
.flatten()
|
||||
.filter(|s| !s.is_empty())
|
||||
.map(|raw| {
|
||||
serde_json::from_str::<String>(&raw)
|
||||
.unwrap_or_else(|_| raw.trim_matches('"').to_string())
|
||||
})
|
||||
.unwrap_or_else(|| "ws://localhost:8080/ws/device".to_string());
|
||||
// token:固定常量(三端同源,对齐 df-relay relay.rs:37 DEFAULT_TOKEN)
|
||||
let token = "devflow-relay-default-token".to_string();
|
||||
@@ -157,10 +164,11 @@ pub fn run() {
|
||||
},
|
||||
);
|
||||
|
||||
// connect(失败非阻断,tunnel 可后续手动重连)。收发循环在 client 内部 spawn。
|
||||
// connect(失败非阻断,supervisor 兜底重连)。收发循环在 client 内部 spawn。
|
||||
// 注:on_command 用 clone 传入 connect(原值留给 supervisor 重连复用,Arc clone 廉价)。
|
||||
match state
|
||||
.tunnel
|
||||
.connect(&relay_url, &device_id, &token, on_command)
|
||||
.connect(&relay_url, &device_id, &token, on_command.clone())
|
||||
.await
|
||||
{
|
||||
Ok(()) => tracing::info!(
|
||||
@@ -168,7 +176,44 @@ pub fn run() {
|
||||
device_id,
|
||||
relay_url
|
||||
),
|
||||
Err(e) => tracing::warn!("[tunnel] 连接 relay 失败(非阻断): {}", e),
|
||||
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 生命周期 = 应用生命周期)。
|
||||
let mut backoff = std::time::Duration::from_secs(2);
|
||||
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
|
||||
);
|
||||
match state
|
||||
.tunnel
|
||||
.connect(&relay_url, &device_id, &token, on_command.clone())
|
||||
.await
|
||||
{
|
||||
Ok(()) => {
|
||||
tracing::info!("[tunnel-supervisor] 重连成功,退避重置");
|
||||
backoff = std::time::Duration::from_secs(2);
|
||||
}
|
||||
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));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
Reference in New Issue
Block a user