Geliştirdiğiniz uygulamanın türüne bağlı olarak, kullanıcılarınızın veya cihazlarınızın hangilerinin etkin olarak çevrimiçi olduğunu (diğer adıyla "varlığı") tespit etmek faydalı olabilir.
Örneğin, sosyal ağ gibi bir uygulama geliştiriyorsanız veya bir IoT cihaz filosu dağıtıyorsanız bu bilgileri kullanarak çevrimiçi olan ve sohbet etmeye müsait arkadaşların listesini gösterebilir ya da IoT cihazlarınızı "en son görülen" ölçütüne göre sıralayabilirsiniz.
Cloud Firestore, varlık özelliğini doğal olarak desteklemez ancak varlık sistemi oluşturmak için diğer Firebase ürünlerinden yararlanabilirsiniz.
Çözüm: Realtime Database ile Cloud Functions
Cloud Firestore'ı Firebase Realtime Database'in yerel varlık özelliğine bağlamak için Cloud Functions'ı kullanın.
Bağlantı durumunu bildirmek için Realtime Database'i, bu verileri Cloud Firestore'ya yansıtmak için Cloud Functions'ı kullanın.
Realtime Database'de varlık özelliğini kullanma
Öncelikle, geleneksel bir varlık sisteminin Realtime Database'de nasıl çalıştığını göz önünde bulundurun.
Web
// 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); }); });
Bu örnek, eksiksiz bir Realtime Database varlık sistemidir. Birden fazla bağlantı kesilmesi, kilitlenme vb. durumları işler.
Cloud Firestore cihazına bağlanıyor
Cloud Firestore'da benzer bir çözümü uygulamak için aynı Realtime Database kodunu kullanın, ardından Realtime Database ve Cloud Firestore'ı senkronize etmek için Cloud Functions'ı kullanın.
Henüz yapmadıysanız projenize Realtime Database'i ekleyin ve yukarıdaki varlık çözümünü dahil edin.
Ardından, aşağıdaki yöntemlerle varlık durumunu Cloud Firestore ile senkronize edersiniz:
- Uygulamanın çevrimdışı olduğunu bilmesi için çevrimdışı cihazın Cloud Firestore önbelleğine yerel olarak.
- Dünya genelinde, Cloud Firestore adlı cihaza erişen diğer tüm cihazların bu cihazın çevrimdışı olduğunu bilmesi için Cloud Function kullanma.
Cloud Firestore kullanıcısının yerel önbelleği güncelleniyor
İlk sorunu çözmek için yapılması gereken değişikliklere göz atalım: Cloud Firestore'nın yerel önbelleğini güncelleme.
Web
// ... 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); }); });
Bu değişikliklerle birlikte, yerel Cloud Firestore durumun her zaman cihazın online/offline durumunu yansıtmasını sağladık. Bu sayede /status/{uid}
dokümanını dinleyebilir ve verileri kullanarak kullanıcı arayüzünüzü bağlantı durumunu yansıtacak şekilde değiştirebilirsiniz.
Web
userStatusFirestoreRef.onSnapshot(function(doc) { var isOnline = doc.data().state == 'online'; // ... use isOnline });
Cloud Firestore dünya genelinde güncelleniyor
Uygulamamız, çevrimiçi durumu kendi içinde doğru şekilde bildiriyor olsa da "çevrimdışı" durum yazma işlemi yalnızca yerel olarak yapıldığından ve bağlantı geri yüklendiğinde senkronize edilmediğinden bu durum, diğer Cloud Firestore uygulamalarda henüz doğru olmayacaktır. Bunu önlemek için Realtime Database'deki status/{uid}
yolunu izleyen bir Cloud Functions işlevi kullanacağız. Realtime Database değeri değiştiğinde değer, tüm kullanıcıların durumlarının doğru olması için Cloud Firestore ile senkronize edilir.
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); // ... } }); });
Bu işlevi dağıttıktan sonra Cloud Firestore ile çalışan eksiksiz bir varlık sisteminiz olur. Aşağıda, where()
sorgusu kullanılarak çevrimiçi olan veya çevrimdışı kalan kullanıcıların izlenmesine dair bir örnek verilmiştir.
Web
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); // ... } }); });
Sınırlamalar
Realtime Database'i kullanarak Cloud Firestore uygulamanıza varlık özelliği eklemek ölçeklenebilir ve etkili bir yöntemdir ancak bazı sınırlamaları vardır:
- Sekme önleme: Cloud Firestore içinde gerçek zamanlı değişiklikler dinlenirken bu çözümün birden fazla değişikliği tetiklemesi olasıdır. Bu değişiklikler, istediğinizden daha fazla etkinliği tetikliyorsa Cloud Firestore etkinliklerini manuel olarak azaltın.
- Bağlantı: Bu uygulama, Cloud Firestore'ye değil, Realtime Database'e bağlantıyı ölçer. Her veritabanına bağlantı durumu aynı değilse bu çözüm yanlış bir varlık durumu bildirebilir.
- Android: Android'de Realtime Database, 60 saniye boyunca işlem yapılmadığında arka uçla bağlantısını keser. Etkin olmama, açık dinleyicilerin veya bekleyen işlemlerin olmaması anlamına gelir. Bağlantının açık kalması için
.info/connected
dışındaki bir yola değer etkinlik dinleyicisi eklemenizi öneririz. Örneğin, her oturumun başındaFirebaseDatabase.getInstance().getReference((new Date()).toString()).keepSynced()
yapabilirsiniz. Daha fazla bilgi için Bağlantı Durumunu Algılama başlıklı makaleyi inceleyin.