diff options
| author | Adam Soltys <[email protected]> | 2026-03-07 10:39:57 -0800 |
|---|---|---|
| committer | Adam Soltys <[email protected]> | 2026-03-07 10:39:57 -0800 |
| commit | 63249aed9dd62e59aa302ddcf7c3a419effc43b3 (patch) | |
| tree | 48e89bcc0c58a92753a75d5d8d9e9dea4291dc87 /src/routes | |
| parent | ad0b4009b2b2ae9173fffb41f0cfa7b35edcb303 (diff) | |
| download | coinos-ui-63249aed9dd62e59aa302ddcf7c3a419effc43b3.tar.gz coinos-ui-63249aed9dd62e59aa302ddcf7c3a419effc43b3.zip | |
improve message delivery with websocket reconnect and push data transport
- Enable auto-reconnect on relay connections so dropped WebSockets recover
- Connect relays in parallel with 5s timeout for faster startup
- Add visibility change handler to catch up missed messages on tab return
- Forward kind 445 events via push notifications as a data channel
- Show "reconnecting..." status in chat UI when connections are down
Co-Authored-By: Claude Opus 4.6 <[email protected]>
Diffstat (limited to 'src/routes')
| -rw-r--r-- | src/routes/(app)/messages/+page.svelte | 28 | ||||
| -rw-r--r-- | src/routes/(app)/messages/[id]/+page.svelte | 23 |
2 files changed, 49 insertions, 2 deletions
diff --git a/src/routes/(app)/messages/+page.svelte b/src/routes/(app)/messages/+page.svelte index 1981b5f1..215f07b0 100644 --- a/src/routes/(app)/messages/+page.svelte +++ b/src/routes/(app)/messages/+page.svelte @@ -4,6 +4,7 @@ import { getGroups, subscribeToMessages, fetchGroupHistory, searchMlsUsers, preloadMlsUsers, resolveUser, displayName, + isConnected, onConnectionChange, } from "$lib/messaging"; import type { GroupInfo } from "$lib/messaging"; import { t } from "$lib/translations"; @@ -22,6 +23,7 @@ let groups: GroupInfo[] = $state([]); let loaded = $state(false); + let connected = $state(isConnected()); let memberInfos = $state(new Map<string, any>()); // Search state @@ -68,8 +70,10 @@ }; let closeSub: (() => void) | undefined; + let closeConnectionListener: (() => void) | undefined; onMount(() => { + closeConnectionListener = onConnectionChange((c) => (connected = c)); // Show cached groups immediately, then fetch history in background refreshGroups().then(() => { loaded = true; }); fetchGroupHistory(user).then(refreshGroups); @@ -77,9 +81,16 @@ subscribeToMessages(user, refreshGroups).then((close) => (closeSub = close)); }); - onDestroy(() => closeSub?.()); + onDestroy(() => { + closeSub?.(); + closeConnectionListener?.(); + }); </script> +{#if !connected} + <div class="reconnecting-banner">Reconnecting...</div> +{/if} + <div class="container mx-auto max-w-xl px-4 space-y-1"> <input use:focus @@ -134,3 +145,18 @@ {/each} {/if} </div> + +<style> + .reconnecting-banner { + text-align: center; + font-size: 0.75rem; + color: #f59e0b; + padding: 0.25rem; + animation: pulse-text 1.5s ease-in-out infinite; + } + + @keyframes pulse-text { + 0%, 100% { opacity: 0.6; } + 50% { opacity: 1; } + } +</style> diff --git a/src/routes/(app)/messages/[id]/+page.svelte b/src/routes/(app)/messages/[id]/+page.svelte index a5768df7..4af0def5 100644 --- a/src/routes/(app)/messages/[id]/+page.svelte +++ b/src/routes/(app)/messages/[id]/+page.svelte @@ -12,6 +12,7 @@ findOrCreateDmGroup, resolveUser, displayName, decryptMediaUrl, + isConnected, onConnectionChange, } from "$lib/messaging"; import type { GroupInfo } from "$lib/messaging"; import { t } from "$lib/translations"; @@ -48,6 +49,7 @@ let dates: number[] = $state([]); let sendError = $state(""); let uploading = $state(false); + let connected = $state(isConnected()); let senderInfos = $state(new Map<string, any>()); const groupDisplayName = (g: GroupInfo | undefined): string => { @@ -243,8 +245,10 @@ }; let closeSub: (() => void) | undefined; + let closeConnectionListener: (() => void) | undefined; onMount(() => { + closeConnectionListener = onConnectionChange((c) => (connected = c)); loadGroup(); const vv = window.visualViewport; @@ -272,7 +276,10 @@ }).then((close) => (closeSub = close)); }); - onDestroy(() => closeSub?.()); + onDestroy(() => { + closeSub?.(); + closeConnectionListener?.(); + }); </script> <div class="chat-container"> @@ -281,6 +288,9 @@ {#if groupInfo && groupInfo.members.length > 2} <span class="text-secondary text-sm">{groupInfo.members.length} members</span> {/if} + {#if !connected} + <span class="connection-status">reconnecting...</span> + {/if} </div> <div id="messages"> @@ -394,6 +404,17 @@ flex-shrink: 0; } + .connection-status { + font-size: 0.75rem; + color: #f59e0b; + animation: pulse-text 1.5s ease-in-out infinite; + } + + @keyframes pulse-text { + 0%, 100% { opacity: 0.6; } + 50% { opacity: 1; } + } + .warning { color: #ff7f00; } |
