UNPKG

bitmart-api

Version:

Complete & robust Node.js SDK for BitMart's REST APIs and WebSockets, with TypeScript declarations.

134 lines 4.33 kB
import { DefaultLogger } from '../logger.js'; import { WsConnectionStateEnum } from './WsStore.types.js'; /** * Simple comparison of two objects, only checks 1-level deep (nested objects won't match) */ function isDeepObjectMatch(object1, object2) { if (typeof object1 === 'string' && typeof object2 === 'string') { return object1 === object2; } if (typeof object1 !== 'object' || typeof object2 !== 'object') { return false; } for (const key in object1) { const value1 = object1[key]; const value2 = object2[key]; if (value1 !== value2) { return false; } } return true; } export class WsStore { wsState = {}; logger; constructor(logger) { this.logger = logger || DefaultLogger; } get(key, createIfMissing) { if (this.wsState[key]) { return this.wsState[key]; } if (createIfMissing) { return this.create(key); } } getKeys() { return Object.keys(this.wsState); } create(key) { if (this.hasExistingActiveConnection(key)) { this.logger.info('WsStore setConnection() overwriting existing open connection: ', this.getWs(key)); } this.wsState[key] = { subscribedTopics: new Set(), connectionState: WsConnectionStateEnum.INITIAL, }; return this.get(key); } delete(key) { // TODO: should we allow this at all? Perhaps block this from happening... if (this.hasExistingActiveConnection(key)) { const ws = this.getWs(key); this.logger.info('WsStore deleting state for connection still open: ', ws); ws?.close(); } delete this.wsState[key]; } /* connection websocket */ hasExistingActiveConnection(key) { return this.get(key) && this.isWsOpen(key); } getWs(key) { return this.get(key)?.ws; } setWs(key, wsConnection) { if (this.isWsOpen(key)) { this.logger.info('WsStore setConnection() overwriting existing open connection: ', this.getWs(key)); } this.get(key, true).ws = wsConnection; return wsConnection; } /* connection state */ isWsOpen(key) { const existingConnection = this.getWs(key); return (!!existingConnection && existingConnection.readyState === existingConnection.OPEN); } getConnectionState(key) { return this.get(key, true).connectionState; } setConnectionState(key, state) { this.get(key, true).connectionState = state; } isConnectionState(key, state) { return this.getConnectionState(key) === state; } /* subscribed topics */ getTopics(key) { return this.get(key, true).subscribedTopics; } getTopicsByKey() { const result = {}; for (const refKey in this.wsState) { result[refKey] = this.getTopics(refKey); } return result; } // Since topics are objects we can't rely on the set to detect duplicates getMatchingTopic(key, topic) { // if (typeof topic === 'string') { // return this.getMatchingTopic(key, { channel: topic }); // } const allTopics = this.getTopics(key).values(); for (const storedTopic of allTopics) { if (isDeepObjectMatch(topic, storedTopic)) { return storedTopic; } } } addTopic(key, topic) { // if (typeof topic === 'string') { // return this.addTopic(key, { // instType: 'sp', // channel: topic, // instId: 'default', // }; // } // Check for duplicate topic. If already tracked, don't store this one const existingTopic = this.getMatchingTopic(key, topic); if (existingTopic) { return this.getTopics(key); } return this.getTopics(key).add(topic); } deleteTopic(key, topic) { // Check if we're subscribed to a topic like this const storedTopic = this.getMatchingTopic(key, topic); if (storedTopic) { this.getTopics(key).delete(storedTopic); } return this.getTopics(key); } } //# sourceMappingURL=WsStore.js.map