Auto-Updater: Doppelstart verhindern + Download-Status sichtbar
- State-Tracking im Main-Prozess (idle/checking/downloading/ready) - Manueller Check gibt aktuellen Status zurück statt Squirrel-Doppelstart - Auto-Check nur wenn idle (kein Konflikt mit laufendem Download) - Frontend synchronisiert Status beim Mount und Modal-Öffnen - getUpdateStatus IPC für synchrone Status-Abfrage Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
2c6ac0745d
commit
d909909591
3 changed files with 61 additions and 13 deletions
|
|
@ -33,43 +33,75 @@ function setupAutoUpdater() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// State-Tracking: verhindert Doppelstarts und bewahrt Status
|
||||||
|
let updateState = 'idle'; // idle | checking | downloading | ready
|
||||||
|
|
||||||
|
autoUpdater.on('checking-for-update', () => {
|
||||||
|
console.log('[AutoUpdater] Checking for updates...');
|
||||||
|
updateState = 'checking';
|
||||||
|
});
|
||||||
|
|
||||||
autoUpdater.on('update-available', () => {
|
autoUpdater.on('update-available', () => {
|
||||||
console.log('[AutoUpdater] Update available, downloading...');
|
console.log('[AutoUpdater] Update available, downloading...');
|
||||||
|
updateState = 'downloading';
|
||||||
if (mainWindow) mainWindow.webContents.send('update-available');
|
if (mainWindow) mainWindow.webContents.send('update-available');
|
||||||
});
|
});
|
||||||
|
|
||||||
autoUpdater.on('update-downloaded', (_event, releaseNotes, releaseName) => {
|
autoUpdater.on('update-downloaded', (_event, releaseNotes, releaseName) => {
|
||||||
console.log('[AutoUpdater] Update downloaded:', releaseName || 'new version');
|
console.log('[AutoUpdater] Update downloaded:', releaseName || 'new version');
|
||||||
|
updateState = 'ready';
|
||||||
if (mainWindow) mainWindow.webContents.send('update-ready');
|
if (mainWindow) mainWindow.webContents.send('update-ready');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
autoUpdater.on('update-not-available', () => {
|
||||||
|
console.log('[AutoUpdater] App is up to date.');
|
||||||
|
updateState = 'idle';
|
||||||
|
if (mainWindow) mainWindow.webContents.send('update-not-available');
|
||||||
|
});
|
||||||
|
|
||||||
|
autoUpdater.on('error', (err) => {
|
||||||
|
console.error('[AutoUpdater] Error:', err.message);
|
||||||
|
updateState = 'idle';
|
||||||
|
if (mainWindow) mainWindow.webContents.send('update-error', err.message);
|
||||||
|
});
|
||||||
|
|
||||||
// Handle install-update request from renderer
|
// Handle install-update request from renderer
|
||||||
ipcMain.on('install-update', () => {
|
ipcMain.on('install-update', () => {
|
||||||
autoUpdater.quitAndInstall();
|
autoUpdater.quitAndInstall();
|
||||||
});
|
});
|
||||||
|
|
||||||
autoUpdater.on('update-not-available', () => {
|
// Manual check from renderer — gibt aktuellen Status zurück statt Doppelstart
|
||||||
console.log('[AutoUpdater] App is up to date.');
|
|
||||||
if (mainWindow) mainWindow.webContents.send('update-not-available');
|
|
||||||
});
|
|
||||||
|
|
||||||
// Manual check from renderer
|
|
||||||
ipcMain.on('check-for-updates', () => {
|
ipcMain.on('check-for-updates', () => {
|
||||||
|
if (updateState === 'downloading') {
|
||||||
|
if (mainWindow) mainWindow.webContents.send('update-available');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (updateState === 'ready') {
|
||||||
|
if (mainWindow) mainWindow.webContents.send('update-ready');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (updateState === 'checking') {
|
||||||
|
return; // bereits am Prüfen
|
||||||
|
}
|
||||||
try { autoUpdater.checkForUpdates(); } catch (e) { console.error('[AutoUpdater]', e.message); }
|
try { autoUpdater.checkForUpdates(); } catch (e) { console.error('[AutoUpdater]', e.message); }
|
||||||
});
|
});
|
||||||
|
|
||||||
autoUpdater.on('error', (err) => {
|
// Sync-Abfrage: Frontend kann aktuellen Status beim Modal-Öffnen abfragen
|
||||||
console.error('[AutoUpdater] Error:', err.message);
|
ipcMain.on('get-update-status', (event) => {
|
||||||
if (mainWindow) mainWindow.webContents.send('update-error', err.message);
|
event.returnValue = updateState;
|
||||||
});
|
});
|
||||||
|
|
||||||
// Check for updates after 5 seconds, then every 30 minutes
|
// Auto-Check nach 5 Sek, dann alle 30 Min (nur wenn idle)
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
|
if (updateState === 'idle') {
|
||||||
try { autoUpdater.checkForUpdates(); } catch (e) { console.error('[AutoUpdater]', e.message); }
|
try { autoUpdater.checkForUpdates(); } catch (e) { console.error('[AutoUpdater]', e.message); }
|
||||||
|
}
|
||||||
}, 5000);
|
}, 5000);
|
||||||
|
|
||||||
setInterval(() => {
|
setInterval(() => {
|
||||||
|
if (updateState === 'idle') {
|
||||||
try { autoUpdater.checkForUpdates(); } catch (e) { console.error('[AutoUpdater]', e.message); }
|
try { autoUpdater.checkForUpdates(); } catch (e) { console.error('[AutoUpdater]', e.message); }
|
||||||
|
}
|
||||||
}, 30 * 60 * 1000);
|
}, 30 * 60 * 1000);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,7 @@ contextBridge.exposeInMainWorld('electronAPI', {
|
||||||
onUpdateNotAvailable: (callback) => ipcRenderer.on('update-not-available', callback),
|
onUpdateNotAvailable: (callback) => ipcRenderer.on('update-not-available', callback),
|
||||||
onUpdateError: (callback) => ipcRenderer.on('update-error', (_e, msg) => callback(msg)),
|
onUpdateError: (callback) => ipcRenderer.on('update-error', (_e, msg) => callback(msg)),
|
||||||
checkForUpdates: () => ipcRenderer.send('check-for-updates'),
|
checkForUpdates: () => ipcRenderer.send('check-for-updates'),
|
||||||
|
getUpdateStatus: () => ipcRenderer.sendSync('get-update-status'),
|
||||||
installUpdate: () => ipcRenderer.send('install-update'),
|
installUpdate: () => ipcRenderer.send('install-update'),
|
||||||
setStreaming: (active) => ipcRenderer.send('streaming-status', active),
|
setStreaming: (active) => ipcRenderer.send('streaming-status', active),
|
||||||
showNotification: (title, body) => ipcRenderer.send('show-notification', title, body),
|
showNotification: (title, body) => ipcRenderer.send('show-notification', title, body),
|
||||||
|
|
|
||||||
|
|
@ -65,6 +65,11 @@ export default function App() {
|
||||||
setUpdateStatus('error');
|
setUpdateStatus('error');
|
||||||
setUpdateError(msg || 'Unbekannter Fehler');
|
setUpdateError(msg || 'Unbekannter Fehler');
|
||||||
});
|
});
|
||||||
|
// Sync initial status (Hintergrund-Download könnte bereits laufen)
|
||||||
|
const currentState = api.getUpdateStatus?.();
|
||||||
|
if (currentState === 'downloading') setUpdateStatus('downloading');
|
||||||
|
else if (currentState === 'ready') setUpdateStatus('ready');
|
||||||
|
else if (currentState === 'checking') setUpdateStatus('checking');
|
||||||
}, [isElectron]);
|
}, [isElectron]);
|
||||||
|
|
||||||
// Fetch plugin list
|
// Fetch plugin list
|
||||||
|
|
@ -185,7 +190,17 @@ export default function App() {
|
||||||
)}
|
)}
|
||||||
<span
|
<span
|
||||||
className="hub-version hub-version-clickable"
|
className="hub-version hub-version-clickable"
|
||||||
onClick={() => setShowVersionModal(true)}
|
onClick={() => {
|
||||||
|
// Status vom Main-Prozess synchronisieren bevor Modal öffnet
|
||||||
|
if (isElectron) {
|
||||||
|
const api = (window as any).electronAPI;
|
||||||
|
const s = api.getUpdateStatus?.();
|
||||||
|
if (s === 'downloading') setUpdateStatus('downloading');
|
||||||
|
else if (s === 'ready') setUpdateStatus('ready');
|
||||||
|
else if (s === 'checking') setUpdateStatus('checking');
|
||||||
|
}
|
||||||
|
setShowVersionModal(true);
|
||||||
|
}}
|
||||||
title="Versionsinformationen"
|
title="Versionsinformationen"
|
||||||
>
|
>
|
||||||
v{version}
|
v{version}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue