nfp_sites/base/server.mjs

128 lines
3.4 KiB
JavaScript

import { Flaska, QueryHandler, JsonHandler, FormidableHandler } from 'flaska'
import formidable from 'formidable'
import { initPool } from './db.mjs'
import config from './config.mjs'
import PageRoutes from './page/routes.mjs'
import ArticleRoutes from './article/routes.mjs'
import AuthenticationRoutes from './authentication/routes.mjs'
import { authenticate } from './authentication/security.mjs'
import StaticRoutes from './static_routes.mjs'
export default class Server {
constructor(http, port, core, opts = {}) {
Object.assign(this, opts)
this.http = http
this.port = port
this.core = core
this.flaskaOptions = {
appendHeaders: {
'Content-Security-Policy': `default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; img-src * data: blob:; font-src 'self' data:; object-src 'none'; frame-ancestors 'none'`,
},
log: this.core.log,
nonce: ['script-src'],
nonceCacheLength: 50,
}
this.authenticate = authenticate
this.formidable = FormidableHandler.bind(this, formidable)
this.jsonHandler = JsonHandler
this.routes = {
page: new PageRoutes(),
article: new ArticleRoutes(),
auth: new AuthenticationRoutes(),
static: new StaticRoutes(),
}
this.init()
}
init() { }
runCreateServer() {
// Create our server
this.flaska = new Flaska(this.flaskaOptions, this.http)
// Create our database pool
let pool = this.runCreateDatabase()
// configure our server
if (config.get('NODE_ENV') === 'development') {
this.flaska.devMode()
}
this.flaska.before(function(ctx) {
ctx.state.started = new Date().getTime()
ctx.req.ip = ctx.req.headers['x-forwarded-for'] || ctx.req.connection.remoteAddress
ctx.log = ctx.log.child({
id: Math.random().toString(36).substring(2, 14),
})
ctx.db = pool
})
this.flaska.before(QueryHandler())
let healthChecks = 0
let healthCollectLimit = 60 * 60 * 12
this.flaska.after(function(ctx) {
if (ctx.aborted && ctx.status === 200) {
ctx.status = 299
}
let ended = new Date().getTime()
var requestTime = ended - ctx.state.started
let status = ''
let level = 'info'
if (ctx.status >= 400) {
status = ctx.status + ' '
level = 'warn'
}
if (ctx.status >= 500) {
level = 'error'
}
if (ctx.url === '/health') {
healthChecks++
if (healthChecks >= healthCollectLimit) {
ctx.log[level]({
duration: Math.round(ended),
status: ctx.status,
}, `<-- ${status}${ctx.method} ${ctx.url} {has happened ${healthChecks} times}`)
healthChecks = 0
}
return
}
ctx.log[level]({
duration: requestTime,
status: ctx.status,
ip: ctx.req.ip,
}, (ctx.aborted ? '[ABORT]' : '<--') + ` ${status}${ctx.method} ${ctx.url}`)
})
}
runRegisterRoutes() {
let keys = Object.keys(this.routes)
for (let key of keys) {
this.routes[key].register(this)
}
}
runCreateDatabase() {
return initPool(this.core, config.get('mssql'))
}
runStartListen() {
return this.flaska.listenAsync(this.port).then(() => {
this.core.log.info('Server is listening on port ' + this.port)
})
}
run() {
this.runCreateServer()
this.runRegisterRoutes()
return this.runStartListen()
}
}