Jonatan Nilsson
47344c5e7a
Some checks failed
continuous-integration/appveyor/branch AppVeyor build failed
Fixed some minor bugs. Will now no longer travel through history but instead stop at last stable version.
183 lines
6.1 KiB
JavaScript
183 lines
6.1 KiB
JavaScript
import Application from './application.mjs'
|
|
import Util from './util.mjs'
|
|
import getLog from './log.mjs'
|
|
import { Low } from 'lowdb'
|
|
import StaticProvider from './providers/static.mjs'
|
|
import GitProvider from './providers/git.mjs'
|
|
|
|
export default class Core {
|
|
static providers = new Map()
|
|
static addProvider(name, provider) {
|
|
if (!name || typeof(name) !== 'string')
|
|
throw new Error('addProvider name must be a string')
|
|
if (typeof(provider) !== 'function')
|
|
throw new Error(`addProvider ${name} provider must be a class`)
|
|
|
|
let test = new provider({})
|
|
if (typeof(test.checkConfig) !== 'function')
|
|
throw new Error(`addProvider ${name} provider class missing checkConfig`)
|
|
if (typeof(test.getLatestVersion) !== 'function')
|
|
throw new Error(`addProvider ${name} provider class missing getLatestVersion`)
|
|
|
|
Core.providers.set(name, provider)
|
|
}
|
|
|
|
constructor(db, util, log, restart = function() {}) {
|
|
// some sanity checks
|
|
if (!log || typeof(log) !== 'object') throw new Error('log parameter was invalid')
|
|
if (typeof(log.event) !== 'object') throw new Error('log parameter was invalid')
|
|
if (typeof(log.info) !== 'function'
|
|
|| typeof(log.warn) !== 'function'
|
|
|| typeof(log.error) !== 'function'
|
|
|| typeof(log.event.info) !== 'function'
|
|
|| typeof(log.event.warn) !== 'function'
|
|
|| typeof(log.event.error) !== 'function') throw new Error('log parameter was invalid')
|
|
if (!util || !(util instanceof Util)) throw new Error('util not instance of Util')
|
|
if (!db || !(db instanceof Low)) throw new Error('db not instance of Low')
|
|
if (typeof(restart) !== 'function') throw new Error('restart was not a function')
|
|
|
|
this.running = false
|
|
this.db = db
|
|
this.util = util
|
|
this.log = log
|
|
this.restart = restart
|
|
this.applications = []
|
|
this.applicationMap = new Map()
|
|
this._applicationFatalCrash = null
|
|
}
|
|
|
|
getApplication(name) {
|
|
return this.applicationMap.get(name)
|
|
}
|
|
|
|
async init() {
|
|
this.log.info(`Verifying config`)
|
|
|
|
this.util.verifyConfig(this.db.config)
|
|
let names = this.util.getAppNames(this.db.config)
|
|
|
|
this.log.info(`Found applications: ${names.join(', ')}.`)
|
|
|
|
for (let name of names) {
|
|
try {
|
|
let provConstructor = Core.providers.get(this.db.config[name].provider)
|
|
let provider = new provConstructor(this.db.config[name])
|
|
await provider.checkConfig(this.db.config[name])
|
|
|
|
let application = new Application({
|
|
db: this.db,
|
|
util: this.util,
|
|
log: getLog(name, this.db.config[name].log || null),
|
|
core: this,
|
|
}, provider, name)
|
|
this.applications.push(application)
|
|
this.applicationMap.set(name, application)
|
|
} catch (err) {
|
|
this.log.error(err, `Error creating application ${name} with provider ${this.db.config[name].provider}: ${err.message}`)
|
|
}
|
|
}
|
|
|
|
if (names.length && !this.applications.length) {
|
|
return Promise.reject(new Error('None of the application were successful in running'))
|
|
}
|
|
}
|
|
|
|
async run() {
|
|
if (this.running) return
|
|
this.running = true
|
|
|
|
this.log.info(`Running updater on ${this.applications.length} apps`)
|
|
await Promise.all(this.applications.map((app) => {
|
|
return app.update().catch(err => {
|
|
app.ctx.log.error(err, `Error updating: ${err.message}`)
|
|
})
|
|
}))
|
|
|
|
let found = false
|
|
|
|
for (let app of this.applications) {
|
|
app.startAutoupdater()
|
|
|
|
await this.runApplication(app).then(
|
|
() => {
|
|
found = true
|
|
},
|
|
err => {
|
|
app.ctx.log.error(err, `Error running: ${err.message}`)
|
|
}
|
|
)
|
|
|
|
app.on('updated', this.runApplication.bind(this, app))
|
|
}
|
|
|
|
if (!found) {
|
|
throw new Error('No stable application was found')
|
|
}
|
|
}
|
|
|
|
criticalError(application, version, errorCode) {
|
|
application.ctx.log.fatal(`Critical error ${errorCode} running ${version.version}`)
|
|
version.stable = -2
|
|
this.db.writeSync()
|
|
}
|
|
|
|
async runApplication(application) {
|
|
let name = application.name
|
|
let found = false
|
|
|
|
if (!this.db.data.core[name].versions.length) {
|
|
return Promise.reject(new Error(`No versions were found`))
|
|
}
|
|
|
|
for (let i = 0; i < this.db.data.core[name].versions.length; i++) {
|
|
let version = this.db.data.core[name].versions[i]
|
|
if (!version.installed || version.stable < -1) continue
|
|
if (version.stable < 0 && !application.fresh) {
|
|
application.ctx.log.warn(`Restarting for ${version.version} due to last run failing while not being in fresh state`)
|
|
return this.restart(`Application ${name} has fresh false while attempting to run ${version.version} with stable -1`)
|
|
}
|
|
await application.closeServer()
|
|
|
|
this._applicationFatalCrash = this.criticalError.bind(this, application, version)
|
|
process.once('exit', this._applicationFatalCrash)
|
|
|
|
let wasFresh = application.fresh
|
|
|
|
try {
|
|
application.ctx.log.info(`Attempting to run version ${version.version}`)
|
|
await application.runVersion(version.version)
|
|
found = true
|
|
version.stable = 1
|
|
await this.db.write()
|
|
break
|
|
} catch(err) {
|
|
application.ctx.log.error(err, `Error starting ${version.version}: ${err.message}`)
|
|
process.off('exit', this._applicationFatalCrash)
|
|
|
|
if (version.stable < 1) {
|
|
if (wasFresh) {
|
|
version.stable = -2
|
|
} else {
|
|
version.stable = -1
|
|
}
|
|
await this.db.write()
|
|
if (version.stable === -1) {
|
|
return this.restart(`Application ${name} version ${version.version} failed to start but application was dirty, check if restarting fixes it`)
|
|
}
|
|
} else {
|
|
await this.db.write()
|
|
return this.restart(`Application ${name} version ${version.version} previously stable but now failing`)
|
|
}
|
|
} finally {
|
|
process.off('exit', this._applicationFatalCrash)
|
|
}
|
|
}
|
|
|
|
if (!found) {
|
|
return Promise.reject(Error(`No stable versions were found`))
|
|
}
|
|
}
|
|
}
|
|
|
|
Core.addProvider('static', StaticProvider)
|
|
Core.addProvider('git', GitProvider)
|