wait for templates to compile even if using clustering
fix emitter.all
upgrade.check error first
removed plugins.ready, using callback on plugins.init
removed webserver.init, using webserver.listen
v1.18.x
barisusakli 10 years ago
parent 51212c2bfa
commit d946a2fcbd

146
app.js

@ -133,89 +133,79 @@ function start() {
winston.verbose('* using themes stored in: %s', nconf.get('themes_path'));
}
process.on('SIGTERM', shutdown);
process.on('SIGINT', shutdown);
process.on('SIGHUP', restart);
process.on('message', function(message) {
if (typeof message !== 'object') {
return;
}
var meta = require('./src/meta');
var emitter = require('./src/emitter');
switch (message.action) {
case 'reload':
meta.reload();
break;
case 'js-propagate':
meta.js.cache = message.cache;
meta.js.map = message.map;
meta.js.hash = message.hash;
emitter.emit('meta:js.compiled');
winston.verbose('[cluster] Client-side javascript and mapping propagated to worker %s', process.pid);
break;
case 'css-propagate':
meta.css.cache = message.cache;
meta.css.acpCache = message.acpCache;
meta.css.hash = message.hash;
emitter.emit('meta:css.compiled');
winston.verbose('[cluster] Stylesheets propagated to worker %s', process.pid);
break;
case 'templates:compiled':
emitter.emit('templates:compiled');
break;
}
});
var webserver = require('./src/webserver');
process.on('uncaughtException', function(err) {
winston.error(err.stack);
console.log(err.stack);
require('./src/database').init(function(err) {
require('./src/meta').js.killMinifier();
shutdown(1);
});
async.waterfall([
function(next) {
require('./src/database').init(next);
},
function(next) {
require('./src/meta').configs.init(next);
},
function(next) {
require('./src/upgrade').check(next);
},
function(schema_ok, next) {
if (!schema_ok && nconf.get('check-schema') !== false) {
winston.warn('Your NodeBB schema is out-of-date. Please run the following command to bring your dataset up to spec:');
winston.warn(' ./nodebb upgrade');
process.exit();
return;
}
var webserver = require('./src/webserver');
require('./src/socket.io').init(webserver.server);
if (nconf.get('isPrimary') === 'true' && !nconf.get('jobsDisabled')) {
require('./src/notifications').init();
require('./src/user').startJobs();
}
webserver.listen();
}
], function(err) {
if (err) {
winston.error(err.stack);
process.exit();
}
var meta = require('./src/meta');
meta.configs.init(function () {
var templates = require('templates.js'),
sockets = require('./src/socket.io'),
plugins = require('./src/plugins'),
upgrade = require('./src/upgrade');
templates.setGlobal('relative_path', nconf.get('relative_path'));
upgrade.check(function(schema_ok) {
if (schema_ok || nconf.get('check-schema') === false) {
webserver.init();
sockets.init(webserver.server);
if (nconf.get('isPrimary') === 'true' && !nconf.get('jobsDisabled')) {
require('./src/notifications').init();
require('./src/user').startJobs();
}
webserver.listen();
async.waterfall([
async.apply(meta.themes.setupPaths),
async.apply(plugins.ready),
async.apply(meta.templates.compile)
], function(err) {
if (err) {
winston.error(err.stack);
process.exit();
}
if (process.send) {
process.send({
action: 'ready'
});
}
});
process.on('SIGTERM', shutdown);
process.on('SIGINT', shutdown);
process.on('SIGHUP', restart);
process.on('message', function(message) {
switch(message.action) {
case 'reload':
meta.reload();
break;
case 'js-propagate':
meta.js.cache = message.cache;
meta.js.map = message.map;
meta.js.hash = message.hash;
winston.verbose('[cluster] Client-side javascript and mapping propagated to worker %s', process.pid);
break;
case 'css-propagate':
meta.css.cache = message.cache;
meta.css.acpCache = message.acpCache;
meta.css.hash = message.hash;
winston.verbose('[cluster] Stylesheets propagated to worker %s', process.pid);
break;
}
});
process.on('uncaughtException', function(err) {
winston.error(err.stack);
console.log(err.stack);
meta.js.killMinifier();
shutdown(1);
});
} else {
winston.warn('Your NodeBB schema is out-of-date. Please run the following command to bring your dataset up to spec:');
winston.warn(' ./nodebb upgrade');
process.exit();
}
});
});
});
}
@ -243,7 +233,7 @@ function setup() {
winston.error('There was a problem completing NodeBB setup: ', err.message);
} else {
if (data.hasOwnProperty('password')) {
process.stdout.write('An administrative user was automatically created for you:\n')
process.stdout.write('An administrative user was automatically created for you:\n');
process.stdout.write(' Username: ' + data.username + '\n');
process.stdout.write(' Password: ' + data.password + '\n');
process.stdout.write('\n');

@ -82,7 +82,7 @@ Loader.addWorkerEvents = function(worker) {
if (message && typeof message === 'object' && message.action) {
switch (message.action) {
case 'ready':
if (Loader.js.cache) {
if (Loader.js.cache && !worker.isPrimary) {
worker.send({
action: 'js-propagate',
cache: Loader.js.cache,
@ -91,7 +91,7 @@ Loader.addWorkerEvents = function(worker) {
});
}
if (Loader.css.cache) {
if (Loader.css.cache && !worker.isPrimary) {
worker.send({
action: 'css-propagate',
cache: Loader.css.cache,
@ -99,6 +99,8 @@ Loader.addWorkerEvents = function(worker) {
hash: Loader.css.hash
});
}
break;
case 'restart':
console.log('[cluster] Restarting...');
@ -132,6 +134,11 @@ Loader.addWorkerEvents = function(worker) {
hash: message.hash
}, worker.pid);
break;
case 'templates:compiled':
Loader.notifyWorkers({
action: 'templates:compiled',
}, worker.pid);
break;
}
}
});

@ -6,39 +6,30 @@ var eventEmitter = new (require('events')).EventEmitter();
eventEmitter.all = function(events, callback) {
var eventList = events.slice(0);
function onEvent(event) {
eventEmitter.on(events[event], function() {
eventList.splice(eventList.indexOf(events[event]), 1);
events.forEach(function onEvent(event) {
eventEmitter.on(event, function() {
var index = eventList.indexOf(event);
if (index === -1) {
return;
}
eventList.splice(index, 1);
if (eventList.length === 0) {
callback();
}
});
}
for (var ev in events) {
if (events.hasOwnProperty(ev)) {
onEvent(ev);
}
}
});
};
eventEmitter.any = function(events, callback) {
function onEvent(event) {
eventEmitter.on(events[event], function() {
events.forEach(function onEvent(event) {
eventEmitter.on(event, function() {
if (events !== null) {
callback();
}
events = null;
});
}
for (var ev in events) {
if (events.hasOwnProperty(ev)) {
onEvent(ev);
}
}
});
};
module.exports = eventEmitter;

@ -499,7 +499,10 @@ install.setup = function (callback) {
setCopyrightWidget,
function (next) {
var upgrade = require('./upgrade');
upgrade.check(function(uptodate) {
upgrade.check(function(err, uptodate) {
if (err) {
return next(err);
}
if (!uptodate) { upgrade.upgrade(next); }
else { next(); }
});

@ -15,6 +15,7 @@ var mkdirp = require('mkdirp'),
Templates = {};
Templates.compile = function(callback) {
callback = callback || function() {};
var fromFile = nconf.get('from-file') || '';
if (nconf.get('isPrimary') === 'false' || fromFile.match('tpl')) {
@ -22,11 +23,7 @@ Templates.compile = function(callback) {
winston.info('[minifier] Compiling templates skipped');
}
emitter.emit('templates:compiled');
if (callback) {
callback();
}
return;
return callback();
}
var coreTemplatesPath = nconf.get('core_templates_path'),
@ -119,15 +116,20 @@ Templates.compile = function(callback) {
}, function(err) {
if (err) {
winston.error('[meta/templates] ' + err.stack);
} else {
compileIndex(viewsPath, function() {
winston.verbose('[meta/templates] Successfully compiled templates.');
emitter.emit('templates:compiled');
if (callback) {
callback();
}
});
return callback(err);
}
compileIndex(viewsPath, function() {
winston.verbose('[meta/templates] Successfully compiled templates.');
emitter.emit('templates:compiled');
if (process.send) {
process.send({
action: 'templates:compiled'
});
}
callback();
});
});
});
});

@ -39,9 +39,10 @@ var fs = require('fs'),
Plugins.libraryPaths.push(libraryPath);
};
Plugins.init = function(nbbApp, nbbMiddleware) {
Plugins.init = function(nbbApp, nbbMiddleware, callback) {
callback = callback || function() {};
if (Plugins.initialized) {
return;
return callback();
}
app = nbbApp;
@ -55,7 +56,7 @@ var fs = require('fs'),
Plugins.reload(function(err) {
if (err) {
winston.error('[plugins] NodeBB encountered a problem while loading plugins', err.message);
return;
return callback(err);
}
if (global.env === 'development') {
@ -64,6 +65,7 @@ var fs = require('fs'),
Plugins.initialized = true;
emitter.emit('plugins:loaded');
callback();
});
Plugins.registerHook('core', {
@ -72,14 +74,6 @@ var fs = require('fs'),
});
};
Plugins.ready = function(callback) {
if (!Plugins.initialized) {
emitter.once('plugins:loaded', callback);
} else {
callback();
}
};
Plugins.reload = function(callback) {
// Resetting all local plugin data
Plugins.libraries = {};

@ -40,44 +40,42 @@
var router = express.Router();
router.hotswapId = 'auth';
plugins.ready(function() {
loginStrategies.length = 0;
loginStrategies.length = 0;
if (plugins.hasListeners('action:auth.overrideLogin')) {
winston.warn('[authentication] Login override detected, skipping local login strategy.');
plugins.fireHook('action:auth.overrideLogin');
} else {
passport.use(new passportLocal({passReqToCallback: true}, Auth.login));
if (plugins.hasListeners('action:auth.overrideLogin')) {
winston.warn('[authentication] Login override detected, skipping local login strategy.');
plugins.fireHook('action:auth.overrideLogin');
} else {
passport.use(new passportLocal({passReqToCallback: true}, Auth.login));
}
plugins.fireHook('filter:auth.init', loginStrategies, function(err) {
if (err) {
winston.error('filter:auth.init - plugin failure');
return callback(err);
}
plugins.fireHook('filter:auth.init', loginStrategies, function(err) {
if (err) {
winston.error('filter:auth.init - plugin failure');
return callback(err);
loginStrategies.forEach(function(strategy) {
if (strategy.url) {
router.get(strategy.url, passport.authenticate(strategy.name, {
scope: strategy.scope
}));
}
loginStrategies.forEach(function(strategy) {
if (strategy.url) {
router.get(strategy.url, passport.authenticate(strategy.name, {
scope: strategy.scope
}));
}
router.get(strategy.callbackURL, passport.authenticate(strategy.name, {
successReturnToOrRedirect: nconf.get('relative_path') + '/',
failureRedirect: nconf.get('relative_path') + '/login'
}));
});
router.get(strategy.callbackURL, passport.authenticate(strategy.name, {
successReturnToOrRedirect: nconf.get('relative_path') + '/',
failureRedirect: nconf.get('relative_path') + '/login'
}));
});
router.post('/logout', Auth.middleware.applyCSRF, logout);
router.post('/register', Auth.middleware.applyCSRF, register);
router.post('/login', Auth.middleware.applyCSRF, login);
router.post('/logout', Auth.middleware.applyCSRF, logout);
router.post('/register', Auth.middleware.applyCSRF, register);
router.post('/login', Auth.middleware.applyCSRF, login);
hotswap.replace('auth', router);
if (typeof callback === 'function') {
callback();
}
});
hotswap.replace('auth', router);
if (typeof callback === 'function') {
callback();
}
});
};

@ -25,18 +25,21 @@ var db = require('./database'),
Upgrade.check = function(callback) {
db.get('schemaDate', function(err, value) {
if(!value) {
if (err) {
return callback(err);
}
if (!value) {
db.set('schemaDate', latestSchema, function(err) {
callback(true);
if (err) {
return callback(err);
}
callback(null, true);
});
return;
}
if (parseInt(value, 10) >= latestSchema) {
callback(true);
} else {
callback(false);
}
callback(null, parseInt(value, 10) >= latestSchema);
});
};

@ -5,7 +5,7 @@ var path = require('path'),
fs = require('fs'),
nconf = require('nconf'),
express = require('express'),
WebServer = express(),
app = express(),
server,
winston = require('winston'),
async = require('async'),
@ -18,195 +18,216 @@ var path = require('path'),
routes = require('./routes'),
emitter = require('./emitter'),
helpers = require('./../public/src/modules/helpers'),
net;
helpers = require('../public/src/modules/helpers');
if(nconf.get('ssl')) {
if (nconf.get('ssl')) {
server = require('https').createServer({
key: fs.readFileSync(nconf.get('ssl').key),
cert: fs.readFileSync(nconf.get('ssl').cert)
}, WebServer);
}, app);
} else {
server = require('http').createServer(WebServer);
server = require('http').createServer(app);
}
(function (app) {
var port = nconf.get('port');
module.exports.server = server;
if (Array.isArray(port)) {
if (!port.length) {
winston.error('[startup] empty ports array in config.json');
process.exit();
}
winston.warn('[startup] If you want to start nodebb on multiple ports please use loader.js');
winston.warn('[startup] Defaulting to first port in array, ' + port[0]);
port = port[0];
if (!port) {
winston.error('[startup] Invalid port, exiting');
process.exit();
}
server.on('error', function(err) {
winston.error(err);
if (err.code === 'EADDRINUSE') {
winston.error('NodeBB address in use, exiting...');
process.exit(0);
} else {
throw err;
}
});
module.exports.init = function() {
var skipJS, skipLess, fromFile = nconf.get('from-file') || '';
if (server.setTimeout) {
server.setTimeout(10000);
}
emailer.registerApp(app);
module.exports.listen = function() {
emailer.registerApp(app);
if (fromFile.match('js')) {
winston.info('[minifier] Minifying client-side JS skipped');
skipJS = true;
}
middleware = middleware(app);
helpers.register();
logger.init(app);
emitter.all(['templates:compiled', 'meta:js.compiled', 'meta:css.compiled'], function() {
winston.info('NodeBB Ready');
emitter.emit('nodebb:ready');
listen();
});
if (fromFile.match('less')) {
winston.info('[minifier] Compiling LESS files skipped');
skipLess = true;
initializeNodeBB(function(err) {
if (err) {
winston.error(err);
process.exit();
}
if (process.send) {
process.send({
action: 'ready'
});
}
});
};
function initializeNodeBB(callback) {
var skipJS, skipLess, fromFile = nconf.get('from-file') || '';
if (fromFile.match('js')) {
winston.info('[minifier] Minifying client-side JS skipped');
skipJS = true;
}
if (fromFile.match('less')) {
winston.info('[minifier] Compiling LESS files skipped');
skipLess = true;
}
// Preparation dependent on plugins
plugins.ready(function() {
async.waterfall([
async.apply(cacheStaticFiles),
async.apply(meta.themes.setupPaths),
function(next) {
plugins.init(app, middleware, next);
},
function(next) {
async.parallel([
async.apply(meta.templates.compile),
async.apply(!skipJS ? meta.js.minify : meta.js.getFromFile, app.enabled('minification')),
async.apply(!skipLess ? meta.css.minify : meta.css.getFromFile),
async.apply(meta.sounds.init)
]);
], next);
},
function(results, next) {
plugins.fireHook('static:app.preload', {
app: app,
middleware: middleware
}, function(err) {
if (err) {
return winston.error('[plugins] Encountered error while executing pre-router plugins hooks: ' + err.message);
}
routes(app, middleware);
});
});
middleware = middleware(app);
plugins.init(app, middleware);
}, next);
},
function(results, next) {
routes(app, middleware);
next();
}
], callback);
}
// Load server-side template helpers
helpers.register();
function cacheStaticFiles(callback) {
if (global.env === 'development') {
return callback();
}
// Cache static files on production
if (global.env !== 'development') {
app.enable('cache');
app.enable('minification');
app.enable('cache');
app.enable('minification');
// Configure cache-buster timestamp
require('child_process').exec('git describe --tags', {
cwd: path.join(__dirname, '../')
}, function(err, stdOut) {
if (!err) {
meta.config['cache-buster'] = stdOut.trim();
} else {
fs.stat(path.join(__dirname, '../package.json'), function(err, stats) {
meta.config['cache-buster'] = new Date(stats.mtime).getTime();
});
// Configure cache-buster timestamp
require('child_process').exec('git describe --tags', {
cwd: path.join(__dirname, '../')
}, function(err, stdOut) {
if (!err) {
meta.config['cache-buster'] = stdOut.trim();
callback();
} else {
fs.stat(path.join(__dirname, '../package.json'), function(err, stats) {
if (err) {
return callback(err);
}
meta.config['cache-buster'] = new Date(stats.mtime).getTime();
callback();
});
}
});
}
if (port !== 80 && port !== 443 && nconf.get('use_port') === false) {
winston.info('Enabling \'trust proxy\'');
app.enable('trust proxy');
}
function listen(callback) {
var port = nconf.get('port');
if ((port === 80 || port === 443) && process.env.NODE_ENV !== 'development') {
winston.info('Using ports 80 and 443 is not recommend; use a proxy instead. See README.md');
if (Array.isArray(port)) {
if (!port.length) {
winston.error('[startup] empty ports array in config.json');
process.exit();
}
};
server.on('error', function(err) {
winston.error(err.stack);
console.log(err.stack);
if (err.code === 'EADDRINUSE') {
winston.error('NodeBB address in use, exiting...');
process.exit(0);
} else {
throw err;
winston.warn('[startup] If you want to start nodebb on multiple ports please use loader.js');
winston.warn('[startup] Defaulting to first port in array, ' + port[0]);
port = port[0];
if (!port) {
winston.error('[startup] Invalid port, exiting');
process.exit();
}
});
}
module.exports.server = server;
if (port !== 80 && port !== 443 && nconf.get('use_port') === false) {
winston.info('Enabling \'trust proxy\'');
app.enable('trust proxy');
}
emitter.all(['templates:compiled', 'meta:js.compiled', 'meta:css.compiled'], function() {
winston.info('NodeBB Ready');
emitter.emit('nodebb:ready');
});
if ((port === 80 || port === 443) && process.env.NODE_ENV !== 'development') {
winston.info('Using ports 80 and 443 is not recommend; use a proxy instead. See README.md');
}
server.setTimout && server.setTimeout(10000);
var isSocket = isNaN(port),
args = isSocket ? [port] : [port, nconf.get('bind_address')],
bind_address = ((nconf.get('bind_address') === "0.0.0.0" || !nconf.get('bind_address')) ? '0.0.0.0' : nconf.get('bind_address')) + ':' + port,
oldUmask;
module.exports.listen = function() {
logger.init(app);
args.push(function(err) {
if (err) {
winston.info('[startup] NodeBB was unable to listen on: ' + bind_address);
process.exit();
}
var isSocket = isNaN(port),
args = isSocket ? [port] : [port, nconf.get('bind_address')],
bind_address = ((nconf.get('bind_address') === "0.0.0.0" || !nconf.get('bind_address')) ? '0.0.0.0' : nconf.get('bind_address')) + ':' + port,
oldUmask;
winston.info('NodeBB is now listening on: ' + (isSocket ? port : bind_address));
if (oldUmask) {
process.umask(oldUmask);
}
});
args.push(function(err) {
if (err) {
winston.info('[startup] NodeBB was unable to listen on: ' + bind_address);
// Alter umask if necessary
if (isSocket) {
oldUmask = process.umask('0000');
module.exports.testSocket(port, function(err) {
if (!err) {
server.listen.apply(server, args);
} else {
winston.error('[startup] NodeBB was unable to secure domain socket access (' + port + ')');
winston.error('[startup] ' + err.message);
process.exit();
}
winston.info('NodeBB is now listening on: ' + (isSocket ? port : bind_address));
if (oldUmask) {
process.umask(oldUmask);
}
});
} else {
server.listen.apply(server, args);
}
}
// Alter umask if necessary
if (isSocket) {
oldUmask = process.umask('0000');
net = require('net');
module.exports.testSocket(port, function(err) {
if (!err) {
emitter.on('nodebb:ready', function() {
server.listen.apply(server, args);
});
module.exports.testSocket = function(socketPath, callback) {
if (typeof socketPath !== 'string') {
return callback(new Error('invalid socket path : ' + socketPath));
}
var net = require('net');
async.series([
function(next) {
fs.exists(socketPath, function(exists) {
if (exists) {
next();
} else {
winston.error('[startup] NodeBB was unable to secure domain socket access (' + port + ')');
winston.error('[startup] ' + err.message);
process.exit();
callback();
}
});
} else {
emitter.on('nodebb:ready', function() {
server.listen.apply(server, args);
},
function(next) {
var testSocket = new net.Socket();
testSocket.on('error', function(err) {
next(err.code !== 'ECONNREFUSED' ? err : null);
});
}
};
testSocket.connect({ path: socketPath }, function() {
// Something's listening here, abort
callback(new Error('port-in-use'));
});
},
async.apply(fs.unlink, socketPath), // The socket was stale, kick it out of the way
], callback);
};
module.exports.testSocket = function(socketPath, callback) {
if (typeof socketPath !== 'string') {
return callback(new Error('invalid socket path : ' + socketPath));
}
async.series([
function(next) {
fs.exists(socketPath, function(exists) {
if (exists) {
next();
} else {
callback();
}
});
},
function(next) {
var testSocket = new net.Socket();
testSocket.on('error', function(err) {
next(err.code !== 'ECONNREFUSED' ? err : null);
});
testSocket.connect({ path: socketPath }, function() {
// Something's listening here, abort
callback(new Error('port-in-use'));
});
},
async.apply(fs.unlink, socketPath), // The socket was stale, kick it out of the way
], callback);
};
}(WebServer));

Loading…
Cancel
Save