1
+ function rtdb_presence ( ) {
2
+ // [START rtdb_presence]
3
+ // Fetch the current user's ID from Firebase Authentication.
4
+ const uid = firebase . auth ( ) . currentUser . uid ;
5
+
6
+ // Create a reference to this user's specific status node.
7
+ // This is where we will store data about being online/offline.
8
+ const userStatusDatabaseRef = firebase . database ( ) . ref ( `/status/${ uid } ` ) ;
9
+
10
+ // We'll create two constants which we will write to
11
+ // the Realtime database when this device is offline
12
+ // or online.
13
+ const isOfflineForDatabase = {
14
+ state : "offline" ,
15
+ last_changed : firebase . database . ServerValue . TIMESTAMP ,
16
+ } ;
17
+
18
+ const isOnlineForDatabase = {
19
+ state : "online" ,
20
+ last_changed : firebase . database . ServerValue . TIMESTAMP ,
21
+ } ;
22
+
23
+ // Create a reference to the special ".info/connected" path in
24
+ // Realtime Database. This path returns `true` when connected
25
+ // and `false` when disconnected.
26
+ firebase . database ( ) . ref ( ".info/connected" ) . on ( "value" , function ( snapshot ) {
27
+ // If we're not currently connected, don't do anything.
28
+ if ( snapshot . val ( ) == false ) {
29
+ return ;
30
+ } ;
31
+
32
+ // If we are currently connected, then use the 'onDisconnect()'
33
+ // method to add a set which will only trigger once this
34
+ // client has disconnected by closing the app,
35
+ // losing internet, or any other means.
36
+ userStatusDatabaseRef . onDisconnect ( ) . set ( isOfflineForDatabase ) . then ( function ( ) {
37
+ // The promise returned from .onDisconnect().set() will
38
+ // resolve as soon as the server acknowledges the onDisconnect()
39
+ // request, NOT once we've actually disconnected:
40
+ // https://firebase.google.com/docs/reference/js/firebase.database.OnDisconnect
41
+
42
+ // We can now safely set ourselves as "online" knowing that the
43
+ // server will mark us as offline once we lose connection.
44
+ userStatusDatabaseRef . set ( isOnlineForDatabase ) ;
45
+ } ) ;
46
+ } ) ;
47
+ // [END rtdb_presence]
48
+ }
49
+
50
+ function rtdb_and_local_fs_presence ( ) {
51
+ // [START rtdb_and_local_fs_presence]
52
+ // [START_EXCLUDE]
53
+ const uid = firebase . auth ( ) . currentUser . uid ;
54
+ const userStatusDatabaseRef = firebase . database ( ) . ref ( `/status/${ uid } ` ) ;
55
+
56
+ const isOfflineForDatabase = {
57
+ state : "offline" ,
58
+ last_changed : firebase . database . ServerValue . TIMESTAMP ,
59
+ } ;
60
+
61
+ const isOnlineForDatabase = {
62
+ state : "online" ,
63
+ last_changed : firebase . database . ServerValue . TIMESTAMP ,
64
+ } ;
65
+
66
+ // [END_EXCLUDE]
67
+ const userStatusFirestoreRef = firebase . firestore ( ) . doc ( `/status/${ uid } ` ) ;
68
+
69
+ // Firestore uses a different server timestamp value, so we'll
70
+ // create two more constants for Firestore state.
71
+ const isOfflineForFirestore = {
72
+ state : "offline" ,
73
+ last_changed : firebase . firestore . FieldValue . serverTimestamp ( ) ,
74
+ } ;
75
+
76
+ const isOnlineForFirestore = {
77
+ state : "online" ,
78
+ last_changed : firebase . firestore . FieldValue . serverTimestamp ( ) ,
79
+ } ;
80
+
81
+ firebase . database ( ) . ref ( ".info/connected" ) . on ( "value" , function ( snapshot ) {
82
+ if ( snapshot . val ( ) == false ) {
83
+ // Instead of simply returning, we'll also set Firestore's state
84
+ // to "offline". This ensures that our Firestore cache is aware
85
+ // of the switch to "offline."
86
+ userStatusFirestoreRef . set ( isOfflineForFirestore ) ;
87
+ return ;
88
+ } ;
89
+
90
+ userStatusDatabaseRef . onDisconnect ( ) . set ( isOfflineForDatabase ) . then ( function ( ) {
91
+ userStatusDatabaseRef . set ( isOnlineForDatabase ) ;
92
+
93
+ // We'll also add Firestore set here for when we come online.
94
+ userStatusFirestoreRef . set ( isOnlineForFirestore ) ;
95
+ } ) ;
96
+ } ) ;
97
+ // [END rtdb_and_local_fs_presence]
98
+ }
99
+
100
+ function fs_listen ( ) {
101
+ // [START fs_onsnapshot]
102
+ userStatusFirestoreRef . onSnapshot ( function ( doc ) {
103
+ const isOnline = doc . data ( ) . state == "online" ;
104
+ // ... use isOnline
105
+ } ) ;
106
+ // [END fs_onsnapshot]
107
+ }
108
+
109
+ function fs_listen_online ( ) {
110
+ const history = document . querySelector ( "#history" ) ;
111
+ // [START fs_onsnapshot_online]
112
+ firebase . firestore ( ) . collection ( "status" )
113
+ . where ( "state" , "==" , "online" )
114
+ . onSnapshot ( function ( snapshot ) {
115
+ snapshot . docChanges . forEach ( function ( change ) {
116
+ if ( change . type === "added" ) {
117
+ const msg = `User ${ change . doc . id } is online.` ;
118
+ console . log ( msg ) ;
119
+ // [START_EXCLUDE]
120
+ history . innerHTML += msg + "<br />" ;
121
+ // [END_EXCLUDE]
122
+ }
123
+ if ( change . type === "removed" ) {
124
+ const msg = `User ${ change . doc . id } is offline.` ;
125
+ console . log ( msg ) ;
126
+ // [START_EXCLUDE]
127
+ history . innerHTML += msg + "<br />"
128
+ // [END_EXCLUDE]
129
+ }
130
+ } ) ;
131
+ } ) ;
132
+ // [END fs_onsnapshot_online]
133
+ }
134
+
135
+ firebase . auth ( ) . signInAnonymously ( ) . then ( function ( ) {
136
+ rtdb_and_local_fs_presence ( ) ;
137
+ fs_listen_online ( ) ;
138
+ } ) . catch ( function ( err ) {
139
+ console . warn ( err ) ;
140
+ console . warn ( "Please enable Anonymous Authentication in your Firebase project!" ) ;
141
+ } ) ;
0 commit comments