Synchronisation des connexions clientes
Vue d'ensemble
La fonctionnalité Client Sync répond au besoin de coordination entre plusieurs connexions clientes accédant simultanément à un même projet (identifié par un projectId). Elle garantit qu'un seul client détient le contrôle d'un projet à la fois, et notifie en temps réel les autres clients de leur statut : perte du contrôle, expiration de session, reprise du contrôle, etc. Cela évite des modifications en simultané de la part de deux connexions clientes pour un même projet.
La fonctionnalité repose sur une connexion WebSocket établie entre le client et le serveur. Côté client, un hook React useClientSync permet d'être notifié en temps réel des changements de statut et d'agir en conséquence (afficher un message, proposer la reprise du contrôle, etc.). Côté serveur, une classe dédiée gère le registre des connexions actives par session et par projet.
Garanties apportées par la fonctionnalité :
- Un seul client actif (onglet de navigateur ou session) par projet à la fois.
- Transfert automatique du contrôle au client le plus récemment actif lors d'une déconnexion ou d'une expiration de session.
- Envoi d'un heartbeat toutes les 30 secondes pour détecter les connexions mortes.
- Nettoyage automatique des sessions expirées toutes les 5 minutes.
- La fonctionnalité est désactivée par défaut (opt-in) : elle doit être explicitement activée côté serveur et côté client.
Prérequis
- Un projet utilisant le framework OIP.
- Version 4.1.0 ou supérieure de la bibliothèque @fasstech/oip-starter-utils.
Implémentation
Côté serveur
L'activation de la fonctionnalité se fait via le champ session.clientSync.enabled dans la configuration passée à la fonction start() du module serveur.
Exemple du fichier server/index.mjs (activer la fonctionnalité) :
import { start as startServer } from "@fasstech/oip-starter-utils/server";
let serverConfig = {
session: {
// ...
clientSync: { enabled: true }
}
};
await startServer(serverConfig);Lorsque la fonctionnalité est activée, le serveur instancie un serveur WebSocket qui :
- maintient un registre des connexions actives par session et par projet,
- valide les sessions entrantes,
- envoie des heartbeats périodiques pour détecter les connexions mortes,
- nettoie automatiquement les sessions expirées.
Messages WebSocket
Serveur vers client :
Message | Description |
|---|---|
CONTROL_GRANTED | Le client reçoit le contrôle du projet. |
OUT_OF_SYNC | Le client perd le contrôle (une autre connexion a pris le contrôle). |
SESSION_EXPIRED | La session du client a expiré. |
Client vers serveur :
Message | Description |
|---|---|
INIT_CONNECTION | Initialisation de la connexion WebSocket. |
RECLAIM_CONTROL | Le client demande à reprendre le contrôle du projet. |
CLOSE_CONNECTION | Fermeture propre de la connexion. |
Côté client
L'activation côté client se fait via la propriété clientSyncEnabled dans la fonction startApp().
Exemple du fichier app/index.js (activer la fonctionnalité) :
import { start as startApp } from "@fasstech/oip-starter-utils/app";
import { App } from "./App";
(async () => {
startApp({
// ...
app: App,
clientSyncEnabled: true
});
})();Hook useClientSync
useClientSync est un hook React qui permet à n'importe quel composant de l'application d'accéder au statut courant du client, au message associé au dernier événement reçu, et à la fonction reclaimControl pour demander la reprise du contrôle du projet.
Le hook expose les valeurs suivantes :
Valeur | Type | Description |
|---|---|---|
instanceId | string | Identifiant unique de la connexion courante. |
status | ClientSyncStatus | Statut courant du client. |
message | string | Message associé au dernier événement reçu. |
reclaimControl | function | Fonction permettant de demander la reprise du contrôle. |
Statuts possibles (ClientSyncStatus)
Statut | Description |
|---|---|
IN_CONTROL | Le client possède le contrôle du projet. |
OUT_OF_SYNC | Le client a perdu le contrôle (une autre connexion est active). |
SESSION_EXPIRED | La session du client a expiré. |
Implémentation minimale
Exemple de l'implémentation minimale de la fonctionnalité dans le fichier app/App.jsx :
import { Router, useClientSync } from "@fasstech/oip-starter-utils/app";
import views from "./views.mjs";
export const App = () => {
const { instanceId, status, message, reclaimControl } = useClientSync();
console.log(">> instanceId", instanceId);
const onReclaimControl = () => {
reclaimControl();
};
if (status === "SESSION_EXPIRED") {
return (
<>
<div>Session Expired...</div>
</>
);
}
if (status === "OUT_OF_SYNC") {
return (
<>
<div>{message}</div>
<button onClick={onReclaimControl}>[RECLAIM CONTROL]</button>
</>
);
}
return <Router views={views} />;
};Dans cet exemple :
- Si le statut est SESSION_EXPIRED, l'application affiche un message d'expiration de session.
- Si le statut est OUT_OF_SYNC, l'application affiche le message reçu et propose à l'utilisateur de reprendre le contrôle via reclaimControl().
- Dans tous les autres cas (statut IN_CONTROL), l'application s'affiche normalement.
Résumé
- Client Sync est une fonctionnalité opt-in permettant de coordonner l'accès concurrent à un projet entre plusieurs connexions clientes.
- Elle repose sur une connexion WebSocket persistante et un système de statuts (IN_CONTROL, OUT_OF_SYNC, SESSION_EXPIRED).
- Un seul client détient le contrôle d'un projet à la fois. Le contrôle est automatiquement transféré en cas de déconnexion ou d'expiration de session.
- Côté serveur, activer session.clientSync.enabled: true dans la configuration de start().
- Côté client, passer clientSyncEnabled: true à startApp(), puis consommer le hook useClientSync pour réagir aux changements de statut.
- La bibliothèque @fasstech/oip-starter-utils en version 4.1.0 minimum est requise.