🐛 fix: shutdown countdown ignores mode change, timer leaks

Critical: handleShutdownAfterFinish() captured shutdown mode in a
closure at scheduling time — changing mode during countdown was ignored,
causing unexpected system shutdown/restart/sleep.

Now reads shutdownMode at execution time, clears timer when mode
changes to 'nothing', clears orphaned timers before creating new ones,
and adds error handling on exec() calls.

Also: guard stats timer against double-start in upload-manager.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Administrator 2026-03-21 13:19:07 +01:00
parent af48a485e8
commit 27905d66de
2 changed files with 18 additions and 8 deletions

View File

@ -550,6 +550,7 @@ class UploadManager extends EventEmitter {
} }
_startStatsTimer() { _startStatsTimer() {
if (this.statsInterval) clearInterval(this.statsInterval);
this.statsInterval = setInterval(() => { this.statsInterval = setInterval(() => {
let globalSpeedKbs = 0; let globalSpeedKbs = 0;
let activeCount = 0; let activeCount = 0;

25
main.js
View File

@ -1258,6 +1258,11 @@ let shutdownTimer = null;
ipcMain.handle('set-shutdown-after-finish', (_event, mode) => { ipcMain.handle('set-shutdown-after-finish', (_event, mode) => {
shutdownMode = mode || 'nothing'; shutdownMode = mode || 'nothing';
// Cancel active countdown if mode changed to 'nothing'
if (shutdownMode === 'nothing' && shutdownTimer) {
clearTimeout(shutdownTimer);
shutdownTimer = null;
}
return true; return true;
}); });
@ -1278,21 +1283,25 @@ function handleShutdownAfterFinish() {
if (shutdownMode === 'nothing') return; if (shutdownMode === 'nothing') return;
const { exec } = require('child_process'); const { exec } = require('child_process');
const mode = shutdownMode;
// Notify renderer // Notify renderer
if (mainWindow && !mainWindow.isDestroyed()) { if (mainWindow && !mainWindow.isDestroyed()) {
mainWindow.webContents.send('shutdown-countdown', { mode, seconds: 60 }); mainWindow.webContents.send('shutdown-countdown', { mode: shutdownMode, seconds: 60 });
} }
// Clear any previous countdown to prevent orphaned timers
if (shutdownTimer) clearTimeout(shutdownTimer);
shutdownTimer = setTimeout(() => { shutdownTimer = setTimeout(() => {
if (mode === 'shutdown') { // Read current mode at execution time (not captured at scheduling time)
exec('shutdown /s /t 0'); if (shutdownMode === 'shutdown') {
} else if (mode === 'restart') { exec('shutdown /s /t 0', (err) => { if (err) debugLog(`shutdown failed: ${err.message}`); });
exec('shutdown /r /t 0'); } else if (shutdownMode === 'restart') {
} else if (mode === 'sleep') { exec('shutdown /r /t 0', (err) => { if (err) debugLog(`restart failed: ${err.message}`); });
exec('rundll32.exe powrprof.dll,SetSuspendState 0,1,0'); } else if (shutdownMode === 'sleep') {
exec('rundll32.exe powrprof.dll,SetSuspendState 0,1,0', (err) => { if (err) debugLog(`sleep failed: ${err.message}`); });
} }
// else: mode was changed to 'nothing' during countdown — do nothing
}, 60000); }, 60000);
} }