最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - Handle users’ online and offline status in Firebase - Stack Overflow

programmeradmin0浏览0评论

I want to handle the online and offline status in my webapp. So that users can see who is online and who not.

I found this awesome tutorial which explain it very good, but I am stuck.

I thing there is a problem with the cloud-functions, because I got an error there.

Furthermore the tutorial is from Dec 15, 2017 and I know that the cloud-functions got updated but I don't know how to update the code.

Link to docs:

Can someone take a look on the tutorial and can help me maybe?

Cloud function:

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

I want to handle the online and offline status in my webapp. So that users can see who is online and who not.

I found this awesome tutorial which explain it very good, but I am stuck.

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

I thing there is a problem with the cloud-functions, because I got an error there.

Furthermore the tutorial is from Dec 15, 2017 and I know that the cloud-functions got updated but I don't know how to update the code.

Link to docs: https://firebase.google.com/docs/functions/beta-v1-diff

Can someone take a look on the tutorial and can help me maybe?

Cloud function:

 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
      })
  });
Share Improve this question edited Aug 9, 2018 at 13:35 Frank van Puffelen 599k85 gold badges888 silver badges858 bronze badges asked Aug 9, 2018 at 13:23 LukasLukas 6032 gold badges9 silver badges19 bronze badges
Add a comment  | 

3 Answers 3

Reset to default 7

There is an updated tutorial in the official Firestore documentation (Build presence in Cloud Firestore) that explains how to set up Firestore, Realtime Database, and Cloud Functions.

I'm just going to post the fully functional code to help others who stuck with it like me.

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

To know the user presence, all we need is an event. Firebase Functions aren't free plus deploy etc. So for event, how if we use Firebase Cloud Messaging? it's free and unlimited. We can handle messaging events even if notificatiions are turned off. What follows is how I have it to work on React Native.

//GENERAL APP CODE:

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);
    });
发布评论

评论列表(0)

  1. 暂无评论