From 447766c752af04ee8711513a7caea6c32a8451df Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Vest=C3=B8l?= Date: Sat, 16 Jun 2018 15:41:06 +0200 Subject: [PATCH] Fixed mod manager not exiting after downloading mods --- client.js | 43 ++-- lib/manager/modManager.js | 322 ++++++++++++++------------ package.json | 2 + sharedPlugins/remoteCommands/index.js | 2 +- 4 files changed, 206 insertions(+), 163 deletions(-) diff --git a/client.js b/client.js index 835e42f8..a853935e 100644 --- a/client.js +++ b/client.js @@ -158,7 +158,7 @@ if (!command || command == "help" || command == "--help") { }); displayLines.forEach(line => console.log(line)); - process.exit(1); + process.exit(0); } else if (command == "manage"){ // console.log("Launching mod manager"); //const fullUsage = 'node client.js manage [instance, "shared"] ["mods", "config"] ...'; @@ -175,20 +175,26 @@ if (!command || command == "help" || command == "--help") { const action = process.argv[5] || ""; if(instance){ if(tool == "mods"){ - // allow managing mods - if(action == "list"){ - modManager.listMods(instance); - } else if(action == "search"){ - modManager.findMods(process.argv[6]); - } else if(action == "add" || action == "download"){ - modManager.addMod(process.argv[6], instance); - } else if(action == "remove" || action == "rm" || action == "delete"){ - modManager.removeMod(process.argv[6], instance); - } else if(action == "update"){ - modManager.updateAllMods(); - } else { - usage(instance, tool); - } + (async function(){try{ + // allow managing mods + if(action == "list"){ + console.log(await modManager.listMods(instance)); + } else if(action == "search"){ + console.log(await modManager.findMods(process.argv[6])); + } else if(action == "add" || action == "download"){ + await modManager.addMod(process.argv[6], instance); + } else if(action == "remove" || action == "rm" || action == "delete"){ + await modManager.removeMod(process.argv[6], instance); + } else if(action == "update"){ + await modManager.updateAllMods(); + } else { + usage(instance, tool); + } + process.exit(0); + }catch(e){ + console.log("Got error from modManager:") + console.log(e); + }})(); } else if(tool == "config"){ // allow managing the config if(action == "list" || action == "show" || action == "display"){ @@ -213,7 +219,7 @@ if (!command || command == "help" || command == "--help") { console.log('Usage:'); usage(instance); } - // process.exit(1); + // process.exit(0); } else if (command == "delete") { if (!process.argv[3]) { console.error("Usage: node client.js delete [instance]"); @@ -221,10 +227,10 @@ if (!command || command == "help" || command == "--help") { } else if (typeof process.argv[3] == "string" && fs.existsSync("./instances/" + process.argv[3]) && process.argv[3] != "/" && process.argv[3] != "") { fileOps.deleteFolderRecursiveSync("./instances/" + process.argv[3]); console.log("Deleted instance " + process.argv[3]); - process.exit(1); + process.exit(0); } else { console.error("Instance not found: " + process.argv[3]); - process.exit(1); + process.exit(0); } } else if (command == "download") { console.log("Downloading mods..."); @@ -238,6 +244,7 @@ if (!command || command == "help" || command == "--help") { https.get(url, function(response) { response.pipe(file); console.log("Downloaded "+name); + process.exit(0); }); } } else if (command == "start" && instance === undefined) { diff --git a/lib/manager/modManager.js b/lib/manager/modManager.js index fec45562..022fd013 100644 --- a/lib/manager/modManager.js +++ b/lib/manager/modManager.js @@ -11,6 +11,7 @@ const fs = require("fs"); const https = require('follow-redirects').https; const factorioAPI = require("node-factorio-api"); const sLog = require("single-line-log").stdout; +const query = require('cli-interact').getYesNo; const fileOps = require("_app/fileOps"); const config = require("./../../config"); @@ -35,56 +36,62 @@ modManager.listMods("shared"); // console.logs mods located in /sharedMods as a nice table */ module.exports.listMods = function(instance){ - if(instance && instances.includes(instance)){ - factorioAPI.init(false, 'instances/'+instance+'/instanceMods', 'instances/'+instance+'/saves', config.factorio_version); - factorioAPI.authenticate({ - username: config.username, - token: config.token, - require_ownership: false - }).then(token => { - console.log("* Currently installed:"); - factorioAPI.readModZips().then(list => { - console.log(asTable(list.map(mod => { - return { - name:(mod.title || mod.name), - version:mod.version, - date:mod.date, - factorio_ver:mod.factorio_version, - author:mod.author, - } - }))); + return new Promise((resolve, reject) => { + if(instance && instances.includes(instance)){ + factorioAPI.init(false, 'instances/'+instance+'/instanceMods', 'instances/'+instance+'/saves', config.factorio_version); + factorioAPI.authenticate({ + username: config.username, + token: config.token, + require_ownership: false + }).then(token => { + console.log("* Currently installed:"); + factorioAPI.readModZips().then(list => { + console.log(asTable(list.map(mod => { + return { + name:(mod.title || mod.name), + version:mod.version, + date:mod.date, + factorio_ver:mod.factorio_version, + author:mod.author, + } + }))); + }); + // Had issues earlier due to bug in node-factorio-api, see https://github.com/Danacus/node-factorio-api/issues/2 + // bug is resolved, thanks to @Danacus and @brotherpot + factorioAPI.getModsFromSaves().then(list => { + console.log("* Mods used in save:"); + console.log(asTable(list[0].mods)) + }); + }).catch(reason => { + console.log("Failed to authenticate to factorio.com! Please check your connection and the username+token used for authentication in config.json"); + resolve(); }); - // Had issues earlier due to bug in node-factorio-api, see https://github.com/Danacus/node-factorio-api/issues/2 - // bug is resolved, thanks to @Danacus and @brotherpot - factorioAPI.getModsFromSaves().then(list => { - console.log("* Mods used in save:"); - console.log(asTable(list[0].mods)) + } else { + // list shared mods in /sharedMods/ + factorioAPI.init(false, 'sharedMods/', '', config.factorio_version); + factorioAPI.authenticate({ + username: config.username, + token: config.token, + require_ownership: false + }).then(() => { + console.log("\r\n") + console.log("* Mods shared by all instances:") + factorioAPI.getInstalledMods().then(mods => { + console.log(asTable(mods)); + resolve(); + }); + }).catch(e => { + reject(new Error(e)); }); - }).catch(reason => { - console.log("Failed to authenticate to factorio.com! Please check your connection and the username+token used for authentication in config.json"); - }); - } else { - // list shared mods in /sharedMods/ - factorioAPI.init(false, 'sharedMods/', '', config.factorio_version); - factorioAPI.authenticate({ - username: config.username, - token: config.token, - require_ownership: false - }).then(() => { - console.log("\r\n") - console.log("* Mods shared by all instances:") - factorioAPI.getInstalledMods().then(mods => { - console.log(asTable(mods)); - }); - }); - } - - // get JSON data about GH releases - /*let res = syncRequest('GET', 'https://api.github.com/repos/Danielv123/factorioClusterioMod/releases', {"headers":{"User-Agent":"Fuck you for requiring user agents!"}}); - let url = JSON.parse(res.getBody())[0].assets[0].browser_download_url; - let name = JSON.parse(res.getBody())[0].assets[0].name; - console.log(JSON.parse(res.getBody())) - */ + } + + // get JSON data about GH releases + /*let res = syncRequest('GET', 'https://api.github.com/repos/Danielv123/factorioClusterioMod/releases', {"headers":{"User-Agent":"Fuck you for requiring user agents!"}}); + let url = JSON.parse(res.getBody())[0].assets[0].browser_download_url; + let name = JSON.parse(res.getBody())[0].assets[0].name; + console.log(JSON.parse(res.getBody())) + */ + }); } /** Searches mods.factorio.com for mods matching a search term and prints @@ -93,116 +100,143 @@ the results to console as a neat looking table @param {string} searchTerm What to search for */ module.exports.findMods = function(searchTerm){ - factorioAPI.init(false); - factorioAPI.authenticate({ - username: config.username, - token: config.token, - require_ownership: false - }).then(token => { - factorioAPI.searchMods(searchTerm).then(mods => { - console.log(asTable(mods.reverse().map(mod => { - return { - title:ellipse(mod.title, 50), - name:ellipse(mod.name, 30), - downloads:mod.downloads_count, - updated: moment(mod.updated_at).format("DD.MM.YY"), - latest_version: mod.latest_release.version, - owner:mod.owner, - //license: mod.license_name, - } - }))) - }) + return new Promise((resolve, reject) => { + factorioAPI.init(false); + factorioAPI.authenticate({ + username: config.username, + token: config.token, + require_ownership: false + }).then(token => { + factorioAPI.searchMods(searchTerm).then(mods => { + let result = asTable(mods.reverse().map(mod => { + return { + title:ellipse(mod.title, 50), + name:ellipse(mod.name, 30), + downloads:mod.downloads_count, + updated: moment(mod.updated_at).format("DD.MM.YY"), + latest_version: mod.latest_release.version, + owner:mod.owner, + //license: mod.license_name, + } + })); + resolve(result); + // console.log(result); + }); + }).catch(e => { + if(e.contains("Insufficient information")) console.log("We are missing some parameters required for logging in! Make sure your factorio username and token are specified in config.json."); + reject(new Error(e)); + }); }); } module.exports.addMod = function(term, instance){ - if(instance == "shared"){ // modDirectory has to end in / - var modDirectory = "sharedMods/"; - } else { - var modDirectory = "instances/"+instance+"/instanceMods/"; - } - if(term && term.length > 0){ - if(term.includes("mods.factorio.com/mods/")){ // https://mods.factorio.com/mods/Danielv123/ChooChoo - // treat it as a link download - factorioAPI.init(false, modDirectory, "", config.factorio_version); - factorioAPI.authenticate({ - username: config.username, - token: config.token, - require_ownership: false - }).then(() => { - factorioAPI.searchMods(term.split("/")[term.split("/").length-1]).then(body => { - console.log("Im gonna download: "+body[0].name + " in version: " + body[0].latest_release.version); - factorioAPI.downloadMod( {name: body[0].name, version: body[0].latest_release.version}).then(()=>{ - console.log("Mod downloaded"); + return new Promise((resolve, reject) => { + if(instance == "shared"){ // modDirectory has to end in / + var modDirectory = "sharedMods/"; + } else { + var modDirectory = "instances/"+instance+"/instanceMods/"; + } + if(term && term.length > 0){ + if(term.includes("mods.factorio.com/mods/")){ // https://mods.factorio.com/mods/Danielv123/ChooChoo + // treat it as a link download + factorioAPI.init(false, modDirectory, "", config.factorio_version); + factorioAPI.authenticate({ + username: config.username, + token: config.token, + require_ownership: false + }).then(() => { + factorioAPI.searchMods(term.split("/")[term.split("/").length-1]).then(body => { + console.log("Im gonna download: "+body[0].name + " in version: " + body[0].latest_release.version); + factorioAPI.downloadMod( {name: body[0].name, version: body[0].latest_release.version}).then(()=>{ + console.log("Mod downloaded"); + resolve(); + }); }); }); - }); - } else if(term.includes("github.com")){ // https://github.com/Danielv123/factorioClusterioMod - // treat it as a github releases download - let apiURL = "https://api.github.com/repos/" + term.split("/")[3] + "/" + term.split("/")[4] + "/releases"; // https://api.github.com/repos/Danielv123/factorioClusterioMod/releases - - let res = syncRequest('GET', apiURL, {"headers":{"User-Agent":"Fuck you for requiring user agents!"}}); - let url = JSON.parse(res.getBody())[0].assets[0].browser_download_url; - let name = JSON.parse(res.getBody())[0].assets[0].name; - if(url) { - console.log("Downloading " + url); - let file = fs.createWriteStream(modDirectory + name); - let bytesDownloaded = 0; - let downloadStartTime = Date.now(); - https.get(url, function(response) { - let bytesToDownload = response.headers['content-length']; - response.pipe(file); - response.on("data", chunk => { - bytesDownloaded += chunk.length; - let downloadTimeElapsed = Date.now() - downloadStartTime; - let bytesPerSecond = bytesDownloaded / (downloadTimeElapsed/1000); - let timeToComplete = Math.floor((bytesToDownload - bytesDownloaded)/bytesPerSecond); - sLog("Downloading "+name+" "+(bytesDownloaded/bytesToDownload*100).toPrecision(3)+"% ("+formatBytes(bytesDownloaded)+" / "+formatBytes(bytesToDownload)+")\r\n"+ - "about "+timeToComplete+" seconds remaining ("+formatBytes(bytesPerSecond)+"/s)"); - }).on("end", x => { - sLog.clear(); - console.log(" Downloaded in "+moment.utc(moment.duration(Date.now()-downloadStartTime).as('milliseconds')).format('mm:ss')); // because sLog.clear() doesn't seem to do the job of ending the line properly + } else if(term.includes("github.com")){ // https://github.com/Danielv123/factorioClusterioMod + // treat it as a github releases download + let apiURL = "https://api.github.com/repos/" + term.split("/")[3] + "/" + term.split("/")[4] + "/releases"; // https://api.github.com/repos/Danielv123/factorioClusterioMod/releases + + let res = syncRequest('GET', apiURL, {"headers":{"User-Agent":"Fuck you for requiring user agents!"}}); + let url = JSON.parse(res.getBody())[0].assets[0].browser_download_url; + let name = JSON.parse(res.getBody())[0].assets[0].name; + if(url) { + console.log("Downloading " + url); + let file = fs.createWriteStream(modDirectory + name); + let bytesDownloaded = 0; + let downloadStartTime = Date.now(); + https.get(url, function(response) { + let bytesToDownload = response.headers['content-length']; + response.pipe(file); + response.on("data", chunk => { + bytesDownloaded += chunk.length; + let downloadTimeElapsed = Date.now() - downloadStartTime; + let bytesPerSecond = bytesDownloaded / (downloadTimeElapsed/1000); + let timeToComplete = Math.floor((bytesToDownload - bytesDownloaded)/bytesPerSecond); + sLog("Downloading "+name+" "+(bytesDownloaded/bytesToDownload*100).toPrecision(3)+"% ("+formatBytes(bytesDownloaded)+" / "+formatBytes(bytesToDownload)+")\r\n"+ + "about "+timeToComplete+" seconds remaining ("+formatBytes(bytesPerSecond)+"/s)"); + }).on("end", x => { + sLog.clear(); + console.log(" Downloaded in "+moment.utc(moment.duration(Date.now()-downloadStartTime).as('milliseconds')).format('mm:ss')); // because sLog.clear() doesn't seem to do the job of ending the line properly + resolve(); + }); + }); + } + } else { + // treat it as a search and download the top result + factorioAPI.init(false, modDirectory, "", config.factorio_version); + factorioAPI.authenticate({ + username: config.username, + token: config.token, + require_ownership: false + }).then(() => { + factorioAPI.searchMods(term).then(body => { + console.log(body) + console.log("Im gonna download: "+body[0].name + " in version: " + body[0].latest_release.version); + factorioAPI.downloadMod( {name: body[0].name, version: body[0].latest_release.version}).then(()=>{ + console.log("Mod downloaded"); + resolve(); + }); }); }); } } else { - // treat it as a search and download the top result - factorioAPI.init(false, modDirectory, "", config.factorio_version); - factorioAPI.authenticate({ - username: config.username, - token: config.token, - require_ownership: false - }).then(() => { - factorioAPI.searchMods(term).then(body => { - console.log("Im gonna download: "+body[0].name + " in version: " + body[0].latest_release.version); - factorioAPI.downloadMod( {name: body[0].name, version: body[0].latest_release.version}).then(()=>{ - console.log("Mod downloaded"); - }); - }); - }); + reject(new Error("Invalid search term")); } - } + }); } module.exports.removeMod = function removeMod(term, instance, force = false){ - if(instance == "shared"){ // modDirectory has to end in / - var modDirectory = "sharedMods/"; - } else { - var modDirectory = "instances/"+instance+"/instanceMods/"; - } - if(term && typeof term == "string" && term.length > 0){ - let mods = fs.readdirSync(modDirectory); - let modsMatchingFilter = mods.filter(mod => mod.toLowerCase().includes(term.toLowerCase())); - if(modsMatchingFilter.length < 1){ - console.log("No mods found matching search"); - } else if(modsMatchingFilter.length == 1){ - console.log("Deleting "+modsMatchingFilter[0]); - fs.unlinkSync(modDirectory+modsMatchingFilter[0]); - console.log("Deleted."); - } else if(modsMatchingFilter.length > 1){ - console.log("Found multiple mods, not doing anything"); - modsMatchingFilter.forEach(mod => console.log(mod)); + return new Promise((resolve, reject) => { + if(instance == "shared"){ // modDirectory has to end in / + var modDirectory = "sharedMods/"; + } else { + var modDirectory = "instances/"+instance+"/instanceMods/"; } - } + if(term && typeof term == "string" && term.length > 0){ + let mods = fs.readdirSync(modDirectory); + let modsMatchingFilter = mods.filter(mod => mod.toLowerCase().includes(term.toLowerCase())); + if(modsMatchingFilter.length < 1){ + console.log("No mods found matching search"); + } else if(modsMatchingFilter.length == 1){ + console.log("Deleting "+modsMatchingFilter[0]); + fs.unlinkSync(modDirectory+modsMatchingFilter[0]); + console.log("Deleted."); + } else if(modsMatchingFilter.length > 1){ + console.log("Found multiple mods"); + modsMatchingFilter.forEach(mod => console.log(mod)); + if(query("Delete all mods matching filter?")){ + let modsToDelete = modsMatchingFilter.length; + for(let i = 0; i < modsToDelete; i++){ + fs.unlinkSync(modDirectory+modsMatchingFilter[i]); + console.log("Deleted "+modsMatchingFilter[i]); + } + } else console.log("Did not delete mods.") + } + resolve(); + } else { + reject(new Error("Invalid search term")); + } + }); } // 'https://api.github.com/repos/Danielv123/factorioClusterioMod/releases' diff --git a/package.json b/package.json index 6cacc99c..e21197f1 100644 --- a/package.json +++ b/package.json @@ -27,6 +27,7 @@ "bcryptjs": "^2.4.3", "body-parser": "^1.18.2", "cache-require-paths": "^0.3.0", + "cli-interact": "^0.1.9", "codecov": "^3.0.1", "compression": "^1.7.2", "deepmerge": "^1.5.2", @@ -56,6 +57,7 @@ "request": "^2.83.0", "right-pad": "^1.0.1", "rmdir-sync": "^1.0.1", + "sanitizer": "^0.1.3", "single-line-log": "^1.1.2", "socket.io": "^2.0.4", "socket.io-client": "^2.0.4", diff --git a/sharedPlugins/remoteCommands/index.js b/sharedPlugins/remoteCommands/index.js index 98dc11a6..62a7df20 100644 --- a/sharedPlugins/remoteCommands/index.js +++ b/sharedPlugins/remoteCommands/index.js @@ -22,4 +22,4 @@ module.exports = class remoteCommands { scriptOutput(data){ // we don't return anything yet } -} \ No newline at end of file +}