आपके ऐप्लिकेशन के टाइप के आधार पर, आपको यह पता लगाना मददगार लग सकता है कि आपके कौनसे उपयोगकर्ता या डिवाइस ऑनलाइन हैं. इसे "उपस्थिति" का पता लगाना भी कहा जाता है.
उदाहरण के लिए, अगर आपको सोशल नेटवर्क जैसा कोई ऐप्लिकेशन बनाना है या IoT डिवाइसों का कोई फ़्लीट डिप्लॉय करना है, तो इस जानकारी का इस्तेमाल करके, ऑनलाइन और चैट के लिए उपलब्ध दोस्तों की सूची दिखाई जा सकती है. इसके अलावा, अपने IoT डिवाइसों को "पिछली बार देखा गया" के हिसाब से क्रम में लगाया जा सकता है.
Cloud Firestore में, प्रज़ेंस की सुविधा नेटिव तौर पर काम नहीं करती. हालांकि, प्रज़ेंस सिस्टम बनाने के लिए, Firebase के अन्य प्रॉडक्ट का इस्तेमाल किया जा सकता है.
समाधान: रीयलटाइम डेटाबेस के साथ Cloud Functions
Cloud Firestore को Firebase रीयलटाइम डेटाबेस के नेटिव प्रेज़ेंस फ़ीचर से कनेक्ट करने के लिए, Cloud Functions का इस्तेमाल करें.
कनेक्शन की स्थिति की जानकारी देने के लिए, रीयलटाइम डेटाबेस का इस्तेमाल करें. इसके बाद, Cloud Functions का इस्तेमाल करके, उस डेटा को Cloud Firestore में मिरर करें.
रीयलटाइम डेटाबेस में मौजूदगी की सुविधा का इस्तेमाल करना
सबसे पहले, यह समझें कि रीयलटाइम डेटाबेस में, मौजूदगी की जानकारी देने वाला पारंपरिक सिस्टम कैसे काम करता है.
वेब
// Fetch the current user's ID from Firebase Authentication. var uid = firebase.auth().currentUser.uid; // Create a reference to this user's specific status node. // This is where we will store data about being online/offline. var userStatusDatabaseRef = firebase.database().ref('/status/' + uid); // We'll create two constants which we will write to // the Realtime database when this device is offline // or online. var isOfflineForDatabase = { state: 'offline', last_changed: firebase.database.ServerValue.TIMESTAMP, }; var isOnlineForDatabase = { state: 'online', last_changed: firebase.database.ServerValue.TIMESTAMP, }; // Create a reference to the special '.info/connected' path in // Realtime Database. This path returns `true` when connected // and `false` when disconnected. firebase.database().ref('.info/connected').on('value', function(snapshot) { // If we're not currently connected, don't do anything. if (snapshot.val() == false) { return; }; // If we are currently connected, then use the 'onDisconnect()' // method to add a set which will only trigger once this // client has disconnected by closing the app, // losing internet, or any other means. userStatusDatabaseRef.onDisconnect().set(isOfflineForDatabase).then(function() { // The promise returned from .onDisconnect().set() will // resolve as soon as the server acknowledges the onDisconnect() // request, NOT once we've actually disconnected: // https://firebase.google.com/docs/reference/js/firebase.database.OnDisconnect // We can now safely set ourselves as 'online' knowing that the // server will mark us as offline once we lose connection. userStatusDatabaseRef.set(isOnlineForDatabase); }); });
यह उदाहरण, रीयलटाइम डेटाबेस में मौजूदगी की जानकारी देने वाले सिस्टम का है. यह कई बार डिसकनेक्ट होने, क्रैश होने वगैरह को मैनेज करता है.
Cloud Firestore से कनेक्ट किया जा रहा है
Cloud Firestore में ऐसा ही समाधान लागू करने के लिए, रीयलटाइम डेटाबेस के कोड का इस्तेमाल करें. इसके बाद, रीयलटाइम डेटाबेस और Cloud Firestore को सिंक में रखने के लिए, Cloud Functions का इस्तेमाल करें.
अगर आपने पहले से ही ऐसा नहीं किया है, तो अपने प्रोजेक्ट में रीयलटाइम डेटाबेस जोड़ें और ऊपर दिए गए प्रज़ेंस सलूशन को शामिल करें.
इसके बाद, आपको इनमें से किसी तरीके का इस्तेमाल करके, मौजूदगी की स्थिति को Cloud Firestore के साथ सिंक करना होगा:
- ऑफ़लाइन डिवाइस के Cloud Firestore कैश मेमोरी में, ताकि ऐप्लिकेशन को पता चल सके कि वह ऑफ़लाइन है.
- ग्लोबल लेवल पर, Cloud फ़ंक्शन का इस्तेमाल करके, Cloud Firestore को ऐक्सेस करने वाले अन्य सभी डिवाइसों को यह जानकारी दी जाती है कि यह डिवाइस ऑफ़लाइन है.
इस ट्यूटोरियल में सुझाए गए फ़ंक्शन, किसी क्लाइंट ऐप्लिकेशन में नहीं चलाए जा सकते. इन्हें Cloud Functions for Firebase पर डिप्लॉय किया जाना चाहिए. साथ ही, इन्हें Firebase Admin SDK से सर्वर-साइड लॉजिक की ज़रूरत होती है. ज़्यादा जानकारी के लिए, Cloud Functions का दस्तावेज़ देखें.
Cloud Firestore की लोकल कैश मेमोरी अपडेट की जा रही है
आइए, पहली समस्या को हल करने के लिए ज़रूरी बदलावों पर नज़र डालते हैं. इसके लिए, Cloud Firestore के लोकल कैश को अपडेट करना होगा.
वेब
// ... var userStatusFirestoreRef = firebase.firestore().doc('/status/' + uid); // Firestore uses a different server timestamp value, so we'll // create two more constants for Firestore state. var isOfflineForFirestore = { state: 'offline', last_changed: firebase.firestore.FieldValue.serverTimestamp(), }; var isOnlineForFirestore = { state: 'online', last_changed: firebase.firestore.FieldValue.serverTimestamp(), }; firebase.database().ref('.info/connected').on('value', function(snapshot) { if (snapshot.val() == false) { // Instead of simply returning, we'll also set Firestore's state // to 'offline'. This ensures that our Firestore cache is aware // of the switch to 'offline.' userStatusFirestoreRef.set(isOfflineForFirestore); return; }; userStatusDatabaseRef.onDisconnect().set(isOfflineForDatabase).then(function() { userStatusDatabaseRef.set(isOnlineForDatabase); // We'll also add Firestore set here for when we come online. userStatusFirestoreRef.set(isOnlineForFirestore); }); });
इन बदलावों के बाद, अब हम यह पक्का कर पाए हैं कि लोकल Cloud Firestore स्टेट में हमेशा डिवाइस का ऑनलाइन/ऑफ़लाइन स्टेटस दिखेगा. इसका मतलब है कि /status/{uid} दस्तावेज़ को सुना जा सकता है. साथ ही, डेटा का इस्तेमाल करके यूज़र इंटरफ़ेस (यूआई) में बदलाव किया जा सकता है, ताकि कनेक्शन की स्थिति दिख सके.
वेब
userStatusFirestoreRef.onSnapshot(function(doc) { var isOnline = doc.data().state == 'online'; // ... use isOnline });
दुनिया भर में Cloud Firestore को अपडेट किया जा रहा है
हालांकि, हमारा ऐप्लिकेशन खुद को ऑनलाइन मौजूदगी की सही जानकारी देता है, लेकिन यह स्टेटस अन्य Cloud Firestore ऐप्लिकेशन में अब भी सटीक नहीं होगा. इसकी वजह यह है कि हमारा "ऑफ़लाइन" स्टेटस सिर्फ़ स्थानीय तौर पर लिखा जाता है. साथ ही, कनेक्शन वापस आने पर सिंक नहीं किया जाएगा. इस समस्या को हल करने के लिए, हम एक Cloud फ़ंक्शन का इस्तेमाल करेंगे. यह फ़ंक्शन, रीयलटाइम डेटाबेस में status/{uid} पाथ पर नज़र रखता है. रीयलटाइम डेटाबेस की वैल्यू बदलने पर, वह वैल्यू Cloud Firestore के साथ सिंक हो जाएगी, ताकि सभी उपयोगकर्ताओं के स्टेटस सही हों.
Node.js
const functions = require('firebase-functions/v1'); const { initializeApp } = require('firebase-admin/app'); const { getFirestore } = require('firebase-admin/firestore'); initializeApp(); // Since this code will be running in the Cloud Functions environment // we call initialize Firestore without any arguments because it // detects authentication from the environment. const firestore = getFirestore(); // Create a new function which is triggered on changes to /status/{uid} // Note: This is a Realtime Database trigger, *not* Firestore. exports.onUserStatusChanged = functions.database.ref('/status/{uid}').onUpdate( async (change, context) => { // Get the data written to Realtime Database const eventStatus = change.after.val(); // Then use other event data to create a reference to the // corresponding Firestore document. const userStatusFirestoreRef = firestore.doc(`status/${context.params.uid}`); // It is likely that the Realtime Database change that triggered // this event has already been overwritten by a fast change in // online / offline status, so we'll re-read the current data // and compare the timestamps. const statusSnapshot = await change.after.ref.once('value'); const status = statusSnapshot.val(); functions.logger.log(status, eventStatus); // If the current timestamp for this data is newer than // the data that triggered this event, we exit this function. if (status.last_changed > eventStatus.last_changed) { return null; } // Otherwise, we convert the last_changed field to a Date eventStatus.last_changed = new Date(eventStatus.last_changed); // ... and write it to Firestore. return userStatusFirestoreRef.set(eventStatus); });
इस फ़ंक्शन को डिप्लॉय करने के बाद, आपके पास Cloud Firestore के साथ काम करने वाला, मौजूदगी का पूरा सिस्टम होगा. यहां where() क्वेरी का इस्तेमाल करके, ऑनलाइन या ऑफ़लाइन होने वाले उपयोगकर्ताओं को मॉनिटर करने का उदाहरण दिया गया है.
वेब
firebase.firestore().collection('status') .where('state', '==', 'online') .onSnapshot(function(snapshot) { snapshot.docChanges().forEach(function(change) { if (change.type === 'added') { var msg = 'User ' + change.doc.id + ' is online.'; console.log(msg); // ... } if (change.type === 'removed') { var msg = 'User ' + change.doc.id + ' is offline.'; console.log(msg); // ... } }); });
सीमाएं
अपने Cloud Firestore ऐप्लिकेशन में मौजूदगी की जानकारी जोड़ने के लिए, रीयलटाइम डेटाबेस का इस्तेमाल करना, स्केलेबल और असरदार होता है. हालांकि, इसकी कुछ सीमाएं हैं:
- डीबाउंसिंग - Cloud Firestore में रीयल-टाइम में होने वाले बदलावों को सुनते समय, इस समाधान से कई बदलाव ट्रिगर हो सकते हैं. अगर इन बदलावों की वजह से आपकी ज़रूरत से ज़्यादा इवेंट ट्रिगर होते हैं, तो Cloud Firestore इवेंट को मैन्युअल तरीके से डिबाउंस करें.
- कनेक्टिविटी - यह मेट्रिक, रीयलटाइम डेटाबेस से कनेक्टिविटी को मेज़र करती है, न कि Cloud Firestore से. अगर हर डेटाबेस के लिए कनेक्शन की स्थिति एक जैसी नहीं है, तो हो सकता है कि यह समाधान, मौजूदगी की गलत स्थिति की जानकारी दे.
- Android - Android पर, 60 सेकंड तक कोई गतिविधि न होने पर, रीयलटाइम डेटाबेस बैकएंड से डिसकनेक्ट हो जाता है. इनऐक्टिविटी का मतलब है कि कोई लिसनर खुला नहीं है या कोई कार्रवाई बाकी नहीं है. कनेक्शन को चालू रखने के लिए, हमारा सुझाव है कि आप
.info/connectedके अलावा किसी पाथ में वैल्यू इवेंट लिसनर जोड़ें. उदाहरण के लिए, हर सेशन की शुरुआत मेंFirebaseDatabase.getInstance().getReference((new Date()).toString()).keepSynced()किया जा सकता है. ज़्यादा जानकारी के लिए, कनेक्शन की स्थिति का पता लगाना लेख पढ़ें.