Skip to content

Commit 0061a26

Browse files
committed
Release. Bump version number
1 parent ae93a33 commit 0061a26

File tree

4 files changed

+147
-36
lines changed

4 files changed

+147
-36
lines changed

docs/_coverpage.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# Barchart Market Data SDK <small>JavaScript 6.2.6</small>
1+
# Barchart Market Data SDK <small>JavaScript 6.3.0</small>
22

33
> Inject real-time market data into your JavaScript applications
44

example/browser/example.js

Lines changed: 144 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -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){
455455
const array = require('@barchart/common-js/lang/array'),
456+
assert = require('@barchart/common-js/lang/assert'),
456457
object = require('@barchart/common-js/lang/object');
457458
const 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 = /^(?:(wss|ws):\/\/)?(.+?)(?::(\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){
20742171
const is = require('@barchart/common-js/lang/is');
20752172
const 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

lib/meta.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,6 @@ module.exports = (() => {
22
'use strict';
33

44
return {
5-
version: '6.2.6'
5+
version: '6.3.0'
66
};
77
})();

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@barchart/marketdata-api-js",
3-
"version": "6.2.6",
3+
"version": "6.3.0",
44
"description": "SDK for streaming market data from Barchart.com",
55
"author": {
66
"name": "Eero Pikat",

0 commit comments

Comments
 (0)