Make service-core librariable

This commit is contained in:
Jonatan Nilsson 2020-09-08 08:11:42 +00:00
parent a7c5cee7da
commit e0413bbaa6
11 changed files with 117 additions and 66 deletions

View file

@ -4,8 +4,6 @@
"description": "NodeJS Test Service", "description": "NodeJS Test Service",
"port": 4270, "port": 4270,
"managePort": 4269, "managePort": 4269,
"hasManage": true,
"appRepository": "thething/sc-helloworld", "appRepository": "thething/sc-helloworld",
"manageRepository": null, "manageRepository": null
"useDev": true
} }

View file

@ -1,13 +1,13 @@
import fs from 'fs' import fs from 'fs'
import { EventEmitter } from 'events' import { EventEmitter } from 'events'
import { request } from './client.mjs' import { request } from './client.mjs'
import { getPathFromRoot, getUrlFromRoot, runCommand } from './util.mjs'
const fsp = fs.promises const fsp = fs.promises
export default class Core extends EventEmitter{ export default class Core extends EventEmitter{
constructor(config, db, log, closeCb) { constructor(util, config, db, log, closeCb) {
super() super()
this._util = util
this._config = config this._config = config
this._db = db this._db = db
this._log = log this._log = log
@ -107,39 +107,39 @@ export default class Core extends EventEmitter{
} }
async installVersion(name, active, version) { async installVersion(name, active, version) {
if (fs.existsSync(getPathFromRoot(`./${name}/` + version.name))) { if (fs.existsSync(this._util.getPathFromRoot(`./${name}/` + version.name))) {
await runCommand('rmdir', ['/S', '/Q', `"${getPathFromRoot(`./${name}/` + version.name)}"`]) await this._util.runCommand('rmdir', ['/S', '/Q', `"${this._util.getPathFromRoot(`./${name}/` + version.name)}"`])
} }
try { try {
await fsp.mkdir(getPathFromRoot(`./${name}/` + version.name)) await fsp.mkdir(this._util.getPathFromRoot(`./${name}/` + version.name))
} catch(err) { } catch(err) {
if (err.code !== 'EEXIST') { if (err.code !== 'EEXIST') {
throw err throw err
} }
} }
// await fsp.mkdir(getPathFromRoot(`./${name}/` + version.name + '/node_modules')) // await fsp.mkdir(this._util.getPathFromRoot(`./${name}/` + version.name + '/node_modules'))
this.logActive(name, active, `[Core] Downloading ${version.name} (${version.url}) to ${version.name + '/' + version.name + '.zip'}\n`) this.logActive(name, active, `[Core] Downloading ${version.name} (${version.url}) to ${version.name + '/' + version.name + '.zip'}\n`)
let filePath = getPathFromRoot(`./${name}/` + version.name + '/' + version.name + '.zip') let filePath = this._util.getPathFromRoot(`./${name}/` + version.name + '/' + version.name + '.zip')
await request(version.url, filePath) await request(version.url, filePath)
this.logActive(name, active, `[Core] Downloading finished, starting extraction\n`) this.logActive(name, active, `[Core] Downloading finished, starting extraction\n`)
await runCommand( await this._util.runCommand(
'"C:\\Program Files\\7-Zip\\7z.exe"', '"C:\\Program Files\\7-Zip\\7z.exe"',
['x', `"${filePath}"`], ['x', `"${filePath}"`],
getPathFromRoot(`./${name}/` + version.name + '/'), this._util.getPathFromRoot(`./${name}/` + version.name + '/'),
this.logActive.bind(this, name, active) this.logActive.bind(this, name, active)
) )
if (!fs.existsSync(getPathFromRoot(`./${name}/` + version.name + '/index.mjs'))) { if (!fs.existsSync(this._util.getPathFromRoot(`./${name}/` + version.name + '/index.mjs'))) {
this.logActive(name, active, `\n[Core] ERROR: Missing index.mjs in the folder, exiting\n`) this.logActive(name, active, `\n[Core] ERROR: Missing index.mjs in the folder, exiting\n`)
throw new Error(`Missing index.mjs in ${getPathFromRoot(`./${name}/` + version.name + '/index.mjs')}`) throw new Error(`Missing index.mjs in ${this._util.getPathFromRoot(`./${name}/` + version.name + '/index.mjs')}`)
} }
this.logActive(name, active, `\n[Core] Starting npm install\n`) this.logActive(name, active, `\n[Core] Starting npm install\n`)
await runCommand( await this._util.runCommand(
'npm.cmd', 'npm.cmd',
['install', '--production', '--no-optional', '--no-package-lock', '--no-audit'], ['install', '--production', '--no-optional', '--no-package-lock', '--no-audit'],
getPathFromRoot(`./${name}/` + version.name + '/'), this._util.getPathFromRoot(`./${name}/` + version.name + '/'),
this.logActive.bind(this, name, active) this.logActive.bind(this, name, active)
) )
@ -188,7 +188,7 @@ export default class Core extends EventEmitter{
async tryStartProgram(name, active, version) { async tryStartProgram(name, active, version) {
if (!version) return false if (!version) return false
this.logActive(name, active, `[${name}] Attempting to start ${version}\n`) this.logActive(name, active, `[${name}] Attempting to start ${version}\n`)
let indexPath = getUrlFromRoot(`./${name}/` + version + '/index.mjs') let indexPath = this._util.getUrlFromRoot(`./${name}/` + version + '/index.mjs')
let module let module
try { try {

View file

@ -131,9 +131,9 @@ const lodashId = {
} }
} }
const adapter = new FileAsync('db.json') export default function GetDB(util, log) {
const adapter = new FileAsync(util.getPathFromRoot('./db.json'))
export default function GetDB(log) {
return lowdb(adapter) return lowdb(adapter)
.then(function(db) { .then(function(db) {
db._.mixin(lodashId) db._.mixin(lodashId)

View file

@ -1,6 +1,5 @@
import nodewindows from 'node-windows' import nodewindows from 'node-windows'
import bunyan from 'bunyan-lite' import bunyan from 'bunyan-lite'
import lowdb from './db.mjs'
export default function getLog(name) { export default function getLog(name) {
let settings let settings

View file

@ -2,16 +2,21 @@ import path from 'path'
import { spawn } from 'child_process' import { spawn } from 'child_process'
import { fileURLToPath, pathToFileURL } from 'url' import { fileURLToPath, pathToFileURL } from 'url'
export function getPathFromRoot(add) { export default class Util {
const __dirname = path.dirname(fileURLToPath(import.meta.url)); constructor(root_import_meta_url) {
return path.join(__dirname,'../', add) this._root_import_meta_url = root_import_meta_url
} }
export function getUrlFromRoot(add) { getPathFromRoot(add) {
return path.join(import.meta.url,'../../', add) const __dirname = path.dirname(fileURLToPath(this._root_import_meta_url));
} return path.join(__dirname,'./', add)
}
export function runCommand(command, options = [], folder = null, stream = function() {}) { getUrlFromRoot(add) {
return path.join(this._root_import_meta_url,'../', add)
}
runCommand(command, options = [], folder = null, stream = function() {}) {
return new Promise(function(res, rej) { return new Promise(function(res, rej) {
stream(`[Command] ${folder ? folder : ''}${command} ${options.join(' ')}\n`) stream(`[Command] ${folder ? folder : ''}${command} ${options.join(' ')}\n`)
let processor = spawn(command, options, { let processor = spawn(command, options, {
@ -39,4 +44,5 @@ export function runCommand(command, options = [], folder = null, stream = functi
res(code) res(code)
}) })
}) })
}
} }

View file

@ -1 +0,0 @@
@ECHO off

View file

@ -1,5 +0,0 @@
export function start(config, db, log, core) {
return import('./api/server.mjs').then(function(module) {
return module.run(config, db, log, core)
})
}

47
lib.mjs Normal file
View file

@ -0,0 +1,47 @@
import Util from './core/util.mjs'
import { readFileSync } from 'fs'
import { getLog } from './core/log.mjs'
import lowdb from './core/db.mjs'
export default class ServiceCore {
constructor(name, root_import_meta_url) {
if (!root_import_meta_url) {
throw new Error('ServiceCore must be called with the full string from "import.meta.url" from a file residing in the root directory')
}
this._root_import_meta_url = root_import_meta_url
this.util = new Util(this._root_import_meta_url)
this.log = getLog(name)
this.db = null
this.config = null
this.core = null
}
close(err) {
if (err) {
log.fatal(err, 'App recorded a fatal error')
process.exit(4)
}
log.warn('App asked to be restarted')
process.exit(0)
}
async init() {
try {
this.config = JSON.parse(readFileSync(this.util.getPathFromRoot('./config.json')))
} catch (err) {
throw new Error('Unable to read config.json from root directory: ' + err)
}
try {
this.db = await lowdb(this.util, this.log)
} catch (err) {
throw new Error('Unable to read initialise lowdb: ' + err)
}
this.core = new Core(this.util, this.config, this.db, this.log, (err) => this.close(err))
}
async startModule(module) {
return module.start(config, db, log, core)
}
}

View file

@ -2,7 +2,7 @@
"name": "service-core", "name": "service-core",
"version": "1.0.0", "version": "1.0.0",
"description": "Core boiler plate code to install node server as windows service", "description": "Core boiler plate code to install node server as windows service",
"main": "index.js", "main": "lib.js",
"scripts": { "scripts": {
"dev": "nodemon --watch dev/api --watch core --watch runner.mjs --watch db.mjs --watch log.mjs runner.mjs | bunyan", "dev": "nodemon --watch dev/api --watch core --watch runner.mjs --watch db.mjs --watch log.mjs runner.mjs | bunyan",
"test": "echo \"Error: no test specified\" && exit 1" "test": "echo \"Error: no test specified\" && exit 1"

View file

@ -1,7 +1,8 @@
import { readFileSync } from 'fs' import { readFileSync } from 'fs'
import getLog from './log.mjs' import getLog from './core/log.mjs'
import lowdb from './db.mjs' import lowdb from './core/db.mjs'
import Core from './core/core.mjs' import Core from './core/core.mjs'
import Util from './core/util.mjs'
let config let config
@ -32,8 +33,10 @@ const close = function(err) {
}) })
} }
lowdb(log).then(function(db) { const util = new Util(import.meta.url)
let core = new Core(config, db, log, close)
lowdb(util, log).then(function(db) {
let core = new Core(util, config, db, log, close)
if (config.useDev) { if (config.useDev) {
return import('./dev/index.mjs').then(function(module) { return import('./dev/index.mjs').then(function(module) {

View file

@ -1,8 +1,12 @@
import path from 'path' import path from 'path'
import { readFileSync } from 'fs' import { readFileSync } from 'fs'
import { getPathFromRoot } from '../core/util.mjs'
import nodewindows from 'node-windows' import nodewindows from 'node-windows'
function getPathFromRoot(add) {
const __dirname = path.dirname(fileURLToPath(import.meta.url));
return path.join(__dirname,'../', add)
}
let config = JSON.parse(readFileSync(getPathFromRoot('./config.json'))) let config = JSON.parse(readFileSync(getPathFromRoot('./config.json')))
const Service = nodewindows.Service const Service = nodewindows.Service