בהתאם לסוג האפליקציה שאתם מפתחים, יכול להיות שיהיה לכם שימושי לזהות אילו מהמשתמשים או המכשירים שלכם נמצאים אונליין באופן פעיל – או במילים אחרות, לזהות 'נוכחות'.
לדוגמה, אם אתם מפתחים אפליקציה כמו רשת חברתית או פורסים צי של מכשירי IoT, אתם יכולים להשתמש במידע הזה כדי להציג רשימה של חברים שמחוברים לאינטרנט וזמינים לצ'אט, או למיין את מכשירי ה-IoT לפי 'הפעילות האחרונה'.
Cloud Firestore לא תומך בנוכחות באופן מובנה, אבל אפשר להשתמש במוצרי Firebase אחרים כדי לבנות מערכת נוכחות.
פתרון: Cloud Functions עם Realtime Database
כדי לקשר את Cloud Firestore לתכונת הנוכחות המובנית של Firebase Realtime Database, צריך להשתמש ב-Cloud Functions.
משתמשים ב-Realtime Database כדי לדווח על סטטוס החיבור, ואז משתמשים ב-Cloud Functions כדי לשכפל את הנתונים האלה ל-Cloud Firestore.
שימוש בנוכחות ב-Realtime Database
קודם כל, כדאי להבין איך מערכת נוכחות מסורתית פועלת ב-Realtime Database.
אינטרנט
// 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); }); });
הדוגמה הזו היא מערכת נוכחות מלאה של Realtime Database. הוא מטפל בכמה ניתוקים, קריסות וכו'.
מתבצע חיבור אל Cloud Firestore
כדי להטמיע פתרון דומה ב-Cloud Firestore, משתמשים באותו קוד של Realtime Database, ואז משתמשים ב-Cloud Functions כדי לשמור על סנכרון בין Realtime Database לבין Cloud Firestore.
אם עדיין לא עשיתם זאת, מוסיפים את מסד הנתונים בזמן אמת לפרויקט וכוללים את פתרון הנוכחות שלמעלה.
בשלב הבא תסנכרנו את מצב הנוכחות עם Cloud Firestore באמצעות השיטות הבאות:
- באופן מקומי, במטמון של Cloud Firestore במכשיר אופליין, כדי שהאפליקציה תדע שהמכשיר אופליין.
- באופן גלובלי, באמצעות Cloud Function, כך שכל המכשירים האחרים שיש להם גישה ל-Cloud Firestore ידעו שהמכשיר הספציפי הזה נמצא במצב אופליין.
המטמון המקומי של 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 Function שעוקבת אחרי הנתיב status/{uid}
ב-Realtime Database. כשהערך ב-Realtime Database משתנה, הערך מסתנכרן עם Cloud Firestore
כדי שסטטוס המשתמשים יהיה נכון.
Node.js
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. למטה מוצגת דוגמה למעקב אחרי משתמשים שמתחברים לאינטרנט או מתנתקים ממנו באמצעות שאילתת 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); // ... } }); });
מגבלות
השימוש ב-Realtime Database כדי להוסיף נוכחות לאפליקציית Cloud Firestore הוא יעיל וניתן להרחבה, אבל יש לו כמה מגבלות:
- Debouncing – כשמאזינים לשינויים בזמן אמת ב-Cloud Firestore, סביר להניח שהפתרון הזה יפעיל כמה שינויים. אם השינויים האלה מפעילים יותר אירועים ממה שרוצים, צריך לבצע באופן ידני הסרת כפילויות של האירועים Cloud Firestore.
- קישוריות – ההטמעה הזו מודדת את הקישוריות ל-Realtime Database, ולא ל-Cloud Firestore. אם סטטוס החיבור לכל מסד נתונים לא זהה, יכול להיות שהפתרון הזה ידווח על מצב נוכחות שגוי.
- Android – ב-Android, מסד הנתונים בזמן אמת מתנתק מהקצה העורפי אחרי 60 שניות של חוסר פעילות. אי-פעילות פירושה שאין מאזינים פתוחים או פעולות בהמתנה. כדי שהחיבור יישאר פתוח, מומלץ להוסיף מאזין לאירוע של ערך לנתיב שאינו
.info/connected
. לדוגמה, אפשר להשתמש ב-FirebaseDatabase.getInstance().getReference((new Date()).toString()).keepSynced()
בתחילת כל סשן. מידע נוסף זמין במאמר זיהוי מצב החיבור.