diff --git a/.github/workflows/compatibility.yml b/.github/workflows/compatibility.yml index e60d8893..48ea6553 100644 --- a/.github/workflows/compatibility.yml +++ b/.github/workflows/compatibility.yml @@ -51,6 +51,7 @@ jobs: TDENGINE_CLOUD_TOKEN: ${{ secrets.TDENGINE_CLOUD_TOKEN }} TDENGINE_TEST_USERNAME: ${{ secrets.TDENGINE_TEST_USERNAME }} TDENGINE_TEST_PASSWORD: ${{ secrets.TDENGINE_TEST_PASSWORD }} + TEST_3360: true run: | npm install npm list diff --git a/nodejs/package-lock.json b/nodejs/package-lock.json index bdd55f5e..b26e6e94 100644 --- a/nodejs/package-lock.json +++ b/nodejs/package-lock.json @@ -1,12 +1,12 @@ { "name": "@tdengine/websocket", - "version": "3.2.2", + "version": "3.2.3", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@tdengine/websocket", - "version": "3.2.2", + "version": "3.2.3", "license": "MIT", "dependencies": { "async-mutex": "^0.5.0", diff --git a/nodejs/package.json b/nodejs/package.json index b301d360..5846cedb 100644 --- a/nodejs/package.json +++ b/nodejs/package.json @@ -1,6 +1,6 @@ { "name": "@tdengine/websocket", - "version": "3.2.2", + "version": "3.2.3", "description": "The websocket Node.js connector for TDengine. TDengine versions 3.3.2.0 and above are recommended to use this connector.", "source": "index.ts", "main": "lib/index.js", diff --git a/nodejs/prepare.js b/nodejs/prepare.js index d5928604..687e44ac 100644 --- a/nodejs/prepare.js +++ b/nodejs/prepare.js @@ -4,6 +4,7 @@ const path = require("path"); const { resolve, parse } = path; const tsFile = /\/src\/.*.ts$/; + async function dir(folder, ts = []) { let files = await readdir(folder); for (let f of files) { diff --git a/nodejs/src/client/wsClient.ts b/nodejs/src/client/wsClient.ts index fd19cda1..aee82d93 100644 --- a/nodejs/src/client/wsClient.ts +++ b/nodejs/src/client/wsClient.ts @@ -12,7 +12,7 @@ import { ReqId } from "../common/reqid"; import logger from "../common/log"; import { safeDecodeURIComponent, compareVersions, maskSensitiveForLog, maskUrlForLog } from "../common/utils"; import { w3cwebsocket } from "websocket"; -import { TSDB_OPTION_CONNECTION } from "../common/constant"; +import { ConnectorInfo, TSDB_OPTION_CONNECTION } from "../common/constant"; export class WsClient { private _wsConnector?: WebSocketConnector; @@ -44,6 +44,7 @@ export class WsClient { user: safeDecodeURIComponent(this._url.username), password: safeDecodeURIComponent(this._url.password), db: database, + connector: ConnectorInfo, ...(this._timezone && { tz: this._timezone }), ...(this._bearerToken && { bearer_token: this._bearerToken }), }, diff --git a/nodejs/src/common/constant.ts b/nodejs/src/common/constant.ts index 4bc8cb56..5f8f32bb 100644 --- a/nodejs/src/common/constant.ts +++ b/nodejs/src/common/constant.ts @@ -1,3 +1,5 @@ +import pkg from "../../package.json"; + export interface IndexableString { [index: number]: string; } @@ -10,6 +12,7 @@ export interface NumberIndexable { [index: number]: number; } +export const ConnectorInfo = `nodejs-ws-v${pkg.version}-ncid000`; export const BinaryQueryMessage: bigint = BigInt(6); export const FetchRawBlockMessage: bigint = BigInt(7); export const MinStmt2Version: string = "3.3.6.0"; diff --git a/nodejs/src/index.ts b/nodejs/src/index.ts index 8759924a..1d057e55 100644 --- a/nodejs/src/index.ts +++ b/nodejs/src/index.ts @@ -29,4 +29,5 @@ let setLogLevel = (level: string) => { let destroy = () => { WebSocketConnectionPool.instance().destroyed(); }; + export { sqlConnect, tmqConnect, setLogLevel, destroy }; diff --git a/nodejs/src/tmq/config.ts b/nodejs/src/tmq/config.ts index 96b05b52..eea62338 100644 --- a/nodejs/src/tmq/config.ts +++ b/nodejs/src/tmq/config.ts @@ -61,6 +61,7 @@ export class TmqConfig { } else { this.user = this.url.username; } + if (this.password) { this.url.password = this.password; } else { diff --git a/nodejs/src/tmq/wsTmq.ts b/nodejs/src/tmq/wsTmq.ts index 41693237..d95a6e99 100644 --- a/nodejs/src/tmq/wsTmq.ts +++ b/nodejs/src/tmq/wsTmq.ts @@ -23,6 +23,7 @@ import { ReqId } from "../common/reqid"; import logger from "../common/log"; import { WSFetchBlockResponse } from "../client/wsResponse"; import { maskTmqConfigForLog, maskUrlForLog } from "../common/utils"; +import { ConnectorInfo } from "../common/constant"; export class WsConsumer { private _wsClient: WsClient; @@ -109,6 +110,7 @@ export class WsConsumer { auto_commit: String(this._wsConfig.auto_commit), auto_commit_interval_ms: String(this._wsConfig.auto_commit_interval_ms), config: Object.fromEntries(this._wsConfig.otherConfigs), + connector: ConnectorInfo, }, }; this._topics = topics; diff --git a/nodejs/test/bulkPulling/sql.test.ts b/nodejs/test/bulkPulling/sql.test.ts index 33522cb1..f14a6d2d 100644 --- a/nodejs/test/bulkPulling/sql.test.ts +++ b/nodejs/test/bulkPulling/sql.test.ts @@ -1,7 +1,7 @@ import { WebSocketConnectionPool } from "../../src/client/wsConnectorPool"; import { WSConfig } from "../../src/common/config"; import { WsSql } from "../../src/sql/wsSql"; -import { Sleep, testPassword, testUsername, testEnterprise } from "../utils"; +import { Sleep, testPassword, testUsername, testEnterprise, testNon3360 } from "../utils"; import { setLevel } from "../../src/common/log"; let dsn = "ws://localhost:6041"; @@ -326,6 +326,26 @@ describe("TDWebSocket.WsSql()", () => { message: expect.stringMatching(/invalid url/i), }); }); + + testNon3360("connector version info", async () => { + const conf = new WSConfig(dsn); + conf.setUser(testUsername()); + conf.setPwd(testPassword()); + const wsSql = await WsSql.open(conf); + await Sleep(2000); + const wsRows = await wsSql.query("show connections"); + let hasNodejsWs = false; + while (await wsRows.next()) { + const data = wsRows.getData(); + if (Array.isArray(data) && data.some(v => typeof v === "string" && v.includes("nodejs-ws"))) { + hasNodejsWs = true; + break; + } + } + expect(hasNodejsWs).toBe(true); + await wsRows.close(); + await wsSql.close(); + }); }); afterAll(async () => { diff --git a/nodejs/test/bulkPulling/tmq.test.ts b/nodejs/test/bulkPulling/tmq.test.ts index 8c8a0f47..7af0c5d2 100644 --- a/nodejs/test/bulkPulling/tmq.test.ts +++ b/nodejs/test/bulkPulling/tmq.test.ts @@ -2,7 +2,7 @@ import { TMQConstants } from "../../src/tmq/constant"; import { WsConsumer } from "../../src/tmq/wsTmq"; import { WSConfig } from "../../src/common/config"; import { WsSql } from "../../src/sql/wsSql"; -import { createSTable, insertStable, testPassword, testUsername, Sleep, testEnterprise } from "../utils"; +import { createSTable, insertStable, testPassword, testUsername, Sleep, testEnterprise, testNon3360 } from "../utils"; import { WebSocketConnectionPool } from "../../src/client/wsConnectorPool"; import { setLevel } from "../../src/common/log"; @@ -510,6 +510,32 @@ describe("TDWebSocket.Tmq()", () => { message: expect.stringMatching(/invalid url/i), }); }); + + testNon3360("connector version info", async () => { + const consumer = await WsConsumer.newConsumer(configMap); + await consumer.subscribe(topics); + + const conf = new WSConfig("ws://localhost:6041"); + conf.setUser(testUsername()); + conf.setPwd(testPassword()); + const wsSql = await WsSql.open(conf); + await Sleep(2000); + + const wsRows = await wsSql.query("show connections"); + let count = 0; + while (await wsRows.next()) { + const data = wsRows.getData(); + if (Array.isArray(data) && data.some(v => typeof v === "string" && v.includes("nodejs-ws"))) { + count++; + } + } + expect(count).toBeGreaterThanOrEqual(2); + await wsRows.close(); + await wsSql.close(); + + await consumer.unsubscribe(); + await consumer.close(); + }); }); afterAll(async () => { diff --git a/nodejs/test/utils.ts b/nodejs/test/utils.ts index 2f7a258e..4af6a877 100644 --- a/nodejs/test/utils.ts +++ b/nodejs/test/utils.ts @@ -333,3 +333,4 @@ export function testPassword(): string { } export const testEnterprise = process.env.TEST_ENTERPRISE?.toLowerCase() === "true" ? test : test.skip; +export const testNon3360 = process.env.TEST_3360?.toLowerCase() === "true" ? test.skip : test; diff --git a/nodejs/tsconfig.json b/nodejs/tsconfig.json index e75363d2..9b14dd90 100644 --- a/nodejs/tsconfig.json +++ b/nodejs/tsconfig.json @@ -33,7 +33,7 @@ // "typeRoots": [], /* Specify multiple folders that act like `./node_modules/@types`. */ // "types": [], /* Specify type package names to be included without being referenced in a source file. */ // "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */ - // "resolveJsonModule": true, /* Enable importing .json files */ + "resolveJsonModule": true, /* Enable importing .json files */ // "noResolve": true, /* Disallow `import`s, `require`s or ``s from expanding the number of files TypeScript should add to a project. */ /* JavaScript Support */