'use strict'; module.exports = function (opts) { 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 = opts.content; //var server; var serveInit; var app; function _reloadWrite(data, enc, cb) { /*jshint validthis: true */ if (this.headersSent) { this.__write(data, enc, cb); return; } if (!/html/i.test(this.getHeader('Content-Type'))) { this.__write(data, enc, cb); return; } if (this.getHeader('Content-Length')) { this.setHeader('Content-Length', this.getHeader('Content-Length') + this.__my_addLen); } this.__write(this.__my_livereload); this.__write(data, enc, cb); } function createServeInit() { var PromiseA = require('bluebird'); var fs = PromiseA.promisifyAll(require('fs')); var ownersPath = path.join(__dirname, '..', 'var', 'owners.json'); return require('../packages/apis/com.daplie.caddy').create({ PromiseA: PromiseA , storage: { owners: { all: function () { var owners; try { owners = require(ownersPath); } catch(e) { owners = {}; } return PromiseA.resolve(Object.keys(owners).map(function (key) { var owner = owners[key]; owner.id = key; return owner; })); } , set: function (id, obj) { var owners; try { owners = require(ownersPath); } catch(e) { owners = {}; } obj.id = id; owners[id] = obj; return fs.writeFileAsync(ownersPath, JSON.stringify(owners), 'utf8'); } } } , recase: require('recase').create({}) , options: opts }); } app = express(); return app.use('/', function (req, res, next) { if (!req.headers.host) { next(new Error('missing HTTP Host header')); return; } if (0 === req.url.indexOf('/api/com.daplie.caddy/')) { if (!serveInit) { serveInit = createServeInit(); } } if ('/api/com.daplie.caddy/init' === req.url) { serveInit.init(req, res); return; } if ('/api/com.daplie.caddy/config' === req.url) { serveInit.config(req, res); 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 || {}, opts.sites[hostname] || {}, opts.defer || {} ]; var loadables = { serve: function (config, hostname, pathname, req, res, next) { config = config.slice(0); var originalUrl = req.url; function nextServe() { var dirname = config.pop(); console.log('[serve]', req.url, hostname, pathname, dirname); if (!dirname) { req.url = originalUrl; next(); return; } 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) { config = config.slice(0); var originalUrl = req.url; function nextIndex() { var dirname = config.pop(); console.log('[indexes]', req.url, hostname, pathname, dirname); if (!dirname) { req.url = originalUrl; next(); return; } if (!serveStaticMap[dirname]) { serveIndexMap[dirname] = serveIndex(dirname); } serveIndexMap[dirname](req, res, nextIndex); } req.url = req.url.substr(pathname.length - 1); nextIndex(); } }; function runModule(config, 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); } function iterModules(modules, hostname, pathname, req, res, next) { var modulenames = Object.keys(modules); function nextModule() { var modulename = modulenames.pop(); if (!modulename) { next(); return; } console.log('modules', modules); runModule(modules[modulename], hostname, pathname, modulename, req, res, nextModule); } nextModule(); } function iterPaths(site, hostname, req, res, next) { var pathnames = Object.keys(site.paths || {}); 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; }); function nextPath() { var pathname = pathnames.pop(); if (!pathname) { next(); return; } console.log('iterPaths', hostname, pathname, req.url); iterModules(site.paths[pathname], hostname, pathname, req, res, nextPath); } nextPath(); } function nextSite() { var site = sites.pop(); if (!site) { next(); // 404 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); */ }); };