if (!this instanceof Server)
throw Error('Server is a constructor')
- this.mime_types = {}
- this.listen = []
this.enable_caching = false
+ this.listen = []
+ this.mime_types = {}
+ this.sites = {}
this.build_cache_email = new BuildCache()
this.build_cache_json = new BuildCache()
this.build_cache_zip = new BuildCache()
this.json_cache = new JSONCache(true)
- this.mime_types = undefined
- this.mime_type_html = undefined
+ this.mime_type_html = 'text/html; charset=utf-8'
this.mime_type_default = 'application/octet-stream'
}
}
Server.prototype.refresh_config = async function() {
- let config = await this.get_json('_config/server.json')
-
- this.enable_caching = config.enable_caching
+ try {
+ let config = await this.get_jst('_config/server.jst', '.')
- this.mime_types = config.mime_types
- this.mime_type_html =
- Object.prototype.hasOwnProperty.call(this.mime_types, '.html') ?
- this.mime_types['.html'] :
- this.mime_type_default
+ this.enable_caching = config.enable_caching
- let listen = []
- for (let i = 0; i < config.listen.length; ++i)
- listen.push(
- Object.assign(
- {
- port: 0,
- host: '0.0.0.0',
- protocol: 'http:',
- ssl_cert: '_ssl/localhost_cert_bundle.pem',
- ssl_key: '_ssl/localhost_key.pem',
- },
- config.listen[i]
- )
- )
- listen.sort(compare_listen)
- //console.log('listen', listen)
-
- // stop all servers no longer in configuration file
- let i = 0
- let j = 0
- while (i < this.listen.length)
- switch (
- j < this.listen.length ?
- compare_listen(this.listen[i], listen[j]) :
- -1
- ) {
- case -1:
- if (this.listen[i].server !== undefined) {
- console.log(
- `stop listening on ${this.listen[i].protocol}//${this.listen[i].host}:${this.listen[i].port}`
- )
- await new Promise(
- (resolve, reject) => {
- this.listen[i].server.close(
- err => {
- if (err)
- reject(err)
- resolve()
- }
- )
- }
+ let listen = []
+ for (let i = 0; i < config.listen.length; ++i)
+ listen.push(
+ Object.assign(
+ {
+ port: 0,
+ host: '0.0.0.0',
+ protocol: 'http:',
+ ssl_cert: '_ssl/localhost_cert_bundle.pem',
+ ssl_key: '_ssl/localhost_key.pem',
+ },
+ config.listen[i]
)
- }
- ++i
- break
- case 0:
- listen[j++].server = this.listen[i++].server
- break
- case 1:
- listen[j++].server = undefined // just to be on the safe side
- break
- }
-
- // then start all newly mentioned servers (or those which need retrying)
- for (i = 0; i < listen.length; ++i)
- if (listen[i].server === undefined) {
- console.log(
- `start listening on ${listen[i].protocol}//${listen[i].host}:${listen[i].port}`
)
- let server
- switch (listen[i].protocol) {
- case 'http:':
- server = require('http').createServer()
+ listen.sort(compare_listen)
+ //console.log('listen', listen)
+
+ // stop all servers no longer in configuration file
+ let i = 0
+ let j = 0
+ while (i < this.listen.length)
+ switch (
+ j < this.listen.length ?
+ compare_listen(this.listen[i], listen[j]) :
+ -1
+ ) {
+ case -1:
+ if (this.listen[i].server !== undefined) {
+ console.log(
+ `stop listening on ${this.listen[i].protocol}//${this.listen[i].host}:${this.listen[i].port}`
+ )
+ await new Promise(
+ (resolve, reject) => {
+ this.listen[i].server.close(
+ err => {
+ if (err)
+ reject(err)
+ resolve()
+ }
+ )
+ }
+ )
+ }
+ ++i
break
- case 'https:':
- server = require('https').createServer(
- {
- 'cert': await fs_readFile(listen[i].ssl_cert),
- 'key': await fs_readFile(listen[i].ssl_key)
- }
- )
+ case 0:
+ listen[j++].server = this.listen[i++].server
+ break
+ case 1:
+ listen[j++].server = undefined // just to be on the safe side
break
- default:
- assert(false)
- }
- try {
- await new Promise(
- (resolve, reject) => {
- server.on('listening', () => {resolve()})
- server.on('error', err => {reject(err)})
- server.listen(listen[i].port)
- // should remove the listeners afterwards
- }
- )
}
- catch (err) {
- if (err.code !== 'EADDRINUSE') // err type ??
- throw err
+
+ // then start all newly mentioned servers (or those which need retrying)
+ for (i = 0; i < listen.length; ++i)
+ if (listen[i].server === undefined) {
console.log(
- `address ${listen[i].protocol}//${listen[i].host}:${listen[i].port} in use`
+ `start listening on ${listen[i].protocol}//${listen[i].host}:${listen[i].port}`
)
- continue // leaves listen[i].server undefined, will retry
+ let server
+ switch (listen[i].protocol) {
+ case 'http:':
+ server = require('http').createServer()
+ break
+ case 'https:':
+ server = require('https').createServer(
+ {
+ 'cert': await fs_readFile(listen[i].ssl_cert),
+ 'key': await fs_readFile(listen[i].ssl_key)
+ }
+ )
+ break
+ default:
+ assert(false)
+ }
+ try {
+ await new Promise(
+ (resolve, reject) => {
+ server.on('listening', () => {resolve()})
+ server.on('error', err => {reject(err)})
+ server.listen(listen[i].port)
+ // should remove the listeners afterwards
+ }
+ )
+ }
+ catch (err) {
+ if (err.code !== 'EADDRINUSE') // err type ??
+ throw err
+ console.log(
+ `address ${listen[i].protocol}//${listen[i].host}:${listen[i].port} in use`
+ )
+ continue // leaves listen[i].server undefined, will retry
+ }
+ this.attach(server, listen[i].protocol)
+ if (this.socket_io !== undefined)
+ this.socket_io.attach(server)
+ listen[i].server = server
}
- this.attach(server, listen[i].protocol)
- if (this.socket_io !== undefined)
- this.socket_io.attach(server)
- listen[i].server = server
- }
- this.listen = listen
+ this.listen = listen
+
+ this.mime_types = config.mime_types
+ this.mime_type_html =
+ Object.prototype.hasOwnProperty.call(this.mime_types, '.html') ?
+ this.mime_types['.html'] :
+ this.mime_type_default
+
+ this.sites = config.sites
+ }
+ catch (err) {
+ console.log(`configuration error: ${err.stack || err.message}`)
+ }
}
Server.prototype.serve = function(response, status, mime_type, data, message) {
// html files will be direct recipient of links/bookmarks so can't have
// a long lifetime, other files like css or images are often large files
// and won't change frequently (but we'll need cache busting eventually)
- if (this.caching && mime_type !== this.mime_types_html)
+ if (this.enable_caching && mime_type !== this.mime_type_html)
response.setHeader('Cache-Control', 'max-age=3600')
response.setHeader('Content-Type', mime_type)
response.setHeader('Content-Length', data.length)
let site_factory_default = async (server, root) => new Site(server, root)
Server.prototype.respond = async function(request, response, protocol) {
- let sites = await this.get_jst('_config/sites.jst', '.')
try {
let parsed_url = url.parse(
protocol + '//' + (request.headers.host || 'localhost') + request.url,
//console.log('parsed_url', parsed_url)
if (
- !Object.prototype.hasOwnProperty.call(sites, parsed_url.hostname)
+ !Object.prototype.hasOwnProperty.call(this.sites, parsed_url.hostname)
) {
this.die(
response,
mime_type = this.mime_types[extension]
}
- let site = sites[parsed_url.hostname]
+ let site = this.sites[parsed_url.hostname]
await site.respond(
{
mime_type: mime_type,