@@ -27,10 +27,12 @@ const events = [
27
27
'discarded' ,
28
28
'disconnected' ,
29
29
'loginAttempt' ,
30
+ 'logoutAttempt' ,
30
31
'networkError' ,
31
32
'offlineQueuePush' ,
32
33
'offlineQueuePop' ,
33
34
'queryError' ,
35
+ 'reAuthenticated' ,
34
36
'reconnected' ,
35
37
'reconnectionError' ,
36
38
'tokenExpired'
@@ -98,6 +100,8 @@ export class Kuzzle extends KuzzleEventEmitter {
98
100
private _tokenExpiredInterval : any ;
99
101
private _lastTokenExpired : any ;
100
102
private _cookieAuthentication : boolean ;
103
+ private _reconnectInProgress : boolean ;
104
+ private _loggedIn : boolean ;
101
105
102
106
private __proxy__ : any ;
103
107
@@ -323,6 +327,48 @@ export class Kuzzle extends KuzzleEventEmitter {
323
327
324
328
this . _lastTokenExpired = null ;
325
329
330
+ this . _reconnectInProgress = false ;
331
+
332
+ this . _loggedIn = false ;
333
+
334
+ this . on ( 'loginAttempt' , async status => {
335
+ if ( status . success ) {
336
+ this . _loggedIn = true ;
337
+ return ;
338
+ }
339
+
340
+ /**
341
+ * In case of login failure we need to be sure that the stored token is still valid
342
+ */
343
+ try {
344
+ const response = await this . auth . checkToken ( ) ;
345
+ this . _loggedIn = response . valid ;
346
+ } catch {
347
+ this . _loggedIn = false ;
348
+ }
349
+ } ) ;
350
+
351
+ /**
352
+ * When successfuly logged out
353
+ */
354
+ this . on ( 'logoutAttempt' , status => {
355
+ if ( status . success ) {
356
+ this . _loggedIn = false ;
357
+ }
358
+ } ) ;
359
+
360
+ /**
361
+ * On connection we need to verify if the token is still valid to know if we are still "logged in"
362
+ */
363
+ this . on ( 'connected' , async ( ) => {
364
+ try {
365
+ const { valid } = await this . auth . checkToken ( ) ;
366
+ this . _loggedIn = valid ;
367
+ } catch {
368
+ this . _loggedIn = false ;
369
+ }
370
+ } ) ;
371
+
326
372
return proxify ( this , {
327
373
seal : true ,
328
374
name : 'kuzzle' ,
@@ -531,31 +577,44 @@ export class Kuzzle extends KuzzleEventEmitter {
531
577
this . emit ( 'disconnected' , context ) ;
532
578
} ) ;
533
579
534
- this . protocol . addListener ( 'reconnect' , async ( ) => {
535
- if ( this . autoQueue ) {
536
- this . stopQueuing ( ) ;
537
- }
538
-
539
- // If an authenticator was set, check if the token is still valid and try
540
- // to re-authenticate if needed. Otherwise the SDK is in disconnected state.
541
- if ( this . authenticator && ! await this . tryReAuthenticate ( ) ) {
542
- this . disconnect ( ) ;
543
-
544
- return ;
545
- }
546
-
547
- if ( this . autoReplay ) {
548
- this . playQueue ( ) ;
549
- }
550
-
551
- this . emit ( 'reconnected' ) ;
552
- } ) ;
580
+ this . protocol . addListener ( 'reconnect' , this . _reconnect . bind ( this ) ) ;
553
581
554
582
this . protocol . addListener ( 'discarded' , data => this . emit ( 'discarded' , data ) ) ;
555
583
584
+ this . protocol . addListener ( 'websocketRenewalStart' , ( ) => { this . _reconnectInProgress = true ; } ) ;
585
+ this . protocol . addListener ( 'websocketRenewalDone' , ( ) => { this . _reconnectInProgress = false ; } ) ;
586
+
556
587
return this . protocol . connect ( ) ;
557
588
}
558
589
590
+ async _reconnect ( ) {
591
+ if ( this . _reconnectInProgress ) {
592
+ return ;
593
+ }
594
+
595
+ if ( this . autoQueue ) {
596
+ this . stopQueuing ( ) ;
597
+ }
598
+
599
+ // If an authenticator was set, check if a user was logged in and if the token is still valid and try
600
+ // to re-authenticate if needed. Otherwise the SDK is in disconnected state.
601
+ if ( this . _loggedIn
602
+ && this . authenticator
603
+ && ! await this . tryReAuthenticate ( )
604
+ ) {
605
+ this . _loggedIn = false ;
606
+ this . disconnect ( ) ;
607
+
608
+ return ;
609
+ }
610
+
611
+ if ( this . autoReplay ) {
612
+ this . playQueue ( ) ;
613
+ }
614
+
615
+ this . emit ( 'reconnected' ) ;
616
+ }
617
+
559
618
/**
560
619
* Try to re-authenticate the SDK if the current token is invalid.
561
620
*
@@ -567,6 +626,7 @@ export class Kuzzle extends KuzzleEventEmitter {
567
626
* This method never returns a rejected promise.
568
627
*/
569
628
private async tryReAuthenticate ( ) : Promise < boolean > {
629
+ this . _reconnectInProgress = true ;
570
630
try {
571
631
const { valid } = await this . auth . checkToken ( ) ;
572
632
@@ -584,6 +644,8 @@ export class Kuzzle extends KuzzleEventEmitter {
584
644
} ) ;
585
645
586
646
return false ;
647
+ } finally {
648
+ this . _reconnectInProgress = false ;
587
649
}
588
650
}
589
651
@@ -601,6 +663,8 @@ export class Kuzzle extends KuzzleEventEmitter {
601
663
602
664
const { valid } = await this . auth . checkToken ( ) ;
603
665
666
+ this . _loggedIn = valid ;
667
+
604
668
if ( ! valid ) {
605
669
throw new Error ( 'The "authenticator" function failed to authenticate the SDK.' ) ;
606
670
}
@@ -639,6 +703,7 @@ export class Kuzzle extends KuzzleEventEmitter {
639
703
* Disconnects from Kuzzle and invalidate this instance.
640
704
*/
641
705
disconnect ( ) {
706
+ this . _loggedIn = false ;
642
707
this . protocol . close ( ) ;
643
708
}
644
709
@@ -769,7 +834,17 @@ Discarded request: ${JSON.stringify(request)}`));
769
834
* On token expiration, reset jwt and unsubscribe all rooms.
770
835
* Throttles to avoid duplicate event triggers.
771
836
*/
772
- tokenExpired ( ) {
837
+ async tokenExpired ( ) {
838
+ if ( this . _reconnectInProgress ) {
839
+ return ;
840
+ }
841
+
842
+ if ( this . _loggedIn && this . authenticator && await this . tryReAuthenticate ( ) ) {
843
+ this . emit ( 'reAuthenticated' ) ;
844
+
845
+ return ;
846
+ }
847
+
773
848
const now = Date . now ( ) ;
774
849
775
850
if ( ( now - this . _lastTokenExpired ) < this . tokenExpiredInterval ) {
0 commit comments