123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294 |
- 'use strict';
- const os = require('os');
- const crypto = require('crypto');
- const requireOptional = require('optional-require')(require);
- /**
- * Generate a UUIDv4
- */
- const uuidV4 = () => {
- const result = crypto.randomBytes(16);
- result[6] = (result[6] & 0x0f) | 0x40;
- result[8] = (result[8] & 0x3f) | 0x80;
- return result;
- };
- /**
- * Relays events for a given listener and emitter
- *
- * @param {EventEmitter} listener the EventEmitter to listen to the events from
- * @param {EventEmitter} emitter the EventEmitter to relay the events to
- */
- function relayEvents(listener, emitter, events) {
- events.forEach(eventName => listener.on(eventName, event => emitter.emit(eventName, event)));
- }
- function retrieveKerberos() {
- let kerberos;
- try {
- kerberos = requireOptional('kerberos');
- } catch (err) {
- if (err.code === 'MODULE_NOT_FOUND') {
- throw new Error('The `kerberos` module was not found. Please install it and try again.');
- }
- throw err;
- }
- return kerberos;
- }
- // Throw an error if an attempt to use EJSON is made when it is not installed
- const noEJSONError = function() {
- throw new Error('The `mongodb-extjson` module was not found. Please install it and try again.');
- };
- // Facilitate loading EJSON optionally
- function retrieveEJSON() {
- let EJSON = requireOptional('mongodb-extjson');
- if (!EJSON) {
- EJSON = {
- parse: noEJSONError,
- deserialize: noEJSONError,
- serialize: noEJSONError,
- stringify: noEJSONError,
- setBSONModule: noEJSONError,
- BSON: noEJSONError
- };
- }
- return EJSON;
- }
- /**
- * A helper function for determining `maxWireVersion` between legacy and new topology
- * instances
- *
- * @private
- * @param {(Topology|Server)} topologyOrServer
- */
- function maxWireVersion(topologyOrServer) {
- if (topologyOrServer) {
- if (topologyOrServer.ismaster) {
- return topologyOrServer.ismaster.maxWireVersion;
- }
- if (typeof topologyOrServer.lastIsMaster === 'function') {
- const lastIsMaster = topologyOrServer.lastIsMaster();
- if (lastIsMaster) {
- return lastIsMaster.maxWireVersion;
- }
- }
- if (topologyOrServer.description) {
- return topologyOrServer.description.maxWireVersion;
- }
- }
- return 0;
- }
- /*
- * Checks that collation is supported by server.
- *
- * @param {Server} [server] to check against
- * @param {object} [cmd] object where collation may be specified
- * @param {function} [callback] callback function
- * @return true if server does not support collation
- */
- function collationNotSupported(server, cmd) {
- return cmd && cmd.collation && maxWireVersion(server) < 5;
- }
- /**
- * Checks if a given value is a Promise
- *
- * @param {*} maybePromise
- * @return true if the provided value is a Promise
- */
- function isPromiseLike(maybePromise) {
- return maybePromise && typeof maybePromise.then === 'function';
- }
- /**
- * Applies the function `eachFn` to each item in `arr`, in parallel.
- *
- * @param {array} arr an array of items to asynchronusly iterate over
- * @param {function} eachFn A function to call on each item of the array. The callback signature is `(item, callback)`, where the callback indicates iteration is complete.
- * @param {function} callback The callback called after every item has been iterated
- */
- function eachAsync(arr, eachFn, callback) {
- arr = arr || [];
- let idx = 0;
- let awaiting = 0;
- for (idx = 0; idx < arr.length; ++idx) {
- awaiting++;
- eachFn(arr[idx], eachCallback);
- }
- if (awaiting === 0) {
- callback();
- return;
- }
- function eachCallback(err) {
- awaiting--;
- if (err) {
- callback(err);
- return;
- }
- if (idx === arr.length && awaiting <= 0) {
- callback();
- }
- }
- }
- function eachAsyncSeries(arr, eachFn, callback) {
- arr = arr || [];
- let idx = 0;
- let awaiting = arr.length;
- if (awaiting === 0) {
- callback();
- return;
- }
- function eachCallback(err) {
- idx++;
- awaiting--;
- if (err) {
- callback(err);
- return;
- }
- if (idx === arr.length && awaiting <= 0) {
- callback();
- return;
- }
- eachFn(arr[idx], eachCallback);
- }
- eachFn(arr[idx], eachCallback);
- }
- function isUnifiedTopology(topology) {
- return topology.description != null;
- }
- function arrayStrictEqual(arr, arr2) {
- if (!Array.isArray(arr) || !Array.isArray(arr2)) {
- return false;
- }
- return arr.length === arr2.length && arr.every((elt, idx) => elt === arr2[idx]);
- }
- function tagsStrictEqual(tags, tags2) {
- const tagsKeys = Object.keys(tags);
- const tags2Keys = Object.keys(tags2);
- return tagsKeys.length === tags2Keys.length && tagsKeys.every(key => tags2[key] === tags[key]);
- }
- function errorStrictEqual(lhs, rhs) {
- if (lhs === rhs) {
- return true;
- }
- if ((lhs == null && rhs != null) || (lhs != null && rhs == null)) {
- return false;
- }
- if (lhs.constructor.name !== rhs.constructor.name) {
- return false;
- }
- if (lhs.message !== rhs.message) {
- return false;
- }
- return true;
- }
- function makeStateMachine(stateTable) {
- return function stateTransition(target, newState) {
- const legalStates = stateTable[target.s.state];
- if (legalStates && legalStates.indexOf(newState) < 0) {
- throw new TypeError(
- `illegal state transition from [${target.s.state}] => [${newState}], allowed: [${legalStates}]`
- );
- }
- target.emit('stateChanged', target.s.state, newState);
- target.s.state = newState;
- };
- }
- function makeClientMetadata(options) {
- options = options || {};
- const metadata = {
- driver: {
- name: 'nodejs',
- version: require('../../package.json').version
- },
- os: {
- type: os.type(),
- name: process.platform,
- architecture: process.arch,
- version: os.release()
- },
- platform: `'Node.js ${process.version}, ${os.endianness} (${
- options.useUnifiedTopology ? 'unified' : 'legacy'
- })`
- };
- // support optionally provided wrapping driver info
- if (options.driverInfo) {
- if (options.driverInfo.name) {
- metadata.driver.name = `${metadata.driver.name}|${options.driverInfo.name}`;
- }
- if (options.driverInfo.version) {
- metadata.version = `${metadata.driver.version}|${options.driverInfo.version}`;
- }
- if (options.driverInfo.platform) {
- metadata.platform = `${metadata.platform}|${options.driverInfo.platform}`;
- }
- }
- if (options.appname) {
- // MongoDB requires the appname not exceed a byte length of 128
- const buffer = Buffer.from(options.appname);
- metadata.application = {
- name: buffer.length > 128 ? buffer.slice(0, 128).toString('utf8') : options.appname
- };
- }
- return metadata;
- }
- const noop = () => {};
- module.exports = {
- uuidV4,
- relayEvents,
- collationNotSupported,
- retrieveEJSON,
- retrieveKerberos,
- maxWireVersion,
- isPromiseLike,
- eachAsync,
- eachAsyncSeries,
- isUnifiedTopology,
- arrayStrictEqual,
- tagsStrictEqual,
- errorStrictEqual,
- makeStateMachine,
- makeClientMetadata,
- noop
- };
|