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