'use strict'; module.exports = function (myDeps, conf, overrideHttp) { var express = require('express'); //var finalhandler = require('finalhandler'); var serveStatic = require('serve-static'); var serveIndex = require('serve-index'); //var assetServer = serveStatic(opts.assetsPath); var path = require('path'); //var wellKnownServer = serveStatic(path.join(opts.assetsPath, 'well-known')); var serveStaticMap = {}; var serveIndexMap = {}; var content = conf.content; //var server; var goldilocksApis; var app; var request; function createGoldilocksApis() { var PromiseA = require('bluebird'); var OAUTH3 = require('../packages/assets/org.oauth3'); require('../packages/assets/org.oauth3/oauth3.domains.js'); require('../packages/assets/org.oauth3/oauth3.dns.js'); require('../packages/assets/org.oauth3/oauth3.tunnel.js'); OAUTH3._hooks = require('../packages/assets/org.oauth3/oauth3.node.storage.js'); request = request || PromiseA.promisify(require('request')); myDeps.PromiseA = PromiseA; myDeps.OAUTH3 = OAUTH3; myDeps.recase = require('recase').create({}); myDeps.request = request; return require('../packages/apis/com.daplie.goldilocks').create(myDeps, conf); } app = express(); var Sites = { add: function (sitesMap, site) { if (!sitesMap[site.$id]) { sitesMap[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; }); }); } }; var opts = overrideHttp || conf.http; if (!opts.defaults) { opts.defaults = {}; } if (!opts.global) { opts.global = {}; } if (!opts.sites) { opts.sites = []; } opts.sites._map = {}; opts.sites.forEach(function (site) { Sites.add(opts.sites._map, site); }); 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); }); function _goldApis(req, res, next) { if (!goldilocksApis) { goldilocksApis = createGoldilocksApis(); } if (typeof goldilocksApis[req.params.name] === 'function') { goldilocksApis[req.params.name](req, res); } else { next(); } } return app .use('/api/com.daplie.goldilocks/:name', _goldApis) .use('/api/goldilocks@daplie.com/:name', _goldApis) .use('/', function (req, res, next) { if (!req.headers.host) { next(new Error('missing HTTP Host header')); return; } if (content && '/' === req.url) { // res.setHeader('Content-Type', 'application/octet-stream'); res.end(content); return; } //var done = finalhandler(req, res); var host = req.headers.host; var hostname = (host||'').split(':')[0].toLowerCase(); console.log('opts.global', opts.global); var sites = [ opts.global || null, opts.sites._map[hostname] || null, opts.defaults || null ]; var loadables = { serve: function (config, hostname, pathname, req, res, next) { var originalUrl = req.url; var dirpaths = config.paths.slice(0); function nextServe() { var dirname = dirpaths.pop(); if (!dirname) { req.url = originalUrl; next(); return; } console.log('[serve]', req.url, hostname, pathname, dirname); dirname = path.resolve(conf.cwd, dirname.replace(/:hostname/, hostname)); if (!serveStaticMap[dirname]) { serveStaticMap[dirname] = serveStatic(dirname); } serveStaticMap[dirname](req, res, nextServe); } req.url = req.url.substr(pathname.length - 1); nextServe(); } , indexes: function (config, hostname, pathname, req, res, next) { var originalUrl = req.url; var dirpaths = config.paths.slice(0); function nextIndex() { var dirname = dirpaths.pop(); if (!dirname) { req.url = originalUrl; next(); return; } console.log('[indexes]', req.url, hostname, pathname, dirname); dirname = path.resolve(conf.cwd, dirname.replace(/:hostname/, hostname)); if (!serveStaticMap[dirname]) { serveIndexMap[dirname] = serveIndex(dirname); } serveIndexMap[dirname](req, res, nextIndex); } 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); try { var app = require(appfile); app(req, res, next); } catch (err) { next(); } } }; function runModule(module, hostname, pathname, modulename, req, res, next) { if (!loadables[modulename]) { next(new Error("no module '" + modulename + "' found")); return; } loadables[modulename](module, hostname, pathname, req, res, next); } function iterModules(modules, hostname, pathname, req, res, next) { console.log('modules'); console.log(modules); var modulenames = Object.keys(modules._map); function nextModule() { var modulename = modulenames.pop(); if (!modulename) { next(); return; } console.log('modules', modules); runModule(modules._map[modulename], hostname, pathname, modulename, req, res, nextModule); } nextModule(); } function iterPaths(site, hostname, req, res, next) { 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)); //return req.url.match(pathname); }); pathnames.sort(function (a, b) { return b.length - a.length; }); console.log('pathnames', pathnames); function nextPath() { var pathname = pathnames.shift(); if (!pathname) { next(); return; } console.log('iterPaths', hostname, pathname, req.url); iterModules(site.paths._map[pathname].modules, hostname, pathname, req, res, nextPath); } nextPath(); } function nextSite() { 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); } nextSite(); /* function serveStaticly(server) { function serveTheStatic() { server.serve(req, res, function (err) { if (err) { return done(err); } server.index(req, res, function (err) { if (err) { return done(err); } req.url = req.url.replace(/\/assets/, ''); assetServer(req, res, function () { if (err) { return done(err); } req.url = req.url.replace(/\/\.well-known/, ''); wellKnownServer(req, res, done); }); }); }); } if (server.expressApp) { server.expressApp(req, res, serveTheStatic); return; } serveTheStatic(); } if (opts.livereload) { res.__my_livereload = ''; res.__my_addLen = res.__my_livereload.length; // TODO modify prototype instead of each instance? res.__write = res.write; res.write = _reloadWrite; } console.log('hostname:', hostname, opts.sites[0].paths); addServer(hostname); server = hostsMap[hostname] || hostsMap[opts.sites[0].name]; serveStaticly(server); */ }); };