[IMPROVE] Change user presence events to Meteor Streams (#14488)
parent
fbb4ac4f1f
commit
40cab8f30f
@ -0,0 +1,10 @@ |
||||
import { Base } from './_Base'; |
||||
|
||||
class FullUser extends Base { |
||||
constructor() { |
||||
super(); |
||||
this._initModel('full_user'); |
||||
} |
||||
} |
||||
|
||||
export default new FullUser(); |
@ -0,0 +1,28 @@ |
||||
export const getDefaultUserFields = () => ({ |
||||
name: 1, |
||||
username: 1, |
||||
emails: 1, |
||||
status: 1, |
||||
statusDefault: 1, |
||||
statusConnection: 1, |
||||
avatarOrigin: 1, |
||||
utcOffset: 1, |
||||
language: 1, |
||||
settings: 1, |
||||
enableAutoAway: 1, |
||||
idleTimeLimit: 1, |
||||
roles: 1, |
||||
active: 1, |
||||
defaultRoom: 1, |
||||
customFields: 1, |
||||
requirePasswordChange: 1, |
||||
requirePasswordChangeReason: 1, |
||||
'services.github': 1, |
||||
'services.gitlab': 1, |
||||
'services.tokenpass': 1, |
||||
'services.blockstack': 1, |
||||
'services.password.bcrypt': 1, |
||||
'services.totp.enabled': 1, |
||||
statusLivechat: 1, |
||||
banners: 1, |
||||
}); |
@ -1,2 +1,3 @@ |
||||
import '../../message-read-receipt/client'; |
||||
import '../../personal-access-tokens/client'; |
||||
import './listenActiveUsers'; |
||||
|
@ -0,0 +1,107 @@ |
||||
import { Meteor } from 'meteor/meteor'; |
||||
import { Tracker } from 'meteor/tracker'; |
||||
import { debounce } from 'underscore'; |
||||
|
||||
import { Notifications } from '../../../app/notifications/client'; |
||||
import { APIClient } from '../../../app/utils/client'; |
||||
|
||||
// mirror of object in /imports/users-presence/server/activeUsers.js - keep updated
|
||||
const STATUS_MAP = [ |
||||
'offline', |
||||
'online', |
||||
'away', |
||||
'busy', |
||||
]; |
||||
|
||||
const saveUser = (user, force = false) => { |
||||
// do not update my own user, my user's status will come from a subscription
|
||||
if (user._id === Meteor.userId()) { |
||||
return; |
||||
} |
||||
if (force) { |
||||
return Meteor.users.upsert({ _id: user._id }, { |
||||
$set: { |
||||
username: user.username, |
||||
// name: user.name,
|
||||
// utcOffset: user.utcOffset,
|
||||
status: user.status, |
||||
}, |
||||
}); |
||||
} |
||||
|
||||
const found = Meteor.users.findOne(user._id, { fields: { _id: 1 } }); |
||||
if (found) { |
||||
return; |
||||
} |
||||
|
||||
Meteor.users.insert(user); |
||||
}; |
||||
|
||||
let lastStatusChange = null; |
||||
let retry = 0; |
||||
const getUsersPresence = debounce(async (isConnected) => { |
||||
try { |
||||
const params = {}; |
||||
|
||||
if (lastStatusChange) { |
||||
params.from = lastStatusChange.toISOString(); |
||||
} |
||||
|
||||
const { |
||||
users, |
||||
full, |
||||
} = await APIClient.v1.get('users.presence', params); |
||||
|
||||
// if is reconnecting, set everyone else to offline
|
||||
if (full && isConnected) { |
||||
Meteor.users.update({ |
||||
_id: { $ne: Meteor.userId() }, |
||||
}, { |
||||
$set: { |
||||
status: 'offline', |
||||
}, |
||||
}, { multi: true }); |
||||
} |
||||
|
||||
users.forEach((user) => saveUser(user, full)); |
||||
|
||||
lastStatusChange = new Date(); |
||||
} catch (e) { |
||||
setTimeout(() => getUsersPresence(isConnected), retry++ * 2000); |
||||
} |
||||
}, 1000); |
||||
|
||||
let wasConnected = false; |
||||
Tracker.autorun(() => { |
||||
if (!Meteor.userId() || !Meteor.status().connected) { |
||||
return; |
||||
} |
||||
|
||||
lastStatusChange = null; |
||||
|
||||
getUsersPresence(wasConnected); |
||||
|
||||
wasConnected = true; |
||||
}); |
||||
|
||||
Meteor.startup(function() { |
||||
Notifications.onLogged('user-status', ([_id, username, status]) => { |
||||
// only set after first request completed
|
||||
if (lastStatusChange) { |
||||
lastStatusChange = new Date(); |
||||
} |
||||
|
||||
saveUser({ _id, username, status: STATUS_MAP[status] }, true); |
||||
}); |
||||
|
||||
Notifications.onLogged('Users:NameChanged', ({ _id, username }) => { |
||||
if (!username) { |
||||
return; |
||||
} |
||||
Meteor.users.upsert({ _id }, { |
||||
$set: { |
||||
username, |
||||
}, |
||||
}); |
||||
}); |
||||
}); |
@ -1,2 +1,3 @@ |
||||
import '../../message-read-receipt/server'; |
||||
import '../../personal-access-tokens/server'; |
||||
import '../../users-presence/server'; |
||||
|
@ -0,0 +1,26 @@ |
||||
import { UserPresenceEvents } from 'meteor/konecty:user-presence'; |
||||
|
||||
import { Notifications } from '../../../app/notifications/server'; |
||||
|
||||
// mirror of object in /imports/startup/client/listenActiveUsers.js - keep updated
|
||||
const STATUS_MAP = { |
||||
offline: 0, |
||||
online: 1, |
||||
away: 2, |
||||
busy: 3, |
||||
}; |
||||
|
||||
UserPresenceEvents.on('setUserStatus', (user, status/* , statusConnection*/) => { |
||||
const { |
||||
_id, |
||||
username, |
||||
} = user; |
||||
|
||||
// since this callback can be called by only one instance in the cluster
|
||||
// we need to broadcast the change to all instances
|
||||
Notifications.notifyLogged('user-status', [ |
||||
_id, |
||||
username, |
||||
STATUS_MAP[status], |
||||
]); |
||||
}); |
@ -0,0 +1 @@ |
||||
import './activeUsers'; |
@ -1,39 +1,22 @@ |
||||
import { Meteor } from 'meteor/meteor'; |
||||
|
||||
import { Users } from '../../app/models'; |
||||
import { getDefaultUserFields } from '../../app/utils/server/functions/getDefaultUserFields'; |
||||
|
||||
Meteor.publish('userData', function() { |
||||
if (!this.userId) { |
||||
return this.ready(); |
||||
} |
||||
|
||||
return Users.find(this.userId, { |
||||
fields: { |
||||
name: 1, |
||||
username: 1, |
||||
status: 1, |
||||
statusDefault: 1, |
||||
statusConnection: 1, |
||||
avatarOrigin: 1, |
||||
utcOffset: 1, |
||||
language: 1, |
||||
settings: 1, |
||||
enableAutoAway: 1, |
||||
idleTimeLimit: 1, |
||||
roles: 1, |
||||
active: 1, |
||||
defaultRoom: 1, |
||||
customFields: 1, |
||||
'services.github': 1, |
||||
'services.gitlab': 1, |
||||
'services.tokenpass': 1, |
||||
'services.blockstack': 1, |
||||
requirePasswordChange: 1, |
||||
requirePasswordChangeReason: 1, |
||||
'services.password.bcrypt': 1, |
||||
'services.totp.enabled': 1, |
||||
statusLivechat: 1, |
||||
banners: 1, |
||||
}, |
||||
const handle = Users.find({ _id: this.userId }, { |
||||
fields: getDefaultUserFields(), |
||||
}).observeChanges({ |
||||
added: (_id, record) => this.added('own_user', _id, record), |
||||
changed: (_id, record) => this.changed('own_user', _id, record), |
||||
removed: (_id, record) => this.removed('own_user', _id, record), |
||||
}); |
||||
|
||||
this.ready(); |
||||
|
||||
this.onStop(() => handle.stop()); |
||||
}); |
||||
|
Loading…
Reference in new issue