11 KiB
Perfetto Fabio — ora ti preparo il diagramma del flusso completo, chiaro, leggibile e fedele al comportamento reale del tuo sistema.
È un diagramma architetturale, non un semplice schema: mostra tutto il ciclo di vita di una sessione WebSocket affidabile, con SQLite, retry, timeout, needfullsync e sync del client.
🟦 DIAGRAMMA DEL FLUSSO COMPLETO — WebSocket Affidabile + Sync
Lo divido in 6 sezioni:
- Connessione iniziale
- Autenticazione + session_id
- Invio evento dal server
- Ricezione evento dal client
- Retry + Timeout + needfullsync
- Riconnessione del client
🟩 1) CONNESSIONE INIZIALE
` CLIENT (browser) SERVER (ws-server.js) ──────────────────────────────────────────────────────────────────────
startWebSocket() ↓ Apre WebSocket ------------------------→ ws.on("connection") crea ws object ws.authenticated = false `
🟩 2) AUTENTICAZIONE + SESSION_ID
` CLIENT SERVER ──────────────────────────────────────────────────────────────────────
Invia: { type: "auth", token: JWT, session_id: } ↓ ws.on("message") verifica JWT cerca sessione in SQLite se non esiste → createSession() aggiorna last_ack salva wsBySession[session_id] = ws
Riceve: { type: "auth_ok", user: "...", session_id: "...", needfullsync: true/false } ↓ Se needfullsync = true → incrementalSync() `
🟩 3) INVIO EVENTO DAL SERVER (broadcast affidabile)
` SERVER ──────────────────────────────────────────────────────────────────────
broadcastToUserReliable(user, payload) ↓ Genera event_id (UUID) ↓ Per ogni sessione dell’utente: - Se ws attivo: ws.send(payload + event_id) addPendingEvent(eventid, sessionid) - Se ws NON attivo: setSessionNeedFullSync(session_id, true) `
🟩 4) RICEZIONE EVENTO DAL CLIENT
` CLIENT ──────────────────────────────────────────────────────────────────────
Riceve evento: { type: "added" | "removed" | ..., id: "...", event_id: "..." }
↓
Se event_id già in processedEvents: - invia solo ACK - ignora evento - FINE
Se nuovo: - applica evento (add/remove foto) - aggiorna UI - aggiunge event_id a processedEvents - invia ACK: { type: "ack", event_id } `
🟩 5) RETRY + TIMEOUT + NEEDFULLSYNC
` SERVER (ogni 3 secondi) ──────────────────────────────────────────────────────────────────────
Legge da SQLite tutti gli eventi pendenti con sent_at < now - 3000 ms
Per ogni evento:
Se retries < 40 (2 minuti):
- se ws attivo:
ws.send(payload)
updatePendingEventRetry()
- se ws NON attivo:
setSessionNeedFullSync(session_id, true)
deletePendingEvent(event_id)
Se retries >= 40:
- ws.terminate()
- wsBySession.delete(session_id)
- deleteSession(session_id) ← cancella queue
- (sessione verrà ricreata al prossimo auth)
`
🟩 6) RICONNESSIONE DEL CLIENT
` CLIENT riapre la tab / si risveglia ──────────────────────────────────────────────────────────────────────
startWebSocket() ↓ Invia auth con lo stesso session_id ↓ SERVER: - trova sessione in SQLite? NO → la ricrea con needfullsync = true SÌ → legge needfullsync
- invia authok con needfull_sync
CLIENT: Se needfullsync = true: incrementalSync() Altrimenti: continua con WS realtime `
🟦 RISULTATO DEL FLUSSO
✔ Nessun evento perso
✔ Nessun evento duplicato
✔ Chrome Android non può più “morire in silenzio”
✔ Multi‑dispositivo perfetto
✔ Queue pulita dopo 2 minuti
✔ Sync completo automatico quando serve
✔ WS leggero (ping solo on‑demand)
✔ Stato persistente in SQLite
┌──────────────────────────┐ ┌──────────────────────────┐ │ CLIENT │ │ SERVER │ └─────────────┬────────────┘ └─────────────┬────────────┘ │ │ │ 1) Connessione WS │ ├──────────────────────────────────────→│ │ │ │ 2) AUTH + session_id │ │ {type:auth, token, session_id} │ ├──────────────────────────────────────→│ │ │ │ │ verifica JWT │ │ cerca sessione in DB │ │ crea/aggiorna sessione │ │ │ 3) AUTH_OK │ │ ←──────────────────────────────────────┤ │ {need_full_sync:true/false} │ │ │ │ se need_full_sync → incrementalSync() │ │ │ ──────────────┼────────────────────────────────────────┼────────────── │ │ │ 4) Ricezione evento WS │ │ {type:added/removed, event_id} │ │ ←──────────────────────────────────────┤ │ │ │ se event_id già visto → ACK │ │ se nuovo → applica evento │ │ │ │ ACK │ ├──────────────────────────────────────→│ │ │ ──────────────┼────────────────────────────────────────┼────────────── │ │ │ │ 5) Retry loop (ogni 3s) │ │ cerca eventi pendenti │ │ │ │ se retries < 40: │ │ reinvia evento │ │ │ │ se retries >= 40: │ │ ws.terminate() │ │ deleteSession() │ │ (queue eliminata) │ │ ──────────────┼────────────────────────────────────────┼────────────── │ │ │ 6) Riconnessione client │ ├──────────────────────────────────────→│ │ {auth, token, session_id} │ │ │ │ │ server vede sessione mancante │ │ → need_full_sync = true │ │ │ AUTH_OK │ │ ←──────────────────────────────────────┤ │ {need_full_sync:true} │ │ │ │ incrementalSync() │ │ │ ──────────────┴────────────────────────────────────────┴──────────────
CLIENT → WS CONNECT CLIENT → AUTH(token, session_id) SERVER → AUTH_OK(need_full_sync)
EVENTO: SERVER → EVENT(event_id) CLIENT: se nuovo → applica + ACK se già visto → solo ACK
RETRY LOOP: se retries < 40 → reinvia se retries >= 40 → chiudi WS + cancella sessione
RICONNESSIONE: CLIENT → AUTH(session_id) SERVER → AUTH_OK(need_full_sync=true) CLIENT → incrementalSync()
AUTH → EVENTI → ACK → (retry finché vivo) se client sparisce → timeout → cancella sessione se torna → need_full_sync → incrementalSync