aboutsummaryrefslogtreecommitdiff
path: root/node_modules/mongodb-core/lib/topologies/server.js
diff options
context:
space:
mode:
authornanalelfe <nargiza.nosirova@mail.utoronto.ca>2016-07-18 10:54:08 +0000
committernanalelfe <nargiza.nosirova@mail.utoronto.ca>2016-07-18 10:54:08 +0000
commita35da9f9ccc1124d9b6f4461c7216ffbb0285e2f (patch)
treed5b4b8548caae36a20e1258a8341dab4b3d522d2 /node_modules/mongodb-core/lib/topologies/server.js
parent16bbc66ebafc6f1a55e47dbda3f3c0f658fe715c (diff)
parentc1ce89359a7b54ec97b54ce577e5534c180c5c4b (diff)
merged
Diffstat (limited to 'node_modules/mongodb-core/lib/topologies/server.js')
-rw-r--r--node_modules/mongodb-core/lib/topologies/server.js805
1 files changed, 805 insertions, 0 deletions
diff --git a/node_modules/mongodb-core/lib/topologies/server.js b/node_modules/mongodb-core/lib/topologies/server.js
new file mode 100644
index 0000000..6304274
--- /dev/null
+++ b/node_modules/mongodb-core/lib/topologies/server.js
@@ -0,0 +1,805 @@
+"use strict"
+
+var inherits = require('util').inherits,
+ f = require('util').format,
+ EventEmitter = require('events').EventEmitter,
+ BSON = require('bson').native().BSON,
+ ReadPreference = require('./read_preference'),
+ Logger = require('../connection/logger'),
+ debugOptions = require('../connection/utils').debugOptions,
+ Pool = require('../connection/pool'),
+ Query = require('../connection/commands').Query,
+ MongoError = require('../error'),
+ PreTwoSixWireProtocolSupport = require('../wireprotocol/2_4_support'),
+ TwoSixWireProtocolSupport = require('../wireprotocol/2_6_support'),
+ ThreeTwoWireProtocolSupport = require('../wireprotocol/3_2_support'),
+ BasicCursor = require('../cursor'),
+ sdam = require('./shared'),
+ assign = require('./shared').assign;
+
+// Used for filtering out fields for loggin
+var debugFields = ['reconnect', 'reconnectTries', 'reconnectInterval', 'emitError', 'cursorFactory', 'host'
+ , 'port', 'size', 'keepAlive', 'keepAliveInitialDelay', 'noDelay', 'connectionTimeout', 'checkServerIdentity'
+ , 'socketTimeout', 'singleBufferSerializtion', 'ssl', 'ca', 'cert', 'key', 'rejectUnauthorized', 'promoteLongs'];
+
+// Server instance id
+var id = 0;
+var serverAccounting = false;
+var servers = {};
+
+/**
+ * Creates a new Server instance
+ * @class
+ * @param {boolean} [options.reconnect=true] Server will attempt to reconnect on loss of connection
+ * @param {number} [options.reconnectTries=30] Server attempt to reconnect #times
+ * @param {number} [options.reconnectInterval=1000] Server will wait # milliseconds between retries
+ * @param {number} [options.monitoring=true] Enable the server state monitoring (calling ismaster at monitoringInterval)
+ * @param {number} [options.monitoringInterval=5000] The interval of calling ismaster when monitoring is enabled.
+ * @param {Cursor} [options.cursorFactory=Cursor] The cursor factory class used for all query cursors
+ * @param {string} options.host The server host
+ * @param {number} options.port The server port
+ * @param {number} [options.size=5] Server connection pool size
+ * @param {boolean} [options.keepAlive=true] TCP Connection keep alive enabled
+ * @param {number} [options.keepAliveInitialDelay=0] Initial delay before TCP keep alive enabled
+ * @param {boolean} [options.noDelay=true] TCP Connection no delay
+ * @param {number} [options.connectionTimeout=0] TCP Connection timeout setting
+ * @param {number} [options.socketTimeout=0] TCP Socket timeout setting
+ * @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
+ * @param {Buffer} [options.cert] SSL Certificate binary buffer
+ * @param {Buffer} [options.key] SSL Key file binary buffer
+ * @param {string} [options.passphrase] SSL Certificate pass phrase
+ * @param {boolean} [options.rejectUnauthorized=true] Reject unauthorized server certificates
+ * @param {boolean} [options.promoteLongs=true] Convert Long values from the db into Numbers if they fit into 53 bits
+ * @return {Server} A cursor instance
+ * @fires Server#connect
+ * @fires Server#close
+ * @fires Server#error
+ * @fires Server#timeout
+ * @fires Server#parseError
+ * @fires Server#reconnect
+ * @fires Server#reconnectFailed
+ * @fires Server#serverHeartbeatStarted
+ * @fires Server#serverHeartbeatSucceeded
+ * @fires Server#serverHeartbeatFailed
+ * @fires Server#topologyOpening
+ * @fires Server#topologyClosed
+ * @fires Server#topologyDescriptionChanged
+ */
+var Server = function(options) {
+ options = options || {};
+
+ // Add event listener
+ EventEmitter.call(this);
+
+ // Server instance id
+ this.id = id++;
+
+ // Reconnect retries
+ var reconnectTries = options.reconnectTries || 30;
+
+ // Internal state
+ this.s = {
+ // Options
+ options: options,
+ // Logger
+ logger: Logger('Server', options),
+ // Factory overrides
+ Cursor: options.cursorFactory || BasicCursor,
+ // BSON instance
+ bson: options.bson || new BSON(),
+ // Pool
+ pool: null,
+ // Disconnect handler
+ disconnectHandler: options.disconnectHandler,
+ // Monitor thread (keeps the connection alive)
+ monitoring: typeof options.monitoring == 'boolean' ? options.monitoring : true,
+ // Is the server in a topology
+ inTopology: typeof options.inTopology == 'boolean' ? options.inTopology : false,
+ // Monitoring timeout
+ monitoringInterval: typeof options.monitoringInterval == 'number'
+ ? options.monitoringInterval
+ : 5000,
+ // Topology id
+ topologyId: -1
+ }
+
+ // Curent ismaster
+ this.ismaster = null;
+ // Current ping time
+ this.lastIsMasterMS = -1;
+ // The monitoringProcessId
+ this.monitoringProcessId = null;
+ // Initial connection
+ this.initalConnect = true;
+ // Wire protocol handler, default to oldest known protocol handler
+ // this gets changed when the first ismaster is called.
+ this.wireProtocolHandler = new PreTwoSixWireProtocolSupport();
+ // Default type
+ this._type = 'server';
+}
+
+inherits(Server, EventEmitter);
+
+Object.defineProperty(Server.prototype, 'type', {
+ enumerable:true, get: function() { return this._type; }
+});
+
+Server.enableServerAccounting = function() {
+ serverAccounting = true;
+ servers = {};
+}
+
+Server.disableServerAccounting = function() {
+ serverAccounting = false;
+}
+
+Server.servers = function() {
+ return servers;
+}
+
+Object.defineProperty(Server.prototype, 'name', {
+ enumerable:true,
+ get: function() { return this.s.options.host + ":" + this.s.options.port; }
+});
+
+function configureWireProtocolHandler(self, ismaster) {
+ // 3.2 wire protocol handler
+ if(ismaster.maxWireVersion >= 4) {
+ return new ThreeTwoWireProtocolSupport(new TwoSixWireProtocolSupport());
+ }
+
+ // 2.6 wire protocol handler
+ if(ismaster.maxWireVersion >= 2) {
+ return new TwoSixWireProtocolSupport();
+ }
+
+ // 2.4 or earlier wire protocol handler
+ return new PreTwoSixWireProtocolSupport();
+}
+
+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
+ if(!self.s.pool.isConnected() && self.s.disconnectHandler != null && !options.monitoring) {
+ self.s.disconnectHandler.add(type, ns, cmd, options, callback);
+ return true;
+ }
+
+ // If we have no connection error
+ if(!self.s.pool.isConnected()) {
+ callback(MongoError.create(f("no connection available to server %s", self.name)));
+ return true;
+ }
+}
+
+function monitoringProcess(self) {
+ return function() {
+ // Pool was destroyed do not continue process
+ if(self.s.pool.isDestroyed()) return;
+ // 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.toBin(), {}, function(err, result) {
+ // Set initial lastIsMasterMS
+ self.lastIsMasterMS = new Date().getTime() - start;
+ if(self.s.pool.isDestroyed()) return;
+ // Update the ismaster view if we have a result
+ if(result) {
+ 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';
+ }
+ }
+ // Re-schedule the monitoring process
+ self.monitoringProcessId = setTimeout(monitoringProcess(self), self.s.monitoringInterval);
+ });
+ }
+}
+
+var eventHandler = function(self, event) {
+ return function(err) {
+ // Log information of received information if in info mode
+ if(self.s.logger.isInfo()) {
+ var object = err instanceof MongoError ? JSON.stringify(err) : {}
+ self.s.logger.info(f('server %s fired event %s out with message %s'
+ , self.name, event, object));
+ }
+
+ // 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 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.toBin(), {}, function(err, result) {
+ // Set initial lastIsMasterMS
+ self.lastIsMasterMS = new Date().getTime() - start;
+ if(err) {
+ self.destroy();
+ if(self.listeners('error').length > 0) self.emit('error', err);
+ return;
+ }
+
+ // Ensure no error emitted after initial connect when reconnecting
+ self.initalConnect = false;
+ // Save the ismaster
+ self.ismaster = result.result;
+ // 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: !self.s.inTopology ? 'Standalone' : sdam.getTopologyType(self)
+ });
+
+ // Emit topology description changed if something listening
+ sdam.emitTopologyDescriptionChanged(self, {
+ topologyType: 'Single', servers: [{address: self.name, arbiters: [], hosts: [], passives: [], type: 'Standalone'}]
+ });
+
+ // 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);
+ });
+ } else if(event == 'error' || event == 'parseError'
+ || event == 'close' || event == 'timeout' || event == 'reconnect'
+ || event == 'attemptReconnect' || 'reconnectFailed') {
+
+ // Remove server instance from accounting
+ if(serverAccounting && ['close', 'timeout', 'error', 'parseError', 'reconnectFailed'].indexOf(event) != -1) {
+ // Emit toplogy opening event if not in topology
+ if(!self.s.inTopology) {
+ self.emit('topologyOpening', { topologyId: self.id });
+ }
+
+ delete servers[self.id];
+ }
+
+ // Reconnect failed return error
+ if(event == 'reconnectFailed') {
+ self.emit('reconnectFailed', err);
+ // Emit error if any listeners
+ if(self.listeners('error').length > 0) {
+ self.emit('error', err);
+ }
+ // Terminate
+ return;
+ }
+
+ // On first connect fail
+ if(self.s.pool.state == 'disconnected' && self.initalConnect && ['close', 'timeout', 'error', 'parseError'].indexOf(event) != -1) {
+ self.initalConnect = false;
+ return self.emit('error', new MongoError(f('failed to connect to server [%s] on first connect', self.name)));
+ }
+
+ // Reconnect event, emit the server
+ if(event == 'reconnect') {
+ return self.emit(event, self);
+ }
+
+ // Emit the event
+ self.emit(event, err);
+ }
+ }
+}
+
+/**
+ * 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;
+ options = options || {};
+
+ // Set the connections
+ if(serverAccounting) servers[this.id] = this;
+
+ // Do not allow connect to be called on anything that's not disconnected
+ if(self.s.pool && !self.s.pool.isDisconnected() && !self.s.pool.isDestroyed()) {
+ throw MongoError.create(f('server instance in invalid state %s', self.s.state));
+ }
+
+ // Create a pool
+ self.s.pool = new Pool(assign(self.s.options, options, {bson: this.s.bson}));
+
+ // Set up listeners
+ self.s.pool.on('close', eventHandler(self, 'close'));
+ self.s.pool.on('error', eventHandler(self, 'error'));
+ self.s.pool.on('timeout', eventHandler(self, 'timeout'));
+ self.s.pool.on('parseError', eventHandler(self, 'parseError'));
+ self.s.pool.on('connect', eventHandler(self, 'connect'));
+ self.s.pool.on('reconnect', eventHandler(self, 'reconnect'));
+ self.s.pool.on('reconnectFailed', eventHandler(self, 'reconnectFailed'));
+
+ // Emit toplogy opening event if not in topology
+ if(!self.s.inTopology) {
+ this.emit('topologyOpening', { topologyId: self.id });
+ }
+
+ // Emit opening server event
+ self.emit('serverOpening', {
+ topologyId: self.s.topologyId != -1 ? self.s.topologyId : self.id,
+ 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();
+ }
+}
+
+/**
+ * Get the server description
+ * @method
+ * @return {object}
+*/
+Server.prototype.getDescription = function() {
+ var ismaster = this.ismaster || {};
+ var description = {
+ type: sdam.getTopologyType(this),
+ address: this.name,
+ };
+
+ // Add fields if available
+ if(ismaster.hosts) description.hosts = ismaster.hosts;
+ if(ismaster.arbiters) description.arbiters = ismaster.arbiters;
+ if(ismaster.passives) description.passives = ismaster.passives;
+ if(ismaster.setName) description.setName = ismaster.setName;
+ return description;
+}
+
+/**
+ * Returns the last known ismaster document for this server
+ * @method
+ * @return {object}
+ */
+Server.prototype.lastIsMaster = function() {
+ return this.ismaster;
+}
+
+/**
+ * Unref all connections belong to this server
+ * @method
+ */
+Server.prototype.unref = function() {
+ this.s.pool.unref();
+}
+
+/**
+ * Figure out if the server is connected
+ * @method
+ * @return {boolean}
+ */
+Server.prototype.isConnected = function() {
+ if(!this.s.pool) return false;
+ return this.s.pool.isConnected();
+}
+
+/**
+ * Figure out if the server instance was destroyed by calling destroy
+ * @method
+ * @return {boolean}
+ */
+Server.prototype.isDestroyed = function() {
+ if(!this.s.pool) return false;
+ return this.s.pool.isDestroyed();
+}
+
+function basicWriteValidations(self, options) {
+ if(!self.s.pool) return MongoError.create('server instance is not connected');
+ if(self.s.pool.isDestroyed()) return MongoError.create('server instance pool was destroyed');
+}
+
+function basicReadValidations(self, options) {
+ basicWriteValidations(self, options);
+
+ if(options.readPreference && !(options.readPreference instanceof ReadPreference)) {
+ throw new Error("readPreference must be an instance of ReadPreference");
+ }
+}
+
+/**
+ * Execute a command
+ * @method
+ * @param {string} ns The MongoDB fully qualified namespace (ex: db1.collection1)
+ * @param {object} cmd The command hash
+ * @param {ReadPreference} [options.readPreference] Specify read preference if command supports it
+ * @param {Boolean} [options.serializeFunctions=false] Specify if functions on an object should be serialized.
+ * @param {Boolean} [options.ignoreUndefined=false] Specify if the BSON serializer should ignore undefined fields.
+ * @param {Boolean} [options.fullResult=false] Return the full envelope instead of just the result document.
+ * @param {opResultCallback} callback A callback function
+ */
+Server.prototype.command = function(ns, cmd, options, callback) {
+ var self = this;
+ if(typeof options == 'function') callback = options, options = {}, options = options || {};
+ var result = basicReadValidations(self, options);
+ if(result) return callback(result);
+
+ // Debug log
+ if(self.s.logger.isDebug()) self.s.logger.debug(f('executing command [%s] against %s', JSON.stringify({
+ ns: ns, cmd: cmd, options: debugOptions(debugFields, options)
+ }), self.name));
+
+ // If we are not connected or have a disconnectHandler specified
+ if(disconnectHandler(self, 'command', ns, cmd, options, callback)) return;
+
+ // Query options
+ var queryOptions = {
+ numberToSkip: 0,
+ numberToReturn: -1,
+ checkKeys: typeof options.checkKeys == 'boolean' ? options.checkKeys: false,
+ serializeFunctions: typeof options.serializeFunctions == 'boolean' ? options.serializeFunctions : false,
+ ignoreUndefined: typeof options.ignoreUndefined == 'boolean' ? options.ignoreUndefined : false
+ };
+
+ // Create a query instance
+ var query = new Query(self.s.bson, ns, cmd, queryOptions);
+ // 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,
+ command: true,
+ monitoring: typeof options.monitoring == 'boolean' ? options.monitoring : false,
+ };
+
+ // Write the operation to the pool
+ self.s.pool.write(query.toBin(), writeOptions, callback);
+}
+
+/**
+ * Insert one or more documents
+ * @method
+ * @param {string} ns The MongoDB fully qualified namespace (ex: db1.collection1)
+ * @param {array} ops An array of documents to insert
+ * @param {boolean} [options.ordered=true] Execute in order or out of order
+ * @param {object} [options.writeConcern={}] Write concern for the operation
+ * @param {Boolean} [options.serializeFunctions=false] Specify if functions on an object should be serialized.
+ * @param {Boolean} [options.ignoreUndefined=false] Specify if the BSON serializer should ignore undefined fields.
+ * @param {opResultCallback} callback A callback function
+ */
+Server.prototype.insert = function(ns, ops, options, callback) {
+ var self = this;
+ if(typeof options == 'function') callback = options, options = {}, options = options || {};
+ var result = basicWriteValidations(self, options);
+ if(result) return callback(result);
+
+ // If we are not connected or have a disconnectHandler specified
+ if(disconnectHandler(self, 'insert', ns, ops, options, callback)) return;
+
+ // Setup the docs as an array
+ ops = Array.isArray(ops) ? ops : [ops];
+
+ // Execute write
+ return self.wireProtocolHandler.insert(self.s.pool, self.ismaster, ns, self.s.bson, ops, options, callback);
+}
+
+/**
+ * Perform one or more update operations
+ * @method
+ * @param {string} ns The MongoDB fully qualified namespace (ex: db1.collection1)
+ * @param {array} ops An array of updates
+ * @param {boolean} [options.ordered=true] Execute in order or out of order
+ * @param {object} [options.writeConcern={}] Write concern for the operation
+ * @param {Boolean} [options.serializeFunctions=false] Specify if functions on an object should be serialized.
+ * @param {Boolean} [options.ignoreUndefined=false] Specify if the BSON serializer should ignore undefined fields.
+ * @param {opResultCallback} callback A callback function
+ */
+Server.prototype.update = function(ns, ops, options, callback) {
+ var self = this;
+ if(typeof options == 'function') callback = options, options = {}, options = options || {};
+ var result = basicWriteValidations(self, options);
+ if(result) return callback(result);
+
+ // If we are not connected or have a disconnectHandler specified
+ if(disconnectHandler(self, 'update', ns, ops, options, callback)) return;
+
+ // Setup the docs as an array
+ ops = Array.isArray(ops) ? ops : [ops];
+ // Execute write
+ return self.wireProtocolHandler.update(self.s.pool, self.ismaster, ns, self.s.bson, ops, options, callback);
+}
+
+/**
+ * Perform one or more remove operations
+ * @method
+ * @param {string} ns The MongoDB fully qualified namespace (ex: db1.collection1)
+ * @param {array} ops An array of removes
+ * @param {boolean} [options.ordered=true] Execute in order or out of order
+ * @param {object} [options.writeConcern={}] Write concern for the operation
+ * @param {Boolean} [options.serializeFunctions=false] Specify if functions on an object should be serialized.
+ * @param {Boolean} [options.ignoreUndefined=false] Specify if the BSON serializer should ignore undefined fields.
+ * @param {opResultCallback} callback A callback function
+ */
+Server.prototype.remove = function(ns, ops, options, callback) {
+ var self = this;
+ if(typeof options == 'function') callback = options, options = {}, options = options || {};
+ var result = basicWriteValidations(self, options);
+ if(result) return callback(result);
+
+ // If we are not connected or have a disconnectHandler specified
+ if(disconnectHandler(self, 'remove', ns, ops, options, callback)) return;
+
+ // Setup the docs as an array
+ ops = Array.isArray(ops) ? ops : [ops];
+ // Execute write
+ return self.wireProtocolHandler.remove(self.s.pool, self.ismaster, ns, self.s.bson, ops, options, callback);
+}
+
+/**
+ * Get a new cursor
+ * @method
+ * @param {string} ns The MongoDB fully qualified namespace (ex: db1.collection1)
+ * @param {{object}|{Long}} cmd Can be either a command returning a cursor or a cursorId
+ * @param {object} [options.batchSize=0] Batchsize for the operation
+ * @param {array} [options.documents=[]] Initial documents list for cursor
+ * @param {ReadPreference} [options.readPreference] Specify read preference if command supports it
+ * @param {Boolean} [options.serializeFunctions=false] Specify if functions on an object should be serialized.
+ * @param {Boolean} [options.ignoreUndefined=false] Specify if the BSON serializer should ignore undefined fields.
+ * @param {opResultCallback} callback A callback function
+ */
+Server.prototype.cursor = function(ns, cmd, cursorOptions) {
+ var s = this.s;
+ cursorOptions = cursorOptions || {};
+ // Set up final cursor type
+ var FinalCursor = cursorOptions.cursorFactory || s.Cursor;
+ // Return the cursor
+ return new FinalCursor(s.bson, ns, cmd, cursorOptions, 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 we have the default mechanism we pick mechanism based on the wire
+ // protocol max version. If it's >= 3 then scram-sha1 otherwise mongodb-cr
+ if(mechanism == 'default' && self.ismaster && self.ismaster.maxWireVersion >= 3) {
+ mechanism = 'scram-sha-1';
+ } else if(mechanism == 'default') {
+ mechanism = 'mongocr';
+ }
+
+ // 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
+ //function disconnectHandler(self, type, ns, cmd, options, callback) {
+ 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
+ * @param {Server} server Server to compare equality against
+ * @return {boolean}
+ */
+Server.prototype.equals = function(server) {
+ if(typeof server == 'string') return this.name == server;
+ if(server.name) return this.name == server.name;
+ return false;
+}
+
+/**
+ * All raw connections
+ * @method
+ * @return {Connection[]}
+ */
+Server.prototype.connections = function() {
+ return this.s.pool.allConnections();
+}
+
+/**
+ * Get server
+ * @method
+ * @return {Server}
+ */
+Server.prototype.getServer = function() {
+ return this;
+}
+
+/**
+ * Get connection
+ * @method
+ * @return {Connection}
+ */
+Server.prototype.getConnection = function() {
+ return this.s.pool.get();
+}
+
+var listeners = ['close', 'error', 'timeout', 'parseError', 'connect'];
+
+/**
+ * Destroy the server connection
+ * @method
+ * @param {boolean} [options.emitClose=false] Emit close event on destroy
+ * @param {boolean} [options.emitDestroy=false] Emit destroy event on destroy
+ */
+Server.prototype.destroy = function(options) {
+ options = options || {};
+ var self = this;
+
+ // Set the connections
+ if(serverAccounting) delete servers[this.id];
+
+ // Destroy the monitoring process if any
+ if(this.monitoringProcessId) {
+ clearTimeout(this.monitoringProcessId);
+ }
+
+ // Emit close event
+ if(options.emitClose) {
+ self.emit('close', self);
+ }
+
+ // Emit destroy event
+ if(options.emitDestroy) {
+ self.emit('destroy', self);
+ }
+
+ // Remove all listeners
+ listeners.forEach(function(event) {
+ self.s.pool.removeAllListeners(event);
+ });
+
+ // Emit opening server event
+ if(self.listeners('serverClosed').length > 0) self.emit('serverClosed', {
+ topologyId: self.s.topologyId != -1 ? self.s.topologyId : self.id, address: self.name
+ });
+
+ // Emit toplogy opening event if not in topology
+ if(self.listeners('topologyClosed').length > 0 && !self.s.inTopology) {
+ self.emit('topologyClosed', { topologyId: self.id });
+ }
+
+ if(self.s.logger.isDebug()) {
+ self.s.logger.debug(f('destroy called on server %s', self.name));
+ }
+
+ // Destroy the pool
+ this.s.pool.destroy();
+}
+
+/**
+ * A server connect event, used to verify that the connection is up and running
+ *
+ * @event Server#connect
+ * @type {Server}
+ */
+
+/**
+ * A server reconnect event, used to verify that the server topology has reconnected
+ *
+ * @event Server#reconnect
+ * @type {Server}
+ */
+
+/**
+ * A server opening SDAM monitoring event
+ *
+ * @event Server#serverOpening
+ * @type {object}
+ */
+
+/**
+ * A server closed SDAM monitoring event
+ *
+ * @event Server#serverClosed
+ * @type {object}
+ */
+
+/**
+ * A server description SDAM change monitoring event
+ *
+ * @event Server#serverDescriptionChanged
+ * @type {object}
+ */
+
+/**
+ * A topology open SDAM event
+ *
+ * @event Server#topologyOpening
+ * @type {object}
+ */
+
+/**
+ * A topology closed SDAM event
+ *
+ * @event Server#topologyClosed
+ * @type {object}
+ */
+
+/**
+ * A topology structure SDAM change event
+ *
+ * @event Server#topologyDescriptionChanged
+ * @type {object}
+ */
+
+/**
+ * Server reconnect failed
+ *
+ * @event Server#reconnectFailed
+ * @type {Error}
+ */
+
+/**
+ * Server connection pool closed
+ *
+ * @event Server#close
+ * @type {object}
+ */
+
+/**
+ * Server connection pool caused an error
+ *
+ * @event Server#error
+ * @type {Error}
+ */
+
+/**
+ * Server destroyed was called
+ *
+ * @event Server#destroy
+ * @type {Server}
+ */
+
+module.exports = Server;