From 8952c93f2cf7b2fdd3354e766a67e320f6977f0f Mon Sep 17 00:00:00 2001 From: Jonatan Nilsson Date: Sat, 12 Sep 2020 20:31:36 +0000 Subject: [PATCH] Fixed last few issues and bugs --- .gitignore | 1 + app/v1.0.1.5/v1.0.1.5.zip | Bin 1318 -> 0 bytes core/client.mjs | 29 ++++++++++---- core/core.mjs | 79 +++++++++++++++++++++++++++++++++----- core/db.mjs | 1 + core/http.mjs | 7 +++- install.bat | 3 +- service/service.mjs | 1 + 8 files changed, 101 insertions(+), 20 deletions(-) delete mode 100644 app/v1.0.1.5/v1.0.1.5.zip diff --git a/.gitignore b/.gitignore index a7c31ee..51df9ba 100644 --- a/.gitignore +++ b/.gitignore @@ -107,6 +107,7 @@ dist db.json package-lock.json +daemon app/* manage/* dev/public/main.js diff --git a/app/v1.0.1.5/v1.0.1.5.zip b/app/v1.0.1.5/v1.0.1.5.zip deleted file mode 100644 index 760124a87f5c57b0ab603b948988edf4d8483e0f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1318 zcmWIWW@Zs#U|`^25NuKjtg_dZ&Ia=40Wl|o3`1sKN@|5(ZdP$<2qyz`Vn$GW5)hYG za5FHnWbraEfQi!HgIp~JJTC9+T=TXme4TwqYHPQzim$7{|GQngw(sTbuQcAFtHb52 zw!V>bQrV(o#=MC+3;vrJ6m!mF)qNw{upmv5N$1DLTuC>~bddiBCfuWd*fq@6;+JeO7?8Nj`y{zK=JbVtG z8f5E#*g)X!Z*4!vS4_SdNw0W18XFe|P3O`q?Yj~BX7jr_TSBk?@0+_sK4-(t_jjw` ze|htmMWJ}<(HzE^D`p;BwotY(IF-Ni)r6xHyx-W=pLxz4wNS&%uIEg(&_S)03%vWu8y;wlRkWVRkR^6=~T;G3&v6UE1@{oDF_4~U^Qx~_M|a|u?gcV;tu*3t6+Th}x1 z2+O0xrAG@s)W&b+eBLu{w&2d|iWQL}t~RgBCTnjx8uU0wI$V6e)Vaz3ghIAC3ad|E zI74mQ^Cjmab?@8Rvz1)FW**zSvffXp$D_N5_iD<;>8AfqKkeJNMrYoBr|(U2$$$MM z_uR~_Iq>AqSCReaisxHd`qnX^hX48Fr@WT}!@r7|fq@Sg{)q*d`o*b5WvNAklFZt` zgLzjB1ol4He%6rU?xMEJqOpo4l;dDmYw_!}$x|+W) z%R8TJO<5EdB5L5j0b5Vh$1S_!IGwIsEVI6A`{J=z(fhTNwM&(!RGClXDwW?O>}~D+xKIE0 z`}^&0X)L`>Z={eD!@BFK=q3$HHIEW{*VAPY}ChgPf;a!df6e1iOmyhj`MTP&zU0rv~b*Fi(lS#AEjN ztma#j=Y^b6dFOsSoA%jv@1}qDc6LYqhzEExGRZOHDjXz$MFax_F!mXiG=f-2MFlIQ zs6Z= 300 && res.statusCode < 400) { - if (redirects > 5) { + if (newRedirects > 5) { return reject(new Error(`Too many redirects (last one was ${res.headers.location})`)) } - return resolve(request(res.headers.location, filePath, redirects + 1)) + if (!res.headers.location) { + return reject(new Error('Redirect returned no path in location header')) + } + if (res.headers.location.startsWith('http')) { + return resolve(request(res.headers.location, filePath, newRedirects, returnText)) + } else { + return resolve(request(url.resolve(path, res.headers.location), filePath, newRedirects, returnText)) + } } else if (res.statusCode >= 400) { - return reject(new Error(`HTTP Error ${statusCode}: ${output}`)) + return reject(new Error(`HTTP Error ${res.statusCode}: ${output}`)) } resolve({ statusCode: res.statusCode, @@ -54,10 +66,13 @@ export function request(path, filePath = null, redirects = 0) { }) }) req.on('error', reject) + req.on('timeout', function(err) { + reject(err) + }) }) req.end() }).then(function(res) { - if (!filePath) { + if (!filePath && !returnText) { try { res.body = JSON.parse(res.body) } catch(e) { diff --git a/core/core.mjs b/core/core.mjs index 3c220aa..d1abf84 100644 --- a/core/core.mjs +++ b/core/core.mjs @@ -8,20 +8,24 @@ const fsp = fs.promises export default class Core extends EventEmitter{ constructor(util, config, db, log, closeCb) { super() + process.stdin.resume() this.http = new HttpServer() this.util = util this.config = config this.db = db this.log = log this._close = closeCb + this._activeCrashHandler = null this.appRunning = false this.manageRunning = false this._appUpdating = { + fresh: true, updating: false, starting: false, logs: '', } this._manageUpdating = { + fresh: true, updating: false, starting: false, logs: '', @@ -114,6 +118,9 @@ export default class Core extends EventEmitter{ if (fs.existsSync(this.util.getPathFromRoot(`./${name}/` + version.name))) { await this.util.runCommand('rmdir', ['/S', '/Q', `"${this.util.getPathFromRoot(`./${name}/` + version.name)}"`]) } + if (!fs.existsSync(this.util.getPathFromRoot(`./${name}/`))) { + await fsp.mkdir(this.util.getPathFromRoot(`./${name}/`)) + } try { await fsp.mkdir(this.util.getPathFromRoot(`./${name}/` + version.name)) } catch(err) { @@ -195,7 +202,8 @@ export default class Core extends EventEmitter{ this.logActive(name, active, `[${name}] Finding available version of ${name}\n`) for (let i = 0; i < history.length; i++) { - if (history[i].stable < 0) { + if ((history[i].stable === -1 && !active.fresh) + || (history[i].stable < -1)) { this.logActive(name, active, `[${name}] Skipping version ${history[i].name} due to marked as unstable\n`) continue } @@ -208,11 +216,16 @@ export default class Core extends EventEmitter{ if (running) { history[i].stable = 1 } else { - history[i].stable = -1 + if (active.fresh || history[i].stable === -1) { + history[i].stable = -2 + } else { + history[i].stable = -1 + } await this.db.set(`core.${name}Active`, null) .write() this.emit('dbupdated', {}) } + active.fresh = false await this.db.get(`core_${name}History`).updateById(history[i].id, history[i].stable).write() if (history[i].stable > 0) break @@ -227,6 +240,17 @@ export default class Core extends EventEmitter{ active.starting = false } + programCrashed(name, version, active, oldStable) { + let newStable = -2 + console.log('EXITING:', oldStable, active) + if (oldStable === 0 && !active.fresh) { + newStable = -1 + } + let temp = this.db.get(`core_${name}History`).getById(version).set('stable', newStable ) + temp.value() // Trigger update on __wrapped__ + fs.writeFileSync(this.db.adapterFilePath, JSON.stringify(temp.__wrapped__, null, 2)) + } + async tryStartProgramVersion(name, active, version) { if (!version) return false this.logActive(name, active, `[${name}] Attempting to start ${version}\n`) @@ -242,10 +266,15 @@ export default class Core extends EventEmitter{ this.log.error(err, `Failed to load ${indexPath}`) return false } + let checkTimeout = null + let oldStable = this.db.get(`core_${name}History`).getById(version).value().stable + this._activeCrashHandler = this.programCrashed.bind(this, name, version, active, oldStable) + process.once('exit', this._activeCrashHandler) try { + let port = name === 'app' ? this.config.port : this.config.managePort await new Promise((res, rej) => { - let checkTimeout = setTimeout(function() { + checkTimeout = setTimeout(function() { rej(new Error('Program took longer than 60 seconds to resolve promise')) }, 60 * 1000) @@ -253,14 +282,20 @@ export default class Core extends EventEmitter{ try { this.http.setContext(name) - this.startModule(module, name === 'app' ? this.config.port : this.config.managePort) + this.startModule(module, port) .then(res, rej) } catch (err) { rej(err) } }) + clearTimeout(checkTimeout) + + this.logActive(name, active, `[${name}] Testing out module port ${version}\n`) + await this.checkProgramRunning(name, active, port) + process.off('exit', this._activeCrashHandler) } catch (err) { clearTimeout(checkTimeout) + process.off('exit', this._activeCrashHandler) await this.http.closeServer(name) this.logActive(name, active, `[${name}] Error starting\n`, true) @@ -268,15 +303,12 @@ export default class Core extends EventEmitter{ this.log.error(err, `Failed to start ${name}`) return false } - clearTimeout(checkTimeout) + this._activeCrashHandler = null this.logActive(name, active, `[${name}] Successfully started version ${version}\n`) await this.db.set(`core.${name}Active`, version) .write() - let port = name === 'app' ? this.config.port : this.config.managePort - this.logActive(name, active, `[${name}] Checking if listening to port ${port}\n`) - if (name === 'app') { this.appRunning = true } else { @@ -289,6 +321,26 @@ export default class Core extends EventEmitter{ return true } + async checkProgramRunning(name, active, port) { + let start = new Date() + let error = null + let success = false + + while (new Date() - start < 10 * 1000) { + try { + let check = await request(`http://localhost:${port}`, null, 0, true) + success = true + break + } catch(err) { + this.logActive(name, active, `[${name}:${port}] ${err.message}, retrying in 3 seconds\n`) + error = err + await new Promise(function(res) { setTimeout(res, 3000)}) + } + } + if (success) return true + throw error || new Error('Checking server failed') + } + async updateProgram(name) { if (!this.config[name + 'Repository']) { if (name === 'app') { @@ -302,6 +354,11 @@ export default class Core extends EventEmitter{ } let active = this.getActive(name) + let oldLogs = active.logs || '' + if (oldLogs) { + oldLogs += '\n' + } + active.logs = '' active.updating = true this.emit('statusupdated', {}) @@ -329,7 +386,7 @@ export default class Core extends EventEmitter{ this.logActive(name, active, '\n', true) this.logActive(name, active, `[Error] Exception occured while updating ${name}\n`, true) this.logActive(name, active, err.stack, true) - this.log.error(err, 'Error while updating ' + name) + this.log.error('Error while updating ' + name, err) } active.updating = false if (version && !found) { @@ -341,9 +398,11 @@ export default class Core extends EventEmitter{ description: version.description, logs: active.logs, stable: 0, - installed: installed, + installed: installed && installed.toISOString(), }).write() } + active.logs = oldLogs + active.logs + this.emit(name + 'log', active) this.emit('statusupdated', {}) } diff --git a/core/db.mjs b/core/db.mjs index 970a58f..bd80ad3 100644 --- a/core/db.mjs +++ b/core/db.mjs @@ -137,6 +137,7 @@ export default function GetDB(util, log) { return lowdb(adapter) .then(function(db) { db._.mixin(lodashId) + db.adapterFilePath = util.getPathFromRoot('./db.json') db.defaults({ core: { diff --git a/core/http.mjs b/core/http.mjs index 22e0206..0b20942 100644 --- a/core/http.mjs +++ b/core/http.mjs @@ -19,6 +19,7 @@ export default class HttpServer { if (name !== 'app' && name !== 'manage' && name !== 'dev') { throw new Error('Cannot call setContext with values other than app or manage') } + this._context = name } createServer(opts, listener) { @@ -45,7 +46,7 @@ export default class HttpServer { } closeServer(name) { - if (!this.active[name]) return + if (!this.active[name]) return console.log('no active found with name', name, this.active) return new Promise((res, rej) => { this.sockets[name].forEach(function(socket) { @@ -55,7 +56,9 @@ export default class HttpServer { this.active[name].close(function(err) { if (err) return rej(err) - res() + + // Waiting 1 second for it to close down + setTimeout(res, 1000) }) }) } diff --git a/install.bat b/install.bat index 351618a..acfc9a5 100644 --- a/install.bat +++ b/install.bat @@ -1 +1,2 @@ -node service\install.mjs \ No newline at end of file +node service\install.mjs +PAUSE \ No newline at end of file diff --git a/service/service.mjs b/service/service.mjs index cadd83c..3ba6f80 100644 --- a/service/service.mjs +++ b/service/service.mjs @@ -1,5 +1,6 @@ import path from 'path' import { readFileSync } from 'fs' +import { fileURLToPath } from 'url' import nodewindows from 'node-windows' function getPathFromRoot(add) {