Skip to content

Commit 35d0274

Browse files
committed
fix: report the correct platform in client metadata
This relatively large refactoring ultimately corrects the fact that the platform was not always reported correctly in client metadata during initial handshake. It also takes the steps to localize the creation of that metadata to one place, and makes the metadata consistent across legacy and unified topologies NODE-2418
1 parent c528a66 commit 35d0274

19 files changed

+143
-194
lines changed

lib/cmap/connection_pool.js

+2-1
Original file line numberDiff line numberDiff line change
@@ -131,7 +131,8 @@ class ConnectionPool extends EventEmitter {
131131
maxIdleTimeMS: typeof options.maxIdleTimeMS === 'number' ? options.maxIdleTimeMS : 0,
132132
waitQueueTimeoutMS:
133133
typeof options.waitQueueTimeoutMS === 'number' ? options.waitQueueTimeoutMS : 0,
134-
autoEncrypter: options.autoEncrypter
134+
autoEncrypter: options.autoEncrypter,
135+
metadata: options.metadata
135136
});
136137

137138
if (options.minSize > options.maxSize) {

lib/core/connection/connect.js

+2-2
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,11 @@ const net = require('net');
33
const tls = require('tls');
44
const Connection = require('./connection');
55
const Query = require('./commands').Query;
6-
const createClientInfo = require('../topologies/shared').createClientInfo;
76
const MongoError = require('../error').MongoError;
87
const MongoNetworkError = require('../error').MongoNetworkError;
98
const defaultAuthProviders = require('../auth/defaultAuthProviders').defaultAuthProviders;
109
const WIRE_CONSTANTS = require('../wireprotocol/constants');
10+
const makeClientMetadata = require('../utils').makeClientMetadata;
1111
const MAX_SUPPORTED_WIRE_VERSION = WIRE_CONSTANTS.MAX_SUPPORTED_WIRE_VERSION;
1212
const MAX_SUPPORTED_SERVER_VERSION = WIRE_CONSTANTS.MAX_SUPPORTED_SERVER_VERSION;
1313
const MIN_SUPPORTED_WIRE_VERSION = WIRE_CONSTANTS.MIN_SUPPORTED_WIRE_VERSION;
@@ -105,7 +105,7 @@ function performInitialHandshake(conn, options, _callback) {
105105
const handshakeDoc = Object.assign(
106106
{
107107
ismaster: true,
108-
client: createClientInfo(options),
108+
client: options.metadata || makeClientMetadata(options),
109109
compression: compressors
110110
},
111111
getSaslSupportedMechs(options)

lib/core/sdam/server.js

-3
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ const ConnectionPool = require('../../cmap/connection_pool').ConnectionPool;
44
const MongoError = require('../error').MongoError;
55
const relayEvents = require('../utils').relayEvents;
66
const BSON = require('../connection/utils').retrieveBSON();
7-
const createClientInfo = require('../topologies/shared').createClientInfo;
87
const Logger = require('../connection/logger');
98
const ServerDescription = require('./server_description').ServerDescription;
109
const ReadPreference = require('../topologies/read_preference');
@@ -99,8 +98,6 @@ class Server extends EventEmitter {
9998
BSON.Symbol,
10099
BSON.Timestamp
101100
]),
102-
// client metadata for the initial handshake
103-
clientInfo: createClientInfo(options),
104101
// the server state
105102
state: STATE_CLOSED,
106103
credentials: options.credentials,

lib/core/sdam/topology.js

+10-9
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@ const createCompressionInfo = require('../topologies/shared').createCompressionI
1616
const isRetryableError = require('../error').isRetryableError;
1717
const isSDAMUnrecoverableError = require('../error').isSDAMUnrecoverableError;
1818
const ClientSession = require('../sessions').ClientSession;
19-
const createClientInfo = require('../topologies/shared').createClientInfo;
2019
const MongoError = require('../error').MongoError;
2120
const resolveClusterTime = require('../topologies/shared').resolveClusterTime;
2221
const SrvPoller = require('./srv_polling').SrvPoller;
@@ -25,6 +24,7 @@ const makeStateMachine = require('../utils').makeStateMachine;
2524
const eachAsync = require('../utils').eachAsync;
2625
const emitDeprecationWarning = require('../../utils').emitDeprecationWarning;
2726
const ServerSessionPool = require('../sessions').ServerSessionPool;
27+
const makeClientMetadata = require('../utils').makeClientMetadata;
2828

2929
const common = require('./common');
3030
const drainTimerQueue = common.drainTimerQueue;
@@ -119,6 +119,13 @@ class Topology extends EventEmitter {
119119
}
120120

121121
options = Object.assign({}, common.TOPOLOGY_DEFAULTS, options);
122+
options = Object.freeze(
123+
Object.assign(options, {
124+
metadata: makeClientMetadata(options),
125+
compression: { compressors: createCompressionInfo(options) }
126+
})
127+
);
128+
122129
DEPRECATED_OPTIONS.forEach(optionName => {
123130
if (options[optionName]) {
124131
emitDeprecationWarning(
@@ -196,12 +203,6 @@ class Topology extends EventEmitter {
196203
connectionTimers: new Set()
197204
};
198205

199-
// amend options for server instance creation
200-
this.s.options.compression = { compressors: createCompressionInfo(options) };
201-
202-
// add client info
203-
this.s.clientInfo = createClientInfo(options);
204-
205206
if (options.srvHost) {
206207
this.s.srvPoller =
207208
options.srvPoller ||
@@ -705,8 +706,8 @@ class Topology extends EventEmitter {
705706
return new CursorClass(topology, ns, cmd, options);
706707
}
707708

708-
get clientInfo() {
709-
return this.s.clientInfo;
709+
get clientMetadata() {
710+
return this.s.options.metadata;
710711
}
711712

712713
isConnected() {

lib/core/topologies/mongos.js

+5-13
Original file line numberDiff line numberDiff line change
@@ -8,16 +8,15 @@ const Logger = require('../connection/logger');
88
const retrieveBSON = require('../connection/utils').retrieveBSON;
99
const MongoError = require('../error').MongoError;
1010
const Server = require('./server');
11-
const clone = require('./shared').clone;
1211
const diff = require('./shared').diff;
1312
const cloneOptions = require('./shared').cloneOptions;
14-
const createClientInfo = require('./shared').createClientInfo;
1513
const SessionMixins = require('./shared').SessionMixins;
1614
const isRetryableWritesSupported = require('./shared').isRetryableWritesSupported;
1715
const relayEvents = require('../utils').relayEvents;
1816
const isRetryableError = require('../error').isRetryableError;
1917
const BSON = retrieveBSON();
2018
const getMMAPError = require('./shared').getMMAPError;
19+
const makeClientMetadata = require('../utils').makeClientMetadata;
2120

2221
/**
2322
* @fileOverview The **Mongos** class is a class that represents a Mongos Proxy topology and is
@@ -116,7 +115,7 @@ var Mongos = function(seedlist, options) {
116115

117116
// Internal state
118117
this.s = {
119-
options: Object.assign({}, options),
118+
options: Object.assign({ metadata: makeClientMetadata(options) }, options),
120119
// BSON instance
121120
bson:
122121
options.bson ||
@@ -153,14 +152,9 @@ var Mongos = function(seedlist, options) {
153152
// Are we running in debug mode
154153
debug: typeof options.debug === 'boolean' ? options.debug : false,
155154
// localThresholdMS
156-
localThresholdMS: options.localThresholdMS || 15,
157-
// Client info
158-
clientInfo: createClientInfo(options)
155+
localThresholdMS: options.localThresholdMS || 15
159156
};
160157

161-
// Set the client info
162-
this.s.options.clientInfo = createClientInfo(options);
163-
164158
// Log info warning if the socketTimeout < haInterval as it will cause
165159
// a lot of recycled connections to happen.
166160
if (
@@ -265,8 +259,7 @@ Mongos.prototype.connect = function(options) {
265259
Object.assign({}, self.s.options, x, options, {
266260
reconnect: false,
267261
monitoring: false,
268-
parent: self,
269-
clientInfo: clone(self.s.clientInfo)
262+
parent: self
270263
})
271264
);
272265

@@ -607,8 +600,7 @@ function reconnectProxies(self, proxies, callback) {
607600
port: parseInt(_server.name.split(':')[1], 10),
608601
reconnect: false,
609602
monitoring: false,
610-
parent: self,
611-
clientInfo: clone(self.s.clientInfo)
603+
parent: self
612604
})
613605
);
614606

lib/core/topologies/replset.js

+5-10
Original file line numberDiff line numberDiff line change
@@ -10,17 +10,16 @@ const Logger = require('../connection/logger');
1010
const MongoError = require('../error').MongoError;
1111
const Server = require('./server');
1212
const ReplSetState = require('./replset_state');
13-
const clone = require('./shared').clone;
1413
const Timeout = require('./shared').Timeout;
1514
const Interval = require('./shared').Interval;
16-
const createClientInfo = require('./shared').createClientInfo;
1715
const SessionMixins = require('./shared').SessionMixins;
1816
const isRetryableWritesSupported = require('./shared').isRetryableWritesSupported;
1917
const relayEvents = require('../utils').relayEvents;
2018
const isRetryableError = require('../error').isRetryableError;
2119
const BSON = retrieveBSON();
2220
const calculateDurationInMs = require('../utils').calculateDurationInMs;
2321
const getMMAPError = require('./shared').getMMAPError;
22+
const makeClientMetadata = require('../utils').makeClientMetadata;
2423

2524
//
2625
// States
@@ -140,7 +139,7 @@ var ReplSet = function(seedlist, options) {
140139

141140
// Internal state
142141
this.s = {
143-
options: Object.assign({}, options),
142+
options: Object.assign({ metadata: makeClientMetadata(options) }, options),
144143
// BSON instance
145144
bson:
146145
options.bson ||
@@ -187,9 +186,7 @@ var ReplSet = function(seedlist, options) {
187186
// Connect function options passed in
188187
connectOptions: {},
189188
// Are we running in debug mode
190-
debug: typeof options.debug === 'boolean' ? options.debug : false,
191-
// Client info
192-
clientInfo: createClientInfo(options)
189+
debug: typeof options.debug === 'boolean' ? options.debug : false
193190
};
194191

195192
// Add handler for topology change
@@ -369,8 +366,7 @@ function connectNewServers(self, servers, callback) {
369366
port: parseInt(_server.split(':')[1], 10),
370367
reconnect: false,
371368
monitoring: false,
372-
parent: self,
373-
clientInfo: clone(self.s.clientInfo)
369+
parent: self
374370
})
375371
);
376372

@@ -918,8 +914,7 @@ ReplSet.prototype.connect = function(options) {
918914
Object.assign({}, self.s.options, x, options, {
919915
reconnect: false,
920916
monitoring: false,
921-
parent: self,
922-
clientInfo: clone(self.s.clientInfo)
917+
parent: self
923918
})
924919
);
925920
});

lib/core/topologies/server.js

+9-4
Original file line numberDiff line numberDiff line change
@@ -13,13 +13,13 @@ var inherits = require('util').inherits,
1313
wireProtocol = require('../wireprotocol'),
1414
CoreCursor = require('../cursor').CoreCursor,
1515
sdam = require('./shared'),
16-
createClientInfo = require('./shared').createClientInfo,
1716
createCompressionInfo = require('./shared').createCompressionInfo,
1817
resolveClusterTime = require('./shared').resolveClusterTime,
1918
SessionMixins = require('./shared').SessionMixins,
2019
relayEvents = require('../utils').relayEvents;
2120

2221
const collationNotSupported = require('../utils').collationNotSupported;
22+
const makeClientMetadata = require('../utils').makeClientMetadata;
2323

2424
// Used for filtering out fields for loggin
2525
var debugFields = [
@@ -120,7 +120,7 @@ var Server = function(options) {
120120
// Internal state
121121
this.s = {
122122
// Options
123-
options: options,
123+
options: Object.assign({ metadata: makeClientMetadata(options) }, options),
124124
// Logger
125125
logger: Logger('Server', options),
126126
// Factory overrides
@@ -175,8 +175,6 @@ var Server = function(options) {
175175
this.initialConnect = true;
176176
// Default type
177177
this._type = 'server';
178-
// Set the client info
179-
this.clientInfo = createClientInfo(options);
180178

181179
// Max Stalleness values
182180
// last time we updated the ismaster state
@@ -212,6 +210,13 @@ Object.defineProperty(Server.prototype, 'logicalSessionTimeoutMinutes', {
212210
}
213211
});
214212

213+
Object.defineProperty(Server.prototype, 'clientMetadata', {
214+
enumerable: true,
215+
get: function() {
216+
return this.s.options.metadata;
217+
}
218+
});
219+
215220
// In single server deployments we track the clusterTime directly on the topology, however
216221
// in Mongos and ReplSet deployments we instead need to delegate the clusterTime up to the
217222
// tracking objects so we can ensure we are gossiping the maximum time received from the

lib/core/topologies/shared.js

-60
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,5 @@
11
'use strict';
2-
3-
const os = require('os');
42
const ReadPreference = require('./read_preference');
5-
const Buffer = require('safe-buffer').Buffer;
63
const TopologyType = require('../sdam/common').TopologyType;
74
const MongoError = require('../error').MongoError;
85

@@ -18,62 +15,6 @@ function emitSDAMEvent(self, event, description) {
1815
}
1916
}
2017

21-
// Get package.json variable
22-
const driverVersion = require('../../../package.json').version;
23-
const nodejsVersion = `'Node.js ${process.version}, ${os.endianness}`;
24-
const type = os.type();
25-
const name = process.platform;
26-
const architecture = process.arch;
27-
const release = os.release();
28-
29-
function createClientInfo(options) {
30-
const clientInfo = options.clientInfo
31-
? clone(options.clientInfo)
32-
: {
33-
driver: {
34-
name: 'nodejs',
35-
version: driverVersion
36-
},
37-
os: {
38-
type: type,
39-
name: name,
40-
architecture: architecture,
41-
version: release
42-
}
43-
};
44-
45-
if (options.useUnifiedTopology) {
46-
clientInfo.platform = `${nodejsVersion} (${options.useUnifiedTopology ? 'unified' : 'legacy'})`;
47-
}
48-
49-
// Do we have an application specific string
50-
if (options.appname) {
51-
// Cut at 128 bytes
52-
var buffer = Buffer.from(options.appname);
53-
// Return the truncated appname
54-
var appname = buffer.length > 128 ? buffer.slice(0, 128).toString('utf8') : options.appname;
55-
// Add to the clientInfo
56-
clientInfo.application = { name: appname };
57-
}
58-
59-
// support optionally provided wrapping driver info
60-
if (options.driverInfo) {
61-
if (options.driverInfo.name) {
62-
clientInfo.driver.name = `${clientInfo.driver.name}|${options.driverInfo.name}`;
63-
}
64-
65-
if (options.driverInfo.version) {
66-
clientInfo.driver.version = `${clientInfo.driver.version}|${options.driverInfo.version}`;
67-
}
68-
69-
if (options.driverInfo.platform) {
70-
clientInfo.platform = `${clientInfo.platform}|${options.driverInfo.platform}`;
71-
}
72-
}
73-
74-
return clientInfo;
75-
}
76-
7718
function createCompressionInfo(options) {
7819
if (!options.compression || !options.compression.compressors) {
7920
return [];
@@ -475,7 +416,6 @@ module.exports.getTopologyType = getTopologyType;
475416
module.exports.emitServerDescriptionChanged = emitServerDescriptionChanged;
476417
module.exports.emitTopologyDescriptionChanged = emitTopologyDescriptionChanged;
477418
module.exports.cloneOptions = cloneOptions;
478-
module.exports.createClientInfo = createClientInfo;
479419
module.exports.createCompressionInfo = createCompressionInfo;
480420
module.exports.clone = clone;
481421
module.exports.diff = diff;

0 commit comments

Comments
 (0)