Join us for Firebase Summit on November 10, 2021. Tune in to learn how Firebase can help you accelerate app development, release with confidence, and scale with ease. Register

בנה נוכחות בענן Firestore

בהתאם לסוג האפליקציה שאתה בונה, ייתכן שתעזור לך לזהות מי מהמשתמשים או המכשירים שלך מחוברים באופן פעיל - אחרת ידועה כזיהוי "נוכחות".

לדוגמה, אם אתה בונה אפליקציה כמו רשת חברתית או פורס צי של מכשירי IoT, תוכל להשתמש במידע זה כדי להציג רשימת חברים שהינם מחוברים בחינם ולשוחח בחינם, או למיין את מכשירי ה- IoT שלך לפי "נראה לאחרונה" . "

Cloud Firestore אינו תומך נוכחות באופן מקורי, אך תוכל לנצל מוצרים אחרים של Firebase לבניית מערכת נוכחות.

פתרון: פונקציות ענן עם מסד נתונים בזמן אמת

כדי לחבר את Cloud Firestore לתכונת הנוכחות המקורית של מסד הנתונים של Firebase בזמן אמת, השתמש בפונקציות ענן.

השתמש במסד נתונים בזמן אמת כדי לדווח על מצב החיבור ולאחר מכן השתמש בפונקציות ענן כדי לשקף את הנתונים האלה ל- 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 Firestore בשיטות הבאות:

  1. באופן מקומי, למטמון Cloud Firestore של המכשיר הלא מקוון כך שהאפליקציה תדע שהיא לא מקוונת.
  2. ברחבי העולם, באמצעות פונקציית ענן כך שכל המכשירים האחרים שניגשים ל- 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);
    });
});

עם השינויים האלה אנחנו עכשיו וידאנו המדינה המקומית הענן Firestore תמיד תשקף את מקוונים / מעמד מחובר המכשיר. אמצעי זה אתה יכול להקשיב /status/{uid} מסמך ולהשתמש בנתונים כדי לשנות UI שלך כדי לשקף את מצב החיבור.

אינטרנט

userStatusFirestoreRef.onSnapshot(function(doc) {
    var isOnline = doc.data().state == 'online';
    // ... use isOnline
});

מעדכן את Cloud Firestore ברחבי העולם

למרות שהאפליקציה שלנו מדווחת לעצמה נוכחות מקוונת בצורה נכונה, סטטוס זה עדיין לא יהיה מדויק באפליקציות אחרות של Cloud Firestore מכיוון שכתיבת הסטטוס ה"לא מקוון "שלנו היא מקומית בלבד ולא תסונכרן כאשר החיבור ישוחזר. כדי להתמודד עם זה, נשתמש פונקציה ענן אשר צופה status/{uid} הנתיב מסד זמן אמת. כאשר ערך מסד הנתונים בזמן אמת ישתנה הערך יסונכרן עם Cloud Firestore כך שכל הסטטוסים של המשתמשים יהיו נכונים.

Node.js

const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.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 = admin.firestore();

// 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 שלך ​​הוא מדרגי ויעיל אך יש לו כמה מגבלות:

  • Debouncing - בעת האזנה בזמן אמת לשינויים ענן Firestore, פתרון זה עשוי לגרום לשינויים מרובים. אם שינויים אלה מפעילים יותר אירועים ממה שאתה רוצה, אפשר לבטל את ההפעלה הידנית של אירועי Cloud Firestore.
  • קישוריות - קישוריות צעדים ליישום זה מסד זמן אמת, לא ענן firestore. אם מצב החיבור לכל מסד נתונים אינו זהה, פתרון זה עשוי לדווח על מצב נוכחות שגוי.
  • אנדרואיד - על אנדרואיד, מתנתק מסד זמן אמת מן backend לאחר 60 שניות של חוסר פעילות. חוסר פעילות פירושו אין מאזינים פתוחים או פעולות בהמתנה. כדי לשמור על פתוח חיבור, המלצנו לך להוסיף מאזין אירוע ערך נתיב מלבד .info/connected . לדוגמה אתה יכול לעשות FirebaseDatabase.getInstance().getReference((new Date()).toString()).keepSynced() בתחילת כל מפגש. לקבלת מידע נוסף, ראה מצב חיבור זיהוי .