Use Timer & new UserActivity api in Presence.

The only behaviour that should have changed here is that
presence is also set to online when switching back to the
tab/window.

Presence is not set to unavailable when coming back to the window/tab,
as that might be a bit invasive, but only when timing out.
pull/21833/head
Bruno Windels 2018-12-11 16:16:00 +01:00
parent 6a248c2e72
commit 7f6d581377
1 changed files with 37 additions and 47 deletions

View File

@ -17,21 +17,33 @@ limitations under the License.
const MatrixClientPeg = require("./MatrixClientPeg"); const MatrixClientPeg = require("./MatrixClientPeg");
const dis = require("./dispatcher"); const dis = require("./dispatcher");
import Timer from './utils/Timer';
// Time in ms after that a user is considered as unavailable/away // Time in ms after that a user is considered as unavailable/away
const UNAVAILABLE_TIME_MS = 3 * 60 * 1000; // 3 mins const UNAVAILABLE_TIME_MS = 3 * 60 * 1000; // 3 mins
const PRESENCE_STATES = ["online", "offline", "unavailable"]; const PRESENCE_STATES = ["online", "offline", "unavailable"];
class Presence { class Presence {
constructor() {
this._activitySignal = null;
this._unavailableTimer = null;
this._onAction = this._onAction.bind(this);
this._dispatcherRef = null;
}
/** /**
* Start listening the user activity to evaluate his presence state. * Start listening the user activity to evaluate his presence state.
* Any state change will be sent to the Home Server. * Any state change will be sent to the Home Server.
*/ */
start() { async start() {
this.running = true; this._unavailableTimer = new Timer(UNAVAILABLE_TIME_MS);
if (undefined === this.state) { // the user_activity_start action starts the timer
this._resetTimer(); this._dispatcherRef = dis.register(this._onAction);
this.dispatcherRef = dis.register(this._onAction.bind(this)); while (this._unavailableTimer) {
try {
await this._unavailableTimer.finished();
this.setState("unavailable");
} catch(e) { /* aborted, stop got called */ }
} }
} }
@ -39,13 +51,14 @@ class Presence {
* Stop tracking user activity * Stop tracking user activity
*/ */
stop() { stop() {
this.running = false; if (this._dispatcherRef) {
if (this.timer) { dis.unregister(this._dispatcherRef);
clearInterval(this.timer); this._dispatcherRef = null;
this.timer = undefined; }
dis.unregister(this.dispatcherRef); if (this._unavailableTimer) {
this._unavailableTimer.abort();
this._unavailableTimer = null;
} }
this.state = undefined;
} }
/** /**
@ -56,21 +69,26 @@ class Presence {
return this.state; return this.state;
} }
_onAction(payload) {
if (payload.action === 'user_activity_start') {
this.setState("online");
this._unavailableTimer.restart();
}
}
/** /**
* Set the presence state. * Set the presence state.
* If the state has changed, the Home Server will be notified. * If the state has changed, the Home Server will be notified.
* @param {string} newState the new presence state (see PRESENCE enum) * @param {string} newState the new presence state (see PRESENCE enum)
*/ */
setState(newState) { async setState(newState) {
console.log("setting Presence state!!", newState);
if (newState === this.state) { if (newState === this.state) {
return; return;
} }
if (PRESENCE_STATES.indexOf(newState) === -1) { if (PRESENCE_STATES.indexOf(newState) === -1) {
throw new Error("Bad presence state: " + newState); throw new Error("Bad presence state: " + newState);
} }
if (!this.running) {
return;
}
const old_state = this.state; const old_state = this.state;
this.state = newState; this.state = newState;
@ -78,42 +96,14 @@ class Presence {
return; // don't try to set presence when a guest; it won't work. return; // don't try to set presence when a guest; it won't work.
} }
const self = this; try {
MatrixClientPeg.get().setPresence(this.state).done(function() { await MatrixClientPeg.get().setPresence(this.state);
console.log("Presence: %s", newState); console.log("Presence: %s", newState);
}, function(err) { } catch(err) {
console.error("Failed to set presence: %s", err); console.error("Failed to set presence: %s", err);
self.state = old_state; this.state = old_state;
});
}
/**
* Callback called when the user made no action on the page for UNAVAILABLE_TIME ms.
* @private
*/
_onUnavailableTimerFire() {
this.setState("unavailable");
}
_onAction(payload) {
if (payload.action === "user_activity") {
this._resetTimer();
} }
} }
/**
* Callback called when the user made an action on the page
* @private
*/
_resetTimer() {
const self = this;
this.setState("online");
// Re-arm the timer
clearTimeout(this.timer);
this.timer = setTimeout(function() {
self._onUnavailableTimerFire();
}, UNAVAILABLE_TIME_MS);
}
} }
module.exports = new Presence(); module.exports = new Presence();