From 760f00af350e250800500e286d4319c1d35dfbc4 Mon Sep 17 00:00:00 2001 From: AJ ONeal Date: Wed, 2 Dec 2015 12:33:42 +0000 Subject: [PATCH] allow multiple apis, broke multiple pages --- lib/package-server.js | 78 +++++++++++++++++++++---------------------- lib/schemes-config.js | 66 +++++++++++++++++++++++------------- 2 files changed, 80 insertions(+), 64 deletions(-) diff --git a/lib/package-server.js b/lib/package-server.js index f17ec66..ea0feb2 100644 --- a/lib/package-server.js +++ b/lib/package-server.js @@ -90,7 +90,7 @@ function loadPages(pkgConf, route, req, res, next) { route._promise_app = new PromiseA(function (resolve, reject) { fs.exists(pkgpath, function (exists) { if (!exists) { - reject(new Error("package is registered but does not exist")); + reject(new Error("package '" + pkgpath + "' is registered but does not exist")); return; } @@ -103,10 +103,10 @@ function loadPages(pkgConf, route, req, res, next) { handlePromise(route._promise_app); } -function getApi(pkgConf, pkgDeps, route) { +function getApi(pkgConf, pkgDeps, packagedApi) { var PromiseA = require('bluebird'); var path = require('path'); - var pkgpath = path.join(pkgConf.apipath, route.api.id/*, (route.api.version || '')*/); + var pkgpath = path.join(pkgConf.apipath, packagedApi.id/*, (packagedApi.api.version || '')*/); // TODO needs some version stuff (which would also allow hot-loading of updates) // TODO version could be tied to sha256sum @@ -138,10 +138,10 @@ function getApi(pkgConf, pkgDeps, route) { } try { - route._apipkg = require(path.join(pkgpath, 'package.json')); - route._apiname = route._apipkg.name; - if (route._apipkg.walnut) { - pkgpath += '/' + route.apipkg.walnut; + packagedApi._apipkg = require(path.join(pkgpath, 'package.json')); + packagedApi._apiname = packagedApi._apipkg.name; + if (packagedApi._apipkg.walnut) { + pkgpath += '/' + packagedApi._apipkg.walnut; } promise = require(pkgpath).create(pkgConf, pkgDeps, myApp); } catch(e) { @@ -151,41 +151,41 @@ function getApi(pkgConf, pkgDeps, route) { promise.then(function () { // TODO give pub/priv pair for app and all public keys - // route._api = require(pkgpath).create(pkgConf, pkgDeps, myApp); - route._api = require('express')(); - route._api_app = myApp; + // packagedApi._api = require(pkgpath).create(pkgConf, pkgDeps, myApp); + packagedApi._api = require('express')(); + packagedApi._api_app = myApp; // TODO fix backwards compat // /api/com.example.foo (no change) - route._api.use('/', route._api_app); + packagedApi._api.use('/', packagedApi._api_app); // /api/com.example.foo => / - route._api.use('/api/' + route.api.id, function (req, res, next) { - //console.log('api mangle 2:', '/api/' + route.api.id, req.url); - route._api_app(req, res, next); + packagedApi._api.use('/api/' + packagedApi.id, function (req, res, next) { + //console.log('api mangle 2:', '/api/' + packagedApi.api.id, req.url); + packagedApi._api_app(req, res, next); }); // /api/com.example.foo => /api - route._api.use('/', function (req, res, next) { - req.url = '/api' + req.url.slice(('/api/' + route.api.id).length); + packagedApi._api.use('/', function (req, res, next) { + req.url = '/api' + req.url.slice(('/api/' + packagedApi.id).length); //console.log('api mangle 3:', req.url); - route._api_app(req, res, next); + packagedApi._api_app(req, res, next); }); - resolve(route._api); + resolve(packagedApi._api); }, reject); }); } -function loadApi(pkgConf, pkgDeps, route) { +function loadApi(pkgConf, pkgDeps, packagedApi) { function handlePromise(p) { return p.then(function (api) { - route._api = api; + packagedApi._api = api; return api; }); } - if (!route._promise_api) { - route._promise_api = getApi(pkgConf, pkgDeps, route); + if (!packagedApi._promise_api) { + packagedApi._promise_api = getApi(pkgConf, pkgDeps, packagedApi); } - return handlePromise(route._promise_api); + return handlePromise(packagedApi._promise_api); } function layerItUp(pkgConf, router, req, res, next) { @@ -232,42 +232,39 @@ function runApi(opts, router, req, res, next) { var pkgConf = opts.config; var pkgDeps = opts.deps; //var Services = opts.Services; - var route; + var packagedApi; // TODO compile packagesMap // TODO people may want to use the framework in a non-framework way (i.e. to conceal the module name) - router.packages.some(function (_route) { - if (!_route.api) { - return; - } - + router.packagedApis.some(function (_packagedApi) { var pathname = router.pathname; if ('/' === pathname) { pathname = ''; } // TODO allow for special apis that do not follow convention (.well_known, webfinger, oauth3.html, etc) - if (!_route._api_re) { - _route._api_re = new RegExp(escapeStringRegexp(pathname + '/api/' + _route.api.id) + '\/([\\w\\.\\-]+)(\\/|\\?|$)'); - //console.log('[api re 2]', _route._api_re); + if (!_packagedApi._api_re) { + _packagedApi._api_re = new RegExp(escapeStringRegexp(pathname + '/api/' + _packagedApi.id) + '\/([\\w\\.\\-]+)(\\/|\\?|$)'); + //console.log('[api re 2]', _packagedApi._api_re); } - if (_route._api_re.test(req.url)) { - route = _route; + if (_packagedApi._api_re.test(req.url)) { + packagedApi = _packagedApi; return true; } }); - if (!route) { - //console.log('[no api route]'); + if (!packagedApi) { + console.log("[ODD] no api for '" + req.url + "'"); next(); return; } + // appId means hash(api.id + host + path) - also called "experience" Object.defineProperty(req, 'appId', { enumerable: true , configurable: false , writable: false // TODO this identifier may need to be non-deterministic as to transfer if a domain name changes but is still the "same" app // (i.e. a company name change. maybe auto vs manual register - just like oauth3?) - , value: route.id + , value: packagedApi.domain.id }); Object.defineProperty(req, 'appConfig', { enumerable: true @@ -292,12 +289,13 @@ function runApi(opts, router, req, res, next) { // TODO freeze objects for passing them into app // - if (route._api) { - route._api(req, res, next); + if (packagedApi._api) { + packagedApi._api(req, res, next); return; } - loadApi(pkgConf, pkgDeps, route).then(function (api) { + console.log("pkgpath", pkgConf.apipath, packagedApi.id); + loadApi(pkgConf, pkgDeps, packagedApi).then(function (api) { api(req, res, next); }, function (err) { console.error('[App Promise Error]'); diff --git a/lib/schemes-config.js b/lib/schemes-config.js index 995591a..a2b7561 100644 --- a/lib/schemes-config.js +++ b/lib/schemes-config.js @@ -19,54 +19,61 @@ function deserialize(results) { results.domains.forEach(function (domain) { config.domains[domain.id] = domain; - // as it currently stands each of these will only have one - /* domain.apis = []; domain.apiIds = []; - domain.apisMap = {}; domain.apps = []; domain.appIds = []; - domain.appsMap = {}; - */ - domain.api = null; - domain.apiId = null; - domain.app = null; - domain.appId = null; - domain.appsMap = null; + //domain.appsMap = null; }); results.apisDomains.forEach(function (ad) { var api = config.apis[ad.apiId]; var domain = config.domains[ad.domainId]; + if (api && !api.domainsMap[domain.id]) { api.domainIds.push(domain.id); api.domainsMap[domain.id] = domain; api.domains.push(domain); } - if (domain) { - if (domain.api) { - console.error("[SANITY FAIL] single domain has multiple frontends in db: '" + domain.id + "'"); - } - domain.apiId = api.id; - domain.api = api; + + if (!domain) { + return; } + + if (!api) { + console.error("NO API '" + ad.apiId + "' requested by '" + ad.domainId + "'"); + return; + } + + domain.apiIds.push(api.id); + domain.apis.push(api); }); results.appsDomains.forEach(function (ad) { var app = config.apps[ad.appId]; var domain = config.domains[ad.domainId]; + if (app && !app.domainsMap[domain.id]) { app.domainIds.push(domain.id); app.domainsMap[domain.id] = domain; app.domains.push(domain); } - if (domain) { - if (domain.app) { - console.error("[SANITY FAIL] single domain has multiple frontends in db: '" + domain.id + "'"); - } - domain.appId = app.id; - domain.app = app; + + if (!domain) { + return; } + + if (domain.apps.length > 1) { + console.error("[TODO] multiple frontend roots for '" + domain.id + "' cannot be managed by caddy (yet)"); + } + + if (!app) { + console.error("NO PAGES '" + ad.appId + "' requested by '" + ad.domainId + "'"); + return; + } + + domain.appIds.push(app.id); + domain.apps.push(app); }); return config; @@ -114,11 +121,22 @@ function getVhostsMap(config) { } if (!vhostsMap[domain.hostname].pathnamesMap[domain.pathname]) { - vhostsMap[domain.hostname].pathnamesMap[domain.pathname] = { pathname: domain.pathname, packages: [] }; + vhostsMap[domain.hostname].pathnamesMap[domain.pathname] = { + pathname: domain.pathname + , packagedApis: [] + , packagedPages: [] + }; vhostsMap[domain.hostname].pathnames.push(vhostsMap[domain.hostname].pathnamesMap[domain.pathname]); } - vhostsMap[domain.hostname].pathnamesMap[domain.pathname].packages.push(domain); + domain.apis.forEach(function (api) { + api.domain = domain; + vhostsMap[domain.hostname].pathnamesMap[domain.pathname].packagedApis.push(api); + }); + domain.apps.forEach(function (page) { + page.domain = domain; + vhostsMap[domain.hostname].pathnamesMap[domain.pathname].packagedPages.push(page); + }); }); return vhostsMap;