新增: Phase3 src-tauri 集成 df-tunnel(跨端闭环)
Cargo.toml(df-tunnel+uuid workspace) + state.rs(tunnel 字段 Arc<WsTunnelClient>) + lib.rs spawn tunnel task:device_id(KV/UUID 持久) + relay_url(KV/默认 localhost:8080) + token 固定常量 + subscriber(ai_event_bus→send_raw_event) + on_command(remote_bridge 下行路由) + connect(失败非阻断)。打通桌面↔relay↔miniapp 全双工闭环。cargo EXIT=0。
This commit is contained in:
@@ -6,6 +6,8 @@ mod state;
|
||||
use tauri::{Emitter, Listener, Manager};
|
||||
|
||||
use state::AppState;
|
||||
// Phase3 跨端隧道:TunnelClient trait(connect/send_raw_event/disconnect 方法)需在作用域内
|
||||
use df_tunnel::TunnelClient;
|
||||
|
||||
#[cfg_attr(mobile, tauri::mobile_entry_point)]
|
||||
pub fn run() {
|
||||
@@ -86,6 +88,90 @@ pub fn run() {
|
||||
});
|
||||
});
|
||||
|
||||
// Phase3 跨端隧道集成:tunnel connect relay + subscriber 透传 ai_event_bus → miniapp
|
||||
// + on_command 下行路由(miniap 指令 → remote_bridge → Tauri command)。
|
||||
// spawn 后台 task:device_id/relay_url 解析(持久 KV,无则默认)→ subscriber 透传
|
||||
// → on_command 回调注册 → connect(失败非阻断,可后续手动重连)。
|
||||
let tunnel_app = app.handle().clone();
|
||||
tauri::async_runtime::spawn(async move {
|
||||
let state = tunnel_app.state::<AppState>();
|
||||
|
||||
// device_id:KV 取,无则生成 UUID v4 落库(持久,relay 按 device_id 路由配对)。
|
||||
let device_id = match state.settings.get("device_id").await {
|
||||
Ok(Some(id)) if !id.is_empty() => id,
|
||||
_ => {
|
||||
let id = uuid::Uuid::new_v4().to_string();
|
||||
let _ = state.settings.set("device_id", &id).await;
|
||||
id
|
||||
}
|
||||
};
|
||||
// relay_url:KV 取,无则默认本地(df-miniapp config.ts:33 同源 localhost:8080)。
|
||||
let relay_url = state
|
||||
.settings
|
||||
.get("relay_url")
|
||||
.await
|
||||
.ok()
|
||||
.flatten()
|
||||
.filter(|s| !s.is_empty())
|
||||
.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();
|
||||
|
||||
// subscriber task:subscribe ai_event_bus → tunnel.send_raw_event 透传 miniapp
|
||||
let mut rx = state.ai_event_bus.subscribe();
|
||||
let tunnel_for_sub = state.tunnel.clone();
|
||||
tauri::async_runtime::spawn(async move {
|
||||
tracing::info!("[tunnel-sub] subscriber task 启动,透传 ai_event_bus → relay");
|
||||
while let Ok(value) = rx.recv().await {
|
||||
if let Err(e) = tunnel_for_sub.send_raw_event(value).await {
|
||||
tracing::warn!("[tunnel-sub] send_raw_event 失败(可能未连接): {}", e);
|
||||
}
|
||||
}
|
||||
tracing::info!("[tunnel-sub] subscriber task 退出(rx 关闭)");
|
||||
});
|
||||
|
||||
// on_command 回调:miniapp 下行指令 → remote_bridge 路由 Tauri command。
|
||||
// CommandHandler = Arc<dyn Fn(Value) -> BoxFuture<'static, ()> + Send + Sync>
|
||||
// (tunnel.rs:45)。回调返 BoxFuture,Box::pin 构造 + 类型标注对齐签名。
|
||||
//
|
||||
// 借用处理:`handle_remote_command(payload, app, state)` 的 state 是
|
||||
// `State<'_, AppState>`(newtype `&AppState`),借用 app。若先 `let state =
|
||||
// app.state()` 再 move app 入函数,E0505(借用的 app 被 move)。
|
||||
// 正解:同一表达式内 `app.clone()` move clone、`app.state()` 借用原 app,
|
||||
// 原 app 不 move(仅被 state 借用到调用结束),借用检查通过。
|
||||
let cmd_app = tunnel_app.clone();
|
||||
let on_command: df_tunnel::tunnel::CommandHandler = std::sync::Arc::new(
|
||||
move |payload: serde_json::Value| {
|
||||
let app = cmd_app.clone();
|
||||
Box::pin(async move {
|
||||
crate::commands::ai::remote_bridge::handle_remote_command(
|
||||
payload,
|
||||
app.clone(),
|
||||
app.state::<AppState>(),
|
||||
)
|
||||
.await;
|
||||
})
|
||||
as std::pin::Pin<
|
||||
Box<dyn std::future::Future<Output = ()> + Send>,
|
||||
>
|
||||
},
|
||||
);
|
||||
|
||||
// connect(失败非阻断,tunnel 可后续手动重连)。收发循环在 client 内部 spawn。
|
||||
match state
|
||||
.tunnel
|
||||
.connect(&relay_url, &device_id, &token, on_command)
|
||||
.await
|
||||
{
|
||||
Ok(()) => tracing::info!(
|
||||
"[tunnel] 连接 relay 成功 device_id={} url={}",
|
||||
device_id,
|
||||
relay_url
|
||||
),
|
||||
Err(e) => tracing::warn!("[tunnel] 连接 relay 失败(非阻断): {}", e),
|
||||
}
|
||||
});
|
||||
|
||||
Ok(())
|
||||
})
|
||||
.invoke_handler(tauri::generate_handler![
|
||||
|
||||
Reference in New Issue
Block a user