feat(connection): resilient reconnect for changing networks + Disconnect button#21
Merged
HarryCordewener merged 1 commit intoJul 1, 2026
Conversation
…ect button Makes a session survive the network churn of a long drive (WiFi↔cellular, tower handoffs, dead zones) and adds a manual escape hatch. Core: - ForceReconnectAsync() on TelnetConnection/ITelnetConnection — reconnect now to the last endpoint, tearing down the dead socket and any backoff; resumes even after auto-reconnect gave up (Error). No-op after an intentional disconnect. - Tune TCP keepalive (30s idle / 10s interval / 3 probes) so a silently-dead peer surfaces in ~1 min instead of the OS default (~2h). - Application-level IAC NOP heartbeat (45s) that keeps the server session alive and drops+reconnects when a write fails. - ReconnectOptions.Default retries far longer (MaxAttempts 6 → 60, ~30 min) so a long dead zone doesn't permanently give up. - Intentional DisconnectAsync + ForceReconnectAsync on ISession/Session. Android: - Keep-alive service now watches the DEFAULT network: on a change it pins the process to the new network (BindProcessToNetwork) and signals a reconnect; ConnectionKeepAliveCoordinator turns that into an immediate ForceReconnect on every session. NetworkChangeSignal bridges the two without the coordinator referencing Android-only types. UI: - Disconnect button in the session header (drops the connection / stops auto-reconnect) for when the client thinks it's connected but the socket is dead. Builds off the reconnect auto-login fix so a reconnected session re-authenticates. Core 198 / UI 47 / Data 17 tests pass; Android head builds clean. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01HHCRc5CJ6595iMzEgYYdQp
HarryCordewener
added a commit
that referenced
this pull request
Jul 1, 2026
* fix(session): re-send auto-login on automatic reconnect When a session dropped and TelnetConnection reconnected on its own, the stored connect string was never re-sent — the launcher only sent it once, on the initial connect. So an auto-reconnected session was left sitting at the server's login screen (unauthenticated), and with an empty input box the Send button stays disabled, leaving the user stuck. Move the auto-login into the Session: it now runs on every transition into Connected (initial connect AND each auto-reconnect) via a provider that resolves the character's stored connect string from the secret store on demand. The launcher supplies the provider and no longer sends the credential itself. Adds SessionSendsAutoLoginOnConnectAndReconnect and SessionWithoutAutoLoginSendsNothingOnConnect; full Core suite (196) passes. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01HHCRc5CJ6595iMzEgYYdQp * feat(connection): resilient reconnect for changing networks + Disconnect button (#21) Makes a session survive the network churn of a long drive (WiFi↔cellular, tower handoffs, dead zones) and adds a manual escape hatch. Core: - ForceReconnectAsync() on TelnetConnection/ITelnetConnection — reconnect now to the last endpoint, tearing down the dead socket and any backoff; resumes even after auto-reconnect gave up (Error). No-op after an intentional disconnect. - Tune TCP keepalive (30s idle / 10s interval / 3 probes) so a silently-dead peer surfaces in ~1 min instead of the OS default (~2h). - Application-level IAC NOP heartbeat (45s) that keeps the server session alive and drops+reconnects when a write fails. - ReconnectOptions.Default retries far longer (MaxAttempts 6 → 60, ~30 min) so a long dead zone doesn't permanently give up. - Intentional DisconnectAsync + ForceReconnectAsync on ISession/Session. Android: - Keep-alive service now watches the DEFAULT network: on a change it pins the process to the new network (BindProcessToNetwork) and signals a reconnect; ConnectionKeepAliveCoordinator turns that into an immediate ForceReconnect on every session. NetworkChangeSignal bridges the two without the coordinator referencing Android-only types. UI: - Disconnect button in the session header (drops the connection / stops auto-reconnect) for when the client thinks it's connected but the socket is dead. Builds off the reconnect auto-login fix so a reconnected session re-authenticates. Core 198 / UI 47 / Data 17 tests pass; Android head builds clean. Claude-Session: https://claude.ai/code/session_01HHCRc5CJ6595iMzEgYYdQp Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Makes a session survive the network churn of a long drive (WiFi↔cellular, tower handoffs, dead zones) and adds a manual escape hatch. Implements the options discussed: #1 react to network changes, #2 survive long dead zones, #3 bind to the active network, #4 faster silent-death detection — plus a Disconnect button.
Core
ForceReconnectAsync()onTelnetConnection/ITelnetConnection— reconnect now to the last endpoint, tearing down the dead socket and any backoff. Resumes even after auto-reconnect gave up (Error); no-op after an intentional disconnect. (Phase 1: core telnet/ANSI/session pipeline #1)ReconnectOptions.Defaultretries far longer (MaxAttempts6 → 60, ~30 min) so a long gap doesn't permanently give up. (Phase 2: UI foundation → feature-complete MUSH client (web preview + Android) #2)DisconnectAsync+ForceReconnectAsynconISession/Session.Android
BindProcessToNetwork, ci: PR unit tests + release APK build workflows #3) and raises a signal;ConnectionKeepAliveCoordinatorturns that into an immediateForceReconnecton every session (Phase 1: core telnet/ANSI/session pipeline #1).NetworkChangeSignalbridges the two without the coordinator touching Android-only types. Permissions already present.UI
Tests
SessionDisconnectStopsTheConnection,SessionForceReconnectDelegatesToConnection(plus the auto-login tests from fix(session): re-send auto-login on automatic reconnect #20).🤖 Generated with Claude Code