@@ -27,10 +27,12 @@ const events = [
2727 'discarded' ,
2828 'disconnected' ,
2929 'loginAttempt' ,
30+ 'logoutAttempt' ,
3031 'networkError' ,
3132 'offlineQueuePush' ,
3233 'offlineQueuePop' ,
3334 'queryError' ,
35+ 'reAuthenticated' ,
3436 'reconnected' ,
3537 'reconnectionError' ,
3638 'tokenExpired'
@@ -98,6 +100,8 @@ export class Kuzzle extends KuzzleEventEmitter {
98100 private _tokenExpiredInterval : any ;
99101 private _lastTokenExpired : any ;
100102 private _cookieAuthentication : boolean ;
103+ private _reconnectInProgress : boolean ;
104+ private _loggedIn : boolean ;
101105
102106 private __proxy__ : any ;
103107
@@ -323,6 +327,48 @@ export class Kuzzle extends KuzzleEventEmitter {
323327
324328 this . _lastTokenExpired = null ;
325329
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+
326372 return proxify ( this , {
327373 seal : true ,
328374 name : 'kuzzle' ,
@@ -531,31 +577,44 @@ export class Kuzzle extends KuzzleEventEmitter {
531577 this . emit ( 'disconnected' , context ) ;
532578 } ) ;
533579
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 ) ) ;
553581
554582 this . protocol . addListener ( 'discarded' , data => this . emit ( 'discarded' , data ) ) ;
555583
584+ this . protocol . addListener ( 'websocketRenewalStart' , ( ) => { this . _reconnectInProgress = true ; } ) ;
585+ this . protocol . addListener ( 'websocketRenewalDone' , ( ) => { this . _reconnectInProgress = false ; } ) ;
586+
556587 return this . protocol . connect ( ) ;
557588 }
558589
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+
559618 /**
560619 * Try to re-authenticate the SDK if the current token is invalid.
561620 *
@@ -567,6 +626,7 @@ export class Kuzzle extends KuzzleEventEmitter {
567626 * This method never returns a rejected promise.
568627 */
569628 private async tryReAuthenticate ( ) : Promise < boolean > {
629+ this . _reconnectInProgress = true ;
570630 try {
571631 const { valid } = await this . auth . checkToken ( ) ;
572632
@@ -584,6 +644,8 @@ export class Kuzzle extends KuzzleEventEmitter {
584644 } ) ;
585645
586646 return false ;
647+ } finally {
648+ this . _reconnectInProgress = false ;
587649 }
588650 }
589651
@@ -601,6 +663,8 @@ export class Kuzzle extends KuzzleEventEmitter {
601663
602664 const { valid } = await this . auth . checkToken ( ) ;
603665
666+ this . _loggedIn = valid ;
667+
604668 if ( ! valid ) {
605669 throw new Error ( 'The "authenticator" function failed to authenticate the SDK.' ) ;
606670 }
@@ -639,6 +703,7 @@ export class Kuzzle extends KuzzleEventEmitter {
639703 * Disconnects from Kuzzle and invalidate this instance.
640704 */
641705 disconnect ( ) {
706+ this . _loggedIn = false ;
642707 this . protocol . close ( ) ;
643708 }
644709
@@ -769,7 +834,17 @@ Discarded request: ${JSON.stringify(request)}`));
769834 * On token expiration, reset jwt and unsubscribe all rooms.
770835 * Throttles to avoid duplicate event triggers.
771836 */
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+
773848 const now = Date . now ( ) ;
774849
775850 if ( ( now - this . _lastTokenExpired ) < this . tokenExpiredInterval ) {
0 commit comments