binbot-charts 0.0.21 → 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/components/TVChartContainer.js +41 -77
- package/dist/components/datafeed.js +131 -100
- package/dist/components/streaming.js +1 -1
- package/package.json +5 -4
- package/dist/datafeeds/README.md +0 -3
- package/dist/datafeeds/udf/README.md +0 -46
- package/dist/datafeeds/udf/dist/bundle.js +0 -1
- package/dist/datafeeds/udf/lib/data-pulse-provider.js +0 -104
- package/dist/datafeeds/udf/lib/helpers.js +0 -20
- package/dist/datafeeds/udf/lib/history-provider.js +0 -73
- package/dist/datafeeds/udf/lib/iquotes-provider.js +0 -1
- package/dist/datafeeds/udf/lib/quotes-provider.js +0 -25
- package/dist/datafeeds/udf/lib/quotes-pulse-provider.js +0 -44
- package/dist/datafeeds/udf/lib/requester.js +0 -28
- package/dist/datafeeds/udf/lib/symbols-storage.js +0 -180
- package/dist/datafeeds/udf/lib/udf-compatible-datafeed-base.js +0 -252
- package/dist/datafeeds/udf/lib/udf-compatible-datafeed.js +0 -10
- package/dist/datafeeds/udf/package.json +0 -17
- package/dist/datafeeds/udf/rollup.config.js +0 -25
- package/dist/datafeeds/udf/src/data-pulse-provider.ts +0 -152
- package/dist/datafeeds/udf/src/helpers.ts +0 -38
- package/dist/datafeeds/udf/src/history-provider.ts +0 -134
- package/dist/datafeeds/udf/src/iquotes-provider.ts +0 -14
- package/dist/datafeeds/udf/src/quotes-provider.ts +0 -37
- package/dist/datafeeds/udf/src/quotes-pulse-provider.ts +0 -85
- package/dist/datafeeds/udf/src/requester.ts +0 -39
- package/dist/datafeeds/udf/src/symbols-storage.ts +0 -298
- package/dist/datafeeds/udf/src/udf-compatible-datafeed-base.ts +0 -369
- package/dist/datafeeds/udf/src/udf-compatible-datafeed.ts +0 -11
- package/dist/datafeeds/udf/tsconfig.json +0 -25
|
@@ -1,152 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
LibrarySymbolInfo,
|
|
3
|
-
SubscribeBarsCallback,
|
|
4
|
-
} from '../../../charting_library/datafeed-api';
|
|
5
|
-
|
|
6
|
-
import {
|
|
7
|
-
GetBarsResult,
|
|
8
|
-
HistoryProvider,
|
|
9
|
-
} from './history-provider';
|
|
10
|
-
|
|
11
|
-
import {
|
|
12
|
-
getErrorMessage,
|
|
13
|
-
logMessage,
|
|
14
|
-
} from './helpers';
|
|
15
|
-
|
|
16
|
-
interface DataSubscriber {
|
|
17
|
-
symbolInfo: LibrarySymbolInfo;
|
|
18
|
-
resolution: string;
|
|
19
|
-
lastBarTime: number | null;
|
|
20
|
-
listener: SubscribeBarsCallback;
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
interface DataSubscribers {
|
|
24
|
-
[guid: string]: DataSubscriber;
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
export class DataPulseProvider {
|
|
28
|
-
private readonly _subscribers: DataSubscribers = {};
|
|
29
|
-
private _requestsPending: number = 0;
|
|
30
|
-
private readonly _historyProvider: HistoryProvider;
|
|
31
|
-
|
|
32
|
-
public constructor(historyProvider: HistoryProvider, updateFrequency: number) {
|
|
33
|
-
this._historyProvider = historyProvider;
|
|
34
|
-
setInterval(this._updateData.bind(this), updateFrequency);
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
public subscribeBars(symbolInfo: LibrarySymbolInfo, resolution: string, newDataCallback: SubscribeBarsCallback, listenerGuid: string): void {
|
|
38
|
-
if (this._subscribers.hasOwnProperty(listenerGuid)) {
|
|
39
|
-
logMessage(`DataPulseProvider: already has subscriber with id=${listenerGuid}`);
|
|
40
|
-
return;
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
this._subscribers[listenerGuid] = {
|
|
44
|
-
lastBarTime: null,
|
|
45
|
-
listener: newDataCallback,
|
|
46
|
-
resolution: resolution,
|
|
47
|
-
symbolInfo: symbolInfo,
|
|
48
|
-
};
|
|
49
|
-
|
|
50
|
-
logMessage(`DataPulseProvider: subscribed for #${listenerGuid} - {${symbolInfo.name}, ${resolution}}`);
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
public unsubscribeBars(listenerGuid: string): void {
|
|
54
|
-
delete this._subscribers[listenerGuid];
|
|
55
|
-
logMessage(`DataPulseProvider: unsubscribed for #${listenerGuid}`);
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
private _updateData(): void {
|
|
59
|
-
if (this._requestsPending > 0) {
|
|
60
|
-
return;
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
this._requestsPending = 0;
|
|
64
|
-
for (const listenerGuid in this._subscribers) { // tslint:disable-line:forin
|
|
65
|
-
this._requestsPending += 1;
|
|
66
|
-
this._updateDataForSubscriber(listenerGuid)
|
|
67
|
-
.then(() => {
|
|
68
|
-
this._requestsPending -= 1;
|
|
69
|
-
logMessage(`DataPulseProvider: data for #${listenerGuid} updated successfully, pending=${this._requestsPending}`);
|
|
70
|
-
})
|
|
71
|
-
.catch((reason?: string | Error) => {
|
|
72
|
-
this._requestsPending -= 1;
|
|
73
|
-
logMessage(`DataPulseProvider: data for #${listenerGuid} updated with error=${getErrorMessage(reason)}, pending=${this._requestsPending}`);
|
|
74
|
-
});
|
|
75
|
-
}
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
private _updateDataForSubscriber(listenerGuid: string): Promise<void> {
|
|
79
|
-
const subscriptionRecord = this._subscribers[listenerGuid];
|
|
80
|
-
|
|
81
|
-
const rangeEndTime = parseInt((Date.now() / 1000).toString());
|
|
82
|
-
|
|
83
|
-
// BEWARE: please note we really need 2 bars, not the only last one
|
|
84
|
-
// see the explanation below. `10` is the `large enough` value to work around holidays
|
|
85
|
-
const rangeStartTime = rangeEndTime - periodLengthSeconds(subscriptionRecord.resolution, 10);
|
|
86
|
-
|
|
87
|
-
return this._historyProvider.getBars(
|
|
88
|
-
subscriptionRecord.symbolInfo,
|
|
89
|
-
subscriptionRecord.resolution,
|
|
90
|
-
{
|
|
91
|
-
from: rangeStartTime,
|
|
92
|
-
to: rangeEndTime,
|
|
93
|
-
countBack: 2,
|
|
94
|
-
firstDataRequest: false,
|
|
95
|
-
})
|
|
96
|
-
.then((result: GetBarsResult) => {
|
|
97
|
-
this._onSubscriberDataReceived(listenerGuid, result);
|
|
98
|
-
});
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
private _onSubscriberDataReceived(listenerGuid: string, result: GetBarsResult): void {
|
|
102
|
-
// means the subscription was cancelled while waiting for data
|
|
103
|
-
if (!this._subscribers.hasOwnProperty(listenerGuid)) {
|
|
104
|
-
logMessage(`DataPulseProvider: Data comes for already unsubscribed subscription #${listenerGuid}`);
|
|
105
|
-
return;
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
const bars = result.bars;
|
|
109
|
-
if (bars.length === 0) {
|
|
110
|
-
return;
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
const lastBar = bars[bars.length - 1];
|
|
114
|
-
const subscriptionRecord = this._subscribers[listenerGuid];
|
|
115
|
-
|
|
116
|
-
if (subscriptionRecord.lastBarTime !== null && lastBar.time < subscriptionRecord.lastBarTime) {
|
|
117
|
-
return;
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
const isNewBar = subscriptionRecord.lastBarTime !== null && lastBar.time > subscriptionRecord.lastBarTime;
|
|
121
|
-
|
|
122
|
-
// Pulse updating may miss some trades data (ie, if pulse period = 10 secods and new bar is started 5 seconds later after the last update, the
|
|
123
|
-
// old bar's last 5 seconds trades will be lost). Thus, at fist we should broadcast old bar updates when it's ready.
|
|
124
|
-
if (isNewBar) {
|
|
125
|
-
if (bars.length < 2) {
|
|
126
|
-
throw new Error('Not enough bars in history for proper pulse update. Need at least 2.');
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
const previousBar = bars[bars.length - 2];
|
|
130
|
-
subscriptionRecord.listener(previousBar);
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
subscriptionRecord.lastBarTime = lastBar.time;
|
|
134
|
-
subscriptionRecord.listener(lastBar);
|
|
135
|
-
}
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
function periodLengthSeconds(resolution: string, requiredPeriodsCount: number): number {
|
|
139
|
-
let daysCount = 0;
|
|
140
|
-
|
|
141
|
-
if (resolution === 'D' || resolution === '1D') {
|
|
142
|
-
daysCount = requiredPeriodsCount;
|
|
143
|
-
} else if (resolution === 'M' || resolution === '1M') {
|
|
144
|
-
daysCount = 31 * requiredPeriodsCount;
|
|
145
|
-
} else if (resolution === 'W' || resolution === '1W') {
|
|
146
|
-
daysCount = 7 * requiredPeriodsCount;
|
|
147
|
-
} else {
|
|
148
|
-
daysCount = requiredPeriodsCount * parseInt(resolution) / (24 * 60);
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
return daysCount * 24 * 60 * 60;
|
|
152
|
-
}
|
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
export interface RequestParams {
|
|
2
|
-
[paramName: string]: string | string[] | number;
|
|
3
|
-
}
|
|
4
|
-
|
|
5
|
-
export interface UdfResponse {
|
|
6
|
-
s: string;
|
|
7
|
-
}
|
|
8
|
-
|
|
9
|
-
export interface UdfOkResponse extends UdfResponse {
|
|
10
|
-
s: 'ok';
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
export interface UdfErrorResponse {
|
|
14
|
-
s: 'error';
|
|
15
|
-
errmsg: string;
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
/**
|
|
19
|
-
* If you want to enable logs from datafeed set it to `true`
|
|
20
|
-
*/
|
|
21
|
-
const isLoggingEnabled = false;
|
|
22
|
-
export function logMessage(message: string): void {
|
|
23
|
-
if (isLoggingEnabled) {
|
|
24
|
-
const now = new Date();
|
|
25
|
-
// tslint:disable-next-line:no-console
|
|
26
|
-
console.log(`${now.toLocaleTimeString()}.${now.getMilliseconds()}> ${message}`);
|
|
27
|
-
}
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
export function getErrorMessage(error: string | Error | undefined): string {
|
|
31
|
-
if (error === undefined) {
|
|
32
|
-
return '';
|
|
33
|
-
} else if (typeof error === 'string') {
|
|
34
|
-
return error;
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
return error.message;
|
|
38
|
-
}
|
|
@@ -1,134 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
Bar,
|
|
3
|
-
HistoryMetadata,
|
|
4
|
-
LibrarySymbolInfo,
|
|
5
|
-
PeriodParams,
|
|
6
|
-
} from '../../../charting_library/datafeed-api';
|
|
7
|
-
|
|
8
|
-
import {
|
|
9
|
-
getErrorMessage,
|
|
10
|
-
RequestParams,
|
|
11
|
-
UdfErrorResponse,
|
|
12
|
-
UdfOkResponse,
|
|
13
|
-
UdfResponse,
|
|
14
|
-
} from './helpers';
|
|
15
|
-
|
|
16
|
-
import { Requester } from './requester';
|
|
17
|
-
// tslint:disable: no-any
|
|
18
|
-
interface HistoryPartialDataResponse extends UdfOkResponse {
|
|
19
|
-
t: any;
|
|
20
|
-
c: any;
|
|
21
|
-
o?: never;
|
|
22
|
-
h?: never;
|
|
23
|
-
l?: never;
|
|
24
|
-
v?: never;
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
interface HistoryFullDataResponse extends UdfOkResponse {
|
|
28
|
-
t: any;
|
|
29
|
-
c: any;
|
|
30
|
-
o: any;
|
|
31
|
-
h: any;
|
|
32
|
-
l: any;
|
|
33
|
-
v: any;
|
|
34
|
-
}
|
|
35
|
-
// tslint:enable: no-any
|
|
36
|
-
interface HistoryNoDataResponse extends UdfResponse {
|
|
37
|
-
s: 'no_data';
|
|
38
|
-
nextTime?: number;
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
type HistoryResponse = HistoryFullDataResponse | HistoryPartialDataResponse | HistoryNoDataResponse;
|
|
42
|
-
|
|
43
|
-
export type PeriodParamsWithOptionalCountback = Omit<PeriodParams, 'countBack'> & { countBack?: number };
|
|
44
|
-
|
|
45
|
-
export interface GetBarsResult {
|
|
46
|
-
bars: Bar[];
|
|
47
|
-
meta: HistoryMetadata;
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
export class HistoryProvider {
|
|
51
|
-
private _datafeedUrl: string;
|
|
52
|
-
private readonly _requester: Requester;
|
|
53
|
-
|
|
54
|
-
public constructor(datafeedUrl: string, requester: Requester) {
|
|
55
|
-
this._datafeedUrl = datafeedUrl;
|
|
56
|
-
this._requester = requester;
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
public getBars(symbolInfo: LibrarySymbolInfo, resolution: string, periodParams: PeriodParamsWithOptionalCountback): Promise<GetBarsResult> {
|
|
60
|
-
const requestParams: RequestParams = {
|
|
61
|
-
symbol: symbolInfo.ticker || '',
|
|
62
|
-
resolution: resolution,
|
|
63
|
-
from: periodParams.from,
|
|
64
|
-
to: periodParams.to,
|
|
65
|
-
};
|
|
66
|
-
if (periodParams.countBack !== undefined) {
|
|
67
|
-
requestParams.countback = periodParams.countBack;
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
if (symbolInfo.currency_code !== undefined) {
|
|
71
|
-
requestParams.currencyCode = symbolInfo.currency_code;
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
if (symbolInfo.unit_id !== undefined) {
|
|
75
|
-
requestParams.unitId = symbolInfo.unit_id;
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
return new Promise((resolve: (result: GetBarsResult) => void, reject: (reason: string) => void) => {
|
|
79
|
-
this._requester.sendRequest<HistoryResponse>(this._datafeedUrl, 'history', requestParams)
|
|
80
|
-
.then((response: HistoryResponse | UdfErrorResponse) => {
|
|
81
|
-
if (response.s !== 'ok' && response.s !== 'no_data') {
|
|
82
|
-
reject(response.errmsg);
|
|
83
|
-
return;
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
const bars: Bar[] = [];
|
|
87
|
-
const meta: HistoryMetadata = {
|
|
88
|
-
noData: false,
|
|
89
|
-
};
|
|
90
|
-
|
|
91
|
-
if (response.s === 'no_data') {
|
|
92
|
-
meta.noData = true;
|
|
93
|
-
meta.nextTime = response.nextTime;
|
|
94
|
-
} else {
|
|
95
|
-
const volumePresent = response.v !== undefined;
|
|
96
|
-
const ohlPresent = response.o !== undefined;
|
|
97
|
-
|
|
98
|
-
for (let i = 0; i < response.t.length; ++i) {
|
|
99
|
-
const barValue: Bar = {
|
|
100
|
-
time: response.t[i] * 1000,
|
|
101
|
-
close: parseFloat(response.c[i]),
|
|
102
|
-
open: parseFloat(response.c[i]),
|
|
103
|
-
high: parseFloat(response.c[i]),
|
|
104
|
-
low: parseFloat(response.c[i]),
|
|
105
|
-
};
|
|
106
|
-
|
|
107
|
-
if (ohlPresent) {
|
|
108
|
-
barValue.open = parseFloat((response as HistoryFullDataResponse).o[i]);
|
|
109
|
-
barValue.high = parseFloat((response as HistoryFullDataResponse).h[i]);
|
|
110
|
-
barValue.low = parseFloat((response as HistoryFullDataResponse).l[i]);
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
if (volumePresent) {
|
|
114
|
-
barValue.volume = parseFloat((response as HistoryFullDataResponse).v[i]);
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
bars.push(barValue);
|
|
118
|
-
}
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
resolve({
|
|
122
|
-
bars: bars,
|
|
123
|
-
meta: meta,
|
|
124
|
-
});
|
|
125
|
-
})
|
|
126
|
-
.catch((reason?: string | Error) => {
|
|
127
|
-
const reasonString = getErrorMessage(reason);
|
|
128
|
-
// tslint:disable-next-line:no-console
|
|
129
|
-
console.warn(`HistoryProvider: getBars() failed, error=${reasonString}`);
|
|
130
|
-
reject(reasonString);
|
|
131
|
-
});
|
|
132
|
-
});
|
|
133
|
-
}
|
|
134
|
-
}
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
import { QuoteData } from '../../../charting_library/datafeed-api';
|
|
2
|
-
|
|
3
|
-
import {
|
|
4
|
-
UdfOkResponse,
|
|
5
|
-
} from './helpers';
|
|
6
|
-
|
|
7
|
-
export interface UdfQuotesResponse extends UdfOkResponse {
|
|
8
|
-
d: QuoteData[];
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
export interface IQuotesProvider {
|
|
12
|
-
// tslint:disable-next-line:variable-name tv-variable-name
|
|
13
|
-
getQuotes(symbols: string[]): Promise<QuoteData[]>;
|
|
14
|
-
}
|
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
import { UdfQuotesResponse, IQuotesProvider } from './iquotes-provider';
|
|
2
|
-
import { QuoteData } from '../../../charting_library/datafeed-api';
|
|
3
|
-
|
|
4
|
-
import {
|
|
5
|
-
getErrorMessage,
|
|
6
|
-
logMessage,
|
|
7
|
-
UdfErrorResponse,
|
|
8
|
-
} from './helpers';
|
|
9
|
-
import { Requester } from './requester';
|
|
10
|
-
|
|
11
|
-
export class QuotesProvider implements IQuotesProvider {
|
|
12
|
-
private readonly _datafeedUrl: string;
|
|
13
|
-
private readonly _requester: Requester;
|
|
14
|
-
|
|
15
|
-
public constructor(datafeedUrl: string, requester: Requester) {
|
|
16
|
-
this._datafeedUrl = datafeedUrl;
|
|
17
|
-
this._requester = requester;
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
public getQuotes(symbols: string[]): Promise<QuoteData[]> {
|
|
21
|
-
return new Promise((resolve: (data: QuoteData[]) => void, reject: (reason: string) => void) => {
|
|
22
|
-
this._requester.sendRequest<UdfQuotesResponse>(this._datafeedUrl, 'quotes', { symbols: symbols })
|
|
23
|
-
.then((response: UdfQuotesResponse | UdfErrorResponse) => {
|
|
24
|
-
if (response.s === 'ok') {
|
|
25
|
-
resolve(response.d);
|
|
26
|
-
} else {
|
|
27
|
-
reject(response.errmsg);
|
|
28
|
-
}
|
|
29
|
-
})
|
|
30
|
-
.catch((error?: string | Error) => {
|
|
31
|
-
const errorMessage = getErrorMessage(error);
|
|
32
|
-
logMessage(`QuotesProvider: getQuotes failed, error=${errorMessage}`);
|
|
33
|
-
reject(`network error: ${errorMessage}`);
|
|
34
|
-
});
|
|
35
|
-
});
|
|
36
|
-
}
|
|
37
|
-
}
|
|
@@ -1,85 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
QuoteData,
|
|
3
|
-
QuotesCallback,
|
|
4
|
-
} from '../../../charting_library/datafeed-api';
|
|
5
|
-
|
|
6
|
-
import {
|
|
7
|
-
getErrorMessage,
|
|
8
|
-
logMessage,
|
|
9
|
-
} from './helpers';
|
|
10
|
-
|
|
11
|
-
import { IQuotesProvider } from './iquotes-provider';
|
|
12
|
-
|
|
13
|
-
interface QuoteSubscriber {
|
|
14
|
-
symbols: string[];
|
|
15
|
-
fastSymbols: string[];
|
|
16
|
-
listener: QuotesCallback;
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
interface QuoteSubscribers {
|
|
20
|
-
[listenerId: string]: QuoteSubscriber;
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
const enum SymbolsType {
|
|
24
|
-
General,
|
|
25
|
-
Fast,
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
const enum UpdateTimeouts {
|
|
29
|
-
Fast = 10 * 1000,
|
|
30
|
-
General = 60 * 1000,
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
export class QuotesPulseProvider {
|
|
34
|
-
private readonly _quotesProvider: IQuotesProvider;
|
|
35
|
-
private readonly _subscribers: QuoteSubscribers = {};
|
|
36
|
-
private _requestsPending: number = 0;
|
|
37
|
-
|
|
38
|
-
public constructor(quotesProvider: IQuotesProvider) {
|
|
39
|
-
this._quotesProvider = quotesProvider;
|
|
40
|
-
|
|
41
|
-
setInterval(this._updateQuotes.bind(this, SymbolsType.Fast), UpdateTimeouts.Fast);
|
|
42
|
-
setInterval(this._updateQuotes.bind(this, SymbolsType.General), UpdateTimeouts.General);
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
public subscribeQuotes(symbols: string[], fastSymbols: string[], onRealtimeCallback: QuotesCallback, listenerGuid: string): void {
|
|
46
|
-
this._subscribers[listenerGuid] = {
|
|
47
|
-
symbols: symbols,
|
|
48
|
-
fastSymbols: fastSymbols,
|
|
49
|
-
listener: onRealtimeCallback,
|
|
50
|
-
};
|
|
51
|
-
|
|
52
|
-
logMessage(`QuotesPulseProvider: subscribed quotes with #${listenerGuid}`);
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
public unsubscribeQuotes(listenerGuid: string): void {
|
|
56
|
-
delete this._subscribers[listenerGuid];
|
|
57
|
-
logMessage(`QuotesPulseProvider: unsubscribed quotes with #${listenerGuid}`);
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
private _updateQuotes(updateType: SymbolsType): void {
|
|
61
|
-
if (this._requestsPending > 0) {
|
|
62
|
-
return;
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
for (const listenerGuid in this._subscribers) { // tslint:disable-line:forin
|
|
66
|
-
this._requestsPending++;
|
|
67
|
-
|
|
68
|
-
const subscriptionRecord = this._subscribers[listenerGuid];
|
|
69
|
-
this._quotesProvider.getQuotes(updateType === SymbolsType.Fast ? subscriptionRecord.fastSymbols : subscriptionRecord.symbols)
|
|
70
|
-
.then((data: QuoteData[]) => {
|
|
71
|
-
this._requestsPending--;
|
|
72
|
-
if (!this._subscribers.hasOwnProperty(listenerGuid)) {
|
|
73
|
-
return;
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
subscriptionRecord.listener(data);
|
|
77
|
-
logMessage(`QuotesPulseProvider: data for #${listenerGuid} (${updateType}) updated successfully, pending=${this._requestsPending}`);
|
|
78
|
-
})
|
|
79
|
-
.catch((reason?: string | Error) => {
|
|
80
|
-
this._requestsPending--;
|
|
81
|
-
logMessage(`QuotesPulseProvider: data for #${listenerGuid} (${updateType}) updated with error=${getErrorMessage(reason)}, pending=${this._requestsPending}`);
|
|
82
|
-
});
|
|
83
|
-
}
|
|
84
|
-
}
|
|
85
|
-
}
|
|
@@ -1,39 +0,0 @@
|
|
|
1
|
-
import { RequestParams, UdfResponse, UdfErrorResponse, logMessage } from './helpers';
|
|
2
|
-
|
|
3
|
-
export class Requester {
|
|
4
|
-
private _headers: HeadersInit | undefined;
|
|
5
|
-
|
|
6
|
-
public constructor(headers?: HeadersInit) {
|
|
7
|
-
if (headers) {
|
|
8
|
-
this._headers = headers;
|
|
9
|
-
}
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
public sendRequest<T extends UdfResponse>(datafeedUrl: string, urlPath: string, params?: RequestParams): Promise<T | UdfErrorResponse>;
|
|
13
|
-
public sendRequest<T>(datafeedUrl: string, urlPath: string, params?: RequestParams): Promise<T>;
|
|
14
|
-
public sendRequest<T>(datafeedUrl: string, urlPath: string, params?: RequestParams): Promise<T> {
|
|
15
|
-
if (params !== undefined) {
|
|
16
|
-
const paramKeys = Object.keys(params);
|
|
17
|
-
if (paramKeys.length !== 0) {
|
|
18
|
-
urlPath += '?';
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
urlPath += paramKeys.map((key: string) => {
|
|
22
|
-
return `${encodeURIComponent(key)}=${encodeURIComponent(params[key].toString())}`;
|
|
23
|
-
}).join('&');
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
logMessage('New request: ' + urlPath);
|
|
27
|
-
|
|
28
|
-
// Send user cookies if the URL is on the same origin as the calling script.
|
|
29
|
-
const options: RequestInit = { credentials: 'same-origin' };
|
|
30
|
-
|
|
31
|
-
if (this._headers !== undefined) {
|
|
32
|
-
options.headers = this._headers;
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
return fetch(`${datafeedUrl}/${urlPath}`, options)
|
|
36
|
-
.then((response: Response) => response.text())
|
|
37
|
-
.then((responseTest: string) => JSON.parse(responseTest));
|
|
38
|
-
}
|
|
39
|
-
}
|