186 lines
5.1 KiB
JavaScript
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'))
|
|
})
|