UNPKG

admin-mongo

Version:

A Web user interface to administer MongoDB databases built using Express

267 lines (234 loc) 8.96 kB
var express = require('express'); var path = require('path'); var favicon = require('serve-favicon'); var logger = require('morgan'); var cookieParser = require('cookie-parser'); var bodyParser = require('body-parser'); var MongoClient = require('mongodb').MongoClient; var handlebars = require('express-handlebars'); var nconf = require('nconf'); var session = require('express-session'); var async = require('async'); // Define routes var indexRoute = require('./routes/index'); var apiRoute = require('./routes/api'); var usersRoute = require('./routes/users'); var configRoute = require('./routes/config'); var docRoute = require('./routes/document'); var dbRoute = require('./routes/database'); var collectionRoute = require('./routes/collection'); // set the base dir to __dirname when running as webapp and electron path if running as electron app var dir_base = __dirname; if(process.versions['electron']){ dir_base = path.join(process.resourcesPath.toString(), 'app/'); } var app = express(); // setup the translation var i18n = new (require('i18n-2'))({ locales: ['en', 'de', 'es', 'ru'], directory: path.join(dir_base, 'locales/') }); // setup DB for server stats var Datastore = require('nedb'); var db = new Datastore({filename: path.join(dir_base, 'data/dbStats.db'), autoload: true}); // view engine setup app.set('views', path.join(dir_base, 'views/')); app.engine('hbs', handlebars({extname: 'hbs', defaultLayout: path.join(dir_base, 'views/layouts/layout.hbs')})); app.set('view engine', 'hbs'); // helpers for the handlebars templating platform handlebars = handlebars.create({ helpers: { __: function (value){ return i18n.__(value); }, toJSON: function (object){ return JSON.stringify(object); }, niceBool: function (object){ if(object === undefined)return'No'; if(object === true)return'Yes'; return'No'; }, app_context: function (){ if(nconf.stores.app.get('app:context') !== undefined){ return'/' + nconf.stores.app.get('app:context'); }return''; }, formatBytes: function (bytes){ if(bytes === 0)return'0 Byte'; var k = 1000; var decimals = 2; var dm = decimals + 1 || 3; var sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB']; var i = Math.floor(Math.log(bytes) / Math.log(k)); return(bytes / Math.pow(k, i)).toPrecision(dm) + ' ' + sizes[i]; } } }); // setup nconf to read in the file // create config dir and blank files if they dont exist var fs = require('fs'); var dir_config = path.join(dir_base, 'config/'); var config_connections = path.join(dir_config, 'config.json'); var config_app = path.join(dir_config, 'app.json'); // Check existence of config dir and config files, create if nothing if(!fs.existsSync(dir_config)) fs.mkdirSync(dir_config); if(!fs.existsSync(config_connections)) fs.writeFileSync(config_connections, '{}'); if(!fs.existsSync(config_app)) fs.writeFileSync(config_app, '{}'); // if config files exist but are blank we write blank files for nconf if(fs.existsSync(config_app, 'utf8')){ if(fs.readFileSync(config_app, 'utf8') === ''){ fs.writeFileSync(config_app, '{}', 'utf8'); } } if(fs.existsSync(config_connections, 'utf8')){ if(fs.readFileSync(config_connections, 'utf8') === ''){ fs.writeFileSync(config_connections, '{}', 'utf8'); } } // setup the two conf. 'app' holds application config, and connections // holds the mongoDB connections nconf.add('connections', {type: 'file', file: config_connections}); nconf.add('app', {type: 'file', file: config_app}); // set app defaults var app_host = '0.0.0.0'; var app_port = process.env.PORT || 1234; // get the app configs and override if present if(nconf.stores.app.get('app:host') !== undefined){ app_host = nconf.stores.app.get('app:host'); } if(nconf.stores.app.get('app:port') !== undefined){ app_port = nconf.stores.app.get('app:port'); } if(nconf.stores.app.get('app:locale') !== undefined){ i18n.setLocale(nconf.stores.app.get('app:locale')); } app.locals.app_host = app_host; app.locals.app_port = app_port; // setup the app context var app_context = ''; if(nconf.stores.app.get('app:context') !== undefined){ app_context = '/' + nconf.stores.app.get('app:context'); } app.use(logger('dev')); app.use(bodyParser.json({limit: '16mb'})); app.use(bodyParser.urlencoded({extended: false})); app.use(cookieParser()); // setup session app.use(session({ secret: '858SGTUyX8w1L6JNm1m93Cvm8uX1QX2D', resave: true, saveUninitialized: true })); // front-end modules loaded from NPM app.use(app_context + '/font-awesome', express.static(path.join(dir_base, 'node_modules/font-awesome/'))); app.use(app_context + '/jquery', express.static(path.join(dir_base, 'node_modules/jquery/dist/'))); app.use(app_context + '/bootstrap', express.static(path.join(dir_base, 'node_modules/bootstrap/dist/'))); app.use(app_context + '/css', express.static(path.join(dir_base, 'public/css'))); app.use(app_context + '/fonts', express.static(path.join(dir_base, 'public/fonts'))); app.use(app_context + '/js', express.static(path.join(dir_base, 'public/js'))); app.use(app_context + '/favicon.ico', express.static(path.join(dir_base, 'public/favicon.ico'))); // Make stuff accessible to our router app.use(function (req, res, next){ req.nconf = nconf.stores; req.handlebars = handlebars; req.i18n = i18n; req.app_context = app_context; req.db = db; next(); }); // add context to route if required if(app_context !== ''){ app.use(app_context, apiRoute); app.use(app_context, usersRoute); app.use(app_context, configRoute); app.use(app_context, docRoute); app.use(app_context, dbRoute); app.use(app_context, collectionRoute); app.use(app_context, indexRoute); }else{ app.use('/', apiRoute); app.use('/', usersRoute); app.use('/', configRoute); app.use('/', docRoute); app.use('/', dbRoute); app.use('/', collectionRoute); app.use('/', indexRoute); } // catch 404 and forward to error handler app.use(function (req, res, next){ var err = new Error('Not Found'); err.status = 404; next(err); }); // === Error handlers === // development error handler // will print stacktrace if(app.get('env') === 'development'){ app.use(function (err, req, res, next){ console.log(err.stack); res.status(err.status || 500); res.render('error', { message: err.message, error: err, helpers: handlebars.helpers }); }); } // production error handler // no stacktraces leaked to user app.use(function (err, req, res, next){ console.log(err.stack); res.status(err.status || 500); res.render('error', { message: err.message, error: {}, helpers: handlebars.helpers }); }); app.on('uncaughtException', function(err){ console.error(err.stack); process.exit(); }); // add the connections to the connection pool var connection_list = nconf.stores.connections.get('connections'); var connPool = require('./connections'); var monitoring = require('./monitoring'); app.locals.dbConnections = null; async.forEachOf(connection_list, function (value, key, callback){ var MongoURI = require('mongo-uri'); try{ uri = MongoURI.parse(value.connection_string); connPool.addConnection({connName: key, connString: value.connection_string, connOptions: value.connection_options}, app, function (err, data){ if(err)delete connection_list[key]; callback(); }); }catch(err){ callback(); } }, function (err){ if(err) console.error(err.message); // lift the app app.listen(app_port, app_host, function (){ console.log('adminMongo listening on host: http://' + app_host + ':' + app_port + app_context); // used for electron to know when express app has started app.emit('startedAdminMongo'); if(nconf.stores.app.get('app:monitoring') !== false){ // start the initial monitoring monitoring.serverMonitoring(db, app.locals.dbConnections); // Keep firing monitoring every 30 seconds setInterval(function (){ monitoring.serverMonitoring(db, app.locals.dbConnections); }, 30000); } }).on('error', function (err){ if(err.code === 'EADDRINUSE'){ console.error('Error starting adminMongo: Port ' + app_port + ' already in use, choose another'); }else{ console.error('Error starting adminMongo: ' + err); app.emit('errorAdminMongo'); } }); }); module.exports = app;