service-core/core/application.mjs

179 lines
5.5 KiB
JavaScript

import { EventEmitter } from 'events'
import fs from 'fs/promises'
export default class Application extends EventEmitter {
constructor(util, db, provider, name, opts = {}) {
super()
this.util = util
this.db = db
this.config = db.config[name] || { }
this.provider = provider
this.name = name
this.updating = false
Object.assign(this, {
setInterval: opts.setInterval || setInterval,
fs: opts.fs || fs,
})
this.db.addApplication(name)
}
startAutoupdater() {
if (this.provider.static) return
let timer = this.setInterval(() => {
this.update().then(
() => {
this.db.data.core[this.name].updater += 'Automatic update finished successfully. '
},
(err) => {
this.db.data.core[this.name].updater += 'Error while running automatic update: ' + err.message + '. '
}
)
}, (this.config.updateEvery || 180) * 60 * 1000)
timer.unref()
}
updateLog(message) {
this.db.data.core[this.name].updater += message
this.db.log.info(message)
return message
}
async update() {
if (this.updating) return
if (this.provider.static) {
this.updateLog('Provider in question is static and so no update required, nothing to do.')
return
}
this.updating = true
this.db.data.core[this.name].updater = ''
let cleanup = true
let folder = ''
let log = ''
let latest = null
try {
log += this.updateLog(`Checking for latest version at ${new Date().toISOString().replace('T', ' ').split('.')[0]}. `) + '\n'
latest = await this.provider.getLatestVersion()
log += this.updateLog(`Found ${latest.version}. `) + '\n'
if (this.db.data.core[this.name].latestInstalled === latest.version) {
this.updateLog('Already up to date, nothing to do. ')
this.updating = false
return
}
latest.id = latest.version
var found = this.db.get(this.db.data.core[this.name].versions, latest.id)
if (found) {
Object.keys(latest).forEach(function(key) {
found[key] = latest[key]
})
latest = found
log = latest.log + log
} else {
this.db.upsert(this.db.data.core[this.name].versions, latest)
}
if (latest.failtodownload && latest.failtodownload > 3) {
this.updateLog('Version failed to download too many times, skipping this version. ')
this.updating = false
return
}
if (latest.failtoinstall && latest.failtoinstall > 3) {
this.updateLog('Version failed to install too many times, skipping this version. ')
this.updating = false
return
}
let target = this.util.getPathFromRoot(`./${this.name}/${latest.version}/file${this.util.getExtension(latest.filename)}`)
folder = this.util.getPathFromRoot(`./${this.name}/${latest.version}`)
await this.fs.mkdir(folder, { recursive: true })
log += this.updateLog(`Downloading ${latest.link} to ${target}. `) + '\n'
await this.provider.downloadVersion(latest, target)
.catch(function(err) {
latest.failtodownload = (latest.failtodownload || 0) + 1
return Promise.reject(err)
})
log += '\n' + this.updateLog(`Extracting ${target}. `) + '\n'
await this.util.extractFile(target, function(msg) {
log += msg
}).catch(function(err) {
latest.failtodownload = (latest.failtodownload || 0) + 1
return Promise.reject(err)
})
await this.fs.rm(target, { force: true }).catch(function() {})
if (!log.endsWith('\n')) {
log += '\n'
}
if (!log.endsWith('\n\n')) {
log += '\n'
}
await this.fs.stat(this.util.getPathFromRoot(`./${this.name}/${latest.version}/index.mjs`))
.catch((err) => {
latest.failtodownload = (latest.failtodownload || 0) + 1
log += this.updateLog('Version did not include or was missing index.mjs. ') + '\n'
return Promise.reject(err)
})
cleanup = false
let packageStat = await this.fs.stat(this.util.getPathFromRoot(`./${this.name}/${latest.version}/package.json`))
.catch(function() { return null })
if (packageStat) {
log += this.updateLog(`running npm install --production. `) + '\n'
await this.util.runCommand(
'npm.cmd',
['install', '--production', '--no-optional', '--no-package-lock', '--no-audit', '--loglevel=notice'],
folder,
function(msg) {
log += msg
}
).catch(function(err) {
latest.failtoinstall = (latest.failtoinstall || 0) + 1
return Promise.reject(err)
})
if (!log.endsWith('\n')) {
log += '\n'
}
if (!log.endsWith('\n\n')) {
log += '\n'
}
} else {
log += this.updateLog('Release did not contain package.json, skipping npm install. ') + '\n'
}
} catch (err) {
this.updating = false
log += this.updateLog(`Error: ${err.message}. `) + '\n'
if (folder && cleanup) {
await this.fs.rm(folder, { force: true, recursive: true }).catch((err) => {
this.updateLog(`Error while cleaning up: ${err.message}. `)
})
}
if (latest) {
latest.log = log
}
return Promise.reject(err)
}
log += this.updateLog(`Finished updating ${this.name} to version ${latest.version}.`) + '\n'
this.db.data.core[this.name].latestInstalled = latest.version
latest.log = log
this.updating = false
}
}