Files
mattermostest/src/main/UserActivityMonitor.ts
Devin Binnie 245215c678 [MM-51873] Create central logging module for adding prefixes to differentiate logs between modules (#2652)
* Create central logging module for adding prefixes to differentiate logs between modules

* Turn logger into class

* Merge'd

* Rework to use class more intelligently

* Fix modalView

* Fix webContentEvents

* Update src/main/app/intercom.ts

Co-authored-by: Daniel Espino García <larkox@gmail.com>

* Shorten prefixes on object creation

---------

Co-authored-by: Daniel Espino García <larkox@gmail.com>
2023-04-05 12:09:56 -04:00

145 lines
4.6 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 {app, powerMonitor} from 'electron';
import {Logger} from 'common/log';
const log = new Logger('UserActivityMonitor');
/**
* Monitors system idle time, listens for system events and fires status updates as needed
*/
export 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);
// Node typings don't map Timeout to number, but then clearInterval requires a number?
this.systemIdleTimeIntervalID = setInterval(() => {
try {
this.updateIdleTime(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,
});
}
}
const userActivityMonitor = new UserActivityMonitor();
export default userActivityMonitor;