perf(tauri): Rust-native desktop event transport#16
Conversation
Reintroduce the smallest Tauri-native event transport slice needed to compare it against the browser EventSource path on real sessions. Add a frontend/server benchmark hook so the desktop runtime can report end-to-end transport behavior without pulling in the broader UI performance changes from the original PR. # Conflicts: # packages/tauri-app/src-tauri/src/cli_manager.rs # Conflicts: # packages/tauri-app/src-tauri/src/main.rs
Handle named SSE ping events with explicit pong replies so the native transport survives the server heartbeat window, and remove the unused active-session fast path while keeping the benchmark harness authenticated. # Conflicts: # packages/tauri-app/src-tauri/src/cli_manager.rs
Require the explicit bench build flag before the UI harness can be activated, remove query-string command overrides, gate perf logging behind a runtime flag, and add a regression test for named SSE ping frames.
Reuse the desktop event transport session cookie for the native /api/client-connections/pong request so heartbeat updates follow the same auth contract as the SSE stream, and cover it with a request-header regression test.
Expose a device-level setting that lets Tauri users disable the native Rust desktop event transport and fall back to the browser EventSource path when debugging transport issues or comparing behavior. Persist the preference in UI settings, mirror it into localStorage so startup transport selection can read it synchronously, and restart the backend event stream immediately when the toggle changes so the new transport takes effect without a full app restart. Validation: npx tsc --noEmit --pretty -p packages/ui/tsconfig.json; npx tsc --noEmit --pretty -p packages/server/tsconfig.json; cargo test --no-run
Move the Tauri native transport fallback toggle out of the shared UI config and treat it as a true device-local preference. The setting now lives only in local state plus localStorage, so browser, Electron, and other Tauri clients do not inherit a host-specific transport choice through storage broadcasts. While updating the selector, remove the hidden forceBrowserEvents override so the visible Tauri fallback setting becomes the only shipped transport-selection path outside the benchmark build gates. Validation: npx tsc --noEmit --pretty -p packages/ui/tsconfig.json; npx tsc --noEmit --pretty -p packages/server/tsconfig.json; cargo test --no-run
The transport benchmark harness still called loadMessages with the old boolean force flag, which broke UI typecheck after the session API moved to an options object. This keeps the PR242 benchmark code compatible with the current Pagec_tauri integration baseline instead of leaving a validation-only regression on the stack.
The change is limited to the benchmark harness and preserves the existing forced reload behavior by switching to the current { force: true } call shape. This keeps the fix scoped to the branch that introduced the transport bench so downstream integrations can cherry-pick a normal commit without rewriting history.
Validation: npm run typecheck --workspace @codenomad/ui
Drop the temporary in-app benchmark harness, perf logging endpoint, and batch metrics now that the native desktop transport has been validated on Windows and Linux. Keep the shipped PR focused on the transport implementation and the user-facing Tauri fallback setting rather than the instrumentation used during evaluation. The benchmark results are preserved in the PR description as historical validation, but the benchmark code itself no longer ships in the branch. Validation: npx tsc --noEmit --pretty -p packages/ui/tsconfig.json; npx tsc --noEmit --pretty -p packages/server/tsconfig.json; cargo test --no-run # Conflicts: # packages/ui/src/transport-bench.tsx
Guard the async event-stream connect failure path with the same generation check used by the success callbacks so an older rejected connection attempt cannot tear down a newer healthy stream. This keeps Tauri restarts and other reconnect races from disconnecting the active transport after the local desktop transport preference changes or another connection attempt wins first. Validation: npx tsc --noEmit --pretty -p packages/ui/tsconfig.json; npx tsc --noEmit --pretty -p packages/server/tsconfig.json
Fix the current upstream/dev baseline type mismatches exposed during the integrated PR batch validation. Align the session SDK imports with the v2 surface and narrow the git status workspace payload typing so the merged batch typechecks cleanly without changing feature behavior.
Merge current upstream/dev into pagec/rust-desktop-event-transport to clear PR NeuralNomadsAI#242 conflicts. The conflict resolution preserves the recent-folder/project-name launch flow from upstream while keeping the native Tauri event transport wiring, and retains the SDK v2 session type/diff compatibility already validated in the integrated Pagec_tauri branch. Validation: git diff --check and npm run typecheck --workspace @codenomad/ui.
Prioritize packaged server entrypoint candidates before the workspace fallback in production desktop launches, compare native event transport starts without the generated connection id, and percent-encode unsafe cookie-value bytes before building Cookie headers. Adds focused Rust coverage for production candidate ordering, idempotent transport starts with fresh connection ids, material stream changes, and Cookie header delimiter/control-byte encoding. Validated with the Tauri Rust test suite.
|
| Filename | Overview |
|---|---|
| packages/tauri-app/src-tauri/src/desktop_event_transport.rs | New core module; defines public types (DesktopEventStreamConfig, DesktopEventsStartRequest, DesktopEventTransportManager) and event classification / coalescing logic. Minor inconsistency in delta_scope where session_id falls back to empty string instead of bailing with ? like sibling functions. |
| packages/tauri-app/src-tauri/src/desktop_event_transport/transport.rs | Run-loop, reconnect scheduling, and batch/status emission. Blocking pong send shares the consumer thread with no read timeout; acceptable for localhost but could stall event delivery if pong endpoint hangs. |
| packages/tauri-app/src-tauri/src/desktop_event_transport/stream.rs | SSE parsing, named-event dispatch, cookie resolution, and RFC-6265-compliant cookie header encoding. Well tested; path matching in read_session_cookie_from_webview uses a simplified starts_with (not strictly RFC 6265) but is harmless for localhost URLs. |
| packages/tauri-app/src-tauri/src/desktop_event_transport/assembler.rs | PendingBatch: delta coalescing (append), snapshot coalescing (last-write-wins, drops superseded deltas), status coalescing, and hold-window logic. Logic is correct and comprehensively tested. |
| packages/tauri-app/src-tauri/src/desktop_event_transport/tests.rs | Good test coverage for coalescing scenarios, reconnect delay computation, delta hold window, and equivalence checks. |
| packages/tauri-app/src-tauri/src/cli_manager.rs | Adds session_cookie / auth_cookie_name Arc storage, desktop_event_stream_config() builder, augment_launch_url() with fragment trimming, and test coverage for the new helpers. |
| packages/ui/src/lib/native/desktop-events.ts | connectTauriWorkspaceEvents: registers Tauri listeners before invoking start, buffers events until generation is confirmed, and uses the new createTerminalErrorNotifier for idempotent error callbacks. Clean and well-structured. |
| packages/ui/src/lib/server-events.ts | Refactored from EventSource to abstract WorkspaceEventConnection. Adds connect-generation guard to prevent stale callbacks, adds restart() method, and wraps batch dispatch in solidBatch(). The onPing callback for native transport is now handled in Rust; for the browser path it is still forwarded through event-transport.ts correctly. |
| packages/ui/src/lib/event-transport.ts | Transport selector: native Tauri if available and enabled, with transparent fallback to browser EventSource on failure. Clean abstraction layer. |
| packages/ui/src/stores/preferences.tsx | Adds useTauriNativeEventTransport signal backed by localStorage, with setUseTauriNativeEventTransport triggering an immediate server-events restart on change. |
Sequence Diagram
sequenceDiagram
participant UI as TypeScript UI
participant SE as ServerEvents
participant ET as event-transport.ts
participant DET as desktop-events.ts (Tauri)
participant Rust as DesktopEventTransportManager
participant Server as Local Server
UI->>SE: new ServerEvents() → connect()
SE->>ET: connectWorkspaceEvents(callbacks)
ET->>ET: readUseTauriNativeEventTransportPreference()
alt Tauri host + native enabled
ET->>DET: connectTauriWorkspaceEvents(callbacks, options)
DET->>DET: listen("desktop:event-batch")
DET->>DET: listen("desktop:event-stream-status")
DET->>Rust: "invoke("desktop_events_start", {request})"
Rust->>Rust: spawn run_transport_loop(generation)
Rust->>Server: "GET /api/events?clientId=&connectionId= (SSE)"
Rust-->>DET: "desktop:event-stream-status {state:"connecting"}"
Server-->>Rust: HTTP 200 text/event-stream
Rust-->>DET: "desktop:event-stream-status {state:"connected"}"
DET->>SE: callbacks.onOpen()
Server-->>Rust: "data: {event JSON}"
Rust->>Rust: PendingBatch.push() — coalesce deltas/snapshots/status
Rust-->>DET: "desktop:event-batch {generation, sequence, events[]}"
DET->>SE: callbacks.onBatch(events)
SE->>UI: "solidBatch(() => dispatch each event)"
Server-->>Rust: "event: codenomad.client.ping / data: {ts:…}"
Rust->>Server: POST /api/client-connections/pong (blocking, consumer thread)
else Browser / Electron or fallback
ET->>SE: connectBrowserWorkspaceEvents(callbacks)
SE->>Server: new EventSource(/api/events)
Server-->>SE: SSE stream
SE->>UI: dispatch(event)
end
UI->>SE: (pref toggle) setUseTauriNativeEventTransport(false)
SE->>SE: serverEvents.restart("desktop transport preference changed")
SE->>Rust: invoke("desktop_events_stop")
SE->>ET: connectWorkspaceEvents() → browser path
Reviews (2): Last reviewed commit: "fix: task-084 address Greptile transport..." | Re-trigger Greptile
|
PR builds are available as GitHub Actions artifacts: https://github.com/Pagecran/CodeNomad/actions/runs/27062398244 Artifacts expire in 7 days.
|
Ensure native desktop terminal status handling raises onError only once per terminal sequence, including stopped events after terminal failures. Trim leading fragment markers from CODENOMAD_UI_LAUNCH_QUERY before appending launch query values, and add focused TypeScript and Rust tests for the regressions.
|
PR builds are available as GitHub Actions artifacts: https://github.com/Pagecran/CodeNomad/actions/runs/27063307975 Artifacts expire in 7 days.
|
Summary
EventSourcepath to a native Rust desktop event transport while leaving browser and Electron unchangedevent:frames and replying tocodenomad.client.pingwith an authenticated/api/client-connections/pongEventSourcetransport without leaking that choice through shared configBenchmark
The temporary in-app benchmark harness used during validation has been removed from the final code, but the measured results are retained here for review context.
Real Tauri/WebView2 benchmark on Windows using the dedicated session:
D:\CodeNomadses_21feb15b3ffeLz3uRModK4KKnGShort command:
node -e "for (let i = 1; i <= 400; i += 1) console.log('line ' + i)"Results:
EventSourceforced in Tauri:131479.7mssawWorking=falsereachedIdle=falsebatchesReceived=84eventsReceived=84maxBatchSize=11437.4mssawWorking=truereachedIdle=truebatchesReceived=4eventsReceived=45maxBatchSize=27Long heartbeat / stale-timeout validation:
powershell -NoProfile -Command Start-Sleep -Seconds 7071689.5mssawWorking=truereachedIdle=truebatchesReceived=13eventsReceived=72maxBatchSize=25Confirmed separately afterward: the native transport also behaves better on Linux.
Validation
cargo test named_ping_event_is_routed_to_ping_channelcargo test session_cookie_is_attached_to_requestscargo test --no-runnpx tsc --noEmit --pretty -p packages/ui/tsconfig.jsonnpx tsc --noEmit --pretty -p packages/server/tsconfig.jsonNotes
EventSourcepathFork-local note
This PR is opened in the Pagecran fork to trigger a fresh Greptile review on the updated PR NeuralNomadsAI#242 branch after addressing the first Greptile pass.
Source upstream PR: NeuralNomadsAI#242
Previous fork-local review PR: #15