Implement Site object, which can be extended by a site_factory.jst file at root
authorNick Downing <downing.nick@gmail.com>
Sat, 20 Oct 2018 01:22:20 +0000 (12:22 +1100)
committerNick Downing <downing.nick@gmail.com>
Sat, 20 Oct 2018 03:27:17 +0000 (14:27 +1100)
Site.js [moved from site.js with 79% similarity]
package.json
resources.js
server.js

diff --git a/site.js b/Site.js
similarity index 79%
rename from site.js
rename to Site.js
index 8e2fcd6..f5666df 100644 (file)
--- a/site.js
+++ b/Site.js
@@ -11,7 +11,13 @@ let url = require('url')
 let fs_readFile = util.promisify(fs.readFile)
 let fs_stat = util.promisify(fs.stat)
 
-let app = async (site, site_root, req, res, protocol) => {
+let Site = function(root) {
+  if (!this instanceof Site)
+    throw Error('Site is a constructor')
+  this.root = root
+}
+
+Site.prototype.app = async function(host, req, res, protocol) {
   // parse the pathname portion of url
   // this is actually cheating since it's not a complete url
   let parsed_url = url.parse(req.url, true)
@@ -29,13 +35,13 @@ let app = async (site, site_root, req, res, protocol) => {
   for (let i = 1; i < path.length - 1; ++i) {
     dir_name += '/' + path[i]
     if (path[i].length === 0 || path[i].charAt(0) === '.') {
-      console.log(site, 'bad path component', dir_name)
+      console.log(host, 'bad path component', dir_name)
       server.die(res)
       return
     }
     let stats
     try {
-      stats = await fs_stat(site_root + dir_name)
+      stats = await fs_stat(this.root + dir_name)
     }
     catch (err) {
       if (err.code !== 'ENOENT')
@@ -43,20 +49,20 @@ let app = async (site, site_root, req, res, protocol) => {
       if (!dir_name_is_pub) {
         let temp = dir_name + '.pub'
         try {
-          stats = await fs_stat(site_root + temp)
+          stats = await fs_stat(this.root + temp)
           dir_name = temp
           dir_name_is_pub = true
         }
         catch (err2) {
           if (err2.code !== 'ENOENT')
             throw err2
-          console.log(site, 'directory not found', dir_name)
+          console.log(host, 'directory not found', dir_name)
           server.die(res)
           return
         }
       }
       if (!stats.isDirectory()) {
-        console.log(site, 'not directory', dir_name)
+        console.log(host, 'not directory', dir_name)
         server.die(res)
         return
       }
@@ -67,7 +73,7 @@ let app = async (site, site_root, req, res, protocol) => {
   if (file_name === '') {
     path[path.length - 1] = 'index.html'
     path = path.join('/')
-    console.log(site, 'server.redirecting', parsed_url.pathname, 'to', path)
+    console.log(host, 'server.redirecting', parsed_url.pathname, 'to', path)
     server.redirect(res, path + (parsed_url.search || ''))
     return
   }
@@ -81,11 +87,11 @@ let app = async (site, site_root, req, res, protocol) => {
     config.mime_type_default
 
   if (dir_name_is_pub) {
-    temp = site_root + dir_name + '/' + file_name
+    temp = this.root + dir_name + '/' + file_name
     try {
       let data = await fs_readFile(temp)
       console.log(
-        site,
+        host,
         'serving',
         temp,
         'length',
@@ -105,9 +111,9 @@ let app = async (site, site_root, req, res, protocol) => {
     // (has no .pub component), though constructed in a roundabout way
     temp = page + '.pub'
     try {
-      let data = await fs_readFile(site_root + temp)
+      let data = await fs_readFile(this.root + temp)
       console.log(
-        site,
+        host,
         'serving',
         temp,
         'length',
@@ -125,17 +131,26 @@ let app = async (site, site_root, req, res, protocol) => {
     switch (file_type) {
     case 'html':
       temp = page + '.jst'
+      let template
       try {
+        template = await js_template(this.root, this.root, temp)
+      }
+      catch (err) {
+        if (err.code !== 'ENOENT') // note: err.code might be undefined
+          throw err
+        template = undefined
+      }
+      if (template !== undefined) {
         let _out = []
-        await (await js_template(site_root, site_root, temp))(
+        await template(
           {
             cookies: cookie.parse(req.headers.cookie || ''),
             lang: 'en',
+            host: host,
             method: req.method,
             page: page,
             query: parsed_url.query,
             read_stream: req,
-            resources: resources,
             set_cookie: (key, value, expires, path) => {
               res.setHeader(
                 'Set-Cookie',
@@ -149,14 +164,13 @@ let app = async (site, site_root, req, res, protocol) => {
                 ';'
               )
             },
-            site: site,
-            site_root: site_root
+            site: this
           },
           _out
         )
         let data = Buffer.from(_out.join(''))
         console.log(
-          site,
+          host,
           'serving',
           temp,
           'length',
@@ -166,22 +180,18 @@ let app = async (site, site_root, req, res, protocol) => {
         server.serve(res, 200, mime_type, data)
         return
       }
-      catch (err) {
-        if (err.code !== 'ENOENT') // should check error type
-          throw err
-      }
       break
 
     case 'css':
       temp = page + '.less'
       try {
         let data = await resources.get_less(
-          site_root + temp,
-          site_root,
+          this.root + temp,
+          this.root,
           dir_name
         )
         console.log(
-          site,
+          host,
           'serving',
           temp,
           'length',
@@ -199,11 +209,11 @@ let app = async (site, site_root, req, res, protocol) => {
     }
   }
 
-  let favicons = await resources.get_zip(site_root + '/favicons.zip')
+  let favicons = await resources.get_zip(this.root + '/favicons.zip')
   if (Object.prototype.hasOwnProperty.call(favicons, page)) {
     let data = favicons[page]
     console.log(
-      site,
+      host,
       'serving',
       page,
       'length',
@@ -214,8 +224,8 @@ let app = async (site, site_root, req, res, protocol) => {
     return
   }
 
-  console.log(site, 'file not found', page)
+  console.log(host, 'file not found', page)
   server.die(res)
 }
 
-exports.app = app
+module.exports = Site
index 2ea0e43..705977a 100644 (file)
@@ -5,23 +5,23 @@
   "main": "jst_server.js",
   "directories": {},
   "dependencies": {
+    "BuildCache": "../build_cache.git/BuildCache-1.0.0.tgz",
+    "JSONCache": "../json_cache.git/JSONCache-1.0.0.tgz",
     "babel-cli": "^6.26.0",
-    "build_cache": "file:../build_cache.git/build_cache-1.0.0.tgz",
     "commander": "^2.18.0",
     "cookie": "^0.3.1",
     "emailjs": "^2.2.0",
     "fs": "^0.0.1-security",
     "http": "^0.0.0",
     "https": "^1.0.0",
-    "js_template": "file:../js_template.git/acorn/js_template-6.0.2.tgz",
-    "json_cache": "file:../json_cache.git/json_cache-1.0.0.tgz",
+    "js_template": "../js_template.git/acorn/js_template-v6.0.2.tgz",
     "less": "^3.8.1",
     "querystring": "^0.2.0",
     "stream-buffers": "^3.0.2",
     "url": "^0.11.0",
     "xdate": "^0.8.2",
     "yauzl": "^2.10.0",
-    "zetjs": "file:../zettair.git/src/zetjs/zetjs-1.0.0.tgz"
+    "zetjs": "../zettair.git/src/zetjs/zetjs-1.0.0.tgz"
   },
   "devDependencies": {},
   "scripts": {},
index a492da6..c7943bd 100644 (file)
@@ -1,7 +1,7 @@
-let BuildCache = require('build_cache')
+let BuildCache = require('BuildCache')
+let JSONCache = require('JSONCache')
 let emailjs = require('emailjs')
 let fs = require('fs')
-let JSONCache = require('json_cache')
 let less = require('less/lib/less-node')
 var stream_buffers = require('stream-buffers')
 let util = require('util')
@@ -35,7 +35,7 @@ let get_json = path => build_cache_json.get(
 )
 
 let build_cache_less = new BuildCache()
-let get_less = (path, site_root, dir_name) => build_cache_less.get(
+let get_less = (path, root, dir_name) => build_cache_less.get(
   path,
   async result => {
     console.log('compiling', path)
@@ -53,11 +53,11 @@ let get_less = (path, site_root, dir_name) => build_cache_less.get(
         //lint: false,
         //math: 0,
         //modifyVars: null,
-        paths: [site_root + dir_name],
+        paths: [root + dir_name],
         //plugins: [],
         //reUsePluginManager: true,
         //rewriteUrls: false,
-        rootpath: site_root//,
+        rootpath: root//,
         //strictImports: false,
         //strictUnits: false,
         //urlArgs: ''
@@ -77,6 +77,21 @@ let get_text = path => build_cache_text.get(
   }
 )
 
+let build_cache_zet = new BuildCache()
+let get_zet = path => build_cache_zet.get(
+  path,
+  async result => {
+    console.log('opening', path)
+    result.deps = [
+      path + '.map.0',
+      path + '.param.0',
+      path + '.v.0',
+      path + '.vocab.0'
+    ]
+    result.value = new zetjs.Index(path)
+  }
+)
+
 let build_cache_zip = new BuildCache()
 let get_zip = path => build_cache_zip.get(
   path,
@@ -123,21 +138,6 @@ let get_zip = path => build_cache_zip.get(
   }
 )
 
-let build_cache_zet = new BuildCache()
-let get_zet = path => build_cache_zet.get(
-  path,
-  async result => {
-    console.log('opening', path)
-    result.deps = [
-      path + '.map.0',
-      path + '.param.0',
-      path + '.v.0',
-      path + '.vocab.0'
-    ]
-    result.value = new zetjs.Index(path)
-  }
-)
-
 // this is for read/write JSON files
 // they will not be reloaded from disk if modified
 let try_mkdir = async path => {
@@ -149,14 +149,13 @@ let try_mkdir = async path => {
       throw err
   }
 }
-let json_cache = new JSONCache()
-json_cache.diag = true
+let json_cache = new JSONCache(true)
 
 exports.get_email = get_email
 exports.get_json = get_json
 exports.get_less = get_less
 exports.get_text = get_text
-exports.get_zip = get_zip
 exports.get_zet = get_zet
+exports.get_zip = get_zip
 exports.try_mkdir = try_mkdir
 exports.json_cache = json_cache
index cfc64ac..0502ce9 100644 (file)
--- a/server.js
+++ b/server.js
@@ -1,6 +1,7 @@
+let Site = require('./Site')
 let assert = require('assert')
 let config = require('./config')
-let site = require('./site')
+let js_template = require('js_template')
 
 let caching = false
 let set_caching = value => {
@@ -30,30 +31,57 @@ let redirect = (res, location) => {
   res.end('Redirecting to ' + location)
 }
 
+let site_cache = {}
+let site_factory_default = async root => new Site(root)
+
 let app = async (req, res, protocol) => {
   await config.refresh()
   try {
-    let domain_name = req.headers.host || 'localhost'
-    let temp = domain_name.indexOf(':')
-    let port_suffix = temp === -1 ? '' : domain_name.substring(temp)
-    domain_name = domain_name.substring(
+    let host = req.headers.host || 'localhost'
+    let temp = host.indexOf(':')
+    let port_suffix = temp === -1 ? '' : host.substring(temp)
+    host = host.substring(
       0,
-      domain_name.length - port_suffix.length
+      host.length - port_suffix.length
     )
-    if (!Object.prototype.hasOwnProperty.call(config.sites, domain_name)) {
-      console.log('nonexistent site', domain_name)
+    if (!Object.prototype.hasOwnProperty.call(config.sites, host)) {
+      console.log('nonexistent site', host)
       die(res)
       return
     }
-    temp = config.sites[domain_name]
+    temp = config.sites[host]
     switch (temp.type) {
     case 'redirect':
       let new_domain = temp.domain
-      console.log('redirecting', domain_name, 'to', new_domain)
+      console.log('redirecting', host, 'to', new_domain)
       redirect(res, protocol + '://' + new_domain + port_suffix + req.url)
       break
     case 'site':
-      await site.app(domain_name, temp.root, req, res, protocol)
+      let site_factory
+      try {
+        site_factory = await js_template(
+          temp.root,
+          temp.root,
+          'site_factory.jst'
+        )
+      }
+      catch (err) {
+        if (err.code !== 'ENOENT') // note: err.code might be undefined
+          throw err
+        site_factory = site_factory_default
+      }
+      let site
+      if (
+        !Object.prototype.hasOwnProperty.call(site_cache, temp.root) ||
+        (site = site_cache[temp.root]).factory !== site_factory
+      ) {
+        site = {
+          factory: site_factory,
+          object: await site_factory(temp.root)
+        }
+        site_cache[temp.root] = site
+      }
+      await site.object.app(host, req, res, protocol)
       break
     default:
       assert(false)