Update Node_modules
This commit is contained in:
+10
-3
@@ -1,4 +1,5 @@
|
||||
'use strict';
|
||||
const Msg = require('../connection/msg').Msg;
|
||||
const KillCursor = require('../connection/commands').KillCursor;
|
||||
const GetMore = require('../connection/commands').GetMore;
|
||||
const calculateDurationInMs = require('../utils').calculateDurationInMs;
|
||||
@@ -17,7 +18,7 @@ const SENSITIVE_COMMANDS = new Set([
|
||||
]);
|
||||
|
||||
// helper methods
|
||||
const extractCommandName = command => Object.keys(command)[0];
|
||||
const extractCommandName = commandDoc => Object.keys(commandDoc)[0];
|
||||
const namespace = command => command.ns;
|
||||
const databaseName = command => command.ns.split('.')[0];
|
||||
const collectionName = command => command.ns.split('.')[1];
|
||||
@@ -75,6 +76,10 @@ const extractCommand = command => {
|
||||
};
|
||||
}
|
||||
|
||||
if (command instanceof Msg) {
|
||||
return command.command;
|
||||
}
|
||||
|
||||
if (command.query && command.query.$query) {
|
||||
let result;
|
||||
if (command.ns === 'admin.$cmd') {
|
||||
@@ -90,8 +95,7 @@ const extractCommand = command => {
|
||||
}
|
||||
|
||||
Object.keys(LEGACY_FIND_OPTIONS_MAP).forEach(key => {
|
||||
if (typeof command.options[key] !== 'undefined')
|
||||
result[LEGACY_FIND_OPTIONS_MAP[key]] = command.options[key];
|
||||
if (typeof command[key] !== 'undefined') result[LEGACY_FIND_OPTIONS_MAP[key]] = command[key];
|
||||
});
|
||||
|
||||
OP_QUERY_KEYS.forEach(key => {
|
||||
@@ -143,6 +147,9 @@ const extractReply = (command, reply) => {
|
||||
};
|
||||
}
|
||||
|
||||
// in the event of a `noResponse` command, just return
|
||||
if (reply === null) return reply;
|
||||
|
||||
return reply.result;
|
||||
};
|
||||
|
||||
|
||||
+3
-1
@@ -19,7 +19,9 @@ var CommandResult = function(result, connection, message) {
|
||||
* @return {object}
|
||||
*/
|
||||
CommandResult.prototype.toJSON = function() {
|
||||
return this.result;
|
||||
let result = Object.assign({}, this, this.result);
|
||||
delete result.message;
|
||||
return result;
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
+10
-52
@@ -3,7 +3,6 @@
|
||||
var retrieveBSON = require('./utils').retrieveBSON;
|
||||
var BSON = retrieveBSON();
|
||||
var Long = BSON.Long;
|
||||
const MongoError = require('../error').MongoError;
|
||||
const Buffer = require('safe-buffer').Buffer;
|
||||
|
||||
// Incrementing request id
|
||||
@@ -22,7 +21,7 @@ var OPTS_EXHAUST = 64;
|
||||
var OPTS_PARTIAL = 128;
|
||||
|
||||
// Response flags
|
||||
var CURSOR_NOT_FOUND = 0;
|
||||
var CURSOR_NOT_FOUND = 1;
|
||||
var QUERY_FAILURE = 2;
|
||||
var SHARD_CONFIG_STALE = 4;
|
||||
var AWAIT_CAPABLE = 8;
|
||||
@@ -46,9 +45,6 @@ var Query = function(bson, ns, query, options) {
|
||||
this.ns = ns;
|
||||
this.query = query;
|
||||
|
||||
// Ensure empty options
|
||||
this.options = options || {};
|
||||
|
||||
// Additional options
|
||||
this.numberToSkip = options.numberToSkip || 0;
|
||||
this.numberToReturn = options.numberToReturn || 0;
|
||||
@@ -466,53 +462,6 @@ Response.prototype.parse = function(options) {
|
||||
// (See https://docs.mongodb.com/manual/reference/mongodb-wire-protocol/#wire-op-reply)
|
||||
this.index = 20;
|
||||
|
||||
//
|
||||
// Single document and documentsReturnedIn set
|
||||
//
|
||||
if (this.numberReturned === 1 && documentsReturnedIn != null && raw) {
|
||||
// Calculate the bson size
|
||||
bsonSize =
|
||||
this.data[this.index] |
|
||||
(this.data[this.index + 1] << 8) |
|
||||
(this.data[this.index + 2] << 16) |
|
||||
(this.data[this.index + 3] << 24);
|
||||
// Slice out the buffer containing the command result document
|
||||
var document = this.data.slice(this.index, this.index + bsonSize);
|
||||
// Set up field we wish to keep as raw
|
||||
var fieldsAsRaw = {};
|
||||
fieldsAsRaw[documentsReturnedIn] = true;
|
||||
_options.fieldsAsRaw = fieldsAsRaw;
|
||||
|
||||
// Deserialize but keep the array of documents in non-parsed form
|
||||
var doc = this.bson.deserialize(document, _options);
|
||||
|
||||
if (doc instanceof Error) {
|
||||
throw doc;
|
||||
}
|
||||
|
||||
if (doc.errmsg) {
|
||||
throw new MongoError(doc.errmsg);
|
||||
}
|
||||
|
||||
if (!doc.cursor) {
|
||||
throw new MongoError('Cursor not found');
|
||||
}
|
||||
|
||||
// Get the documents
|
||||
this.documents = doc.cursor[documentsReturnedIn];
|
||||
this.numberReturned = this.documents.length;
|
||||
// Ensure we have a Long valie cursor id
|
||||
this.cursorId =
|
||||
typeof doc.cursor.id === 'number' ? Long.fromNumber(doc.cursor.id) : doc.cursor.id;
|
||||
|
||||
// Adjust the index
|
||||
this.index = this.index + bsonSize;
|
||||
|
||||
// Set as parsed
|
||||
this.parsed = true;
|
||||
return;
|
||||
}
|
||||
|
||||
//
|
||||
// Parse Body
|
||||
//
|
||||
@@ -537,6 +486,15 @@ Response.prototype.parse = function(options) {
|
||||
this.index = this.index + bsonSize;
|
||||
}
|
||||
|
||||
if (this.documents.length === 1 && documentsReturnedIn != null && raw) {
|
||||
const fieldsAsRaw = {};
|
||||
fieldsAsRaw[documentsReturnedIn] = true;
|
||||
_options.fieldsAsRaw = fieldsAsRaw;
|
||||
|
||||
const doc = this.bson.deserialize(this.documents[0], _options);
|
||||
this.documents = [doc];
|
||||
}
|
||||
|
||||
// Set parsed
|
||||
this.parsed = true;
|
||||
};
|
||||
|
||||
+370
@@ -0,0 +1,370 @@
|
||||
'use strict';
|
||||
const net = require('net');
|
||||
const tls = require('tls');
|
||||
const Connection = require('./connection');
|
||||
const Query = require('./commands').Query;
|
||||
const createClientInfo = require('../topologies/shared').createClientInfo;
|
||||
const MongoError = require('../error').MongoError;
|
||||
const MongoNetworkError = require('../error').MongoNetworkError;
|
||||
const defaultAuthProviders = require('../auth/defaultAuthProviders').defaultAuthProviders;
|
||||
const WIRE_CONSTANTS = require('../wireprotocol/constants');
|
||||
const MAX_SUPPORTED_WIRE_VERSION = WIRE_CONSTANTS.MAX_SUPPORTED_WIRE_VERSION;
|
||||
const MAX_SUPPORTED_SERVER_VERSION = WIRE_CONSTANTS.MAX_SUPPORTED_SERVER_VERSION;
|
||||
const MIN_SUPPORTED_WIRE_VERSION = WIRE_CONSTANTS.MIN_SUPPORTED_WIRE_VERSION;
|
||||
const MIN_SUPPORTED_SERVER_VERSION = WIRE_CONSTANTS.MIN_SUPPORTED_SERVER_VERSION;
|
||||
let AUTH_PROVIDERS;
|
||||
|
||||
function connect(options, callback) {
|
||||
if (AUTH_PROVIDERS == null) {
|
||||
AUTH_PROVIDERS = defaultAuthProviders(options.bson);
|
||||
}
|
||||
|
||||
if (options.family !== void 0) {
|
||||
makeConnection(options.family, options, (err, socket) => {
|
||||
if (err) {
|
||||
callback(err, socket); // in the error case, `socket` is the originating error event name
|
||||
return;
|
||||
}
|
||||
|
||||
performInitialHandshake(new Connection(socket, options), options, callback);
|
||||
});
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
return makeConnection(6, options, (err, ipv6Socket) => {
|
||||
if (err) {
|
||||
makeConnection(4, options, (err, ipv4Socket) => {
|
||||
if (err) {
|
||||
callback(err, ipv4Socket); // in the error case, `ipv4Socket` is the originating error event name
|
||||
return;
|
||||
}
|
||||
|
||||
performInitialHandshake(new Connection(ipv4Socket, options), options, callback);
|
||||
});
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
performInitialHandshake(new Connection(ipv6Socket, options), options, callback);
|
||||
});
|
||||
}
|
||||
|
||||
function getSaslSupportedMechs(options) {
|
||||
if (!(options && options.credentials)) {
|
||||
return {};
|
||||
}
|
||||
|
||||
const credentials = options.credentials;
|
||||
|
||||
// TODO: revisit whether or not items like `options.user` and `options.dbName` should be checked here
|
||||
const authMechanism = credentials.mechanism;
|
||||
const authSource = credentials.source || options.dbName || 'admin';
|
||||
const user = credentials.username || options.user;
|
||||
|
||||
if (typeof authMechanism === 'string' && authMechanism.toUpperCase() !== 'DEFAULT') {
|
||||
return {};
|
||||
}
|
||||
|
||||
if (!user) {
|
||||
return {};
|
||||
}
|
||||
|
||||
return { saslSupportedMechs: `${authSource}.${user}` };
|
||||
}
|
||||
|
||||
function checkSupportedServer(ismaster, options) {
|
||||
const serverVersionHighEnough =
|
||||
ismaster &&
|
||||
typeof ismaster.maxWireVersion === 'number' &&
|
||||
ismaster.maxWireVersion >= MIN_SUPPORTED_WIRE_VERSION;
|
||||
const serverVersionLowEnough =
|
||||
ismaster &&
|
||||
typeof ismaster.minWireVersion === 'number' &&
|
||||
ismaster.minWireVersion <= MAX_SUPPORTED_WIRE_VERSION;
|
||||
|
||||
if (serverVersionHighEnough) {
|
||||
if (serverVersionLowEnough) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const message = `Server at ${options.host}:${options.port} reports minimum wire version ${
|
||||
ismaster.minWireVersion
|
||||
}, but this version of the Node.js Driver requires at most ${MAX_SUPPORTED_WIRE_VERSION} (MongoDB ${MAX_SUPPORTED_SERVER_VERSION})`;
|
||||
return new MongoError(message);
|
||||
}
|
||||
|
||||
const message = `Server at ${options.host}:${
|
||||
options.port
|
||||
} reports maximum wire version ${ismaster.maxWireVersion ||
|
||||
0}, but this version of the Node.js Driver requires at least ${MIN_SUPPORTED_WIRE_VERSION} (MongoDB ${MIN_SUPPORTED_SERVER_VERSION})`;
|
||||
return new MongoError(message);
|
||||
}
|
||||
|
||||
function performInitialHandshake(conn, options, _callback) {
|
||||
const callback = function(err, ret) {
|
||||
if (err && conn) {
|
||||
conn.destroy();
|
||||
}
|
||||
_callback(err, ret);
|
||||
};
|
||||
|
||||
let compressors = [];
|
||||
if (options.compression && options.compression.compressors) {
|
||||
compressors = options.compression.compressors;
|
||||
}
|
||||
|
||||
const handshakeDoc = Object.assign(
|
||||
{
|
||||
ismaster: true,
|
||||
client: createClientInfo(options),
|
||||
compression: compressors
|
||||
},
|
||||
getSaslSupportedMechs(options)
|
||||
);
|
||||
|
||||
const start = new Date().getTime();
|
||||
runCommand(conn, 'admin.$cmd', handshakeDoc, options, (err, ismaster) => {
|
||||
if (err) {
|
||||
callback(err, null);
|
||||
return;
|
||||
}
|
||||
|
||||
if (ismaster.ok === 0) {
|
||||
callback(new MongoError(ismaster), null);
|
||||
return;
|
||||
}
|
||||
|
||||
const supportedServerErr = checkSupportedServer(ismaster, options);
|
||||
if (supportedServerErr) {
|
||||
callback(supportedServerErr, null);
|
||||
return;
|
||||
}
|
||||
|
||||
// resolve compression
|
||||
if (ismaster.compression) {
|
||||
const agreedCompressors = compressors.filter(
|
||||
compressor => ismaster.compression.indexOf(compressor) !== -1
|
||||
);
|
||||
|
||||
if (agreedCompressors.length) {
|
||||
conn.agreedCompressor = agreedCompressors[0];
|
||||
}
|
||||
|
||||
if (options.compression && options.compression.zlibCompressionLevel) {
|
||||
conn.zlibCompressionLevel = options.compression.zlibCompressionLevel;
|
||||
}
|
||||
}
|
||||
|
||||
// NOTE: This is metadata attached to the connection while porting away from
|
||||
// handshake being done in the `Server` class. Likely, it should be
|
||||
// relocated, or at very least restructured.
|
||||
conn.ismaster = ismaster;
|
||||
conn.lastIsMasterMS = new Date().getTime() - start;
|
||||
|
||||
const credentials = options.credentials;
|
||||
if (!ismaster.arbiterOnly && credentials) {
|
||||
credentials.resolveAuthMechanism(ismaster);
|
||||
authenticate(conn, credentials, callback);
|
||||
return;
|
||||
}
|
||||
|
||||
callback(null, conn);
|
||||
});
|
||||
}
|
||||
|
||||
const LEGAL_SSL_SOCKET_OPTIONS = [
|
||||
'pfx',
|
||||
'key',
|
||||
'passphrase',
|
||||
'cert',
|
||||
'ca',
|
||||
'ciphers',
|
||||
'NPNProtocols',
|
||||
'ALPNProtocols',
|
||||
'servername',
|
||||
'ecdhCurve',
|
||||
'secureProtocol',
|
||||
'secureContext',
|
||||
'session',
|
||||
'minDHSize',
|
||||
'crl',
|
||||
'rejectUnauthorized'
|
||||
];
|
||||
|
||||
function parseConnectOptions(family, options) {
|
||||
const host = typeof options.host === 'string' ? options.host : 'localhost';
|
||||
if (host.indexOf('/') !== -1) {
|
||||
return { path: host };
|
||||
}
|
||||
|
||||
const result = {
|
||||
family,
|
||||
host,
|
||||
port: typeof options.port === 'number' ? options.port : 27017,
|
||||
rejectUnauthorized: false
|
||||
};
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
function parseSslOptions(family, options) {
|
||||
const result = parseConnectOptions(family, options);
|
||||
|
||||
// Merge in valid SSL options
|
||||
for (const name in options) {
|
||||
if (options[name] != null && LEGAL_SSL_SOCKET_OPTIONS.indexOf(name) !== -1) {
|
||||
result[name] = options[name];
|
||||
}
|
||||
}
|
||||
|
||||
// Override checkServerIdentity behavior
|
||||
if (options.checkServerIdentity === false) {
|
||||
// Skip the identiy check by retuning undefined as per node documents
|
||||
// https://nodejs.org/api/tls.html#tls_tls_connect_options_callback
|
||||
result.checkServerIdentity = function() {
|
||||
return undefined;
|
||||
};
|
||||
} else if (typeof options.checkServerIdentity === 'function') {
|
||||
result.checkServerIdentity = options.checkServerIdentity;
|
||||
}
|
||||
|
||||
// Set default sni servername to be the same as host
|
||||
if (result.servername == null) {
|
||||
result.servername = result.host;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
function makeConnection(family, options, _callback) {
|
||||
const useSsl = typeof options.ssl === 'boolean' ? options.ssl : false;
|
||||
const keepAlive = typeof options.keepAlive === 'boolean' ? options.keepAlive : true;
|
||||
let keepAliveInitialDelay =
|
||||
typeof options.keepAliveInitialDelay === 'number' ? options.keepAliveInitialDelay : 300000;
|
||||
const noDelay = typeof options.noDelay === 'boolean' ? options.noDelay : true;
|
||||
const connectionTimeout =
|
||||
typeof options.connectionTimeout === 'number' ? options.connectionTimeout : 30000;
|
||||
const socketTimeout = typeof options.socketTimeout === 'number' ? options.socketTimeout : 360000;
|
||||
const rejectUnauthorized =
|
||||
typeof options.rejectUnauthorized === 'boolean' ? options.rejectUnauthorized : true;
|
||||
|
||||
if (keepAliveInitialDelay > socketTimeout) {
|
||||
keepAliveInitialDelay = Math.round(socketTimeout / 2);
|
||||
}
|
||||
|
||||
let socket;
|
||||
const callback = function(err, ret) {
|
||||
if (err && socket) {
|
||||
socket.destroy();
|
||||
}
|
||||
_callback(err, ret);
|
||||
};
|
||||
|
||||
try {
|
||||
if (useSsl) {
|
||||
socket = tls.connect(parseSslOptions(family, options));
|
||||
if (typeof socket.disableRenegotiation === 'function') {
|
||||
socket.disableRenegotiation();
|
||||
}
|
||||
} else {
|
||||
socket = net.createConnection(parseConnectOptions(family, options));
|
||||
}
|
||||
} catch (err) {
|
||||
return callback(err);
|
||||
}
|
||||
|
||||
socket.setKeepAlive(keepAlive, keepAliveInitialDelay);
|
||||
socket.setTimeout(connectionTimeout);
|
||||
socket.setNoDelay(noDelay);
|
||||
|
||||
const errorEvents = ['error', 'close', 'timeout', 'parseError', 'connect'];
|
||||
function errorHandler(eventName) {
|
||||
return err => {
|
||||
errorEvents.forEach(event => socket.removeAllListeners(event));
|
||||
socket.removeListener('connect', connectHandler);
|
||||
callback(connectionFailureError(eventName, err), eventName);
|
||||
};
|
||||
}
|
||||
|
||||
function connectHandler() {
|
||||
errorEvents.forEach(event => socket.removeAllListeners(event));
|
||||
if (socket.authorizationError && rejectUnauthorized) {
|
||||
return callback(socket.authorizationError);
|
||||
}
|
||||
|
||||
socket.setTimeout(socketTimeout);
|
||||
callback(null, socket);
|
||||
}
|
||||
|
||||
socket.once('error', errorHandler('error'));
|
||||
socket.once('close', errorHandler('close'));
|
||||
socket.once('timeout', errorHandler('timeout'));
|
||||
socket.once('parseError', errorHandler('parseError'));
|
||||
socket.once('connect', connectHandler);
|
||||
}
|
||||
|
||||
const CONNECTION_ERROR_EVENTS = ['error', 'close', 'timeout', 'parseError'];
|
||||
function runCommand(conn, ns, command, options, callback) {
|
||||
if (typeof options === 'function') (callback = options), (options = {});
|
||||
const socketTimeout = typeof options.socketTimeout === 'number' ? options.socketTimeout : 360000;
|
||||
const bson = conn.options.bson;
|
||||
const query = new Query(bson, ns, command, {
|
||||
numberToSkip: 0,
|
||||
numberToReturn: 1
|
||||
});
|
||||
|
||||
function errorHandler(err) {
|
||||
conn.resetSocketTimeout();
|
||||
CONNECTION_ERROR_EVENTS.forEach(eventName => conn.removeListener(eventName, errorHandler));
|
||||
conn.removeListener('message', messageHandler);
|
||||
callback(err, null);
|
||||
}
|
||||
|
||||
function messageHandler(msg) {
|
||||
if (msg.responseTo !== query.requestId) {
|
||||
return;
|
||||
}
|
||||
|
||||
conn.resetSocketTimeout();
|
||||
CONNECTION_ERROR_EVENTS.forEach(eventName => conn.removeListener(eventName, errorHandler));
|
||||
conn.removeListener('message', messageHandler);
|
||||
|
||||
msg.parse({ promoteValues: true });
|
||||
callback(null, msg.documents[0]);
|
||||
}
|
||||
|
||||
conn.setSocketTimeout(socketTimeout);
|
||||
CONNECTION_ERROR_EVENTS.forEach(eventName => conn.once(eventName, errorHandler));
|
||||
conn.on('message', messageHandler);
|
||||
conn.write(query.toBin());
|
||||
}
|
||||
|
||||
function authenticate(conn, credentials, callback) {
|
||||
const mechanism = credentials.mechanism;
|
||||
if (!AUTH_PROVIDERS[mechanism]) {
|
||||
callback(new MongoError(`authMechanism '${mechanism}' not supported`));
|
||||
return;
|
||||
}
|
||||
|
||||
const provider = AUTH_PROVIDERS[mechanism];
|
||||
provider.auth(runCommand, [conn], credentials, err => {
|
||||
if (err) return callback(err);
|
||||
callback(null, conn);
|
||||
});
|
||||
}
|
||||
|
||||
function connectionFailureError(type, err) {
|
||||
switch (type) {
|
||||
case 'error':
|
||||
return new MongoNetworkError(err);
|
||||
case 'timeout':
|
||||
return new MongoNetworkError(`connection timed out`);
|
||||
case 'close':
|
||||
return new MongoNetworkError(`connection closed`);
|
||||
default:
|
||||
return new MongoNetworkError(`unknown network error`);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = connect;
|
||||
+406
-587
File diff suppressed because it is too large
Load Diff
+219
@@ -0,0 +1,219 @@
|
||||
'use strict';
|
||||
|
||||
// Implementation of OP_MSG spec:
|
||||
// https://github.com/mongodb/specifications/blob/master/source/message/OP_MSG.rst
|
||||
//
|
||||
// struct Section {
|
||||
// uint8 payloadType;
|
||||
// union payload {
|
||||
// document document; // payloadType == 0
|
||||
// struct sequence { // payloadType == 1
|
||||
// int32 size;
|
||||
// cstring identifier;
|
||||
// document* documents;
|
||||
// };
|
||||
// };
|
||||
// };
|
||||
|
||||
// struct OP_MSG {
|
||||
// struct MsgHeader {
|
||||
// int32 messageLength;
|
||||
// int32 requestID;
|
||||
// int32 responseTo;
|
||||
// int32 opCode = 2013;
|
||||
// };
|
||||
// uint32 flagBits;
|
||||
// Section+ sections;
|
||||
// [uint32 checksum;]
|
||||
// };
|
||||
|
||||
const opcodes = require('../wireprotocol/shared').opcodes;
|
||||
const databaseNamespace = require('../wireprotocol/shared').databaseNamespace;
|
||||
const ReadPreference = require('../topologies/read_preference');
|
||||
|
||||
// Incrementing request id
|
||||
let _requestId = 0;
|
||||
|
||||
// Msg Flags
|
||||
const OPTS_CHECKSUM_PRESENT = 1;
|
||||
const OPTS_MORE_TO_COME = 2;
|
||||
const OPTS_EXHAUST_ALLOWED = 1 << 16;
|
||||
|
||||
class Msg {
|
||||
constructor(bson, ns, command, options) {
|
||||
// Basic options needed to be passed in
|
||||
if (command == null) throw new Error('query must be specified for query');
|
||||
|
||||
// Basic options
|
||||
this.bson = bson;
|
||||
this.ns = ns;
|
||||
this.command = command;
|
||||
this.command.$db = databaseNamespace(ns);
|
||||
|
||||
if (options.readPreference && options.readPreference.mode !== ReadPreference.PRIMARY) {
|
||||
this.command.$readPreference = options.readPreference.toJSON();
|
||||
}
|
||||
|
||||
// Ensure empty options
|
||||
this.options = options || {};
|
||||
|
||||
// Additional options
|
||||
this.requestId = Msg.getRequestId();
|
||||
|
||||
// Serialization option
|
||||
this.serializeFunctions =
|
||||
typeof options.serializeFunctions === 'boolean' ? options.serializeFunctions : false;
|
||||
this.ignoreUndefined =
|
||||
typeof options.ignoreUndefined === 'boolean' ? options.ignoreUndefined : false;
|
||||
this.checkKeys = typeof options.checkKeys === 'boolean' ? options.checkKeys : false;
|
||||
this.maxBsonSize = options.maxBsonSize || 1024 * 1024 * 16;
|
||||
|
||||
// flags
|
||||
this.checksumPresent = false;
|
||||
this.moreToCome = options.moreToCome || false;
|
||||
this.exhaustAllowed = false;
|
||||
}
|
||||
|
||||
toBin() {
|
||||
const buffers = [];
|
||||
let flags = 0;
|
||||
|
||||
if (this.checksumPresent) {
|
||||
flags |= OPTS_CHECKSUM_PRESENT;
|
||||
}
|
||||
|
||||
if (this.moreToCome) {
|
||||
flags |= OPTS_MORE_TO_COME;
|
||||
}
|
||||
|
||||
if (this.exhaustAllowed) {
|
||||
flags |= OPTS_EXHAUST_ALLOWED;
|
||||
}
|
||||
|
||||
const header = new Buffer(
|
||||
4 * 4 + // Header
|
||||
4 // Flags
|
||||
);
|
||||
|
||||
buffers.push(header);
|
||||
|
||||
let totalLength = header.length;
|
||||
const command = this.command;
|
||||
totalLength += this.makeDocumentSegment(buffers, command);
|
||||
|
||||
header.writeInt32LE(totalLength, 0); // messageLength
|
||||
header.writeInt32LE(this.requestId, 4); // requestID
|
||||
header.writeInt32LE(0, 8); // responseTo
|
||||
header.writeInt32LE(opcodes.OP_MSG, 12); // opCode
|
||||
header.writeUInt32LE(flags, 16); // flags
|
||||
return buffers;
|
||||
}
|
||||
|
||||
makeDocumentSegment(buffers, document) {
|
||||
const payloadTypeBuffer = new Buffer(1);
|
||||
payloadTypeBuffer[0] = 0;
|
||||
|
||||
const documentBuffer = this.serializeBson(document);
|
||||
buffers.push(payloadTypeBuffer);
|
||||
buffers.push(documentBuffer);
|
||||
|
||||
return payloadTypeBuffer.length + documentBuffer.length;
|
||||
}
|
||||
|
||||
serializeBson(document) {
|
||||
return this.bson.serialize(document, {
|
||||
checkKeys: this.checkKeys,
|
||||
serializeFunctions: this.serializeFunctions,
|
||||
ignoreUndefined: this.ignoreUndefined
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
Msg.getRequestId = function() {
|
||||
return ++_requestId;
|
||||
};
|
||||
|
||||
class BinMsg {
|
||||
constructor(bson, message, msgHeader, msgBody, opts) {
|
||||
opts = opts || { promoteLongs: true, promoteValues: true, promoteBuffers: false };
|
||||
this.parsed = false;
|
||||
this.raw = message;
|
||||
this.data = msgBody;
|
||||
this.bson = bson;
|
||||
this.opts = opts;
|
||||
|
||||
// Read the message header
|
||||
this.length = msgHeader.length;
|
||||
this.requestId = msgHeader.requestId;
|
||||
this.responseTo = msgHeader.responseTo;
|
||||
this.opCode = msgHeader.opCode;
|
||||
this.fromCompressed = msgHeader.fromCompressed;
|
||||
|
||||
// Read response flags
|
||||
this.responseFlags = msgBody.readInt32LE(0);
|
||||
this.checksumPresent = (this.responseFlags & OPTS_CHECKSUM_PRESENT) !== 0;
|
||||
this.moreToCome = (this.responseFlags & OPTS_MORE_TO_COME) !== 0;
|
||||
this.exhaustAllowed = (this.responseFlags & OPTS_EXHAUST_ALLOWED) !== 0;
|
||||
this.promoteLongs = typeof opts.promoteLongs === 'boolean' ? opts.promoteLongs : true;
|
||||
this.promoteValues = typeof opts.promoteValues === 'boolean' ? opts.promoteValues : true;
|
||||
this.promoteBuffers = typeof opts.promoteBuffers === 'boolean' ? opts.promoteBuffers : false;
|
||||
|
||||
this.documents = [];
|
||||
}
|
||||
|
||||
isParsed() {
|
||||
return this.parsed;
|
||||
}
|
||||
|
||||
parse(options) {
|
||||
// Don't parse again if not needed
|
||||
if (this.parsed) return;
|
||||
options = options || {};
|
||||
|
||||
this.index = 4;
|
||||
// Allow the return of raw documents instead of parsing
|
||||
const raw = options.raw || false;
|
||||
const documentsReturnedIn = options.documentsReturnedIn || null;
|
||||
const promoteLongs =
|
||||
typeof options.promoteLongs === 'boolean' ? options.promoteLongs : this.opts.promoteLongs;
|
||||
const promoteValues =
|
||||
typeof options.promoteValues === 'boolean' ? options.promoteValues : this.opts.promoteValues;
|
||||
const promoteBuffers =
|
||||
typeof options.promoteBuffers === 'boolean'
|
||||
? options.promoteBuffers
|
||||
: this.opts.promoteBuffers;
|
||||
|
||||
// Set up the options
|
||||
const _options = {
|
||||
promoteLongs: promoteLongs,
|
||||
promoteValues: promoteValues,
|
||||
promoteBuffers: promoteBuffers
|
||||
};
|
||||
|
||||
while (this.index < this.data.length) {
|
||||
const payloadType = this.data.readUInt8(this.index++);
|
||||
if (payloadType === 1) {
|
||||
console.error('TYPE 1');
|
||||
} else if (payloadType === 0) {
|
||||
const bsonSize = this.data.readUInt32LE(this.index);
|
||||
const bin = this.data.slice(this.index, this.index + bsonSize);
|
||||
this.documents.push(raw ? bin : this.bson.deserialize(bin, _options));
|
||||
|
||||
this.index += bsonSize;
|
||||
}
|
||||
}
|
||||
|
||||
if (this.documents.length === 1 && documentsReturnedIn != null && raw) {
|
||||
const fieldsAsRaw = {};
|
||||
fieldsAsRaw[documentsReturnedIn] = true;
|
||||
_options.fieldsAsRaw = fieldsAsRaw;
|
||||
|
||||
const doc = this.bson.deserialize(this.documents[0], _options);
|
||||
this.documents = [doc];
|
||||
}
|
||||
|
||||
this.parsed = true;
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = { Msg, BinMsg };
|
||||
+490
-886
File diff suppressed because it is too large
Load Diff
+14
-70
@@ -1,71 +1,17 @@
|
||||
'use strict';
|
||||
|
||||
var f = require('util').format,
|
||||
require_optional = require('require_optional');
|
||||
const require_optional = require('require_optional');
|
||||
|
||||
// Set property function
|
||||
var setProperty = function(obj, prop, flag, values) {
|
||||
Object.defineProperty(obj, prop.name, {
|
||||
enumerable: true,
|
||||
set: function(value) {
|
||||
if (typeof value !== 'boolean') throw new Error(f('%s required a boolean', prop.name));
|
||||
// Flip the bit to 1
|
||||
if (value === true) values.flags |= flag;
|
||||
// Flip the bit to 0 if it's set, otherwise ignore
|
||||
if (value === false && (values.flags & flag) === flag) values.flags ^= flag;
|
||||
prop.value = value;
|
||||
},
|
||||
get: function() {
|
||||
return prop.value;
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
// Set property function
|
||||
var getProperty = function(obj, propName, fieldName, values, func) {
|
||||
Object.defineProperty(obj, propName, {
|
||||
enumerable: true,
|
||||
get: function() {
|
||||
// Not parsed yet, parse it
|
||||
if (values[fieldName] == null && obj.isParsed && !obj.isParsed()) {
|
||||
obj.parse();
|
||||
}
|
||||
|
||||
// Do we have a post processing function
|
||||
if (typeof func === 'function') return func(values[fieldName]);
|
||||
// Return raw value
|
||||
return values[fieldName];
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
// Set simple property
|
||||
var getSingleProperty = function(obj, name, value) {
|
||||
Object.defineProperty(obj, name, {
|
||||
enumerable: true,
|
||||
get: function() {
|
||||
return value;
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
// Shallow copy
|
||||
var copy = function(fObj, tObj) {
|
||||
tObj = tObj || {};
|
||||
for (var name in fObj) tObj[name] = fObj[name];
|
||||
return tObj;
|
||||
};
|
||||
|
||||
var debugOptions = function(debugFields, options) {
|
||||
function debugOptions(debugFields, options) {
|
||||
var finaloptions = {};
|
||||
debugFields.forEach(function(n) {
|
||||
finaloptions[n] = options[n];
|
||||
});
|
||||
|
||||
return finaloptions;
|
||||
};
|
||||
}
|
||||
|
||||
var retrieveBSON = function() {
|
||||
function retrieveBSON() {
|
||||
var BSON = require('bson');
|
||||
BSON.native = false;
|
||||
|
||||
@@ -78,17 +24,17 @@ var retrieveBSON = function() {
|
||||
} catch (err) {} // eslint-disable-line
|
||||
|
||||
return BSON;
|
||||
};
|
||||
}
|
||||
|
||||
// Throw an error if an attempt to use Snappy is made when Snappy is not installed
|
||||
var noSnappyWarning = function() {
|
||||
function noSnappyWarning() {
|
||||
throw new Error(
|
||||
'Attempted to use Snappy compression, but Snappy is not installed. Install or disable Snappy compression and try again.'
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
// Facilitate loading Snappy optionally
|
||||
var retrieveSnappy = function() {
|
||||
function retrieveSnappy() {
|
||||
var snappy = null;
|
||||
try {
|
||||
snappy = require_optional('snappy');
|
||||
@@ -102,12 +48,10 @@ var retrieveSnappy = function() {
|
||||
};
|
||||
}
|
||||
return snappy;
|
||||
};
|
||||
}
|
||||
|
||||
exports.setProperty = setProperty;
|
||||
exports.getProperty = getProperty;
|
||||
exports.getSingleProperty = getSingleProperty;
|
||||
exports.copy = copy;
|
||||
exports.debugOptions = debugOptions;
|
||||
exports.retrieveBSON = retrieveBSON;
|
||||
exports.retrieveSnappy = retrieveSnappy;
|
||||
module.exports = {
|
||||
debugOptions,
|
||||
retrieveBSON,
|
||||
retrieveSnappy
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user