Update Node_modules
This commit is contained in:
+179
-332
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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;
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user