Skip to content

perf(tauri): Rust-native desktop event transport#16

Closed
pascalandr wants to merge 17 commits into
devfrom
greptile-rerun-pr242
Closed

perf(tauri): Rust-native desktop event transport#16
pascalandr wants to merge 17 commits into
devfrom
greptile-rerun-pr242

Conversation

@pascalandr

Copy link
Copy Markdown

Summary

  • switch the Tauri desktop runtime from the browser EventSource path to a native Rust desktop event transport while leaving browser and Electron unchanged
  • restore SSE heartbeat parity by parsing named event: frames and replying to codenomad.client.ping with an authenticated /api/client-connections/pong
  • add a Tauri-only settings toggle that lets the current device fall back to the browser EventSource transport without leaking that choice through shared config
  • remove the temporary benchmark harness from the shipped code now that the transport behavior has been validated

Benchmark

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:

  • workspace: D:\CodeNomad
  • session: ses_21feb15b3ffeLz3uRModK4KKnG

Short command:

  • node -e "for (let i = 1; i <= 400; i += 1) console.log('line ' + i)"

Results:

  • browser EventSource forced in Tauri:
    • timed out after 131479.7ms
    • sawWorking=false
    • reachedIdle=false
    • batchesReceived=84
    • eventsReceived=84
    • maxBatchSize=1
  • Rust-native transport:
    • completed in 1437.4ms
    • sawWorking=true
    • reachedIdle=true
    • batchesReceived=4
    • eventsReceived=45
    • maxBatchSize=27

Long heartbeat / stale-timeout validation:

  • command: powershell -NoProfile -Command Start-Sleep -Seconds 70
  • Rust-native transport:
    • completed in 71689.5ms
    • sawWorking=true
    • reachedIdle=true
    • batchesReceived=13
    • eventsReceived=72
    • maxBatchSize=25

Confirmed separately afterward: the native transport also behaves better on Linux.

Validation

  • cargo test named_ping_event_is_routed_to_ping_channel
  • cargo test session_cookie_is_attached_to_requests
  • cargo test --no-run
  • npx tsc --noEmit --pretty -p packages/ui/tsconfig.json
  • npx tsc --noEmit --pretty -p packages/server/tsconfig.json
  • manual Tauri/WebView2 benchmark on Windows
  • manual confirmation on Linux after the benchmark phase

Notes

  • this remains a Tauri-only transport; browser and Electron stay on the browser EventSource path
  • the Tauri fallback toggle is now genuinely device-local and restarts the local event stream immediately when changed
  • the long run validates heartbeat / stale-timeout robustness, not headline perf

Fork-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

pascalandr added 16 commits May 11, 2026 08:16
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.
@greptile-apps

greptile-apps Bot commented Jun 6, 2026

Copy link
Copy Markdown

Greptile Summary

This PR replaces the browser EventSource path in Tauri with a native Rust SSE transport (DesktopEventTransportManager), improving throughput ~90× on Windows (per the benchmark). Browser and Electron remain on the original path; a Tauri-only localStorage toggle enables fallback to the old behavior without touching shared config.

  • Rust transport (desktop_event_transport/) opens an HTTP SSE stream with reqwest::blocking, parses named SSE frames to distinguish codenomad.client.ping heartbeats (replied to in-process) from data events, and coalesces message.part.delta, snapshot, and status events before batching them to the UI via Tauri's IPC emitter. Reconnect uses configurable exponential back-off with cancellation on generation change.
  • TypeScript layer (event-transport.ts, native/desktop-events.ts) wraps the Tauri invoke/listen APIs, buffers events until the generation is confirmed, and guards onError against double-fire with the new createTerminalErrorNotifier helper.
  • server-events.ts is refactored to dispatch through the new abstract WorkspaceEventConnection interface and wraps all batch events in a SolidJS batch() call for atomic UI updates.

Confidence Score: 5/5

Safe to merge — the Rust transport is well-isolated behind a Tauri-only code path with a functioning user-accessible fallback toggle, and no regressions are introduced to the browser or Electron paths.

The new transport is thoroughly tested (coalescing, reconnect delay, ping routing, cookie encoding), the generation/stop-flag dual-cancellation prevents stale event delivery, and the TypeScript layer correctly buffers events until the generation is confirmed. The two findings are defensive-programming improvements for scenarios that are unlikely in normal operation and cannot cause data corruption even if they occur.

desktop_event_transport.rs (delta_scope session_id handling) and transport.rs (pong request timeout) have minor robustness gaps worth addressing before the next iteration, but neither blocks merging.

Important Files Changed

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
Loading

Reviews (2): Last reviewed commit: "fix: task-084 address Greptile transport..." | Re-trigger Greptile

Comment thread packages/ui/src/lib/native/desktop-events.ts
Comment thread packages/tauri-app/src-tauri/src/cli_manager.rs Outdated
@github-actions

github-actions Bot commented Jun 6, 2026

Copy link
Copy Markdown

PR builds are available as GitHub Actions artifacts:

https://github.com/Pagecran/CodeNomad/actions/runs/27062398244

Artifacts expire in 7 days.
Artifacts:

  • pr-16-1f79720ca99c4564a381937638cb63170e051af4-tauri-macos
  • pr-16-1f79720ca99c4564a381937638cb63170e051af4-tauri-linux
  • pr-16-1f79720ca99c4564a381937638cb63170e051af4-electron-macos
  • pr-16-1f79720ca99c4564a381937638cb63170e051af4-tauri-windows
  • pr-16-1f79720ca99c4564a381937638cb63170e051af4-tauri-macos-arm64
  • pr-16-1f79720ca99c4564a381937638cb63170e051af4-electron-windows
  • pr-16-1f79720ca99c4564a381937638cb63170e051af4-electron-linux

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.
@github-actions

github-actions Bot commented Jun 6, 2026

Copy link
Copy Markdown

PR builds are available as GitHub Actions artifacts:

https://github.com/Pagecran/CodeNomad/actions/runs/27063307975

Artifacts expire in 7 days.
Artifacts:

  • pr-15-30076576e83c77087447eee5c3d5e2c822abf192-tauri-macos
  • pr-15-30076576e83c77087447eee5c3d5e2c822abf192-tauri-windows
  • pr-15-30076576e83c77087447eee5c3d5e2c822abf192-tauri-linux
  • pr-15-30076576e83c77087447eee5c3d5e2c822abf192-electron-macos
  • pr-15-30076576e83c77087447eee5c3d5e2c822abf192-tauri-macos-arm64
  • pr-15-30076576e83c77087447eee5c3d5e2c822abf192-electron-windows
  • pr-15-30076576e83c77087447eee5c3d5e2c822abf192-electron-linux

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant