@@ -17,6 +17,7 @@ import { checkWebCryptoAPISupported } from './webCryptoAPI.js';
1717import {
1818 getNormalisedTopicRequests ,
1919 PRIVATE_CHANNELS ,
20+ PUBLIC_CHANNELS_WITH_AUTH ,
2021 safeTerminateWs ,
2122 WS_LOGGER_CATEGORY ,
2223 WsTopicRequest ,
@@ -216,7 +217,10 @@ export abstract class BaseWebsocketClient<
216217
217218 protected abstract isWsPong ( data : any ) : boolean ;
218219
219- protected abstract getWsAuthRequestEvent ( wsKey : TWSKey ) : Promise < object > ;
220+ protected abstract getWsAuthRequestEvent (
221+ wsKey : TWSKey ,
222+ skipPublicWsKeyCheck : boolean ,
223+ ) : Promise < object | null > ;
220224
221225 protected abstract isPrivateTopicRequest (
222226 request : WsTopicRequest < string > ,
@@ -339,7 +343,11 @@ export abstract class BaseWebsocketClient<
339343 // Queue immediate auth if so
340344 for ( const topicRequest of normalisedTopicRequests ) {
341345 if ( PRIVATE_CHANNELS . includes ( topicRequest . topic ) ) {
342- await this . assertIsAuthenticated ( wsKey ) ;
346+ await this . assertIsAuthenticated ( wsKey , false ) ;
347+ break ;
348+ }
349+ if ( PUBLIC_CHANNELS_WITH_AUTH . includes ( topicRequest . topic ) ) {
350+ await this . assertIsAuthenticated ( wsKey , true ) ;
343351 break ;
344352 }
345353 }
@@ -449,6 +457,37 @@ export abstract class BaseWebsocketClient<
449457 } ) ;
450458 }
451459
460+ /**
461+ * Closes a connection, if it's even open. If open, this will trigger a reconnect asynchronously.
462+ * If closed, trigger a reconnect immediately
463+ */
464+ public executeReconnectableClose ( wsKey : TWSKey , reason : string ) {
465+ this . logger . info ( `${ reason } - closing socket to reconnect` , {
466+ ...WS_LOGGER_CATEGORY ,
467+ wsKey,
468+ reason,
469+ } ) ;
470+
471+ this . clearTimers ( wsKey ) ;
472+
473+ const wasOpen = this . wsStore . isWsOpen ( wsKey ) ;
474+ if ( wasOpen ) {
475+ safeTerminateWs ( this . wsStore . getWs ( wsKey ) , true ) ;
476+ }
477+
478+ if ( ! wasOpen ) {
479+ this . logger . info (
480+ `${ reason } - socket already closed - trigger immediate reconnect` ,
481+ {
482+ ...WS_LOGGER_CATEGORY ,
483+ wsKey,
484+ reason,
485+ } ,
486+ ) ;
487+ this . reconnectWithDelay ( wsKey , this . options . reconnectTimeout ) ;
488+ }
489+ }
490+
452491 public isConnected ( wsKey : TWSKey ) : boolean {
453492 return this . wsStore . isConnectionState (
454493 wsKey ,
@@ -568,7 +607,10 @@ export abstract class BaseWebsocketClient<
568607 }
569608
570609 /** Get a signature, build the auth request and send it */
571- private async sendAuthRequest ( wsKey : TWSKey ) : Promise < unknown > {
610+ private async sendAuthRequest (
611+ wsKey : TWSKey ,
612+ skipPublicWsKeyCheck : boolean ,
613+ ) : Promise < unknown > {
572614 try {
573615 this . logger . trace ( 'Sending auth request...' , {
574616 ...WS_LOGGER_CATEGORY ,
@@ -577,19 +619,22 @@ export abstract class BaseWebsocketClient<
577619
578620 await this . assertIsConnected ( wsKey ) ;
579621
622+ const request = await this . getWsAuthRequestEvent (
623+ wsKey ,
624+ skipPublicWsKeyCheck ,
625+ ) ;
626+
580627 if ( ! this . wsStore . getAuthenticationInProgressPromise ( wsKey ) ) {
581628 this . wsStore . createAuthenticationInProgressPromise ( wsKey , false ) ;
582629 }
583630
584- const request = await this . getWsAuthRequestEvent ( wsKey ) ;
585-
586631 // console.log('ws auth req', request);
587632
588633 this . tryWsSend ( wsKey , JSON . stringify ( request ) ) ;
589634
590635 return this . wsStore . getAuthenticationInProgressPromise ( wsKey ) ?. promise ;
591636 } catch ( e ) {
592- this . logger . trace ( e , { ...WS_LOGGER_CATEGORY , wsKey } ) ;
637+ this . logger . error ( e , { ...WS_LOGGER_CATEGORY , wsKey } ) ;
593638 }
594639 }
595640
@@ -919,12 +964,22 @@ export abstract class BaseWebsocketClient<
919964 this . isAuthOnConnectWsKey ( wsKey ) &&
920965 this . options . authPrivateConnectionsOnConnect
921966 ) {
922- await this . assertIsAuthenticated ( wsKey ) ;
967+ await this . assertIsAuthenticated ( wsKey , false ) ;
968+ }
969+
970+ const topicsForWsKey = [ ...this . wsStore . getTopics ( wsKey ) ] ;
971+
972+ // Guard to assert auth for some of the public topics that require it
973+ for ( const topicRequest of topicsForWsKey ) {
974+ if ( PUBLIC_CHANNELS_WITH_AUTH . includes ( topicRequest . topic ) ) {
975+ await this . assertIsAuthenticated ( wsKey , true ) ;
976+ break ;
977+ }
923978 }
924979
925980 // Reconnect to topics known before it connected
926981 const { privateReqs, publicReqs } = this . sortTopicRequestsIntoPublicPrivate (
927- [ ... this . wsStore . getTopics ( wsKey ) ] ,
982+ topicsForWsKey ,
928983 wsKey ,
929984 ) ;
930985
@@ -1206,7 +1261,10 @@ export abstract class BaseWebsocketClient<
12061261 /**
12071262 * Promise-driven method to assert that a ws has been successfully authenticated (will await until auth is confirmed)
12081263 */
1209- public async assertIsAuthenticated ( wsKey : TWSKey ) : Promise < unknown > {
1264+ public async assertIsAuthenticated (
1265+ wsKey : TWSKey ,
1266+ skipPublicWsKeyCheck : boolean ,
1267+ ) : Promise < unknown > {
12101268 const isConnected = this . getWsStore ( ) . isConnectionState (
12111269 wsKey ,
12121270 WsConnectionStateEnum . CONNECTED ,
@@ -1237,7 +1295,7 @@ export abstract class BaseWebsocketClient<
12371295 // Start authentication, it should automatically store/return a promise.
12381296 this . logger . trace ( 'assertIsAuthenticated(): authenticating...' ) ;
12391297
1240- await this . sendAuthRequest ( wsKey ) ;
1298+ await this . sendAuthRequest ( wsKey , skipPublicWsKeyCheck ) ;
12411299
12421300 this . logger . trace ( 'assertIsAuthenticated(): newly authenticated!' ) ;
12431301 }
0 commit comments