استنادًا إلى نوع التطبيق الذي تنشئه، قد يكون من المفيد رصد المستخدمين أو الأجهزة المتصلة بالإنترنت بشكل نشط، ويُعرف ذلك أيضًا باسم رصد "حالة التوفّر".
على سبيل المثال، إذا كنت بصدد إنشاء تطبيق مثل شبكة اجتماعية أو نشر مجموعة من أجهزة إنترنت الأشياء، يمكنك استخدام هذه المعلومات لعرض قائمة بالأصدقاء المتصلين بالإنترنت والمتاحين للدردشة، أو لترتيب أجهزة إنترنت الأشياء حسب "آخر ظهور".
لا يتيح Cloud Firestore إمكانية معرفة حالة المستخدمين بشكلٍ مباشر، ولكن يمكنك الاستفادة من منتجات Firebase الأخرى لإنشاء نظام لمعرفة حالة المستخدمين.
الحلّ: "وظائف السحابة الإلكترونية" مع Realtime Database
لربط Cloud Firestore بميزة "حالة التوفّر" الأصلية في قاعدة بيانات Firebase الآنية الاستجابة، استخدِم "وظائف السحابة الإلكترونية".
استخدِم Realtime Database للإبلاغ عن حالة الاتصال، ثم استخدِم Cloud Functions لنقل البيانات إلى Cloud Firestore.
استخدام ميزة "التواجد" في Realtime Database
أولاً، لنلقِ نظرة على طريقة عمل نظام الحضور التقليدي في Realtime Database.
الويب
// 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 Database. ويتعامل مع حالات انقطاع الاتصال المتعددة والأعطال وما إلى ذلك.
جارٍ الاتصال بجهاز Cloud Firestore
لتنفيذ حلّ مشابه في Cloud Firestore، استخدِم رمز Realtime Database نفسه، ثم استخدِم Cloud Functions للحفاظ على مزامنة Realtime Database وCloud Firestore.
إذا لم يسبق لك إجراء ذلك، أضِف قاعدة البيانات في الوقت الفعلي إلى مشروعك وأدرِج حلّ حالة الحضور أعلاه.
بعد ذلك، ستتم مزامنة حالة التوفّر مع Cloud Firestore من خلال الطرق التالية:
- محليًا، إلى ذاكرة التخزين المؤقت Cloud Firestore للجهاز غير المتصل بالإنترنت، لكي يعرف التطبيق أنّ الجهاز غير متصل بالإنترنت.
- على مستوى العالم، يتم استخدام Cloud Function لكي تعرف جميع الأجهزة الأخرى التي يمكنها الوصول إلى 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}
في قاعدة بيانات Realtime. عندما تتغيّر قيمة Realtime Database، ستتم مزامنة القيمة مع 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 Database بالخادم الخلفي بعد 60 ثانية من عدم النشاط. يعني عدم النشاط عدم توفّر أي أدوات استماع مفتوحة أو عمليات معلّقة. لإبقاء الاتصال مفتوحًا، ننصحك بإضافة أداة معالجة أحداث القيمة إلى مسار آخر غير
.info/connected
. على سبيل المثال، يمكنك تنفيذFirebaseDatabase.getInstance().getReference((new Date()).toString()).keepSynced()
في بداية كل جلسة. لمزيد من المعلومات، يُرجى الاطّلاع على رصد حالة الاتصال.