@@ -20,7 +20,6 @@ const MAX_CONNECTION_NAME_LENGTH = 512;
20
20
export enum DataServiceEventTypes {
21
21
CONNECTIONS_DID_CHANGE = 'CONNECTIONS_DID_CHANGE' ,
22
22
ACTIVE_CONNECTION_CHANGED = 'ACTIVE_CONNECTION_CHANGED' ,
23
- ACTIVE_CONNECTION_CHANGING = 'ACTIVE_CONNECTION_CHANGING'
24
23
}
25
24
26
25
export enum ConnectionTypes {
@@ -55,6 +54,12 @@ export default class ConnectionController {
55
54
_activeConnectionModel : null | ConnectionModelType = null ;
56
55
private _currentConnectionId : null | string = null ;
57
56
57
+ // When we are connecting to a server we save a connection version to
58
+ // the request. That way if a new connection attempt is made while
59
+ // the connection is being established, we know we can ignore the
60
+ // request when it is completed so we don't have two live connections at once.
61
+ private _connectingVersion = 0 ;
62
+
58
63
private _connecting = false ;
59
64
private _connectingConnectionId : null | string = null ;
60
65
private _disconnecting = false ;
@@ -231,32 +236,24 @@ export default class ConnectionController {
231
236
public sendTelemetry (
232
237
newDataService : DataServiceType ,
233
238
connectionType : ConnectionTypes
234
- ) {
239
+ ) : void {
235
240
// Send metrics to Segment
236
241
this . _telemetryController . trackNewConnection (
237
242
newDataService ,
238
243
connectionType
239
244
) ;
240
245
}
241
246
242
- public parseNewConnectionAndConnect = (
247
+ public parseNewConnection = (
243
248
newConnectionModel : ConnectionModelType
244
- ) : Promise < boolean > => {
249
+ ) : ConnectionModelType => {
245
250
// Here we re-parse the connection, as it can be loaded from storage or
246
251
// passed by the connection model without the class methods.
247
- let connectionModel : ConnectionModelType ;
248
-
249
- try {
250
- connectionModel = new Connection ( newConnectionModel ) ;
251
- } catch ( error ) {
252
- vscode . window . showErrorMessage ( `Unable to load connection: ${ error } ` ) ;
253
- return Promise . reject ( new Error ( `Unable to load connection: ${ error } ` ) ) ;
254
- }
255
-
256
- return this . saveNewConnectionAndConnect (
257
- connectionModel ,
258
- ConnectionTypes . CONNECTION_FORM
252
+ const connectionModel : ConnectionModelType = new Connection (
253
+ newConnectionModel
259
254
) ;
255
+
256
+ return connectionModel ;
260
257
} ;
261
258
262
259
public saveNewConnectionAndConnect = async (
@@ -330,27 +327,19 @@ export default class ConnectionController {
330
327
} ) . instanceId
331
328
) ;
332
329
333
- if ( this . _connecting ) {
334
- return Promise . reject (
335
- new Error ( 'Unable to connect: already connecting.' )
336
- ) ;
337
- }
338
-
339
- if ( this . _disconnecting ) {
340
- return Promise . reject (
341
- new Error ( 'Unable to connect: currently disconnecting.' )
342
- ) ;
343
- }
344
-
345
- if ( this . _activeDataService ) {
346
- await this . disconnect ( ) ;
347
- }
330
+ // Store a version of this connection, so we can see when the conection
331
+ // is successful if it is still the most recent connection attempt.
332
+ this . _connectingVersion ++ ;
333
+ const connectingAttemptVersion = this . _connectingVersion ;
348
334
349
335
this . _connecting = true ;
350
336
this . _connectingConnectionId = connectionId ;
351
337
352
338
this . eventEmitter . emit ( DataServiceEventTypes . CONNECTIONS_DID_CHANGE ) ;
353
- this . eventEmitter . emit ( DataServiceEventTypes . ACTIVE_CONNECTION_CHANGING ) ;
339
+
340
+ if ( this . _activeDataService ) {
341
+ await this . disconnect ( ) ;
342
+ }
354
343
355
344
this . _statusView . showMessage ( 'Connecting to MongoDB...' ) ;
356
345
@@ -361,6 +350,22 @@ export default class ConnectionController {
361
350
const newDataService : DataServiceType = new DataService ( connectionModel ) ;
362
351
363
352
newDataService . connect ( ( err : Error | undefined ) => {
353
+ if (
354
+ connectingAttemptVersion !== this . _connectingVersion ||
355
+ ! this . _connections [ connectionId ]
356
+ ) {
357
+ // If the current attempt is no longer the most recent attempt
358
+ // or the connection no longer exists we silently end the connection
359
+ // and return.
360
+ try {
361
+ newDataService . disconnect ( ( ) => { } ) ;
362
+ } catch ( e ) {
363
+ /* */
364
+ }
365
+
366
+ return resolve ( false ) ;
367
+ }
368
+
364
369
this . _statusView . hideMessage ( ) ;
365
370
366
371
if ( err ) {
@@ -392,7 +397,7 @@ export default class ConnectionController {
392
397
393
398
public connectWithConnectionId = ( connectionId : string ) : Promise < boolean > => {
394
399
if ( this . _connections [ connectionId ] ) {
395
- let connectionModel : any ;
400
+ let connectionModel : ConnectionModelType ;
396
401
397
402
try {
398
403
const savedConnectionModel = this . _connections [ connectionId ]
@@ -433,36 +438,28 @@ export default class ConnectionController {
433
438
this . _currentConnectionId
434
439
) ;
435
440
436
- if ( this . _disconnecting ) {
441
+ if ( ! this . _activeDataService ) {
437
442
vscode . window . showErrorMessage (
438
- 'Unable to disconnect: already disconnecting from an instance .'
443
+ 'Unable to disconnect: no active connection .'
439
444
) ;
440
445
441
446
return Promise . resolve ( false ) ;
442
447
}
443
448
444
- if ( this . _connecting ) {
445
- // TODO: The desired UX here may be for the connection to be interrupted.
446
- vscode . window . showErrorMessage (
447
- 'Unable to disconnect: currently connecting to an instance.'
448
- ) ;
449
+ const dataServiceToDisconnectFrom = this . _activeDataService ;
449
450
450
- return Promise . resolve ( false ) ;
451
- }
451
+ this . _activeDataService = null ;
452
+ this . _currentConnectionId = null ;
453
+ this . _activeConnectionModel = null ;
454
+ this . _disconnecting = true ;
455
+
456
+ this . eventEmitter . emit ( DataServiceEventTypes . CONNECTIONS_DID_CHANGE ) ;
457
+ this . eventEmitter . emit ( DataServiceEventTypes . ACTIVE_CONNECTION_CHANGED ) ;
452
458
453
459
// Disconnect from the active connection.
454
460
return new Promise < boolean > ( ( resolve ) => {
455
- if ( ! this . _activeDataService ) {
456
- vscode . window . showErrorMessage (
457
- 'Unable to disconnect: no active connection.'
458
- ) ;
459
-
460
- return resolve ( false ) ;
461
- }
462
-
463
- this . _disconnecting = true ;
464
461
this . _statusView . showMessage ( 'Disconnecting from current connection...' ) ;
465
- this . _activeDataService . disconnect ( ( err : Error | undefined ) : void => {
462
+ dataServiceToDisconnectFrom . disconnect ( ( err : Error | undefined ) : void => {
466
463
if ( err ) {
467
464
// Show an error, however we still reset the active connection to free up the extension.
468
465
vscode . window . showErrorMessage (
@@ -471,17 +468,9 @@ export default class ConnectionController {
471
468
} else {
472
469
vscode . window . showInformationMessage ( 'MongoDB disconnected.' ) ;
473
470
}
474
-
475
- this . _activeDataService = null ;
476
- this . _currentConnectionId = null ;
477
- this . _activeConnectionModel = null ;
478
-
479
471
this . _disconnecting = false ;
480
472
this . _statusView . hideMessage ( ) ;
481
473
482
- this . eventEmitter . emit ( DataServiceEventTypes . CONNECTIONS_DID_CHANGE ) ;
483
- this . eventEmitter . emit ( DataServiceEventTypes . ACTIVE_CONNECTION_CHANGED ) ;
484
-
485
474
return resolve ( true ) ;
486
475
} ) ;
487
476
} ) ;
@@ -506,24 +495,6 @@ export default class ConnectionController {
506
495
507
496
// Prompts the user to remove the connection then removes it on affirmation.
508
497
public async removeMongoDBConnection ( connectionId : string ) : Promise < boolean > {
509
- // Ensure we aren't currently connecting.
510
- if ( this . _connecting ) {
511
- vscode . window . showErrorMessage (
512
- 'Unable to remove connection: currently connecting.'
513
- ) ;
514
-
515
- return Promise . resolve ( false ) ;
516
- }
517
-
518
- // Ensure we aren't currently disconnecting.
519
- if ( this . _disconnecting ) {
520
- vscode . window . showErrorMessage (
521
- 'Unable to remove connection: currently disconnecting.'
522
- ) ;
523
-
524
- return Promise . resolve ( false ) ;
525
- }
526
-
527
498
if ( ! this . _connections [ connectionId ] ) {
528
499
// No active connection(s) to remove.
529
500
vscode . window . showErrorMessage ( 'Connection does not exist.' ) ;
@@ -545,6 +516,11 @@ export default class ConnectionController {
545
516
await this . disconnect ( ) ;
546
517
}
547
518
519
+ if ( ! this . _connections [ connectionId ] ) {
520
+ // If the connection was removed while we were disconnecting we resolve.
521
+ return Promise . resolve ( false ) ;
522
+ }
523
+
548
524
await this . removeSavedConnection ( connectionId ) ;
549
525
550
526
vscode . window . showInformationMessage ( 'MongoDB connection removed.' ) ;
@@ -555,24 +531,6 @@ export default class ConnectionController {
555
531
public async onRemoveMongoDBConnection ( ) : Promise < boolean > {
556
532
log . info ( 'mdb.removeConnection command called' ) ;
557
533
558
- // Ensure we aren't currently connecting.
559
- if ( this . _connecting ) {
560
- vscode . window . showErrorMessage (
561
- 'Unable to remove connection: currently connecting.'
562
- ) ;
563
-
564
- return Promise . resolve ( false ) ;
565
- }
566
-
567
- // Ensure we aren't currently disconnecting.
568
- if ( this . _disconnecting ) {
569
- vscode . window . showErrorMessage (
570
- 'Unable to remove connection: currently disconnecting.'
571
- ) ;
572
-
573
- return Promise . resolve ( false ) ;
574
- }
575
-
576
534
const connectionIds = Object . keys ( this . _connections ) ;
577
535
578
536
if ( connectionIds . length === 0 ) {
@@ -591,13 +549,13 @@ export default class ConnectionController {
591
549
const connectionNameToRemove :
592
550
| string
593
551
| undefined = await vscode . window . showQuickPick (
594
- connectionIds . map (
595
- ( id , index ) => `${ index + 1 } : ${ this . _connections [ id ] . name } `
596
- ) ,
597
- {
598
- placeHolder : 'Choose a connection to remove...'
599
- }
600
- ) ;
552
+ connectionIds . map (
553
+ ( id , index ) => `${ index + 1 } : ${ this . _connections [ id ] . name } `
554
+ ) ,
555
+ {
556
+ placeHolder : 'Choose a connection to remove...'
557
+ }
558
+ ) ;
601
559
602
560
if ( ! connectionNameToRemove ) {
603
561
return Promise . resolve ( false ) ;
@@ -729,13 +687,6 @@ export default class ConnectionController {
729
687
730
688
return ! ! this . _connections [ connectionId ] ;
731
689
}
732
- public getConnectingConnectionName ( ) : string | null {
733
- if ( this . _connectingConnectionId === null ) {
734
- return null ;
735
- }
736
-
737
- return this . _connections [ this . _connectingConnectionId ] . name ;
738
- }
739
690
public getConnectingConnectionId ( ) : string | null {
740
691
return this . _connectingConnectionId ;
741
692
}
@@ -765,6 +716,11 @@ export default class ConnectionController {
765
716
this . _connecting = false ;
766
717
this . _disconnecting = false ;
767
718
this . _connectingConnectionId = '' ;
719
+ this . _connectingVersion = 0 ;
720
+ }
721
+
722
+ public getConnectingVersion ( ) : number {
723
+ return this . _connectingVersion ;
768
724
}
769
725
770
726
public setActiveConnection ( newActiveConnection : any ) : void {
0 commit comments