diff --git a/app.js b/app.js index e072ffd..b20a7a7 100644 --- a/app.js +++ b/app.js @@ -13,8 +13,8 @@ var logger = require('./src/server/logging').logger; var ControlService = require('./src/services/control'); -ControlService.update(null, function (ok) { - if (!ok) { +ControlService.update(function (err) { + if (err) { logger.warn('Unable to perform initial control repository load'); } diff --git a/src/control-repo.js b/src/control-repo.js new file mode 100644 index 0000000..f17b636 --- /dev/null +++ b/src/control-repo.js @@ -0,0 +1,145 @@ +var fs = require('fs'); +var path = require('path'); +var spawn = require('child_process').spawn; + +var async = require('async'); +var npm = require('npm'); + +var logger = require('./server/logging').logger; + +var NPMInstallInProgress = false; + + +var NPMUtils = { + getInstance: function (callback) { + return npm.load({}, callback); + }, + cleanCache: function (callback) { + logger.debug('Cleaning control repo module from NPM cache', { + moduleName: process.env.CONTROL_REPO_MODULE_NAME + }); + + this.getInstance(function (err, npm) { + npm.commands.cache(['clean', process.env.CONTROL_REPO_MODULE_NAME], callback); + }); + } +}; + +var RequireUtils = { + cleanCache: function (callback) { + logger.debug('Cleaning control repo and children from CommonJS module cache', { + moduleName: process.env.CONTROL_REPO_MODULE_NAME + }); + + // Invalidate the cache for the control repo and all of its children + var ControlRepoPath = path.resolve(require.resolve(process.env.CONTROL_REPO_MODULE_NAME), '..'); + var controlRepoModulePaths = [ControlRepoPath]; + + async.waterfall([ + function (callback) { + fs.readFile(path.resolve(ControlRepoPath, 'package.json'), 'utf-8', callback); + }, + function (file, callback) { + var jsonDocument; + try { + jsonDocument = JSON.parse(file); + } catch (e) { + return callback(e); + } + + for(var moduleName in jsonDocument.dependencies) { + controlRepoModulePaths.push(path.resolve(require.resolve(moduleName), '..')); + } + + return callback(null); + } + ], function (err, result) { + var pathStartsWithAny = function (path, prefixes) { + var match = false; + Array.prototype.forEach.call(prefixes, function (prefix) { + if(path.indexOf(prefix) === 0) { + match = true; + } + }); + + return match; + }; + + var modulesToCacheBust = []; + for(var moduleName in require.cache) { + if(pathStartsWithAny(moduleName, controlRepoModulePaths)) { + modulesToCacheBust.push(moduleName); + } + } + + logger.debug('Clearing cached control repo modules', { + modules: modulesToCacheBust + }); + + modulesToCacheBust.forEach(function (module) { + delete require.cache[module]; + }); + + return callback(err); + }); + } +}; + +var ControlRepo = { + loaded: function () { + try { + require.resolve(process.env.CONTROL_REPO_MODULE_NAME); + return true; + } catch (e) { + return false; + } + }, + // We want this to be as idempotent as possible + reload: function (callback) { + callback = callback || function () {}; + var startTime = Date.now(); + logger.debug('Beginning control repo reload', {}); + + async.waterfall([ + function (callback) { + if(NPMInstallInProgress) { + return callback('NPM Install already in progress'); + } + + NPMInstallInProgress = true; + logger.debug('Running npm install ' + process.env.CONTROL_REPO_MODULE); + var npmInstall = spawn('npm', ['install', process.env.CONTROL_REPO_MODULE]); + + npmInstall.on('close', function (code) { + NPMInstallInProgress = false; + if(code !== 0) { + return callback('npm install exited with code ' + code); + } + + return callback(null); + }); + }, + function (callback) { + return RequireUtils.cleanCache(arguments[arguments.length - 1]); + } + ], function (err, result) { + if (err) { + logger.warn('Control repo reload aborted', { + error: err, + duration: Date.now() - startTime + }); + } else { + logger.debug('Finished control repo reload', { + duration: Date.now() - startTime + }); + } + + return callback(err, result); + }); + }, + getInstance: function () { + return require(process.env.CONTROL_REPO_MODULE_NAME); + } +}; + +module.exports = ControlRepo; diff --git a/src/routers/content.js b/src/routers/content.js index 6c2ac97..ce9ac2d 100644 --- a/src/routers/content.js +++ b/src/routers/content.js @@ -111,17 +111,19 @@ module.exports = function (req, res) { return callback(null, toc.envelope.body); }); }, - control: function (callback) { - ContentService.getControlSHA(context, function (err, sha) { - if (err) return callback(err); - - // No need to hold up the current request for the control repository update. - // Kick it off here but don't wait for it to complete. - if (sha && sha !== ControlService.getControlSHA()) ControlService.update(sha); - - callback(null, sha); - }); - } + // control: function (callback) { + // ContentService.getControlSHA(context, function (err, sha) { + // if (err) return callback(err); + // + // // No need to hold up the current request for the control repository update. + // // Kick it off here but don't wait for it to complete. + // if (sha && sha !== ControlService.getControlSHA()) { + // ControlService.update(sha); + // } + // + // callback(null, sha); + // }); + // } }, function (err, output) { if (err || capturedError) { return context.handleError(err || capturedError); diff --git a/src/server/index.js b/src/server/index.js index 1e795e0..4469415 100644 --- a/src/server/index.js +++ b/src/server/index.js @@ -8,13 +8,20 @@ var logging = require('./logging'); var proxies = require('./proxies'); var rewrites = require('./rewrites'); var routes = require('../routers'); +var config = require('../config'); var PathService = require('../services/path'); exports.create = function () { var app = express(); - app.use('/assets', express.static(PathService.getAssetPath())); + // Serve assets from the appropriate site in the control repo + app.use('/assets', function (req, res, next) { + var domain = config.presented_url_domain() || req.hostname; + var assetsPath = PathService.getAssetPath(domain); + + return express.static(assetsPath).apply(this, arguments); + }); app.use(logging.requestLogger()); app.set('trust proxy', true); diff --git a/src/server/proxies.js b/src/server/proxies.js index 89db7fb..6568fed 100644 --- a/src/server/proxies.js +++ b/src/server/proxies.js @@ -6,9 +6,11 @@ var request = require('request'); function makeProxyRoute (site, path, target) { return function (req, res, next) { - var host = config.presented_url_domain() || req.get('Host'); - if (host !== site) { - return next(); + if(site) { + var host = config.presented_url_domain() || req.get('Host'); + if (host !== site) { + return next(); + } } var suffix = url.parse(req.originalUrl).path.replace(path, ''); @@ -24,6 +26,16 @@ function makeProxyRoute (site, path, target) { module.exports = function (app) { var proxies = ContentRoutingService.getAllProxies(); + // This __local_asset__ path is returned when the content service is memory-backed. + // This little patch probably belongs over there, but I'm here right now so + // this will do for now. + // See also: https://github.com/deconst/content-service/issues/66 + app.use('/__local_asset__', makeProxyRoute( + null, + '__local_asset__/', + url.resolve(config.content_service_url(), '/assets') + )); + proxies.forEach(function (each) { for (var path in each.proxy) { app.use(path + '*', makeProxyRoute(each.site, path, each.proxy[path])); diff --git a/src/services/control.js b/src/services/control.js index 3a0038f..cb61fe8 100644 --- a/src/services/control.js +++ b/src/services/control.js @@ -2,12 +2,12 @@ var fs = require('fs'); var path = require('path'); var async = require('async'); var npm = require('npm'); -var tmp = require('tmp'); var childProcess = require('child_process'); var mkdirp = require('mkdirp'); var config = require('../config'); var logger = require('../server/logging').logger; +var ControlRepo = require('../control-repo'); var PathService = require('./path'); var ContentRoutingService = require('./content/routing'); var TemplateRoutingService = require('./template/routing'); @@ -20,8 +20,9 @@ var lastAttemptSHA = null; var updateInProgress = false; var cachePath = null; -var ControlService = { +var ControlRepoUpdater = { load: function (callback) { + callback = callback || function () {}; var startTs = Date.now(); logger.info('Loading control repository'); @@ -33,7 +34,7 @@ var ControlService = { duration: Date.now() - startTs }); - return callback(false); + return callback(new Error('Unable to bootstrap nunjucks templates.')); } async.parallel({ @@ -50,7 +51,7 @@ var ControlService = { duration: Date.now() - startTs }); - return callback(false); + return callback(new Error('Unable to load control repository.')); } ContentRoutingService.setContentMap(result.contentMap); @@ -75,477 +76,127 @@ var ControlService = { duration: Date.now() - startTs }); - callback(true); + callback(null); }); }); }, - update: function (sha, callback) { + update: function (callback) { // The callback is optional. if (!callback) { callback = function () {}; } if (updateInProgress) { - return callback(false); - } - - var startTs = Date.now(); - logger.info('Updating control repository', { - sha: sha - }); - - if (sha !== null && lastAttemptSHA === sha) { - logger.info('Skipping load of already-attempted SHA', { - sha: sha, - lastAttemptSHA: lastAttemptSHA - }); - return callback(false); - } - lastAttemptSHA = sha; - - var isGit = !!config.control_repo_url(); - var shouldUpdate = (sha === null) || (sha !== controlSHA); - - if (!shouldUpdate) { - logger.info('Control repository SHA is already up to date.', { - sha: sha - }); - - return callback(false); + return callback(new Error('Control Repo update already in progress'), null); } updateInProgress = true; - var handleErr = function (err) { - logger.error('Unable to update control repository', { - errMessage: err.message, - stack: err.stack, - sha: sha - }); - - updateInProgress = false; - callback(false); - }; - - var gitStartTs = null; - var gitCompletePayload = null; - - var andLoad = function (err, newSHA) { - if (err) return handleErr(err); - - if (gitStartTs !== null && gitCompletePayload !== null) { - gitCompletePayload.duration = Date.now() - gitStartTs; - var msg = gitCompletePayload.message; - delete gitCompletePayload.message; - - logger.info(msg, gitCompletePayload); - } - - this.load(function (ok) { - if (ok) { - logger.info('Control repository update complete.', { - fromSHA: controlSHA, - toSHA: newSHA, - duration: Date.now() - startTs - }); - - controlSHA = newSHA; - } else { - logger.error('Control repository load failed.', { - currentSHA: controlSHA, - toSHA: sha - }); - } - + // Do something to determine whether a reload is necessary. + ControlRepo.reload(function (err) { + ControlRepoUpdater.load(function (err) { updateInProgress = false; - callback(ok); + callback(err); }); - }.bind(this); - - if (isGit) { - var parentPath = path.dirname(PathService.getControlRepoPath()); - - mkdirp(parentPath, function (err) { - if (err) return handleErr(err); - - fs.readdir(PathService.getControlRepoPath(), function (err, contents) { - if (err) { - if (err.code === 'ENOENT') { - // New repository. - - logger.debug('Beginning control repository clone', { - url: config.control_repo_url(), - branch: config.control_repo_branch() - }); - gitCompletePayload = { - message: 'Completed control repository clone', - url: config.control_repo_url(), - branch: config.control_repo_branch() - }; - gitStartTs = Date.now(); - - gitClone( - config.control_repo_url(), - config.control_repo_branch(), - PathService.getControlRepoPath(), - andLoad); - return; - } - - return handleErr(err); - } - - // Existing repository. - logger.debug('Beginning control repository pull'); - gitCompletePayload = {message: 'Completed control repository pull'}; - gitStartTs = Date.now(); - - gitPull( - PathService.getControlRepoPath(), - andLoad); - }); - }); - } else { - // Non-git repository. Most likely a local mount. - logger.debug('Skipping update for non-git control repository.'); - - return andLoad(null, 'non-git'); - } - }, - getControlSHA: function () { - return controlSHA; - } -}; - -module.exports = ControlService; - -var readAndMergeConfigFiles = function (files, def, callback) { - // for compatibility. Might be called with files as a single path, not an - // array of paths - if (!Array.isArray(files)) { - files = [files]; - } - - async.reduce(files, {}, function (previousValue, currentValue, reduceCallback) { - fs.readFile(currentValue, {encoding: 'utf-8'}, function (err, body) { - if (err) { - if (err.code === 'ENOENT') { - return callback(null, def); - } - - return callback(err); - } - - var doc; - try { - doc = JSON.parse(body); - } catch (e) { - doc = {}; - logger.warn('Configuration file contained invalid JSON', { - errMessage: e.message, - filename: currentValue, - source: body - }); - } - - // I'm surprised this little concatenation loop works as well as it does. - // Could definitely use some testing to be sure it covers all the - // _reasonable_ use cases. - for (var site in doc) { - if (doc.hasOwnProperty(site)) { - if (previousValue.hasOwnProperty(site)) { - previousValue[site] = previousValue[site].concat(doc[site]); - } else { - previousValue[site] = doc[site]; - } - } - } - - reduceCallback(null, previousValue); }); - }, callback); + } }; -var subdirectories = function (rootPath, callback) { - fs.readdir(rootPath, function (err, entries) { - if (err) return callback(err); +module.exports = ControlRepoUpdater; - async.filter(entries, function (entry, cb) { - fs.stat(path.join(rootPath, entry), function (err, fstat) { - if (err) return callback(err); - cb(fstat.isDirectory()); - }); - }, function (dirs) { - return callback(null, dirs); +/** + * @todo This interval is not how we want to check for control repo updates. + */ +setInterval(function () { + ControlRepoUpdater.update(function () { + ControlRepoUpdater.load(function (err) { + updateInProgress = false; }); }); -}; +}, 60000); -var readCurrentSHA = function (repoPath, callback) { - return function (err, stdout, stderr) { - if (err) { - err.stdout = stdout; - err.stderr = stderr; - return callback(err); - } - childProcess.execFile( - '/usr/bin/git', - ['rev-parse', 'HEAD'], - {cwd: repoPath}, - function (err, stdout, stderr) { - if (err) { - err.stdout = stdout; - err.stderr = stderr; - return callback(err); - } - - callback(null, stdout.replace(/\r?\n$/, '')); - } - ); - }; -}; - -var gitClone = function (url, branch, repoPath, callback) { - childProcess.execFile( - '/usr/bin/git', - ['clone', '--branch', branch, url, repoPath], - readCurrentSHA(repoPath, callback) - ); -}; - -var gitPull = function (repoPath, callback) { - childProcess.execFile( - '/usr/bin/git', - ['pull'], - {cwd: repoPath}, - readCurrentSHA(repoPath, callback) - ); -}; // Read functions - var readContentMap = function (callback) { - var contentFiles = PathService.getContentFiles(); - - logger.debug('Beginning content map load', { - files: contentFiles - }); - - readAndMergeConfigFiles(contentFiles, {}, function (err, contentMap) { - if (err) return callback(err); + ControlRepo.getInstance().getContentMaps(function (err, maps) { + if (err) { + return callback(err, null); + } - logger.debug('Successfully loaded content map', { - files: contentFiles + logger.debug('Successfully loaded content maps', { + // maps: maps }); - callback(null, contentMap); - }); -}; - -var readTemplateMap = function (callback) { - var routeFiles = PathService.getRoutesFiles(); - - logger.debug('Begining template map load', { - files: routeFiles - }); - readAndMergeConfigFiles(routeFiles, {}, function (err, templateMap) { - if (err) return callback(err); - - logger.debug('Successfully loaded template map', { - filename: routeFiles - }); - callback(null, templateMap); + callback(err, maps); }); }; -var readRewriteMap = function (callback) { - var rewriteFiles = PathService.getRewritesFiles(); - - logger.debug('Beginning rewrite map load', { - files: rewriteFiles - }); - - readAndMergeConfigFiles(rewriteFiles, {}, function (err, rewriteMap) { - if (err) return callback(err); +var readTemplateMap = function (callback) { + ControlRepo.getInstance().getRouteMaps(function (err, maps) { + if (err) { + return callback(err, null); + } - logger.debug('Successfully loaded rewrite map', { - files: rewriteFiles + logger.debug('Successfully loaded template maps', { + // maps: maps }); - callback(null, rewriteMap); + callback(err, maps); }); }; -var loadPlugins = function (callback) { - var pluginsRoot = PathService.getPluginsRoot(); - var beginTs = Date.now(); - logger.debug('Beginning plugin load', { - path: pluginsRoot - }); - - subdirectories(pluginsRoot, function (err, subdirs) { +var readRewriteMap = function (callback) { + ControlRepo.getInstance().getRewriteMaps(function (err, maps) { if (err) { - if (err.code === 'ENOENT') { - // No plugins to enumerate. - return callback(null, {}); - } - - return callback(err); + return callback(err, null); } - async.map(subdirs, loadDomainPlugins, function (err, results) { - if (err) return callback(err); - - logger.debug('Successfully loaded plugins', { - path: pluginsRoot, - pluginCount: results.length, - duration: Date.now() - beginTs - }); - - var output = {}; - for (var i = 0; i < results.length; i++) { - output[subdirs[i]] = results[i]; - } - - callback(null, output); + logger.debug('Successfully loaded rewrite maps', { + // maps: maps }); - }); -}; -var loadDomainPlugins = function (domain, callback) { - var domainRoot = path.join(PathService.getPluginsRoot(), domain); - - subdirectories(domainRoot, function (err, subdirs) { - if (err) return callback(err); - - async.map(subdirs, function (subdir, cb) { - loadDomainPlugin(path.join(domainRoot, subdir), cb); - }, function (err, results) { - if (err) return callback(err); - - callback(null, results); - }); + callback(err, maps); }); }; -var loadDomainPlugin = function (pluginRoot, callback) { +var loadPlugins = function (callback) { var startTs = Date.now(); - logger.debug('Loading plugin', { - pluginRoot: pluginRoot - }); + logger.debug('Beginning plugin load', {}); - var deps = null; - var plugin = null; + var allPlugins = {}; - var createDir = function (cb) { - if (cachePath !== null) { - return cb(null); - } - - tmp.dir({prefix: 'npm-cache-'}, function (err, cp) { - cachePath = cp; - cb(err); + async.each(ControlRepo.getInstance().sites, function (site, cb) { + site.getPlugins(function (err, plugins) { + allPlugins[site.domain] = plugins; + return cb(); }); - }; - - var parseDependencies = function (cb) { - fs.readFile(path.join(pluginRoot, 'package.json'), {encoding: 'utf-8'}, function (err, doc) { - if (err) return cb(err); - - var depDoc = {}; - try { - depDoc = JSON.parse(doc); - } catch (e) { - return cb(e); - } - - deps = []; - for (var key in depDoc.dependencies) { - deps.push(key + '@' + depDoc.dependencies[key]); - } - - cb(null); + }, function (err) { + logger.debug('Finished plugin load', { + duration: Date.now() - startTs }); - }; - - var installDependencies = function (cb) { - npm.load({cache: cachePath}, function (err) { - if (err) return cb(err); - - npm.commands.install(pluginRoot, deps, function (err, result) { - if (err) return cb(err); - logger.debug('Plugin dependencies installed', { - pluginRoot: pluginRoot, - duration: Date.now() - startTs - }); - - var requireTs = Date.now(); - try { - plugin = require(pluginRoot); - } catch (e) { - return callback(e); - } - - logger.debug('Plugin required', { - pluginRoot: pluginRoot, - duration: Date.now() - requireTs - }); - - cb(null); - }); - }); - }; - - async.series([ - createDir, - parseDependencies, - installDependencies - ], function (err) { - return callback(err, plugin); + return callback(null, allPlugins); }); }; var loadTemplates = function (callback) { var startTs = Date.now(); - var templatesRoot = PathService.getTemplatesRoot(); - logger.debug('Beginning template preload', { - templatesRoot: templatesRoot - }); + logger.debug('Beginning template preload', {}); - subdirectories(templatesRoot, function (err, subdirs) { - if (err) { - if (err.code === 'ENOENT') { - // No templates to load in this control repository. - logger.debug('No templates to load', { - duration: Date.now() - startTs - }); - - return callback(null, {}); - } + var sources = {}; - return callback(err); - } - - async.map(subdirs, function (subdir, cb) { - var fullPath = path.resolve(templatesRoot, subdir); - - createAtomicLoader(fullPath, cb); - }, function (err, results) { - if (err) return callback(err); - - var output = {}; - for (var i = 0; i < results.length; i++) { - output[subdirs[i]] = results[i]; - } - - logger.debug('Successfully preloaded templates', { - domains: subdirs, - duration: Date.now() - startTs + async.each(ControlRepo.getInstance().sites, function (site, cb) { + site.getTemplateSources(function (err, templateSources) { + createAtomicLoader(templateSources, function (err, loader) { + sources[site.domain] = loader; + cb(); }); - - callback(null, output); }); + }, function (err) { + logger.debug('Finished template preload', { + duration: Date.now() - startTs + }); + callback(null, sources); }); }; diff --git a/src/services/nunjucks/atomic-loader.js b/src/services/nunjucks/atomic-loader.js index 7302e92..01f3e01 100644 --- a/src/services/nunjucks/atomic-loader.js +++ b/src/services/nunjucks/atomic-loader.js @@ -4,68 +4,16 @@ var walk = require('walk'); var logger = require('../../server/logging').logger; -var AtomicLoader = function (basePath, templateFiles) { - this.templateSources = {}; - - var templatePaths = Object.keys(templateFiles); - - for (var i = 0; i < templatePaths.length; i++) { - var templateName = templatePaths[i]; - var templateSource = templateFiles[templateName]; - var templateFullPath = path.resolve(basePath, templateName); - - if (templateFullPath.indexOf(basePath) === -1) { - logger.warn('Attempt to load template outside of base path', { - basePath: basePath, - templateName: templateName, - templatePath: templateFullPath - }); - continue; - } - - this.templateSources[templateName] = { - src: templateSource, - path: templateFullPath, - noCache: this.noCache - }; - } +var AtomicLoader = function (templateSources) { + this.templateSources = templateSources; }; AtomicLoader.prototype.getSource = function (name) { return this.templateSources[name] || null; }; -var createAtomicLoader = function (rootPath, callback) { - if (!/\/$/.test(rootPath)) { - rootPath += '/'; - } - - var templateFiles = {}; - var walker = walk.walk(rootPath, {followLinks: false}); - - walker.on('file', function (root, stat, next) { - var fullPath = path.join(root, stat.name); - var templateName = fullPath.replace(rootPath, ''); - - fs.readFile(fullPath, {encoding: 'utf-8'}, function (err, body) { - if (err) { - logger.warn('Unable to read template file', { - templatePath: fullPath, - errMessage: err.message, - stack: err.stack - }); - - return next(); - } - - templateFiles[templateName] = body; - next(); - }); - }); - - walker.on('end', function () { - callback(null, new AtomicLoader(rootPath, templateFiles)); - }); +var createAtomicLoader = function (templateSources, callback) { + return callback(null, new AtomicLoader(templateSources)); }; module.exports = createAtomicLoader; diff --git a/src/services/nunjucks/index.js b/src/services/nunjucks/index.js index 946ea6b..8ad2ecf 100644 --- a/src/services/nunjucks/index.js +++ b/src/services/nunjucks/index.js @@ -1,3 +1,7 @@ +var fs = require('fs'); +var path = require('path'); +var async = require('async'); +var globby = require('globby'); var nunjucks = require('nunjucks'); var nunjucksDate = require('nunjucks-date'); @@ -18,12 +22,12 @@ var NunjucksService = { return callback(null); } - createAtomicLoader(PathService.getDefaultTemplatesPath(), function (err, loader) { - if (err) return callback(err); - - staticLoader = loader; - staticEnv = createEnvironment(null, [staticLoader]); - callback(null); + getStaticTemplateSources(function (err, sources) { + createAtomicLoader(sources, function (err, loader) { + staticLoader = loader; + staticEnv = createEnvironment(null, [staticLoader]); + callback(null); + }); }); }, clearEnvironments: function () { @@ -55,6 +59,25 @@ var NunjucksService = { module.exports = NunjucksService; +var getStaticTemplateSources = function (callback) { + var templateDir = PathService.getDefaultTemplatesPath(); + var templateFiles = globby.sync(path.resolve(templateDir, '**/*'), {nodir: true}); + var sources = {}; + + async.each(templateFiles, function (file, callback) { + fs.readFile(file, 'utf-8', function (err, contents) { + sources[path.relative(templateDir, file)] = { + src: contents, + path: file + }; + + callback(null); + }); + }, function (err) { + return callback(null, sources); + }); +}; + var createEnvironment = function (domain, loaders) { loaders.push(staticLoader); var env = new nunjucks.Environment(loaders, { diff --git a/src/services/path.js b/src/services/path.js index 702b23e..394beba 100644 --- a/src/services/path.js +++ b/src/services/path.js @@ -1,6 +1,7 @@ var path = require('path'); var globby = require('globby'); var config = require('../config'); +var ControlRepo = require('../control-repo'); var CONFIG_PATH = 'config'; @@ -15,16 +16,16 @@ var PathService = { return path.resolve(this.getControlRepoPath(), 'plugins'); }, getPluginsPath: function (domain) { - return path.resolve(this.getPluginsRoot(), domain); + return ControlRepo.getInstance().getPluginsPath(domain); }, getTemplatesRoot: function (domain) { return path.resolve(this.getControlRepoPath(), 'templates'); }, getTemplatesPath: function (domain) { - return path.resolve(this.getTemplatesRoot(), domain); + return ControlRepo.getInstance().getTemplatesPath(domain); }, - getAssetPath: function () { - return path.resolve(PathService.getControlRepoPath(), 'assets'); + getAssetPath: function (domain) { + return ControlRepo.getInstance().getAssetsPath(domain); }, getConfigPath: function (configPath) { configPath = configPath || ''; diff --git a/src/services/rewrite.js b/src/services/rewrite.js index d9c69cb..787adc5 100644 --- a/src/services/rewrite.js +++ b/src/services/rewrite.js @@ -11,14 +11,18 @@ var RewriteService = { }; for (var domain in configMap) { - configMap[domain].forEach(compileRx); + Array.prototype.forEach.call(configMap[domain].rewrites, compileRx); } rewriteMap = configMap; }, getRewrite: function (req) { var domain = config.presented_url_domain() || req.get('Host'); - var rewrites = rewriteMap[domain] || []; + if(!rewriteMap[domain]) { + return; + } + + var rewrites = rewriteMap[domain].rewrites || []; for (var i = 0; i < rewrites.length; i++) { var rule = rewrites[i]; diff --git a/src/services/template/index.js b/src/services/template/index.js index 562f57f..b11c29d 100644 --- a/src/services/template/index.js +++ b/src/services/template/index.js @@ -3,6 +3,7 @@ var path = require('path'); var NunjucksService = require('../nunjucks'); var PathService = require('../path'); var UrlService = require('../url'); +var ControlRepo = require('../../control-repo'); var TemplateService = { render: function (context, options, callback) { @@ -58,7 +59,7 @@ var findTemplate = function (context, templatePath) { ]; var templateDir = null; - if (context.host()) { + if (context.host() && ControlRepo.getInstance().siteExists(context.host())) { templateDir = PathService.getTemplatesPath(context.host()); var templateBase = path.resolve(templateDir, templatePath); diff --git a/static/404.html b/static/404.html index 9deaa46..d46385d 100644 --- a/static/404.html +++ b/static/404.html @@ -10,6 +10,6 @@

Page Not Found

Sorry, the page you requested does not exist.

- Powered by deconst + Powered by deconst diff --git a/static/500.html b/static/500.html index 12b4e91..d4e2521 100644 --- a/static/500.html +++ b/static/500.html @@ -10,6 +10,6 @@

System Error

Sorry, a system error has prevented this page from being shown correctly.

- Powered by deconst + Powered by deconst