Tuỳ thuộc vào loại ứng dụng mà bạn đang xây dựng, bạn có thể thấy hữu ích khi phát hiện người dùng hoặc thiết bị nào đang hoạt động trực tuyến – còn được gọi là phát hiện "trạng thái hiện diện".
Ví dụ: nếu bạn đang xây dựng một ứng dụng như mạng xã hội hoặc triển khai một nhóm 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à rảnh để trò chuyện hoặc sắp xếp các thiết bị IoT theo "lần truy cập gần đây nhất".
Cloud Firestore không hỗ trợ sẵn trạng thái 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 trạng thái hiện diện.
Giải pháp: Cloud Functions với Cơ sở dữ liệu theo thời gian thực
Để kết nối Cloud Firestore với tính năng trạng thái hiện diện gốc của Firebase Realtime Database, hãy 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 để sao chép dữ liệu đó vào Cloud Firestore.
Sử dụng trạng thái 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 hệ thống trạng thái 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 trạng thái hiện diện hoàn chỉnh của Cơ sở dữ liệu theo thời gian thực. Hệ thống này xử lý nhiều trường hợp ngắt kết nối, sự cố, v.v.
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ột mã Cơ sở dữ liệu theo thời gian thực, sau đó sử dụng Cloud Functions để đồng bộ hoá Cơ sở dữ liệu theo thời gian thực và Cloud Firestore.
Nếu bạn chưa thực hiện, hãy thêm Cơ sở dữ liệu theo thời gian thực vào dự án của bạn và đưa giải pháp trạng thái hiện diện ở trên vào.
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:
- Theo cách cục bộ, vào bộ nhớ đệm Cloud Firestore của thiết bị ngoại tuyến để ứng dụng biết rằng thiết bị đang ngoại tuyến.
- Theo cách toàn cục, bằng cách sử dụng Cloud Function để tất cả các thiết bị khác truy cập vào Cloud Firestore đều biết rằng thiết bị cụ thể này đang ngoại tuyến.
Các hàm được đề xuất trong hướng dẫn này không thể chạy trong ứng dụng khách. Bạn phải triển khai các hàm này vào Cloud Functions for Firebase, và các hàm này yêu cầu logic phía máy chủ từ SDK của Firebase dành cho quản trị viên. Để biết hướng dẫn chi tiết, hãy xem tài liệu về Cloud Functions.
Cập nhật bộ nhớ đệm cục bộ của Cloud Firestore
Hãy xem xét các thay đổi cần thiết để giải quyết vấn đề đầu tiên – cập nhật Cloud Firestore bộ nhớ đệm cục bộ.
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, chúng tôi đã đảm bảo rằng trạng thái cục bộ Cloud Firestore 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ể theo dõi tài liệu /status/{uid} và sử dụng dữ liệu để thay đổi giao diện người dùng nhằm phản ánh trạng thái kết nố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 trạng thái hiện diện trực tuyến cho chính ứng dụng đó, nhưng trạng thái này
sẽ chưa chính xác trong các ứng dụng Cloud Firestore khác vì thao tác ghi trạng thái "ngoại tuyến"
của chúng tôi chỉ là cục bộ và sẽ không được đồng bộ hoá khi kết nối được khôi phục. Để khắc phục điều này, chúng tôi sẽ sử dụng một Cloud Function theo dõi đường dẫn status/{uid} trong Realtime Database. Khi giá trị 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
để trạng thái của tất cả người dùng đều 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ẽ có một hệ thống trạng thái hiện diện hoàn chỉnh chạy
với Cloud Firestore. Dưới đây là ví dụ về việc giám sát bất kỳ người dùng nào chuyển sang trạng thái trực tuyến hoặc 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); // ... } }); });
Hạn chế
Việc sử dụng Cơ sở dữ liệu theo thời gian thực để thêm trạng thái hiện diện vào ứng dụng Cloud Firestore có thể mở rộng và hiệu quả nhưng có một số hạn chế:
- Loại bỏ trùng lặp – khi theo dõi 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 mức bạn muốn, hãy loại bỏ trùng lặp các sự kiện Cloud Firestore theo cách thủ công.
- 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 Realtime Database, chứ không phải với Cloud Firestore. Nếu trạng thái kết nối với từng cơ sở dữ liệu không giống nhau, thì 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 theo thời gian thực sẽ ngắt kết nối với phần phụ trợ sau 60 giây không hoạt động. Không hoạt động có nghĩa là không có trình nghe đang mở hoặc hoạt động đang chờ xử lý. Để duy trì kết nối mở, bạn nên thêm trình nghe sự kiện giá trị vào một đường dẫn bên cạnh
.info/connected. Ví dụ: bạn có thể thực hiệnFirebaseDatabase.getInstance().getReference((new Date()).toString()).keepSynced()khi bắt đầu mỗi phiên. Để biết thêm thông tin, hãy xem bài viết Phát hiện trạng thái kết nối.