Tworzenie obecności w Cloud Firestore

W zależności od typu tworzonej aplikacji przydatne może być wykrywanie którzy użytkownicy lub urządzenia aktywnie korzystają z internetu. wykrywania obecności.

Na przykład, jeśli tworzysz aplikację, taką jak sieć społecznościowa, lub wdrażasz urządzeń IoT, można użyć tych informacji do wyświetlenia listy ze znajomymi, którzy są online i mogą rozmawiać, lub sortuj urządzenia IoT według „ostatnio widziano”.

Cloud Firestore nie obsługuje natywnie obecności, ale możesz Wykorzystać inne usługi Firebase do stworzenia systemu obecności.

Rozwiązanie: funkcje w Cloud Functions z bazą danych czasu rzeczywistego

Aby połączyć Cloud Firestore z natywną bazą danych czasu rzeczywistego Firebase obecności, użyj Cloud Functions.

Używaj Bazy danych czasu rzeczywistego do raportowania stanu połączenia, a następnie używaj Cloud Functions do powielanie tych danych w Cloud Firestore.

Korzystanie z obecności w bazie danych czasu rzeczywistego

Najpierw zastanów się, jak działa tradycyjny system obecności w bazie danych czasu rzeczywistego.

Sieć

// 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);
    });
});

Ten przykład przedstawia kompletny system obecności w bazie danych czasu rzeczywistego. Obsługuje wielokrotne rozłączenia, awarie itd.

Łączę z Cloud Firestore

Aby wdrożyć podobne rozwiązanie w Cloud Firestore, użyj tego samego w Bazie danych czasu rzeczywistego, a następnie za pomocą Cloud Functions Usługa Cloud Firestore jest zsynchronizowana.

Dodaj do swojego projektu Bazę danych czasu rzeczywistego, chyba że masz to już za sobą. i uwzględnij powyższe rozwiązanie do wykrywania obecności.

Następnie zsynchronizuj stan obecności z Cloud Firestore następujące metody:

  1. Lokalnie, do pamięci podręcznej Cloud Firestore urządzenia offline, urządzenie wie, że jest offline.
  2. globalnie za pomocą funkcji w Cloud Functions, aby wszystkie inne urządzenia miały dostęp Cloud Firestore wie, że to konkretne urządzenie jest offline.

Aktualizowanie lokalnej pamięci podręcznej Cloud Firestore

Przyjrzyjmy się zmianom wymaganym do rozwiązania pierwszego problemu, czyli aktualizacji Lokalna pamięć podręczna Cloud Firestore.

Sieć

// ...
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);
    });
});

Dzięki tym zmianom lokalny stan Cloud Firestore będzie zawsze pokazują stan online/offline urządzenia. Oznacza to, że możesz odsłuchiwać /status/{uid} dokument i użyj danych, aby zmienić UI i odzwierciedlić połączenie stanu.

Sieć

userStatusFirestoreRef.onSnapshot(function(doc) {
    var isOnline = doc.data().state == 'online';
    // ... use isOnline
});

Globalne aktualizowanie Cloud Firestore

Mimo że nasza aplikacja prawidłowo zgłasza swoją obecność w internecie, ten stan nie będzie jeszcze dokładna w innych aplikacjach Cloud Firestore, ponieważ nasza funkcja „offline” Zapis stanu jest sprawdzany lokalnie i nie będzie synchronizowany po przywróceniu połączenia. Do kontrahenta użyjemy funkcji w Cloud Functions, która monitoruje ścieżkę status/{uid} w czasie rzeczywistym, Baza danych. Gdy wartość Bazy danych czasu rzeczywistego się zmieni, wartość zostanie zsynchronizowana z Cloud Firestore aby wszyscy użytkownicy są poprawne.

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);
                // ...
            }
        });
    });

Po wdrożeniu tej funkcji zostanie uruchomiony kompletny system obecności w Cloud Firestore. Poniżej znajduje się przykład monitorowania dla użytkowników, którzy przejdź do trybu online lub offline za pomocą zapytania where().

Sieć

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);
                // ...
            }
        });
    });

Ograniczenia

Użycie Bazy danych czasu rzeczywistego w celu dodania obecności aplikacji Cloud Firestore to skalowalne i efektywne, ale mają pewne ograniczenia:

  • Debouncing – podczas słuchania zmian w czasie rzeczywistym Cloud Firestore, to rozwiązanie prawdopodobnie wywoła wiele zmian. Jeśli te zmiany wywołują więcej zdarzeń niż potrzebujesz, ręcznie odrzuca zdarzenia Cloud Firestore.
  • Połączenia – ta implementacja służy do pomiaru połączeń z interfejsem Czas rzeczywisty. Bazy danych, a nie Cloud Firestore. Jeśli połączenie stan każdej bazy danych nie jest taki sam, to rozwiązanie może zgłosić błąd nieprawidłowy stan obecności.
  • Android – na Androidzie Baza danych czasu rzeczywistego rozłącza się od do backendu po 60 sekundach braku aktywności. Brak aktywności oznacza brak otwartych detektorów lub operacje oczekujące. Aby połączenie pozostawało otwarte, zalecamy dodanie detektor zdarzeń wartości do ścieżki innej niż .info/connected. Na przykład Ty może FirebaseDatabase.getInstance().getReference((new Date()).toString()).keepSynced() na początku każdej sesji. Więcej informacji: Wykrywam stan połączenia.