javonet-nodejs-sdk 2.5.18 → 2.5.20

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -47,7 +47,7 @@ class TransmitterWebsocket {
47
47
  static sendCommand(messageByteArray, connectionData) {
48
48
  const { hostname } = connectionData;
49
49
  const options = {
50
- isDisconnectedAfterMessage: true
50
+ isDisconnectedAfterMessage: false
51
51
  };
52
52
  return new import_WebSocketClient.WebSocketClient(hostname, options).send(messageByteArray);
53
53
  }
@@ -41,8 +41,7 @@ class TransmitterWebsocketBrowser {
41
41
  */
42
42
  static async sendCommand(messageByteArray, connectionData) {
43
43
  const { hostname } = connectionData;
44
- const response = new import_WebSocketClientBrowser.WebSocketClientBrowser(hostname).send(messageByteArray);
45
- return response;
44
+ return new import_WebSocketClientBrowser.WebSocketClientBrowser(hostname).send(messageByteArray);
46
45
  }
47
46
  /**
48
47
  * @async
@@ -18,18 +18,27 @@ var __copyProps = (to, from, except, desc) => {
18
18
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
19
  var WebSocketClient_exports = {};
20
20
  __export(WebSocketClient_exports, {
21
- WebSocketClient: () => WebSocketClient
21
+ WebSocketClient: () => WebSocketClient,
22
+ clients: () => clients
22
23
  });
23
24
  module.exports = __toCommonJS(WebSocketClient_exports);
24
25
  var import_Runtime = require("../../utils/Runtime.cjs");
25
26
  const import_meta = {};
26
27
  const requireDynamic = (0, import_Runtime.getRequire)(import_meta.url);
27
28
  const WebSocketStateEnum = {
29
+ CONNECTING: 0,
30
+ OPEN: 1,
31
+ CLOSING: 2,
32
+ CLOSED: 3
33
+ };
34
+ const WebSocketStateEvent = {
28
35
  OPEN: "open",
29
36
  CLOSE: "close",
30
- ERROR: "error"
37
+ ERROR: "error",
38
+ MESSAGE: "message"
31
39
  };
32
40
  let WebSocket = null;
41
+ const clients = {};
33
42
  class WebSocketClient {
34
43
  /**
35
44
  * @param {string} url
@@ -37,45 +46,14 @@ class WebSocketClient {
37
46
  */
38
47
  constructor(url, options) {
39
48
  this.url = url;
40
- this.instance = null;
41
- this.isConnected = false;
42
- this.isDisconnectedAfterMessage = options?.isDisconnectedAfterMessage ?? true;
49
+ this.isDisconnectedAfterMessage = options?.isDisconnectedAfterMessage ?? false;
43
50
  }
44
- /**
45
- * Connects to the WebSocket server.
46
- * @async
47
- * @returns {Promise<wsClient>} - A promise that resolves when the connection is established.
48
- */
49
- async connect() {
50
- if (!WebSocket) {
51
- if ((0, import_Runtime.isNodejsRuntime)()) {
52
- try {
53
- WebSocket = requireDynamic("ws");
54
- } catch (error) {
55
- if (typeof error === "object" && error && "code" in error && error.code === "MODULE_NOT_FOUND") {
56
- throw new Error("ws module not found. Please install it using npm install ws");
57
- }
58
- throw error;
59
- }
60
- }
61
- }
62
- return new Promise((resolve, reject) => {
63
- if (!WebSocket) {
64
- reject(new Error("ws client is null"));
65
- return;
66
- }
67
- const client = new WebSocket(this.url);
68
- client.on(WebSocketStateEnum.OPEN, () => {
69
- this.instance = client;
70
- resolve(client);
71
- });
72
- client.on(WebSocketStateEnum.ERROR, (error) => {
73
- reject(error);
74
- });
75
- client.on(WebSocketStateEnum.CLOSE, () => {
76
- reject(new Error("Connection closed before receiving message"));
77
- });
78
- });
51
+ /** @type {wsClient | null} */
52
+ get instance() {
53
+ return clients[this.url] || null;
54
+ }
55
+ get isConnected() {
56
+ return this.instance ? this.instance?.readyState === WebSocketStateEnum.OPEN : false;
79
57
  }
80
58
  /**
81
59
  * Sends messageArray through websocket connection
@@ -85,21 +63,36 @@ class WebSocketClient {
85
63
  */
86
64
  send(messageArray) {
87
65
  return new Promise((resolve, reject) => {
88
- ;
89
- (this.instance ? Promise.resolve(this.instance) : this._connect()).then((client) => {
66
+ const client = this.instance;
67
+ if (client) {
90
68
  client.send(
91
69
  /** @type {any} */
92
70
  messageArray
93
71
  );
94
- client.on("message", (message) => {
72
+ const messageHandler = (message) => {
95
73
  resolve(message);
96
74
  if (this.isDisconnectedAfterMessage) {
97
75
  this.disconnect();
98
76
  }
99
- });
100
- }).catch((error) => {
101
- reject(error);
102
- });
77
+ client.removeListener(WebSocketStateEvent.MESSAGE, messageHandler);
78
+ };
79
+ client.on(WebSocketStateEvent.MESSAGE, messageHandler);
80
+ } else {
81
+ this._connect().then((ws) => {
82
+ ws.send(
83
+ /** @type {any} */
84
+ messageArray
85
+ );
86
+ const messageHandler = (message) => {
87
+ resolve(message);
88
+ if (this.isDisconnectedAfterMessage) {
89
+ this.disconnect();
90
+ }
91
+ ws.removeListener(WebSocketStateEvent.MESSAGE, messageHandler);
92
+ };
93
+ ws.on(WebSocketStateEvent.MESSAGE, messageHandler);
94
+ }).catch(reject);
95
+ }
103
96
  });
104
97
  }
105
98
  /**
@@ -108,9 +101,8 @@ class WebSocketClient {
108
101
  disconnect() {
109
102
  if (this.instance) {
110
103
  this.instance.close();
111
- this.instance = null;
104
+ delete clients[this.url];
112
105
  }
113
- this.isConnected = false;
114
106
  }
115
107
  /**
116
108
  * Connects to the WebSocket server.
@@ -119,36 +111,31 @@ class WebSocketClient {
119
111
  * @returns {Promise<wsClient>} - A promise that resolves when the connection is established.
120
112
  */
121
113
  _connect() {
122
- if (!WebSocket) {
123
- if ((0, import_Runtime.isNodejsRuntime)()) {
124
- try {
125
- WebSocket = requireDynamic("ws");
126
- } catch (error) {
127
- if (
128
- /** @type {{ code?: string }} */
129
- error.code === "MODULE_NOT_FOUND"
130
- ) {
131
- throw new Error("ws module not found. Please install it using npm install ws");
132
- }
133
- throw error;
114
+ if (!WebSocket && (0, import_Runtime.isNodejsRuntime)()) {
115
+ try {
116
+ WebSocket = requireDynamic("ws");
117
+ } catch (error) {
118
+ if (
119
+ /** @type {{ code?: string }} */
120
+ error.code === "MODULE_NOT_FOUND"
121
+ ) {
122
+ throw new Error("ws module not found. Please install it using npm install ws");
134
123
  }
124
+ throw error;
135
125
  }
136
126
  }
137
127
  return new Promise((resolve, reject) => {
138
128
  if (!WebSocket) {
139
- reject(new Error("ws client is null"));
140
- return;
129
+ return reject(new Error("ws client is null"));
141
130
  }
142
- const client = new WebSocket(this.url);
143
- client.on(WebSocketStateEnum.OPEN, () => {
144
- this.isConnected = true;
145
- this.instance = client;
146
- resolve(client);
147
- });
148
- client.on(WebSocketStateEnum.ERROR, (error) => {
149
- reject(error);
150
- });
151
- client.on(WebSocketStateEnum.CLOSE, () => {
131
+ let client = clients[this.url];
132
+ if (!client) {
133
+ client = new WebSocket(this.url);
134
+ clients[this.url] = client;
135
+ }
136
+ client.on(WebSocketStateEvent.OPEN, () => resolve(client));
137
+ client.on(WebSocketStateEvent.ERROR, (error) => reject(error));
138
+ client.on(WebSocketStateEvent.CLOSE, () => {
152
139
  reject(new Error("Connection closed before receiving message"));
153
140
  });
154
141
  });
@@ -156,5 +143,6 @@ class WebSocketClient {
156
143
  }
157
144
  // Annotate the CommonJS export names for ESM import in node:
158
145
  0 && (module.exports = {
159
- WebSocketClient
146
+ WebSocketClient,
147
+ clients
160
148
  });
@@ -18,7 +18,8 @@ var __copyProps = (to, from, except, desc) => {
18
18
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
19
  var WebSocketClientBrowser_exports = {};
20
20
  __export(WebSocketClientBrowser_exports, {
21
- WebSocketClientBrowser: () => WebSocketClientBrowser
21
+ WebSocketClientBrowser: () => WebSocketClientBrowser,
22
+ clients: () => clients
22
23
  });
23
24
  module.exports = __toCommonJS(WebSocketClientBrowser_exports);
24
25
  var import_Runtime = require("../../utils/Runtime.cjs");
@@ -35,6 +36,7 @@ let WsClient = null;
35
36
  if ((0, import_Runtime.isBrowserRuntime)()) {
36
37
  WsClient = WebSocket;
37
38
  }
39
+ const clients = {};
38
40
  class WebSocketClientBrowser {
39
41
  /**
40
42
  * @param {string} url
@@ -42,10 +44,15 @@ class WebSocketClientBrowser {
42
44
  */
43
45
  constructor(url, options) {
44
46
  this.url = url;
45
- this.instance = null;
46
- this.isConnected = false;
47
47
  this.isDisconnectedAfterMessage = options?.isDisconnectedAfterMessage ?? false;
48
48
  }
49
+ /** @type {WebSocket | null} */
50
+ get instance() {
51
+ return clients[this.url] || null;
52
+ }
53
+ get isConnected() {
54
+ return this.instance ? this.instance.readyState === WebSocket.OPEN : false;
55
+ }
49
56
  /**
50
57
  * Sends messageArray through websocket connection
51
58
  * @async
@@ -54,94 +61,81 @@ class WebSocketClientBrowser {
54
61
  */
55
62
  send(messageArray) {
56
63
  return new Promise((resolve, reject) => {
57
- try {
58
- if (this.isConnected) {
59
- this._sendMessage(messageArray, resolve, reject);
60
- } else {
61
- this._connect().then(() => {
62
- this._sendMessage(messageArray, resolve, reject);
63
- });
64
- }
65
- } catch (error) {
66
- reject(error);
64
+ const client = this.instance;
65
+ if (client && this.isConnected) {
66
+ this._sendMessage(client, messageArray, resolve, reject);
67
+ } else {
68
+ this._connect().then((ws) => {
69
+ this._sendMessage(ws, messageArray, resolve, reject);
70
+ }).catch(reject);
67
71
  }
68
72
  });
69
73
  }
70
74
  /**
71
75
  * Disconnects the WebSocket by terminating the connection.
72
- * @returns {void}
73
- *
74
76
  */
75
77
  disconnect() {
76
- if (this.instance) {
77
- this.instance.close();
78
+ const client = this.instance;
79
+ if (client) {
80
+ client.close();
81
+ delete clients[this.url];
78
82
  }
79
- this.isConnected = false;
80
83
  }
81
84
  /**
82
85
  * Connects to the WebSocket server.
83
86
  * @private
84
87
  * @async
85
- * @returns {Promise<void>} - A promise that resolves when the connection is established.
88
+ * @returns {Promise<WebSocket>}
86
89
  */
87
90
  _connect() {
88
91
  return new Promise((resolve, reject) => {
89
- if (WsClient === null) {
92
+ if (!WsClient) {
90
93
  return reject(new Error("missing WebSocket client"));
91
94
  }
92
- this.instance = new WsClient(this.url);
93
- this.instance.binaryType = "arraybuffer";
94
- this.instance.addEventListener(WebSocketState.OPEN, () => {
95
- this.isConnected = true;
96
- resolve();
97
- });
98
- this.instance.addEventListener(WebSocketState.ERROR, (error) => {
99
- reject(error);
100
- });
101
- this.instance.addEventListener(WebSocketState.CLOSE, () => {
102
- this.isConnected = false;
95
+ let client = clients[this.url];
96
+ if (!client) {
97
+ client = new WsClient(this.url);
98
+ client.binaryType = "arraybuffer";
99
+ clients[this.url] = client;
100
+ }
101
+ client.addEventListener(WebSocketState.OPEN, () => resolve(client));
102
+ client.addEventListener(WebSocketState.ERROR, reject);
103
+ client.addEventListener(WebSocketState.CLOSE, () => {
104
+ reject(new Error("Connection closed before receiving message"));
103
105
  });
104
106
  });
105
107
  }
106
108
  /**
107
109
  * Sends the data to the WebSocket server and listens for a response.
108
110
  * @private
109
- * @async
110
- * @param {Int8Array} data - The data to send.
111
- * @param {Function} resolve - The resolve function for the Promise.
112
- * @param {Function} reject - The reject function for the Promise.
113
- * @returns {void}
111
+ * @param {WebSocket} client
112
+ * @param {Int8Array} data
113
+ * @param {(value: Int8Array) => void} resolve
114
+ * @param {(reason?: any) => void} reject
114
115
  */
115
- _sendMessage(data, resolve, reject) {
116
+ _sendMessage(client, data, resolve, reject) {
116
117
  try {
117
- if (this.instance === null || !this.instance) {
118
- throw new Error("error websocket not connected");
119
- }
120
118
  const arrayBuffer = data.buffer;
121
- this.instance.send(arrayBuffer);
122
- const handleMessage = (msg) => {
123
- if (this.instance === null || !this.instance) {
124
- throw new Error("error websocket not connected");
119
+ client.send(arrayBuffer);
120
+ const handleMessage = (message) => {
121
+ if (!message?.data) {
122
+ return reject(new Error("Invalid message received"));
125
123
  }
126
- const byteArray = new Int8Array(msg.data);
124
+ const byteArray = new Int8Array(message?.data);
127
125
  resolve(byteArray);
128
126
  if (this.isDisconnectedAfterMessage) {
129
127
  this.disconnect();
130
128
  }
131
- this.instance.removeEventListener(WebSocketState.MESSAGE, handleMessage);
132
- this.instance.removeEventListener(WebSocketState.ERROR, handleError);
129
+ client.removeEventListener(WebSocketState.MESSAGE, handleMessage);
130
+ client.removeEventListener(WebSocketState.ERROR, handleError);
133
131
  };
134
132
  const handleError = (error) => {
135
133
  reject(error);
136
- if (this.instance) {
137
- this.instance.removeEventListener(WebSocketState.MESSAGE, handleMessage);
138
- this.instance.removeEventListener(WebSocketState.ERROR, handleError);
139
- }
134
+ client.removeEventListener(WebSocketState.MESSAGE, handleMessage);
135
+ client.removeEventListener(WebSocketState.ERROR, handleError);
140
136
  };
141
- if (this.instance) {
142
- this.instance.addEventListener(WebSocketState.MESSAGE, handleMessage);
143
- this.instance.addEventListener(WebSocketState.ERROR, handleError);
144
- }
137
+ client.addEventListener(WebSocketState.MESSAGE, handleMessage);
138
+ client.addEventListener(WebSocketState.ERROR, handleError);
145
139
  } catch (err) {
146
140
  reject(err);
147
141
  }
@@ -149,5 +143,6 @@ class WebSocketClientBrowser {
149
143
  }
150
144
  // Annotate the CommonJS export names for ESM import in node:
151
145
  0 && (module.exports = {
152
- WebSocketClientBrowser
146
+ WebSocketClientBrowser,
147
+ clients
153
148
  });
@@ -75,10 +75,6 @@ class RuntimeContext {
75
75
  * @returns {RuntimeContext}
76
76
  */
77
77
  static getInstance(runtimeName, connectionData) {
78
- if (!_Transmitter) {
79
- const { Transmitter } = require("../core/transmitter/Transmitter.cjs");
80
- _Transmitter = Transmitter;
81
- }
82
78
  switch (connectionData.connectionType) {
83
79
  case import_ConnectionType.ConnectionType.IN_MEMORY:
84
80
  const key = String(runtimeName);
@@ -88,6 +84,10 @@ class RuntimeContext {
88
84
  runtimeCtx.#currentCommand = null;
89
85
  return runtimeCtx;
90
86
  } else {
87
+ if (!_Transmitter) {
88
+ const { Transmitter } = require("../core/transmitter/Transmitter.cjs");
89
+ _Transmitter = Transmitter;
90
+ }
91
91
  const runtimeCtx = new RuntimeContext(runtimeName, connectionData);
92
92
  RuntimeContext.memoryRuntimeContexts.set(key, runtimeCtx);
93
93
  return runtimeCtx;
@@ -100,6 +100,10 @@ class RuntimeContext {
100
100
  runtimeCtx.#currentCommand = null;
101
101
  return runtimeCtx;
102
102
  } else {
103
+ if (!_Transmitter) {
104
+ const { Transmitter } = require("../core/transmitter/Transmitter.cjs");
105
+ _Transmitter = Transmitter;
106
+ }
103
107
  const runtimeCtx = new RuntimeContext(runtimeName, connectionData);
104
108
  RuntimeContext.networkRuntimeContexts.set(key1, runtimeCtx);
105
109
  return runtimeCtx;
@@ -1,3 +1,5 @@
1
+ /** @type {Record<string, wsClient>} */
2
+ export const clients: Record<string, wsClient>;
1
3
  export type wsClient = import("ws").WebSocket;
2
4
  export type WebSocketClass = typeof import("ws").WebSocket;
3
5
  /**
@@ -13,18 +15,11 @@ export class WebSocketClient {
13
15
  });
14
16
  /** @type {string} */
15
17
  url: string;
16
- /** @type {wsClient | null} */
17
- instance: wsClient | null;
18
- /** @type {boolean} */
19
- isConnected: boolean;
20
18
  /** @type {boolean} */
21
19
  isDisconnectedAfterMessage: boolean;
22
- /**
23
- * Connects to the WebSocket server.
24
- * @async
25
- * @returns {Promise<wsClient>} - A promise that resolves when the connection is established.
26
- */
27
- connect(): Promise<wsClient>;
20
+ /** @type {wsClient | null} */
21
+ get instance(): wsClient | null;
22
+ get isConnected(): boolean;
28
23
  /**
29
24
  * Sends messageArray through websocket connection
30
25
  * @async
@@ -1,10 +1,12 @@
1
- export type Options = {
2
- isDisconnectedAfterMessage: boolean;
3
- };
4
1
  /**
5
2
  * @typedef {object} Options
6
- * @property {boolean} isDisconnectedAfterMessage
3
+ * @property {boolean} [isDisconnectedAfterMessage]
7
4
  */
5
+ /** @type {Record<string, WebSocket>} */
6
+ export const clients: Record<string, WebSocket>;
7
+ export type Options = {
8
+ isDisconnectedAfterMessage?: boolean | undefined;
9
+ };
8
10
  /**
9
11
  * WebSocketClient class that handles WebSocket connection, message sending, and automatic disconnection.
10
12
  */
@@ -14,22 +16,13 @@ export class WebSocketClientBrowser {
14
16
  * @param {Options} [options]
15
17
  */
16
18
  constructor(url: string, options?: Options);
17
- /**
18
- * @type {string}
19
- */
19
+ /** @type {string} */
20
20
  url: string;
21
- /**
22
- * @type {WebSocket | null}
23
- */
24
- instance: WebSocket | null;
25
- /**
26
- * @type {boolean} isConnected indicates whether the WebSocket is connected.
27
- */
28
- isConnected: boolean;
29
- /**
30
- * @type {boolean}
31
- */
21
+ /** @type {boolean} */
32
22
  isDisconnectedAfterMessage: boolean;
23
+ /** @type {WebSocket | null} */
24
+ get instance(): WebSocket | null;
25
+ get isConnected(): boolean;
33
26
  /**
34
27
  * Sends messageArray through websocket connection
35
28
  * @async
@@ -39,25 +32,22 @@ export class WebSocketClientBrowser {
39
32
  send(messageArray: Int8Array): Promise<Int8Array>;
40
33
  /**
41
34
  * Disconnects the WebSocket by terminating the connection.
42
- * @returns {void}
43
- *
44
35
  */
45
36
  disconnect(): void;
46
37
  /**
47
38
  * Connects to the WebSocket server.
48
39
  * @private
49
40
  * @async
50
- * @returns {Promise<void>} - A promise that resolves when the connection is established.
41
+ * @returns {Promise<WebSocket>}
51
42
  */
52
43
  private _connect;
53
44
  /**
54
45
  * Sends the data to the WebSocket server and listens for a response.
55
46
  * @private
56
- * @async
57
- * @param {Int8Array} data - The data to send.
58
- * @param {Function} resolve - The resolve function for the Promise.
59
- * @param {Function} reject - The reject function for the Promise.
60
- * @returns {void}
47
+ * @param {WebSocket} client
48
+ * @param {Int8Array} data
49
+ * @param {(value: Int8Array) => void} resolve
50
+ * @param {(reason?: any) => void} reject
61
51
  */
62
52
  private _sendMessage;
63
53
  }
@@ -29,7 +29,7 @@ export class TransmitterWebsocket {
29
29
  static sendCommand(messageByteArray, connectionData) {
30
30
  const { hostname } = connectionData
31
31
  const options = {
32
- isDisconnectedAfterMessage: true,
32
+ isDisconnectedAfterMessage: false,
33
33
  }
34
34
  return new WebSocketClient(hostname, options).send(messageByteArray)
35
35
  }
@@ -23,8 +23,7 @@ export class TransmitterWebsocketBrowser {
23
23
  */
24
24
  static async sendCommand(messageByteArray, connectionData) {
25
25
  const { hostname } = connectionData
26
- const response = new WebSocketClientBrowser(hostname).send(messageByteArray)
27
- return response
26
+ return new WebSocketClientBrowser(hostname).send(messageByteArray)
28
27
  }
29
28
 
30
29
  /**
@@ -9,17 +9,33 @@ const requireDynamic = getRequire(import.meta.url)
9
9
  /**
10
10
  * Enum for WebSocket states.
11
11
  * @readonly
12
- * @enum {string}
12
+ * @enum {number}
13
13
  */
14
14
  const WebSocketStateEnum = {
15
+ CONNECTING: 0,
16
+ OPEN: 1,
17
+ CLOSING: 2,
18
+ CLOSED: 3,
19
+ }
20
+
21
+ /**
22
+ * Enum for WebSocket event states.
23
+ * @readonly
24
+ * @enum {string}
25
+ */
26
+ const WebSocketStateEvent = {
15
27
  OPEN: 'open',
16
28
  CLOSE: 'close',
17
29
  ERROR: 'error',
30
+ MESSAGE: 'message',
18
31
  }
19
32
 
20
33
  /** @type {WebSocketClass | null} */
21
34
  let WebSocket = null
22
35
 
36
+ /** @type {Record<string, wsClient>} */
37
+ export const clients = {}
38
+
23
39
  /**
24
40
  * WebSocketClient class that handles WebSocket connection, message sending, and automatic disconnection.
25
41
  */
@@ -31,59 +47,17 @@ class WebSocketClient {
31
47
  constructor(url, options) {
32
48
  /** @type {string} */
33
49
  this.url = url
34
- /** @type {wsClient | null} */
35
- this.instance = null
36
50
  /** @type {boolean} */
37
- this.isConnected = false
38
- /** @type {boolean} */
39
- this.isDisconnectedAfterMessage = options?.isDisconnectedAfterMessage ?? true
51
+ this.isDisconnectedAfterMessage = options?.isDisconnectedAfterMessage ?? false
40
52
  }
41
53
 
42
- /**
43
- * Connects to the WebSocket server.
44
- * @async
45
- * @returns {Promise<wsClient>} - A promise that resolves when the connection is established.
46
- */
47
- async connect() {
48
- if (!WebSocket) {
49
- if (isNodejsRuntime()) {
50
- try {
51
- WebSocket = requireDynamic('ws')
52
- } catch (error) {
53
- if (
54
- typeof error === 'object' &&
55
- error &&
56
- 'code' in error &&
57
- error.code === 'MODULE_NOT_FOUND'
58
- ) {
59
- throw new Error('ws module not found. Please install it using npm install ws')
60
- }
61
- throw error
62
- }
63
- }
64
- }
65
-
66
- return new Promise((resolve, reject) => {
67
- if (!WebSocket) {
68
- reject(new Error('ws client is null'))
69
- return
70
- }
71
- const client = new WebSocket(this.url)
72
-
73
- client.on(WebSocketStateEnum.OPEN, () => {
74
- this.instance = client
75
- resolve(client)
76
- })
77
-
78
- // eslint-disable-next-line no-unused-vars
79
- client.on(WebSocketStateEnum.ERROR, (/** @type {unknown} */ error) => {
80
- reject(error)
81
- })
54
+ /** @type {wsClient | null} */
55
+ get instance() {
56
+ return clients[this.url] || null
57
+ }
82
58
 
83
- client.on(WebSocketStateEnum.CLOSE, () => {
84
- reject(new Error('Connection closed before receiving message'))
85
- })
86
- })
59
+ get isConnected() {
60
+ return this.instance ? this.instance?.readyState === WebSocketStateEnum.OPEN : false
87
61
  }
88
62
 
89
63
  /**
@@ -94,21 +68,32 @@ class WebSocketClient {
94
68
  */
95
69
  send(messageArray) {
96
70
  return new Promise((resolve, reject) => {
97
- ;(this.instance ? Promise.resolve(this.instance) : this._connect())
98
- .then((client) => {
99
- client.send(/** @type {any} */ (messageArray))
100
-
101
- client.on('message', (/** @type {any} */ message) => {
102
- resolve(message)
103
-
104
- if (this.isDisconnectedAfterMessage) {
105
- this.disconnect()
71
+ const client = this.instance
72
+ if (client) {
73
+ client.send(/** @type {any} */ (messageArray))
74
+ const messageHandler = (/** @type {any} */ message) => {
75
+ resolve(message)
76
+ if (this.isDisconnectedAfterMessage) {
77
+ this.disconnect()
78
+ }
79
+ client.removeListener(WebSocketStateEvent.MESSAGE, messageHandler)
80
+ }
81
+ client.on(WebSocketStateEvent.MESSAGE, messageHandler)
82
+ } else {
83
+ this._connect()
84
+ .then((ws) => {
85
+ ws.send(/** @type {any} */ (messageArray))
86
+ const messageHandler = (/** @type {any} */ message) => {
87
+ resolve(message)
88
+ if (this.isDisconnectedAfterMessage) {
89
+ this.disconnect()
90
+ }
91
+ ws.removeListener(WebSocketStateEvent.MESSAGE, messageHandler)
106
92
  }
93
+ ws.on(WebSocketStateEvent.MESSAGE, messageHandler)
107
94
  })
108
- })
109
- .catch((error) => {
110
- reject(error)
111
- })
95
+ .catch(reject)
96
+ }
112
97
  })
113
98
  }
114
99
 
@@ -118,9 +103,8 @@ class WebSocketClient {
118
103
  disconnect() {
119
104
  if (this.instance) {
120
105
  this.instance.close()
121
- this.instance = null
106
+ delete clients[this.url]
122
107
  }
123
- this.isConnected = false
124
108
  }
125
109
 
126
110
  /**
@@ -130,38 +114,31 @@ class WebSocketClient {
130
114
  * @returns {Promise<wsClient>} - A promise that resolves when the connection is established.
131
115
  */
132
116
  _connect() {
133
- if (!WebSocket) {
134
- if (isNodejsRuntime()) {
135
- try {
136
- WebSocket = requireDynamic('ws')
137
- } catch (error) {
138
- if (/** @type {{ code?: string }} */ (error).code === 'MODULE_NOT_FOUND') {
139
- throw new Error('ws module not found. Please install it using npm install ws')
140
- }
141
- throw error
117
+ if (!WebSocket && isNodejsRuntime()) {
118
+ try {
119
+ WebSocket = requireDynamic('ws')
120
+ } catch (error) {
121
+ if (/** @type {{ code?: string }} */ (error).code === 'MODULE_NOT_FOUND') {
122
+ throw new Error('ws module not found. Please install it using npm install ws')
142
123
  }
124
+ throw error
143
125
  }
144
126
  }
145
127
 
146
128
  return new Promise((resolve, reject) => {
147
129
  if (!WebSocket) {
148
- reject(new Error('ws client is null'))
149
- return
130
+ return reject(new Error('ws client is null'))
150
131
  }
151
- const client = new WebSocket(this.url)
152
-
153
- client.on(WebSocketStateEnum.OPEN, () => {
154
- this.isConnected = true
155
- this.instance = client
156
- resolve(client)
157
- })
158
132
 
159
- // eslint-disable-next-line no-unused-vars
160
- client.on(WebSocketStateEnum.ERROR, (/** @type {unknown} */ error) => {
161
- reject(error)
162
- })
133
+ let client = clients[this.url]
134
+ if (!client) {
135
+ client = new WebSocket(this.url)
136
+ clients[this.url] = client
137
+ }
163
138
 
164
- client.on(WebSocketStateEnum.CLOSE, () => {
139
+ client.on(WebSocketStateEvent.OPEN, () => resolve(client))
140
+ client.on(WebSocketStateEvent.ERROR, (/** @type {unknown} */ error) => reject(error))
141
+ client.on(WebSocketStateEvent.CLOSE, () => {
165
142
  reject(new Error('Connection closed before receiving message'))
166
143
  })
167
144
  })
@@ -1,5 +1,5 @@
1
1
  // @ts-check
2
- import { isBrowserRuntime } from "../../utils/Runtime.js"
2
+ import { isBrowserRuntime } from '../../utils/Runtime.js'
3
3
 
4
4
  const WebSocketState = /** @type {const} */ ({
5
5
  OPEN: 'open',
@@ -14,15 +14,17 @@ const WebSocketState = /** @type {const} */ ({
14
14
  let WsClient = null
15
15
 
16
16
  if (isBrowserRuntime()) {
17
- /** @type {typeof WebSocket} */
18
17
  WsClient = WebSocket
19
18
  }
20
19
 
21
20
  /**
22
21
  * @typedef {object} Options
23
- * @property {boolean} isDisconnectedAfterMessage
22
+ * @property {boolean} [isDisconnectedAfterMessage]
24
23
  */
25
24
 
25
+ /** @type {Record<string, WebSocket>} */
26
+ export const clients = {}
27
+
26
28
  /**
27
29
  * WebSocketClient class that handles WebSocket connection, message sending, and automatic disconnection.
28
30
  */
@@ -32,25 +34,20 @@ class WebSocketClientBrowser {
32
34
  * @param {Options} [options]
33
35
  */
34
36
  constructor(url, options) {
35
- /**
36
- * @type {string}
37
- */
37
+ /** @type {string} */
38
38
  this.url = url
39
39
 
40
- /**
41
- * @type {WebSocket | null}
42
- */
43
- this.instance = null
40
+ /** @type {boolean} */
41
+ this.isDisconnectedAfterMessage = options?.isDisconnectedAfterMessage ?? false
42
+ }
44
43
 
45
- /**
46
- * @type {boolean} isConnected indicates whether the WebSocket is connected.
47
- */
48
- this.isConnected = false
44
+ /** @type {WebSocket | null} */
45
+ get instance() {
46
+ return clients[this.url] || null
47
+ }
49
48
 
50
- /**
51
- * @type {boolean}
52
- */
53
- this.isDisconnectedAfterMessage = options?.isDisconnectedAfterMessage ?? false
49
+ get isConnected() {
50
+ return this.instance ? this.instance.readyState === WebSocket.OPEN : false
54
51
  }
55
52
 
56
53
  /**
@@ -61,57 +58,53 @@ class WebSocketClientBrowser {
61
58
  */
62
59
  send(messageArray) {
63
60
  return new Promise((resolve, reject) => {
64
- try {
65
- if (this.isConnected) {
66
- this._sendMessage(messageArray, resolve, reject)
67
- } else {
68
- this._connect().then(() => {
69
- this._sendMessage(messageArray, resolve, reject)
61
+ const client = this.instance
62
+ if (client && this.isConnected) {
63
+ this._sendMessage(client, messageArray, resolve, reject)
64
+ } else {
65
+ this._connect()
66
+ .then((ws) => {
67
+ this._sendMessage(ws, messageArray, resolve, reject)
70
68
  })
71
- }
72
- } catch (error) {
73
- reject(error)
69
+ .catch(reject)
74
70
  }
75
71
  })
76
72
  }
77
73
 
78
74
  /**
79
75
  * Disconnects the WebSocket by terminating the connection.
80
- * @returns {void}
81
- *
82
76
  */
83
77
  disconnect() {
84
- if (this.instance) {
85
- this.instance.close()
78
+ const client = this.instance
79
+ if (client) {
80
+ client.close()
81
+ delete clients[this.url]
86
82
  }
87
- this.isConnected = false
88
83
  }
89
84
 
90
85
  /**
91
86
  * Connects to the WebSocket server.
92
87
  * @private
93
88
  * @async
94
- * @returns {Promise<void>} - A promise that resolves when the connection is established.
89
+ * @returns {Promise<WebSocket>}
95
90
  */
96
91
  _connect() {
97
92
  return new Promise((resolve, reject) => {
98
- if (WsClient === null) {
93
+ if (!WsClient) {
99
94
  return reject(new Error('missing WebSocket client'))
100
95
  }
101
- this.instance = new WsClient(this.url)
102
- this.instance.binaryType = 'arraybuffer'
103
-
104
- this.instance.addEventListener(WebSocketState.OPEN, () => {
105
- this.isConnected = true
106
- resolve()
107
- })
108
96
 
109
- this.instance.addEventListener(WebSocketState.ERROR, (error) => {
110
- reject(error)
111
- })
97
+ let client = clients[this.url]
98
+ if (!client) {
99
+ client = new WsClient(this.url)
100
+ client.binaryType = 'arraybuffer'
101
+ clients[this.url] = client
102
+ }
112
103
 
113
- this.instance.addEventListener(WebSocketState.CLOSE, () => {
114
- this.isConnected = false
104
+ client.addEventListener(WebSocketState.OPEN, () => resolve(client))
105
+ client.addEventListener(WebSocketState.ERROR, reject)
106
+ client.addEventListener(WebSocketState.CLOSE, () => {
107
+ reject(new Error('Connection closed before receiving message'))
115
108
  })
116
109
  })
117
110
  }
@@ -119,51 +112,41 @@ class WebSocketClientBrowser {
119
112
  /**
120
113
  * Sends the data to the WebSocket server and listens for a response.
121
114
  * @private
122
- * @async
123
- * @param {Int8Array} data - The data to send.
124
- * @param {Function} resolve - The resolve function for the Promise.
125
- * @param {Function} reject - The reject function for the Promise.
126
- * @returns {void}
115
+ * @param {WebSocket} client
116
+ * @param {Int8Array} data
117
+ * @param {(value: Int8Array) => void} resolve
118
+ * @param {(reason?: any) => void} reject
127
119
  */
128
- _sendMessage(data, resolve, reject) {
120
+ _sendMessage(client, data, resolve, reject) {
129
121
  try {
130
- if (this.instance === null || !this.instance) {
131
- throw new Error('error websocket not connected')
132
- }
133
-
134
122
  const arrayBuffer = data.buffer
135
- this.instance.send(arrayBuffer)
123
+ client.send(arrayBuffer)
136
124
 
137
- // @ts-ignore
138
- const handleMessage = (msg) => {
139
- if (this.instance === null || !this.instance) {
140
- throw new Error('error websocket not connected')
125
+ const handleMessage = (/** @type {any} */ message) => {
126
+ if (!message?.data) {
127
+ return reject(new Error('Invalid message received'))
141
128
  }
142
129
 
143
- const byteArray = new Int8Array(msg.data)
130
+ const byteArray = new Int8Array(message?.data)
144
131
  resolve(byteArray)
145
132
 
146
133
  if (this.isDisconnectedAfterMessage) {
147
134
  this.disconnect()
148
135
  }
149
136
 
150
- this.instance.removeEventListener(WebSocketState.MESSAGE, handleMessage)
151
- this.instance.removeEventListener(WebSocketState.ERROR, handleError)
137
+ client.removeEventListener(WebSocketState.MESSAGE, handleMessage)
138
+ client.removeEventListener(WebSocketState.ERROR, handleError)
152
139
  }
153
140
 
154
- const handleError = (/** @type {any} */ error) => {
141
+ const handleError = (/** @type {unknown} */ error) => {
155
142
  reject(error)
156
143
 
157
- if (this.instance) {
158
- this.instance.removeEventListener(WebSocketState.MESSAGE, handleMessage)
159
- this.instance.removeEventListener(WebSocketState.ERROR, handleError)
160
- }
144
+ client.removeEventListener(WebSocketState.MESSAGE, handleMessage)
145
+ client.removeEventListener(WebSocketState.ERROR, handleError)
161
146
  }
162
147
 
163
- if (this.instance) {
164
- this.instance.addEventListener(WebSocketState.MESSAGE, handleMessage)
165
- this.instance.addEventListener(WebSocketState.ERROR, handleError)
166
- }
148
+ client.addEventListener(WebSocketState.MESSAGE, handleMessage)
149
+ client.addEventListener(WebSocketState.ERROR, handleError)
167
150
  } catch (err) {
168
151
  reject(err)
169
152
  }
@@ -81,10 +81,6 @@ class RuntimeContext {
81
81
  * @returns {RuntimeContext}
82
82
  */
83
83
  static getInstance(runtimeName, connectionData) {
84
- if (!_Transmitter) {
85
- const { Transmitter } = requireDynamic('../core/transmitter/Transmitter.js')
86
- _Transmitter = Transmitter
87
- }
88
84
  switch (connectionData.connectionType) {
89
85
  case ConnectionType.IN_MEMORY:
90
86
  const key = String(runtimeName)
@@ -94,6 +90,10 @@ class RuntimeContext {
94
90
  runtimeCtx.#currentCommand = null
95
91
  return runtimeCtx
96
92
  } else {
93
+ if (!_Transmitter) {
94
+ const { Transmitter } = requireDynamic('../core/transmitter/Transmitter.js')
95
+ _Transmitter = Transmitter
96
+ }
97
97
  const runtimeCtx = new RuntimeContext(runtimeName, connectionData)
98
98
  RuntimeContext.memoryRuntimeContexts.set(key, runtimeCtx)
99
99
  return runtimeCtx
@@ -106,6 +106,10 @@ class RuntimeContext {
106
106
  runtimeCtx.#currentCommand = null
107
107
  return runtimeCtx
108
108
  } else {
109
+ if (!_Transmitter) {
110
+ const { Transmitter } = requireDynamic('../core/transmitter/Transmitter.js')
111
+ _Transmitter = Transmitter
112
+ }
109
113
  const runtimeCtx = new RuntimeContext(runtimeName, connectionData)
110
114
  RuntimeContext.networkRuntimeContexts.set(key1, runtimeCtx)
111
115
  return runtimeCtx
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "javonet-nodejs-sdk",
3
- "version": "2.5.18",
3
+ "version": "2.5.20",
4
4
  "description": "Javonet allows you to reference and use modules or packages written in (Java/Kotlin/Groovy/Clojure, C#/VB.NET, Ruby, Perl, Python, JavaScript/TypeScript) like they were created in your technology. It works on Linux/Windows and MacOS for applications created in JVM, CLR/Netcore, Perl, Python, Ruby, NodeJS, C++ or GoLang and gives you unparalleled freedom and flexibility with native performance in building your mixed-technologies products. Let it be accessing best AI or cryptography libraries, devices SDKs, legacy client modules, internal custom packages or anything from public repositories available on NPM, Nuget, PyPI, Maven/Gradle, RubyGems or GitHub. Get free from programming languages barriers today! For more information check out our guides at https://www.javonet.com/guides/v2/",
5
5
  "keywords": [],
6
6
  "author": "SdNCenter Sp. z o. o.",
@@ -30,11 +30,19 @@
30
30
  "default": "./lib/utils/CreateRequire.node.js"
31
31
  }
32
32
  },
33
+ "jest": {
34
+ "verbose": true,
35
+ "testResultsProcessor": "./node_modules/jest-junit-reporter",
36
+ "coverageReporters": [
37
+ "json",
38
+ "lcov",
39
+ "text",
40
+ "clover",
41
+ "cobertura"
42
+ ]
43
+ },
33
44
  "scripts": {
34
- "test": "cross-env NODE_OPTIONS=--experimental-vm-modules jest tests/unitTests tests/functionalTests tests/performanceTests --maxWorkers=3 --colors",
35
- "test:watch": "cross-env NODE_OPTIONS=--experimental-vm-modules jest tests/unitTests tests/functionalTests tests/performanceTests --maxWorkers=3 --colors --watch",
36
- "test:unit": "cross-env NODE_OPTIONS=--experimental-vm-modules jest tests/unitTests --maxWorkers=3 --colors --outputName=\"test-report.xml\" -t=\"(Unit)\" --coverage ",
37
- "test:functional": "cross-env NODE_OPTIONS=--experimental-vm-modules jest tests/functionalTests --maxWorkers=1 --colors -t=\"(Functional)\"",
45
+ "test": "cross-env NODE_OPTIONS=--experimental-vm-modules jest tests/unitTests -t=\"(Unit)\" --maxWorkers=3 --colors --coverage",
38
46
  "build:types": "tsc --project tsconfig.declarations.json",
39
47
  "build:cjs": "tsup && node scripts/resolve-dist-imports.js",
40
48
  "build": "npm run build:cjs && npm run build:types",