Rename Server.roots to Server.site_roots, make each site_root entry be stored in...
authorNick Downing <nick@ndcode.org>
Tue, 4 Dec 2018 11:50:04 +0000 (22:50 +1100)
committerNick Downing <nick@ndcode.org>
Tue, 4 Dec 2018 11:50:04 +0000 (22:50 +1100)
Resources.js
Server.js
Site.js
_config/server.jst
cli.js
package.json
site/_config/site.jst

index fb29e17..640da5d 100644 (file)
@@ -32,7 +32,6 @@ let Resources = function(diag) {
 
 Resources.prototype.ref = async function(key, factory_func, destroy_func) {
   result = this.map.get(key)
-  let value
   if (result === undefined) {
     result = {
       refs: 0,
@@ -40,19 +39,21 @@ Resources.prototype.ref = async function(key, factory_func, destroy_func) {
       destroy_func: destroy_func
     }
     this.map.set(key, result)
-    try {
-      value = await result.value
-    }
-    catch (err) {
-      this.map.delete(key)
-      throw err
-    }
   }
-  else
-    value = await result.value
   result.refs += 1
   if (this.diag)
     console.log(`ref ${key} refs -> ${result.refs}`)
+  let value
+  try {
+    value = await result.value
+  }
+  catch (err) {
+    result.refs -= 1
+    console.log(`err ${key} refs-> ${result.refs}`)
+    if (result.refs === 0)
+      this.map.delete(key)
+    throw err
+  }
   return value
 }
 
index 594eb6c..1c2cc2b 100644 (file)
--- a/Server.js
+++ b/Server.js
@@ -33,7 +33,7 @@ let util = require('util')
 
 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
@@ -62,13 +62,13 @@ let Server = function(resources, options, prev_server) {
     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() {
@@ -78,6 +78,36 @@ 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) {
@@ -113,7 +143,6 @@ Server.prototype.start = async function() {
       async () => new Listener(undefined, options, true),
       listener => /*await*/ listener.stop()
     )
-    listener.request_func = this.request_func
     this.listeners.push(listener)
   }
 }
@@ -122,6 +151,11 @@ Server.prototype.stop = async function() {
   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(
@@ -130,8 +164,33 @@ Server.prototype.stop = async function() {
 }
  
 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) {
@@ -219,36 +278,9 @@ Server.prototype.respond = async function(request, response, protocol) {
         `${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,
@@ -256,13 +288,14 @@ Server.prototype.respond = async function(request, response, protocol) {
           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,
diff --git a/Site.js b/Site.js
index 66a25c6..f33933c 100644 (file)
--- a/Site.js
+++ b/Site.js
@@ -41,7 +41,7 @@ let fs_mkdir = util.promisify(fs.mkdir)
 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
@@ -173,6 +173,38 @@ Site.prototype.stop = async function() {
   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
index f8d6b82..cadf50d 100644 (file)
@@ -1,10 +1,5 @@
 return async (resources, prev_server) => new _jst_server.Server(
   resources,
-  {
-    listeners: [
-      {protocol: 'http:', port: 8080},
-      {protocol: 'https:', port: 8443},
-    ]
-  },
+  {},
   prev_server
 )
diff --git a/cli.js b/cli.js
index baed54a..bc7a45e 100755 (executable)
--- a/cli.js
+++ b/cli.js
@@ -43,15 +43,21 @@ let Server = require('./Server')
     // 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
     }
index b9ecf3c..b9fd2d4 100644 (file)
@@ -1,8 +1,29 @@
 {
   "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"
 }
index e0964a7..45ba10e 100644 (file)
@@ -1 +1,6 @@
-return async (resources, root) => new _jst_server.Site(resources, root)
+return async (resources, root, prev_site) => new _jst_server.Site(
+  resources,
+  root,
+  {},
+  prev_site
+)