import { getErrorMessage, logMessage } from './helpers'; import { HistoryProvider } from './history-provider'; import { DataPulseProvider } from './data-pulse-provider'; import { QuotesPulseProvider } from './quotes-pulse-provider'; import { SymbolsStorage } from './symbols-storage'; function extractField(data, field, arrayIndex) { var value = data[field]; return Array.isArray(value) ? value[arrayIndex] : value; } /** * This class implements interaction with UDF-compatible datafeed. * See UDF protocol reference at https://github.com/tradingview/charting_library/wiki/UDF */ var UDFCompatibleDatafeedBase = /** @class */ (function () { function UDFCompatibleDatafeedBase( datafeedURL, quotesProvider, requester, updateFrequency, ) { var _this = this; if (updateFrequency === void 0) { updateFrequency = 10 * 1000; } this._configuration = defaultConfiguration(); this._symbolsStorage = null; this._datafeedURL = datafeedURL; this._requester = requester; this._historyProvider = new HistoryProvider(datafeedURL, this._requester); this._quotesProvider = quotesProvider; this._dataPulseProvider = new DataPulseProvider( this._historyProvider, updateFrequency, ); this._quotesPulseProvider = new QuotesPulseProvider(this._quotesProvider); this._configurationReadyPromise = this._requestConfiguration().then( function (configuration) { if (configuration === null) { configuration = defaultConfiguration(); } _this._setupWithConfiguration(configuration); }, ); } UDFCompatibleDatafeedBase.prototype.onReady = function (callback) { var _this = this; this._configurationReadyPromise.then(function () { callback(_this._configuration); }); }; UDFCompatibleDatafeedBase.prototype.getQuotes = function ( symbols, onDataCallback, onErrorCallback, ) { this._quotesProvider .getQuotes(symbols) .then(onDataCallback) .catch(onErrorCallback); }; UDFCompatibleDatafeedBase.prototype.subscribeQuotes = function ( symbols, fastSymbols, onRealtimeCallback, listenerGuid, ) { this._quotesPulseProvider.subscribeQuotes( symbols, fastSymbols, onRealtimeCallback, listenerGuid, ); }; UDFCompatibleDatafeedBase.prototype.unsubscribeQuotes = function ( listenerGuid, ) { this._quotesPulseProvider.unsubscribeQuotes(listenerGuid); }; UDFCompatibleDatafeedBase.prototype.calculateHistoryDepth = function ( resolution, resolutionBack, intervalBack, ) { return undefined; }; UDFCompatibleDatafeedBase.prototype.getMarks = function ( symbolInfo, from, to, onDataCallback, resolution, ) { if (!this._configuration.supports_marks) { return; } var requestParams = { symbol: symbolInfo.ticker || '', from: from, to: to, resolution: resolution, }; this._send('marks', requestParams) .then(function (response) { if (!Array.isArray(response)) { var result = []; for (var i = 0; i < response.id.length; ++i) { result.push({ id: extractField(response, 'id', i), time: extractField(response, 'time', i), color: extractField(response, 'color', i), text: extractField(response, 'text', i), label: extractField(response, 'label', i), labelFontColor: extractField(response, 'labelFontColor', i), minSize: extractField(response, 'minSize', i), }); } response = result; } onDataCallback(response); }) .catch(function (error) { logMessage( 'UdfCompatibleDatafeed: Request marks failed: ' + getErrorMessage(error), ); onDataCallback([]); }); }; UDFCompatibleDatafeedBase.prototype.getTimescaleMarks = function ( symbolInfo, from, to, onDataCallback, resolution, ) { if (!this._configuration.supports_timescale_marks) { return; } var requestParams = { symbol: symbolInfo.ticker || '', from: from, to: to, resolution: resolution, }; this._send('timescale_marks', requestParams) .then(function (response) { if (!Array.isArray(response)) { var result = []; for (var i = 0; i < response.id.length; ++i) { result.push({ id: extractField(response, 'id', i), time: extractField(response, 'time', i), color: extractField(response, 'color', i), label: extractField(response, 'label', i), tooltip: extractField(response, 'tooltip', i), }); } response = result; } onDataCallback(response); }) .catch(function (error) { logMessage( 'UdfCompatibleDatafeed: Request timescale marks failed: ' + getErrorMessage(error), ); onDataCallback([]); }); }; UDFCompatibleDatafeedBase.prototype.getServerTime = function (callback) { if (!this._configuration.supports_time) { return; } this._send('time') .then(function (response) { var time = parseInt(response); if (!isNaN(time)) { callback(time); } }) .catch(function (error) { logMessage( 'UdfCompatibleDatafeed: Fail to load server time, error=' + getErrorMessage(error), ); }); }; UDFCompatibleDatafeedBase.prototype.searchSymbols = function ( userInput, exchange, symbolType, onResult, ) { if (this._configuration.supports_search) { var params = { limit: 30 /* SearchItemsLimit */, query: userInput.toUpperCase(), type: symbolType, exchange: exchange, }; this._send('search', params) .then(function (response) { if (response.s !== undefined) { logMessage( 'UdfCompatibleDatafeed: search symbols error=' + response.errmsg, ); onResult([]); return; } onResult(response); }) .catch(function (reason) { logMessage( "UdfCompatibleDatafeed: Search symbols for '" + userInput + "' failed. Error=" + getErrorMessage(reason), ); onResult([]); }); } else { if (this._symbolsStorage === null) { throw new Error( 'UdfCompatibleDatafeed: inconsistent configuration (symbols storage)', ); } this._symbolsStorage .searchSymbols( userInput, exchange, symbolType, 30 /* SearchItemsLimit */, ) .then(onResult) .catch(onResult.bind(null, [])); } }; UDFCompatibleDatafeedBase.prototype.resolveSymbol = function ( symbolName, onResolve, onError, extension, ) { logMessage('Resolve requested'); var currencyCode = extension && extension.currencyCode; var resolveRequestStartTime = Date.now(); function onResultReady(symbolInfo) { logMessage( 'Symbol resolved: ' + (Date.now() - resolveRequestStartTime) + 'ms', ); onResolve(symbolInfo); } if (!this._configuration.supports_group_request) { var params = { symbol: symbolName, }; if (currencyCode !== undefined) { params.currencyCode = currencyCode; } this._send('symbols', params) .then(function (response) { if (response.s !== undefined) { onError('unknown_symbol'); } else { onResultReady(response); } }) .catch(function (reason) { logMessage( 'UdfCompatibleDatafeed: Error resolving symbol: ' + getErrorMessage(reason), ); onError('unknown_symbol'); }); } else { if (this._symbolsStorage === null) { throw new Error( 'UdfCompatibleDatafeed: inconsistent configuration (symbols storage)', ); } this._symbolsStorage .resolveSymbol(symbolName, currencyCode) .then(onResultReady) .catch(onError); } }; UDFCompatibleDatafeedBase.prototype.getBars = function ( symbolInfo, resolution, rangeStartDate, rangeEndDate, onResult, onError, ) { this._historyProvider .getBars(symbolInfo, resolution, rangeStartDate, rangeEndDate) .then(function (result) { onResult(result.bars, result.meta); }) .catch(onError); }; UDFCompatibleDatafeedBase.prototype.subscribeBars = function ( symbolInfo, resolution, onTick, listenerGuid, onResetCacheNeededCallback, ) { this._dataPulseProvider.subscribeBars( symbolInfo, resolution, onTick, listenerGuid, ); }; UDFCompatibleDatafeedBase.prototype.unsubscribeBars = function ( listenerGuid, ) { this._dataPulseProvider.unsubscribeBars(listenerGuid); }; UDFCompatibleDatafeedBase.prototype._requestConfiguration = function () { return this._send('config').catch(function (reason) { logMessage( 'UdfCompatibleDatafeed: Cannot get datafeed configuration - use default, error=' + getErrorMessage(reason), ); return null; }); }; UDFCompatibleDatafeedBase.prototype._send = function (urlPath, params) { return this._requester.sendRequest(this._datafeedURL, urlPath, params); }; UDFCompatibleDatafeedBase.prototype._setupWithConfiguration = function ( configurationData, ) { this._configuration = configurationData; if (configurationData.exchanges === undefined) { configurationData.exchanges = []; } if ( !configurationData.supports_search && !configurationData.supports_group_request ) { throw new Error( 'Unsupported datafeed configuration. Must either support search, or support group request', ); } if ( configurationData.supports_group_request || !configurationData.supports_search ) { this._symbolsStorage = new SymbolsStorage( this._datafeedURL, configurationData.supported_resolutions || [], this._requester, ); } logMessage( 'UdfCompatibleDatafeed: Initialized with ' + JSON.stringify(configurationData), ); }; return UDFCompatibleDatafeedBase; })(); export { UDFCompatibleDatafeedBase }; function defaultConfiguration() { return { supports_search: false, supports_group_request: true, supported_resolutions: ['1', '5', '15', '30', '60', '1D', '1W', '1M'], supports_marks: false, supports_timescale_marks: false, }; }