@egeria/egeria
Version:
Egeria bestows wisdom and knowledge
229 lines (197 loc) • 7.41 kB
JavaScript
/*
.--. .-'. .--. .--. .--. .--. .`-. .--.
:::::.\::::::::.\::::::::.\::::::::.\::::::::.\::::::::.\::::::::.\::::::::.\
' `--' `.-' `--' `--' `--' `-.' `--' `
Egeria - She bestows Knowledge and Wisdom
Copyright (C) 2016-2019 MySidesTheyAreGone <mysidestheyaregone@protonmail.com>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published
by the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
.--. .-'. .--. .--. .--. .--. .`-. .--.
:::::.\::::::::.\::::::::.\::::::::.\::::::::.\::::::::.\::::::::.\::::::::.\
' `--' `.-' `--' `--' `--' `-.' `--' `
*/
module.exports = async function (userconf) {
process.once('unhandledException', (e) => {
console.log('UNHANDLED EXCEPTION - CRASHING')
console.log(e.stack)
process.exit(1)
})
process.once('unhandledRejection', (e) => {
console.log('UNHANDLED REJECTION - CRASHING')
console.log(e.stack)
shutdown()
})
const path = require('path')
const R = require('ramda')
const Baobab = require('baobab')
const T = require('@egeria/tools')
const Logger = require('@egeria/logger')
const FS = require('@egeria/fslib')
const Queue = require('@egeria/queue')
const Auth = require('@egeria/auth')
const Storage = require('@egeria/storage')
const Cache = require('@egeria/cache')
const PluginManager = require('@egeria/plugin-manager')
const Job = require('@egeria/job')
const _baobabCfg = {
immutable: false,
persistent: false,
autoCommit: true,
asynchronous: false
}
const userHomeDir = require('os').homedir()
const _defaultAppstate = {
prefix: 'EGERIA |',
system: {
port: 54321,
logLevels: {
silly: false,
debug: false,
info: true,
warning: true,
error: true
},
logFile: path.resolve(userHomeDir, '.egeria', 'egeria.log'),
masterPassword: '1234567812345678',
directories: {
base: path.resolve(userHomeDir, '.egeria')
}
},
jobs: []
}
function interval (delay) {
return new Promise((resolve) => {
setTimeout(resolve, delay)
})
}
// [INIT]
let cfg = R.clone(_defaultAppstate)
cfg.system = R.merge(_defaultAppstate.system, userconf.system)
cfg.jobs = R.merge(_defaultAppstate.jobs, userconf.jobs)
let state = new Baobab(cfg, _baobabCfg)
let systemcfg = state.select('system')
// setup logging
let logger = Logger('YYYY-MM-DD HH:mm:ss', { logLevels: cfg.system.logLevels })
state.set('outbox', { push: logger.log })
const logError = (message, origin, data) => T.log(state, 'error', message, origin, data)
const logInfo = (message, origin, data) => T.log(state, 'info', message, origin, data)
const logDebug = (message, origin, data) => T.log(state, 'debug', message, origin, data)
const logSilly = (message, origin, data) => T.log(state, 'silly', message, origin, data)
let baseDir = systemcfg.get('directories', 'base')
let idBaseDir = systemcfg.get('directories', 'identities')
let storageBaseDir = systemcfg.get('directories', 'memory')
if (R.isNil(idBaseDir)) {
idBaseDir = path.resolve(baseDir, 'identities')
}
if (R.isNil(storageBaseDir)) {
storageBaseDir = path.resolve(baseDir, 'memory')
}
try {
await FS.mkdir(baseDir)
await FS.mkdir(idBaseDir)
await FS.mkdir(storageBaseDir)
} catch (e) {
console.log('FATAL ERROR')
console.log(e.stack)
process.exit(1)
}
logInfo('Diverting main power to secondary subsystems...')
// setup queue state
state.select('subsystem', 'queue').set({ outbox: { push: logger.log } })
let queue = Queue(state.select('subsystem', 'queue'))
logInfo('Action queue: ONLINE')
// setup identity manager
state.select('subsystem', 'auth').set({
masterPassword: systemcfg.get('masterPassword'),
directory: idBaseDir,
outbox: { push: logger.log }
})
let auth = Auth(queue, state.select('subsystem', 'auth'))
logInfo('Identity manager: ONLINE')
// setup memory cache
let cache = Cache()
logInfo('Cache: ONLINE')
// setup storage manager
state.select('subsystem', 'storageManager').set({
configuration: {
keyField: 'key',
ttlField: 'system:ttl',
storage: state.get('system', 'storage'),
storageDirectory: storageBaseDir
},
outbox: { push: logger.log }
})
let storage = Storage(state.select('subsystem', 'storageManager'))
logInfo('Storage manager: ONLINE')
// setup plugin manager
const plugins = require('../data/plugins.json')
state.select('subsystem', 'pluginManager').set({
plugins: plugins,
moduleBaseDir: baseDir,
outbox: { push: logger.log }
})
let pluginManager = PluginManager(state.select('subsystem', 'pluginManager'))
logInfo('Plugin manager: ONLINE')
logInfo('Assembling jobs...')
let jobcfg = state.select('jobs', 0)
while (!R.isNil(jobcfg) && !R.isNil(jobcfg.get())) {
jobcfg.set('outbox', { push: logger.log })
let jobName = jobcfg.get('name')
let action = 'While assembling job ' + jobName
try {
let job = Job(queue, pluginManager, auth, storage, cache, jobcfg)
jobcfg.set('instance', job)
await job.construct()
job.start()
} catch (e) {
logError(action, e)
process.exit(1)
}
logInfo('Job "' + jobName + '": ONLINE')
jobcfg = jobcfg.right()
}
logInfo('All systems nominal.')
async function shutdown () {
logInfo('KILL SIGNAL RECEIVED - INITIATING SELF-DESTRUCT SEQUENCE')
let job = state.select('jobs', 0)
while (!R.isNil(job) && !R.isNil(job.get())) {
let jobName = job.get('name')
job.get('instance').stop()
logDebug('Job "' + jobName + '": stopped')
job = job.right()
}
queue.shutdown()
await interval(1)
logInfo('Queue manager: OFFLINE')
job = state.select('jobs', 0)
while (!R.isNil(job) && !R.isNil(job.get())) {
let jobName = job.get('name')
let action = 'While destroying job ' + jobName
logSilly('Destroying job "' + jobName + '"...')
try {
await job.get('instance').destruct()
} catch (e) {
logError(action, e)
}
logInfo('Job "' + jobName + '": OFFLINE')
job = job.right()
}
logInfo('All systems OFFLINE. Shutting down...')
try {
let gby = require('../data/goodbye.json')
logInfo(gby[Math.floor(Math.random() * gby.length)] + ' \n\n')
process.exit(0)
} catch (e) {
process.exit(1)
}
}
return { shutdown }
}