Skip to content

fix(remote-connect): isolate host stream readers and recover live sync - #3877

Merged
bobleer merged 1 commit into
openBitFun:mainfrom
bobleer:bob/fix-host-stream-readers
Nov 12, 2026
Merged

bobleer merged 1 commit into
openBitFun:mainfrom
bobleer:bob/fix-host-stream-readers

Conversation

@bobleer

@bobleer bobleer commented Nov 11, 2026

Copy link
Copy Markdown
Collaborator

Summary

Make remote session streams survive retired readers and transient read failures, across the host, desktop controller, shared TS reader, KMP and HarmonyOS clients.

  • Per-reader host stream lease. The host kept one lease per controller device. A late unsubscribe_stream from a retired reader (reopened session, second view on the same device) removed the lease of the live reader, which then stopped receiving hints. read_stream now offers an optional subscription_id; a capable host echoes it in stream_page and unsubscribe_stream removes only that lease. Readers connected to older hosts get no echo, skip the unscoped unsubscribe and let the existing 10-minute lease expire. Leases per device are bounded (64) and validated.
  • Live recovery in the desktop subscriber. A failed refresh slept inside the select loop (up to 30 s), blocking hints and older-page requests, and a failure during an older-page read was never retried; if it was the last hint, catch-up waited for the 4-minute keepalive. Failures now arm a retry timer with capped backoff, also while older-page IO is blocked, and recovery is announced with relay://session-ready carrying live: true.
  • Retired-reader isolation on desktop. account_subscribe_session tags every event with a controller-local subscriptionId and marks sync errors retrying: true. RelaySessionHistory ignores events from other subscriptions (untagged legacy events stay accepted), keeps the reader alive on retrying errors, does not let a live ready complete an unrelated history page, and a failed older-page read no longer closes the live subscription.
  • Opening-page hint. The shared TS reader and the KMP hostStream subscribed to hints only after the first page, so a final hint sent while that page was in flight was lost until the next keepalive. Listeners are now installed before the opening read.
  • HarmonyOS cleanup after account switch. subscribeSession looked up the socket lazily in unsubscribe/onReconnect, so closing a stream after a sign-out or account switch could close the new account's socket. It now keeps the socket it opened.

Type and Areas

Type: bug fix

Areas: services-integrations (host stream), assembly core (remote connect), desktop/Tauri, web UI, shared relay transport, mobile web, mobile KMP, HarmonyOS

Motivation / Impact

Remote control and Peer Device Mode sessions could silently stop updating after a session was reopened or viewed twice on one device, or after a single lost live read, until the user reloaded. Wire changes are additive and optional (subscription_id, subscriptionId, live, retrying); older hosts and clients keep working through the existing lease-expiry path.

Verification

  • cargo test --locked -p openbitfun-services-integrations --no-default-features --features remote-connect --lib remote_connect::host_stream (42 passed, includes new lease and live-retry tests)
  • cargo test --locked -p openbitfun-core --no-default-features --features remote-connect --lib service::remote_connect:: (includes host_stream_command_tests)
  • cargo test --locked -p openbitfun-desktop --lib relay_routes_tests (desktop crate compiles; route tests pass)
  • npx vitest run src/flow_chat/services/RelaySessionHistory.test.ts src/flow_chat/store/FlowChatStore.test.ts in src/web-ui; tsc --noEmit for web-ui and mobile-web
  • node --test tests/host-stream.test.mjs tests/session-stream-browser.test.mjs in src/mobile-web (18 passed)
  • node --test src/apps/mobile/harmonyos/tools/tests/host-stream.test.cjs (11 passed)
  • ./gradlew :core-transport:jvmTest :core-protocol:jvmTest (HostStreamTest, CloudAccountClientTest pass)

Remote scenarios: exercised only with local loopback fixtures and fakes (remote control / Peer Device stream paths). Not verified against a live Relay or real devices.

Reviewer Notes

AI-assisted change, lightly tested as listed above.

Checklist

  • This PR is focused and does not include secrets, temporary prompts, generated scratch files, or unrelated artifacts.
  • Relevant verification is recorded above, or skipped checks are explained.
  • User-facing strings, docs, and locales are updated where applicable.

- Give every host stream reader its own optional subscription_id lease. A
  capable host echoes it and removes only that lease on unsubscribe, so a
  retired reader's late cleanup no longer cancels its replacement. Readers
  talking to older hosts skip cleanup and let the existing lease expire.
- Retry a failed live read on a timer with capped backoff instead of sleeping
  inside the subscriber loop, also during older-page IO, and report recovery
  with a live ready event that does not complete an unrelated history page.
- Tag desktop session events with a controller-local subscriptionId and mark
  retryable sync errors so a stale reader cannot fail its successor.
- Install hint and reconnect listeners before the opening read in the shared
  TS and KMP readers so a final hint during that read is not lost.
- HarmonyOS stream cleanup keeps the socket it opened, so closing after an
  account switch cannot touch the new account's connection.
@bobleer
bobleer merged commit e856908 into openBitFun:main Nov 12, 2026
13 checks passed
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