ELECTRON-928 - migrate presence to the Power Monitor API (#530)

This commit is contained in:
VICTOR RAPHAEL BRAGA DE SALES MASCARENHAS 2018-12-20 12:11:06 -02:00 committed by Vishwas Shashidhar
parent 8ca8db65ed
commit 81ac612552
6 changed files with 129 additions and 97 deletions

View File

@ -1,6 +1,6 @@
'use strict';
const systemIdleTime = require('@paulcbetts/system-idle-time');
const electron = require('electron');
const { app } = electron;
const throttle = require('../utils/throttle');
const log = require('../log.js');
const logLevels = require('../enums/logLevels.js');
@ -19,21 +19,33 @@ let maxIdleTime;
let activityWindow;
let intervalId;
let throttleActivity;
/**
* Check if the user is idle
*/
function activityDetection() {
// Get system idle status and idle time from PaulCBetts package
if (systemIdleTime.getIdleTime() < maxIdleTime) {
return { isUserIdle: false, systemIdleTime: systemIdleTime.getIdleTime() };
}
// If idle for more than 4 mins, monitor system idle status every second
if (!intervalId) {
monitorUserActivity();
if (app.isReady()) {
electron.powerMonitor.querySystemIdleTime((time) => {
// sent Idle time in milliseconds
let idleTime = time * 1000 + 1; //ensuring that zero wont be sent
if (idleTime != null && idleTime !== undefined) {
if (idleTime < maxIdleTime) {
let systemActivity = { isUserIdle: false, systemIdleTime: idleTime };
if (systemActivity && !systemActivity.isUserIdle && typeof systemActivity.systemIdleTime === 'number') {
return self.send({ systemIdleTime: systemActivity.systemIdleTime });
}
}
}
// If idle for more than 4 mins, monitor system idle status every second
if (!intervalId) {
self.monitorUserActivity();
}
return null;
})
}
return null;
}
/**
@ -43,12 +55,10 @@ function activityDetection() {
function initiateActivityDetection() {
if (!throttleActivity) {
throttleActivity = throttle(maxIdleTime, sendActivity);
throttleActivity = throttle(maxIdleTime, activityDetection);
setInterval(throttleActivity, maxIdleTime);
}
sendActivity();
self.activityDetection();
}
/**
@ -58,27 +68,24 @@ function monitorUserActivity() {
intervalId = setInterval(monitor, 1000);
function monitor() {
if (systemIdleTime.getIdleTime() < maxIdleTime && typeof getIsOnlineFnc === 'function' && getIsOnlineFnc()) {
// If system is active, send an update to the app bridge and clear the timer
sendActivity();
if (typeof setIsAutoReloadFnc === 'function') {
setIsAutoReloadFnc(false);
}
clearInterval(intervalId);
intervalId = undefined;
if (app.isReady()) {
electron.powerMonitor.querySystemIdleTime((time) => {
// sent Idle time in milliseconds
let idleTime = time * 1000 + 1; //ensuring that zero wont be sent
if (idleTime != null && idleTime !== undefined) {
if (idleTime < maxIdleTime && typeof getIsOnlineFnc === 'function' && getIsOnlineFnc()) {
// If system is active, send an update to the app bridge and clear the timer
self.activityDetection();
if (typeof setIsAutoReloadFnc === 'function') {
setIsAutoReloadFnc(false);
}
clearInterval(intervalId);
intervalId = undefined;
}
}
});
}
}
}
/**
* Send user activity status to the app bridge
* to be updated across all clients
*/
function sendActivity() {
let systemActivity = activityDetection();
if (systemActivity && !systemActivity.isUserIdle && systemActivity.systemIdleTime) {
send({ systemIdleTime: systemActivity.systemIdleTime });
}
}
@ -109,9 +116,11 @@ function setActivityWindow(period, win) {
initiateActivityDetection();
}
module.exports = {
// Exporting this for unit tests
const self = {
send: send,
setActivityWindow: setActivityWindow,
activityDetection: activityDetection,
monitorUserActivity: monitorUserActivity, // Exporting this for unit tests
};
monitorUserActivity: monitorUserActivity,
};
module.exports = self;

View File

@ -1,7 +1,6 @@
'use strict';
const { app } = require('electron');
const systemIdleTime = require('@paulcbetts/system-idle-time');
const electron = require('electron');
const app = electron.app;
const log = require('./log.js');
const logLevels = require('./enums/logLevels.js');
const { getMainWindow, setIsAutoReload, getIsOnline } = require('./windowMgr');
@ -43,47 +42,50 @@ function optimizeMemory() {
const cpuUsagePercentage = preloadMemory.cpuUsage.percentCPUUsage;
const activeNetworkRequest = preloadMemory.activeRequests === 0;
if (cpuUsagePercentage <= cpuUsageThreshold
&& !isInMeeting
&& getIsOnline()
&& canReload
&& systemIdleTime.getIdleTime() > maxIdleTime
&& activeNetworkRequest
) {
getConfigField('memoryRefresh')
.then((enabled) => {
if (enabled) {
const mainWindow = getMainWindow();
if (mainWindow && !mainWindow.isDestroyed()) {
setIsAutoReload(true);
log.send(logLevels.INFO, `Reloading the app to optimize memory usage as
memory consumption is no longer detectable
CPU usage percentage was ${preloadMemory.cpuUsage.percentCPUUsage}
user was in a meeting? ${isInMeeting}
pending network request on the client was ${preloadMemory.activeRequests}
is network online? ${getIsOnline()}`);
mainWindow.reload();
// do not refresh for another 1hrs
canReload = false;
setTimeout(() => {
canReload = true;
}, memoryRefreshThreshold);
electron.powerMonitor.querySystemIdleTime((time) => {
const idleTime = time * 1000;
if (cpuUsagePercentage <= cpuUsageThreshold
&& !isInMeeting
&& getIsOnline()
&& canReload
&& idleTime > maxIdleTime
&& activeNetworkRequest
) {
getConfigField('memoryRefresh')
.then((enabled) => {
if (enabled) {
const mainWindow = getMainWindow();
if (mainWindow && !mainWindow.isDestroyed()) {
setIsAutoReload(true);
log.send(logLevels.INFO, `Reloading the app to optimize memory usage as
memory consumption is no longer detectable
CPU usage percentage was ${preloadMemory.cpuUsage.percentCPUUsage}
user was in a meeting? ${isInMeeting}
pending network request on the client was ${preloadMemory.activeRequests}
is network online? ${getIsOnline()}`);
mainWindow.reload();
// do not refresh for another 1hrs
canReload = false;
setTimeout(() => {
canReload = true;
}, memoryRefreshThreshold);
}
} else {
log.send(logLevels.INFO, `Memory refresh not enabled by the user so Not Reloading the app`);
}
} else {
log.send(logLevels.INFO, `Memory refresh not enabled by the user so Not Reloading the app`);
}
});
} else {
log.send(logLevels.INFO, `Not Reloading the app as
application was refreshed less than a hour ago? ${canReload ? 'no' : 'yes'}
memory consumption is no longer detectable
CPU usage percentage was ${preloadMemory.cpuUsage.percentCPUUsage}
user was in a meeting? ${isInMeeting}
pending network request on the client was ${preloadMemory.activeRequests}
is network online? ${getIsOnline()}`);
}
});
} else {
log.send(logLevels.INFO, `Not Reloading the app as
application was refreshed less than a hour ago? ${canReload ? 'no' : 'yes'}
memory consumption is no longer detectable
CPU usage percentage was ${preloadMemory.cpuUsage.percentCPUUsage}
user was in a meeting? ${isInMeeting}
pending network request on the client was ${preloadMemory.activeRequests}
is network online? ${getIsOnline()}`);
}
});
}
/**

View File

@ -388,7 +388,7 @@ function createAPI() {
// listen for user activity from main process
local.ipcRenderer.on('activity', (event, arg) => {
if (local.activityDetection && arg && arg.systemIdleTime) {
if (local.activityDetection && arg && typeof arg.systemIdleTime === 'number') {
local.activityDetection(arg.systemIdleTime);
}
});

View File

@ -108,7 +108,6 @@
"wdio-selenium-standalone-service": "0.0.10"
},
"dependencies": {
"@paulcbetts/system-idle-time": "1.0.4",
"archiver": "3.0.0",
"async.map": "0.5.2",
"async.mapseries": "0.5.2",

View File

@ -72,7 +72,7 @@ const ipcRenderer = {
module.exports = {
require: jest.fn(),
match: jest.fn(),
app: jest.fn(),
app: app,
ipcMain: ipcMain,
ipcRenderer: ipcRenderer,
remote: jest.fn(),

View File

@ -1,15 +1,15 @@
const electron = require('./__mocks__/electron');
const activityDetection = require('../js/activityDetection');
describe('Tests for Activity Detection', function() {
const originalTimeout = jasmine.DEFAULT_TIMEOUT_INTERVAL;
jasmine.DEFAULT_TIMEOUT_INTERVAL = 60000;
beforeAll(function(done) {
activityDetection.setActivityWindow(900000, electron.ipcRenderer);
done();
});
beforeAll(function(done) {
electron.app.isReady = jest.fn().mockReturnValue(true);
electron.powerMonitor = { querySystemIdleTime: jest.fn() }
done();
});
beforeEach(function() {
jest.clearAllMocks()
@ -20,17 +20,8 @@ describe('Tests for Activity Detection', function() {
done();
});
it('should return null', function() {
activityDetection.setActivityWindow(0, electron.ipcRenderer);
const noData = activityDetection.activityDetection();
expect(noData).toBeNull();
});
it('should send activity event', function() {
const spy = jest.spyOn(activityDetection, 'send');
expect(spy).not.toBeCalled();
activityDetection.send({ systemIdleTime: 120000 });
@ -49,6 +40,14 @@ describe('Tests for Activity Detection', function() {
});
it('should start `activityDetection()`', () => {
const spy = jest.spyOn(activityDetection, 'activityDetection');
expect(spy).not.toBeCalled();
activityDetection.activityDetection();
expect(spy).toBeCalled();
});
it('should not send activity event as data is undefined', function() {
const spy = jest.spyOn(activityDetection, 'send');
@ -59,4 +58,27 @@ describe('Tests for Activity Detection', function() {
});
it('should call `send()` when period was greater than idleTime', () => {
const spy = jest.spyOn(activityDetection, 'send');
expect(spy).not.toBeCalled();
electron.powerMonitor = { querySystemIdleTime: jest.fn().mockImplementationOnce(cb => cb(1)) };
activityDetection.setActivityWindow(900000, electron.ipcRenderer);
expect(spy).toBeCalled();
});
it('should start `activityDetection()` when `setActivityWindow()` was called', () => {
const spy = jest.spyOn(activityDetection, 'activityDetection');
expect(spy).not.toBeCalled();
activityDetection.setActivityWindow(900000, electron.ipcRenderer);
expect(spy).toBeCalled();
});
});