Update Node_modules

This commit is contained in:
2019-07-02 16:05:15 +02:00
parent 95a0ff3913
commit 9dab5e2dbc
3495 changed files with 39728 additions and 465154 deletions
+179 -332
View File
@@ -37,8 +37,6 @@ const BSON = retrieveBSON();
* server.connect();
*/
const defaultAuthProviders = require('../auth/defaultAuthProviders').defaultAuthProviders;
//
// States
var DISCONNECTED = 'disconnected';
@@ -91,7 +89,6 @@ var handlers = ['connect', 'close', 'error', 'timeout', 'parseError'];
* @param {boolean} [options.noDelay=true] TCP Connection no delay
* @param {number} [options.connectionTimeout=1000] TCP Connection timeout setting
* @param {number} [options.socketTimeout=0] TCP Socket timeout setting
* @param {boolean} [options.singleBufferSerializtion=true] Serialize into single buffer, trade of peak memory for serialization speed
* @param {boolean} [options.ssl=false] Use SSL for connection
* @param {boolean|function} [options.checkServerIdentity=true] Ensure we check server identify during SSL, set to false to disable checking. Only works for Node 0.12.x or higher. You can pass in a boolean or your own checkServerIdentity override function.
* @param {Buffer} [options.ca] SSL Certificate store binary buffer
@@ -170,9 +167,7 @@ var Mongos = function(seedlist, options) {
// localThresholdMS
localThresholdMS: options.localThresholdMS || 15,
// Client info
clientInfo: createClientInfo(options),
// Authentication context
authenticationContexts: []
clientInfo: createClientInfo(options)
};
// Set the client info
@@ -194,9 +189,6 @@ var Mongos = function(seedlist, options) {
);
}
// All the authProviders
this.authProviders = options.authProviders || defaultAuthProviders(this.s.bson);
// Disconnected state
this.state = DISCONNECTED;
@@ -206,8 +198,6 @@ var Mongos = function(seedlist, options) {
this.connectedProxies = [];
// Disconnected proxies
this.disconnectedProxies = [];
// Are we authenticating
this.authenticating = false;
// Index of proxy to run operations against
this.index = 0;
// High availability timeout id
@@ -264,16 +254,14 @@ function emitSDAMEvent(self, event, description) {
}
const SERVER_EVENTS = ['serverDescriptionChanged', 'error', 'close', 'timeout', 'parseError'];
function destroyServer(server, options) {
function destroyServer(server, options, callback) {
options = options || {};
SERVER_EVENTS.forEach(event => server.removeAllListeners(event));
server.destroy(options);
server.destroy(options, callback);
}
/**
* Initiate server connect
* @method
* @param {array} [options.auth=null] Array of auth options to apply on connect
*/
Mongos.prototype.connect = function(options) {
var self = this;
@@ -286,8 +274,7 @@ Mongos.prototype.connect = function(options) {
// Create server instances
var servers = this.s.seedlist.map(function(x) {
const server = new Server(
Object.assign({}, self.s.options, x, {
authProviders: self.authProviders,
Object.assign({}, self.s.options, x, options, {
reconnect: false,
monitoring: false,
parent: self,
@@ -306,6 +293,16 @@ Mongos.prototype.connect = function(options) {
connectProxies(self, servers);
};
/**
* Authenticate the topology.
* @method
* @param {MongoCredentials} credentials The credentials for authentication we are using
* @param {authResultCallback} callback A callback function
*/
Mongos.prototype.auth = function(credentials, callback) {
if (typeof callback === 'function') callback(null, null);
};
function handleEvent(self) {
return function() {
if (self.state === DESTROYED) return;
@@ -338,60 +335,57 @@ function handleInitialConnectEvent(self, event) {
// Check the type of server
if (event === 'connect') {
// Do we have authentication contexts that need to be applied
applyAuthenticationContexts(self, _this, function() {
// Get last known ismaster
self.ismaster = _this.lastIsMaster();
// Get last known ismaster
self.ismaster = _this.lastIsMaster();
// Is this not a proxy, remove t
if (self.ismaster.msg === 'isdbgrid') {
// Add to the connectd list
for (var i = 0; i < self.connectedProxies.length; i++) {
if (self.connectedProxies[i].name === _this.name) {
// Move from connectingProxies
moveServerFrom(self.connectingProxies, self.disconnectedProxies, _this);
// Emit the initial topology
emitTopologyDescriptionChanged(self);
_this.destroy();
return self.emit('failed', _this);
}
// Is this not a proxy, remove t
if (self.ismaster.msg === 'isdbgrid') {
// Add to the connectd list
for (let i = 0; i < self.connectedProxies.length; i++) {
if (self.connectedProxies[i].name === _this.name) {
// Move from connectingProxies
moveServerFrom(self.connectingProxies, self.disconnectedProxies, _this);
// Emit the initial topology
emitTopologyDescriptionChanged(self);
_this.destroy();
return self.emit('failed', _this);
}
// Remove the handlers
for (i = 0; i < handlers.length; i++) {
_this.removeAllListeners(handlers[i]);
}
// Add stable state handlers
_this.on('error', handleEvent(self, 'error'));
_this.on('close', handleEvent(self, 'close'));
_this.on('timeout', handleEvent(self, 'timeout'));
_this.on('parseError', handleEvent(self, 'parseError'));
// Move from connecting proxies connected
moveServerFrom(self.connectingProxies, self.connectedProxies, _this);
// Emit the joined event
self.emit('joined', 'mongos', _this);
} else {
// Print warning if we did not find a mongos proxy
if (self.s.logger.isWarn()) {
var message = 'expected mongos proxy, but found replicaset member mongod for server %s';
// We have a standalone server
if (!self.ismaster.hosts) {
message = 'expected mongos proxy, but found standalone mongod for server %s';
}
self.s.logger.warn(f(message, _this.name));
}
// This is not a mongos proxy, remove it completely
removeProxyFrom(self.connectingProxies, _this);
// Emit the left event
self.emit('left', 'server', _this);
// Emit failed event
self.emit('failed', _this);
}
});
// Remove the handlers
for (let i = 0; i < handlers.length; i++) {
_this.removeAllListeners(handlers[i]);
}
// Add stable state handlers
_this.on('error', handleEvent(self, 'error'));
_this.on('close', handleEvent(self, 'close'));
_this.on('timeout', handleEvent(self, 'timeout'));
_this.on('parseError', handleEvent(self, 'parseError'));
// Move from connecting proxies connected
moveServerFrom(self.connectingProxies, self.connectedProxies, _this);
// Emit the joined event
self.emit('joined', 'mongos', _this);
} else {
// Print warning if we did not find a mongos proxy
if (self.s.logger.isWarn()) {
var message = 'expected mongos proxy, but found replicaset member mongod for server %s';
// We have a standalone server
if (!self.ismaster.hosts) {
message = 'expected mongos proxy, but found standalone mongod for server %s';
}
self.s.logger.warn(f(message, _this.name));
}
// This is not a mongos proxy, remove it completely
removeProxyFrom(self.connectingProxies, _this);
// Emit the left event
self.emit('left', 'server', _this);
// Emit failed event
self.emit('failed', _this);
}
} else {
moveServerFrom(self.connectingProxies, self.disconnectedProxies, this);
// Emit the left event
@@ -470,7 +464,18 @@ function connectProxies(self, servers) {
}
}
function pickProxy(self) {
function pickProxy(self, session) {
// TODO: Destructure :)
const transaction = session && session.transaction;
if (transaction && transaction.server) {
if (transaction.server.isConnected()) {
return transaction.server;
} else {
transaction.unpinServer();
}
}
// Get the currently connected Proxies
var connectedProxies = self.connectedProxies.slice(0);
@@ -494,15 +499,22 @@ function pickProxy(self) {
}
});
let proxy;
// We have no connectedProxies pick first of the connected ones
if (connectedProxies.length === 0) {
return self.connectedProxies[0];
proxy = self.connectedProxies[0];
} else {
// Get proxy
proxy = connectedProxies[self.index % connectedProxies.length];
// Update the index
self.index = (self.index + 1) % connectedProxies.length;
}
if (transaction && transaction.isActive && proxy && proxy.isConnected()) {
transaction.pinServer(proxy);
}
// Get proxy
var proxy = connectedProxies[self.index % connectedProxies.length];
// Update the index
self.index = (self.index + 1) % connectedProxies.length;
// Return the proxy
return proxy;
}
@@ -547,33 +559,30 @@ function reconnectProxies(self, proxies, callback) {
return this.destroy();
}
if (event === 'connect' && !self.authenticating) {
// Do we have authentication contexts that need to be applied
applyAuthenticationContexts(self, _self, function() {
// Destroyed
if (self.state === DESTROYED || self.state === UNREFERENCED) {
moveServerFrom(self.connectingProxies, self.disconnectedProxies, _self);
return _self.destroy();
}
if (event === 'connect') {
// Destroyed
if (self.state === DESTROYED || self.state === UNREFERENCED) {
moveServerFrom(self.connectingProxies, self.disconnectedProxies, _self);
return _self.destroy();
}
// Remove the handlers
for (var i = 0; i < handlers.length; i++) {
_self.removeAllListeners(handlers[i]);
}
// Remove the handlers
for (var i = 0; i < handlers.length; i++) {
_self.removeAllListeners(handlers[i]);
}
// Add stable state handlers
_self.on('error', handleEvent(self, 'error'));
_self.on('close', handleEvent(self, 'close'));
_self.on('timeout', handleEvent(self, 'timeout'));
_self.on('parseError', handleEvent(self, 'parseError'));
// Add stable state handlers
_self.on('error', handleEvent(self, 'error'));
_self.on('close', handleEvent(self, 'close'));
_self.on('timeout', handleEvent(self, 'timeout'));
_self.on('parseError', handleEvent(self, 'parseError'));
// Move to the connected servers
moveServerFrom(self.connectingProxies, self.connectedProxies, _self);
// Emit topology Change
emitTopologyDescriptionChanged(self);
// Emit joined event
self.emit('joined', 'mongos', _self);
});
// Move to the connected servers
moveServerFrom(self.connectingProxies, self.connectedProxies, _self);
// Emit topology Change
emitTopologyDescriptionChanged(self);
// Emit joined event
self.emit('joined', 'mongos', _self);
} else {
// Move from connectingProxies
moveServerFrom(self.connectingProxies, self.disconnectedProxies, _self);
@@ -605,7 +614,6 @@ function reconnectProxies(self, proxies, callback) {
Object.assign({}, self.s.options, {
host: _server.name.split(':')[0],
port: parseInt(_server.name.split(':')[1], 10),
authProviders: self.authProviders,
reconnect: false,
monitoring: false,
parent: self,
@@ -647,35 +655,6 @@ function reconnectProxies(self, proxies, callback) {
}
}
function applyAuthenticationContexts(self, server, callback) {
if (self.s.authenticationContexts.length === 0) {
return callback();
}
// Copy contexts to ensure no modificiation in the middle of
// auth process.
var authContexts = self.s.authenticationContexts.slice(0);
// Apply one of the contexts
function applyAuth(authContexts, server, callback) {
if (authContexts.length === 0) return callback();
// Get the first auth context
var authContext = authContexts.shift();
// Copy the params
var customAuthContext = authContext.slice(0);
// Push our callback handler
customAuthContext.push(function(/* err */) {
applyAuth(authContexts, server, callback);
});
// Attempt authentication
server.auth.apply(server, customAuthContext);
}
// Apply all auth contexts
applyAuth(authContexts, server, callback);
}
function topologyMonitor(self, options) {
options = options || {};
@@ -829,34 +808,43 @@ Mongos.prototype.unref = function() {
* @param {boolean} [options.force=false] Force destroy the pool
* @method
*/
Mongos.prototype.destroy = function(options) {
var self = this;
// Transition state
stateTransition(this, DESTROYED);
// Get all proxies
var proxies = this.connectedProxies.concat(this.connectingProxies);
// Clear out any monitoring process
if (this.haTimeoutId) clearTimeout(this.haTimeoutId);
// Clear out authentication contexts
this.s.authenticationContexts = [];
Mongos.prototype.destroy = function(options, callback) {
if (this.haTimeoutId) {
clearTimeout(this.haTimeoutId);
}
const proxies = this.connectedProxies.concat(this.connectingProxies);
let serverCount = proxies.length;
const serverDestroyed = () => {
serverCount--;
if (serverCount > 0) {
return;
}
emitTopologyDescriptionChanged(this);
emitSDAMEvent(this, 'topologyClosed', { topologyId: this.id });
stateTransition(this, DESTROYED);
if (typeof callback === 'function') {
callback(null, null);
}
};
if (serverCount === 0) {
serverDestroyed();
return;
}
// Destroy all connecting servers
proxies.forEach(function(server) {
proxies.forEach(server => {
// Emit the sdam event
self.emit('serverClosed', {
topologyId: self.id,
this.emit('serverClosed', {
topologyId: this.id,
address: server.name
});
destroyServer(server, options);
// Move to list of disconnectedProxies
moveServerFrom(self.connectedProxies, self.disconnectedProxies, server);
destroyServer(server, options, serverDestroyed);
moveServerFrom(this.connectedProxies, this.disconnectedProxies, server);
});
// Emit the final topology change
emitTopologyDescriptionChanged(self);
// Emit toplogy closing event
emitSDAMEvent(this, 'topologyClosed', { topologyId: this.id });
};
/**
@@ -881,43 +869,59 @@ Mongos.prototype.isDestroyed = function() {
// Operations
//
// Execute write operation
var executeWriteOperation = function(self, op, ns, ops, options, callback) {
function executeWriteOperation(args, options, callback) {
if (typeof options === 'function') (callback = options), (options = {});
options = options || {};
// TODO: once we drop Node 4, use destructuring either here or in arguments.
const self = args.self;
const op = args.op;
const ns = args.ns;
const ops = args.ops;
// Pick a server
let server = pickProxy(self);
let server = pickProxy(self, options.session);
// No server found error out
if (!server) return callback(new MongoError('no mongos proxy available'));
if (!options.retryWrites || !options.session || !isRetryableWritesSupported(self)) {
// Execute the command
return server[op](ns, ops, options, callback);
}
const willRetryWrite =
!args.retrying &&
!!options.retryWrites &&
options.session &&
isRetryableWritesSupported(self) &&
!options.session.inTransaction();
// increment and assign txnNumber
options.willRetryWrite = true;
options.session.incrementTransactionNumber();
server[op](ns, ops, options, (err, result) => {
const handler = (err, result) => {
if (!err) return callback(null, result);
if (!isRetryableError(err)) {
if (!isRetryableError(err) || !willRetryWrite) {
return callback(err);
}
// Pick another server
server = pickProxy(self);
server = pickProxy(self, options.session);
// No server found error out with original error
if (!server || !isRetryableWritesSupported(server)) {
if (!server) {
return callback(err);
}
// rerun the operation
server[op](ns, ops, options, callback);
});
};
const newArgs = Object.assign({}, args, { retrying: true });
return executeWriteOperation(newArgs, options, callback);
};
if (callback.operationId) {
handler.operationId = callback.operationId;
}
// increment and assign txnNumber
if (willRetryWrite) {
options.session.incrementTransactionNumber();
options.willRetryWrite = willRetryWrite;
}
// rerun the operation
server[op](ns, ops, options, handler);
}
/**
* Insert one or more documents
@@ -950,7 +954,7 @@ Mongos.prototype.insert = function(ns, ops, options, callback) {
}
// Execute write operation
executeWriteOperation(this, 'insert', ns, ops, options, callback);
executeWriteOperation({ self: this, op: 'insert', ns, ops }, options, callback);
};
/**
@@ -984,7 +988,7 @@ Mongos.prototype.update = function(ns, ops, options, callback) {
}
// Execute write operation
executeWriteOperation(this, 'update', ns, ops, options, callback);
executeWriteOperation({ self: this, op: 'update', ns, ops }, options, callback);
};
/**
@@ -1018,7 +1022,7 @@ Mongos.prototype.remove = function(ns, ops, options, callback) {
}
// Execute write operation
executeWriteOperation(this, 'remove', ns, ops, options, callback);
executeWriteOperation({ self: this, op: 'remove', ns, ops }, options, callback);
};
const RETRYABLE_WRITE_OPERATIONS = ['findAndModify', 'insert', 'update', 'delete'];
@@ -1048,7 +1052,7 @@ Mongos.prototype.command = function(ns, cmd, options, callback) {
var self = this;
// Pick a proxy
var server = pickProxy(self);
var server = pickProxy(self, options.session);
// Topology is not connected, save the call in the provided store to be
// Executed at some point when the handler deems it's reconnected
@@ -1123,170 +1127,13 @@ Mongos.prototype.cursor = function(ns, cmd, options) {
return new FinalCursor(this.s.bson, ns, cmd, options, topology, this.s.options);
};
/**
* Authenticate using a specified mechanism
* @method
* @param {string} mechanism The Auth mechanism we are invoking
* @param {string} db The db we are invoking the mechanism against
* @param {...object} param Parameters for the specific mechanism
* @param {authResultCallback} callback A callback function
*/
Mongos.prototype.auth = function(mechanism, db) {
var allArgs = Array.prototype.slice.call(arguments, 0).slice(0);
var self = this;
var args = Array.prototype.slice.call(arguments, 2);
var callback = args.pop();
var currentContextIndex = 0;
// If we don't have the mechanism fail
if (this.authProviders[mechanism] == null && mechanism !== 'default') {
return callback(new MongoError(f('auth provider %s does not exist', mechanism)));
}
// Are we already authenticating, throw
if (this.authenticating) {
return callback(new MongoError('authentication or logout allready in process'));
}
// Topology is not connected, save the call in the provided store to be
// Executed at some point when the handler deems it's reconnected
if (!self.isConnected() && self.s.disconnectHandler != null) {
return self.s.disconnectHandler.add('auth', db, allArgs, {}, callback);
}
// Set to authenticating
this.authenticating = true;
// All errors
var errors = [];
// Get all the servers
var servers = this.connectedProxies.slice(0);
// No servers return
if (servers.length === 0) {
this.authenticating = false;
callback(null, true);
}
// Authenticate
function auth(server) {
// Arguments without a callback
var argsWithoutCallback = [mechanism, db].concat(args.slice(0));
// Create arguments
var finalArguments = argsWithoutCallback.concat([
function(err) {
count = count - 1;
// Save all the errors
if (err) errors.push({ name: server.name, err: err });
// We are done
if (count === 0) {
// Auth is done
self.authenticating = false;
// Return the auth error
if (errors.length) {
// Remove the entry from the stored authentication contexts
self.s.authenticationContexts.splice(currentContextIndex, 0);
// Return error
return callback(
new MongoError({
message: 'authentication fail',
errors: errors
}),
false
);
}
// Successfully authenticated session
callback(null, self);
}
}
]);
// Execute the auth only against non arbiter servers
if (!server.lastIsMaster().arbiterOnly) {
server.auth.apply(server, finalArguments);
}
}
// Save current context index
currentContextIndex = this.s.authenticationContexts.length;
// Store the auth context and return the last index
this.s.authenticationContexts.push([mechanism, db].concat(args.slice(0)));
// Get total count
var count = servers.length;
// Authenticate against all servers
while (servers.length > 0) {
auth(servers.shift());
}
};
/**
* Logout from a database
* @method
* @param {string} db The db we are logging out from
* @param {authResultCallback} callback A callback function
*/
Mongos.prototype.logout = function(dbName, callback) {
var self = this;
// Are we authenticating or logging out, throw
if (this.authenticating) {
throw new MongoError('authentication or logout allready in process');
}
// Ensure no new members are processed while logging out
this.authenticating = true;
// Remove from all auth providers (avoid any reaplication of the auth details)
var providers = Object.keys(this.authProviders);
for (var i = 0; i < providers.length; i++) {
this.authProviders[providers[i]].logout(dbName);
}
// Now logout all the servers
var servers = this.connectedProxies.slice(0);
var count = servers.length;
if (count === 0) return callback();
var errors = [];
function logoutServer(_server, cb) {
_server.logout(dbName, function(err) {
if (err) errors.push({ name: _server.name, err: err });
cb();
});
}
// Execute logout on all server instances
for (i = 0; i < servers.length; i++) {
logoutServer(servers[i], function() {
count = count - 1;
if (count === 0) {
// Do not block new operations
self.authenticating = false;
// If we have one or more errors
if (errors.length)
return callback(
new MongoError({
message: f('logout failed against db %s', dbName),
errors: errors
}),
false
);
// No errors
callback();
}
});
}
};
/**
* Selects a server
*
* @method
* @param {function} selector Unused
* @param {ReadPreference} [options.readPreference] Specify read preference if command supports it
* @param {ReadPreference} [options.readPreference] Unused
* @param {ClientSession} [options.session] Specify a session if it is being used
* @param {function} callback
*/
Mongos.prototype.selectServer = function(selector, options, callback) {
@@ -1296,7 +1143,7 @@ Mongos.prototype.selectServer = function(selector, options, callback) {
(callback = options), (options = selector), (selector = undefined);
options = options || {};
const server = pickProxy(this);
const server = pickProxy(this, options.session);
if (this.s.debug) this.emit('pickedServer', null, server);
callback(null, server);
};
+124 -339
View File
@@ -18,10 +18,7 @@ const SessionMixins = require('./shared').SessionMixins;
const isRetryableWritesSupported = require('./shared').isRetryableWritesSupported;
const relayEvents = require('../utils').relayEvents;
const isRetryableError = require('../error').isRetryableError;
const defaultAuthProviders = require('../auth/defaultAuthProviders').defaultAuthProviders;
var BSON = retrieveBSON();
const BSON = retrieveBSON();
//
// States
@@ -77,7 +74,6 @@ var handlers = ['connect', 'close', 'error', 'timeout', 'parseError'];
* @param {boolean} [options.noDelay=true] TCP Connection no delay
* @param {number} [options.connectionTimeout=10000] TCP Connection timeout setting
* @param {number} [options.socketTimeout=0] TCP Socket timeout setting
* @param {boolean} [options.singleBufferSerializtion=true] Serialize into single buffer, trade of peak memory for serialization speed
* @param {boolean} [options.ssl=false] Use SSL for connection
* @param {boolean|function} [options.checkServerIdentity=true] Ensure we check server identify during SSL, set to false to disable checking. Only works for Node 0.12.x or higher. You can pass in a boolean or your own checkServerIdentity override function.
* @param {Buffer} [options.ca] SSL Certificate store binary buffer
@@ -191,9 +187,7 @@ var ReplSet = function(seedlist, options) {
// Are we running in debug mode
debug: typeof options.debug === 'boolean' ? options.debug : false,
// Client info
clientInfo: createClientInfo(options),
// Authentication context
authenticationContexts: []
clientInfo: createClientInfo(options)
};
// Add handler for topology change
@@ -217,9 +211,6 @@ var ReplSet = function(seedlist, options) {
);
}
// All the authProviders
this.authProviders = options.authProviders || defaultAuthProviders(this.s.bson);
// Add forwarding of events from state handler
var types = ['joined', 'left'];
types.forEach(function(x) {
@@ -238,8 +229,6 @@ var ReplSet = function(seedlist, options) {
// Disconnected state
this.state = DISCONNECTED;
this.haTimeoutId = null;
// Are we authenticating
this.authenticating = false;
// Last ismaster
this.ismaster = null;
// Contains the intervalId
@@ -301,50 +290,40 @@ function connectNewServers(self, servers, callback) {
return this.destroy({ force: true });
}
if (event === 'connect' && !self.authenticating) {
if (event === 'connect') {
// Destroyed
if (self.state === DESTROYED || self.state === UNREFERENCED) {
return _self.destroy({ force: true });
}
// Do we have authentication contexts that need to be applied
applyAuthenticationContexts(self, _self, function() {
// Destroy the instance
if (self.state === DESTROYED || self.state === UNREFERENCED) {
return _self.destroy({ force: true });
// Update the state
var result = self.s.replicaSetState.update(_self);
// Update the state with the new server
if (result) {
// Primary lastIsMaster store it
if (_self.lastIsMaster() && _self.lastIsMaster().ismaster) {
self.ismaster = _self.lastIsMaster();
}
// Update the state
var result = self.s.replicaSetState.update(_self);
// Update the state with the new server
if (result) {
// Primary lastIsMaster store it
if (_self.lastIsMaster() && _self.lastIsMaster().ismaster) {
self.ismaster = _self.lastIsMaster();
}
// Remove the handlers
for (var i = 0; i < handlers.length; i++) {
_self.removeAllListeners(handlers[i]);
}
// Add stable state handlers
_self.on('error', handleEvent(self, 'error'));
_self.on('close', handleEvent(self, 'close'));
_self.on('timeout', handleEvent(self, 'timeout'));
_self.on('parseError', handleEvent(self, 'parseError'));
// Enalbe the monitoring of the new server
monitorServer(_self.lastIsMaster().me, self, {});
// Rexecute any stalled operation
rexecuteOperations(self);
} else {
_self.destroy({ force: true });
// Remove the handlers
for (let i = 0; i < handlers.length; i++) {
_self.removeAllListeners(handlers[i]);
}
});
} else if (event === 'connect' && self.authenticating) {
this.destroy({ force: true });
// Add stable state handlers
_self.on('error', handleEvent(self, 'error'));
_self.on('close', handleEvent(self, 'close'));
_self.on('timeout', handleEvent(self, 'timeout'));
_self.on('parseError', handleEvent(self, 'parseError'));
// Enalbe the monitoring of the new server
monitorServer(_self.lastIsMaster().me, self, {});
// Rexecute any stalled operation
rexecuteOperations(self);
} else {
_self.destroy({ force: true });
}
} else if (event === 'error') {
error = err;
}
@@ -375,7 +354,6 @@ function connectNewServers(self, servers, callback) {
Object.assign({}, self.s.options, {
host: _server.split(':')[0],
port: parseInt(_server.split(':')[1], 10),
authProviders: self.authProviders,
reconnect: false,
monitoring: false,
parent: self,
@@ -726,40 +704,6 @@ function handleEvent(self, event) {
};
}
function applyAuthenticationContexts(self, server, callback) {
if (self.s.authenticationContexts.length === 0) {
return callback();
}
// Do not apply any auth contexts if it's an arbiter
if (server.lastIsMaster() && server.lastIsMaster().arbiterOnly) {
return callback();
}
// Copy contexts to ensure no modificiation in the middle of
// auth process.
var authContexts = self.s.authenticationContexts.slice(0);
// Apply one of the contexts
function applyAuth(authContexts, server, callback) {
if (authContexts.length === 0) return callback();
// Get the first auth context
var authContext = authContexts.shift();
// Copy the params
var customAuthContext = authContext.slice(0);
// Push our callback handler
customAuthContext.push(function(/* err */) {
applyAuth(authContexts, server, callback);
});
// Attempt authentication
server.auth.apply(server, customAuthContext);
}
// Apply all auth contexts
applyAuth(authContexts, server, callback);
}
function shouldTriggerConnect(self) {
const isConnecting = self.state === CONNECTING;
const hasPrimary = self.s.replicaSetState.hasPrimary();
@@ -798,67 +742,59 @@ function handleInitialConnectEvent(self, event) {
// Check the type of server
if (event === 'connect') {
// Do we have authentication contexts that need to be applied
applyAuthenticationContexts(self, _this, function() {
// Destroy the instance
if (self.state === DESTROYED || self.state === UNREFERENCED) {
return _this.destroy({ force: true });
// Update the state
var result = self.s.replicaSetState.update(_this);
if (result === true) {
// Primary lastIsMaster store it
if (_this.lastIsMaster() && _this.lastIsMaster().ismaster) {
self.ismaster = _this.lastIsMaster();
}
// Update the state
var result = self.s.replicaSetState.update(_this);
if (result === true) {
// Primary lastIsMaster store it
if (_this.lastIsMaster() && _this.lastIsMaster().ismaster) {
self.ismaster = _this.lastIsMaster();
}
// Debug log
if (self.s.logger.isDebug()) {
self.s.logger.debug(
f(
'handleInitialConnectEvent %s from server %s in replset with id %s has state [%s]',
event,
_this.name,
self.id,
JSON.stringify(self.s.replicaSetState.set)
)
);
}
// Remove the handlers
for (var i = 0; i < handlers.length; i++) {
_this.removeAllListeners(handlers[i]);
}
// Add stable state handlers
_this.on('error', handleEvent(self, 'error'));
_this.on('close', handleEvent(self, 'close'));
_this.on('timeout', handleEvent(self, 'timeout'));
_this.on('parseError', handleEvent(self, 'parseError'));
// Do we have a primary or primaryAndSecondary
if (shouldTriggerConnect(self)) {
// We are connected
self.state = CONNECTED;
// Set initial connect state
self.initialConnectState.connect = true;
// Emit connect event
process.nextTick(function() {
self.emit('connect', self);
});
topologyMonitor(self, {});
}
} else if (result instanceof MongoError) {
_this.destroy({ force: true });
self.destroy({ force: true });
return self.emit('error', result);
} else {
_this.destroy({ force: true });
// Debug log
if (self.s.logger.isDebug()) {
self.s.logger.debug(
f(
'handleInitialConnectEvent %s from server %s in replset with id %s has state [%s]',
event,
_this.name,
self.id,
JSON.stringify(self.s.replicaSetState.set)
)
);
}
});
// Remove the handlers
for (let i = 0; i < handlers.length; i++) {
_this.removeAllListeners(handlers[i]);
}
// Add stable state handlers
_this.on('error', handleEvent(self, 'error'));
_this.on('close', handleEvent(self, 'close'));
_this.on('timeout', handleEvent(self, 'timeout'));
_this.on('parseError', handleEvent(self, 'parseError'));
// Do we have a primary or primaryAndSecondary
if (shouldTriggerConnect(self)) {
// We are connected
self.state = CONNECTED;
// Set initial connect state
self.initialConnectState.connect = true;
// Emit connect event
process.nextTick(function() {
self.emit('connect', self);
});
topologyMonitor(self, {});
}
} else if (result instanceof MongoError) {
_this.destroy({ force: true });
self.destroy({ force: true });
return self.emit('error', result);
} else {
_this.destroy({ force: true });
}
} else {
// Emit failure to connect
self.emit('failed', this);
@@ -953,20 +889,19 @@ function emitSDAMEvent(self, event, description) {
/**
* Initiate server connect
* @method
* @param {array} [options.auth=null] Array of auth options to apply on connect
*/
ReplSet.prototype.connect = function(options) {
var self = this;
// Add any connect level options to the internal state
this.s.connectOptions = options || {};
// Set connecting state
stateTransition(this, CONNECTING);
// Create server instances
var servers = this.s.seedlist.map(function(x) {
return new Server(
Object.assign({}, self.s.options, x, {
authProviders: self.authProviders,
Object.assign({}, self.s.options, x, options, {
reconnect: false,
monitoring: false,
parent: self,
@@ -998,26 +933,44 @@ ReplSet.prototype.connect = function(options) {
connectServers(self, servers);
};
/**
* Authenticate the topology.
* @method
* @param {MongoCredentials} credentials The credentials for authentication we are using
* @param {authResultCallback} callback A callback function
*/
ReplSet.prototype.auth = function(credentials, callback) {
if (typeof callback === 'function') callback(null, null);
};
/**
* Destroy the server connection
* @param {boolean} [options.force=false] Force destroy the pool
* @method
*/
ReplSet.prototype.destroy = function(options) {
ReplSet.prototype.destroy = function(options, callback) {
options = options || {};
// Transition state
stateTransition(this, DESTROYED);
let destroyCount = this.s.connectingServers.length + 1; // +1 for the callback from `replicaSetState.destroy`
const serverDestroyed = () => {
destroyCount--;
if (destroyCount > 0) {
return;
}
// Emit toplogy closing event
emitSDAMEvent(this, 'topologyClosed', { topologyId: this.id });
// Transition state
stateTransition(this, DESTROYED);
if (typeof callback === 'function') {
callback(null, null);
}
};
// Clear out any monitoring process
if (this.haTimeoutId) clearTimeout(this.haTimeoutId);
// Destroy the replicaset
this.s.replicaSetState.destroy(options);
// Clear out authentication contexts
this.s.authenticationContexts = [];
// Destroy all connecting servers
this.s.connectingServers.forEach(function(x) {
x.destroy(options);
});
// Clear out all monitoring
for (var i = 0; i < this.intervalIds.length; i++) {
@@ -1027,8 +980,18 @@ ReplSet.prototype.destroy = function(options) {
// Reset list of intervalIds
this.intervalIds = [];
// Emit toplogy closing event
emitSDAMEvent(this, 'topologyClosed', { topologyId: this.id });
if (destroyCount === 0) {
serverDestroyed();
return;
}
// Destroy the replicaset
this.s.replicaSetState.destroy(options, serverDestroyed);
// Destroy all connecting servers
this.s.connectingServers.forEach(function(x) {
x.destroy(options, serverDestroyed);
});
};
/**
@@ -1091,10 +1054,6 @@ ReplSet.prototype.connections = function() {
ReplSet.prototype.isConnected = function(options) {
options = options || {};
// If we are authenticating signal not connected
// To avoid interleaving of operations
if (this.authenticating) return false;
// If we specified a read preference check if we are connected to something
// than can satisfy this
if (options.readPreference && options.readPreference.equals(ReadPreference.secondary)) {
@@ -1135,6 +1094,7 @@ ReplSet.prototype.isDestroyed = function() {
* @method
* @param {function} selector Unused
* @param {ReadPreference} [options.readPreference] Specify read preference if command supports it
* @param {ClientSession} [options.session] Unused
* @param {function} callback
*/
ReplSet.prototype.selectServer = function(selector, options, callback) {
@@ -1381,181 +1341,6 @@ ReplSet.prototype.command = function(ns, cmd, options, callback) {
server.command(ns, cmd, options, cb);
};
/**
* Authenticate using a specified mechanism
* @method
* @param {string} mechanism The Auth mechanism we are invoking
* @param {string} db The db we are invoking the mechanism against
* @param {...object} param Parameters for the specific mechanism
* @param {authResultCallback} callback A callback function
*/
ReplSet.prototype.auth = function(mechanism, db) {
var allArgs = Array.prototype.slice.call(arguments, 0).slice(0);
var self = this;
var args = Array.prototype.slice.call(arguments, 2);
var callback = args.pop();
var currentContextIndex = 0;
// If we don't have the mechanism fail
if (this.authProviders[mechanism] == null && mechanism !== 'default') {
return callback(new MongoError(f('auth provider %s does not exist', mechanism)));
}
// Are we already authenticating, throw
if (this.authenticating) {
return callback(new MongoError('authentication or logout allready in process'));
}
// Topology is not connected, save the call in the provided store to be
// Executed at some point when the handler deems it's reconnected
if (!this.isConnected() && self.s.disconnectHandler != null) {
if (!self.s.replicaSetState.hasPrimary() && !self.s.options.secondaryOnlyConnectionAllowed) {
return self.s.disconnectHandler.add('auth', db, allArgs, {}, callback);
} else if (
!self.s.replicaSetState.hasSecondary() &&
self.s.options.secondaryOnlyConnectionAllowed
) {
return self.s.disconnectHandler.add('auth', db, allArgs, {}, callback);
}
}
// Set to authenticating
this.authenticating = true;
// All errors
var errors = [];
// Get all the servers
var servers = this.s.replicaSetState.allServers();
// No servers return
if (servers.length === 0) {
this.authenticating = false;
callback(null, true);
}
// Authenticate
function auth(server) {
// Arguments without a callback
var argsWithoutCallback = [mechanism, db].concat(args.slice(0));
// Create arguments
var finalArguments = argsWithoutCallback.concat([
function(err) {
count = count - 1;
// Save all the errors
if (err) errors.push({ name: server.name, err: err });
// We are done
if (count === 0) {
// Auth is done
self.authenticating = false;
// Return the auth error
if (errors.length) {
// Remove the entry from the stored authentication contexts
self.s.authenticationContexts.splice(currentContextIndex, 0);
// Return error
return callback(
new MongoError({
message: 'authentication fail',
errors: errors
}),
false
);
}
// Successfully authenticated session
callback(null, self);
}
}
]);
if (!server.lastIsMaster().arbiterOnly) {
// Execute the auth only against non arbiter servers
server.auth.apply(server, finalArguments);
} else {
// If we are authenticating against an arbiter just ignore it
finalArguments.pop()(null);
}
}
// Get total count
var count = servers.length;
// Save current context index
currentContextIndex = this.s.authenticationContexts.length;
// Store the auth context and return the last index
this.s.authenticationContexts.push([mechanism, db].concat(args.slice(0)));
// Authenticate against all servers
while (servers.length > 0) {
auth(servers.shift());
}
};
/**
* Logout from a database
* @method
* @param {string} db The db we are logging out from
* @param {authResultCallback} callback A callback function
*/
ReplSet.prototype.logout = function(dbName, callback) {
var self = this;
// Are we authenticating or logging out, throw
if (this.authenticating) {
throw new MongoError('authentication or logout allready in process');
}
// Ensure no new members are processed while logging out
this.authenticating = true;
// Remove from all auth providers (avoid any reaplication of the auth details)
var providers = Object.keys(this.authProviders);
for (var i = 0; i < providers.length; i++) {
this.authProviders[providers[i]].logout(dbName);
}
// Clear out any contexts associated with the db
self.s.authenticationContexts = self.s.authenticationContexts.filter(function(context) {
return context[1] !== dbName;
});
// Now logout all the servers
var servers = this.s.replicaSetState.allServers();
var count = servers.length;
if (count === 0) return callback();
var errors = [];
function logoutServer(_server, cb) {
_server.logout(dbName, function(err) {
if (err) errors.push({ name: _server.name, err: err });
cb();
});
}
// Execute logout on all server instances
for (i = 0; i < servers.length; i++) {
logoutServer(servers[i], function() {
count = count - 1;
if (count === 0) {
// Do not block new operations
self.authenticating = false;
// If we have one or more errors
if (errors.length)
return callback(
new MongoError({
message: f('logout failed against db %s', dbName),
errors: errors
}),
false
);
// No errors
callback();
}
});
}
};
/**
* Get a new cursor
* @method
+65 -43
View File
@@ -116,31 +116,43 @@ ReplSetState.prototype.allServers = function(options) {
return servers;
};
ReplSetState.prototype.destroy = function(options) {
// Destroy all sockets
if (this.primary) this.primary.destroy(options);
this.secondaries.forEach(function(x) {
x.destroy(options);
});
this.arbiters.forEach(function(x) {
x.destroy(options);
});
this.passives.forEach(function(x) {
x.destroy(options);
});
this.ghosts.forEach(function(x) {
x.destroy(options);
});
// Clear out the complete state
this.secondaries = [];
this.arbiters = [];
this.passives = [];
this.ghosts = [];
this.unknownServers = [];
this.set = {};
this.primary = null;
// Emit the topology changed
emitTopologyDescriptionChanged(this);
ReplSetState.prototype.destroy = function(options, callback) {
const serversToDestroy = this.secondaries
.concat(this.arbiters)
.concat(this.passives)
.concat(this.ghosts);
if (this.primary) serversToDestroy.push(this.primary);
let serverCount = serversToDestroy.length;
const serverDestroyed = () => {
serverCount--;
if (serverCount > 0) {
return;
}
// Clear out the complete state
this.secondaries = [];
this.arbiters = [];
this.passives = [];
this.ghosts = [];
this.unknownServers = [];
this.set = {};
this.primary = null;
// Emit the topology changed
emitTopologyDescriptionChanged(this);
if (typeof callback === 'function') {
callback(null, null);
}
};
if (serverCount === 0) {
serverDestroyed();
return;
}
serversToDestroy.forEach(server => server.destroy(options, serverDestroyed));
};
ReplSetState.prototype.remove = function(server, options) {
@@ -287,6 +299,34 @@ ReplSetState.prototype.update = function(server) {
// Is this a mongos
//
if (ismaster && ismaster.msg === 'isdbgrid') {
if (this.primary && this.primary.name === serverName) {
this.primary = null;
this.topologyType = TopologyType.ReplicaSetNoPrimary;
}
return false;
}
// A RSGhost instance
if (ismaster.isreplicaset) {
self.set[serverName] = {
type: ServerType.RSGhost,
setVersion: null,
electionId: null,
setName: ismaster.setName
};
if (this.primary && this.primary.name === serverName) {
this.primary = null;
}
// Set the topology
this.topologyType = this.primary
? TopologyType.ReplicaSetWithPrimary
: TopologyType.ReplicaSetNoPrimary;
if (ismaster.setName) this.setName = ismaster.setName;
// Set the topology
return false;
}
@@ -305,30 +345,12 @@ ReplSetState.prototype.update = function(server) {
electionId: null,
setName: ismaster.setName
};
// Set the topology
this.topologyType = this.primary
? TopologyType.ReplicaSetWithPrimary
: TopologyType.ReplicaSetNoPrimary;
if (ismaster.setName) this.setName = ismaster.setName;
return false;
}
// A RSGhost instance
if (ismaster.isreplicaset) {
self.set[serverName] = {
type: ServerType.RSGhost,
setVersion: null,
electionId: null,
setName: null
};
// Set the topology
this.topologyType = this.primary
? TopologyType.ReplicaSetWithPrimary
: TopologyType.ReplicaSetNoPrimary;
if (ismaster.setName) this.setName = ismaster.setName;
// Set the topology
return false;
}
+87 -281
View File
@@ -8,11 +8,9 @@ var inherits = require('util').inherits,
debugOptions = require('../connection/utils').debugOptions,
retrieveBSON = require('../connection/utils').retrieveBSON,
Pool = require('../connection/pool'),
Query = require('../connection/commands').Query,
MongoError = require('../error').MongoError,
MongoNetworkError = require('../error').MongoNetworkError,
TwoSixWireProtocolSupport = require('../wireprotocol/2_6_support'),
ThreeTwoWireProtocolSupport = require('../wireprotocol/3_2_support'),
wireProtocol = require('../wireprotocol'),
BasicCursor = require('../cursor'),
sdam = require('./shared'),
createClientInfo = require('./shared').createClientInfo,
@@ -23,57 +21,6 @@ var inherits = require('util').inherits,
const collationNotSupported = require('../utils').collationNotSupported;
function getSaslSupportedMechs(options) {
if (!options) {
return {};
}
const authArray = options.auth || [];
const authMechanism = authArray[0] || options.authMechanism;
const authSource = authArray[1] || options.authSource || options.dbName || 'admin';
const user = authArray[2] || options.user;
if (typeof authMechanism === 'string' && authMechanism.toUpperCase() !== 'DEFAULT') {
return {};
}
if (!user) {
return {};
}
return { saslSupportedMechs: `${authSource}.${user}` };
}
function getDefaultAuthMechanism(ismaster) {
if (ismaster) {
// If ismaster contains saslSupportedMechs, use scram-sha-256
// if it is available, else scram-sha-1
if (Array.isArray(ismaster.saslSupportedMechs)) {
return ismaster.saslSupportedMechs.indexOf('SCRAM-SHA-256') >= 0
? 'scram-sha-256'
: 'scram-sha-1';
}
// Fallback to legacy selection method. If wire version >= 3, use scram-sha-1
if (ismaster.maxWireVersion >= 3) {
return 'scram-sha-1';
}
}
// Default for wireprotocol < 3
return 'mongocr';
}
function extractIsMasterError(err, result) {
if (err) {
return err;
}
if (result && result.result && result.result.ok === 0) {
return new MongoError(result.result);
}
}
// Used for filtering out fields for loggin
var debugFields = [
'reconnect',
@@ -90,7 +37,6 @@ var debugFields = [
'connectionTimeout',
'checkServerIdentity',
'socketTimeout',
'singleBufferSerializtion',
'ssl',
'ca',
'crl',
@@ -225,9 +171,6 @@ var Server = function(options) {
this.monitoringProcessId = null;
// Initial connection
this.initialConnect = true;
// Wire protocol handler, default to oldest known protocol handler
// this gets changed when the first ismaster is called.
this.wireProtocolHandler = new TwoSixWireProtocolSupport();
// Default type
this._type = 'server';
// Set the client info
@@ -303,20 +246,6 @@ Object.defineProperty(Server.prototype, 'name', {
}
});
function isSupportedServer(response) {
return response && typeof response.maxWireVersion === 'number' && response.maxWireVersion >= 2;
}
function configureWireProtocolHandler(self, ismaster) {
// 3.2 wire protocol handler
if (ismaster.maxWireVersion >= 4) {
return new ThreeTwoWireProtocolSupport();
}
// default to 2.6 wire protocol handler
return new TwoSixWireProtocolSupport();
}
function disconnectHandler(self, type, ns, cmd, options, callback) {
// Topology is not connected, save the call in the provided store to be
// Executed at some point when the handler deems it's reconnected
@@ -344,16 +273,13 @@ function monitoringProcess(self) {
// Emit monitoring Process event
self.emit('monitoring', self);
// Perform ismaster call
// Query options
var queryOptions = { numberToSkip: 0, numberToReturn: -1, checkKeys: false, slaveOk: true };
// Create a query instance
var query = new Query(self.s.bson, 'admin.$cmd', { ismaster: true }, queryOptions);
// Get start time
var start = new Date().getTime();
// Execute the ismaster query
self.s.pool.write(
query,
self.command(
'admin.$cmd',
{ ismaster: true },
{
socketTimeout:
typeof self.s.options.connectionTimeout !== 'number'
@@ -361,7 +287,7 @@ function monitoringProcess(self) {
: self.s.options.connectionTimeout,
monitoring: true
},
function(err, result) {
(err, result) => {
// Set initial lastIsMasterMS
self.lastIsMasterMS = new Date().getTime() - start;
if (self.s.pool.isDestroyed()) return;
@@ -377,7 +303,7 @@ function monitoringProcess(self) {
}
var eventHandler = function(self, event) {
return function(err) {
return function(err, conn) {
// Log information of received information if in info mode
if (self.s.logger.isInfo()) {
var object = err instanceof MongoError ? JSON.stringify(err) : {};
@@ -388,126 +314,67 @@ var eventHandler = function(self, event) {
// Handle connect event
if (event === 'connect') {
// Issue an ismaster command at connect
// Query options
var queryOptions = { numberToSkip: 0, numberToReturn: -1, checkKeys: false, slaveOk: true };
// Create a query instance
var compressors =
self.s.compression && self.s.compression.compressors ? self.s.compression.compressors : [];
var query = new Query(
self.s.bson,
'admin.$cmd',
Object.assign(
{ ismaster: true, client: self.clientInfo, compression: compressors },
getSaslSupportedMechs(self.s.options)
),
queryOptions
);
// Get start time
var start = new Date().getTime();
// Execute the ismaster query
self.s.pool.write(
query,
{
socketTimeout: self.s.options.connectionTimeout || 2000
},
function(err, result) {
// Set initial lastIsMasterMS
self.lastIsMasterMS = new Date().getTime() - start;
self.initialConnect = false;
self.ismaster = conn.ismaster;
self.lastIsMasterMS = conn.lastIsMasterMS;
if (conn.agreedCompressor) {
self.s.pool.options.agreedCompressor = conn.agreedCompressor;
}
const serverError = extractIsMasterError(err, result);
if (conn.zlibCompressionLevel) {
self.s.pool.options.zlibCompressionLevel = conn.zlibCompressionLevel;
}
if (serverError) {
self.destroy();
return self.emit('error', serverError);
}
if (conn.ismaster.$clusterTime) {
const $clusterTime = conn.ismaster.$clusterTime;
self.clusterTime = $clusterTime;
}
if (!isSupportedServer(result.result)) {
self.destroy();
const latestSupportedVersion = '2.6';
const message =
'Server at ' +
self.s.options.host +
':' +
self.s.options.port +
' reports wire version ' +
(result.result.maxWireVersion || 0) +
', but this version of Node.js Driver requires at least 2 (MongoDB' +
latestSupportedVersion +
').';
return self.emit('error', new MongoError(message), self);
}
// It's a proxy change the type so
// the wireprotocol will send $readPreference
if (self.ismaster.msg === 'isdbgrid') {
self._type = 'mongos';
}
// Determine whether the server is instructing us to use a compressor
if (result.result && result.result.compression) {
for (var i = 0; i < self.s.compression.compressors.length; i++) {
if (result.result.compression.indexOf(self.s.compression.compressors[i]) > -1) {
self.s.pool.options.agreedCompressor = self.s.compression.compressors[i];
break;
}
// Have we defined self monitoring
if (self.s.monitoring) {
self.monitoringProcessId = setTimeout(monitoringProcess(self), self.s.monitoringInterval);
}
// Emit server description changed if something listening
sdam.emitServerDescriptionChanged(self, {
address: self.name,
arbiters: [],
hosts: [],
passives: [],
type: sdam.getTopologyType(self)
});
if (!self.s.inTopology) {
// Emit topology description changed if something listening
sdam.emitTopologyDescriptionChanged(self, {
topologyType: 'Single',
servers: [
{
address: self.name,
arbiters: [],
hosts: [],
passives: [],
type: sdam.getTopologyType(self)
}
]
});
}
if (self.s.compression.zlibCompressionLevel) {
self.s.pool.options.zlibCompressionLevel = self.s.compression.zlibCompressionLevel;
}
}
// Log the ismaster if available
if (self.s.logger.isInfo()) {
self.s.logger.info(
f('server %s connected with ismaster [%s]', self.name, JSON.stringify(self.ismaster))
);
}
// Ensure no error emitted after initial connect when reconnecting
self.initialConnect = false;
// Save the ismaster
self.ismaster = result.result;
// It's a proxy change the type so
// the wireprotocol will send $readPreference
if (self.ismaster.msg === 'isdbgrid') {
self._type = 'mongos';
}
// Add the correct wire protocol handler
self.wireProtocolHandler = configureWireProtocolHandler(self, self.ismaster);
// Have we defined self monitoring
if (self.s.monitoring) {
self.monitoringProcessId = setTimeout(
monitoringProcess(self),
self.s.monitoringInterval
);
}
// Emit server description changed if something listening
sdam.emitServerDescriptionChanged(self, {
address: self.name,
arbiters: [],
hosts: [],
passives: [],
type: sdam.getTopologyType(self)
});
if (!self.s.inTopology) {
// Emit topology description changed if something listening
sdam.emitTopologyDescriptionChanged(self, {
topologyType: 'Single',
servers: [
{
address: self.name,
arbiters: [],
hosts: [],
passives: [],
type: sdam.getTopologyType(self)
}
]
});
}
// Log the ismaster if available
if (self.s.logger.isInfo()) {
self.s.logger.info(
f('server %s connected with ismaster [%s]', self.name, JSON.stringify(self.ismaster))
);
}
// Emit connect
self.emit('connect', self);
}
);
// Emit connect
self.emit('connect', self);
} else if (
event === 'error' ||
event === 'parseError' ||
@@ -554,7 +421,7 @@ var eventHandler = function(self, event) {
// On first connect fail
if (
self.s.pool.state === 'disconnected' &&
['disconnected', 'connecting'].indexOf(self.s.pool.state) !== -1 &&
self.initialConnect &&
['close', 'timeout', 'error', 'parseError'].indexOf(event) !== -1
) {
@@ -589,8 +456,6 @@ var eventHandler = function(self, event) {
/**
* Initiate server connect
* @method
* @param {array} [options.auth=null] Array of auth options to apply on connect
*/
Server.prototype.connect = function(options) {
var self = this;
@@ -630,12 +495,17 @@ Server.prototype.connect = function(options) {
address: self.name
});
// Connect with optional auth settings
if (options.auth) {
self.s.pool.connect.apply(self.s.pool, options.auth);
} else {
self.s.pool.connect();
}
self.s.pool.connect();
};
/**
* Authenticate the topology.
* @method
* @param {MongoCredentials} credentials The credentials for authentication we are using
* @param {authResultCallback} callback A callback function
*/
Server.prototype.auth = function(credentials, callback) {
if (typeof callback === 'function') callback(null, null);
};
/**
@@ -755,33 +625,7 @@ Server.prototype.command = function(ns, cmd, options, callback) {
return callback(new MongoError(`server ${this.name} does not support collation`));
}
// Are we executing against a specific topology
var topology = options.topology || {};
// Create the query object
var query = self.wireProtocolHandler.command(self.s.bson, ns, cmd, {}, topology, options);
if (query instanceof MongoError) {
return callback(query, null);
}
// Set slave OK of the query
query.slaveOk = options.readPreference ? options.readPreference.slaveOk() : false;
// Write options
var writeOptions = {
raw: typeof options.raw === 'boolean' ? options.raw : false,
promoteLongs: typeof options.promoteLongs === 'boolean' ? options.promoteLongs : true,
promoteValues: typeof options.promoteValues === 'boolean' ? options.promoteValues : true,
promoteBuffers: typeof options.promoteBuffers === 'boolean' ? options.promoteBuffers : false,
command: true,
monitoring: typeof options.monitoring === 'boolean' ? options.monitoring : false,
fullResult: typeof options.fullResult === 'boolean' ? options.fullResult : false,
requestId: query.requestId,
socketTimeout: typeof options.socketTimeout === 'number' ? options.socketTimeout : null,
session: options.session || null
};
// Write the operation to the pool
self.s.pool.write(query, writeOptions, callback);
wireProtocol.command(self, ns, cmd, options, callback);
};
/**
@@ -812,7 +656,7 @@ Server.prototype.insert = function(ns, ops, options, callback) {
ops = Array.isArray(ops) ? ops : [ops];
// Execute write
return self.wireProtocolHandler.insert(self.s.pool, ns, self.s.bson, ops, options, callback);
return wireProtocol.insert(self, ns, ops, options, callback);
};
/**
@@ -847,7 +691,7 @@ Server.prototype.update = function(ns, ops, options, callback) {
// Setup the docs as an array
ops = Array.isArray(ops) ? ops : [ops];
// Execute write
return self.wireProtocolHandler.update(self.s.pool, ns, self.s.bson, ops, options, callback);
return wireProtocol.update(self, ns, ops, options, callback);
};
/**
@@ -882,7 +726,7 @@ Server.prototype.remove = function(ns, ops, options, callback) {
// Setup the docs as an array
ops = Array.isArray(ops) ? ops : [ops];
// Execute write
return self.wireProtocolHandler.remove(self.s.pool, ns, self.s.bson, ops, options, callback);
return wireProtocol.remove(self, ns, ops, options, callback);
};
/**
@@ -911,52 +755,6 @@ Server.prototype.cursor = function(ns, cmd, options) {
return new FinalCursor(this.s.bson, ns, cmd, options, topology, this.s.options);
};
/**
* Logout from a database
* @method
* @param {string} db The db we are logging out from
* @param {authResultCallback} callback A callback function
*/
Server.prototype.logout = function(dbName, callback) {
this.s.pool.logout(dbName, callback);
};
/**
* Authenticate using a specified mechanism
* @method
* @param {string} mechanism The Auth mechanism we are invoking
* @param {string} db The db we are invoking the mechanism against
* @param {...object} param Parameters for the specific mechanism
* @param {authResultCallback} callback A callback function
*/
Server.prototype.auth = function(mechanism, db) {
var self = this;
if (mechanism === 'default') {
mechanism = getDefaultAuthMechanism(self.ismaster);
}
// Slice all the arguments off
var args = Array.prototype.slice.call(arguments, 0);
// Set the mechanism
args[0] = mechanism;
// Get the callback
var callback = args[args.length - 1];
// If we are not connected or have a disconnectHandler specified
if (disconnectHandler(self, 'auth', db, args, {}, callback)) {
return;
}
// Do not authenticate if we are an arbiter
if (this.lastIsMaster() && this.lastIsMaster().arbiterOnly) {
return callback(null, true);
}
// Apply the arguments to the pool
self.s.pool.auth.apply(self.s.pool, args);
};
/**
* Compare two server instances
* @method
@@ -980,6 +778,10 @@ Server.prototype.connections = function() {
/**
* Selects a server
* @method
* @param {function} selector Unused
* @param {ReadPreference} [options.readPreference] Unused
* @param {ClientSession} [options.session] Unused
* @return {Server}
*/
Server.prototype.selectServer = function(selector, options, callback) {
@@ -1000,8 +802,11 @@ var listeners = ['close', 'error', 'timeout', 'parseError', 'connect'];
* @param {boolean} [options.emitDestroy=false] Emit destroy event on destroy
* @param {boolean} [options.force=false] Force destroy the pool
*/
Server.prototype.destroy = function(options) {
if (this._destroyed) return;
Server.prototype.destroy = function(options, callback) {
if (this._destroyed) {
if (typeof callback === 'function') callback(null, null);
return;
}
options = options || {};
var self = this;
@@ -1017,6 +822,7 @@ Server.prototype.destroy = function(options) {
// No pool, return
if (!self.s.pool) {
this._destroyed = true;
if (typeof callback === 'function') callback(null, null);
return;
}
@@ -1052,7 +858,7 @@ Server.prototype.destroy = function(options) {
}
// Destroy the pool
this.s.pool.destroy(options.force);
this.s.pool.destroy(options.force, callback);
this._destroyed = true;
};
+19
View File
@@ -4,6 +4,7 @@ const os = require('os');
const f = require('util').format;
const ReadPreference = require('./read_preference');
const Buffer = require('safe-buffer').Buffer;
const TopologyType = require('../sdam/topology_description').TopologyType;
/**
* Emit event if it exists
@@ -398,6 +399,20 @@ const SessionMixins = {
}
};
function topologyType(topology) {
if (topology.description) {
return topology.description.type;
}
if (topology.type === 'mongos') {
return TopologyType.Sharded;
} else if (topology.type === 'replset') {
return TopologyType.ReplicaSetWithPrimary;
}
return TopologyType.Single;
}
const RETRYABLE_WIRE_VERSION = 6;
/**
@@ -415,6 +430,10 @@ const isRetryableWritesSupported = function(topology) {
return false;
}
if (topologyType(topology) === TopologyType.Single) {
return false;
}
return true;
};