DEV: Allow PresenceChannel to specify custom activity thresholds (#15217)
This allows consumers to vary the parameters on a per-channel basis. e.g. if you wanted a channel to consider someone 'away' after 10 minutes, and another channel to consider someone 'away' after 1 minute, that is now possible.
This commit is contained in:
parent
6cae6aadf4
commit
f3d480dacb
|
@ -19,6 +19,7 @@ import userPresent, {
|
||||||
onPresenceChange,
|
onPresenceChange,
|
||||||
removeOnPresenceChange,
|
removeOnPresenceChange,
|
||||||
} from "discourse/lib/user-presence";
|
} from "discourse/lib/user-presence";
|
||||||
|
import { bind } from "discourse-common/utils/decorators";
|
||||||
|
|
||||||
const PRESENCE_INTERVAL_S = 30;
|
const PRESENCE_INTERVAL_S = 30;
|
||||||
const PRESENCE_DEBOUNCE_MS = isTesting() ? 0 : 500;
|
const PRESENCE_DEBOUNCE_MS = isTesting() ? 0 : 500;
|
||||||
|
@ -26,7 +27,7 @@ const PRESENCE_THROTTLE_MS = isTesting() ? 0 : 1000;
|
||||||
|
|
||||||
const PRESENCE_GET_RETRY_MS = 5000;
|
const PRESENCE_GET_RETRY_MS = 5000;
|
||||||
|
|
||||||
const USER_PRESENCE_ARGS = {
|
const DEFAULT_ACTIVE_OPTIONS = {
|
||||||
userUnseenTime: 60000,
|
userUnseenTime: 60000,
|
||||||
browserHiddenTime: 10000,
|
browserHiddenTime: 10000,
|
||||||
};
|
};
|
||||||
|
@ -63,8 +64,19 @@ class PresenceChannel extends EmberObject {
|
||||||
// By default, the user will temporarily 'leave' the channel when
|
// By default, the user will temporarily 'leave' the channel when
|
||||||
// the current tab is in the background, or has no interaction for more than 60 seconds.
|
// the current tab is in the background, or has no interaction for more than 60 seconds.
|
||||||
// To override this behaviour, set onlyWhileActive: false
|
// To override this behaviour, set onlyWhileActive: false
|
||||||
async enter({ onlyWhileActive = true } = {}) {
|
// To specify custom thresholds, set `activeOptions`. See `lib/user-presence.js` for options.
|
||||||
this.setProperties({ onlyWhileActive });
|
async enter({ onlyWhileActive = true, activeOptions = null } = {}) {
|
||||||
|
if (onlyWhileActive && activeOptions) {
|
||||||
|
for (const key in DEFAULT_ACTIVE_OPTIONS) {
|
||||||
|
if (activeOptions[key] < DEFAULT_ACTIVE_OPTIONS[key]) {
|
||||||
|
throw `${key} cannot be less than ${DEFAULT_ACTIVE_OPTIONS[key]} (given ${activeOptions[key]})`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (onlyWhileActive && !activeOptions) {
|
||||||
|
activeOptions = DEFAULT_ACTIVE_OPTIONS;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.setProperties({ activeOptions });
|
||||||
await this.presenceService._enter(this);
|
await this.presenceService._enter(this);
|
||||||
this.set("present", true);
|
this.set("present", true);
|
||||||
}
|
}
|
||||||
|
@ -241,13 +253,10 @@ export default class PresenceService extends Service {
|
||||||
this._initialDataRequests = new Map();
|
this._initialDataRequests = new Map();
|
||||||
|
|
||||||
if (this.currentUser) {
|
if (this.currentUser) {
|
||||||
this._beforeUnloadCallback = () => this._beaconLeaveAll();
|
window.addEventListener("beforeunload", this._beaconLeaveAll);
|
||||||
window.addEventListener("beforeunload", this._beforeUnloadCallback);
|
|
||||||
|
|
||||||
this._presenceChangeCallback = () => this._throttledUpdateServer();
|
|
||||||
onPresenceChange({
|
onPresenceChange({
|
||||||
...USER_PRESENCE_ARGS,
|
...DEFAULT_ACTIVE_OPTIONS,
|
||||||
callback: this._presenceChangeCallback,
|
callback: this._throttledUpdateServer,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -258,8 +267,8 @@ export default class PresenceService extends Service {
|
||||||
|
|
||||||
willDestroy() {
|
willDestroy() {
|
||||||
super.willDestroy(...arguments);
|
super.willDestroy(...arguments);
|
||||||
window.removeEventListener("beforeunload", this._beforeUnloadCallback);
|
window.removeEventListener("beforeunload", this._beaconLeaveAll);
|
||||||
removeOnPresenceChange(this._presenceChangeCallback);
|
removeOnPresenceChange(this._throttledUpdateServer);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get a PresenceChannel object representing a single channel
|
// Get a PresenceChannel object representing a single channel
|
||||||
|
@ -440,6 +449,7 @@ export default class PresenceService extends Service {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bind
|
||||||
_beaconLeaveAll() {
|
_beaconLeaveAll() {
|
||||||
if (isTesting()) {
|
if (isTesting()) {
|
||||||
return;
|
return;
|
||||||
|
@ -490,15 +500,15 @@ export default class PresenceService extends Service {
|
||||||
.filter((e) => e.type === "leave")
|
.filter((e) => e.type === "leave")
|
||||||
.map((e) => e.channel);
|
.map((e) => e.channel);
|
||||||
|
|
||||||
const userIsPresent = userPresent(USER_PRESENCE_ARGS);
|
|
||||||
for (const [channelName, proxies] of this._presentProxies) {
|
for (const [channelName, proxies] of this._presentProxies) {
|
||||||
if (
|
if (
|
||||||
!userIsPresent &&
|
Array.from(proxies).some((p) => {
|
||||||
Array.from(proxies).every((p) => p.onlyWhileActive)
|
return !p.activeOptions || userPresent(p.activeOptions);
|
||||||
|
})
|
||||||
) {
|
) {
|
||||||
channelsToLeave.push(channelName);
|
|
||||||
} else {
|
|
||||||
presentChannels.push(channelName);
|
presentChannels.push(channelName);
|
||||||
|
} else {
|
||||||
|
channelsToLeave.push(channelName);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -551,6 +561,7 @@ export default class PresenceService extends Service {
|
||||||
// in a sequence of calls. We want both. We want the first event, to make
|
// in a sequence of calls. We want both. We want the first event, to make
|
||||||
// things very responsive. Then if things are happening too frequently, we
|
// things very responsive. Then if things are happening too frequently, we
|
||||||
// drop back to the last event via the regular throttle function.
|
// drop back to the last event via the regular throttle function.
|
||||||
|
@bind
|
||||||
_throttledUpdateServer() {
|
_throttledUpdateServer() {
|
||||||
if (
|
if (
|
||||||
!this._lastUpdate ||
|
!this._lastUpdate ||
|
||||||
|
|
Loading…
Reference in New Issue