diff --git a/package-lock.json b/package-lock.json index 940089b..372a1a9 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "bybit-api", - "version": "3.10.28", + "version": "3.10.29", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "bybit-api", - "version": "3.10.28", + "version": "3.10.29", "license": "MIT", "dependencies": { "axios": "^1.6.6", diff --git a/src/util/BaseWSClient.ts b/src/util/BaseWSClient.ts index c92d6c4..38c7c52 100644 --- a/src/util/BaseWSClient.ts +++ b/src/util/BaseWSClient.ts @@ -132,8 +132,6 @@ export abstract class BaseWebsocketClient< private timeOffsetMs: number = 0; - // private pendingTopicsSubscriptionsOld: TopicsPendingSubscriptions[] = []; - private pendingTopicSubscriptionRequests: { [key in TWSKey]?: { [requestKey: string]: @@ -259,52 +257,32 @@ export abstract class BaseWebsocketClient< params: any, ): Promise; - protected getTimeOffsetMs() { + public getTimeOffsetMs() { return this.timeOffsetMs; } - protected setTimeOffsetMs(newOffset: number) { + public setTimeOffsetMs(newOffset: number) { this.timeOffsetMs = newOffset; } - // protected upsertPendingTopicsSubscriptionsOld( - // wsKey: string, - // topicKey: string, - // resolver: TopicsPendingSubscriptionsResolver, - // rejector: TopicsPendingSubscriptionsRejector, - // ) { - // const existingWsKeyPendingSubscriptions = - // this.pendingTopicsSubscriptionsOld.find((s) => s.wsKey === wsKey); + private getWsKeyPendingSubscriptionStore(wsKey: TWSKey) { + if (!this.pendingTopicSubscriptionRequests[wsKey]) { + this.pendingTopicSubscriptionRequests[wsKey] = {}; + } - // if (!existingWsKeyPendingSubscriptions) { - // this.pendingTopicsSubscriptionsOld.push({ - // wsKey, - // resolver, - // rejector, - // failedTopicsSubscriptions: new Set(), - // pendingTopicsSubscriptions: new Set([topicKey]), - // }); - // return; - // } - - // existingWsKeyPendingSubscriptions.pendingTopicsSubscriptions.add(topicKey); - // } + return this.pendingTopicSubscriptionRequests[wsKey]!; + } protected upsertPendingTopicSubscribeRequests( wsKey: TWSKey, requestData: MidflightWsRequestEvent, ) { - if (!this.pendingTopicSubscriptionRequests[wsKey]) { - this.pendingTopicSubscriptionRequests[wsKey] = {}; - } - - const existingWsKeyPendingRequests = - this.pendingTopicSubscriptionRequests[wsKey]!; - // a unique identifier for this subscription request (e.g. csv of topics, or request id, etc) const requestKey = requestData.requestKey; // Should not be possible to see a requestKey collision in the current design, since the req ID increments automatically with every request, so this should never be true, but just in case a future mistake happens... + const existingWsKeyPendingRequests = + this.getWsKeyPendingSubscriptionStore(wsKey); if (existingWsKeyPendingRequests[requestKey]) { throw new Error( 'Implementation error: attempted to upsert pending topics with duplicate request ID!', @@ -316,10 +294,8 @@ export abstract class BaseWebsocketClient< resolver: TopicsPendingSubscriptionsResolver, rejector: TopicsPendingSubscriptionsRejector, ) => { - if (!this.pendingTopicSubscriptionRequests[wsKey]) { - this.pendingTopicSubscriptionRequests[wsKey] = {}; - } - this.pendingTopicSubscriptionRequests[wsKey][requestKey] = { + const store = this.getWsKeyPendingSubscriptionStore(wsKey); + store[requestKey] = { requestData: requestData.requestEvent, resolver, rejector, @@ -329,11 +305,8 @@ export abstract class BaseWebsocketClient< } protected removeTopicPendingSubscription(wsKey: TWSKey, requestKey: string) { - if (!this.pendingTopicSubscriptionRequests[wsKey]) { - this.pendingTopicSubscriptionRequests[wsKey] = {}; - } - - delete this.pendingTopicSubscriptionRequests[wsKey][requestKey]; + const store = this.getWsKeyPendingSubscriptionStore(wsKey); + delete store[requestKey]; } private clearTopicsPendingSubscriptions( @@ -342,13 +315,9 @@ export abstract class BaseWebsocketClient< rejectReason: string, ) { if (rejectAll) { - if (!this.pendingTopicSubscriptionRequests[wsKey]) { - this.pendingTopicSubscriptionRequests[wsKey] = {}; - } - - const requests = this.pendingTopicSubscriptionRequests[wsKey]!; - for (const requestKey in requests) { - const request = requests[requestKey]; + const wsKeyPendingRequests = this.getWsKeyPendingSubscriptionStore(wsKey); + for (const requestKey in wsKeyPendingRequests) { + const request = wsKeyPendingRequests[requestKey]; request?.rejector(request.requestData, rejectReason); } } @@ -367,21 +336,16 @@ export abstract class BaseWebsocketClient< msg: object, isTopicSubscriptionSuccessEvent: boolean, ) { - if (!this.pendingTopicSubscriptionRequests[wsKey]) { + const wsKeyPendingRequests = this.getWsKeyPendingSubscriptionStore(wsKey); + if (!wsKeyPendingRequests) { return; } - const pendingSubscriptionRequest = - this.pendingTopicSubscriptionRequests[wsKey][requestKey]; + const pendingSubscriptionRequest = wsKeyPendingRequests[requestKey]; if (!pendingSubscriptionRequest) { return; } - console.log('updatePendingTopicSubscriptionStatus', { - isTopicSubscriptionSuccessEvent, - msg, - }); - if (isTopicSubscriptionSuccessEvent) { pendingSubscriptionRequest.resolver( pendingSubscriptionRequest.requestData, @@ -413,7 +377,6 @@ export abstract class BaseWebsocketClient< wsTopicRequests: WsTopicRequestOrStringTopic[], wsKey: TWSKey, ) { - console.log('subscribeTopicsForWsKey: ', { wsTopicRequests, wsKey }); const normalisedTopicRequests = getNormalisedTopicRequests(wsTopicRequests); // Store topics, so future automation (post-auth, post-reconnect) has everything needed to resubscribe automatically diff --git a/src/websocket-client.ts b/src/websocket-client.ts index d4456c0..193ae15 100644 --- a/src/websocket-client.ts +++ b/src/websocket-client.ts @@ -45,6 +45,46 @@ import { const WS_LOGGER_CATEGORY = { category: 'bybit-ws' }; +/** + * Groups topics in request into per-wsKey groups + * @param normalisedTopicRequests + * @param wsKey + * @param isPrivateTopic + * @returns + */ +function getTopicsPerWSKey( + normalisedTopicRequests: WsTopicRequest[], + wsKey?: WsKey, + isPrivateTopic?: boolean, +): { + [key in WsKey]?: WsTopicRequest[]; +} { + const perWsKeyTopics: { [key in WsKey]?: WsTopicRequest[] } = {}; + + // Sort into per wsKey arrays, in case topics are mixed together for different wsKeys + for (const topicRequest of normalisedTopicRequests) { + const derivedWsKey = + wsKey || + getWsKeyForTopic( + this.options.market, + topicRequest.topic, + isPrivateTopic, + topicRequest.category, + ); + + if ( + !perWsKeyTopics[derivedWsKey] || + !Array.isArray(perWsKeyTopics[derivedWsKey]) + ) { + perWsKeyTopics[derivedWsKey] = []; + } + + perWsKeyTopics[derivedWsKey]!.push(topicRequest); + } + + return perWsKeyTopics; +} + // export class WebsocketClient extends EventEmitter { export class WebsocketClient extends BaseWebsocketClient< WsKey, @@ -183,12 +223,12 @@ export class WebsocketClient extends BaseWebsocketClient< category: CategoryV5, isPrivateTopic?: boolean, ): Promise[] { - const topics = Array.isArray(wsTopics) ? wsTopics : [wsTopics]; + const topicRequests = Array.isArray(wsTopics) ? wsTopics : [wsTopics]; const perWsKeyTopics: { [key in WsKey]?: WsTopicRequest[] } = {}; // Sort into per-WsKey batches, in case there is a mix of topics here - for (const topic of topics) { + for (const topic of topicRequests) { const derivedWsKey = getWsKeyForTopic( this.options.market, topic, @@ -208,7 +248,7 @@ export class WebsocketClient extends BaseWebsocketClient< perWsKeyTopics[derivedWsKey] = []; } - perWsKeyTopics[derivedWsKey].push(wsRequest); + perWsKeyTopics[derivedWsKey]!.push(wsRequest); } const promises: Promise[] = []; @@ -245,12 +285,12 @@ export class WebsocketClient extends BaseWebsocketClient< category: CategoryV5, isPrivateTopic?: boolean, ): Promise[] { - const topics = Array.isArray(wsTopics) ? wsTopics : [wsTopics]; + const topicRequests = Array.isArray(wsTopics) ? wsTopics : [wsTopics]; const perWsKeyTopics: { [key in WsKey]?: WsTopicRequest[] } = {}; // Sort into per-WsKey batches, in case there is a mix of topics here - for (const topic of topics) { + for (const topic of topicRequests) { const derivedWsKey = getWsKeyForTopic( this.options.market, topic, @@ -270,7 +310,7 @@ export class WebsocketClient extends BaseWebsocketClient< perWsKeyTopics[derivedWsKey] = []; } - perWsKeyTopics[derivedWsKey].push(wsRequest); + perWsKeyTopics[derivedWsKey]!.push(wsRequest); } const promises: Promise[] = []; @@ -315,30 +355,7 @@ export class WebsocketClient extends BaseWebsocketClient< const topicRequests = Array.isArray(requests) ? requests : [requests]; const normalisedTopicRequests = getNormalisedTopicRequests(topicRequests); - const isPrivateTopic = undefined; - - const perWsKeyTopics: { [key in WsKey]?: WsTopicRequest[] } = {}; - - // Sort into per wsKey arrays, in case topics are mixed together for different wsKeys - for (const topicRequest of normalisedTopicRequests) { - const derivedWsKey = - wsKey || - getWsKeyForTopic( - this.options.market, - topicRequest.topic, - isPrivateTopic, - topicRequest.category, - ); - - if ( - !perWsKeyTopics[derivedWsKey] || - !Array.isArray(perWsKeyTopics[derivedWsKey]) - ) { - perWsKeyTopics[derivedWsKey] = []; - } - - perWsKeyTopics[derivedWsKey].push(topicRequest); - } + const perWsKeyTopics = getTopicsPerWSKey(normalisedTopicRequests, wsKey); // Batch sub topics per ws key for (const wsKey in perWsKeyTopics) { @@ -364,30 +381,7 @@ export class WebsocketClient extends BaseWebsocketClient< const topicRequests = Array.isArray(requests) ? requests : [requests]; const normalisedTopicRequests = getNormalisedTopicRequests(topicRequests); - const isPrivateTopic = undefined; - - const perWsKeyTopics: { [key in WsKey]?: WsTopicRequest[] } = {}; - - // Sort into per wsKey arrays, in case topics are mixed together for different wsKeys - for (const topicRequest of normalisedTopicRequests) { - const derivedWsKey = - wsKey || - getWsKeyForTopic( - this.options.market, - topicRequest.topic, - isPrivateTopic, - topicRequest.category, - ); - - if ( - !perWsKeyTopics[derivedWsKey] || - !Array.isArray(perWsKeyTopics[derivedWsKey]) - ) { - perWsKeyTopics[derivedWsKey] = []; - } - - perWsKeyTopics[derivedWsKey].push(topicRequest); - } + const perWsKeyTopics = getTopicsPerWSKey(normalisedTopicRequests, wsKey); // Batch sub topics per ws key for (const wsKey in perWsKeyTopics) { @@ -811,7 +805,6 @@ export class WebsocketClient extends BaseWebsocketClient< // WS API Exception if (isError) { - // console.log('wsAPI error: ', parsed); try { this.getWsStore().rejectDeferredPromise( wsKey, diff --git a/tsconfig.json b/tsconfig.json index bf49483..9454c28 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -17,6 +17,6 @@ "baseUrl": ".", "outDir": "./lib" }, - "include": ["src/**/*", "src/.ts"], + "include": ["src/**/*"], "exclude": ["node_modules", "**/node_modules/*", "coverage", "doc"] }