let fs_readFile = util.promisify(fs.readFile)
-let Server = function(resources, options, prev_server) {
+let Server = function(resources, options/*, prev_server*/) {
if (!this instanceof Server)
throw new Error('Server is a constructor')
this.resources = resources
options || {}
)
- this.roots = prev_server !== undefined ? prev_server.roots : {}
this.jst_cache = undefined
-
+ this.site_roots = undefined
this.listeners = undefined
this.request_func =
(request, response, listener) =>
/*await*/ this.respond(request, response, listener.options.protocol)
+ // returned Promise will be ignored
}
Server.prototype.start = async function() {
async () => new JSTCache('.', {_jst_server: jst_server}, true)
)
+ assert(this.site_roots === undefined)
+ this.site_roots = {}
+ for (let i in this.options.hosts) {
+ let host
+ if (
+ Object.prototype.hasOwnProperty.call(this.options.hosts, i) &&
+ (host = this.options.hosts[i]).type === 'site' &&
+ !Object.prototype.hasOwnProperty.call(this.site_roots, host.root)
+ )
+ this.site_roots[host.root] = await this.resources.ref(
+ `site_root:${host.root}`,
+ async () => (
+ {
+ jst_cache: await this.resources.ref(
+ `jst_cache:${host.root}`,
+ async () =>
+ new JSTCache(host.root, {_jst_server: jst_server}, true)
+ ),
+ root: host.root,
+ site: undefined
+ }
+ ),
+ async site_root => {
+ await this.resources.unref(`jst_cache:${site_root.root}`)
+ if (site_root.site !== undefined)
+ await site_root.site.stop()
+ }
+ )
+ }
+
assert(this.listeners === undefined)
this.listeners = []
for (let i = 0; i < this.options.listeners.length; ++i) {
async () => new Listener(undefined, options, true),
listener => /*await*/ listener.stop()
)
- listener.request_func = this.request_func
this.listeners.push(listener)
}
}
assert(this.jst_cache !== undefined)
await this.resources.unref('jst_cache:.')
+ assert(this.site_roots !== undefined)
+ for (let i in this.site_roots)
+ if (Object.prototype.hasOwnProperty.call(this.site_roots, i))
+ await this.resources.unref(`site_root:${i}`)
+
assert(this.listeners !== undefined)
for (let i = 0; i < this.listeners.length; ++i)
await this.resources.unref(
}
Server.prototype.kick = async function() {
- for (let i = 0; i < this.listeners.length; ++i)
+ assert(this.jst_cache !== undefined)
+ this.jst_cache.kick()
+
+ assert(this.site_roots !== undefined)
+ for (let i in this.site_roots)
+ if (Object.prototype.hasOwnProperty.call(this.site_roots, i)) {
+ let site_root = this.site_roots[i]
+ let config = await site_root.jst_cache.get(
+ `${i}/_config/site.jst`,
+ true
+ )
+ if (config !== undefined) {
+ let prev_site = site_root.site
+ let new_site = await config(this.resources, i, prev_site)
+ await new_site.start() // exception here cancels site change
+ site_root.site = new_site
+ if (prev_site !== undefined)
+ await prev_site.stop() // exception here doesn't cancel change
+ }
+ await site_root.site.kick()
+ }
+
+ assert(this.listeners !== undefined)
+ for (let i = 0; i < this.listeners.length; ++i) {
+ this.listeners[i].request_func = this.request_func
await this.listeners[i].start()
+ }
}
Server.prototype.serve_internal = function(response, status, mime_type, data) {
`${parsed_url.protocol}//${new_host}${request.url}`,
`redirecting ${parsed_url.host} to ${new_host}`
)
- return
+ break
case 'site':
- let root
- if (Object.prototype.hasOwnProperty.call(this.roots, host.root))
- root = this.roots[host.root]
- else {
- root = {
- jst_cache: await this.resources.ref(
- `jst_cache:${host.root}`,
- async () =>
- new JSTCache(host.root, {_jst_server: jst_server}, true)
- ),
- site: undefined
- }
- this.roots[host.root] = root
- }
- let config = await root.jst_cache.get(
- `${host.root}/_config/site.jst`,
- true
- )
- if (config !== undefined) {
- // we should somehow block further config changes during this:
- let prev_site = root.site
- let site = await config(this.resources, host.root, prev_site)
- await site.start()
- root.site = site
- if (prev_site !== undefined)
- await prev_site.stop()
- }
- return root.site.respond(
+ await this.site_roots[host.root].site.respond(
{
parsed_url: parsed_url,
response: response,
server: this
}
)
+ break
default:
assert(false)
}
}
catch (err) {
let message = (err.stack || err.message).toString()
- console.log(message)
+ console.error(message)
this.serve_internal(
response,
500,
let fs_readFile = util.promisify(fs.readFile)
let fs_stat = util.promisify(fs.stat)
-let Site = function(resources, root, options) {
+let Site = function(resources, root, options/*, prev_site*/) {
if (!this instanceof Site)
throw new Error('Site is a constructor')
this.resources = resources
await this.resources.unref('zip_cache')
}
+Site.prototype.kick = async function() {
+ assert(this.json_cache !== undefined)
+ this.json_cache.kick()
+
+ assert(this.json_cache_rw !== undefined)
+ this.json_cache_rw.kick()
+
+ assert(this.jst_cache !== undefined)
+ this.jst_cache.kick()
+
+ assert(this.less_css_cache !== undefined)
+ this.less_css_cache.kick()
+
+ assert(this.min_css_cache !== undefined)
+ this.min_css_cache.kick()
+
+ assert(this.min_js_cache !== undefined)
+ this.min_js_cache.kick()
+
+ assert(this.min_html_cache !== undefined)
+ this.min_html_cache.kick()
+
+ assert(this.min_svg_cache !== undefined)
+ this.min_svg_cache.kick()
+
+ assert(this.text_cache !== undefined)
+ this.text_cache.kick()
+
+ assert(this.zip_cache !== undefined)
+ this.zip_cache.kick()
+}
+
Site.prototype.serve_internal = function(response, status, mime_type, data) {
response.statusCode = status
// html files will be direct recipient of links/bookmarks so can't have
// use setTimeout() instead of setInterval() to avoid bunches
// of calls after the computer has been suspended for a while
let refresh_config = async () => {
- let config = await jst_cache.get('_config/server.jst', true)
- if (config !== undefined) {
- let prev_server = server
- server = await config(resources, prev_server)
- await server.start()
- if (prev_server !== undefined)
- await prev_server.stop()
+ try {
+ let config = await jst_cache.get('_config/server.jst', true)
+ if (config !== undefined) {
+ let prev_server = server
+ let new_server = await config(resources, prev_server)
+ await new_server.start() // exception here cancels server change
+ server = new_server
+ if (prev_server !== undefined)
+ await prev_server.stop() // exception here doesn't cancel change
+ }
+ await server.kick()
+ }
+ catch (err) {
+ console.error(err.stack || err.message)
}
- server.kick()
setTimeout(refresh_config, 5000)
// returned Promise will be ignored
}
{
"name": "@ndcode/jst_server",
- "version": "1.0.0",
- "description": "Web server using JavaScript template system",
+ "version": "0.1.0",
+ "description": "Lightweight web server using JavaScript template system",
+ "keywords": [
+ "web",
+ "HTTP",
+ "HTTPS",
+ "server",
+ "template"
+ ],
+ "homepage": "https://www.ndcode.org",
+ "repository": {
+ "type": "git",
+ "url": "https://git.ndcode.org/public/jst_server.git"
+ },
+ "bugs": {
+ "email": "nick@ndcode.org"
+ },
+ "bin": {
+ "jst_server": "cli.js"
+ }
"main": "index.js",
+ "engines": {
+ "node": ">=0.4.0"
+ },
"directories": {},
"dependencies": {
"@ndcode/json_cache": "^0.1.2",
"@ndcode/min_svg_cache": "^0.1.0",
"@ndcode/text_cache": "^0.1.0",
"@ndcode/zip_cache": "^0.1.0",
- "commander": "^2.18.0",
- "fs": "^0.0.1-security",
- "http": "^0.0.0",
- "https": "^1.0.0",
"querystring": "^0.2.0",
"socket.io": "^2.1.1",
"url": "^0.11.0"
},
"devDependencies": {},
"scripts": {},
- "author": "Nick Downing",
- "license": "GPL-3.0",
- "bin": {
- "jst_server": "cli.js"
- }
+ "maintainers": "Nick Downing <nick@ndcode.org>",
+ "license": "MIT"
}