feat(server): add fallback URL with automatic failover#109
Open
yashpatil27 wants to merge 1 commit into
Open
Conversation
Adds a fallback endpoint to each server so the app can keep connecting when the primary URL is unreachable. Supports common LAN/WAN, DDNS, and reverse-proxy setups, and reduces manual intervention when switching networks.
- ServerConfig: new optional fields useFallback, fallbackHost, fallbackPort, fallbackUseHttps, fallbackBasePath. New ServerEndpointKind union.
- utils/server.ts: hasFallback, resolveServerEndpoint, getServerEndpointLabel, getActiveEndpoint helpers.
- ServerManager.connectToServer: try primary first, then fallback only on network errors. Auth/permission errors do not trigger fallback because credentials are shared with the primary.
- ServerManager.testConnection: returns ConnectionTestResult with optional primary/fallback per-endpoint outcomes when fallback is configured; preserves the simple shape for primary-only servers.
- ServerContext: exposes activeEndpoint ('primary' | 'fallback' | null), updated on connect, reconnect, auto-connect, and disconnect.
- storage.ts: persists the new fallback fields alongside existing server data; missing fields naturally mean fallback is disabled, no migration needed.
- app/server/add.tsx and app/server/[id].tsx: new 'Fallback URL' section with switch + conditional host/port/HTTPS fields, validation, save, and edit round-trip. Test Connection now reports per-endpoint outcomes when fallback is enabled.
- app/(tabs)/settings.tsx: connection card shows a 'Connected via primary' / 'Connected via fallback' subtitle when fallback is configured.
- i18n: 12 new strings added across en, es, zh, fr, de, ru (fallback section title, switch + hint, fallback HTTPS, primary/fallback endpoint labels, per-endpoint test result text, connected-via labels, fallback host placeholder, fallback host validation error).
Closes taylorcox75#14
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.
Closes #14
Summary
Adds a fallback endpoint to each server. When the primary URL is unreachable, the app automatically tries the configured fallback (LAN ↔ WAN, DDNS vs static IP, reverse proxy vs direct, etc.), so the user doesn't have to manually edit the server every time the network context changes.
The feature is fully optional — existing servers continue to work exactly as before with no fallback configured, no migration required.
Behavior
Save / Edit
Connect
current_server_idis the same regardless of which endpoint won, so the rest of the app sees a single logical server.reconnect()andcheckAndReconnect()reuse the same flow — fallback happens automatically on stale-connection recovery.Test Connection
Settings tab
What changed
Data model —
types/api.tsServerConfigextended with optional fields:useFallback,fallbackHost,fallbackPort,fallbackUseHttps,fallbackBasePath(last one is reserved for a future UI; data-model parity only).ServerEndpointKind = 'primary' | 'fallback'union.Helpers —
utils/server.tshasFallback(server)— true when fallback is enabled and a host is set.resolveServerEndpoint(server, endpoint)— returns a transientServerConfigwhose host/port/useHttps/basePath are swapped for the chosen endpoint, leaving id/credentials intact so cookies and stored IDs remain coherent.getServerEndpointLabel(server, endpoint)— display string helper.getActiveEndpoint(server, activeServer)— derives which endpoint the API client is currently on by comparing host/port/HTTPS against both resolved endpoints.Connection logic —
services/server-manager.tsconnectToServer(server)refactored: tries primary via a shared privateconnectToEndpoint(server, resolved, endpoint)path, catches network errors, and re-runs the same path against the resolved fallback when configured. Non-network errors propagate unchanged. The most informative error (fallback's, when both fail) is surfaced.testConnection(server, signal)returns the newConnectionTestResultshape (extends the old{ success, error }) with optionalprimary/fallbackkeys when fallback is enabled. A new internaltestEndpointruns the per-endpoint check and translates auth/network errors into the consistent shape. Cancellation propagates between the two endpoint tests.EndpointTestResult,ConnectionTestResult.Context —
context/ServerContext.tsxactiveEndpoint: 'primary' | 'fallback' | null.refreshActiveEndpoint(server, connected)derives the active endpoint fromapiClient.getServer()and is called after every successful connect/reconnect/auto-connect path. Cleared on disconnect and on connection errors.Storage —
services/storage.tssaveServer()persistsuseFallback,fallbackHost(withstripProtocol),fallbackPort,fallbackUseHttps, andfallbackBasePath.getServers()strips any stray protocol onfallbackHostfor legacy safety.UI
app/server/add.tsx: new section, new state, validation in both Save and Test paths, save includes fallback fields, per-endpoint test-result toast.app/server/[id].tsx: same UI section, plus loads/round-trips all fallback fields and preservesfallbackBasePatheven though the UI does not surface it.app/(tabs)/settings.tsx: importshasFallback, consumesactiveEndpoint, shows the connected-via subtitle when applicable.i18n —
locales/{en,es,zh,fr,de,ru}/translation.json12 new keys per locale:
server.fallbackUrl,server.useFallback,server.useFallbackHint,server.fallbackUseHttpsserver.endpointPrimary,server.endpointFallbackserver.testEndpointOk,server.testEndpointFailserver.connectedViaPrimary,server.connectedViaFallbackplaceholders.fallbackHosterrors.fillFallbackHostBackward compatibility
useFallbackreads as undefined →hasFallback()returns false → all flows behave exactly like before.theme/ other preferences are unaffected (this PR only touches server-related types and code).Tested
npx tsc --noEmitpasses clean.Out of scope (intentionally deferred)
fallbackBasePath(field exists for data-model parity).