allow multiple apis, broke multiple pages

This commit is contained in:
AJ ONeal 2015-12-02 12:33:42 +00:00
parent f4c104bf52
commit 760f00af35
2 changed files with 80 additions and 64 deletions

View File

@ -90,7 +90,7 @@ function loadPages(pkgConf, route, req, res, next) {
route._promise_app = new PromiseA(function (resolve, reject) { route._promise_app = new PromiseA(function (resolve, reject) {
fs.exists(pkgpath, function (exists) { fs.exists(pkgpath, function (exists) {
if (!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; return;
} }
@ -103,10 +103,10 @@ function loadPages(pkgConf, route, req, res, next) {
handlePromise(route._promise_app); handlePromise(route._promise_app);
} }
function getApi(pkgConf, pkgDeps, route) { function getApi(pkgConf, pkgDeps, packagedApi) {
var PromiseA = require('bluebird'); var PromiseA = require('bluebird');
var path = require('path'); 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 needs some version stuff (which would also allow hot-loading of updates)
// TODO version could be tied to sha256sum // TODO version could be tied to sha256sum
@ -138,10 +138,10 @@ function getApi(pkgConf, pkgDeps, route) {
} }
try { try {
route._apipkg = require(path.join(pkgpath, 'package.json')); packagedApi._apipkg = require(path.join(pkgpath, 'package.json'));
route._apiname = route._apipkg.name; packagedApi._apiname = packagedApi._apipkg.name;
if (route._apipkg.walnut) { if (packagedApi._apipkg.walnut) {
pkgpath += '/' + route.apipkg.walnut; pkgpath += '/' + packagedApi._apipkg.walnut;
} }
promise = require(pkgpath).create(pkgConf, pkgDeps, myApp); promise = require(pkgpath).create(pkgConf, pkgDeps, myApp);
} catch(e) { } catch(e) {
@ -151,41 +151,41 @@ function getApi(pkgConf, pkgDeps, route) {
promise.then(function () { promise.then(function () {
// TODO give pub/priv pair for app and all public keys // TODO give pub/priv pair for app and all public keys
// route._api = require(pkgpath).create(pkgConf, pkgDeps, myApp); // packagedApi._api = require(pkgpath).create(pkgConf, pkgDeps, myApp);
route._api = require('express')(); packagedApi._api = require('express')();
route._api_app = myApp; packagedApi._api_app = myApp;
// TODO fix backwards compat // TODO fix backwards compat
// /api/com.example.foo (no change) // /api/com.example.foo (no change)
route._api.use('/', route._api_app); packagedApi._api.use('/', packagedApi._api_app);
// /api/com.example.foo => / // /api/com.example.foo => /
route._api.use('/api/' + route.api.id, function (req, res, next) { packagedApi._api.use('/api/' + packagedApi.id, function (req, res, next) {
//console.log('api mangle 2:', '/api/' + route.api.id, req.url); //console.log('api mangle 2:', '/api/' + packagedApi.api.id, req.url);
route._api_app(req, res, next); packagedApi._api_app(req, res, next);
}); });
// /api/com.example.foo => /api // /api/com.example.foo => /api
route._api.use('/', function (req, res, next) { packagedApi._api.use('/', function (req, res, next) {
req.url = '/api' + req.url.slice(('/api/' + route.api.id).length); req.url = '/api' + req.url.slice(('/api/' + packagedApi.id).length);
//console.log('api mangle 3:', req.url); //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); }, reject);
}); });
} }
function loadApi(pkgConf, pkgDeps, route) { function loadApi(pkgConf, pkgDeps, packagedApi) {
function handlePromise(p) { function handlePromise(p) {
return p.then(function (api) { return p.then(function (api) {
route._api = api; packagedApi._api = api;
return api; return api;
}); });
} }
if (!route._promise_api) { if (!packagedApi._promise_api) {
route._promise_api = getApi(pkgConf, pkgDeps, route); packagedApi._promise_api = getApi(pkgConf, pkgDeps, packagedApi);
} }
return handlePromise(route._promise_api); return handlePromise(packagedApi._promise_api);
} }
function layerItUp(pkgConf, router, req, res, next) { function layerItUp(pkgConf, router, req, res, next) {
@ -232,42 +232,39 @@ function runApi(opts, router, req, res, next) {
var pkgConf = opts.config; var pkgConf = opts.config;
var pkgDeps = opts.deps; var pkgDeps = opts.deps;
//var Services = opts.Services; //var Services = opts.Services;
var route; var packagedApi;
// TODO compile packagesMap // TODO compile packagesMap
// TODO people may want to use the framework in a non-framework way (i.e. to conceal the module name) // 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) { router.packagedApis.some(function (_packagedApi) {
if (!_route.api) {
return;
}
var pathname = router.pathname; var pathname = router.pathname;
if ('/' === pathname) { if ('/' === pathname) {
pathname = ''; pathname = '';
} }
// TODO allow for special apis that do not follow convention (.well_known, webfinger, oauth3.html, etc) // TODO allow for special apis that do not follow convention (.well_known, webfinger, oauth3.html, etc)
if (!_route._api_re) { if (!_packagedApi._api_re) {
_route._api_re = new RegExp(escapeStringRegexp(pathname + '/api/' + _route.api.id) + '\/([\\w\\.\\-]+)(\\/|\\?|$)'); _packagedApi._api_re = new RegExp(escapeStringRegexp(pathname + '/api/' + _packagedApi.id) + '\/([\\w\\.\\-]+)(\\/|\\?|$)');
//console.log('[api re 2]', _route._api_re); //console.log('[api re 2]', _packagedApi._api_re);
} }
if (_route._api_re.test(req.url)) { if (_packagedApi._api_re.test(req.url)) {
route = _route; packagedApi = _packagedApi;
return true; return true;
} }
}); });
if (!route) { if (!packagedApi) {
//console.log('[no api route]'); console.log("[ODD] no api for '" + req.url + "'");
next(); next();
return; return;
} }
// appId means hash(api.id + host + path) - also called "experience"
Object.defineProperty(req, 'appId', { Object.defineProperty(req, 'appId', {
enumerable: true enumerable: true
, configurable: false , configurable: false
, writable: 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 // 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?) // (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', { Object.defineProperty(req, 'appConfig', {
enumerable: true enumerable: true
@ -292,12 +289,13 @@ function runApi(opts, router, req, res, next) {
// TODO freeze objects for passing them into app // TODO freeze objects for passing them into app
// //
if (route._api) { if (packagedApi._api) {
route._api(req, res, next); packagedApi._api(req, res, next);
return; 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); api(req, res, next);
}, function (err) { }, function (err) {
console.error('[App Promise Error]'); console.error('[App Promise Error]');

View File

@ -19,54 +19,61 @@ function deserialize(results) {
results.domains.forEach(function (domain) { results.domains.forEach(function (domain) {
config.domains[domain.id] = domain; config.domains[domain.id] = domain;
// as it currently stands each of these will only have one
/*
domain.apis = []; domain.apis = [];
domain.apiIds = []; domain.apiIds = [];
domain.apisMap = {};
domain.apps = []; domain.apps = [];
domain.appIds = []; domain.appIds = [];
domain.appsMap = {}; //domain.appsMap = null;
*/
domain.api = null;
domain.apiId = null;
domain.app = null;
domain.appId = null;
domain.appsMap = null;
}); });
results.apisDomains.forEach(function (ad) { results.apisDomains.forEach(function (ad) {
var api = config.apis[ad.apiId]; var api = config.apis[ad.apiId];
var domain = config.domains[ad.domainId]; var domain = config.domains[ad.domainId];
if (api && !api.domainsMap[domain.id]) { if (api && !api.domainsMap[domain.id]) {
api.domainIds.push(domain.id); api.domainIds.push(domain.id);
api.domainsMap[domain.id] = domain; api.domainsMap[domain.id] = domain;
api.domains.push(domain); api.domains.push(domain);
} }
if (domain) {
if (domain.api) { if (!domain) {
console.error("[SANITY FAIL] single domain has multiple frontends in db: '" + domain.id + "'"); return;
}
domain.apiId = api.id;
domain.api = api;
} }
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) { results.appsDomains.forEach(function (ad) {
var app = config.apps[ad.appId]; var app = config.apps[ad.appId];
var domain = config.domains[ad.domainId]; var domain = config.domains[ad.domainId];
if (app && !app.domainsMap[domain.id]) { if (app && !app.domainsMap[domain.id]) {
app.domainIds.push(domain.id); app.domainIds.push(domain.id);
app.domainsMap[domain.id] = domain; app.domainsMap[domain.id] = domain;
app.domains.push(domain); app.domains.push(domain);
} }
if (domain) {
if (domain.app) { if (!domain) {
console.error("[SANITY FAIL] single domain has multiple frontends in db: '" + domain.id + "'"); return;
}
domain.appId = app.id;
domain.app = app;
} }
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; return config;
@ -114,11 +121,22 @@ function getVhostsMap(config) {
} }
if (!vhostsMap[domain.hostname].pathnamesMap[domain.pathname]) { 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].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; return vhostsMap;