获取我们在 Firebase 峰会上发布的所有信息,了解 Firebase 可如何帮助您加快应用开发速度并满怀信心地运行应用。了解详情

حضور در Cloud Firestore

بسته به نوع برنامه‌ای که می‌سازید، تشخیص اینکه کدام یک از کاربران یا دستگاه‌های شما فعالانه آنلاین هستند، ممکن است مفید باشد - در غیر این صورت به عنوان تشخیص «حضور» شناخته می‌شود.

برای مثال، اگر در حال ساخت اپلیکیشنی مانند یک شبکه اجتماعی یا استقرار ناوگانی از دستگاه‌های اینترنت اشیا هستید، می‌توانید از این اطلاعات برای نمایش لیستی از دوستان آنلاین و رایگان برای چت کردن استفاده کنید، یا دستگاه‌های اینترنت اشیا خود را بر اساس «آخرین بازدید» مرتب کنید. "

Cloud Firestore به طور بومی از حضور پشتیبانی نمی‌کند، اما می‌توانید از سایر محصولات Firebase برای ایجاد یک سیستم حضور استفاده کنید.

راه حل: توابع ابر با پایگاه داده بیدرنگ

برای اتصال Cloud Firestore به ویژگی حضور بومی پایگاه داده بیدرنگ Firebase، از Cloud Functions استفاده کنید.

از پایگاه داده بیدرنگ برای گزارش وضعیت اتصال استفاده کنید، سپس از Cloud Functions برای منعکس کردن آن داده ها در Cloud Firestore استفاده کنید.

استفاده از حضور در پایگاه داده بیدرنگ

ابتدا، نحوه عملکرد یک سیستم حضور سنتی در پایگاه داده Realtime را در نظر بگیرید.

وب

// 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 است. چندین قطع اتصال، خرابی و غیره را کنترل می کند.

اتصال به Cloud Firestore

برای پیاده سازی یک راه حل مشابه در Cloud Firestore از همان کد Realtime Database استفاده کنید، سپس از Cloud Functions برای همگام نگه داشتن پایگاه داده Realtime و Cloud Firestore استفاده کنید.

اگر قبلاً این کار را نکرده‌اید، پایگاه داده Realtime را به پروژه خود اضافه کنید و راه حل حضور بالا را در آن قرار دهید.

در مرحله بعد وضعیت حضور را با روش های زیر با Cloud Firestore همگام می کنید:

  1. به صورت محلی، به حافظه پنهان Cloud Firestore دستگاه آفلاین، به طوری که برنامه بداند آفلاین است.
  2. در سطح جهانی، از یک تابع Cloud استفاده کنید تا همه دستگاه‌های دیگری که به 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} را در پایگاه داده بیدرنگ مشاهده می کند. هنگامی که مقدار پایگاه داده بیدرنگ تغییر می کند، مقدار با 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() 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 - هنگام گوش دادن به تغییرات بلادرنگ در Cloud Firestore، این راه حل احتمالاً تغییرات متعددی را ایجاد می کند. اگر این تغییرات بیش از آنچه می‌خواهید رویدادها را راه‌اندازی می‌کنند، رویدادهای Cloud Firestore را به صورت دستی حذف کنید.
  • اتصال - این پیاده سازی اتصال به پایگاه داده Realtime را اندازه گیری می کند، نه به Cloud Firestore. اگر وضعیت اتصال به هر پایگاه داده یکسان نباشد، این راه حل ممکن است وضعیت حضور نادرست را گزارش کند.
  • Android - در Android، پایگاه داده Realtime پس از 60 ثانیه عدم فعالیت، از Backend قطع می شود. عدم فعالیت به این معنی است که شنوندگان باز یا عملیات معلق وجود نداشته باشند. برای باز نگه داشتن اتصال، توصیه می‌کنیم یک شنونده رویداد ارزشی به مسیری علاوه بر .info/connected اضافه کنید. برای مثال می‌توانید FirebaseDatabase.getInstance().getReference((new Date()).toString()).keepSynced() را در شروع هر جلسه انجام دهید. برای اطلاعات بیشتر، به تشخیص وضعیت اتصال مراجعه کنید.