kucoin-universal-sdk
Version:
Official KuCoin Universal SDK.
154 lines • 6.74 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.DefaultWsService = void 0;
const constant_1 = require("../../model/constant");
const default_transport_1 = require("./default_transport");
const default_ws_callback_1 = require("./default_ws_callback");
const default_ws_client_1 = require("./default_ws_client");
const default_ws_token_provider_1 = require("./default_ws_token_provider");
const model_1 = require("../../model");
const sub_1 = require("../util/sub");
const common_1 = require("../../model/common");
const crypto_1 = require("crypto");
const events_1 = require("events");
const common_2 = require("../../common");
/**
* DefaultWsService implements the WebSocket service interface for handling real-time data communication.
* It manages WebSocket connections, subscriptions, and message handling with automatic reconnection support.
*/
class DefaultWsService {
constructor(option, domain, privateChannel, versionString) {
if (!option.webSocketClientOption) {
throw new Error('WebSocketClientOption is undefined');
}
this.wsOption = option.webSocketClientOption;
this.privateChannel = privateChannel;
this.tokenTransport = new default_transport_1.DefaultTransport(option, versionString);
this.topicManager = new default_ws_callback_1.TopicManager();
this.eventEmitter = new events_1.EventEmitter();
this.eventEmitter.on('event', (event, msg) => {
if (this.wsOption.eventCallback) {
try {
this.wsOption.eventCallback(event, msg);
}
catch (e) {
common_2.logger.error(`call event callback error, event: ${event}`, e);
}
}
});
this.client = new default_ws_client_1.WebSocketClient(new default_ws_token_provider_1.DefaultWsTokenProvider(this.tokenTransport, domain, privateChannel), this.wsOption);
this.client.on('event', (event, msg) => {
this.eventEmitter.emit('event', event, msg);
});
this.client.on('message', (message) => {
this.processMessages(message);
});
this.client.on('reconnected', () => {
this.recovery();
});
}
start() {
return this.client.start();
}
stop() {
return Promise.all([this.tokenTransport.close(), this.client.stop()]).then();
}
subscribe(prefix, args, callback) {
// Create subscription info with prefix, args, and callback
const subInfo = new sub_1.SubInfo(prefix, args || [], callback);
const subId = subInfo.toId();
// Get callback manager for the prefix and attempt to add subscription
const callbackManager = this.topicManager.getCallbackManager(prefix);
const created = callbackManager.add(subInfo);
// Check if already subscribed
if (!created) {
common_2.logger.warn(`Already subscribed: ${subId}`);
return Promise.reject(new Error('Already subscribed'));
}
// Create subscription message
const subEvent = new common_1.WsMessage();
subEvent.id = subId;
subEvent.type = constant_1.MessageType.SubscribeMessage;
subEvent.topic = subInfo.subTopic();
subEvent.privateChannel = this.privateChannel;
subEvent.response = true;
return this.client
.write(subEvent, this.wsOption.writeTimeout)
.then(() => {
common_2.logger.info(`subscribed id: ${subId}`);
return subId;
})
.catch((err) => {
// Clean up on failure
const callbackManager = this.topicManager.getCallbackManager(subInfo.prefix);
callbackManager.remove(subId);
common_2.logger.error(`subscribe id: ${subId}, error`, err);
throw err;
});
}
unsubscribe(id) {
return new Promise((resolve, reject) => {
const subInfo = sub_1.SubInfo.fromId(id);
const callbackManager = this.topicManager.getCallbackManager(subInfo.prefix);
const subEvent = new common_1.WsMessage();
subEvent.id = (0, crypto_1.randomUUID)().toString();
subEvent.type = constant_1.MessageType.UnsubscribeMessage;
subEvent.topic = subInfo.subTopic();
subEvent.privateChannel = this.privateChannel;
subEvent.response = true;
this.client
.write(subEvent, this.wsOption.writeTimeout)
.then(() => {
callbackManager.remove(id);
common_2.logger.info(`unsubscribe id: ${id}`);
resolve();
})
.catch((e) => {
common_2.logger.error(`unsubscribe id: ${id}, error`, e);
reject(e);
});
});
}
processMessages(message) {
const callbackManager = this.topicManager.getCallbackManager(message.topic);
if (!callbackManager) {
common_2.logger.warn(`Unknown topic: ${message.topic}`);
return;
}
const callback = callbackManager.get(message.topic);
if (!callback) {
common_2.logger.warn(`Unknown callback for topic: ${message.topic}`);
return;
}
try {
callback.onMessage(message);
}
catch (err) {
common_2.logger.error('Error processing callback', err);
this.eventEmitter.emit('event', model_1.WebSocketEvent.EventCallbackError, String(err));
}
}
recovery() {
common_2.logger.info('WebSocket client reconnected, resubscribe...');
const oldTopicManager = this.topicManager;
this.topicManager = new default_ws_callback_1.TopicManager();
oldTopicManager.range((key, value) => {
for (const sub of value.getSubInfo()) {
if (sub.callback) {
this.subscribe(sub.prefix, sub.args, sub.callback)
.then((id) => {
common_2.logger.info(`Resubscribe success, id:${id}`);
this.eventEmitter.emit('event', model_1.WebSocketEvent.EventReSubscribeOK, id);
})
.catch((err) => {
common_2.logger.info(`Resubscribe error, id:${sub.toId()}, err:${err}`);
this.eventEmitter.emit('event', model_1.WebSocketEvent.EventReSubscribeError, err.toString());
});
}
}
return true;
});
}
}
exports.DefaultWsService = DefaultWsService;
//# sourceMappingURL=default_ws_service.js.map