تعزيز حضورك في Cloud Firestore

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

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

لا تتيح 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 لمزامنة قاعدة بيانات في الوقت الفعلي وCloud Firestore.

أضِف قاعدة بيانات في الوقت الفعلي إلى مشروعك، في حال لم يسبق لك إجراء ذلك، وأدرِج حلّ معلومات الحضور أعلاه.

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

القيود

إنّ استخدام "قاعدة بيانات الوقت الفعلي" لإضافة ميزة "التواجد" إلى تطبيق Cloud Firestore هو إجراء قابل للتطوير وفعّال، ولكنّه يتضمّن بعض القيود:

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