mirror of
https://github.com/marcoallegretti/WEFT_OS.git
synced 2026-03-27 09:23:09 +00:00
Implements the weft-appd WebSocket server that allows the system-ui.html page running inside Servo to send requests and receive push notifications without requiring custom SpiderMonkey bindings. ws.rs — WebSocket connection handler: - Accepts a tokio TcpStream, performs WebSocket handshake via tokio-tungstenite accept_async. - Reads JSON Text frames, deserializes as Request (serde_json), calls dispatch(), sends Response as JSON Text. - Subscribes to a broadcast::Receiver<Response> for server-push notifications (APP_READY, etc.); forwards to client via select!. - Handles close frames, partial errors, and lagged broadcast gracefully. main.rs — server changes: - broadcast::channel(16) created at startup; WebSocket handlers subscribe for push delivery. - TcpListener bound on 127.0.0.1:7410 (default) or WEFT_APPD_WS_PORT. - ws_port() / write_ws_port(): port written to XDG_RUNTIME_DIR/weft/appd.wsport for runtime discovery. - WS accept branch added to the main select! loop alongside Unix socket. ipc.rs — Response and AppStateKind now derive Clone (required by broadcast::Sender<Response>). system-ui.html — appd WebSocket client: - appdConnect(): opens ws://127.0.0.1:<port>/appd with exponential backoff reconnect (1s → 16s max). - On open: sends QUERY_RUNNING to populate taskbar with live sessions. - handleAppdMessage(): maps LAUNCH_ACK and RUNNING_APPS to taskbar entries; APP_READY shows a timed notification; APP_STATE::stopped removes the taskbar entry. - WEFT_APPD_WS_PORT window global overrides the default port. New deps: tokio-tungstenite 0.24, futures-util 0.3 (sink+std), serde_json 1.
54 lines
2 KiB
Rust
54 lines
2 KiB
Rust
use futures_util::{SinkExt, StreamExt};
|
|
use tokio::sync::broadcast;
|
|
use tokio_tungstenite::{accept_async, tungstenite::Message};
|
|
|
|
use crate::{Registry, dispatch, ipc::Request, ipc::Response};
|
|
|
|
pub async fn handle_ws_connection(
|
|
stream: tokio::net::TcpStream,
|
|
registry: Registry,
|
|
broadcast_rx: broadcast::Receiver<Response>,
|
|
) -> anyhow::Result<()> {
|
|
let ws_stream = accept_async(stream).await?;
|
|
let (mut ws_write, mut ws_read) = ws_stream.split();
|
|
let mut broadcast_rx = broadcast_rx;
|
|
|
|
loop {
|
|
tokio::select! {
|
|
msg = ws_read.next() => {
|
|
match msg {
|
|
Some(Ok(Message::Text(text))) => {
|
|
let req: Request = match serde_json::from_str(&text) {
|
|
Ok(r) => r,
|
|
Err(e) => {
|
|
tracing::warn!(error = %e, "invalid WS request");
|
|
continue;
|
|
}
|
|
};
|
|
tracing::debug!(?req, "ws request");
|
|
let resp = dispatch(req, ®istry).await;
|
|
let json = serde_json::to_string(&resp)?;
|
|
ws_write.send(Message::Text(json)).await?;
|
|
}
|
|
Some(Ok(Message::Close(_))) | None => break,
|
|
Some(Ok(_)) => {}
|
|
Some(Err(e)) => {
|
|
tracing::warn!(error = %e, "ws error");
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
notification = broadcast_rx.recv() => {
|
|
match notification {
|
|
Ok(resp) => {
|
|
let json = serde_json::to_string(&resp)?;
|
|
ws_write.send(Message::Text(json)).await?;
|
|
}
|
|
Err(broadcast::error::RecvError::Lagged(_)) => {}
|
|
Err(broadcast::error::RecvError::Closed) => break,
|
|
}
|
|
}
|
|
}
|
|
}
|
|
Ok(())
|
|
}
|