feat(realtime): long polling for app-wide events behind proxies
When a proxy lets neither WebSocket nor SSE through, the app opens a poll connection: the server buffers its events (an SSEClient without a stream), each GET waits up to 25 s, and room joins work like for SSE. Tasks and lists now update live there too, and note sync takes its notifications from it instead of a second long poll. Idle connections close after two minutes. The profile shows such a connection as limited. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
c19d8fd03e
commit
2b7356d043
16 files changed
+369
-20
No files matched your search
@@ -6,9 +6,9 @@ export const SERVER_OFFLINE_GRACE_MS = 4000;
|
||||
// How often the server is asked while the realtime connection is missing
|
||||
export const SERVER_PROBE_INTERVAL_MS = 15000;
|
||||
|
||||
// online: realtime connection (WebSocket/SSE) is up; limited: the server answers plain requests, but no
|
||||
// realtime connection gets through (e.g. a proxy that buffers event streams; notes fall back to long
|
||||
// polling); offline: no server at all
|
||||
// online: realtime connection (WebSocket/SSE) is up; limited: changes only come by long polling (a proxy
|
||||
// that buffers event streams), or not live at all while the server still answers plain requests;
|
||||
// offline: no server at all
|
||||
export type ConnectionState = 'online' | 'limited' | 'offline';
|
||||
|
||||
async function serverReachable(): Promise<boolean> {
|
||||
@@ -29,6 +29,7 @@ export function useConnectionState(): ConnectionState {
|
||||
|
||||
useEffect(() => {
|
||||
let connected = false;
|
||||
let viaPoll = false;
|
||||
let disposed = false;
|
||||
let timer: number | undefined;
|
||||
const stopProbing = () => {
|
||||
@@ -45,7 +46,7 @@ export function useConnectionState(): ConnectionState {
|
||||
const update = () => {
|
||||
if (connected) {
|
||||
stopProbing();
|
||||
setState('online');
|
||||
setState(viaPoll ? 'limited' : 'online');
|
||||
} else if (navigator.onLine === false) {
|
||||
stopProbing();
|
||||
setState('offline');
|
||||
@@ -53,8 +54,9 @@ export function useConnectionState(): ConnectionState {
|
||||
timer = window.setTimeout(probe, SERVER_OFFLINE_GRACE_MS);
|
||||
}
|
||||
};
|
||||
const unsubscribe = onRealtimeStatus((isConnected) => {
|
||||
const unsubscribe = onRealtimeStatus((isConnected, transport) => {
|
||||
connected = isConnected;
|
||||
viaPoll = transport === 'poll';
|
||||
update();
|
||||
});
|
||||
window.addEventListener('online', update);
|
||||
|
||||
Reference in new issue
Block a user