From 396c061a3ea34d87bfd10d65eaaa09b5d259dc4f Mon Sep 17 00:00:00 2001 From: Pax1601 Date: Sun, 10 Mar 2024 18:38:55 +0100 Subject: [PATCH] Multiple manager improvements and bug fixes --- manager/ejs/passwords.ejs | 8 +-- manager/javascripts/dcsinstance.js | 97 ++++++++++++++++++++---------- manager/javascripts/filesystem.js | 12 +++- manager/javascripts/manager.js | 81 +++++++++++++++++++++---- manager/main.js | 6 +- manager/package.json | 1 + olympus.json | 2 +- 7 files changed, 154 insertions(+), 53 deletions(-) diff --git a/manager/ejs/passwords.ejs b/manager/ejs/passwords.ejs index cf8f45d0..c4ad8ca2 100644 --- a/manager/ejs/passwords.ejs +++ b/manager/ejs/passwords.ejs @@ -19,21 +19,21 @@ Game Master Password - "> + ">
Blue Commander Password - "> + ">
Red Commander Password - "> + ">
-
" style="color: var(--offwhite); font-size: var(--normal); color: var(--lightgray);"> +
Note: to keep the old passwords, click Next without editing any value.
diff --git a/manager/javascripts/dcsinstance.js b/manager/javascripts/dcsinstance.js index 4f5c87ff..2e2c58bb 100644 --- a/manager/javascripts/dcsinstance.js +++ b/manager/javascripts/dcsinstance.js @@ -1,4 +1,5 @@ const { getManager } = require('./managerfactory') +const { dialog } = require('@electron/remote'); var regedit = require('regedit').promisified; var fs = require('fs') var path = require('path') @@ -23,8 +24,8 @@ class DCSInstance { * @returns The list of DCS instances */ static async getInstances(force = false) { - if (this.instances === null || force) - DCSInstance.instances = this.findInstances(); + if (this.instances === null || force) + DCSInstance.instances = this.findInstances(); return DCSInstance.instances; } @@ -49,29 +50,45 @@ class DCSInstance { var result = await regedit.list(shellFoldersKey); /* Check that the registry read was successfull */ - if (result[shellFoldersKey] !== undefined && result[shellFoldersKey]["exists"] && result[shellFoldersKey]['values'][saveGamesKey] !== undefined && result[shellFoldersKey]['values'][saveGamesKey]['value'] !== undefined) { - /* Read all the folders in Saved Games */ - const searchpath = result[shellFoldersKey]['values'][saveGamesKey]['value']; - var folders = fs.readdirSync(searchpath).map((folder) => {return path.join(searchpath, folder);}); - var instances = []; - folders = folders.concat(getManager().getAdditionalDCSInstances()); - /* A DCS Instance is created if either the appsettings.lua or serversettings.lua file is detected */ - for (let i = 0; i < folders.length; i++) { - const folder = folders[i]; - if (fs.existsSync(path.join(folder, "Config", "appsettings.lua")) || fs.existsSync(path.join(folder, "Config", "serversettings.lua")) || getManager().getAdditionalDCSInstances().includes(folder)) { - logger.log(`Found instance in ${folder}, checking for Olympus`) - var newInstance = new DCSInstance(path.join(folder)); + let customSavedGamesFolder = (await getManager().getOptions()).savedGamesFolder; + console.log((await getManager().getOptions())) + if (customSavedGamesFolder !== undefined || (result[shellFoldersKey] !== undefined && result[shellFoldersKey]["exists"] && result[shellFoldersKey]['values'][saveGamesKey] !== undefined && result[shellFoldersKey]['values'][saveGamesKey]['value'] !== undefined)) { + try { + /* Read all the folders in Saved Games */ + const searchpath = customSavedGamesFolder !== undefined ? customSavedGamesFolder : result[shellFoldersKey]['values'][saveGamesKey]['value']; + var folders = fs.readdirSync(searchpath).map((folder) => { return path.join(searchpath, folder); }); + var instances = []; + folders = folders.concat(getManager().getAdditionalDCSInstances()); - /* Check if Olympus is already installed */ - getManager().setLoadingProgress(`Found instance in ${folder}, checking for Olympus...`, (i + 1) / folders.length * 100); - await newInstance.checkInstallation(); - instances.push(newInstance); + /* A DCS Instance is created if either the appsettings.lua or serversettings.lua file is detected */ + for (let i = 0; i < folders.length; i++) { + const folder = folders[i]; + if (fs.existsSync(path.join(folder, "Config", "appsettings.lua")) || fs.existsSync(path.join(folder, "Config", "serversettings.lua")) || getManager().getAdditionalDCSInstances().includes(folder)) { + logger.log(`Found instance in ${folder}, checking for Olympus`) + var newInstance = new DCSInstance(path.join(folder)); + + /* Check if Olympus is already installed */ + getManager().setLoadingProgress(`Found instance in ${folder}, checking for Olympus...`, (i + 1) / folders.length * 100); + await newInstance.checkInstallation(); + instances.push(newInstance); + } } + } catch (err) { + showErrorPopup(`
A critical error has occurred while detecting your DCS Instances locations.
You can find more info in ${path.join(__dirname, "..", "manager.log")}
`) + logger.error(err) } } else { logger.error("An error occured while trying to fetch the location of the DCS instances.") - showErrorPopup(`
An error occured while trying to fetch the location of the DCS instances.
You can find more info in ${getManager().getLogLocation()}
`); + showErrorPopup(`
An error occured while trying to fetch the location of the DCS instances.
After clicking Close, please select the location of your Saved Games folder.
`, async () => { + let res = await dialog.showOpenDialog({ properties: ["openDirectory"] }); + if (!res.canceled) { + getManager().setSavedGamesFolder(res.filePaths[0]); + } + else { + window.location.reload(); + } + }); } getManager().setLoadingProgress(`All DCS instances found!`, 100); @@ -104,7 +121,7 @@ class DCSInstance { setPopupLoadingProgress(`Installing hook scripts in ${instance.folder}...`, (i * 4 + 4) / (instancesToFix.length * 4) * 100); await sleep(100); - await installHooks(instance.folder); + await installHooks(instance.folder); } setPopupLoadingProgress(`All instances fixed!`, 100); @@ -114,7 +131,7 @@ class DCSInstance { folder = ""; name = ""; frontendPort = 3000; - backendPort = 3001; + backendPort = 4512; backendAddress = "localhost"; gameMasterPassword = ""; blueCommanderPassword = ""; @@ -156,10 +173,10 @@ class DCSInstance { this.installationType = 'singleplayer'; this.connectionsType = 'auto'; this.installCameraPlugin = 'install'; - + /* Check if the olympus.json file is detected. If true, Olympus is considered to be installed */ if (fs.existsSync(path.join(this.folder, "Config", "olympus.json"))) { - + getManager().setLoadingProgress(`Olympus installed in ${this.folder}`); try { /* Read the olympus.json */ @@ -459,7 +476,7 @@ class DCSInstance { /** Stop any node process running on the server port. This will stop either the server or the client depending on what is running * - */ + */ stop() { find('port', this.frontendPort) .then((list) => { @@ -494,24 +511,34 @@ class DCSInstance { await sleep(500); await applyConfiguration(getManager().getActiveInstance().folder, getManager().getActiveInstance()); + if (getManager().getActiveInstance().installCameraPlugin === 'install') { + setPopupLoadingProgress("Installing camera plugin...", 50); + await sleep(100); + await installCameraPlugin(getManager().getActiveInstance().folder); + } else { + setPopupLoadingProgress("Removing camera plugin (if installed)...", 50); + await sleep(100); + await deleteCameraPlugin(getManager().getActiveInstance().folder); + } + setPopupLoadingProgress("Editing completed!", 100); await sleep(1500); logger.log(`Editing completed successfully`); hidePopup(); - getManager().getMode() === "basic"? getManager().settingsPage.show(): getManager().instancesPage.show(); + getManager().getMode() === "basic" ? getManager().settingsPage.show() : getManager().instancesPage.show(); } catch (err) { logger.log(`An error occurred during editing: ${err}`); getManager().getActiveInstance().error = true; - + showErrorPopup(`
A critical error occurred!
Check ${getManager().getLogLocation()} for more info.
`) - getManager().getMode() === "basic"? getManager().settingsPage.show(): getManager().instancesPage.show(); + getManager().getMode() === "basic" ? getManager().settingsPage.show() : getManager().instancesPage.show(); } } /** Install this instance * - */ + */ async install() { showWaitLoadingPopup(`Please wait while Olympus is being installed in ${this.name}`); try { @@ -540,6 +567,10 @@ class DCSInstance { setPopupLoadingProgress("Installing camera plugin...", 83); await sleep(100); await installCameraPlugin(getManager().getActiveInstance().folder); + } else { + setPopupLoadingProgress("Removing camera plugin (if installed)...", 83); + await sleep(100); + await deleteCameraPlugin(getManager().getActiveInstance().folder); } setPopupLoadingProgress("Installation completed!", 100); @@ -605,9 +636,9 @@ class DCSInstance { hidePopup(); await getManager().reload(); - if (getManager().getMode() === 'basic') + if (getManager().getMode() === 'basic') getManager().settingsPage.show(); - else + else getManager().instancesPage.show(); return true; } catch (err) { @@ -616,12 +647,12 @@ class DCSInstance { /* Nested popup calls need to wait for animation to complete */ await sleep(300); showErrorPopup(`
An error has occurred while uninstalling the Olympus instance.
Make sure Olympus and DCS are not running.
You can find more info in ${path.join(__dirname, "..", "manager.log")}
`, () => { - if (getManager().getMode() === 'basic') + if (getManager().getMode() === 'basic') getManager().settingsPage.show(); - else + else getManager().instancesPage.show(); }); - } + } }, () => { getManager().setState('IDLE'); }); diff --git a/manager/javascripts/filesystem.js b/manager/javascripts/filesystem.js index 75b394e7..80cd7e21 100644 --- a/manager/javascripts/filesystem.js +++ b/manager/javascripts/filesystem.js @@ -163,9 +163,15 @@ async function applyConfiguration(folder, instance) { config["frontend"]["port"] = instance.frontendPort; config["backend"]["port"] = instance.backendPort; config["backend"]["address"] = instance.backendAddress; - config["authentication"]["gameMasterPassword"] = sha256(instance.gameMasterPassword); - config["authentication"]["blueCommanderPassword"] = sha256(instance.blueCommanderPassword); - config["authentication"]["redCommanderPassword"] = sha256(instance.redCommanderPassword); + + if (instance.gameMasterPassword !== "") + config["authentication"]["gameMasterPassword"] = sha256(instance.gameMasterPassword); + + if (instance.blueCommanderPassword !== "") + config["authentication"]["blueCommanderPassword"] = sha256(instance.blueCommanderPassword); + + if (instance.redCommanderPassword !== "") + config["authentication"]["redCommanderPassword"] = sha256(instance.redCommanderPassword); await fsp.writeFile(path.join(folder, "Config", "olympus.json"), JSON.stringify(config, null, 4)); logger.log(`Config succesfully applied in ${folder}`) diff --git a/manager/javascripts/manager.js b/manager/javascripts/manager.js index 1d59808a..8f4b701e 100644 --- a/manager/javascripts/manager.js +++ b/manager/javascripts/manager.js @@ -2,7 +2,7 @@ const path = require("path") const fs = require("fs"); const DCSInstance = require('./dcsinstance'); -const { showErrorPopup, showWaitPopup, showConfirmPopup } = require('./popup'); +const { showErrorPopup, showConfirmPopup } = require('./popup'); const { logger } = require("./filesystem") const ManagerPage = require("./managerpage"); @@ -236,6 +236,17 @@ class Manager { location.reload(); } + async setSavedGamesFolder(folder) { + var options = JSON.parse(fs.readFileSync("options.json")); + options.savedGamesFolder = folder; + fs.writeFileSync("options.json", JSON.stringify(options, null, 2)); + location.reload(); + } + + async getOptions() { + return JSON.parse(fs.readFileSync("options.json")); + } + /************************************************/ /* CALLBACKS */ /************************************************/ @@ -341,8 +352,8 @@ class Manager { /* When the camera control installation is selected */ async onInstallCameraControlClicked(type) { - this.connectionsTypePage.getElement().querySelector(`.install`).classList.toggle("selected", type === 'install'); - this.connectionsTypePage.getElement().querySelector(`.no-install`).classList.toggle("selected", type === 'no-install'); + this.cameraPage.getElement().querySelector(`.install`).classList.toggle("selected", type === 'install'); + this.cameraPage.getElement().querySelector(`.no-install`).classList.toggle("selected", type === 'no-install'); if (this.getActiveInstance()) this.getActiveInstance().installCameraPlugin = type; else { @@ -406,13 +417,33 @@ class Manager { } /* Installation type page */ } else if (this.activePage == this.cameraPage) { - this.activePage.hide(); - this.getState() === 'INSTALL' ? this.getActiveInstance().install() : this.getActiveInstance().edit(); + if (await this.checkDCSRunning()) { + showConfirmPopup(`
DCS is running!
Please stop the DCS instance you are trying to add Olympus to, then select Accept
`, async () => { + /* Nested popup calls need to wait for animation to complete */ + await sleep(300); + + this.activePage.hide(); + this.getState() === 'INSTALL' ? this.getActiveInstance().install() : this.getActiveInstance().edit(); + }); + } else { + this.activePage.hide(); + this.getState() === 'INSTALL' ? this.getActiveInstance().install() : this.getActiveInstance().edit(); + } /* Expert settings page */ } else if (this.activePage == this.expertSettingsPage) { if (await this.checkPorts() && await this.checkPasswords()) { - this.activePage.hide(); - this.getState() === 'INSTALL' ? this.getActiveInstance().install() : this.getActiveInstance().edit(); + if (await this.checkDCSRunning()) { + showConfirmPopup(`
DCS is running!
Please stop the DCS instance you are trying to add Olympus to, then select Accept
`, async () => { + /* Nested popup calls need to wait for animation to complete */ + await sleep(300); + + this.activePage.hide(); + this.getState() === 'INSTALL' ? this.getActiveInstance().install() : this.getActiveInstance().edit(); + }); + } else { + this.activePage.hide(); + this.getState() === 'INSTALL' ? this.getActiveInstance().install() : this.getActiveInstance().edit(); + } } } } @@ -541,7 +572,7 @@ class Manager { async checkPasswords() { if (this.getActiveInstance()) { - if (this.getActiveInstance().installed && !this.getActiveInstance().arePasswordsEdited()) { + if (this.getState() === 'EDIT' && !this.getActiveInstance().arePasswordsEdited()) { return true; } else { @@ -609,10 +640,20 @@ class Manager { var instance = await this.getClickedInstance(name); this.setActiveInstance(instance); await this.setState('UNINSTALL'); - if (instance.webserverOnline || instance.backendOnline) + if (instance.webserverOnline || instance.backendOnline) { showErrorPopup("
The selected Olympus instance is currently active
Please stop DCS and Olympus Server/Client before removing it!
") - else - await instance.uninstall(); + } else { + if (await this.checkDCSRunning()) { + showConfirmPopup(`
DCS is running!
Please stop the DCS instance you are trying to remove Olympus from, then select Accept
`, async () => { + /* Nested popup calls need to wait for animation to complete */ + await sleep(300); + + await instance.uninstall(); + }); + } else { + await instance.uninstall(); + } + } } async onLinkClicked(url) { @@ -758,6 +799,24 @@ class Manager { this.setActiveInstance(undefined); } + async checkDCSRunning() { + let ps = new Promise((res, rej) => { + exec('tasklist', function(err, stdout, stderr) { + console.log(stdout) + if (stdout.toLowerCase().includes("dcs.exe") || stdout.includes("dcs_server.exe")) { + res(true); + } else { + res(false); + } + }); + }) + try { + return await ps; + } catch { + return false; // An error occurred, let's hope DCS is not running! + } + } + /** Get the currently active instance, i.e. the instance that is being edited/installed/removed * * @returns The active instance diff --git a/manager/main.js b/manager/main.js index 4319a3ff..4f13d8d4 100644 --- a/manager/main.js +++ b/manager/main.js @@ -8,6 +8,8 @@ let window; /* Add the System32 folder to the environment for the shortcuts creation to work properly */ process.env['PATH'] = process.env['PATH'] + "%WINDIR%\\System32;" +require('@electron/remote/main').initialize() + function createWindow() { const window = new electronBrowserWindow({ width: 1200, @@ -18,11 +20,13 @@ function createWindow() { webPreferences: { contextIsolation: true, preload: path.join(__dirname, "javascripts", 'preload.js'), - nodeIntegration: true, + nodeIntegration: true }, icon: "./../img/olympus_configurator.ico" }); + require("@electron/remote/main").enable(window.webContents); + window.loadFile('index.html').then(() => { window.show(); }); window.on("maximize", () => { diff --git a/manager/package.json b/manager/package.json index 45b8f75c..fda57f6e 100644 --- a/manager/package.json +++ b/manager/package.json @@ -10,6 +10,7 @@ "author": "", "license": "ISC", "dependencies": { + "@electron/remote": "^2.1.2", "adm-zip": "^0.5.10", "create-desktop-shortcuts": "^1.10.1", "dir-compare": "^4.2.0", diff --git a/olympus.json b/olympus.json index 1fe78bc0..d6f2b804 100644 --- a/olympus.json +++ b/olympus.json @@ -1,7 +1,7 @@ { "backend": { "address": "localhost", - "port": 3001 + "port": 4512 }, "authentication": { "gameMasterPassword": "4b8823ed9e5c2392ab4a791913bb8ce41956ea32e308b760eefb97536746dd33",