photo_server_json_con_aves22/README_WS.md
2026-04-18 20:14:42 +02:00

11 KiB
Raw Permalink Blame History

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:

  1. Connessione iniziale
  2. Autenticazione + session_id
  3. Invio evento dal server
  4. Ricezione evento dal client
  5. Retry + Timeout + needfullsync
  6. 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 dellutente: - 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”

✔ Multidispositivo perfetto

✔ Queue pulita dopo 2 minuti

✔ Sync completo automatico quando serve

✔ WS leggero (ping solo ondemand)

✔ 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