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

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

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

لا توفّر Cloud Firestore ميزة "التوفُّر" في الأصل، ولكن يمكن الاستفادة من منتجات Firebase الأخرى لإنشاء نظام للحضور.

الحل: دوال السحابة الإلكترونية باستخدام قاعدة بيانات "الوقت الفعلي"

لربط Cloud Firestore بميزة التواجد الأصلية في "قاعدة بيانات Firebase في الوقت الفعلي"، يمكنك استخدام Cloud Functions.

استخدِم "قاعدة بيانات الوقت الفعلي" للإبلاغ عن حالة الاتصال، ثم استخدِم 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، استخدِم رمز قاعدة البيانات في الوقت الفعلي نفسه، ثم استخدِم Cloud Functions للحفاظ على مزامنة قاعدة بيانات "الوقت الفعلي" و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);
    });
});

من خلال هذه التغييرات، تأكّدنا الآن من أنّ حالة 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);
                // ...
            }
        });
    });

القيود

يُعد استخدام قاعدة البيانات في الوقت الفعلي لإضافة حضور إلى تطبيق Cloud Firestore قابلاً للتطور وفعالاً، ولكن هناك بعض القيود:

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