srd/index.js

186 lines
5.1 KiB
JavaScript

/* SRD Website
````````````````````````````````````````````````````````````````````````````````
This is a webapp for serving an RPG SRD in a publicly available format
constructed from a collection of md and configuration files in a git repository
located at `srd`.
*/
/* ==== REQUIRES ============================================================ */
const express = require('express')
const doT = require('dot')
const path = require('path')
const fs = require('fs')
/* ==== CONFIGURATION ======================================================= */
const exp = express()
const app = {
config: {
srd: 'srd',
plugins: {},
port: 7331,
},
live: {
dictionary: {},
conf: {},
menu: '',
},
express: exp,
dot: null,
}
const pub = __dirname + '/public'
const views = __dirname + '/views'
const routes = __dirname + '/routes'
app.dot = doT.process({'path': views})
try {
app.config = {...app.config, ...require(__dirname + '/config.js')}
} catch(err) {
if (err.code === 'MODULE_NOT_FOUND') {
console.error('missing config')
}
}
exp.use(express.static(pub))
exp.use(express.static(path.join(__dirname, app.config.srd)))
exp.engine('dot', (template, options, cb) => {
return cb(null, app.dot[path.parse(template).name](options))
})
exp.set('views', views)
exp.set('view engine', 'dot')
/* ==== PLUGINS ============================================================= */
const plugins = []
try {
fs.readdirSync('plugins').forEach(f => {
let plugin_path = path.resolve('plugins', f)
if (fs.lstatSync(plugin_path).isDirectory()) {
console.log('plugin require:', f)
try {
let plugin = {
defaults: null,
config: {},
log: (...args) => {
console.log.apply(console, [f+':', ...args])
},
error: (...args) => {
console.error.apply(console, [f+':', ...args])
},
module: require(plugin_path),
}
if (app.config.plugins[f]) {
plugin.config = app.config.plugins[f]
}
plugin.defaults = o => {
plugin.config = {...o, ...plugin.config}
}
console.log('...ok')
plugins.push(plugin)
} catch(err) {
if (err.code === 'MODULE_NOT_FOUND') {
console.error('plugin', plugin_path, 'is not a valid module')
} else {
console.error('...fail: ', err)
}
}
}
})
if (plugins.length === 0) {
console.warn('no plugins found');
} else {
// Sort our plugins according to desired priorities. Higher numbers
plugins.sort((first, second) => {
let first_priority = 0
let second_priority = 0
if (first.config.priority !== undefined) {
first_priority = first.config.priority
} else if (first.module === Object(first.module)) {
if (first.module.priority !== undefined) {
first_priority = first.module.priority
}
}
if (second.config.priority !== undefined) {
second_priority = second.config.priority
} else if (second.module === Object(second.module)) {
if (second.module.priority !== undefined) {
second_priority = second.module.priority
}
}
if (first_priority > second_priority) {
return -1
} else if (first_priority < second_priority) {
return 1
}
return 0
})
// Call any needed preloads.
for (let plugin of plugins) {
// Call preload if the module is an object.
if (plugin.module === Object(plugin.module)) {
if (plugin.module.preload) {
console.log('plugin preload:', f)
try {
plugin.module.preload(plugin, app)
console.log('...ok')
} catch(err) {
console.error('...fail: ', err)
}
}
}
}
}
} catch(err) {
if (err.code === 'ENOENT') {
console.warn('no plugins directory')
} else {
console.error('plugins', err)
}
}
/* ==== CMDLINE ============================================================= */
const port = app.config.port
process.argv.forEach((val, index, array) => {
let parts = val.split('=')
let key = ''
let value = ''
if (parts[0].substr(0, 2) == '--') {
key = parts[0].substr(2)
value = parts[1]
}
if (key == 'port') {
if (value != '') {
port = Number(value)
}
}
})
/* ==== RUN ================================================================= */
const server = exp.listen(port, async () => {
const host = server.address().address
const port = server.address().port
for (let plugin of plugins) {
try {
if (plugin.module instanceof Function) {
await plugin.module(plugin, app)
} else if (plugin.module === Object(plugin.module)) {
if (plugin.module.load) {
await plugin.module.load(plugin, app)
}
}
} catch(err) {
console.error('plugin', err)
}
}
console.log('running on', port)
})
process.on('SIGINT', () => {
process.exit()
})
process.on('exit', () => {
fs.writeFileSync(path.join(__dirname + '/config.js'), 'module.exports = ' + JSON.stringify(app.config, null, '\t'))
})