Upload file updater.js via GUI
This commit is contained in:
164
updater.js
Normal file
164
updater.js
Normal file
@@ -0,0 +1,164 @@
|
||||
// updater.js - Moderner Auto-Updater für Git Manager GUI
|
||||
const { app, shell } = require('electron');
|
||||
const https = require('https');
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
const { spawn } = require('child_process');
|
||||
|
||||
const GITEA_API_URL = 'https://git.viper.ipv64.net/api/v1/repos/M_Viper/Git-Manager-Gui/releases';
|
||||
|
||||
class Updater {
|
||||
constructor(mainWindow) {
|
||||
this.mainWindow = mainWindow;
|
||||
this.checkingForUpdates = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Hauptfunktion zur Prüfung auf Updates
|
||||
*/
|
||||
async checkForUpdates(silent = false) {
|
||||
if (this.checkingForUpdates) return;
|
||||
this.checkingForUpdates = true;
|
||||
|
||||
try {
|
||||
const latestRelease = await this.getLatestRelease();
|
||||
if (!latestRelease) return;
|
||||
|
||||
// Versionen säubern (nur Zahlen und Punkte)
|
||||
const serverVer = latestRelease.tag_name.replace(/[^\d.]/g, '');
|
||||
const localVer = app.getVersion().replace(/[^\d.]/g, '');
|
||||
|
||||
console.log(`[Updater] Version-Check: Server(${serverVer}) vs Lokal(${localVer})`);
|
||||
|
||||
if (this.compareVersions(serverVer, localVer) > 0) {
|
||||
console.log("[Updater] Update verfügbar. Sende Daten an Renderer...");
|
||||
this.mainWindow.webContents.send('update-available', {
|
||||
version: serverVer,
|
||||
body: latestRelease.body,
|
||||
url: latestRelease.html_url,
|
||||
asset: this.findAsset(latestRelease.assets)
|
||||
});
|
||||
} else {
|
||||
console.log("[Updater] Anwendung ist auf dem neuesten Stand.");
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('[Updater] Fehler beim Update-Check:', error);
|
||||
} finally {
|
||||
this.checkingForUpdates = false;
|
||||
}
|
||||
}
|
||||
|
||||
async getLatestRelease() {
|
||||
return new Promise((resolve, reject) => {
|
||||
const options = { headers: { 'User-Agent': 'GitManager-GUI-Updater' } };
|
||||
https.get(GITEA_API_URL, options, (res) => {
|
||||
let data = '';
|
||||
res.on('data', chunk => data += chunk);
|
||||
res.on('end', () => {
|
||||
try {
|
||||
const releases = JSON.parse(data);
|
||||
resolve(Array.isArray(releases) ? releases[0] : null);
|
||||
} catch (e) { reject(e); }
|
||||
});
|
||||
}).on('error', reject);
|
||||
});
|
||||
}
|
||||
|
||||
compareVersions(v1, v2) {
|
||||
const a = v1.split('.').map(Number);
|
||||
const b = v2.split('.').map(Number);
|
||||
for (let i = 0; i < 3; i++) {
|
||||
if ((a[i] || 0) > (b[i] || 0)) return 1;
|
||||
if ((a[i] || 0) < (b[i] || 0)) return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
findAsset(assets) {
|
||||
if (!assets) return null;
|
||||
const ext = process.platform === 'win32' ? '.exe' : '.AppImage';
|
||||
return assets.find(a => a.name.toLowerCase().endsWith(ext));
|
||||
}
|
||||
|
||||
/**
|
||||
* Startet den Download und führt die Installation aus
|
||||
*/
|
||||
async startDownload(asset) {
|
||||
if (!asset || !asset.browser_download_url) {
|
||||
console.error("[Updater] Kein gültiges Asset gefunden!");
|
||||
return;
|
||||
}
|
||||
|
||||
const tempPath = path.join(app.getPath('temp'), asset.name);
|
||||
console.log(`[Updater] Download gestartet: ${asset.name} -> ${tempPath}`);
|
||||
|
||||
const file = fs.createWriteStream(tempPath);
|
||||
|
||||
const download = (url) => {
|
||||
https.get(url, { headers: { 'User-Agent': 'Electron-Updater' } }, (res) => {
|
||||
// Handle Redirects
|
||||
if (res.statusCode === 301 || res.statusCode === 302) {
|
||||
return download(res.headers.location);
|
||||
}
|
||||
|
||||
if (res.statusCode !== 200) {
|
||||
console.error(`[Updater] Download-Fehler: Status ${res.statusCode}`);
|
||||
return;
|
||||
}
|
||||
|
||||
res.pipe(file);
|
||||
|
||||
file.on('finish', () => {
|
||||
file.close();
|
||||
console.log("[Updater] Download abgeschlossen. Initialisiere entkoppelten Installer...");
|
||||
this.installAndQuit(tempPath);
|
||||
});
|
||||
}).on('error', (err) => {
|
||||
fs.unlink(tempPath, () => {});
|
||||
console.error("[Updater] Netzwerkfehler beim Download:", err);
|
||||
});
|
||||
};
|
||||
|
||||
download(asset.browser_download_url);
|
||||
}
|
||||
|
||||
/**
|
||||
* Führt den Installer entkoppelt aus und schließt die App mit Verzögerung
|
||||
*/
|
||||
installAndQuit(filePath) {
|
||||
console.log(`[Updater] Bereite Installation vor: ${filePath}`);
|
||||
|
||||
if (process.platform === 'win32') {
|
||||
// Wir nutzen spawn mit detached: true, damit der Installer weiterläuft,
|
||||
// wenn der Hauptprozess (Electron) beendet wird.
|
||||
try {
|
||||
const child = spawn('cmd.exe', ['/c', 'start', '""', filePath], {
|
||||
detached: true,
|
||||
stdio: 'ignore'
|
||||
});
|
||||
|
||||
child.unref(); // Trennt die Referenz zum Installer
|
||||
|
||||
console.log("[Updater] Installer-Prozess entkoppelt gestartet. App schließt in 2 Sek...");
|
||||
|
||||
// WICHTIG: Wir geben Windows Zeit, den Installer stabil zu laden,
|
||||
// bevor wir die App schließen und die Dateisperren aufheben.
|
||||
setTimeout(() => {
|
||||
app.quit();
|
||||
}, 2000);
|
||||
|
||||
} catch (err) {
|
||||
console.error("[Updater] Kritischer Fehler beim Installer-Start:", err);
|
||||
// Notfall-Versuch über shell
|
||||
shell.openPath(filePath).then(() => app.quit());
|
||||
}
|
||||
} else {
|
||||
// Linux/AppImage
|
||||
shell.openPath(filePath).then(() => {
|
||||
setTimeout(() => app.quit(), 1000);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = Updater;
|
||||
Reference in New Issue
Block a user