Skip to content

Commit e86f11e

Browse files
nbbeekendariakp
authored andcommitted
feat(NODE-6392): add timeoutMS support to ClientEncryption helpers part 1 (#4281)
1 parent c28608b commit e86f11e

File tree

14 files changed

+288
-52
lines changed

14 files changed

+288
-52
lines changed

src/client-side-encryption/auto_encrypter.ts

+6-3
Original file line numberDiff line numberDiff line change
@@ -310,7 +310,10 @@ export class AutoEncrypter {
310310
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
311311
// @ts-ignore: TS complains as this always returns true on versions where it is present.
312312
if (net.getDefaultAutoSelectFamily) {
313-
Object.assign(clientOptions, autoSelectSocketOptions(this._client.options));
313+
// AutoEncrypter is made inside of MongoClient constructor while options are being parsed,
314+
// we do not have access to the options that are in progress.
315+
// TODO(NODE-NODE-6449): AutoEncrypter does not use client options for autoSelectFamily
316+
Object.assign(clientOptions, autoSelectSocketOptions(this._client.s?.options ?? {}));
314317
}
315318

316319
this._mongocryptdClient = new MongoClient(this._mongocryptdManager.uri, clientOptions);
@@ -392,7 +395,7 @@ export class AutoEncrypter {
392395
promoteLongs: false,
393396
proxyOptions: this._proxyOptions,
394397
tlsOptions: this._tlsOptions,
395-
socketOptions: autoSelectSocketOptions(this._client.options)
398+
socketOptions: autoSelectSocketOptions(this._client.s.options)
396399
});
397400

398401
return deserialize(await stateMachine.execute(this, context, options.timeoutContext), {
@@ -413,7 +416,7 @@ export class AutoEncrypter {
413416
...options,
414417
proxyOptions: this._proxyOptions,
415418
tlsOptions: this._tlsOptions,
416-
socketOptions: autoSelectSocketOptions(this._client.options)
419+
socketOptions: autoSelectSocketOptions(this._client.s.options)
417420
});
418421

419422
return await stateMachine.execute(

src/client-side-encryption/client_encryption.ts

+32-13
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,8 @@ import { type MongoClient, type MongoClientOptions } from '../mongo_client';
2424
import { type Filter, type WithId } from '../mongo_types';
2525
import { type CreateCollectionOptions } from '../operations/create_collection';
2626
import { type DeleteResult } from '../operations/delete';
27-
import { MongoDBCollectionNamespace } from '../utils';
27+
import { TimeoutContext } from '../timeout';
28+
import { MongoDBCollectionNamespace, resolveTimeoutOptions } from '../utils';
2829
import * as cryptoCallbacks from './crypto_callbacks';
2930
import {
3031
MongoCryptCreateDataKeyError,
@@ -74,6 +75,8 @@ export class ClientEncryption {
7475
_tlsOptions: CSFLEKMSTlsOptions;
7576
/** @internal */
7677
_kmsProviders: KMSProviders;
78+
/** @internal */
79+
_timeoutMS?: number;
7780

7881
/** @internal */
7982
_mongoCrypt: MongoCrypt;
@@ -120,6 +123,8 @@ export class ClientEncryption {
120123
this._proxyOptions = options.proxyOptions ?? {};
121124
this._tlsOptions = options.tlsOptions ?? {};
122125
this._kmsProviders = options.kmsProviders || {};
126+
const { timeoutMS } = resolveTimeoutOptions(client, options);
127+
this._timeoutMS = timeoutMS;
123128

124129
if (options.keyVaultNamespace == null) {
125130
throw new MongoCryptInvalidArgumentError('Missing required option `keyVaultNamespace`');
@@ -212,7 +217,7 @@ export class ClientEncryption {
212217
const stateMachine = new StateMachine({
213218
proxyOptions: this._proxyOptions,
214219
tlsOptions: this._tlsOptions,
215-
socketOptions: autoSelectSocketOptions(this._client.options)
220+
socketOptions: autoSelectSocketOptions(this._client.s.options)
216221
});
217222

218223
const dataKey = deserialize(await stateMachine.execute(this, context)) as DataKey;
@@ -270,10 +275,14 @@ export class ClientEncryption {
270275
const stateMachine = new StateMachine({
271276
proxyOptions: this._proxyOptions,
272277
tlsOptions: this._tlsOptions,
273-
socketOptions: autoSelectSocketOptions(this._client.options)
278+
socketOptions: autoSelectSocketOptions(this._client.s.options)
274279
});
275280

276-
const { v: dataKeys } = deserialize(await stateMachine.execute(this, context));
281+
const timeoutContext = TimeoutContext.create(
282+
resolveTimeoutOptions(this._client, { timeoutMS: this._timeoutMS })
283+
);
284+
285+
const { v: dataKeys } = deserialize(await stateMachine.execute(this, context, timeoutContext));
277286
if (dataKeys.length === 0) {
278287
return {};
279288
}
@@ -303,7 +312,8 @@ export class ClientEncryption {
303312
.db(dbName)
304313
.collection<DataKey>(collectionName)
305314
.bulkWrite(replacements, {
306-
writeConcern: { w: 'majority' }
315+
writeConcern: { w: 'majority' },
316+
timeoutMS: timeoutContext.csotEnabled() ? timeoutContext?.remainingTimeMS : undefined
307317
});
308318

309319
return { bulkWriteResult: result };
@@ -332,7 +342,7 @@ export class ClientEncryption {
332342
return await this._keyVaultClient
333343
.db(dbName)
334344
.collection<DataKey>(collectionName)
335-
.deleteOne({ _id }, { writeConcern: { w: 'majority' } });
345+
.deleteOne({ _id }, { writeConcern: { w: 'majority' }, timeoutMS: this._timeoutMS });
336346
}
337347

338348
/**
@@ -355,7 +365,7 @@ export class ClientEncryption {
355365
return this._keyVaultClient
356366
.db(dbName)
357367
.collection<DataKey>(collectionName)
358-
.find({}, { readConcern: { level: 'majority' } });
368+
.find({}, { readConcern: { level: 'majority' }, timeoutMS: this._timeoutMS });
359369
}
360370

361371
/**
@@ -381,7 +391,7 @@ export class ClientEncryption {
381391
return await this._keyVaultClient
382392
.db(dbName)
383393
.collection<DataKey>(collectionName)
384-
.findOne({ _id }, { readConcern: { level: 'majority' } });
394+
.findOne({ _id }, { readConcern: { level: 'majority' }, timeoutMS: this._timeoutMS });
385395
}
386396

387397
/**
@@ -408,7 +418,10 @@ export class ClientEncryption {
408418
return await this._keyVaultClient
409419
.db(dbName)
410420
.collection<DataKey>(collectionName)
411-
.findOne({ keyAltNames: keyAltName }, { readConcern: { level: 'majority' } });
421+
.findOne(
422+
{ keyAltNames: keyAltName },
423+
{ readConcern: { level: 'majority' }, timeoutMS: this._timeoutMS }
424+
);
412425
}
413426

414427
/**
@@ -442,7 +455,7 @@ export class ClientEncryption {
442455
.findOneAndUpdate(
443456
{ _id },
444457
{ $addToSet: { keyAltNames: keyAltName } },
445-
{ writeConcern: { w: 'majority' }, returnDocument: 'before' }
458+
{ writeConcern: { w: 'majority' }, returnDocument: 'before', timeoutMS: this._timeoutMS }
446459
);
447460

448461
return value;
@@ -503,7 +516,8 @@ export class ClientEncryption {
503516
.collection<DataKey>(collectionName)
504517
.findOneAndUpdate({ _id }, pipeline, {
505518
writeConcern: { w: 'majority' },
506-
returnDocument: 'before'
519+
returnDocument: 'before',
520+
timeoutMS: this._timeoutMS
507521
});
508522

509523
return value;
@@ -650,7 +664,7 @@ export class ClientEncryption {
650664
const stateMachine = new StateMachine({
651665
proxyOptions: this._proxyOptions,
652666
tlsOptions: this._tlsOptions,
653-
socketOptions: autoSelectSocketOptions(this._client.options)
667+
socketOptions: autoSelectSocketOptions(this._client.s.options)
654668
});
655669

656670
const { v } = deserialize(await stateMachine.execute(this, context));
@@ -729,7 +743,7 @@ export class ClientEncryption {
729743
const stateMachine = new StateMachine({
730744
proxyOptions: this._proxyOptions,
731745
tlsOptions: this._tlsOptions,
732-
socketOptions: autoSelectSocketOptions(this._client.options)
746+
socketOptions: autoSelectSocketOptions(this._client.s.options)
733747
});
734748
const context = this._mongoCrypt.makeExplicitEncryptionContext(valueBuffer, contextOptions);
735749

@@ -818,6 +832,11 @@ export interface ClientEncryptionOptions {
818832
* TLS options for kms providers to use.
819833
*/
820834
tlsOptions?: CSFLEKMSTlsOptions;
835+
836+
/**
837+
* The timeout setting to be used for all the operations on ClientEncryption.
838+
*/
839+
timeoutMS?: number;
821840
}
822841

823842
/**

src/cursor/abstract_cursor.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -835,7 +835,7 @@ export abstract class AbstractCursor<
835835
if (this.cursorOptions.timeoutMS != null) {
836836
this.timeoutContext ??= new CursorTimeoutContext(
837837
TimeoutContext.create({
838-
serverSelectionTimeoutMS: this.client.options.serverSelectionTimeoutMS,
838+
serverSelectionTimeoutMS: this.client.s.options.serverSelectionTimeoutMS,
839839
timeoutMS: this.cursorOptions.timeoutMS
840840
}),
841841
this
@@ -925,7 +925,7 @@ export abstract class AbstractCursor<
925925
this.timeoutContext?.clear();
926926
return new CursorTimeoutContext(
927927
TimeoutContext.create({
928-
serverSelectionTimeoutMS: this.client.options.serverSelectionTimeoutMS,
928+
serverSelectionTimeoutMS: this.client.s.options.serverSelectionTimeoutMS,
929929
timeoutMS
930930
}),
931931
this

src/gridfs/index.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -161,7 +161,7 @@ export class GridFSBucket extends TypedEventEmitter<GridFSBucketEvents> {
161161
if (timeoutMS) {
162162
timeoutContext = new CSOTTimeoutContext({
163163
timeoutMS,
164-
serverSelectionTimeoutMS: this.s.db.client.options.serverSelectionTimeoutMS
164+
serverSelectionTimeoutMS: this.s.db.client.s.options.serverSelectionTimeoutMS
165165
});
166166
}
167167

@@ -241,7 +241,7 @@ export class GridFSBucket extends TypedEventEmitter<GridFSBucketEvents> {
241241
if (timeoutMS) {
242242
timeoutContext = new CSOTTimeoutContext({
243243
timeoutMS,
244-
serverSelectionTimeoutMS: this.s.db.client.options.serverSelectionTimeoutMS
244+
serverSelectionTimeoutMS: this.s.db.client.s.options.serverSelectionTimeoutMS
245245
});
246246
}
247247

src/gridfs/upload.ts

+3-2
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import {
1010
MongoOperationTimeoutError
1111
} from '../error';
1212
import { CSOTTimeoutContext } from '../timeout';
13-
import { type Callback, squashError } from '../utils';
13+
import { type Callback, resolveTimeoutOptions, squashError } from '../utils';
1414
import type { WriteConcernOptions } from '../write_concern';
1515
import { WriteConcern } from './../write_concern';
1616
import type { GridFSFile } from './download';
@@ -143,7 +143,8 @@ export class GridFSBucketWriteStream extends Writable {
143143
if (options.timeoutMS != null)
144144
this.timeoutContext = new CSOTTimeoutContext({
145145
timeoutMS: options.timeoutMS,
146-
serverSelectionTimeoutMS: this.bucket.s.db.client.options.serverSelectionTimeoutMS
146+
serverSelectionTimeoutMS: resolveTimeoutOptions(this.bucket.s.db.client, {})
147+
.serverSelectionTimeoutMS
147148
});
148149
}
149150

src/mongo_client.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -490,7 +490,7 @@ export class MongoClient extends TypedEventEmitter<MongoClientEvents> implements
490490

491491
/** @internal */
492492
get timeoutMS(): number | undefined {
493-
return this.options.timeoutMS;
493+
return this.s.options.timeoutMS;
494494
}
495495

496496
/**
@@ -706,7 +706,7 @@ export class MongoClient extends TypedEventEmitter<MongoClientEvents> implements
706706

707707
// Default to db from connection string if not provided
708708
if (!dbName) {
709-
dbName = this.options.dbName;
709+
dbName = this.s.options.dbName;
710710
}
711711

712712
// Copy the options and add out internal override of the not shared flag

src/operations/client_bulk_write/executor.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ export class ClientBulkWriteExecutor {
5656

5757
// If no write concern was provided, we inherit one from the client.
5858
if (!this.options.writeConcern) {
59-
this.options.writeConcern = WriteConcern.fromOptions(this.client.options);
59+
this.options.writeConcern = WriteConcern.fromOptions(this.client.s.options);
6060
}
6161

6262
if (this.options.writeConcern?.w === 0) {

src/operations/create_collection.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -137,7 +137,7 @@ export class CreateCollectionOperation extends CommandOperation<Collection> {
137137

138138
const encryptedFields: Document | undefined =
139139
options.encryptedFields ??
140-
db.client.options.autoEncryption?.encryptedFieldsMap?.[`${db.databaseName}.${name}`];
140+
db.client.s.options.autoEncryption?.encryptedFieldsMap?.[`${db.databaseName}.${name}`];
141141

142142
if (encryptedFields) {
143143
// Creating a QE collection required min server of 7.0.0

src/operations/drop.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ export class DropCollectionOperation extends CommandOperation<boolean> {
3939
const options = this.options;
4040
const name = this.name;
4141

42-
const encryptedFieldsMap = db.client.options.autoEncryption?.encryptedFieldsMap;
42+
const encryptedFieldsMap = db.client.s.options.autoEncryption?.encryptedFieldsMap;
4343
let encryptedFields: Document | undefined =
4444
options.encryptedFields ?? encryptedFieldsMap?.[`${db.databaseName}.${name}`];
4545

0 commit comments

Comments
 (0)