UNPKG

mongodb-tools

Version:
303 lines (253 loc) 7.61 kB
var f = require('util').format; var path = require('path'); var exec = require('child_process').exec; var fs = require('fs'); var Server = require('mongodb-core').Server; // // Clone the options var cloneOptions = function(options) { var opts = {}; for (var name in options) { opts[name] = options[name]; } return opts; }; // // Remove any non-server specific settings var filterInternalOptionsOut = function(options, internalOptions) { var opts = {}; for (var name in options) { if (internalOptions.indexOf(name) === -1) { opts[name] = options[name]; } } return opts; }; var MongosManager = function(mongosOptions) { mongosOptions = mongosOptions || {}; mongosOptions = cloneOptions(mongosOptions); var host = mongosOptions.host || 'localhost'; var port = mongosOptions.port = mongosOptions.port || 50000; var bin = mongosOptions.bin || 'mongos'; // Delete the bin option delete mongosOptions['bin']; // Set default db path if none set var pidfilepath = mongosOptions.pidfilepath = mongosOptions.pidfilepath || path.join(path.resolve('data'), f('data-%d', port)); mongosOptions.logpath = mongosOptions.logpath || path.join(path.resolve('data'), f('data-%d.log', port)); mongosOptions.configdb = mongosOptions.configdb ? mongosOptions.configdb.join(',') : ['localhost:50000'].join(','); // Current process id var pid = 0; var self = this; // Any needed credentials var credentials; // Clone the options mongosOptions = cloneOptions(mongosOptions); // filtered out internal keys filterInternalOptionsOut(mongosOptions, ['bin', 'host']); // Return this.port = port; this.host = host; this.name = f('%s:%s', host, port); // Add the file path pidfilepath = mongosOptions.pidfilepath = f('%s/mongos-%s.pid', pidfilepath, port); // Actual server instance var server = null; var ismaster = null; // Return the startup command var buildStartupCommand = function(options) { var command = []; // Binary command command.push(f('%s', bin)); for (var name in options) { if (name === 'bin') { } else if (options[name] === null) { command.push(f('--%s', name)); } else if (options[name]) { command.push(f('--%s %s', name, options[name])); } } return command.join(' '); }; var bootServer = function(cmd, callback) { var pingServer = function() { // Else we need to start checking if the server is up server = new Server({ host: host, port: port, connectionTimeout: 2000, socketTimeout: 2000, size: 1, reconnect: false }); // On connect let's go server.on('connect', function(_server) { ismaster = server.lastIsMaster(); _server.destroy(); try { /*eslint no-sync:0*/ pid = fs.readFileSync(pidfilepath, 'ascii').trim(); } catch (err) { return setTimeout(pingServer, 1000); } // Finish up if (callback) { var _callback = callback; callback = null; _callback(null, server); } }); var errHandler = function(err) { if (err.code === 10185) { try { pid = fs.readFileSync(pidfilepath, 'ascii').trim(); } catch (err) { return setTimeout(pingServer, 1000); } var _callback = callback; callback = null; return _callback(null, server); } setTimeout(pingServer, 1000); }; // Error or close handling server.once('error', errHandler); server.once('close', errHandler); server.once('timeout', errHandler); server.once('parseError', errHandler); // Attempt connect server.connect(); }; exec(cmd, function(error) { if (error != null && callback) { var _internal = callback; callback = null; return _internal(error); } }); // Attempt to ping the server setTimeout(pingServer, 5000); }; this.setCredentials = function(provider, db, user, password) { credentials = { provider: provider, db: db, user: user, password: password }; }; this.updateMongosOptions = function(options) { for (var attrname in options) { mongosOptions[attrname] = options[attrname]; } }; this.start = function(options, callback) { if (typeof options === 'function') { callback = options; options = {}; } // Build startup command var cmd = buildStartupCommand(mongosOptions); // If we have decided to kill all the processes if (typeof options.signal === 'number' || options.kill) { options.signal = typeof options.signal === 'number' ? options.signal : -9; exec(f('killall %d mongos', options.signal), function() { bootServer(cmd, callback); }); } else { bootServer(cmd, callback); } }; this.stop = function(options, callback) { if (typeof options === 'function') { callback = options; options = {}; } var signal = options.signal || -3; // Stop server connection server.destroy(); // Kill the process with the desired signal exec(f('kill %d %s', signal, pid), function(error) { if (error) return callback(error, null); setTimeout(function() { callback(null, null); }, 500); }); }; this.restart = function(options, callback) { if (typeof options === 'function') { callback = options; options = {}; } var self = this; self.stop(options, function(err) { if (err) return callback(err, null); setTimeout(function () { self.start(options, function() { if (err) return callback(err, null); callback(null, null); }); }, 3000); }); }; this.ismaster = function(callback) { self.connect(function(err, _server) { if (err) return callback(err); _server.command('system.$cmd', { ismaster: true }, function(err, r) { _server.destroy(); if (err) return callback(err); ismaster = r.result; callback(null, ismaster); }); }); }; this.lastIsMaster = function() { return ismaster; }; this.isConnected = function() { return server != null && server.isConnected(); }; this.connect = function(callback) { if (server.isConnected()) return callback(null, server); // Else we need to start checking if the server is up var s = new Server({ host: host, port: port, connectionTimeout: 2000, socketTimeout: 2000, size: 1, reconnect: false, emitError: true }); // On connect let's go s.on('connect', function(_server) { server = _server; ['error', 'close', 'timeout', 'parseError'].forEach(function(e) { server.removeAllListeners(e); }); // If we have credentials apply them if (credentials) { return _server.auth(credentials.provider, credentials.db, credentials.user, credentials.password, function(err) { if (err) return callback(err); callback(null, _server); }); } callback(null, _server); }); // Error var e = function(err) { callback(err, null); }; // Error or close handling s.once('error', e); s.once('close', e); s.once('timeout', e); // Attempt connect s.connect(); }; this.server = function() { return server; }; }; module.exports = MongosManager;