JavaScript में ऑफ़लाइन क्षमताएं चालू करना

अगर आपके ऐप्लिकेशन का नेटवर्क कनेक्शन कुछ समय के लिए बंद हो जाता है, तब भी Firebase ऐप्लिकेशन काम करते हैं. हम उपस्थिति को मॉनिटर करने और स्थानीय स्थिति को सर्वर की स्थिति के साथ सिंक करने के लिए कई टूल उपलब्ध कराते हैं. इनके बारे में इस दस्तावेज़ में बताया गया है.

मौजूदगी मैनेज करना

रीयलटाइम ऐप्लिकेशन में, यह पता लगाना अक्सर काम का होता है कि क्लाइंट कब कनेक्ट और डिसकनेक्ट होते हैं. उदाहरण के लिए, जब किसी उपयोगकर्ता का क्लाइंट डिसकनेक्ट हो जाता है, तब हो सकता है कि आपको उसे 'ऑफ़लाइन' के तौर पर मार्क करना हो.

Firebase Database क्लाइंट, आसान प्रिमिटिव उपलब्ध कराते हैं. इनका इस्तेमाल, क्लाइंट के Firebase Database सर्वर से डिसकनेक्ट होने पर डेटाबेस में लिखने के लिए किया जा सकता है. ये अपडेट तब भी होते हैं, जब क्लाइंट ठीक से डिसकनेक्ट नहीं होता है. इसलिए, डेटा को साफ़ करने के लिए इन पर भरोसा किया जा सकता है. भले ही, कनेक्शन बंद हो गया हो या क्लाइंट क्रैश हो गया हो. कनेक्शन बंद होने पर, लिखने से जुड़ी सभी कार्रवाइयां की जा सकती हैं. जैसे, सेटिंग करना, अपडेट करना, और हटाना.

यहां onDisconnect प्रिमिटिव का इस्तेमाल करके, कनेक्शन बंद होने पर डेटा लिखने का एक सामान्य उदाहरण दिया गया है:

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!");

onDisconnect कैसे काम करता है

onDisconnect() ऑपरेशन सेट अप करने पर, यह Firebase Realtime Database सर्वर पर सेव हो जाता है. सर्वर, सुरक्षा की जांच करता है, ताकि यह पक्का किया जा सके कि उपयोगकर्ता, अनुरोध किया गया राइट इवेंट पूरा कर सकता है. अगर यह अमान्य है, तो सर्वर आपके ऐप्लिकेशन को इसकी सूचना देता है. इसके बाद, सर्वर कनेक्शन की निगरानी करता है. अगर किसी भी समय कनेक्शन टाइम आउट हो जाता है या Realtime Database क्लाइंट उसे बंद कर देता है, तो सर्वर दूसरी बार सुरक्षा की जांच करता है. इससे यह पक्का किया जाता है कि ऑपरेशन अब भी मान्य है. इसके बाद, सर्वर इवेंट को शुरू करता है.

आपका ऐप्लिकेशन, राइट ऑपरेशन पर कॉलबैक का इस्तेमाल कर सकता है. इससे यह पक्का किया जा सकता है कि onDisconnect सही तरीके से अटैच किया गया है:

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);
  }
});

.cancel() पर कॉल करके भी onDisconnect इवेंट को रद्द किया जा सकता है:

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();

कनेक्शन का स्टेटस पता लगाया जा रहा है

उपयोगकर्ता की मौजूदगी से जुड़ी कई सुविधाओं के लिए, आपके ऐप्लिकेशन को यह पता होना चाहिए कि वह ऑनलाइन है या ऑफ़लाइन. Firebase Realtime Database, /.info/connected पर एक खास जगह उपलब्ध कराता है. यह जगह, Firebase Realtime Database क्लाइंट के कनेक्शन की स्थिति में बदलाव होने पर हर बार अपडेट होती है. यहां एक उदाहरण दिया गया है:

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 एक बूलियन वैल्यू है. इसे Realtime Database क्लाइंट के बीच सिंक्रनाइज़ नहीं किया जाता, क्योंकि वैल्यू क्लाइंट की स्थिति पर निर्भर करती है. दूसरे शब्दों में कहें, तो अगर कोई क्लाइंट /.info/connected को 'गलत' के तौर पर पढ़ता है, तो इस बात की कोई गारंटी नहीं है कि कोई दूसरा क्लाइंट भी इसे 'गलत' के तौर पर पढ़ेगा.

हैंडलिंग में लगने वाला समय

सर्वर टाइमस्टैंप

Firebase Realtime Database सर्वर, सर्वर पर जनरेट किए गए टाइमस्टैंप को डेटा के तौर पर डालने का तरीका उपलब्ध कराते हैं. इस सुविधा के साथ-साथ onDisconnect का इस्तेमाल करके, Realtime Database क्लाइंट के डिसकनेक्ट होने के समय को आसानी से नोट किया जा सकता है:

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);

क्लॉक स्क्यू

firebase.database.ServerValue.TIMESTAMP ज़्यादा सटीक है. साथ ही, पढ़ने/लिखने की ज़्यादातर कार्रवाइयों के लिए इसका इस्तेमाल करना बेहतर होता है. हालांकि, कभी-कभी Firebase Realtime Database के सर्वर के हिसाब से क्लाइंट की घड़ी के अंतर का अनुमान लगाने के लिए, इसका इस्तेमाल किया जा सकता है. आपके पास, जगह की जानकारी /.info/serverTimeOffset में कॉलबैक अटैच करने का विकल्प होता है. इससे आपको मिलीसेकंड में वह वैल्यू मिलती है जिसे Firebase Realtime Database क्लाइंट, स्थानीय समय (मिलीसेकंड में इपोक टाइम) में जोड़ते हैं, ताकि सर्वर के समय का अनुमान लगाया जा सके. ध्यान दें कि इस ऑफ़सेट की सटीक जानकारी पर नेटवर्क की वजह से होने वाली देरी का असर पड़ सकता है. इसलिए, यह मुख्य रूप से घड़ी के समय में बड़े (> 1 सेकंड) अंतर का पता लगाने के लिए उपयोगी है.

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;
});

सैंपल के तौर पर उपलब्ध Presence ऐप्लिकेशन

कनेक्शन की स्थिति की निगरानी करने और सर्वर के टाइमस्टैंप के साथ डिसकनेक्ट करने की कार्रवाइयों को मिलाकर, उपयोगकर्ता की मौजूदगी का सिस्टम बनाया जा सकता है. इस सिस्टम में, हर उपयोगकर्ता डेटा को डेटाबेस की किसी जगह पर सेव करता है. इससे यह पता चलता है कि Realtime Database क्लाइंट ऑनलाइन है या नहीं. क्लाइंट, ऑनलाइन होने पर इस जगह की जानकारी को सही के तौर पर सेट करते हैं. साथ ही, डिसकनेक्ट होने पर टाइमस्टैंप सेट करते हैं. इस टाइमस्टैंप से पता चलता है कि उपयोगकर्ता पिछली बार कब ऑनलाइन था.

ध्यान दें कि उपयोगकर्ता को ऑनलाइन के तौर पर मार्क करने से पहले, आपके ऐप्लिकेशन को डिसकनेक्ट करने की कार्रवाइयों को क्रम में लगाना चाहिए. इससे, अगर क्लाइंट का नेटवर्क कनेक्शन सर्वर को दोनों कमांड भेजने से पहले ही बंद हो जाता है, तो रेस कंडीशन से बचा जा सकता है.

उपयोगकर्ता की मौजूदगी का पता लगाने वाला एक आसान सिस्टम यहां दिया गया है:

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);
  }
});