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) {
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]');

View File

@ -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;