在Firebase中处理用户的在线和离线状态

时间:2018-08-09 13:23:23

标签: javascript firebase firebase-realtime-database google-cloud-functions

我想在我的Web应用程序中处理在线和离线状态。 这样用户可以看到谁在线,谁不在。

我发现了这个很棒的教程,对它的解释很好,但是我被困住了。

https://blog.campvanilla.com/firebase-firestore-guide-how-to-user-presence-online-offline-basics-66dc27f67802

我觉得cloud-functions出了问题,因为那里出现了错误。

此外,该教程是从2017年12月15日开始的,我知道cloud-functions已更新,但我不知道如何更新代码。

链接到文档:https://firebase.google.com/docs/functions/beta-v1-diff

有人可以看一下本教程,也许可以帮助我吗?

云功能:

 const functions = require('firebase-functions');
 const Firestore = require('@google-cloud/firestore');
 const firestore = new Firestore();

 exports.onUserStatusChanged = functions.database
  .ref('/status/{userId}') // Reference to the Firebase RealTime database key
  .onUpdate((event, context) => {

    const usersRef = firestore.collection('/users'); // Create a reference to 
    the Firestore Collection

    return event.before.ref.once('value')
      .then(statusSnapshot => snapShot.val()) // Get latest value from  the Firebase Realtime database
      .then(status => {
        // check if the value is 'offline'
        if (status === 'offline') {
          // Set the Firestore's document's online value to false
          usersRef
            .doc(event.params.userId)
            .set({
              online: false
            }, {
              merge: true
            });
        }
        return
      })
  });

3 个答案:

答案 0 :(得分:3)

Firestore 官方文档 (Build presence in Cloud Firestore) 中有一个更新的教程,解释了如何设置 Firestore、实时数据库和 Cloud Functions。

答案 1 :(得分:0)

我将发布完整功能的代码,以帮助那些像我一样坚持使用它的人。

const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp(functions.config().firebase);

const firestore = functions.firestore;

exports.onUserStatusChange = functions.database
    .ref('/status/{userId}')
    .onUpdate((event, context) => {

        var db = admin.firestore();
        var fieldValue = require("firebase-admin").firestore.FieldValue;

        const usersRef = db.collection("users");
        var snapShot = event.after;

        return event.after.ref.once('value')
            .then(statusSnap => snapShot.val())
            .then(status => {
                if (status === 'offline'){
                    usersRef
                        .doc(context.params.userId)
                        .set({
                            online: false
                        }, {merge: true});

                }
                return null;
            })
});

答案 2 :(得分:0)

要了解用户的存在,我们只需要一个事件。 Firebase 函数不是免费的加上部署等。所以对于事件,如果我们使用 Firebase 云消息传递如何?它是免费且无限制的。即使通知被关闭,我们也可以处理消息事件。接下来是我如何让它在 React Native 上工作。

//通用应用代码:

import auth  from '@react-native-firebase/auth';
import database from '@react-native-firebase/database';
import messaging from '@react-native-firebase/messaging';


async requestUserPermission() {
    const authStatus = await messaging().requestPermission();
    const enabled = 
      authStatus === messaging.AuthorizationStatus.AUTHORIZED ||
      authStatus === messaging.AuthorizationStatus.PROVISIONAL;
      
    if (enabled) {
        console.log('Authorization status:', authStatus);
    }
}

updateFCMToken() {
    if (!messaging().isDeviceRegisteredForRemoteMessages)
    messaging().registerDeviceForRemoteMessages()
        .then((value) => {
            messaging().getToken().then( async (fcmToken) => {
            // Update backend (e.g. Firestore) with our token for the user
            });
    });
}

componentDidMount(){
    requestUserPermission();
    updateFCMToken();
    
    //-*-Update Online/Offline in REALTIMEDATABASE-*-*-*-*
    if (auth().currentUser) {
        var userStatusDatabaseRef = database().ref('/users/' + auth().currentUser.uid);
        var isOfflineForDatabase = {
            status: 'offline',
            last_changed: database.ServerValue.TIMESTAMP,
        };
        var isOnlineForDatabase = {
            status: 'online',
            last_changed: database.ServerValue.TIMESTAMP,
        };
        database().ref('.info/connected').on('value', 
        function (snapshot) {
            userStatusDatabaseRef.onDisconnect().set(
                isOfflineForDatabase).then(
                    function () {
                        userStatusDatabaseRef.set(isOnlineForDatabase);
                });
        });
    }
    
    //-*-Register Handle Message-*-*-*-*
    //-*-Here you get uid of user with online/offline status which you triggered using admin apis
    this.unsubscribeMessage = messaging().onMessage(remoteMessage => {
        Alert.alert(re moteMessage.notification.title, 
        remoteMessage.notification.body);
    });
}

//ADMIN APP CODE WHICH IS A SIMPLE NODEJS SERVER:

    //-*-In below code admin app listens when user is online/offline
    var userStatusOnlineRef =  database().ref('/users').orderByChild('status').equalTo('online');
    userStatusOnlineRef.on('value', (snapshot) => {
        //-*-Get the uid and use it to send to relevant users-*-
    });

    var userStatusOnlineRef =  database().ref('/users').orderByChild('status').equalTo('offline');
    userStatusOnlineRef.on('value', (snapshot) => {
        //-*-Get the uid and use it to send to relevant users-*-
    });

FINALLY TRIGGER MULTICAST MESSAGE TO APPLICABLE USERS:

var admin = require('firebase-admin');
const serviceAccount = require("./serviceAvccount.json");

admin.initializeApp({
    credential: admin.credential.cert(serviceAccount),
    databaseURL: "https://***.firebaseio.com"
});

const registrationTokens = [
    '....',
    '....',
];

const message = {
    //-*-Pass uid and online/offline status
    notification: { title: '', body: '', element: '', element: '' },
    tokens: registrationTokens,
};

admin.messaging().sendMulticast(message)
    .then((response) => {
        if (response.successCount > 0)
        console.log(response.successCount + ' messages were sent successfully');

        if (response.failureCount > 0) {
            const failedTokens = [];
            response.responses.forEach((resp, idx) => {
                if (!resp.success) {
                    failedTokens.push(registrationTokens[idx]);
                }
            });
            console.log('List of tokens that caused failures: ' + failedTokens);
        }
    })
    .catch((error) => {
        console.log('Error sending message:', error);
    });