UNPKG

okotoki

Version:
241 lines 8.16 kB
"use strict"; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __exportStar = (this && this.__exportStar) || function(m, exports) { for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p); }; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.coinIndex = exports.candle = exports.leveledTradeVolume = exports.tradeVolume = exports.price = exports.orderBook = exports.largeTrades = void 0; const avsc_1 = require("avsc"); const debug_1 = __importDefault(require("debug")); require("isomorphic-fetch"); const isomorphic_ws_1 = __importDefault(require("isomorphic-ws")); const reconnecting_websocket_1 = __importDefault(require("./reconnecting-websocket")); __exportStar(require("./types"), exports); const largeTrades = (exchange, symbol, options) => ({ kind: 'largeTrades', exchange, symbol, ...options }); exports.largeTrades = largeTrades; const orderBook = (exchange, symbol, options) => ({ kind: 'orderBook', exchange, symbol, ...options }); exports.orderBook = orderBook; const price = (exchange, symbol) => ({ kind: 'price', exchange, symbol }); exports.price = price; const tradeVolume = (exchange, symbol) => ({ kind: 'tradeVolume', exchange, symbol }); exports.tradeVolume = tradeVolume; const leveledTradeVolume = (exchange, symbol, options) => ({ kind: 'leveledTradeVolume', exchange, symbol, ...options }); exports.leveledTradeVolume = leveledTradeVolume; const candle = (exchange, symbol, options) => ({ kind: 'candles', exchange, symbol, ...options }); exports.candle = candle; const coinIndex = (coin) => ({ kind: 'index', coin }); exports.coinIndex = coinIndex; const defaultOptions = { key: '', secret: '', debug: false, useBinary: true }; const defaultWsOptions = { connectionTimeout: 4000, WebSocket: isomorphic_ws_1.default, debug: false, maxReconnectionDelay: 10000, minReconnectionDelay: 4000, maxRetries: Infinity }; class Api { options; wsOptions; _rws; _wsUrl = 'wss://api-eu.okotoki.com/ws'; _restUrl = 'https://api-eu.okotoki.com'; pingInterval = null; binarySchema; _initiallyConnected = false; debug = (0, debug_1.default)('okotoki-api'); onMessage = () => { }; onConnectionStateChange = () => { }; constructor(options, wsOptions) { this.options = options; this.wsOptions = wsOptions; this.options = { ...defaultOptions, ...options }; this._wsUrl = this.options.wsUrl || this._wsUrl; this._restUrl = this.options.restUrl || this._restUrl; this.debug.enabled = !!this.options.debug; this.wsOptions = wsOptions ? { ...defaultWsOptions, ...wsOptions } : defaultWsOptions; this.connect(); } getSupportedCoins = () => fetch(`${this._restUrl}/coins`).then((res) => res.json()); getMarketsForCoin = (coin) => fetch(`${this._restUrl}/markets/${coin.toUpperCase()}`).then((res) => res.json()); subscribe(subscriptions) { this._sendSubscriptionMessage(subscriptions); } connect() { this.debug('estabilishing connection to %s', this._wsUrl); this._rws = new reconnecting_websocket_1.default(`${this._wsUrl}?useBinary=${this.options?.useBinary === undefined ? defaultOptions.useBinary : this.options.useBinary}`, undefined, this.wsOptions); this.onConnectionStateChange('connecting'); this._rws.onopen = this._onConnectionEstabilished; this._rws.onclose = this._onConnectionClosed; this._rws.onmessage = this._onMessage; this._rws.onerror = this._onError; } disconnect() { this.debug('disconnecting from to %s', this._wsUrl); this.stopPingInterval(); this._rws.close(); } reconnect() { this.debug('reconnecting to %s', this._wsUrl); this.stopPingInterval(); this._rws.reconnect(); } _preConnectSubscriptionsQueue = []; _sendSubscriptionMessage(subscriptions) { if (this._initiallyConnected) { this._send({ type: 'subscribe', subscriptions: removeDuplicates(subscriptions) }); } else { this._preConnectSubscriptionsQueue.push(subscriptions); } } _rawBinaryToNormalized = (message) => { // it is guaranteed that there is only one key const res = Object.entries(message).map(([key, message]) => { return { ...message, type: key }; }); return res[0]; }; _parseIncomingMessage = async (message) => { if (message instanceof Blob) { const buf = await new Response(message).arrayBuffer(); const fromBinary = this.binarySchema?.fromBuffer(Buffer.from(buf)); return this._rawBinaryToNormalized(fromBinary); } else if (message instanceof Buffer) { const fromBinary = this.binarySchema?.fromBuffer(message); return this._rawBinaryToNormalized(fromBinary); } else { return JSON.parse(message); } }; _onMessage = async (event) => { this._updatePingInterval(); const message = !this.options?.useBinary ? (() => { const data = JSON.parse(event.data); const type = Object.keys(data)[0]; return { ...data[type], type }; })() : await this._parseIncomingMessage(event.data); this.debug('received message %o', message); if (message.type === 'binarySchema') { this.binarySchema = avsc_1.Type.forSchema(message.schema); return; } if (message.type === 'pong') return; if (message.type === 'subscribed') return; this.onMessage(message); }; _send = (message) => { this.debug('sending message %o', message); this._rws?.send(JSON.stringify(message)); }; _updatePingInterval() { this.stopPingInterval(); this.pingInterval = setInterval(this._ping, 60 * 1000); } stopPingInterval() { if (!this.pingInterval) return; clearInterval(this.pingInterval); this.pingInterval = null; } _ping = () => { this.debug('sending ping'); this._send({ type: 'ping' }); }; _auth = () => { this.debug('sending authorization'); this._send({ type: 'auth', key: this.options.key, secret: this.options.secret }); }; _onError = (error) => { this.debug('connection error', error); }; _onConnectionEstabilished = async () => { this.debug('estabilished connection'); this._updatePingInterval(); this._initiallyConnected = true; this._auth(); this._sendSubscriptionMessage(this._preConnectSubscriptionsQueue.flat()); this._preConnectSubscriptionsQueue = []; this.onConnectionStateChange('connected'); }; _onConnectionClosed = () => { this.debug('connection closed'); this.stopPingInterval(); this._initiallyConnected = false; this.onConnectionStateChange('disconnected'); }; } exports.default = Api; const removeDuplicates = (arr) => arr.filter((item, index) => arr.indexOf(item) === index); //# sourceMappingURL=index.js.map