feat(electron): further improve on idle handling 2

This commit is contained in:
Johannes Millan 2025-10-15 15:27:27 +02:00
parent e96e205de0
commit 3fc7c134f9
2 changed files with 41 additions and 62 deletions

View file

@ -74,76 +74,47 @@ export class IdleTimeHandler {
async getIdleTime(): Promise<number> {
const methodUsed = await this._ensureWorkingMethod();
let idleTime: number;
switch (methodUsed) {
case 'powerMonitor': {
case 'powerMonitor':
try {
idleTime = powerMonitor.getSystemIdleTime() * 1000;
log.debug(`powerMonitor idle time: ${idleTime}ms`);
return powerMonitor.getSystemIdleTime() * 1000;
} catch (error) {
this._logError('powerMonitor failed', error);
throw error;
return 0;
}
break;
}
case 'gnomeDBus': {
case 'gnomeDBus':
try {
const result = await this._getGnomeIdleTime();
if (result === null) {
throw new Error('gnomeDBus returned null');
}
idleTime = result;
log.debug(`gnomeDBus idle time: ${idleTime}ms`);
return result ?? 0;
} catch (error) {
this._logError('GNOME DBus error', error);
throw error;
return 0;
}
break;
}
case 'xprintidle': {
case 'xprintidle':
try {
const result = await this._getXprintidleTime();
if (result === null) {
throw new Error('xprintidle returned null');
}
idleTime = result;
log.debug(`xprintidle idle time: ${idleTime}ms`);
return result ?? 0;
} catch (error) {
this._logError('xprintidle error', error);
throw error;
return 0;
}
break;
}
case 'loginctl': {
case 'loginctl':
try {
const result = await this._getLoginctlIdleTime();
if (result === null) {
throw new Error('loginctl returned null');
}
idleTime = result;
log.debug(`loginctl idle time: ${idleTime}ms`);
return result ?? 0;
} catch (error) {
this._logError('loginctl error', error);
throw error;
return 0;
}
break;
}
case 'none':
default: {
const error = new Error('No working idle detection method available');
this._logError('idle detection unavailable', error);
throw error;
}
default:
this._logError('No working idle detection method available', undefined);
return 0;
}
log.info(`Idle detection result: ${idleTime}ms (method: ${methodUsed})`);
return idleTime;
}
private async _initializeWorkingMethod(): Promise<IdleDetectionMethod> {

View file

@ -182,27 +182,27 @@ export const startApp = (): void => {
// causing timeouts and subsequent 0ms readings, which looks like “only one
// idle event was ever sent”. This ensures at most one check runs at a time.
let isCheckingIdle = false;
const sendIdleMsgIfOverMin = (idleTime: number): void => {
const sendIdleMsgIfOverMin = (
idleTime: number,
): { sent: boolean; reason?: string } => {
// sometimes when starting a second instance we get here although we don't want to
if (!mainWin) {
info(
'special case occurred when trackTimeFn is called even though, this is a second instance of the app',
);
return;
return { sent: false, reason: 'no-window' };
}
// don't update if the user is about to close
if (!appIN.isQuiting && idleTime > CONFIG.MIN_IDLE_TIME) {
log(
`✅ Sending idle time to frontend: ${idleTime}ms (threshold: ${CONFIG.MIN_IDLE_TIME}ms, method: ${idleTimeHandler.currentMethod})`,
);
mainWin.webContents.send(IPC.IDLE_TIME, idleTime);
} else {
log(
// eslint-disable-next-line max-len
`❌ NOT sending idle time: ${idleTime}ms (threshold: ${CONFIG.MIN_IDLE_TIME}ms, isQuiting: ${appIN.isQuiting}, method: ${idleTimeHandler.currentMethod})`,
);
if (appIN.isQuiting) {
return { sent: false, reason: 'quitting' };
}
if (idleTime <= CONFIG.MIN_IDLE_TIME) {
return { sent: false, reason: 'below-threshold' };
}
mainWin.webContents.send(IPC.IDLE_TIME, idleTime);
return { sent: true };
};
// --------IDLE HANDLING---------
@ -217,16 +217,24 @@ export const startApp = (): void => {
return;
}
isCheckingIdle = true;
const startTime = Date.now();
try {
const startTime = Date.now();
const idleTime = await idleTimeHandler.getIdleTime();
const checkDuration = Date.now() - startTime;
log(
`🔍 Idle check completed in ${checkDuration}ms: ${idleTime}ms (method: ${idleTimeHandler.currentMethod})`,
);
consecutiveFailures = 0;
sendIdleMsgIfOverMin(idleTime);
const sendResult = sendIdleMsgIfOverMin(idleTime);
const actionSummary = sendResult.sent
? 'sent'
: `skipped:${sendResult.reason ?? 'unknown'}`;
const logParts = [
`idle=${idleTime}ms`,
`method=${idleTimeHandler.currentMethod}`,
`duration=${checkDuration}ms`,
`threshold=${CONFIG.MIN_IDLE_TIME}ms`,
`action=${actionSummary}`,
];
log(`🕘 Idle check (${logParts.join(', ')})`);
} catch (error) {
consecutiveFailures += 1;
log('💥 Error getting idle time, falling back to powerMonitor:', error);