Cloud Firestore'da varlık oluşturun

Geliştirdiğiniz uygulamanın türüne bağlı olarak, hangi kullanıcılarınızın veya cihazlarınızın etkin bir şekilde internete bağlı olduğunu algılamak (başka bir deyişle "mevcudiyeti" algılamak) yararlı olabilir.

Örneğin, sosyal ağ gibi bir uygulama geliştiriyorsanız veya bir IoT cihazı filosu dağıtıyorsanız bu bilgileri kullanarak sohbet etmeye hazır olan ve online olan arkadaşların listesini görüntüleyebilir veya IoT cihazlarınızı "son görüntülenme"ye göre sıralayabilirsiniz.

Cloud Firestore, varlık durumunu doğal olarak desteklemez ancak varlık durumu 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ığı özelliğine bağlamak için Cloud Functions'ı kullanın.

Bağlantı durumunu bildirmek için Realtime Database'i, ardından bu verileri Cloud Firestore'e yansıtmak için Cloud Functions'ı kullanın.

Realtime Database'de varlığı kullanma

Öncelikle, geleneksel bir mevcutluk sisteminin Realtime Database'de nasıl çalıştığını düşünün.

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ığı sistemidir. Birden fazla bağlantı kesilmesi, kilitlenme vb. durumları ele alır.

Cloud Firestore cihazına bağlanıyor

Cloud Firestore'te benzer bir çözüm uygulamak için aynı Realtime Database kodunu kullanın, ardından Realtime Database ile Cloud Firestore'ü senkronize tutmak için Cloud Functions'ı kullanın.

Henüz yapmadıysanız projenize Realtime Database'i ekleyin ve yukarıdaki mevcutluk çözümünü dahil edin.

Ardından, aşağıdaki yöntemler aracılığıyla mevcutluk durumunu Cloud Firestore ile senkronize edersiniz:

  1. Yerel olarak, çevrimdışı cihazın Cloud Firestore önbelleğine. Böylece uygulama çevrimdışı olduğunu bilir.
  2. Cloud Firestore'e erişen diğer tüm cihazların bu cihazın çevrimdışı olduğunu bilmesi için Cloud işlevi kullanılarak dünya genelinde.

Cloud Firestore'nin yerel önbelleğini güncelleme

İlk sorunu gidermek için gereken değişikliklere (Cloud Firestore'ın yerel önbelleğini güncelleme) göz atalım.

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 durumunun her zaman cihazın çevrimiçi/çevrimdışı durumunu yansıtmasını sağladık. Bu sayede /status/{uid} belgesini 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üncelleme

Uygulamamız, çevrimiçi varlığı kendisine doğru şekilde bildirse de "çevrimdışı" durum yazma işlemimiz yalnızca yerel olduğundan ve bağlantı yeniden kurulduğunda senkronize edilmediğinden bu durum henüz diğer Cloud Firestore uygulamalarında doğru olmayacaktır. Buna karşı koymak için Realtime Database'deki status/{uid} yolunu izleyen bir Cloud Functions işlevi kullanacağız. Gerçek Zamanlı Veritabanı değeri değiştiğinde, tüm kullanıcıların durumlarının doğru olması için değer 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 sistemi elde edersiniz. Aşağıda, where() sorgusu kullanılarak çevrimiçi olan veya çevrimdışı olan tüm kullanıcılar için izleme örneği 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

Cloud Firestore uygulamanıza kullanılabilirlik özelliği eklemek için Realtime Database'i kullanmak ölçeklenebilir ve etkilidir ancak bazı sınırlamaları vardır:

  • Debouncing: Cloud Firestore'deki gerçek zamanlı değişiklikleri dinlerken bu çözümün birden fazla değişikliği tetikleme olasılığı vardır. Bu değişiklikler istediğinizden daha fazla etkinlik tetiklerse Cloud Firestore etkinliklerini manuel olarak debounce edin.
  • Bağlantı: Bu uygulama, Cloud Firestore'ye değil, Gerçek Zamanlı Veritabanı'na olan bağlantıyı ölçer. Her veritabanına ait 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çtan bağlantısını keser. Etkin olmama durumu, açık dinleyici veya bekleyen işlem olmadığı anlamına gelir. Bağlantıyı açık tutmak için .info/connected dışında bir yola değer etkinliği işleyici eklemenizi öneririz. Örneğin, her oturumun başında FirebaseDatabase.getInstance().getReference((new Date()).toString()).keepSynced() yapabilirsiniz. Daha fazla bilgi için Bağlantı durumunu algılama başlıklı makaleyi inceleyin.