بناء التواجد في Cloud Firestore

اعتمادًا على نوع التطبيق الذي تقوم بإنشائه، قد تجد أنه من المفيد اكتشاف المستخدمين أو الأجهزة المتصلة بالإنترنت بشكل نشط - والمعروف أيضًا باسم اكتشاف "التواجد".

على سبيل المثال، إذا كنت تنشئ تطبيقًا مثل شبكة اجتماعية أو تنشر أسطولًا من أجهزة إنترنت الأشياء، فيمكنك استخدام هذه المعلومات لعرض قائمة بالأصدقاء المتصلين بالإنترنت والذين يمكنهم الدردشة مجانًا، أو فرز أجهزة إنترنت الأشياء الخاصة بك حسب "آخر ظهور" ".

لا يدعم Cloud Firestore التواجد بشكل أساسي، ولكن يمكنك الاستفادة من منتجات Firebase الأخرى لإنشاء نظام تواجد.

الحل: وظائف السحابة مع قاعدة بيانات الوقت الحقيقي

لتوصيل Cloud Firestore بميزة التواجد الأصلية لـ Firebase Realtime Database، استخدم Cloud Functions.

استخدم قاعدة بيانات Realtime للإبلاغ عن حالة الاتصال، ثم استخدم 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، استخدم نفس رمز قاعدة بيانات Realtime، ثم استخدم Cloud Functions للحفاظ على مزامنة Realtime Database وCloud Firestore.

إذا لم تقم بذلك بالفعل، قم بإضافة Realtime Database إلى مشروعك وقم بتضمين حل الحضور أعلاه.

بعد ذلك، ستقوم بمزامنة حالة التواجد مع 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);
    });
});

بفضل هذه التغييرات، تأكدنا الآن من أن حالة Cloud Firestore المحلية ستعكس دائمًا حالة الاتصال/عدم الاتصال بالجهاز. هذا يعني أنه يمكنك الاستماع إلى مستند /status/{uid} واستخدام البيانات لتغيير واجهة المستخدم الخاصة بك لتعكس حالة الاتصال.

ويب

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

تحديث Cloud Firestore عالميًا

على الرغم من أن تطبيقنا يُبلغ نفسه عن التواجد عبر الإنترنت بشكل صحيح، فإن هذه الحالة لن تكون دقيقة في تطبيقات Cloud Firestore الأخرى حتى الآن لأن كتابة حالة "غير متصل" لدينا تكون محلية فقط ولن تتم مزامنتها عند استعادة الاتصال. لمواجهة ذلك، سنستخدم وظيفة السحابة التي تراقب مسار status/{uid} في قاعدة بيانات الوقت الفعلي. عندما تتغير قيمة قاعدة بيانات الوقت الحقيقي، ستتم مزامنة القيمة مع 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 الخاص بك قابلاً للتطوير وفعالاً ولكن له بعض القيود:

  • الارتداد - عند الاستماع إلى التغييرات في الوقت الفعلي في Cloud Firestore، من المرجح أن يؤدي هذا الحل إلى إحداث تغييرات متعددة. إذا أدت هذه التغييرات إلى حدوث أحداث أكثر مما تريد، فقم بإلغاء أحداث Cloud Firestore يدويًا.
  • الاتصال - يقيس هذا التنفيذ الاتصال بقاعدة بيانات Realtime، وليس بـ Cloud Firestore. إذا لم تكن حالة الاتصال بكل قاعدة بيانات هي نفسها، فقد يُبلغ هذا الحل عن حالة حضور غير صحيحة.
  • Android - على نظام Android، يتم قطع اتصال قاعدة بيانات Realtime عن الواجهة الخلفية بعد 60 ثانية من عدم النشاط. عدم النشاط يعني عدم وجود مستمعين مفتوحين أو عمليات معلقة. لإبقاء الاتصال مفتوحًا، ننصحك بإضافة مستمع حدث قيمة إلى مسار بجانب .info/connected . على سبيل المثال، يمكنك إجراء FirebaseDatabase.getInstance().getReference((new Date()).toString()).keepSynced() في بداية كل جلسة. لمزيد من المعلومات، راجع الكشف عن حالة الاتصال .