@@ -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