Xây dựng sự hiện diện trong Cloud Firestore

Tuỳ thuộc vào loại ứng dụng đang xây dựng, bạn có thể thấy hữu ích trong việc phát hiện những người dùng hoặc thiết bị nào của bạn đang hoạt động trên mạng (còn được gọi là phát hiện "sự hiện diện".

Ví dụ: nếu bạn đang tạo một ứng dụng như mạng xã hội hoặc triển khai một gồm nhiều thiết bị IoT, bạn có thể sử dụng thông tin này để hiển thị danh sách bạn bè đang trực tuyến và trò chuyện miễn phí hoặc sắp xếp thiết bị IoT của bạn theo "nhìn thấy lần cuối".

Cloud Firestore không hỗ trợ sẵn sự hiện diện, nhưng bạn có thể tận dụng các sản phẩm khác của Firebase để xây dựng hệ thống hiện diện.

Giải pháp: Hàm đám mây với cơ sở dữ liệu theo thời gian thực

Cách kết nối Cloud Firestore với gốc của Cơ sở dữ liệu theo thời gian thực Firebase hiện diện, sử dụng Cloud Functions.

Sử dụng Cơ sở dữ liệu theo thời gian thực để báo cáo trạng thái kết nối, sau đó sử dụng Cloud Functions để phản chiếu dữ liệu đó lên Cloud Firestore.

Sử dụng tính năng hiện diện trong Cơ sở dữ liệu theo thời gian thực

Trước tiên, hãy xem xét cách hoạt động của một hệ thống hiện diện truyền thống trong Cơ sở dữ liệu theo thời gian thực.

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

Ví dụ này là một hệ thống hoàn chỉnh hiện diện Cơ sở dữ liệu theo thời gian thực. Chiến dịch này xử lý nhiều sự cố ngắt kết nối, sự cố, v.v.

Đang kết nối với Cloud Firestore

Để triển khai một giải pháp tương tự trong Cloud Firestore, hãy sử dụng cùng Mã Cơ sở dữ liệu theo thời gian thực, sau đó sử dụng Cloud Functions để lưu giữ Cơ sở dữ liệu theo thời gian thực và Cloud Firestore đang đồng bộ hoá.

Thêm Cơ sở dữ liệu theo thời gian thực vào dự án nếu bạn chưa thêm và bao gồm giải pháp hiện diện nêu trên.

Tiếp theo, bạn sẽ đồng bộ hoá trạng thái hiện diện với Cloud Firestore thông qua các phương thức sau:

  1. Trên máy, vào bộ nhớ đệm Cloud Firestore của thiết bị ngoại tuyến để ứng dụng biết thiết bị đang không kết nối mạng.
  2. Sử dụng Chức năng đám mây trên toàn cầu để tất cả các thiết bị khác truy cập Cloud Firestore biết thiết bị này hiện không có kết nối mạng.

Cập nhật bộ nhớ đệm cục bộ của Cloud Firestore

Hãy cùng xem những thay đổi cần thiết để hoàn thành vấn đề đầu tiên: cập nhật Bộ nhớ đệm cục bộ của Cloud Firestore.

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

Với những thay đổi này, giờ đây chúng tôi đã đảm bảo rằng trạng thái Cloud Firestore cục bộ sẽ luôn phản ánh trạng thái trực tuyến/ngoại tuyến của thiết bị. Điều này có nghĩa là bạn có thể nghe /status/{uid} tạo tài liệu và sử dụng dữ liệu để thay đổi giao diện người dùng nhằm phản ánh kết nối trạng thái.

Web

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

Cập nhật Cloud Firestore trên toàn cầu

Mặc dù ứng dụng của chúng tôi báo cáo chính xác sự hiện diện trực tuyến cho chính nó, nhưng trạng thái này sẽ chưa chính xác trong các ứng dụng khác trên Cloud Firestore vì tính năng "ngoại tuyến" của chúng tôi trạng thái ghi chỉ được lưu trên thiết bị và sẽ không được đồng bộ hoá khi kết nối được khôi phục. Để phản đối nên chúng tôi sẽ dùng một Hàm đám mây theo dõi đường dẫn status/{uid} theo Thời gian thực Cơ sở dữ liệu. Khi giá trị của Cơ sở dữ liệu theo thời gian thực thay đổi, giá trị này sẽ đồng bộ hoá với Cloud Firestore để tất cả người dùng trạng thái là chính xác.

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

Sau khi triển khai hàm này, bạn sẽ chạy toàn bộ hệ thống hiện diện với Cloud Firestore. Dưới đây là ví dụ về cách giám sát đối với bất kỳ người dùng nào kết nối mạng hoặc chuyển sang chế độ ngoại tuyến bằng cách sử dụng truy vấn where().

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

Các điểm hạn chế

Việc sử dụng Cơ sở dữ liệu theo thời gian thực để tăng cường sự hiện diện cho ứng dụng của bạn trên Cloud Firestore đã có thể mở rộng và hiệu quả nhưng có một số hạn chế:

  • Gỡ bỏ – khi nghe các thay đổi theo thời gian thực trong Cloud Firestore, giải pháp này có thể kích hoạt nhiều thay đổi. Nếu những thay đổi này kích hoạt nhiều sự kiện hơn bạn muốn, hãy tự mình gỡ bỏ các sự kiện Cloud Firestore.
  • Khả năng kết nối – cách triển khai này đo lường khả năng kết nối với Báo cáo theo thời gian thực Cơ sở dữ liệu, chứ không phải đến Cloud Firestore. Nếu kết nối trạng thái cho mỗi cơ sở dữ liệu là không giống nhau, giải pháp này có thể báo cáo trạng thái hiện diện không chính xác.
  • Android - trên Android, Cơ sở dữ liệu thời gian thực ngắt kết nối khỏi sau 60 giây không hoạt động. Không hoạt động nghĩa là không có trình nghe mở hoặc các thao tác đang chờ xử lý. Để duy trì kết nối, bạn nên thêm trình nghe sự kiện giá trị đến một đường dẫn bên cạnh .info/connected. Ví dụ: có thể làm FirebaseDatabase.getInstance().getReference((new Date()).toString()).keepSynced() vào đầu mỗi phiên. Để biết thêm thông tin, hãy xem Phát hiện trạng thái kết nối.