Make service-core librariable
This commit is contained in:
parent
a7c5cee7da
commit
e0413bbaa6
11 changed files with 117 additions and 66 deletions
|
@ -4,8 +4,6 @@
|
|||
"description": "NodeJS Test Service",
|
||||
"port": 4270,
|
||||
"managePort": 4269,
|
||||
"hasManage": true,
|
||||
"appRepository": "thething/sc-helloworld",
|
||||
"manageRepository": null,
|
||||
"useDev": true
|
||||
"manageRepository": null
|
||||
}
|
|
@ -1,13 +1,13 @@
|
|||
import fs from 'fs'
|
||||
import { EventEmitter } from 'events'
|
||||
import { request } from './client.mjs'
|
||||
import { getPathFromRoot, getUrlFromRoot, runCommand } from './util.mjs'
|
||||
|
||||
const fsp = fs.promises
|
||||
|
||||
export default class Core extends EventEmitter{
|
||||
constructor(config, db, log, closeCb) {
|
||||
constructor(util, config, db, log, closeCb) {
|
||||
super()
|
||||
this._util = util
|
||||
this._config = config
|
||||
this._db = db
|
||||
this._log = log
|
||||
|
@ -107,39 +107,39 @@ export default class Core extends EventEmitter{
|
|||
}
|
||||
|
||||
async installVersion(name, active, version) {
|
||||
if (fs.existsSync(getPathFromRoot(`./${name}/` + version.name))) {
|
||||
await runCommand('rmdir', ['/S', '/Q', `"${getPathFromRoot(`./${name}/` + version.name)}"`])
|
||||
if (fs.existsSync(this._util.getPathFromRoot(`./${name}/` + version.name))) {
|
||||
await this._util.runCommand('rmdir', ['/S', '/Q', `"${this._util.getPathFromRoot(`./${name}/` + version.name)}"`])
|
||||
}
|
||||
try {
|
||||
await fsp.mkdir(getPathFromRoot(`./${name}/` + version.name))
|
||||
await fsp.mkdir(this._util.getPathFromRoot(`./${name}/` + version.name))
|
||||
} catch(err) {
|
||||
if (err.code !== 'EEXIST') {
|
||||
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`)
|
||||
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)
|
||||
this.logActive(name, active, `[Core] Downloading finished, starting extraction\n`)
|
||||
await runCommand(
|
||||
await this._util.runCommand(
|
||||
'"C:\\Program Files\\7-Zip\\7z.exe"',
|
||||
['x', `"${filePath}"`],
|
||||
getPathFromRoot(`./${name}/` + version.name + '/'),
|
||||
this._util.getPathFromRoot(`./${name}/` + version.name + '/'),
|
||||
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`)
|
||||
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`)
|
||||
|
||||
await runCommand(
|
||||
await this._util.runCommand(
|
||||
'npm.cmd',
|
||||
['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)
|
||||
)
|
||||
|
||||
|
@ -188,7 +188,7 @@ export default class Core extends EventEmitter{
|
|||
async tryStartProgram(name, active, version) {
|
||||
if (!version) return false
|
||||
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
|
||||
|
||||
try {
|
||||
|
|
|
@ -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)
|
||||
.then(function(db) {
|
||||
db._.mixin(lodashId)
|
|
@ -1,6 +1,5 @@
|
|||
import nodewindows from 'node-windows'
|
||||
import bunyan from 'bunyan-lite'
|
||||
import lowdb from './db.mjs'
|
||||
|
||||
export default function getLog(name) {
|
||||
let settings
|
|
@ -2,41 +2,47 @@ import path from 'path'
|
|||
import { spawn } from 'child_process'
|
||||
import { fileURLToPath, pathToFileURL } from 'url'
|
||||
|
||||
export function getPathFromRoot(add) {
|
||||
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
||||
return path.join(__dirname,'../', add)
|
||||
}
|
||||
export default class Util {
|
||||
constructor(root_import_meta_url) {
|
||||
this._root_import_meta_url = root_import_meta_url
|
||||
}
|
||||
|
||||
export function getUrlFromRoot(add) {
|
||||
return path.join(import.meta.url,'../../', add)
|
||||
}
|
||||
getPathFromRoot(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() {}) {
|
||||
return new Promise(function(res, rej) {
|
||||
stream(`[Command] ${folder ? folder : ''}${command} ${options.join(' ')}\n`)
|
||||
let processor = spawn(command, options, {
|
||||
shell: true,
|
||||
cwd: folder,
|
||||
getUrlFromRoot(add) {
|
||||
return path.join(this._root_import_meta_url,'../', add)
|
||||
}
|
||||
|
||||
runCommand(command, options = [], folder = null, stream = function() {}) {
|
||||
return new Promise(function(res, rej) {
|
||||
stream(`[Command] ${folder ? folder : ''}${command} ${options.join(' ')}\n`)
|
||||
let processor = spawn(command, options, {
|
||||
shell: true,
|
||||
cwd: folder,
|
||||
})
|
||||
let timeOuter = setTimeout(function() {
|
||||
processor.stdin.write('n\n')
|
||||
}, 250)
|
||||
processor.stdout.on('data', function(data) {
|
||||
stream(data.toString())
|
||||
})
|
||||
processor.stderr.on('data', function(data) {
|
||||
stream(data.toString())
|
||||
})
|
||||
processor.on('error', function(err) {
|
||||
clearInterval(timeOuter)
|
||||
rej(err)
|
||||
})
|
||||
processor.on('exit', function (code) {
|
||||
clearInterval(timeOuter)
|
||||
if (code !== 0) {
|
||||
return rej(new Error('Program returned error code: ' + code))
|
||||
}
|
||||
res(code)
|
||||
})
|
||||
})
|
||||
let timeOuter = setTimeout(function() {
|
||||
processor.stdin.write('n\n')
|
||||
}, 250)
|
||||
processor.stdout.on('data', function(data) {
|
||||
stream(data.toString())
|
||||
})
|
||||
processor.stderr.on('data', function(data) {
|
||||
stream(data.toString())
|
||||
})
|
||||
processor.on('error', function(err) {
|
||||
clearInterval(timeOuter)
|
||||
rej(err)
|
||||
})
|
||||
processor.on('exit', function (code) {
|
||||
clearInterval(timeOuter)
|
||||
if (code !== 0) {
|
||||
return rej(new Error('Program returned error code: ' + code))
|
||||
}
|
||||
res(code)
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1 +0,0 @@
|
|||
@ECHO off
|
|
@ -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
47
lib.mjs
Normal 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)
|
||||
}
|
||||
}
|
|
@ -2,7 +2,7 @@
|
|||
"name": "service-core",
|
||||
"version": "1.0.0",
|
||||
"description": "Core boiler plate code to install node server as windows service",
|
||||
"main": "index.js",
|
||||
"main": "lib.js",
|
||||
"scripts": {
|
||||
"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"
|
||||
|
|
11
runner.mjs
11
runner.mjs
|
@ -1,7 +1,8 @@
|
|||
import { readFileSync } from 'fs'
|
||||
import getLog from './log.mjs'
|
||||
import lowdb from './db.mjs'
|
||||
import getLog from './core/log.mjs'
|
||||
import lowdb from './core/db.mjs'
|
||||
import Core from './core/core.mjs'
|
||||
import Util from './core/util.mjs'
|
||||
|
||||
let config
|
||||
|
||||
|
@ -32,8 +33,10 @@ const close = function(err) {
|
|||
})
|
||||
}
|
||||
|
||||
lowdb(log).then(function(db) {
|
||||
let core = new Core(config, db, log, close)
|
||||
const util = new Util(import.meta.url)
|
||||
|
||||
lowdb(util, log).then(function(db) {
|
||||
let core = new Core(util, config, db, log, close)
|
||||
|
||||
if (config.useDev) {
|
||||
return import('./dev/index.mjs').then(function(module) {
|
||||
|
|
|
@ -1,8 +1,12 @@
|
|||
import path from 'path'
|
||||
import { readFileSync } from 'fs'
|
||||
import { getPathFromRoot } from '../core/util.mjs'
|
||||
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')))
|
||||
|
||||
const Service = nodewindows.Service
|
||||
|
|
Loading…
Reference in a new issue