import { ManaPlusApp } from "./manaApp/manaApp.interface"; import { ManaPlusAppWindows } from "./manaApp/windows"; import * as os from "os"; import * as path from "path"; import * as fs from "fs-extra"; import { app, ipcMain, shell, dialog } from "electron"; import { Status, EventEmitter } from "../status"; import { ManaPlusAppLinux } from "./manaApp/linux"; 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(); 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.on("getScreenshots", (event: any, arg: string) => { const screenshotsDir = path.normalize( app.getPath("userData") + `/screenshots/${arg}/` ); fs.existsSync(screenshotsDir) || fs.mkdirSync(screenshotsDir); fs.readdir(screenshotsDir, (err, dir) => { let screenshots: string[] = []; for (var i = 0, path; (path = dir[i]); i++) { screenshots.push(path); } event.sender.send("getScreenshots", { dir: screenshotsDir, screenshots: screenshots.reverse().slice(0, 24), }); }); }); EventEmitter.on("Mana:openScreenshotDir", () => { shell.openItem( path.normalize( app.getPath("userData") + `/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 = path.normalize(app.getPath("userData") + "/mana_config"); const localDataDir = path.normalize( app.getPath("userData") + "/mana_local_data" ); const screenshotsDir = path.normalize( app.getPath("userData") + `/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 = require("child_process").execFile( gameExe, parameters, 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 dialog = await dialogPromiseWrapper(options); console.log("....", dialog); return dialog === 1; } function dialogPromiseWrapper(options: any): Promise { return new Promise((res, rej) => { dialog.showMessageBox(options, (index) => { res(index); }); }); } const default_server_config = '\ \ '; const parseString = require("xml2js").parseString, xml2js = require("xml2js"); async function setSkipUpdateWindows(server: string) { const serverConfigXML = path.normalize( app.getPath("userData") + `/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)); }); }); }