Files
mattermostest/src/main/UserActivityMonitor.ts
Devin Binnie 1b3d0eac8f Migrate app to TypeScript (#1637)
* Initial setup and migrated src/common

* WIP

* WIP

* WIP

* Main module basically finished

* Renderer process migrated

* Added CI step and some fixes

* Fixed remainder of issues and added proper ESLint config

* Fixed a couple issues

* Progress!

* Some more fixes

* Fixed a test

* Fix build step

* PR feedback
2021-06-28 09:51:23 -04:00

141 lines
4.5 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import {EventEmitter} from 'events';
import electron from 'electron';
import log from 'electron-log';
const {app} = electron;
/**
* Monitors system idle time, listens for system events and fires status updates as needed
*/
export default class UserActivityMonitor extends EventEmitter {
isActive: boolean;
idleTime: number;
lastSetActive?: number;
systemIdleTimeIntervalID: number;
config: {
updateFrequencyMs: number;
inactiveThresholdMs: number;
statusUpdateThresholdMs: number;
};
constructor() {
super();
this.isActive = true;
this.idleTime = 0;
this.systemIdleTimeIntervalID = -1;
this.config = {
updateFrequencyMs: 1 * 1000, // eslint-disable-line no-magic-numbers
inactiveThresholdMs: 60 * 1000, // eslint-disable-line no-magic-numbers
statusUpdateThresholdMs: 60 * 1000, // eslint-disable-line no-magic-numbers
};
}
get userIsActive() {
return this.isActive;
}
get userIdleTime() {
return this.idleTime;
}
/**
* Begin monitoring system events and idle time at defined frequency
*
* @param {Object} config - overide internal configuration defaults
* @param {number} config.updateFrequencyMs - internal update clock frequency for monitoring idleTime
* @param {number} config.inactiveThresholdMs - the number of milliseconds that idleTime needs to reach to internally be considered inactive
* @param {number} config.statusUpdateThresholdMs - minimum amount of time before sending a new status update
* @emits {error} emitted when method is called before the app is ready
* @emits {error} emitted when this method has previously been called but not subsequently stopped
*/
startMonitoring(config = {}) {
if (!app.isReady()) {
this.emit('error', new Error('UserActivityMonitor.startMonitoring can only be called after app is ready'));
return;
}
if (this.systemIdleTimeIntervalID >= 0) {
this.emit('error', new Error('User activity monitoring is already in progress'));
return;
}
this.config = Object.assign({}, this.config, config);
// TODO: Node typings don't map Timeout to number, but then clearInterval requires a number?
this.systemIdleTimeIntervalID = setInterval(() => {
try {
this.updateIdleTime(electron.powerMonitor.getSystemIdleTime());
} catch (err) {
log.error('Error getting system idle time:', err);
}
}, this.config.updateFrequencyMs) as unknown as number;
}
/**
* Stop monitoring system events and idle time
*/
stopMonitoring() {
clearInterval(this.systemIdleTimeIntervalID);
}
/**
* Updates internal idle time and sets internal user activity state
*
* @param {integer} idleTime
* @private
*/
updateIdleTime(idleTime: number) {
this.idleTime = idleTime;
if (idleTime * 1000 > this.config.inactiveThresholdMs) { // eslint-disable-line no-magic-numbers
this.setActivityState(false);
} else {
this.setActivityState(true);
}
}
/**
* Updates user active state and conditionally triggers a status update
*
* @param {boolean} isActive
* @param {boolean} isSystemEvent indicates whether the update was triggered by a system event (log in/out, screesaver on/off etc)
* @private
*/
setActivityState(isActive = false, isSystemEvent = false) {
this.isActive = isActive;
if (isSystemEvent) {
this.sendStatusUpdate(true);
return;
}
const now = Date.now();
if (isActive && (this.lastSetActive == null || now - this.lastSetActive >= this.config.statusUpdateThresholdMs)) {
this.sendStatusUpdate(false);
this.lastSetActive = now;
} else if (!isActive) {
delete this.lastSetActive;
}
}
/**
* Sends an update with user activity status and current system idle time
*
* @emits {status} emitted at regular, definable intervals providing an update on user active status and idle time
* @private
*/
sendStatusUpdate(isSystemEvent = false) {
this.emit('status', {
userIsActive: this.isActive,
idleTime: this.idleTime,
isSystemEvent,
});
}
}