From df8cb8d96fe9d1f249e2db5edc9e3dd2e15878a9 Mon Sep 17 00:00:00 2001 From: AJ ONeal Date: Mon, 13 Mar 2017 16:39:43 -0600 Subject: [PATCH] use arrays instead of maps --- admin/public/index.html | 45 +++++++++++----- bin/goldilocks.js | 109 +++++++++++++++++++++++-------------- lib/app.js | 115 ++++++++++++++++++++++++++++++++++------ 3 files changed, 201 insertions(+), 68 deletions(-) diff --git a/admin/public/index.html b/admin/public/index.html index 32872e2..2492c96 100644 --- a/admin/public/index.html +++ b/admin/public/index.html @@ -48,32 +48,51 @@

Global Settings:


-
Pathname: - -
Modulename: {{modulename}} -
Target: - +
Pathname: + +
Modulename: {{module.$id}} +
{{key}}: +

Per-Domain Settings:

-
+

-
Pathname: - -
Modulename: {{modulename}} -
Target: - +
Pathname: + +
Modulename: {{module.$id}} +
{{key}}: +
-
-
{{vm.config}}
+
+

Fallback Settings:

+
+
Pathname: + +
Modulename: {{module.$id}} +
{{key}}: + +
+
+
+
+ +
+ +
+
+ +
{{vm.config}}
+
+
diff --git a/bin/goldilocks.js b/bin/goldilocks.js index e7f8808..9fd2119 100755 --- a/bin/goldilocks.js +++ b/bin/goldilocks.js @@ -94,20 +94,10 @@ function createServer(port, _delete_me_, content, opts) { var app = require('../lib/app.js'); var directive = { - content: content - , livereload: opts.livereload - , global: { - greenlock: { email: opts.email, tos: opts.tos } - , rvpn: { email: opts.email, tos: opts.tos } - , paths: { - '/assets/': { serve: [ opts.assetsPath ] } - // TODO figure this b out - , '/.well-known/': { serve: [ path.resolve(opts.assetsPath, 'well-known') ] } - , '/': { serve: [ opts.webRoot ], indexes: [ opts.webRoot ] } - } - } + global: opts.global , sites: opts.sites - , expressApp: opts.expressApp + , defaults: opts.defaults + , cwd: process.cwd() }; var server; var insecureServer; @@ -260,13 +250,15 @@ function run() { var argv = minimist(process.argv.slice(2)); var port = parseInt(argv.p || argv.port || argv._[0], 10) || httpsPort; var livereload = argv.livereload; - var defaultWebRoot = path.resolve(argv['default-web-root'] || argv.d || argv._[1] || process.cwd()); + var defaultWebRoot = path.normalize(argv['default-web-root'] || argv.d || argv._[1] || '.'); + var assetsPath = path.join(__dirname, '..', 'packages', 'assets'); var content = argv.c; var letsencryptHost = argv['letsencrypt-certs']; var yaml = require('js-yaml'); var fs = PromiseA.promisifyAll(require('fs')); var configFile = argv.c || argv.conf || argv.config; var config; + console.log('defaultWebRoot', defaultWebRoot); try { config = fs.readFileSync(configFile || 'Goldilocks.yml'); @@ -383,7 +375,8 @@ function run() { opts.cwd = process.cwd(); - opts.sites = {}; + opts.sites = []; + opts.sites._map = {}; if (argv.sites) { opts._externalHost = false; @@ -394,48 +387,86 @@ function run() { opts._externalHost = opts._externalHost || !/(^|\.)localhost\./.test(servername); // TODO allow reverse proxy - if (!opts.sites[servername]) { - opts.sites[servername] = { paths: {} }; + if (!opts.sites._map[servername]) { + opts.sites._map[servername] = { $id: servername, paths: [] }; + opts.sites._map[servername].paths._map = {}; + opts.sites.push(opts.sites._map[servername]); } if (!nameparts.length) { return; } - if (!opts.sites[servername].paths['/']) { - opts.sites[servername].paths['/'] = {}; + if (!opts.sites._map[servername].paths._map['/']) { + opts.sites._map[servername].paths._map['/'] = { $id: '/', modules: [] }; + opts.sites._map[servername].paths.push(opts.sites._map[servername].paths._map['/']); } - modules = opts.sites[servername].paths['/']; - modules.serve = nameparts; - modules.indexes = nameparts; + modules = opts.sites._map[servername].paths._map['/'].modules; + modules.push({ + $id: 'serve' + , paths: nameparts + }); + modules.push({ + $id: 'indexes' + , paths: nameparts + }); }); } - opts.groups = {}; + opts.groups = []; // 'packages', 'assets', 'com.daplie.caddy' - opts.sites['localhost.alpha.daplie.me'] = { + opts.global = { + modules: [ // TODO uh-oh we've got a mixed bag of modules (various types), a true map + { $id: 'greenlock', email: opts.email, tos: opts.tos } + , { $id: 'rvpn', email: opts.email, tos: opts.tos } + , { $id: 'content', content: content } + , { $id: 'livereload', on: opts.livereload } + , { $id: 'app', path: opts.expressApp } + ] + , paths: [ + { $id: '/assets/', modules: [ { $id: 'serve', paths: [ assetsPath ] } ] } + // TODO figure this b out + , { $id: '/.well-known/', modules: [ + { $id: 'serve', paths: [ path.join(assetsPath, 'well-known') ] } + ] } + ] + }; + opts.defaults = { + modules: [] + , paths: [ + { $id: '/', modules: [ + { $id: 'serve', paths: [ defaultWebRoot ] } + , { $id: 'indexes', paths: [ defaultWebRoot ] } + ] } + ] + }; + opts.sites.push({ // greenlock: {} - paths: { - '/': { serve: [ path.resolve(__dirname, '..', 'admin', 'public') ] } - , '/api/': { app: path.join(__dirname, 'admin') } - } - }; - opts.sites['localhost.daplie.invalid'] = { - paths: { - '/': { serve: [ path.resolve(__dirname, '..', 'admin', 'public') ] } - , '/api/': { app: path.join(__dirname, 'admin') } - } - }; - opts.assetsPath = path.join(__dirname, '..', 'packages', 'assets'); - opts.webRoot = defaultWebRoot; + $id: 'localhost.alpha.daplie.me' + , paths: [ + { $id: '/', modules: [ + { $id: 'serve', paths: [ path.resolve(__dirname, '..', 'admin', 'public') ] } + ] } + , { $id: '/api/', modules: [ + { $id: 'app', path: path.join(__dirname, 'admin') } + ] } + ] + }); + opts.sites.push({ + $id: 'localhost.daplie.invalid' + , paths: [ + { $id: '/', modules: [ { $id: 'serve', paths: [ path.resolve(__dirname, '..', 'admin', 'public') ] } ] } + , { $id: '/api/', modules: [ { $id: 'app', path: path.join(__dirname, 'admin') } ] } + ] + }); // ifaces opts.ifaces = require('../lib/local-ip.js').find(); // TODO use arrays in all things - opts._old_server_name = Object.keys(opts.sites)[0]; + opts._old_server_name = opts.sites[0].$id; opts.pubdir = defaultWebRoot.replace(/(:hostname|:servername).*/, ''); if (argv.p || argv.port || argv._[0]) { @@ -454,7 +485,7 @@ function run() { opts.livereload = livereload; if (argv['express-app']) { - opts.expressApp = require(path.resolve(process.cwd(), argv['express-app'])); + opts.expressApp = require(argv['express-app']); } if (opts.email || opts._externalHost) { diff --git a/lib/app.js b/lib/app.js index 7a5f38b..741f948 100644 --- a/lib/app.js +++ b/lib/app.js @@ -81,6 +81,69 @@ module.exports = function (opts) { app = express(); + if (!opts.sites) { + opts.sites = []; + } + opts.sites._map = {}; + opts.sites.forEach(function (site) { + + if (!opts.sites._map[site.$id]) { + opts.sites._map[site.$id] = site; + } + + if (!site.paths) { + site.paths = []; + } + if (!site.paths._map) { + site.paths._map = {}; + } + site.paths.forEach(function (path) { + + site.paths._map[path.$id] = path; + + if (!path.modules) { + path.modules = []; + } + if (!path.modules._map) { + path.modules._map = {}; + } + path.modules.forEach(function (module) { + + path.modules._map[module.$id] = module; + }); + }); + }); + + function mapMap(el, i, arr) { + arr._map[el.$id] = el; + } + opts.global.modules._map = {}; + opts.global.modules.forEach(mapMap); + opts.global.paths._map = {}; + opts.global.paths.forEach(function (path, i, arr) { + mapMap(path, i, arr); + //opts.global.paths._map[path.$id] = path; + path.modules._map = {}; + path.modules.forEach(mapMap); + }); + opts.sites.forEach(function (site) { + site.paths._map = {}; + site.paths.forEach(function (path, i, arr) { + mapMap(path, i, arr); + //site.paths._map[path.$id] = path; + path.modules._map = {}; + path.modules.forEach(mapMap); + }); + }); + opts.defaults.modules._map = {}; + opts.defaults.modules.forEach(mapMap); + opts.defaults.paths._map = {}; + opts.defaults.paths.forEach(function (path, i, arr) { + mapMap(path, i, arr); + //opts.global.paths._map[path.$id] = path; + path.modules._map = {}; + path.modules.forEach(mapMap); + }); return app.use('/', function (req, res, next) { if (!req.headers.host) { next(new Error('missing HTTP Host header')); @@ -112,21 +175,22 @@ module.exports = function (opts) { var hostname = (host||'').split(':')[0].toLowerCase(); console.log('opts.global', opts.global); - var sites = [ opts.global || {}, opts.sites[hostname] || {}, opts.defer || {} ]; + var sites = [ opts.global || null, opts.sites._map[hostname] || null, opts.defaults || null ]; var loadables = { serve: function (config, hostname, pathname, req, res, next) { - config = config.slice(0); var originalUrl = req.url; + var dirpaths = config.paths.slice(0); function nextServe() { - var dirname = config.pop(); - console.log('[serve]', req.url, hostname, pathname, dirname); + var dirname = dirpaths.pop(); if (!dirname) { req.url = originalUrl; next(); return; } + console.log('[serve]', req.url, hostname, pathname, dirname); + dirname = path.resolve(opts.cwd, dirname.replace(/:hostname/, hostname)); if (!serveStaticMap[dirname]) { serveStaticMap[dirname] = serveStatic(dirname); } @@ -138,18 +202,19 @@ module.exports = function (opts) { nextServe(); } , indexes: function (config, hostname, pathname, req, res, next) { - config = config.slice(0); var originalUrl = req.url; + var dirpaths = config.paths.slice(0); function nextIndex() { - var dirname = config.pop(); - console.log('[indexes]', req.url, hostname, pathname, dirname); + var dirname = dirpaths.pop(); if (!dirname) { req.url = originalUrl; next(); return; } + console.log('[indexes]', req.url, hostname, pathname, dirname); + dirname = path.resolve(opts.cwd, dirname.replace(/:hostname/, hostname)); if (!serveStaticMap[dirname]) { serveIndexMap[dirname] = serveIndex(dirname); } @@ -159,18 +224,26 @@ module.exports = function (opts) { req.url = req.url.substr(pathname.length - 1); nextIndex(); } + , app: function (config, hostname, pathname, req, res, next) { + //var appfile = path.resolve(/*process.cwd(), */config.path.replace(/:hostname/, hostname)); + var appfile = config.path.replace(/:hostname/, hostname); + var app = require(appfile); + app(req, res, next); + } }; - function runModule(config, hostname, pathname, modulename, req, res, next) { + function runModule(module, hostname, pathname, modulename, req, res, next) { if (!loadables[modulename]) { next(new Error("no module '" + modulename + "' found")); return; } - loadables[modulename](config, hostname, pathname, req, res, next); + loadables[modulename](module, hostname, pathname, req, res, next); } function iterModules(modules, hostname, pathname, req, res, next) { - var modulenames = Object.keys(modules); + console.log('modules'); + console.log(modules); + var modulenames = Object.keys(modules._map); function nextModule() { var modulename = modulenames.pop(); @@ -180,14 +253,17 @@ module.exports = function (opts) { } console.log('modules', modules); - runModule(modules[modulename], hostname, pathname, modulename, req, res, nextModule); + runModule(modules._map[modulename], hostname, pathname, modulename, req, res, nextModule); } nextModule(); } function iterPaths(site, hostname, req, res, next) { - var pathnames = Object.keys(site.paths || {}); + console.log('site', hostname); + console.log(site); + var pathnames = Object.keys(site.paths._map); + console.log('pathnames', pathnames); pathnames = pathnames.filter(function (pathname) { // TODO ensure that pathname has trailing / return (0 === req.url.indexOf(pathname)); @@ -196,27 +272,34 @@ module.exports = function (opts) { pathnames.sort(function (a, b) { return b.length - a.length; }); + console.log('pathnames', pathnames); function nextPath() { - var pathname = pathnames.pop(); + var pathname = pathnames.shift(); if (!pathname) { next(); return; } console.log('iterPaths', hostname, pathname, req.url); - iterModules(site.paths[pathname], hostname, pathname, req, res, nextPath); + iterModules(site.paths._map[pathname].modules, hostname, pathname, req, res, nextPath); } nextPath(); } function nextSite() { - var site = sites.pop(); - if (!site) { + console.log('hostname', hostname, sites); + var site; + if (!sites.length) { next(); // 404 return; } + site = sites.shift(); + if (!site) { + nextSite(); + return; + } iterPaths(site, hostname, req, res, nextSite); }