UNPKG

@tdengine/websocket

Version:

The websocket Node.js connector for TDengine. TDengine versions 3.3.2.0 and above are recommended to use this connector.

327 lines (326 loc) 12.9 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.WsConsumer = void 0; const config_1 = require("./config"); const constant_1 = require("./constant"); const wsClient_1 = require("../client/wsClient"); const wsError_1 = require("../common/wsError"); const tmqResponse_1 = require("./tmqResponse"); const reqid_1 = require("../common/reqid"); const log_1 = __importDefault(require("../common/log")); const wsResponse_1 = require("../client/wsResponse"); class WsConsumer { constructor(wsConfig) { this._wsConfig = new config_1.TmqConfig(wsConfig); log_1.default.debug(this._wsConfig); if (wsConfig.size == 0 || !this._wsConfig.url) { throw new wsError_1.WebSocketInterfaceError(wsError_1.ErrorCode.ERR_INVALID_URL, 'invalid url, password or username needed.'); } this._wsClient = new wsClient_1.WsClient(this._wsConfig.url, this._wsConfig.timeout); } async init() { let wsSql = null; try { if (this._wsConfig.sql_url) { wsSql = new wsClient_1.WsClient(this._wsConfig.sql_url, this._wsConfig.timeout); await wsSql.connect(); await wsSql.checkVersion(); await this._wsClient.ready(); } else { throw (new wsError_1.TDWebSocketClientError(wsError_1.ErrorCode.ERR_WEBSOCKET_CONNECTION_FAIL, `connection creation failed, url: ${this._wsConfig.url}`)); } } catch (e) { await this._wsClient.close(); throw (e); } finally { if (wsSql) { await wsSql.close(); } } return this; } static async newConsumer(wsConfig) { if (wsConfig.size == 0 || !wsConfig.get(constant_1.TMQConstants.WS_URL)) { throw new wsError_1.WebSocketInterfaceError(wsError_1.ErrorCode.ERR_INVALID_URL, 'invalid url, password or username needed.'); } let wsConsumer = new WsConsumer(wsConfig); return await wsConsumer.init(); } async subscribe(topics, reqId) { if (!topics || topics.length == 0) { throw new wsError_1.TaosResultError(wsError_1.ErrorCode.ERR_INVALID_PARAMS, 'WsTmq Subscribe params is error!'); } let queryMsg = { action: constant_1.TMQMessageType.Subscribe, args: { req_id: reqid_1.ReqId.getReqID(reqId), user: this._wsConfig.user, password: this._wsConfig.password, group_id: this._wsConfig.group_id, client_id: this._wsConfig.client_id, topics: topics, offset_rest: this._wsConfig.offset_rest, auto_commit: this._wsConfig.auto_commit, auto_commit_interval_ms: this._wsConfig.auto_commit_interval_ms, config: this._wsConfig.otherConfigs }, }; this._topics = topics; return await this._wsClient.exec(JSON.stringify(queryMsg)); } async unsubscribe(reqId) { let queryMsg = { action: constant_1.TMQMessageType.Unsubscribe, args: { req_id: reqid_1.ReqId.getReqID(reqId), }, }; return await this._wsClient.exec(JSON.stringify(queryMsg)); } async poll(timeoutMs, reqId) { if (this._wsConfig.auto_commit) { if (this._commitTime) { let currTime = new Date().getTime(); let diff = Math.abs(currTime - this._commitTime); if (diff >= this._wsConfig.auto_commit_interval_ms) { await this.doCommit(); this._commitTime = new Date().getTime(); } } else { this._commitTime = new Date().getTime(); } } return await this.pollData(timeoutMs, reqId); } async subscription(reqId) { let queryMsg = { action: constant_1.TMQMessageType.ListTopics, args: { req_id: reqid_1.ReqId.getReqID(reqId), }, }; let resp = await this._wsClient.exec(JSON.stringify(queryMsg), false); return new tmqResponse_1.SubscriptionResp(resp).topics; } async commit(reqId) { await this.doCommit(reqId); return await this.assignment(); } async doCommit(reqId) { let queryMsg = { action: constant_1.TMQMessageType.Commit, args: { req_id: reqid_1.ReqId.getReqID(reqId), message_id: 0 }, }; await this._wsClient.exec(JSON.stringify(queryMsg)); } async committed(partitions, reqId) { if (!partitions || partitions.length == 0) { throw new wsError_1.TaosResultError(wsError_1.ErrorCode.ERR_INVALID_PARAMS, 'WsTmq Positions params is error!'); } let offsets = new Array(partitions.length); for (let i = 0; i < partitions.length; i++) { offsets[i] = { topic: partitions[i].topic, vgroup_id: partitions[i].vgroup_id }; offsets[i].vgroup_id = partitions[i].vgroup_id; } let queryMsg = { action: constant_1.TMQMessageType.Committed, args: { req_id: reqid_1.ReqId.getReqID(reqId), topic_vgroup_ids: offsets }, }; let resp = await this._wsClient.exec(JSON.stringify(queryMsg), false); return new tmqResponse_1.CommittedResp(resp).setTopicPartitions(offsets); } async commitOffsets(partitions) { if (!partitions || partitions.length == 0) { throw new wsError_1.TaosResultError(wsError_1.ErrorCode.ERR_INVALID_PARAMS, 'WsTmq CommitOffsets params is error!'); } const allp = []; partitions.forEach(e => { allp.push(this.commitOffset(e)); }); await Promise.all(allp); return await this.committed(partitions); } async commitOffset(partition, reqId) { if (!partition) { throw new wsError_1.TaosResultError(wsError_1.ErrorCode.ERR_INVALID_PARAMS, 'WsTmq CommitOffsets params is error!'); } let queryMsg = { action: constant_1.TMQMessageType.CommitOffset, args: { req_id: reqid_1.ReqId.getReqID(reqId), vgroup_id: partition.vgroup_id, topic: partition.topic, offset: partition.offset, }, }; return await this._wsClient.exec(JSON.stringify(queryMsg)); } async positions(partitions, reqId) { if (!partitions || partitions.length == 0) { throw new wsError_1.TaosResultError(wsError_1.ErrorCode.ERR_INVALID_PARAMS, 'WsTmq Positions params is error!'); } let offsets = new Array(partitions.length); for (let i = 0; i < partitions.length; i++) { offsets[i] = { topic: partitions[i].topic, vgroup_id: partitions[i].vgroup_id }; offsets[i].vgroup_id = partitions[i].vgroup_id; } let queryMsg = { action: constant_1.TMQMessageType.Position, args: { req_id: reqid_1.ReqId.getReqID(reqId), topic_vgroup_ids: offsets }, }; let resp = await this._wsClient.exec(JSON.stringify(queryMsg), false); return new tmqResponse_1.PartitionsResp(resp).setTopicPartitions(offsets); } async seek(partition, reqId) { if (!partition) { throw new wsError_1.TaosResultError(wsError_1.ErrorCode.ERR_INVALID_PARAMS, 'WsTmq Seek params is error!'); } let queryMsg = { action: constant_1.TMQMessageType.Seek, args: { req_id: reqid_1.ReqId.getReqID(reqId), vgroup_id: partition.vgroup_id, topic: partition.topic, offset: partition.offset, }, }; return await this._wsClient.exec(JSON.stringify(queryMsg)); } async seekToBeginning(partitions) { if (!partitions || partitions.length == 0) { throw new wsError_1.TaosResultError(wsError_1.ErrorCode.ERR_INVALID_PARAMS, 'WsTmq SeekToBeginning params is error!'); } return await this.seekToBeginOrEnd(partitions); } async seekToEnd(partitions) { if (!partitions || partitions.length == 0) { throw new wsError_1.TaosResultError(wsError_1.ErrorCode.ERR_INVALID_PARAMS, 'WsTmq SeekToEnd params is error!'); } return await this.seekToBeginOrEnd(partitions, false); } async close() { await this._wsClient.close(); } async fetchBlockData(pollResp, taosResult) { let fetchMsg = { action: 'fetch_raw_data', args: { req_id: reqid_1.ReqId.getReqID(), message_id: pollResp.message_id, }, }; let jsonStr = JSON.stringify(fetchMsg); log_1.default.debug('[wsQueryInterface.fetch.fetchMsg]===>' + jsonStr); let result = await this._wsClient.sendMsg(jsonStr); let wsResponse = new wsResponse_1.WSFetchBlockResponse(result.msg); if (wsResponse && wsResponse.data && wsResponse.blockLen > 0) { let wsTmqResponse = new tmqResponse_1.WSTmqFetchBlockInfo(wsResponse.data, taosResult); log_1.default.debug('[WSTmqFetchBlockInfo.fetchBlockData]===>' + wsTmqResponse.taosResult); if (wsTmqResponse.rows > 0) { return true; } } return false; } async pollData(timeoutMs, reqId) { let queryMsg = { action: constant_1.TMQMessageType.Poll, args: { req_id: reqid_1.ReqId.getReqID(reqId), blocking_time: timeoutMs }, }; let resp = await this._wsClient.exec(JSON.stringify(queryMsg), false); let pollResp = new tmqResponse_1.WsPollResponse(resp); let taosResult = new tmqResponse_1.TaosTmqResult(pollResp); var taosResults = new Map(); taosResults.set(pollResp.topic, taosResult); if (!pollResp.have_message || pollResp.message_type != constant_1.TMQMessageType.ResDataType) { return taosResults; } let finish = false; while (!finish) { finish = await this.fetchBlockData(pollResp, taosResult); } return taosResults; } async sendAssignmentReq(topic) { let queryMsg = { action: constant_1.TMQMessageType.GetTopicAssignment, args: { req_id: reqid_1.ReqId.getReqID(), topic: topic } }; let resp = await this._wsClient.exec(JSON.stringify(queryMsg), false); let assignmentInfo = new tmqResponse_1.AssignmentResp(resp, queryMsg.args.topic); return assignmentInfo.topicPartition; } async assignment(topics) { if (!topics || topics.length == 0) { topics = this._topics; } let topicPartitions = []; if (topics && topics.length > 0) { const allp = []; for (let i in topics) { allp.push(this.sendAssignmentReq(topics[i])); } let result = await Promise.all(allp); result.forEach(e => { topicPartitions.push(...e); }); } return topicPartitions; } async seekToBeginOrEnd(partitions, bBegin = true) { let topics = []; partitions.forEach(e => { topics.push(e.topic); }); let topicPartitions = await this.assignment(topics); let itemMap = topicPartitions.reduce((map, obj) => { map.set(obj.topic + '_' + obj.vgroup_id, obj); return map; }, new Map()); const allp = []; for (let i in partitions) { if (itemMap.has(partitions[i].topic + '_' + partitions[i].vgroup_id)) { let topicPartition = itemMap.get(partitions[i].topic + '_' + partitions[i].vgroup_id); if (topicPartition) { if (bBegin) { topicPartition.offset = topicPartition.begin; } else { topicPartition.offset = topicPartition.end; } allp.push(this.seek(topicPartition)); } } } await Promise.all(allp); } } exports.WsConsumer = WsConsumer;