2013-07-11 12:14:49 -04:00
/ *
2014-07-11 16:26:20 -04:00
NodeBB - A better forum platform for the modern web
https : //github.com/NodeBB/NodeBB/
Copyright ( C ) 2013 - 2014 NodeBB Inc .
2013-07-11 12:14:49 -04:00
This program is free software : you can redistribute it and / or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation , either version 3 of the License , or
( at your option ) any later version .
This program is distributed in the hope that it will be useful ,
but WITHOUT ANY WARRANTY ; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
GNU General Public License for more details .
You should have received a copy of the GNU General Public License
along with this program . If not , see < http : //www.gnu.org/licenses/>.
* /
2014-02-02 01:38:46 -05:00
"use strict" ;
2014-04-23 21:20:40 -04:00
/*global require, global, process*/
2014-02-02 01:38:46 -05:00
var nconf = require ( 'nconf' ) ;
2015-02-26 17:39:23 +01:00
nconf . argv ( ) . env ( '__' ) ;
2014-02-02 01:38:46 -05:00
var fs = require ( 'fs' ) ,
os = require ( 'os' ) ,
2014-11-29 21:54:58 -05:00
url = require ( 'url' ) ,
2014-11-14 15:19:26 -05:00
async = require ( 'async' ) ,
2014-02-02 01:38:46 -05:00
semver = require ( 'semver' ) ,
winston = require ( 'winston' ) ,
path = require ( 'path' ) ,
pkg = require ( './package.json' ) ,
utils = require ( './public/src/utils.js' ) ;
2013-08-13 14:45:28 -04:00
2014-02-02 01:38:46 -05:00
global . env = process . env . NODE _ENV || 'production' ;
2013-07-11 12:10:45 -04:00
2014-02-02 01:38:46 -05:00
winston . remove ( winston . transports . Console ) ;
winston . add ( winston . transports . Console , {
2014-10-26 18:46:50 -04:00
colorize : true ,
2014-11-13 13:52:46 -05:00
timestamp : function ( ) {
2014-11-13 16:47:38 -05:00
var date = new Date ( ) ;
2014-11-14 16:16:06 -05:00
return date . getDate ( ) + '/' + ( date . getMonth ( ) + 1 ) + ' ' + date . toTimeString ( ) . substr ( 0 , 5 ) + ' [' + global . process . pid + ']' ;
2014-11-13 13:52:46 -05:00
} ,
2015-02-24 12:56:49 -05:00
level : ( global . env === 'production' || nconf . get ( 'log-level' ) === 'info' ) ? 'info' : 'verbose'
2014-02-02 01:38:46 -05:00
} ) ;
if ( os . platform ( ) === 'linux' ) {
2013-12-07 16:51:47 -05:00
require ( 'child_process' ) . exec ( '/usr/bin/which convert' , function ( err , stdout , stderr ) {
2013-12-07 17:03:07 -05:00
if ( err || ! stdout ) {
2013-12-08 14:49:47 -05:00
winston . warn ( 'Couldn\'t find convert. Did you install imagemagick?' ) ;
2013-12-07 16:51:47 -05:00
}
} ) ;
2014-02-02 01:38:46 -05:00
}
2013-12-07 16:51:47 -05:00
2014-02-14 11:49:16 -05:00
// Alternate configuration file support
2014-05-31 16:53:18 -04:00
var configFile = path . join ( _ _dirname , '/config.json' ) ,
2014-02-14 11:49:16 -05:00
configExists ;
2014-05-31 16:53:18 -04:00
2014-02-14 11:49:16 -05:00
if ( nconf . get ( 'config' ) ) {
2014-03-21 23:04:27 +00:00
configFile = path . resolve ( _ _dirname , nconf . get ( 'config' ) ) ;
2014-02-14 11:49:16 -05:00
}
configExists = fs . existsSync ( configFile ) ;
2013-09-10 16:26:26 -04:00
2014-10-03 15:28:02 -04:00
if ( ! nconf . get ( 'setup' ) && ! nconf . get ( 'install' ) && ! nconf . get ( 'upgrade' ) && ! nconf . get ( 'reset' ) && configExists ) {
2014-02-02 01:38:46 -05:00
start ( ) ;
2015-04-21 14:32:21 -04:00
} else if ( nconf . get ( 'setup' ) || nconf . get ( 'install' ) ) {
2014-02-02 01:38:46 -05:00
setup ( ) ;
2015-04-21 14:32:21 -04:00
} else if ( ! configExists ) {
2015-04-21 14:52:57 -04:00
require ( './install/web' ) . install ( nconf . get ( 'port' ) ) ;
2014-02-02 01:38:46 -05:00
} else if ( nconf . get ( 'upgrade' ) ) {
upgrade ( ) ;
2014-02-18 17:43:32 -05:00
} else if ( nconf . get ( 'reset' ) ) {
2014-04-08 15:29:51 -04:00
reset ( ) ;
2014-03-02 14:45:57 -05:00
}
2013-09-17 15:38:50 -04:00
2014-02-27 01:32:20 -05:00
function loadConfig ( ) {
2014-02-02 01:38:46 -05:00
nconf . file ( {
2014-02-16 05:35:44 +00:00
file : configFile
2014-02-02 01:38:46 -05:00
} ) ;
2013-07-16 15:22:59 -04:00
2014-02-14 05:01:02 +00:00
nconf . defaults ( {
2014-04-08 16:52:50 -04:00
base _dir : _ _dirname ,
themes _path : path . join ( _ _dirname , 'node_modules' ) ,
2015-04-16 11:30:53 +02:00
views _dir : path . join ( _ _dirname , 'public/templates' ) ,
version : pkg . version
2014-02-14 05:01:02 +00:00
} ) ;
2014-12-03 14:03:41 -05:00
if ( ! nconf . get ( 'isCluster' ) ) {
nconf . set ( 'isPrimary' , 'true' ) ;
nconf . set ( 'isCluster' , 'false' ) ;
}
2014-12-03 01:49:57 -05:00
// Ensure themes_path is a full filepath
nconf . set ( 'themes_path' , path . resolve ( _ _dirname , nconf . get ( 'themes_path' ) ) ) ;
nconf . set ( 'core_templates_path' , path . join ( _ _dirname , 'src/views' ) ) ;
nconf . set ( 'base_templates_path' , path . join ( nconf . get ( 'themes_path' ) , 'nodebb-theme-vanilla/templates' ) ) ;
2015-04-16 11:30:53 +02:00
if ( ! process . send ) {
// If run using `node app`, log GNU copyright info along with server info
winston . info ( 'NodeBB v' + nconf . get ( 'version' ) + ' Copyright (C) 2013-2014 NodeBB Inc.' ) ;
winston . info ( 'This program comes with ABSOLUTELY NO WARRANTY.' ) ;
winston . info ( 'This is free software, and you are welcome to redistribute it under certain conditions.' ) ;
winston . info ( '' ) ;
}
2014-12-03 01:49:57 -05:00
}
function start ( ) {
loadConfig ( ) ;
2014-12-03 01:10:45 -05:00
// nconf defaults, if not set in config
if ( ! nconf . get ( 'upload_path' ) ) {
nconf . set ( 'upload_path' , '/public/uploads' ) ;
}
// Parse out the relative_url and other goodies from the configured URL
var urlObject = url . parse ( nconf . get ( 'url' ) ) ;
var relativePath = urlObject . pathname !== '/' ? urlObject . pathname : '' ;
nconf . set ( 'use_port' , ! ! urlObject . port ) ;
nconf . set ( 'relative_path' , relativePath ) ;
nconf . set ( 'port' , urlObject . port || nconf . get ( 'port' ) || nconf . get ( 'PORT' ) || 4567 ) ;
2015-02-10 13:45:29 -05:00
nconf . set ( 'upload_url' , '/uploads/' ) ;
2014-12-03 01:10:45 -05:00
2014-12-03 14:03:41 -05:00
if ( nconf . get ( 'isPrimary' ) === 'true' ) {
2014-11-24 20:09:23 -05:00
winston . info ( 'Time: %s' , ( new Date ( ) ) . toString ( ) ) ;
2015-04-16 11:30:53 +02:00
winston . info ( 'Initializing NodeBB v%s' , nconf . get ( 'version' ) ) ;
2014-11-26 13:28:10 -05:00
winston . verbose ( '* using configuration stored in: %s' , configFile ) ;
2014-04-11 01:38:47 -04:00
2014-10-17 01:47:13 -04:00
var host = nconf . get ( nconf . get ( 'database' ) + ':host' ) ,
storeLocation = host ? 'at ' + host + ( host . indexOf ( '/' ) === - 1 ? ':' + nconf . get ( nconf . get ( 'database' ) + ':port' ) : '' ) : '' ;
2014-01-05 23:57:43 -05:00
2014-11-26 13:28:10 -05:00
winston . verbose ( '* using %s store %s' , nconf . get ( 'database' ) , storeLocation ) ;
winston . verbose ( '* using themes stored in: %s' , nconf . get ( 'themes_path' ) ) ;
2014-02-02 01:38:46 -05:00
}
2014-11-27 15:36:05 -05:00
var webserver = require ( './src/webserver' ) ;
2014-02-02 01:38:46 -05:00
require ( './src/database' ) . init ( function ( err ) {
2014-07-05 00:11:21 -04:00
if ( err ) {
winston . error ( err . stack ) ;
process . exit ( ) ;
}
2014-07-05 00:19:19 -04:00
var meta = require ( './src/meta' ) ;
2014-02-02 01:38:46 -05:00
meta . configs . init ( function ( ) {
2014-06-25 18:55:22 -04:00
var templates = require ( 'templates.js' ) ,
2014-02-02 01:38:46 -05:00
sockets = require ( './src/socket.io' ) ,
plugins = require ( './src/plugins' ) ,
2014-07-05 00:19:19 -04:00
upgrade = require ( './src/upgrade' ) ;
2014-01-11 16:15:50 -05:00
2014-02-02 01:38:46 -05:00
templates . setGlobal ( 'relative_path' , nconf . get ( 'relative_path' ) ) ;
2013-12-03 14:21:08 -05:00
2014-02-02 01:38:46 -05:00
upgrade . check ( function ( schema _ok ) {
if ( schema _ok || nconf . get ( 'check-schema' ) === false ) {
2014-11-27 15:36:05 -05:00
webserver . init ( ) ;
2014-02-02 01:38:46 -05:00
sockets . init ( webserver . server ) ;
2013-12-31 17:01:51 -05:00
2014-12-17 18:09:09 -05:00
if ( nconf . get ( 'isPrimary' ) === 'true' && ! nconf . get ( 'jobsDisabled' ) ) {
2014-11-27 15:36:05 -05:00
require ( './src/notifications' ) . init ( ) ;
require ( './src/user' ) . startJobs ( ) ;
}
2015-04-27 14:46:05 -04:00
webserver . listen ( ) ;
2014-11-14 15:19:26 -05:00
async . waterfall ( [
2014-12-06 16:05:00 -05:00
async . apply ( meta . themes . setupPaths ) ,
2014-11-14 15:19:26 -05:00
async . apply ( plugins . ready ) ,
2015-04-27 14:46:05 -04:00
async . apply ( meta . templates . compile )
2014-11-14 15:19:26 -05:00
] , function ( err ) {
if ( err ) {
winston . error ( err . stack ) ;
process . exit ( ) ;
}
if ( process . send ) {
process . send ( {
action : 'ready'
2014-08-25 11:56:48 -04:00
} ) ;
2014-11-14 15:19:26 -05:00
}
2014-02-02 01:38:46 -05:00
} ) ;
2014-03-02 13:56:46 -05:00
process . on ( 'SIGTERM' , shutdown ) ;
process . on ( 'SIGINT' , shutdown ) ;
process . on ( 'SIGHUP' , restart ) ;
2014-09-04 17:09:57 -04:00
process . on ( 'message' , function ( message ) {
2014-09-04 17:39:53 -04:00
switch ( message . action ) {
2014-09-04 17:09:57 -04:00
case 'reload' :
meta . reload ( ) ;
break ;
2014-09-04 17:39:53 -04:00
case 'js-propagate' :
meta . js . cache = message . cache ;
meta . js . map = message . map ;
2014-12-01 14:21:03 -05:00
meta . js . hash = message . hash ;
2014-12-03 14:03:41 -05:00
winston . verbose ( '[cluster] Client-side javascript and mapping propagated to worker %s' , process . pid ) ;
2014-09-04 17:39:53 -04:00
break ;
2014-09-29 19:31:27 -04:00
case 'css-propagate' :
meta . css . cache = message . cache ;
meta . css . acpCache = message . acpCache ;
2014-12-01 14:21:03 -05:00
meta . css . hash = message . hash ;
2014-12-03 14:03:41 -05:00
winston . verbose ( '[cluster] Stylesheets propagated to worker %s' , process . pid ) ;
2014-09-29 19:31:27 -04:00
break ;
2014-09-04 17:09:57 -04:00
}
2014-09-29 16:58:23 -04:00
} ) ;
2014-10-15 16:19:27 -04:00
2014-04-17 22:35:49 -04:00
process . on ( 'uncaughtException' , function ( err ) {
2014-10-15 16:19:27 -04:00
winston . error ( err . stack ) ;
2014-04-17 22:35:49 -04:00
console . log ( err . stack ) ;
2014-04-17 13:04:46 -04:00
meta . js . killMinifier ( ) ;
2014-04-17 22:35:49 -04:00
shutdown ( 1 ) ;
2014-07-05 00:11:40 -04:00
} ) ;
2014-02-02 01:38:46 -05:00
} else {
winston . warn ( 'Your NodeBB schema is out-of-date. Please run the following command to bring your dataset up to spec:' ) ;
2014-10-03 15:28:02 -04:00
winston . warn ( ' ./nodebb upgrade' ) ;
2014-12-03 14:03:41 -05:00
process . exit ( ) ;
2014-02-02 01:38:46 -05:00
}
2013-11-13 12:46:55 -05:00
} ) ;
2013-09-17 15:38:50 -04:00
} ) ;
2014-02-02 01:38:46 -05:00
} ) ;
}
2013-05-27 14:02:57 -04:00
2014-02-02 01:38:46 -05:00
function setup ( ) {
2014-02-27 01:32:20 -05:00
loadConfig ( ) ;
2015-04-21 14:32:21 -04:00
winston . info ( 'NodeBB Setup Triggered via Command Line' ) ;
2013-11-03 11:53:44 -05:00
2014-02-02 01:38:46 -05:00
var install = require ( './src/install' ) ;
2013-09-10 16:26:26 -04:00
2015-04-22 10:27:54 -04:00
process . stdout . write ( '\nWelcome to NodeBB!\n' ) ;
process . stdout . write ( '\nThis looks like a new installation, so you\'ll have to answer a few questions about your environment before we can proceed.\n' ) ;
process . stdout . write ( 'Press enter to accept the default setting (shown in brackets).\n' ) ;
install . setup ( function ( err , data ) {
var separator = ' ' ;
if ( process . stdout . columns > 10 ) {
for ( var x = 0 , cols = process . stdout . columns - 10 ; x < cols ; x ++ ) {
separator += '=' ;
}
}
process . stdout . write ( '\n' + separator + '\n\n' ) ;
2013-08-23 13:14:36 -04:00
2014-02-02 01:38:46 -05:00
if ( err ) {
winston . error ( 'There was a problem completing NodeBB setup: ' , err . message ) ;
} else {
2015-04-22 10:27:54 -04:00
if ( data . hasOwnProperty ( 'password' ) ) {
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' ) ;
}
process . stdout . write ( 'NodeBB Setup Completed. Run \'./nodebb start\' to manually start your NodeBB server.\n' ) ;
// If I am a child process, notify the parent of the returned data before exiting (useful for notifying
// hosts of auto-generated username/password during headless setups)
if ( process . send ) {
process . send ( data ) ;
}
2014-02-02 01:38:46 -05:00
}
2013-10-28 15:24:21 -04:00
2014-02-02 01:38:46 -05:00
process . exit ( ) ;
} ) ;
}
2013-10-26 10:56:05 -06:00
2014-02-02 01:38:46 -05:00
function upgrade ( ) {
2014-02-27 01:32:20 -05:00
loadConfig ( ) ;
2014-02-02 01:38:46 -05:00
require ( './src/database' ) . init ( function ( err ) {
2014-07-05 00:11:21 -04:00
if ( err ) {
winston . error ( err . stack ) ;
process . exit ( ) ;
}
2014-07-05 00:19:19 -04:00
require ( './src/meta' ) . configs . init ( function ( ) {
2014-02-02 01:38:46 -05:00
require ( './src/upgrade' ) . upgrade ( ) ;
2013-10-26 10:56:05 -06:00
} ) ;
2014-02-02 01:38:46 -05:00
} ) ;
}
2014-04-08 15:29:51 -04:00
function reset ( ) {
loadConfig ( ) ;
require ( './src/database' ) . init ( function ( err ) {
if ( err ) {
2014-04-08 16:03:42 -04:00
winston . error ( err . message ) ;
2014-04-08 15:29:51 -04:00
process . exit ( ) ;
}
2014-04-08 16:03:42 -04:00
2014-12-23 00:53:20 -05:00
if ( nconf . get ( 'theme' ) ) {
2014-04-08 16:03:42 -04:00
resetThemes ( ) ;
2014-05-14 11:20:23 -04:00
} else if ( nconf . get ( 'plugin' ) ) {
resetPlugin ( nconf . get ( 'plugin' ) ) ;
2014-04-08 16:03:42 -04:00
} else if ( nconf . get ( 'plugins' ) ) {
resetPlugins ( ) ;
} else if ( nconf . get ( 'widgets' ) ) {
resetWidgets ( ) ;
} else if ( nconf . get ( 'settings' ) ) {
resetSettings ( ) ;
} else if ( nconf . get ( 'all' ) ) {
require ( 'async' ) . series ( [ resetWidgets , resetThemes , resetPlugins , resetSettings ] , function ( err ) {
if ( ! err ) {
winston . info ( '[reset] Reset complete.' ) ;
} else {
2014-11-24 20:09:23 -05:00
winston . error ( '[reset] Errors were encountered while resetting your forum settings: %s' , err . message ) ;
2014-04-08 16:03:42 -04:00
}
2014-04-08 15:29:51 -04:00
process . exit ( ) ;
2014-04-08 16:03:42 -04:00
} ) ;
} else {
2014-05-14 11:20:23 -04:00
winston . warn ( '[reset] Nothing reset.' ) ;
2014-12-23 00:53:20 -05:00
winston . info ( 'Use ./nodebb reset {theme|plugins|widgets|settings|all}' ) ;
2014-11-14 22:18:24 -05:00
winston . info ( ' or' ) ;
winston . info ( 'Use ./nodebb reset plugin="nodebb-plugin-pluginName"' ) ;
2014-11-14 22:14:55 -05:00
process . exit ( ) ;
2014-04-08 16:03:42 -04:00
}
} ) ;
}
function resetSettings ( callback ) {
var meta = require ( './src/meta' ) ;
meta . configs . set ( 'allowLocalLogin' , 1 , function ( err ) {
2014-04-08 16:50:23 -04:00
winston . info ( '[reset] Settings reset to default' ) ;
2014-04-08 16:03:42 -04:00
if ( typeof callback === 'function' ) {
callback ( err ) ;
} else {
process . exit ( ) ;
}
2014-04-08 15:29:51 -04:00
} ) ;
}
2014-04-04 22:47:35 -04:00
function resetThemes ( callback ) {
2014-04-08 16:03:42 -04:00
var meta = require ( './src/meta' ) ;
2014-02-18 17:43:32 -05:00
2014-04-08 16:03:42 -04:00
meta . themes . set ( {
type : 'local' ,
id : 'nodebb-theme-vanilla'
} , function ( err ) {
winston . info ( '[reset] Theme reset to Vanilla' ) ;
if ( typeof callback === 'function' ) {
callback ( err ) ;
} else {
process . exit ( ) ;
}
2014-04-04 22:47:35 -04:00
} ) ;
}
2014-05-14 11:20:23 -04:00
function resetPlugin ( pluginId ) {
var db = require ( './src/database' ) ;
2015-02-23 14:57:22 -05:00
db . sortedSetRemove ( 'plugins:active' , pluginId , function ( err ) {
2014-12-30 22:06:48 -05:00
if ( err ) {
winston . error ( '[reset] Could not disable plugin: %s encountered error %s' , pluginId , err . message ) ;
2014-05-14 11:20:23 -04:00
} else {
2014-11-24 20:09:23 -05:00
winston . info ( '[reset] Plugin `%s` disabled' , pluginId ) ;
2014-05-14 11:20:23 -04:00
}
process . exit ( ) ;
} ) ;
}
2014-04-04 22:47:35 -04:00
function resetPlugins ( callback ) {
var db = require ( './src/database' ) ;
2014-04-08 16:03:42 -04:00
db . delete ( 'plugins:active' , function ( err ) {
winston . info ( '[reset] All Plugins De-activated' ) ;
if ( typeof callback === 'function' ) {
callback ( err ) ;
} else {
process . exit ( ) ;
}
2014-02-18 17:43:32 -05:00
} ) ;
}
2014-04-07 17:52:48 -04:00
function resetWidgets ( callback ) {
2014-04-08 16:03:42 -04:00
require ( './src/widgets' ) . reset ( function ( err ) {
winston . info ( '[reset] All Widgets moved to Draft Zone' ) ;
if ( typeof callback === 'function' ) {
callback ( err ) ;
} else {
process . exit ( ) ;
}
2014-04-07 17:52:48 -04:00
} ) ;
}
2014-03-02 13:56:46 -05:00
function shutdown ( code ) {
winston . info ( '[app] Shutdown (SIGTERM/SIGINT) Initialised.' ) ;
2014-03-02 14:00:28 -05:00
require ( './src/database' ) . close ( ) ;
2014-03-02 13:56:46 -05:00
winston . info ( '[app] Database connection closed.' ) ;
2014-08-25 11:56:48 -04:00
require ( './src/webserver' ) . server . close ( ) ;
winston . info ( '[app] Web server closed to connections.' ) ;
2014-03-02 13:56:46 -05:00
winston . info ( '[app] Shutdown complete.' ) ;
2014-04-17 22:35:49 -04:00
process . exit ( code || 0 ) ;
2014-03-02 13:56:46 -05:00
}
function restart ( ) {
if ( process . send ) {
winston . info ( '[app] Restarting...' ) ;
2014-04-09 13:10:28 -04:00
process . send ( {
action : 'restart'
} ) ;
2014-03-02 13:56:46 -05:00
} else {
winston . error ( '[app] Could not restart server. Shutting down.' ) ;
2014-04-17 22:35:49 -04:00
shutdown ( 1 ) ;
2014-03-02 13:56:46 -05:00
}
2014-10-03 15:28:02 -04:00
}