set auto update AND fix download version errors

This commit is contained in:
MathieuG-P
2022-09-19 01:04:50 +02:00
parent 5d0e5f03ee
commit b91e1a3567
38 changed files with 500 additions and 220 deletions
-2
View File
@@ -49,10 +49,8 @@ ipcMain.on('bs-download.installation-folder', async (event, request: IpcRequest<
ipcMain.on('bs-download.set-installation-folder', (event, request: IpcRequest<string>) => {
const installerService = InstallationLocationService.getInstance();
installerService.setInstallationDirectory(request.args).then(res => {
console.log("déplacement terminer");
UtilsService.getInstance().ipcSend(request.responceChannel, {success: true, data: res});
}).catch((err: BsmException) => {
console.log(err);
UtilsService.getInstance().ipcSend(request.responceChannel, {success: false, error: err});
});
})
+1
View File
@@ -10,6 +10,7 @@ ipcMain.on('bs-launch.launch', (event, request: IpcRequest<LauchOption>) => {
const utilsService = UtilsService.getInstance();
launcherService.launch(request.args).then(res => {
console.log("BEAT SABER LANCER");
utilsService.ipcSend(request.responceChannel, {success: true, data: res});
}).catch((err: BsmException) => {
utilsService.ipcSend(request.responceChannel, {success: false, error: err});
-4
View File
@@ -35,20 +35,16 @@ ipcMain.on("bs-version.open-folder", async (event, req: IpcRequest<BSVersion>) =
ipcMain.on("bs-version.edit", async (event, req: IpcRequest<{version: BSVersion, name: string, color: string}>) => {
BSLocalVersionService.getInstance().editVersion(req.args.version, req.args.name, req.args.color).then(res => {
console.log(res);
UtilsService.getInstance().ipcSend(req.responceChannel, {success: !!res, data: res});
}).catch((error: BsmException) => {
UtilsService.getInstance().ipcSend(req.responceChannel, {success: false, error});
console.log(error);
});
});
ipcMain.on("bs-version.clone", async (event, req: IpcRequest<{version: BSVersion, name: string, color: string}>) => {
BSLocalVersionService.getInstance().cloneVersion(req.args.version, req.args.name, req.args.color).then(res => {
console.log(res);
UtilsService.getInstance().ipcSend(req.responceChannel, {success: !!res, data: res});
}).catch((error: BsmException) => {
UtilsService.getInstance().ipcSend(req.responceChannel, {success: false, error});
console.log(error);
});
});
+2
View File
@@ -5,3 +5,5 @@ import './bs-version-ipcs';
import './bs-uninstall-ipcs';
import './map-ipcs';
import './supporters-ipcs';
import './launcher-ipcs';
import './window-manager-ipcs';
+31
View File
@@ -0,0 +1,31 @@
import { ipcMain } from "electron";
import { AutoUpdaterService } from "../services/auto-updater.service";
import { IpcRequest } from "shared/models/ipc";
import { UtilsService } from "../services/utils.service";
ipcMain.on("download-update", async (event, request: IpcRequest<void>) => {
const updaterService = AutoUpdaterService.getInstance();
const utilsService = UtilsService.getInstance();
updaterService.downloadUpdate().then(res => utilsService.ipcSend(request.responceChannel, {success: res}))
.catch(() => utilsService.ipcSend(request.responceChannel, {success: false}));
});
ipcMain.on("check-update", async (event, request: IpcRequest<void>) => {
const updaterService = AutoUpdaterService.getInstance();
const utilsService = UtilsService.getInstance();
updaterService.isUpdateAvailable().then(updateAvailable => {
utilsService.ipcSend(request.responceChannel, {success: true, data: updateAvailable});
})
.catch(() => utilsService.ipcSend(request.responceChannel, {success: false}));
});
ipcMain.on("install-update", async (event, request: IpcRequest<void>) => {
const updaterService = AutoUpdaterService.getInstance();
updaterService.quitAndInstall();
});
+11 -7
View File
@@ -1,26 +1,29 @@
import { ipcMain, shell, dialog, app } from 'electron';
import { UtilsService } from '../services/utils.service';
import { IpcRequest } from 'shared/models/ipc';
import { getMainWindow } from '../main';
ipcMain.on('window.close', async () => {
getMainWindow()?.close();
const utils = UtilsService.getInstance();
utils.getMainWindow()?.close();
});
ipcMain.on('window.maximize', async () => {
getMainWindow()?.maximize();
const utils = UtilsService.getInstance();
utils.getMainWindow()?.maximize();
});
ipcMain.on('window.minimize', async () => {
getMainWindow()?.minimize();
const utils = UtilsService.getInstance();
utils.getMainWindow()?.minimize();
});
ipcMain.on('window.reset', async () => {
getMainWindow()?.restore();
const utils = UtilsService.getInstance();
utils.getMainWindow()?.restore();
});
ipcMain.on('new-window', async (event, request: IpcRequest<string>) => {
shell.openExternal(request.args);
shell.openExternal(request.args);
});
ipcMain.on('choose-folder', async (event, request: IpcRequest<void>) => {
@@ -30,7 +33,8 @@ ipcMain.on('choose-folder', async (event, request: IpcRequest<void>) => {
});
ipcMain.on("window.progression", async (event, request: IpcRequest<number>) => {
getMainWindow().setProgressBar(request.args / 100);
const utils = UtilsService.getInstance();
utils.getMainWindow().setProgressBar(request.args / 100);
});
ipcMain.on('save-file', async (event, request: IpcRequest<{filename?: string, filters?: Electron.FileFilter[]}>) => {
+12
View File
@@ -0,0 +1,12 @@
import { ipcMain } from "electron";
import { WindowManagerService } from "../services/window-manager.service";
import { IpcRequest } from "shared/models/ipc";
import { AppWindow } from "shared/models/window-manager/app-window.model";
ipcMain.on("open-window-then-close-all", async (event, request: IpcRequest<AppWindow>) => {
const windowManager = WindowManagerService.getInstance();
windowManager.openWindow(request.args).then(window => {
windowManager.closeAllWindows(request.args);
});
});
+20 -103
View File
@@ -9,19 +9,15 @@
* `./src/main.js` using webpack. This gives us some performance wins.
*/
import path from 'path';
import { app, BrowserWindow, shell } from 'electron';
import { autoUpdater } from 'electron-updater';
import { app } from 'electron';
import log from 'electron-log';
import { resolveHtmlPath } from './util';
import './ipcs';
import { UtilsService } from './services/utils.service';
import { WindowManagerService } from './services/window-manager.service';
export default class AppUpdater {
constructor() {
autoUpdater.logger = log;
//autoUpdater.checkForUpdatesAndNotify();
}
}
export const PRELOAD_PATH = app.isPackaged ? path.join(__dirname, 'preload.js') : path.join(__dirname, '../../.erb/dll/preload.js')
const isDebug = process.env.NODE_ENV === 'development' || process.env.DEBUG_PROD === 'true';
log.transports.file.level = 'info';
log.transports.file.resolvePath = (() => {
@@ -31,11 +27,8 @@ log.transports.file.resolvePath = (() => {
log.catchErrors();
let mainWindow: BrowserWindow = null;
export function getMainWindow(): BrowserWindow{
return mainWindow;
}
const utilsService = UtilsService.getInstance();
utilsService.setAssetsPath(app.isPackaged ? path.join(process.resourcesPath, 'assets') : path.join(__dirname, '../../assets'));
if (process.env.NODE_ENV === 'production') {
@@ -43,107 +36,31 @@ if (process.env.NODE_ENV === 'production') {
sourceMapSupport.install();
}
const isDebug = process.env.NODE_ENV === 'development' || process.env.DEBUG_PROD === 'true';
if (isDebug) {
require('electron-debug')();
}
const installExtensions = async () => {
const installer = require('electron-devtools-installer');
const forceDownload = !!process.env.UPGRADE_EXTENSIONS;
const extensions = ['REACT_DEVELOPER_TOOLS'];
const installer = require('electron-devtools-installer');
const forceDownload = !!process.env.UPGRADE_EXTENSIONS;
const extensions = ['REACT_DEVELOPER_TOOLS'];
return installer
.default(
extensions.map((name) => installer[name]),
forceDownload
)
.catch(console.log);
return installer.default(extensions.map((name) => installer[name]), forceDownload).catch(console.log);
};
const createWindow = async () => {
if (isDebug) {
await installExtensions();
}
const RESOURCES_PATH = app.isPackaged ? path.join(process.resourcesPath, 'assets') : path.join(__dirname, '../../assets');
UtilsService.getInstance().setAssetsPath(RESOURCES_PATH);
const getAssetPath = (...paths: string[]): string => {
return path.join(RESOURCES_PATH, ...paths);
};
mainWindow = new BrowserWindow({
show: false,
width: 1080,
height: 720,
minWidth: 900,
minHeight: 500,
frame: false,
titleBarOverlay: false,
icon: getAssetPath('favicon.ico'),
webPreferences: {
preload: app.isPackaged
? path.join(__dirname, 'preload.js')
: path.join(__dirname, '../../.erb/dll/preload.js'),
},
});
UtilsService.getInstance().setMainWindow(mainWindow);
mainWindow.loadURL(resolveHtmlPath('index.html'));
mainWindow.on('ready-to-show', () => {
if (!mainWindow) {
throw new Error('"mainWindow" is not defined');
}
if (process.env.START_MINIMIZED) {
mainWindow.minimize();
} else {
mainWindow.show();
}
});
mainWindow.on('closed', () => {
mainWindow = null;
});
mainWindow.removeMenu();
mainWindow.setMenu(null);
// Open urls in the user's browser
mainWindow.webContents.setWindowOpenHandler((edata) => {
shell.openExternal(edata.url);
return { action: 'deny' };
});
// Remove this if your app does not use auto updates
// eslint-disable-next-line
new AppUpdater();
if(isDebug){ await installExtensions(); }
WindowManagerService.getInstance().openWindow("launcher.html");
};
/**
* Add event listeners...
*/
app.on('window-all-closed', () => {
// Respect the OSX convention of having the application in memory even
// after all windows have been closed
if (process.platform !== 'darwin') {
app.quit();
}
// Respect the OSX convention of having the application in memory even
// after all windows have been closed
if (process.platform !== 'darwin') {
app.quit();
}
});
app
.whenReady()
.then(() => {
app.whenReady().then(() => {
createWindow();
app.on('activate', () => {
// On macOS it's common to re-create a window in the app when the
// dock icon is clicked and there are no other windows open.
if (mainWindow === null) createWindow();
});
})
.catch(console.log);
}).catch(console.log);
+55
View File
@@ -0,0 +1,55 @@
import { autoUpdater } from 'electron-updater';
import log from 'electron-log';
import { UtilsService } from './utils.service';
export class AutoUpdaterService {
private static instance: AutoUpdaterService;
private readonly utilsService: UtilsService;
public static getInstance(): AutoUpdaterService{
if(!AutoUpdaterService.instance){ AutoUpdaterService.instance = new AutoUpdaterService(); }
return AutoUpdaterService.instance;
}
constructor(){
autoUpdater.logger = log;
autoUpdater.autoDownload = false;
this.utilsService = UtilsService.getInstance();
}
public isUpdateAvailable(): Promise<boolean>{
return new Promise(resolve => {
autoUpdater.checkForUpdates().then(info => {
const needUpdate = (() => {
if(!info || !info.updateInfo){ return false; }
if(autoUpdater.currentVersion.version === info.updateInfo.version){ return false; }
return true;
})();
resolve(needUpdate)}
).catch(() => resolve(false));
});
}
public downloadUpdate(): Promise<boolean>{
autoUpdater.removeAllListeners("download-progress");
autoUpdater.addListener("download-progress", info => {
this.utilsService.ipcSend("update-download-progress", {success: true, data: info.percent});
});
// const promise = new Promise<boolean>((resolve, reject) => {
// autoUpdater.addListener("update-downloaded", () => resolve(true));
// autoUpdater.addListener("error", () => reject(false))
// });
return autoUpdater.downloadUpdate().then(res => !!res && !!res.length);
}
public quitAndInstall(){
autoUpdater.quitAndInstall();
}
}
+23 -22
View File
@@ -7,7 +7,6 @@ import log from "electron-log";
import { InstallationLocationService } from "./installation-location.service";
import { ctrlc } from "ctrlc-windows";
import { BSLocalVersionService } from "./bs-local-version.service";
import { getMainWindow } from "../main";
import isOnline from 'is-online';
export class BSInstallerService{
@@ -25,7 +24,7 @@ export class BSInstallerService{
this.installLocationService = InstallationLocationService.getInstance();
this.localVersionService = BSLocalVersionService.getInstance();
getMainWindow().on("close", () => {
this.utils.getMainWindow().on("close", () => {
this.killDownloadProcess();
});
}
@@ -35,14 +34,16 @@ export class BSInstallerService{
return BSInstallerService.instance;
}
private getDepotDownloaderExePath(): string{
return path.join(this.utils.getAssetsScriptsPath(), 'depot-downloader', 'DepotDownloader.exe');
}
private getDepotDownloaderExePath(): string{
return path.join(this.utils.getAssetsScriptsPath(), 'depot-downloader', 'DepotDownloader.exe');
}
private sendDownloadEvent(event: DownloadEventType, data?: string|number, success = true): void{
if(typeof data === "string"){ data = data.replaceAll(/\[|\]/g, ""); }
this.utils.ipcSend(`bs-download.${event}`, { success, data });
}
private removeSpecialSchar(txt: string): string{ return txt.replaceAll(/\[|\]/g, ""); }
private sendDownloadEvent(event: DownloadEventType, data?: string|number, success = true): void{
if(typeof data === "string"){ data = this.removeSpecialSchar(data); }
this.utils.ipcSend(`bs-download.${event}`, { success, data });
}
public sendInputProcess(input: string){
if(this.downloadProcess.stdin.writable){
@@ -54,16 +55,16 @@ export class BSInstallerService{
return new Promise(resolve => {
if(this.downloadProcess?.killed && !this.downloadProcess?.pid){ return resolve(false); }
this.downloadProcess.on('close', () => resolve(true));
this.downloadProcess.once('exit', () => resolve(true));
ctrlc(this.downloadProcess.pid);
if(!this.downloadProcess.kill()){ return resolve(false); }
setTimeout(() => resolve(false), 2000);
setTimeout(() => resolve(false), 3000);
});
}
public async downloadBsVersion(downloadInfos: DownloadInfo): Promise<DownloadEvent>{
if(this.downloadProcess && !this.downloadProcess?.killed){ return {type: "[AlreadyDownloading]"}; }
if(this.downloadProcess && this.downloadProcess.connected){ throw "AlreadyDownloading"; }
const {bsVersion} = downloadInfos;
if(!bsVersion){ return {type: "[Error]"}; }
if(!(await isOnline({timeout: 1500}))){ throw "no-internet"; }
@@ -86,9 +87,10 @@ export class BSInstallerService{
this.downloadProcess.stdout.on('data', data => {
const matched = (data.toString() as string).match(/(?:\[(.*?)\])\|(?:\[(.*?)\]\|)?(.*?)(?=$|\[)/gm) ?? [];
console.log(data.toString());
matched.forEach(match => {
const out = match.split("|");
if(out[0] !== "[Progress]" && out[0] !== "[Validated]"){ log.info(data.toString()); }
if(out[0] === "[Password]" as DownloadEventType && downloadInfos.password){
this.sendInputProcess(downloadInfos.password);
@@ -114,8 +116,7 @@ export class BSInstallerService{
this.sendDownloadEvent("[Warning]", out[1]);
}
else if(out[0] === "[Error]" as DownloadEventType){
reject(out[1]);
this.sendDownloadEvent("[Error]", out[1], false);
reject(this.removeSpecialSchar(out[1]));
this.killDownloadProcess();
log.error("Download Event, Error", data.toString());
}
@@ -125,18 +126,18 @@ export class BSInstallerService{
this.downloadProcess.stdout.on('error', (err) => {
log.error("BS-DOWNLOAD ERROR", err.toString());
this.downloadProcess.kill();
reject(err);
this.killDownloadProcess();
reject();
});
this.downloadProcess.stderr.on('data', (err) => {
log.error("BS-DOWNLOAD ERROR", err.toString());
this.downloadProcess.kill();
reject(err);
this.killDownloadProcess();
reject();
});
this.downloadProcess.stderr.on('error', (err) => {
log.error("BS-DOWNLOAD ERROR", err.toString());
this.downloadProcess.kill();
reject(err);
this.killDownloadProcess();
reject();
});
this.downloadProcess.on('close', () => reject());
+2
View File
@@ -38,6 +38,8 @@ export class BSLauncherService{
const cwd = await this.localVersionService.getVersionPath(launchOptions.version);
const exePath = path.join(cwd, BS_EXECUTABLE);
console.log(exePath);
if(!this.utilsService.pathExist(exePath)){ return "EXE_NOT_FINDED"; }
const launchMods = [launchOptions.oculus && "-vrmode oculus", launchOptions.desktop && "fpfc", launchOptions.debug && "--verbose"];
-2
View File
@@ -30,8 +30,6 @@ export class MapService{
const versionPath = await this.localVersionService.getVersionPath(version);
const mapsPath = this.getMapsPath(versionPath);
console.log(outputZip);
const output = createWriteStream(outputZip);
const archive = archiver("zip", {zlib: {level: 9}});
+4 -3
View File
@@ -23,12 +23,13 @@ export class UtilsService{
}
public setAssetsPath(path: string): void{ this.assetsPath = path; }
public getAssetsPath(): string{ return this.assetsPath; }
public getAssetsPath(pathToFile: string): string{ return path.join(this.assetsPath, pathToFile); }
public getAssetsScriptsPath(): string { return path.join(this.getAssetsPath(), 'scripts'); }
public getAssestsJsonsPath(): string { return path.join(this.getAssetsPath(), 'jsons'); }
public getAssetsScriptsPath(): string { return this.getAssetsPath("scripts") }
public getAssestsJsonsPath(): string { return this.getAssetsPath("jsons"); }
public setMainWindow(win: BrowserWindow){ this.mainWindow = win; }
public getMainWindow(){ return this.mainWindow; }
public pathExist(path: string): boolean{ return existsSync(path); }
@@ -0,0 +1,68 @@
import { app, BrowserWindow, BrowserWindowConstructorOptions } from "electron";
import { resolveHtmlPath } from "../util";
import { UtilsService } from "./utils.service";
import { AppWindow } from "shared/models/window-manager/app-window.model";
import { PRELOAD_PATH } from "../main";
export class WindowManagerService{
private static instance: WindowManagerService;
private readonly utilsService: UtilsService = UtilsService.getInstance();
private readonly appWindowsOptions: Record<AppWindow, BrowserWindowConstructorOptions> = {
"launcher.html": {width: 380, height: 500, minWidth: 380, minHeight: 500, resizable: false},
"index.html": {width: 1080, height: 720, minWidth: 900, minHeight: 500}
}
private readonly baseWindowOption: BrowserWindowConstructorOptions = {
icon: this.utilsService.getAssetsPath("favicon.ico"),
show: false,
frame: false,
titleBarOverlay: false,
webPreferences: { preload: PRELOAD_PATH }
}
private readonly windows: Map<AppWindow, BrowserWindow> = new Map<AppWindow, BrowserWindow>();
public static getInstance(): WindowManagerService{
if(!WindowManagerService.instance){ WindowManagerService.instance = new WindowManagerService(); }
return WindowManagerService.instance;
}
private constructor(){}
public openWindow(windowType: AppWindow): Promise<BrowserWindow>{
const window = new BrowserWindow({...this.appWindowsOptions[windowType], ...this.baseWindowOption});
const promise = window.loadURL(resolveHtmlPath(windowType));
window.removeMenu();
window.setMenu(null);
window.once("ready-to-show", () => {
if (!window) { throw new Error('"window" is not defined'); }
return window.show();
});
window.once("closed", () => {
this.windows.delete(windowType);
if(!this.windows.size){ app.quit(); }
});
this.windows.set(windowType, window);
this.utilsService.setMainWindow(window);
return promise.then(() => window);
}
public closeWindow(window: AppWindow){
this.windows.get(window).close();
}
public closeAllWindows(except?: AppWindow){
this.windows.forEach((window, key) => {
if(key === except){ return; }
window.close();
})
}
}