@@ -453,6 +453,7 @@ module.exports = (() => {
453453
454454} , { "./../../../lib/connection/Connection" :2 , "./../../../lib/marketState/Profile" :20 , "./../../../lib/meta" :22 , "./../../../lib/utilities/data/AssetClass" :27 , "./../../../lib/utilities/data/timezones" :29 , "./../../../lib/utilities/format/decimal" :31 , "./../../../lib/utilities/format/price" :34 , "./../../../lib/utilities/format/quote" :35 , "./../../../lib/utilities/format/specialized/cmdtyView" :36 } ] , 2 :[ function ( require , module , exports ) { 
455455const  array  =  require ( '@barchart/common-js/lang/array' ) , 
456+   assert  =  require ( '@barchart/common-js/lang/assert' ) , 
456457  object  =  require ( '@barchart/common-js/lang/object' ) ; 
457458const  ConnectionBase  =  require ( './ConnectionBase' ) , 
458459  parseMessage  =  require ( './../utilities/parse/ddf/message' ) ; 
@@ -468,6 +469,10 @@ module.exports = (() => {
468469  'use strict' ; 
469470
470471  const  _API_VERSION  =  4 ; 
472+   const  mode  =  { 
473+     credentials : 'credentials' , 
474+     token : 'token' 
475+   } ; 
471476  const  state  =  { 
472477    connecting : 'CONNECTING' , 
473478    authenticating : 'LOGGING_IN' , 
@@ -499,6 +504,8 @@ module.exports = (() => {
499504  } ; 
500505  const  _RECONNECT_INTERVAL  =  5000 ; 
501506  const  _WATCHDOG_INTERVAL  =  10000 ; 
507+   const  regex  =  { } ; 
508+   regex . hostname  =  / ^ (?: ( w s s | w s ) : \/ \/ ) ? ( .+ ?) (?: : ( \d + ) ) ? $ / i; 
502509  function  ConnectionInternal ( marketState ,  instance )  { 
503510    const  __logger  =  LoggerFactory . getLogger ( '@barchart/marketdata-api-js' ) ; 
504511    const  __instance  =  instance ; 
@@ -508,6 +515,7 @@ module.exports = (() => {
508515    let  __xmlParser  =  null ; 
509516    let  __connection  =  null ; 
510517    let  __connectionState  =  state . disconnected ; 
518+     let  __connectionCount  =  0 ; 
511519    let  __paused  =  false ; 
512520    let  __reconnectAllowed  =  false ; 
513521    let  __pollingFrequency  =  null ; 
@@ -532,9 +540,12 @@ module.exports = (() => {
532540      timestamp : [ ] 
533541    } ; 
534542    const  __loginInfo  =  { 
543+       mode : null , 
535544      hostname : null , 
536545      username : null , 
537-       password : null 
546+       password : null , 
547+       jwtProvider : null , 
548+       jwtPromise : null 
538549    } ; 
539550    let  __decoder  =  null ; 
540551    let  __diagnosticsController  =  null ; 
@@ -585,16 +596,17 @@ module.exports = (() => {
585596     * 
586597     * @private  
587598     * @param  {String } hostname 
588-      * @param  {String } username 
589-      * @param  {String } password 
599+      * @param  {String=  } username 
600+      * @param  {String=  } password 
590601     * @param  {WebSocketAdapterFactory } webSocketAdapterFactory 
591602     * @param  {XmlParserFactory } xmlParserFactory 
603+      * @param  {Callbacks.JwtProvider } jwtProvider 
592604     */ 
593-     function  initializeConnection ( hostname ,  username ,  password ,  webSocketAdapterFactory ,  xmlParserFactory )  { 
605+     function  initializeConnection ( hostname ,  username ,  password ,  webSocketAdapterFactory ,  xmlParserFactory ,   jwtProvider )  { 
594606      __connectionFactory  =  webSocketAdapterFactory ; 
595607      __xmlParserFactory  =  xmlParserFactory ; 
596608      __reconnectAllowed  =  true ; 
597-       connect ( hostname ,  username ,  password ) ; 
609+       connect ( hostname ,  username ,  password ,   jwtProvider ) ; 
598610    } 
599611
600612    /** 
@@ -608,9 +620,12 @@ module.exports = (() => {
608620        event : 'disconnecting' 
609621      } ) ; 
610622      __reconnectAllowed  =  false ; 
623+       __loginInfo . mode  =  null ; 
624+       __loginInfo . hostname  =  null ; 
611625      __loginInfo . username  =  null ; 
612626      __loginInfo . password  =  null ; 
613-       __loginInfo . hostname  =  null ; 
627+       __loginInfo . jwtProvider  =  null ; 
628+       __loginInfo . jwtPromise  =  null ; 
614629      __knownConsumerSymbols  =  { } ; 
615630      __pendingProfileSymbols  =  { } ; 
616631      __listeners . marketDepth  =  { } ; 
@@ -622,45 +637,104 @@ module.exports = (() => {
622637      disconnect ( ) ; 
623638    } 
624639
640+     /** 
641+      * Attempts to read a JWT from an external provider. 
642+      * 
643+      * @private  
644+      * @param  {Callbacks.JwtProvider } jwtProvider 
645+      * @returns  {Promise<string|null> } 
646+      */ 
647+     function  getJwt ( jwtProvider )  { 
648+       const  connectionCount  =  __connectionCount ; 
649+       return  Promise . resolve ( ) . then ( ( )  =>  { 
650+         __logger . log ( `Connection [ ${ __instance }   ]: Requesting JWT for connection attempt [ ${ connectionCount }   ].` ) ; 
651+         return  jwtProvider ( ) ; 
652+       } ) . then ( jwt  =>  { 
653+         __logger . log ( `Connection [ ${ __instance }   ]: Request for JWT was successful for connection attempt [ ${ connectionCount }   ].` ) ; 
654+         if  ( __connectionCount  !==  connectionCount )  { 
655+           return  null ; 
656+         } 
657+         if  ( typeof  jwt  !==  'string' )  { 
658+           __logger . warn ( `Connection [ ${ __instance }   ]: Unable to extract JWT.` ) ; 
659+           return  null ; 
660+         } 
661+         return  jwt ; 
662+       } ) . catch ( e  =>  { 
663+         __logger . warn ( `Connection [ ${ __instance }   ]: Request for JWT failed for connection attempt [ ${ connectionCount }   ].` ) ; 
664+         return  null ; 
665+       } ) ; 
666+     } 
667+ 
625668    /** 
626669     * Attempts to establish a connection to JERQ. 
627670     * 
628671     * @private  
629672     * @param  {String } hostname 
630-      * @param  {String } username 
631-      * @param  {String } password 
632-      */ 
633-     function  connect ( hostname ,  username ,  password )  { 
634-       if  ( ! hostname )  { 
635-         throw  new  Error ( 'Unable to connect, the "hostname" argument is required.' ) ; 
636-       } 
637-       if  ( ! username )  { 
673+      * @param  {String= } username 
674+      * @param  {String= } password 
675+      * @param  {Callbacks.JwtProvider= } jwtProvider 
676+      */ 
677+     function  connect ( hostname ,  username ,  password ,  jwtProvider )  { 
678+       assert . argumentIsRequired ( hostname ,  'hostname' ,  String ) ; 
679+       assert . argumentIsOptional ( username ,  'username' ,  String ) ; 
680+       assert . argumentIsOptional ( password ,  'password' ,  String ) ; 
681+       assert . argumentIsOptional ( jwtProvider ,  'jwtProvider' ,  Function ) ; 
682+       if  ( ! username  &&  ! jwtProvider )  { 
638683        throw  new  Error ( 'Unable to connect, the "username" argument is required.' ) ; 
639684      } 
640-       if  ( ! password )  { 
685+       if  ( ! password   &&   ! jwtProvider )  { 
641686        throw  new  Error ( 'Unable to connect, the "password" argument is required.' ) ; 
642687      } 
643688      if  ( __connection  !==  null )  { 
644689        __logger . warn ( `Connection [ ${ __instance }   ]: Unable to connect, a connection already exists.` ) ; 
645690        return ; 
646691      } 
647692      ensureExchangeMetadata ( ) ; 
648-       __logger . log ( `Connection [  ${ __instance }  ]: Initializing. Version [  ${ version }  ]. Using [  ${ username } @ ${ hostname }  ].` ) ; 
649-       __xmlParser   =   __xmlParserFactory . build ( ) ; 
693+       __connectionCount   =   __connectionCount   +   1 ; 
694+       __logger . log ( `Connection [  ${ __instance }  ]: Starting connection attempt [  ${ __connectionCount }  ] using [  ${ jwtProvider  ?  'JWT'  :  'credentials-based' }  ] authentication.` ) ; 
650695      let  protocol ; 
696+       let  host ; 
651697      let  port ; 
652698      if  ( hostname  ===  'localhost' )  { 
653699        protocol  =  'ws' ; 
700+         host  =  'localhost' ; 
654701        port  =  8080 ; 
655702      }  else  { 
656-         protocol  =  'wss' ; 
657-         port  =  443 ; 
703+         const  match  =  hostname . match ( regex . hostname ) ; 
704+         if  ( match  !==  null  &&  match [ 1 ] )  { 
705+           protocol  =  match [ 1 ] ; 
706+         }  else  { 
707+           protocol  =  'wss' ; 
708+         } 
709+         if  ( match  !==  null  &&  match [ 2 ] )  { 
710+           host  =  match [ 2 ] ; 
711+         }  else  { 
712+           host  =  hostname ; 
713+         } 
714+         if  ( match  !==  null  &&  match [ 3 ] )  { 
715+           port  =  parseInt ( match [ 3 ] ) ; 
716+         }  else  { 
717+           port  =  protocol  ===  'ws'  ? 80  : 443 ; 
718+         } 
658719      } 
659-       __loginInfo . username  =  username ; 
660-       __loginInfo . password  =  password ; 
661720      __loginInfo . hostname  =  hostname ; 
721+       __loginInfo . username  =  null ; 
722+       __loginInfo . password  =  null ; 
723+       __loginInfo . jwtProvider  =  null ; 
724+       __loginInfo . jwtPromise  =  null ; 
725+       if  ( jwtProvider )  { 
726+         __loginInfo . mode  =  mode . token ; 
727+         __loginInfo . jwtProvider  =  jwtProvider ; 
728+         __loginInfo . jwtPromise  =  getJwt ( jwtProvider ) ; 
729+       }  else  { 
730+         __loginInfo . mode  =  mode . credentials ; 
731+         __loginInfo . username  =  username ; 
732+         __loginInfo . password  =  password ; 
733+       } 
734+       __xmlParser  =  __xmlParserFactory . build ( ) ; 
662735      __connectionState  =  state . disconnected ; 
663-       __connection  =  __connectionFactory . build ( `${ protocol }  ://${ __loginInfo . hostname }  :${ port }  /jerq` ) ; 
736+       __logger . log ( `Connection [ ${ __instance }   ]: Opening connection to [ ${ protocol }  ://${ host }  :${ port }   ].` ) ; 
737+       __connection  =  __connectionFactory . build ( `${ protocol }  ://${ host }  :${ port }  /jerq` ) ; 
664738      __connection . binaryType  =  'arraybuffer' ; 
665739      __decoder  =  __connection . getDecoder ( ) ; 
666740      __connection . onopen  =  ( )  =>  { 
@@ -708,7 +782,7 @@ module.exports = (() => {
708782        } 
709783        if  ( __reconnectAllowed )  { 
710784          __logger . log ( `Connection [ ${ __instance }   ]: Scheduling reconnect attempt.` ) ; 
711-           const  reconnectAction  =  ( )  =>  connect ( __loginInfo . hostname ,  __loginInfo . username ,  __loginInfo . password ) ; 
785+           const  reconnectAction  =  ( )  =>  connect ( __loginInfo . hostname ,  __loginInfo . username ,  __loginInfo . password ,   __loginInfo . jwtProvider ) ; 
712786          const  reconnectDelay  =  _RECONNECT_INTERVAL  +  Math . floor ( Math . random ( )  *  _WATCHDOG_INTERVAL ) ; 
713787          setTimeout ( reconnectAction ,  reconnectDelay ) ; 
714788        } 
@@ -1145,8 +1219,31 @@ module.exports = (() => {
11451219        } 
11461220        if  ( lines . some ( line  =>  line  ===  '+++' ) )  { 
11471221          __connectionState  =  state . authenticating ; 
1148-           __logger . log ( `Connection [ ${ __instance }   ]: Sending credentials.` ) ; 
1149-           __connection . send ( `LOGIN ${ __loginInfo . username }  :${ __loginInfo . password }   VERSION=${ _API_VERSION }  \r\n` ) ; 
1222+           let  connectionCount  =  __connectionCount ; 
1223+           if  ( __loginInfo . mode  ===  mode . credentials )  { 
1224+             __connection . send ( `LOGIN ${ __loginInfo . username }  :${ __loginInfo . password }   VERSION=${ _API_VERSION }  \r\n` ) ; 
1225+             return ; 
1226+           } 
1227+           if  ( __loginInfo . mode  ===  mode . token )  { 
1228+             const  jwtPromise  =  __loginInfo . jwtPromise  ||  Promise . resolve ( null ) ; 
1229+             jwtPromise . then ( jwt  =>  { 
1230+               if  ( __connectionCount  !==  connectionCount )  { 
1231+                 return ; 
1232+               } 
1233+               if  ( __connectionState  !==  state . authenticating )  { 
1234+                 return ; 
1235+               } 
1236+               if  ( jwt  ===  null )  { 
1237+                 broadcastEvent ( 'events' ,  { 
1238+                   event : 'jwt acquisition failed' 
1239+                 } ) ; 
1240+                 disconnect ( ) ; 
1241+                 return ; 
1242+               } 
1243+               __connection . send ( `TOKEN ${ jwt }   VERSION=${ _API_VERSION }  \r\n` ) ; 
1244+             } ) ; 
1245+             return ; 
1246+           } 
11501247        } 
11511248      }  else  if  ( __connectionState  ===  state . authenticating )  { 
11521249        const  lines  =  message . split ( '\n' ) ; 
@@ -2028,7 +2125,7 @@ module.exports = (() => {
20282125      this . _internal  =  ConnectionInternal ( this . getMarketState ( ) ,  this . _getInstance ( ) ) ; 
20292126    } 
20302127    _connect ( webSocketAdapterFactory ,  xmlParserFactory )  { 
2031-       this . _internal . connect ( this . getHostname ( ) ,  this . getUsername ( ) ,  this . getPassword ( ) ,  webSocketAdapterFactory ,  xmlParserFactory ) ; 
2128+       this . _internal . connect ( this . getHostname ( ) ,  this . getUsername ( ) ,  this . getPassword ( ) ,  webSocketAdapterFactory ,  xmlParserFactory ,   this . getJwtProvider ( ) ) ; 
20322129    } 
20332130    _disconnect ( )  { 
20342131      this . _internal . disconnect ( ) ; 
@@ -2070,7 +2167,7 @@ module.exports = (() => {
20702167  return  Connection ; 
20712168} ) ( ) ; 
20722169
2073- } , { "./../logging/LoggerFactory" :15 , "./../meta" :22 , "./../utilities/parse/ddf/message" :38 , "./../utilities/parsers/SymbolParser" :41 , "./ConnectionBase" :3 , "./diagnostics/DiagnosticsControllerBase" :7 , "./snapshots/exchanges/retrieveExchanges" :8 , "./snapshots/profiles/retrieveExtensions" :9 , "./snapshots/quotes/retrieveExtensions" :10 , "./snapshots/quotes/retrieveSnapshots" :11 , "@barchart/common-js/lang/array" :51 , "@barchart/common-js/lang/object" :54 } ] , 3 :[ function ( require , module , exports ) { 
2170+ } , { "./../logging/LoggerFactory" :15 , "./../meta" :22 , "./../utilities/parse/ddf/message" :38 , "./../utilities/parsers/SymbolParser" :41 , "./ConnectionBase" :3 , "./diagnostics/DiagnosticsControllerBase" :7 , "./snapshots/exchanges/retrieveExchanges" :8 , "./snapshots/profiles/retrieveExtensions" :9 , "./snapshots/quotes/retrieveExtensions" :10 , "./snapshots/quotes/retrieveSnapshots" :11 , "@barchart/common-js/lang/array" :51 , "@barchart/common-js/lang/assert"  : 52 , "@barchart/common-js/lang/ object" :54 } ] , 3 :[ function ( require , module , exports ) { 
20742171const  is  =  require ( '@barchart/common-js/lang/is' ) ; 
20752172const  Environment  =  require ( './../environment/Environment' ) , 
20762173  EnvironmentForBrowsers  =  require ( './../environment/EnvironmentForBrowsers' ) ; 
@@ -2094,6 +2191,7 @@ module.exports = (() => {
20942191      this . _hostname  =  null ; 
20952192      this . _username  =  null ; 
20962193      this . _password  =  null ; 
2194+       this . _jwtProvider  =  null ; 
20972195      this . _environment  =  environment  ||  new  EnvironmentForBrowsers ( ) ; 
20982196      this . _marketState  =  new  MarketState ( symbol  =>  this . _handleProfileRequest ( symbol ) ) ; 
20992197      this . _pollingFrequency  =  null ; 
@@ -2110,15 +2208,17 @@ module.exports = (() => {
21102208     * 
21112209     * @public  
21122210     * @param  {string } hostname - Barchart hostname (contact [email protected] ) 2113-      * @param  {string } username - Your username (contact [email protected] ) 2114-      * @param  {string } password - Your password (contact [email protected] ) 2211+      * @param  {string=  } username - Your username (contact [email protected] ) 2212+      * @param  {string=  } password - Your password (contact [email protected] ) 21152213     * @param  {WebSocketAdapterFactory= } webSocketAdapterFactory - Strategy for creating a {@link  WebSocketAdapterFactory} instances (overrides {@link  Environment} settings). 
21162214     * @param  {XmlParserFactory= } xmlParserFactory - Strategy for creating a {@link  WebSocketAdapterFactory} instances (overrides {@link  Environment} settings). 
2215+      * @param  {Callbacks.JwtProvider= } jwtProvider - A function which returns a JWT (or a promise for a JWT) that is used as an alternative for actual credentials. 
21172216     */ 
2118-     connect ( hostname ,  username ,  password ,  webSocketAdapterFactory ,  xmlParserFactory )  { 
2217+     connect ( hostname ,  username ,  password ,  webSocketAdapterFactory ,  xmlParserFactory ,   jwtProvider )  { 
21192218      this . _hostname  =  hostname ; 
2120-       this . _username  =  username ; 
2121-       this . _password  =  password ; 
2219+       this . _username  =  username  ||  null ; 
2220+       this . _password  =  password  ||  null ; 
2221+       this . _jwtProvider  =  jwtProvider  ||  null ; 
21222222      this . _connect ( webSocketAdapterFactory  ||  this . _environment . getWebSocketAdapterFactory ( ) ,  xmlParserFactory  ||  this . _environment . getXmlParserFactory ( ) ) ; 
21232223    } 
21242224
@@ -2142,6 +2242,7 @@ module.exports = (() => {
21422242      this . _hostname  =  null ; 
21432243      this . _username  =  null ; 
21442244      this . _password  =  null ; 
2245+       this . _jwtProvider  =  null ; 
21452246      this . _disconnect ( ) ; 
21462247    } 
21472248
@@ -2428,6 +2529,16 @@ module.exports = (() => {
24282529      return  this . _username ; 
24292530    } 
24302531
2532+     /** 
2533+      * The username used to authenticate to Barchart. 
2534+      * 
2535+      * @public  
2536+      * @returns  {null|Callbacks.JwtProvider } 
2537+      */ 
2538+     getJwtProvider ( )  { 
2539+       return  this . _jwtProvider ; 
2540+     } 
2541+ 
24312542    /** 
24322543     * Gets a unique identifier for the current instance. 
24332544     * 
@@ -5309,7 +5420,7 @@ module.exports = (() => {
53095420  'use strict' ; 
53105421
53115422  return  { 
5312-     version : '6.2.6 ' 
5423+     version : '6.3.0 ' 
53135424  } ; 
53145425} ) ( ) ; 
53155426
0 commit comments