Les applications Firebase fonctionnent même si votre application perd temporairement sa connexion réseau. Nous fournissons plusieurs outils pour surveiller la présence et synchroniser l'état local avec l'état du serveur, qui sont présentés dans ce document.
Gérer la présence
Dans les applications en temps réel, il est souvent utile de détecter quand les clients se connectent et se déconnectent. Par exemple, vous pouvez vouloir marquer un utilisateur comme "hors connexion" lorsque son client se déconnecte.
Les clients de la base de données Firebase fournissent des primitives simples que vous pouvez utiliser pour écrire dans la base de données lorsqu'un client se déconnecte des serveurs de la base de données Firebase. Ces mises à jour se produisent que le client se déconnecte correctement ou non, vous pouvez donc compter sur elles pour nettoyer les données, même si une connexion est interrompue ou qu'un client plante. Toutes les opérations d'écriture, y compris la définition, la mise à jour et la suppression, peuvent être effectuées lors d'une déconnexion.
Voici un exemple simple d'écriture de données lors d'une déconnexion à l'aide de la
onDisconnect primitive :
Web
import { getDatabase, ref, onDisconnect } from "firebase/database"; const db = getDatabase(); const presenceRef = ref(db, "disconnectmessage"); // Write a string when this client loses connection onDisconnect(presenceRef).set("I disconnected!");
Web
var presenceRef = firebase.database().ref("disconnectmessage"); // Write a string when this client loses connection presenceRef.onDisconnect().set("I disconnected!");
Fonctionnement de onDisconnect
Lorsque vous établissez une opération onDisconnect(), celle-ci
réside sur le serveur Firebase Realtime Database. Le serveur vérifie la sécurité pour
s'assurer que l'utilisateur peut effectuer l'événement d'écriture demandé et informe
votre application si elle n'est pas valide. Le serveur surveille ensuite la connexion. Si, à un moment donné, la connexion expire ou est
fermée activement par le Realtime Database client, le serveur vérifie la sécurité une
deuxième fois (pour s'assurer que l'opération est toujours valide), puis appelle
l'événement.
Votre application peut utiliser le rappel sur l'opération d'écriture
pour s'assurer que le onDisconnect a été correctement associé :
Web
onDisconnect(presenceRef).remove().catch((err) => { if (err) { console.error("could not establish onDisconnect event", err); } });
Web
presenceRef.onDisconnect().remove((err) => { if (err) { console.error("could not establish onDisconnect event", err); } });
Un événement onDisconnect peut également être annulé en appelant .cancel() :
Web
const onDisconnectRef = onDisconnect(presenceRef); onDisconnectRef.set("I disconnected"); // some time later when we change our minds onDisconnectRef.cancel();
Web
var onDisconnectRef = presenceRef.onDisconnect(); onDisconnectRef.set("I disconnected"); // some time later when we change our minds onDisconnectRef.cancel();
Détecter l'état de la connexion
Pour de nombreuses fonctionnalités liées à la présence, il est utile que votre application
sache quand elle est en ligne ou hors connexion. Firebase Realtime Database
fournit un emplacement spécial à l'adresse /.info/connected qui
est mis à jour chaque fois que l'état de la connexion du client Firebase Realtime Database change. Voici un exemple :
Web
import { getDatabase, ref, onValue } from "firebase/database"; const db = getDatabase(); const connectedRef = ref(db, ".info/connected"); onValue(connectedRef, (snap) => { if (snap.val() === true) { console.log("connected"); } else { console.log("not connected"); } });
Web
var connectedRef = firebase.database().ref(".info/connected"); connectedRef.on("value", (snap) => { if (snap.val() === true) { console.log("connected"); } else { console.log("not connected"); } });
/.info/connected est une valeur booléenne qui n'est pas
synchronisée entre les clients Realtime Database car la valeur dépend de l'état du client. En d'autres termes, si un client
lit /.info/connected comme "false", cela ne
garantit pas qu'un autre client lira également "false".
Gérer la latence
Horodatages du serveur
Les serveurs Firebase Realtime Database fournissent un mécanisme permettant d'insérer
des horodatages générés sur le serveur en tant que données. Combinée à
onDisconnect, cette fonctionnalité permet de noter facilement et de manière fiable
l'heure à laquelle un Realtime Database client s'est déconnecté :
Web
import { getDatabase, ref, onDisconnect, serverTimestamp } from "firebase/database"; const db = getDatabase(); const userLastOnlineRef = ref(db, "users/joe/lastOnline"); onDisconnect(userLastOnlineRef).set(serverTimestamp());
Web
var userLastOnlineRef = firebase.database().ref("users/joe/lastOnline"); userLastOnlineRef.onDisconnect().set(firebase.database.ServerValue.TIMESTAMP);
Décalage de l'horloge
Bien que firebase.database.ServerValue.TIMESTAMP soit beaucoup plus précis et préférable pour la plupart des opérations de lecture/écriture, il peut parfois être utile d'estimer le décalage de l'horloge du client par rapport aux serveurs de Firebase Realtime Database. Vous
pouvez associer un rappel à l'emplacement /.info/serverTimeOffset
pour obtenir la valeur, en millisecondes, que les clients Firebase Realtime Database
ajoutent à l'heure locale signalée (heure de l'époque en millisecondes) afin d'estimer
l'heure du serveur. Notez que la précision de ce décalage peut être affectée par
la latence du réseau. Il est donc principalement utile pour détecter
les écarts importants (> 1 seconde) dans l'heure de l'horloge.
Web
import { getDatabase, ref, onValue } from "firebase/database"; const db = getDatabase(); const offsetRef = ref(db, ".info/serverTimeOffset"); onValue(offsetRef, (snap) => { const offset = snap.val(); const estimatedServerTimeMs = new Date().getTime() + offset; });
Web
var offsetRef = firebase.database().ref(".info/serverTimeOffset"); offsetRef.on("value", (snap) => { var offset = snap.val(); var estimatedServerTimeMs = new Date().getTime() + offset; });
Exemple d'application de présence
En combinant les opérations de déconnexion avec la surveillance de l'état de la connexion et les horodatages du serveur, vous pouvez créer un système de présence des utilisateurs. Dans ce système, chaque utilisateur stocke des données à un emplacement de base de données pour indiquer si un Realtime Database client est en ligne ou non. Les clients définissent cet emplacement sur "true" lorsqu' ils se connectent et sur un horodatage lorsqu'ils se déconnectent. Cet horodatage indique la dernière fois que l'utilisateur donné était en ligne.
Notez que votre application doit mettre en file d'attente les opérations de déconnexion avant qu'un utilisateur ne soit marqué comme étant en ligne, afin d'éviter toute condition de concurrence si la connexion réseau du client est perdue avant que les deux commandes puissent être envoyées au serveur.
Voici un système de présence des utilisateurs simple :
Web
import { getDatabase, ref, onValue, push, onDisconnect, set, serverTimestamp } from "firebase/database"; // Since I can connect from multiple devices or browser tabs, we store each connection instance separately // any time that connectionsRef's value is null (i.e. has no children) I am offline const db = getDatabase(); const myConnectionsRef = ref(db, 'users/joe/connections'); // stores the timestamp of my last disconnect (the last time I was seen online) const lastOnlineRef = ref(db, 'users/joe/lastOnline'); const connectedRef = ref(db, '.info/connected'); onValue(connectedRef, (snap) => { if (snap.val() === true) { // We're connected (or reconnected)! Do anything here that should happen only if online (or on reconnect) const con = push(myConnectionsRef); // When I disconnect, remove this device onDisconnect(con).remove(); // Add this device to my connections list // this value could contain info about the device or a timestamp too set(con, true); // When I disconnect, update the last time I was seen online onDisconnect(lastOnlineRef).set(serverTimestamp()); } });
Web
// Since I can connect from multiple devices or browser tabs, we store each connection instance separately // any time that connectionsRef's value is null (i.e. has no children) I am offline var myConnectionsRef = firebase.database().ref('users/joe/connections'); // stores the timestamp of my last disconnect (the last time I was seen online) var lastOnlineRef = firebase.database().ref('users/joe/lastOnline'); var connectedRef = firebase.database().ref('.info/connected'); connectedRef.on('value', (snap) => { if (snap.val() === true) { // We're connected (or reconnected)! Do anything here that should happen only if online (or on reconnect) var con = myConnectionsRef.push(); // When I disconnect, remove this device con.onDisconnect().remove(); // Add this device to my connections list // this value could contain info about the device or a timestamp too con.set(true); // When I disconnect, update the last time I was seen online lastOnlineRef.onDisconnect().set(firebase.database.ServerValue.TIMESTAMP); } });