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.
New crate implementing the application daemon entry point:
- crates/weft-appd/Cargo.toml: tokio (current-thread runtime), anyhow,
sd-notify, tracing dependencies
- crates/weft-appd/src/main.rs: async run() resolves IPC socket path
from WEFT_APPD_SOCKET or XDG_RUNTIME_DIR/weft/appd.sock; stubs for
AppRegistry, IpcServer, CompositorClient, RuntimeSupervisor,
CapabilityBroker, ResourceController per WEFT-OS-APPD-DESIGN.md;
sd_notify(READY=1) to be sent after IpcServer bind + CompositorClient
connect
- infra/systemd/weft-appd.service: Type=notify, Requires+After
weft-compositor.service, After servo-shell.service
Also fix two winit backend issues that were present in the working tree:
- remove spurious mut on display binding (never mutated after init)
- wrap std::env::set_var in unsafe block (required since Rust 1.80)
Includes winit Wayland input audit for servo-shell integration planning.
New files:
- crates/weft-servo-shell/: new workspace member
- Cargo.toml: anyhow + tracing deps; no servo dep yet (requires git
dependency on github.com/servo/servo with multi-minute build; deferred
until embedder contract is confirmed)
- src/main.rs: reads WAYLAND_DISPLAY and WEFT_SYSTEM_UI_HTML, locates
system-ui.html from packaged path, calls embed_servo() stub that
returns a descriptive error explaining the integration work remaining
- infra/shell/system-ui.html: system UI document per blueprint Section 5
DOM structure (weft-desktop, weft-wallpaper, weft-taskbar, weft-launcher,
weft-notification-center, weft-window); includes clock and launcher toggle
- infra/systemd/servo-shell.service: Requires+After weft-compositor.service,
Type=simple, Restart=on-failure
- docs/architecture/winit-wayland-audit.md: audit of winit 0.30.x Wayland
backend against WEFT input requirements; identifies keyboard shortcut
inhibit gap, touch gesture gap, IME incomplete (zwp_text_input_v3),
frame pacing absent (wp_presentation_time), DMA-BUF unverified;
none block initial integration; all tracked as pre-GA work items
Modified:
- Cargo.toml: add weft-servo-shell to workspace members
- scripts/wsl-check.sh: switch to --workspace for all three gates