import { ManaPlusApp } from "./manaApp/manaApp.interface"; import { ManaPlusAppWindows } from "./manaApp/windows"; import * as os from "os"; import { join } from "path"; import * as fs from "fs-extra"; import { ipcMain, shell, dialog } from "electron"; import { Status, EventEmitter } from "../status"; import { ManaPlusAppLinux } from "./manaApp/linux"; import { getUserDataPath } from "../util/app_constants"; import { execFile } from "child_process"; let ManaPlusInstance: ManaPlusApp; let CurrentServer: { serverID: string; address: string } = null; export namespace ManaPlus { export const ERRORS = { NOT_INITILIZED_YET_ERROR: new Error( "The ManaPlus updater wasn't initilized" ) }; export function init() { if (os.platform() == "win32") { ManaPlusInstance = new ManaPlusAppWindows(); console.log("GameDir:" + ManaPlusInstance.getGameDir()); } if (os.platform() == "linux") { ManaPlusInstance = new ManaPlusAppLinux(); console.log("startCommand:" + ManaPlusInstance.startCommand); } } export async function update() { if (!wasInitilized()) throw ERRORS.NOT_INITILIZED_YET_ERROR; return await ManaPlusInstance.update(); } export async function start(args: any) { CurrentServer = { serverID: args.serverID, address: args.address }; let params: string[]; try { params = await makeParams( args.address, args.port, args.engine, args.username, args.password ); //params = ['-v'];// DEBUG: This option is to disable manaplus for testing (open it just for getting the version) } catch (e) { console.log(e); Status.showError( "Launch Preperation Failed (LPF_PARMS)", e.message, "Launch preparation failed" ); Status.setPlaying(false); return; } let willUpdate: boolean = false; // check if it is installed if (ManaPlusInstance.isInstalled()) { // Check if update is available and ask if the user wants to update try { let version = await ManaPlusInstance.updateAvailable(); // console.log({version}) willUpdate = !version.isNewVersion && (await updateDialog(version.newestVersion)); } catch (e) { console.log(e); Status.showError( "Launch Preperation Failed (LPF_Update): This error can also mean that you are offline, \ please check you network connection first.", e.message, "Launch preparation failed" ); Status.setPlaying(false); return; } } else { // Not installed will install it willUpdate = true; } // Install/Update the gameclient if needed if (willUpdate) { try { await update(); } catch (error) { Status.setPlaying(false); throw error; } } //IDEA have client data updated here to, if needed // Run it Status.setGameRunning(true); EventEmitter.emit("closeWindow"); EventEmitter.emit("openTray"); await runManaProgram(params, ManaPlusInstance.startCommand, args.address); // On Close Status.setGameStatus({ server: "Launcher" }); Status.setGameRunning(false); Status.setPlaying(false); Status.removeActivity(); EventEmitter.emit("reopenWindow"); EventEmitter.emit("closeTray"); CurrentServer = null; } } ipcMain.handle("getScreenshots", async (_event: any, arg: string) => { const screenshotsDir = join(getUserDataPath(), "/screenshots/", `${arg}/`); (await fs.existsSync(screenshotsDir)) || (await fs.mkdirSync(screenshotsDir)); const dir = await fs.readdir(screenshotsDir); let screenshots: string[] = []; for (var i = 0, path; (path = dir[i]); i++) { screenshots.push(path); } return { dir: screenshotsDir, screenshots: screenshots.reverse().slice(0, 24) }; }); EventEmitter.on("Mana:openScreenshotDir", () => { shell.openPath( join(getUserDataPath(), `/screenshots/${CurrentServer.address}/`) ); }); function wasInitilized() { return ( typeof ManaPlusInstance !== "undefined" && typeof ManaPlusInstance !== "undefined" ); } async function makeParams( server: any, port: any, engine: any, username?: any, password?: any ): Promise { let parameters: string[] = []; if (server && engine && port && server != "noServer") { parameters.push(...["-s", server, "-y", engine, "-p", port]); if (username && password) { parameters.push(...["-U", username, "-P", password]); } } // Setup Paths and stuff const configDir = join(getUserDataPath(), "/mana_config"); const localDataDir = join(getUserDataPath(), "/mana_local_data"); const screenshotsDir = join(getUserDataPath(), `/screenshots/${server}`); await fs.ensureDir(configDir); await fs.ensureDir(localDataDir); await fs.ensureDir(screenshotsDir); parameters.push( ...["-C", configDir, "-L", localDataDir, "--screenshot-dir", screenshotsDir] ); //console.log(parameters); return parameters; } let manaplusInstance: any = null; function runManaProgram( parameters: string[], gameExe: string, server?: string ): Promise { return new Promise(async (resolve, reject) => { if (server) { Status.setActivity(`Preparing Launch`); await setSkipUpdateWindows(server); } Status.setActivity(`Starting ManaPlus`); //console.log(gameExe, parameters); const child = execFile( gameExe, parameters, { env: { ...process.env, APPIMAGELAUNCHER_DISABLE: "true" } }, function (err: Error, data: any) { console.log(err); console.log(data.toString()); Status.setActivity(`ManaPlus is running`); } ); child.on("close", () => { manaplusInstance = null; resolve(); }); child.on("error", () => { manaplusInstance = null; resolve(); //// TODO: Handle Error }); manaplusInstance = child; }); } EventEmitter.on("Mana:killMana", () => { if (manaplusInstance && manaplusInstance !== null) manaplusInstance.kill("SIGINT"); }); async function updateDialog(newestVersion: string): Promise { const options = { type: "info", title: `ManaPlus Update available: ${newestVersion}`, message: "Do you want to update now? Please note that you'll have to update eventually to ensure further compability with the servers", buttons: ["Nah, LATER", "Update NOW"] }; let { response } = await dialog.showMessageBox(null, options); console.log("....", response); return response === 1; } const default_server_config = '\ \ '; const parseString = require("xml2js").parseString, xml2js = require("xml2js"); async function setSkipUpdateWindows(server: string) { const serverConfigXML = join( getUserDataPath(), `/mana_config/${server}/config.xml` ); if (fs.existsSync(serverConfigXML)) { //add to this file try { let data = await fs.readFile(serverConfigXML, "utf8"); data = await editXML(data); await fs.outputFile(serverConfigXML, data); } catch (err) { console.log(err); } } else { //create the file fs.outputFile(serverConfigXML, default_server_config); } return; } function editXML(xml: string): Promise { return new Promise((res, rej) => { parseString(xml, function (err: any, result: any) { if (err) console.log(err); var json = result; const updaterVar = json.configuration.option.find( (item: any) => item.$.name == "updateType" ); if (updaterVar) { if (updaterVar.$.value === 1) { return rej(new Error("Has allready the right value")); } updaterVar.$.value = 1; } else { json.configuration.option.push({ $: { name: "updateType", value: 1 } }); } var builder = new xml2js.Builder(); res(builder.buildObject(json)); }); }); }