node-opcua-transport 2.64.1 → 2.65.0

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.
Files changed (35) hide show
  1. package/dist/source/AcknowledgeMessage.d.ts +27 -27
  2. package/dist/source/AcknowledgeMessage.js +78 -78
  3. package/dist/source/HelloMessage.d.ts +27 -27
  4. package/dist/source/HelloMessage.js +94 -94
  5. package/dist/source/TCPErrorMessage.d.ts +18 -18
  6. package/dist/source/TCPErrorMessage.js +46 -46
  7. package/dist/source/client_tcp_transport.d.ts +68 -68
  8. package/dist/source/client_tcp_transport.js +313 -313
  9. package/dist/source/index.d.ts +11 -11
  10. package/dist/source/index.js +23 -23
  11. package/dist/source/message_builder_base.d.ts +61 -61
  12. package/dist/source/message_builder_base.js +206 -206
  13. package/dist/source/server_tcp_transport.d.ts +48 -48
  14. package/dist/source/server_tcp_transport.js +226 -226
  15. package/dist/source/tcp_transport.d.ts +126 -126
  16. package/dist/source/tcp_transport.js +357 -357
  17. package/dist/source/tools.d.ts +13 -13
  18. package/dist/source/tools.js +103 -103
  19. package/dist/source/utils.d.ts +2 -2
  20. package/dist/source/utils.js +8 -8
  21. package/dist/test-fixtures/fixture_full_tcp_packets.d.ts +21 -21
  22. package/dist/test-fixtures/fixture_full_tcp_packets.js +41 -41
  23. package/dist/test-fixtures/index.d.ts +1 -1
  24. package/dist/test-fixtures/index.js +13 -13
  25. package/dist/test_helpers/direct_transport.d.ts +14 -14
  26. package/dist/test_helpers/direct_transport.js +62 -62
  27. package/dist/test_helpers/fake_server.d.ts +17 -17
  28. package/dist/test_helpers/fake_server.js +54 -54
  29. package/dist/test_helpers/half_com_channel.d.ts +10 -10
  30. package/dist/test_helpers/half_com_channel.js +31 -31
  31. package/dist/test_helpers/index.d.ts +4 -4
  32. package/dist/test_helpers/index.js +16 -16
  33. package/dist/test_helpers/socket_transport.d.ts +10 -10
  34. package/dist/test_helpers/socket_transport.js +30 -30
  35. package/package.json +4 -4
@@ -1,358 +1,358 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.TCP_transport = exports.getFakeTransport = exports.setFakeTransport = void 0;
4
- /**
5
- * @module node-opcua-transport
6
- */
7
- const events_1 = require("events");
8
- const chalk = require("chalk");
9
- const node_opcua_assert_1 = require("node-opcua-assert");
10
- const node_opcua_buffer_utils_1 = require("node-opcua-buffer-utils");
11
- const debug = require("node-opcua-debug");
12
- const node_opcua_object_registry_1 = require("node-opcua-object-registry");
13
- const node_opcua_packet_assembler_1 = require("node-opcua-packet-assembler");
14
- const message_builder_base_1 = require("./message_builder_base");
15
- const tools_1 = require("./tools");
16
- const debugLog = debug.make_debugLog(__filename);
17
- const doDebug = debug.checkDebugFlag(__filename);
18
- const errorLog = debug.make_errorLog(__filename);
19
- let fakeSocket = {
20
- invalid: true,
21
- destroy() {
22
- errorLog("MockSocket.destroy");
23
- },
24
- end() {
25
- errorLog("MockSocket.end");
26
- }
27
- };
28
- function setFakeTransport(mockSocket) {
29
- fakeSocket = mockSocket;
30
- }
31
- exports.setFakeTransport = setFakeTransport;
32
- function getFakeTransport() {
33
- if (fakeSocket.invalid) {
34
- throw new Error("getFakeTransport: setFakeTransport must be called first - BadProtocolVersionUnsupported");
35
- }
36
- return fakeSocket;
37
- }
38
- exports.getFakeTransport = getFakeTransport;
39
- let counter = 0;
40
- // tslint:disable:class-name
41
- class TCP_transport extends events_1.EventEmitter {
42
- constructor() {
43
- super();
44
- this.name = this.constructor.name + counter;
45
- counter += 1;
46
- this._timerId = null;
47
- this._timeout = 30000; // 30 seconds timeout
48
- this._socket = null;
49
- this.headerSize = 8;
50
- this.protocolVersion = 0;
51
- this._disconnecting = false;
52
- this._pendingBuffer = undefined;
53
- this.bytesWritten = 0;
54
- this.bytesRead = 0;
55
- this._theCallback = undefined;
56
- this.chunkWrittenCount = 0;
57
- this.chunkReadCount = 0;
58
- this._onSocketClosedHasBeenCalled = false;
59
- this._onSocketEndedHasBeenCalled = false;
60
- TCP_transport.registry.register(this);
61
- }
62
- get timeout() {
63
- return this._timeout;
64
- }
65
- set timeout(value) {
66
- debugLog("Setting socket " + this.name + " timeout = ", value);
67
- this._timeout = value;
68
- }
69
- dispose() {
70
- this._cleanup_timers();
71
- (0, node_opcua_assert_1.assert)(!this._timerId);
72
- if (this._socket) {
73
- this._socket.destroy();
74
- this._socket.removeAllListeners();
75
- this._socket = null;
76
- }
77
- TCP_transport.registry.unregister(this);
78
- }
79
- /**
80
- * ```createChunk``` is used to construct a pre-allocated chunk to store up to ```length``` bytes of data.
81
- * The created chunk includes a prepended header for ```chunk_type``` of size ```self.headerSize```.
82
- *
83
- * @method createChunk
84
- * @param msgType
85
- * @param chunkType {String} chunk type. should be 'F' 'C' or 'A'
86
- * @param length
87
- * @return a buffer object with the required length representing the chunk.
88
- *
89
- * Note:
90
- * - only one chunk can be created at a time.
91
- * - a created chunk should be committed using the ```write``` method before an other one is created.
92
- */
93
- createChunk(msgType, chunkType, length) {
94
- (0, node_opcua_assert_1.assert)(msgType === "MSG");
95
- (0, node_opcua_assert_1.assert)(this._pendingBuffer === undefined, "createChunk has already been called ( use write first)");
96
- const totalLength = length + this.headerSize;
97
- const buffer = (0, node_opcua_buffer_utils_1.createFastUninitializedBuffer)(totalLength);
98
- (0, tools_1.writeTCPMessageHeader)("MSG", chunkType, totalLength, buffer);
99
- this._pendingBuffer = buffer;
100
- return buffer;
101
- }
102
- /**
103
- * write the message_chunk on the socket.
104
- * @method write
105
- * @param messageChunk
106
- *
107
- * Notes:
108
- * - the message chunk must have been created by ```createChunk```.
109
- * - once a message chunk has been written, it is possible to call ```createChunk``` again.
110
- *
111
- */
112
- write(messageChunk) {
113
- (0, node_opcua_assert_1.assert)(this._pendingBuffer === undefined || this._pendingBuffer === messageChunk, " write should be used with buffer created by createChunk");
114
- const header = (0, message_builder_base_1.readRawMessageHeader)(messageChunk);
115
- (0, node_opcua_assert_1.assert)(header.length === messageChunk.length);
116
- (0, node_opcua_assert_1.assert)(["F", "C", "A"].indexOf(header.messageHeader.isFinal) !== -1);
117
- this._write_chunk(messageChunk);
118
- this._pendingBuffer = undefined;
119
- }
120
- get isDisconnecting() {
121
- return this._disconnecting;
122
- }
123
- /**
124
- * disconnect the TCP layer and close the underlying socket.
125
- * The ```"close"``` event will be emitted to the observers with err=null.
126
- *
127
- * @method disconnect
128
- * @async
129
- * @param callback
130
- */
131
- disconnect(callback) {
132
- (0, node_opcua_assert_1.assert)(typeof callback === "function", "expecting a callback function, but got " + callback);
133
- if (this._disconnecting) {
134
- callback();
135
- return;
136
- }
137
- (0, node_opcua_assert_1.assert)(!this._disconnecting, "TCP Transport has already been disconnected");
138
- this._disconnecting = true;
139
- // xx assert(!this._theCallback,
140
- // "disconnect shall not be called while the 'one time message receiver' is in operation");
141
- this._cleanup_timers();
142
- if (this._socket) {
143
- this._socket.end();
144
- this._socket && this._socket.destroy();
145
- // xx this._socket.removeAllListeners();
146
- this._socket = null;
147
- }
148
- this.on_socket_ended(null);
149
- setImmediate(() => {
150
- callback();
151
- });
152
- }
153
- isValid() {
154
- return this._socket !== null && !this._socket.destroyed && !this._disconnecting;
155
- }
156
- _write_chunk(messageChunk) {
157
- if (this._socket !== null) {
158
- this.bytesWritten += messageChunk.length;
159
- this.chunkWrittenCount++;
160
- this._socket.write(messageChunk);
161
- }
162
- }
163
- on_socket_ended(err) {
164
- (0, node_opcua_assert_1.assert)(!this._onSocketEndedHasBeenCalled);
165
- this._onSocketEndedHasBeenCalled = true; // we don't want to send close event twice ...
166
- /**
167
- * notify the observers that the transport layer has been disconnected.
168
- * @event close
169
- * @param err the Error object or null
170
- */
171
- this.emit("close", err || null);
172
- }
173
- /**
174
- * @method _install_socket
175
- * @param socket {Socket}
176
- * @protected
177
- */
178
- _install_socket(socket) {
179
- (0, node_opcua_assert_1.assert)(socket);
180
- this._socket = socket;
181
- if (doDebug) {
182
- debugLog(" TCP_transport#_install_socket ", this.name);
183
- }
184
- // install packet assembler ...
185
- this.packetAssembler = new node_opcua_packet_assembler_1.PacketAssembler({
186
- readMessageFunc: message_builder_base_1.readRawMessageHeader,
187
- minimumSizeInBytes: this.headerSize
188
- });
189
- /* istanbul ignore next */
190
- if (!this.packetAssembler) {
191
- throw new Error("Internal Error");
192
- }
193
- this.packetAssembler.on("message", (messageChunk) => this._on_message_received(messageChunk));
194
- this._socket
195
- .on("data", (data) => this._on_socket_data(data))
196
- .on("close", (hadError) => this._on_socket_close(hadError))
197
- .on("end", (err) => this._on_socket_end(err))
198
- .on("error", (err) => this._on_socket_error(err));
199
- // set socket timeout
200
- debugLog(" TCP_transport#install => setting " + this.name + " _socket.setTimeout to ", this.timeout);
201
- // let use a large timeout here to make sure that we not conflict with our internal timeout
202
- this._socket.setTimeout(this.timeout + 2000, () => {
203
- debugLog(` _socket ${this.name} has timed out (timeout = ${this.timeout})`);
204
- this.prematureTerminate(new Error("socket timeout : timeout=" + this.timeout));
205
- });
206
- }
207
- prematureTerminate(err) {
208
- debugLog("prematureTerminate", err ? err.message : "");
209
- if (this._socket) {
210
- err.message = "socket has timeout: EPIPE: " + err.message;
211
- // we consider this as an error
212
- const _s = this._socket;
213
- _s.end();
214
- _s.destroy(); // new Error("Socket has timed out"));
215
- _s.emit("error", err);
216
- this._socket = null;
217
- this.dispose();
218
- _s.removeAllListeners();
219
- }
220
- }
221
- /**
222
- * @method _install_one_time_message_receiver
223
- *
224
- * install a one time message receiver callback
225
- *
226
- * Rules:
227
- * * TCP_transport will not emit the ```message``` event, while the "one time message receiver" is in operation.
228
- * * the TCP_transport will wait for the next complete message chunk and call the provided callback func
229
- * ```callback(null,messageChunk);```
230
- *
231
- * if a messageChunk is not received within ```TCP_transport.timeout``` or if the underlying socket reports
232
- * an error, the callback function will be called with an Error.
233
- *
234
- */
235
- _install_one_time_message_receiver(callback) {
236
- (0, node_opcua_assert_1.assert)(!this._theCallback, "callback already set");
237
- (0, node_opcua_assert_1.assert)(typeof callback === "function");
238
- this._theCallback = callback;
239
- this._start_one_time_message_receiver();
240
- }
241
- _fulfill_pending_promises(err, data) {
242
- this._cleanup_timers();
243
- if (this._socket && this._on_error_during_one_time_message_receiver) {
244
- this._socket.removeListener("close", this._on_error_during_one_time_message_receiver);
245
- this._on_error_during_one_time_message_receiver = null;
246
- }
247
- const callback = this._theCallback;
248
- this._theCallback = undefined;
249
- if (callback) {
250
- callback(err, data);
251
- return true;
252
- }
253
- return false;
254
- }
255
- _on_message_received(messageChunk) {
256
- const hadCallback = this._fulfill_pending_promises(null, messageChunk);
257
- this.chunkReadCount++;
258
- if (!hadCallback) {
259
- /**
260
- * notify the observers that a message chunk has been received
261
- * @event message
262
- * @param message_chunk the message chunk
263
- */
264
- this.emit("message", messageChunk);
265
- }
266
- }
267
- _cleanup_timers() {
268
- if (this._timerId) {
269
- clearTimeout(this._timerId);
270
- this._timerId = null;
271
- }
272
- }
273
- _start_one_time_message_receiver() {
274
- (0, node_opcua_assert_1.assert)(!this._timerId, "timer already started");
275
- // Setup timeout detection timer ....
276
- this._timerId = setTimeout(() => {
277
- this._timerId = null;
278
- this._fulfill_pending_promises(new Error(`Timeout in waiting for data on socket ( timeout was = ${this.timeout} ms)`));
279
- }, this.timeout);
280
- // also monitored
281
- if (this._socket) {
282
- // to do = intercept socket error as well
283
- this._on_error_during_one_time_message_receiver = (err) => {
284
- this._fulfill_pending_promises(new Error(`ERROR in waiting for data on socket ( timeout was = ${this.timeout} ms) ` + (err === null || err === void 0 ? void 0 : err.message)));
285
- };
286
- this._socket.on("close", this._on_error_during_one_time_message_receiver);
287
- }
288
- }
289
- on_socket_closed(err) {
290
- if (this._onSocketClosedHasBeenCalled) {
291
- return;
292
- }
293
- (0, node_opcua_assert_1.assert)(!this._onSocketClosedHasBeenCalled);
294
- this._onSocketClosedHasBeenCalled = true; // we don't want to send close event twice ...
295
- /**
296
- * notify the observers that the transport layer has been disconnected.
297
- * @event socket_closed
298
- * @param err the Error object or null
299
- */
300
- this.emit("socket_closed", err || null);
301
- }
302
- _on_socket_data(data) {
303
- if (!this.packetAssembler) {
304
- throw new Error("internal Error");
305
- }
306
- this.bytesRead += data.length;
307
- if (data.length > 0) {
308
- this.packetAssembler.feed(data);
309
- }
310
- }
311
- _on_socket_close(hadError) {
312
- // istanbul ignore next
313
- if (doDebug) {
314
- debugLog(chalk.red(" SOCKET CLOSE : "), chalk.yellow("had_error ="), chalk.cyan(hadError.toString()), this.name);
315
- }
316
- if (this._socket) {
317
- debugLog(" remote address = ", this._socket.remoteAddress, " ", this._socket.remoteFamily, " ", this._socket.remotePort);
318
- }
319
- if (hadError) {
320
- if (this._socket) {
321
- this._socket.destroy();
322
- }
323
- }
324
- const err = hadError ? new Error("ERROR IN SOCKET " + hadError.toString()) : undefined;
325
- this.on_socket_closed(err);
326
- this.dispose();
327
- }
328
- _on_socket_ended_message(err) {
329
- if (this._disconnecting) {
330
- return;
331
- }
332
- debugLog(chalk.red("Transport Connection ended") + " " + this.name);
333
- (0, node_opcua_assert_1.assert)(!this._disconnecting);
334
- err = err || new Error("_socket has been disconnected by third party");
335
- this.on_socket_ended(err);
336
- this._disconnecting = true;
337
- debugLog(" bytesRead = ", this.bytesRead);
338
- debugLog(" bytesWritten = ", this.bytesWritten);
339
- this._fulfill_pending_promises(new Error("Connection aborted - ended by server : " + (err ? err.message : "")));
340
- }
341
- _on_socket_end(err) {
342
- // istanbul ignore next
343
- if (doDebug) {
344
- debugLog(chalk.red(" SOCKET END : err="), chalk.yellow(err ? err.message : "null"), this.name);
345
- }
346
- this._on_socket_ended_message(err);
347
- }
348
- _on_socket_error(err) {
349
- // istanbul ignore next
350
- if (doDebug) {
351
- debugLog(chalk.red(" SOCKET ERROR : "), chalk.yellow(err.message), this.name);
352
- }
353
- // node The "close" event will be called directly following this event.
354
- }
355
- }
356
- exports.TCP_transport = TCP_transport;
357
- TCP_transport.registry = new node_opcua_object_registry_1.ObjectRegistry();
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.TCP_transport = exports.getFakeTransport = exports.setFakeTransport = void 0;
4
+ /**
5
+ * @module node-opcua-transport
6
+ */
7
+ const events_1 = require("events");
8
+ const chalk = require("chalk");
9
+ const node_opcua_assert_1 = require("node-opcua-assert");
10
+ const node_opcua_buffer_utils_1 = require("node-opcua-buffer-utils");
11
+ const debug = require("node-opcua-debug");
12
+ const node_opcua_object_registry_1 = require("node-opcua-object-registry");
13
+ const node_opcua_packet_assembler_1 = require("node-opcua-packet-assembler");
14
+ const message_builder_base_1 = require("./message_builder_base");
15
+ const tools_1 = require("./tools");
16
+ const debugLog = debug.make_debugLog(__filename);
17
+ const doDebug = debug.checkDebugFlag(__filename);
18
+ const errorLog = debug.make_errorLog(__filename);
19
+ let fakeSocket = {
20
+ invalid: true,
21
+ destroy() {
22
+ errorLog("MockSocket.destroy");
23
+ },
24
+ end() {
25
+ errorLog("MockSocket.end");
26
+ }
27
+ };
28
+ function setFakeTransport(mockSocket) {
29
+ fakeSocket = mockSocket;
30
+ }
31
+ exports.setFakeTransport = setFakeTransport;
32
+ function getFakeTransport() {
33
+ if (fakeSocket.invalid) {
34
+ throw new Error("getFakeTransport: setFakeTransport must be called first - BadProtocolVersionUnsupported");
35
+ }
36
+ return fakeSocket;
37
+ }
38
+ exports.getFakeTransport = getFakeTransport;
39
+ let counter = 0;
40
+ // tslint:disable:class-name
41
+ class TCP_transport extends events_1.EventEmitter {
42
+ constructor() {
43
+ super();
44
+ this.name = this.constructor.name + counter;
45
+ counter += 1;
46
+ this._timerId = null;
47
+ this._timeout = 30000; // 30 seconds timeout
48
+ this._socket = null;
49
+ this.headerSize = 8;
50
+ this.protocolVersion = 0;
51
+ this._disconnecting = false;
52
+ this._pendingBuffer = undefined;
53
+ this.bytesWritten = 0;
54
+ this.bytesRead = 0;
55
+ this._theCallback = undefined;
56
+ this.chunkWrittenCount = 0;
57
+ this.chunkReadCount = 0;
58
+ this._onSocketClosedHasBeenCalled = false;
59
+ this._onSocketEndedHasBeenCalled = false;
60
+ TCP_transport.registry.register(this);
61
+ }
62
+ get timeout() {
63
+ return this._timeout;
64
+ }
65
+ set timeout(value) {
66
+ debugLog("Setting socket " + this.name + " timeout = ", value);
67
+ this._timeout = value;
68
+ }
69
+ dispose() {
70
+ this._cleanup_timers();
71
+ (0, node_opcua_assert_1.assert)(!this._timerId);
72
+ if (this._socket) {
73
+ this._socket.destroy();
74
+ this._socket.removeAllListeners();
75
+ this._socket = null;
76
+ }
77
+ TCP_transport.registry.unregister(this);
78
+ }
79
+ /**
80
+ * ```createChunk``` is used to construct a pre-allocated chunk to store up to ```length``` bytes of data.
81
+ * The created chunk includes a prepended header for ```chunk_type``` of size ```self.headerSize```.
82
+ *
83
+ * @method createChunk
84
+ * @param msgType
85
+ * @param chunkType {String} chunk type. should be 'F' 'C' or 'A'
86
+ * @param length
87
+ * @return a buffer object with the required length representing the chunk.
88
+ *
89
+ * Note:
90
+ * - only one chunk can be created at a time.
91
+ * - a created chunk should be committed using the ```write``` method before an other one is created.
92
+ */
93
+ createChunk(msgType, chunkType, length) {
94
+ (0, node_opcua_assert_1.assert)(msgType === "MSG");
95
+ (0, node_opcua_assert_1.assert)(this._pendingBuffer === undefined, "createChunk has already been called ( use write first)");
96
+ const totalLength = length + this.headerSize;
97
+ const buffer = (0, node_opcua_buffer_utils_1.createFastUninitializedBuffer)(totalLength);
98
+ (0, tools_1.writeTCPMessageHeader)("MSG", chunkType, totalLength, buffer);
99
+ this._pendingBuffer = buffer;
100
+ return buffer;
101
+ }
102
+ /**
103
+ * write the message_chunk on the socket.
104
+ * @method write
105
+ * @param messageChunk
106
+ *
107
+ * Notes:
108
+ * - the message chunk must have been created by ```createChunk```.
109
+ * - once a message chunk has been written, it is possible to call ```createChunk``` again.
110
+ *
111
+ */
112
+ write(messageChunk) {
113
+ (0, node_opcua_assert_1.assert)(this._pendingBuffer === undefined || this._pendingBuffer === messageChunk, " write should be used with buffer created by createChunk");
114
+ const header = (0, message_builder_base_1.readRawMessageHeader)(messageChunk);
115
+ (0, node_opcua_assert_1.assert)(header.length === messageChunk.length);
116
+ (0, node_opcua_assert_1.assert)(["F", "C", "A"].indexOf(header.messageHeader.isFinal) !== -1);
117
+ this._write_chunk(messageChunk);
118
+ this._pendingBuffer = undefined;
119
+ }
120
+ get isDisconnecting() {
121
+ return this._disconnecting;
122
+ }
123
+ /**
124
+ * disconnect the TCP layer and close the underlying socket.
125
+ * The ```"close"``` event will be emitted to the observers with err=null.
126
+ *
127
+ * @method disconnect
128
+ * @async
129
+ * @param callback
130
+ */
131
+ disconnect(callback) {
132
+ (0, node_opcua_assert_1.assert)(typeof callback === "function", "expecting a callback function, but got " + callback);
133
+ if (this._disconnecting) {
134
+ callback();
135
+ return;
136
+ }
137
+ (0, node_opcua_assert_1.assert)(!this._disconnecting, "TCP Transport has already been disconnected");
138
+ this._disconnecting = true;
139
+ // xx assert(!this._theCallback,
140
+ // "disconnect shall not be called while the 'one time message receiver' is in operation");
141
+ this._cleanup_timers();
142
+ if (this._socket) {
143
+ this._socket.end();
144
+ this._socket && this._socket.destroy();
145
+ // xx this._socket.removeAllListeners();
146
+ this._socket = null;
147
+ }
148
+ this.on_socket_ended(null);
149
+ setImmediate(() => {
150
+ callback();
151
+ });
152
+ }
153
+ isValid() {
154
+ return this._socket !== null && !this._socket.destroyed && !this._disconnecting;
155
+ }
156
+ _write_chunk(messageChunk) {
157
+ if (this._socket !== null) {
158
+ this.bytesWritten += messageChunk.length;
159
+ this.chunkWrittenCount++;
160
+ this._socket.write(messageChunk);
161
+ }
162
+ }
163
+ on_socket_ended(err) {
164
+ (0, node_opcua_assert_1.assert)(!this._onSocketEndedHasBeenCalled);
165
+ this._onSocketEndedHasBeenCalled = true; // we don't want to send close event twice ...
166
+ /**
167
+ * notify the observers that the transport layer has been disconnected.
168
+ * @event close
169
+ * @param err the Error object or null
170
+ */
171
+ this.emit("close", err || null);
172
+ }
173
+ /**
174
+ * @method _install_socket
175
+ * @param socket {Socket}
176
+ * @protected
177
+ */
178
+ _install_socket(socket) {
179
+ (0, node_opcua_assert_1.assert)(socket);
180
+ this._socket = socket;
181
+ if (doDebug) {
182
+ debugLog(" TCP_transport#_install_socket ", this.name);
183
+ }
184
+ // install packet assembler ...
185
+ this.packetAssembler = new node_opcua_packet_assembler_1.PacketAssembler({
186
+ readMessageFunc: message_builder_base_1.readRawMessageHeader,
187
+ minimumSizeInBytes: this.headerSize
188
+ });
189
+ /* istanbul ignore next */
190
+ if (!this.packetAssembler) {
191
+ throw new Error("Internal Error");
192
+ }
193
+ this.packetAssembler.on("message", (messageChunk) => this._on_message_received(messageChunk));
194
+ this._socket
195
+ .on("data", (data) => this._on_socket_data(data))
196
+ .on("close", (hadError) => this._on_socket_close(hadError))
197
+ .on("end", (err) => this._on_socket_end(err))
198
+ .on("error", (err) => this._on_socket_error(err));
199
+ // set socket timeout
200
+ debugLog(" TCP_transport#install => setting " + this.name + " _socket.setTimeout to ", this.timeout);
201
+ // let use a large timeout here to make sure that we not conflict with our internal timeout
202
+ this._socket.setTimeout(this.timeout + 2000, () => {
203
+ debugLog(` _socket ${this.name} has timed out (timeout = ${this.timeout})`);
204
+ this.prematureTerminate(new Error("socket timeout : timeout=" + this.timeout));
205
+ });
206
+ }
207
+ prematureTerminate(err) {
208
+ debugLog("prematureTerminate", err ? err.message : "");
209
+ if (this._socket) {
210
+ err.message = "socket has timeout: EPIPE: " + err.message;
211
+ // we consider this as an error
212
+ const _s = this._socket;
213
+ _s.end();
214
+ _s.destroy(); // new Error("Socket has timed out"));
215
+ _s.emit("error", err);
216
+ this._socket = null;
217
+ this.dispose();
218
+ _s.removeAllListeners();
219
+ }
220
+ }
221
+ /**
222
+ * @method _install_one_time_message_receiver
223
+ *
224
+ * install a one time message receiver callback
225
+ *
226
+ * Rules:
227
+ * * TCP_transport will not emit the ```message``` event, while the "one time message receiver" is in operation.
228
+ * * the TCP_transport will wait for the next complete message chunk and call the provided callback func
229
+ * ```callback(null,messageChunk);```
230
+ *
231
+ * if a messageChunk is not received within ```TCP_transport.timeout``` or if the underlying socket reports
232
+ * an error, the callback function will be called with an Error.
233
+ *
234
+ */
235
+ _install_one_time_message_receiver(callback) {
236
+ (0, node_opcua_assert_1.assert)(!this._theCallback, "callback already set");
237
+ (0, node_opcua_assert_1.assert)(typeof callback === "function");
238
+ this._theCallback = callback;
239
+ this._start_one_time_message_receiver();
240
+ }
241
+ _fulfill_pending_promises(err, data) {
242
+ this._cleanup_timers();
243
+ if (this._socket && this._on_error_during_one_time_message_receiver) {
244
+ this._socket.removeListener("close", this._on_error_during_one_time_message_receiver);
245
+ this._on_error_during_one_time_message_receiver = null;
246
+ }
247
+ const callback = this._theCallback;
248
+ this._theCallback = undefined;
249
+ if (callback) {
250
+ callback(err, data);
251
+ return true;
252
+ }
253
+ return false;
254
+ }
255
+ _on_message_received(messageChunk) {
256
+ const hadCallback = this._fulfill_pending_promises(null, messageChunk);
257
+ this.chunkReadCount++;
258
+ if (!hadCallback) {
259
+ /**
260
+ * notify the observers that a message chunk has been received
261
+ * @event message
262
+ * @param message_chunk the message chunk
263
+ */
264
+ this.emit("message", messageChunk);
265
+ }
266
+ }
267
+ _cleanup_timers() {
268
+ if (this._timerId) {
269
+ clearTimeout(this._timerId);
270
+ this._timerId = null;
271
+ }
272
+ }
273
+ _start_one_time_message_receiver() {
274
+ (0, node_opcua_assert_1.assert)(!this._timerId, "timer already started");
275
+ // Setup timeout detection timer ....
276
+ this._timerId = setTimeout(() => {
277
+ this._timerId = null;
278
+ this._fulfill_pending_promises(new Error(`Timeout in waiting for data on socket ( timeout was = ${this.timeout} ms)`));
279
+ }, this.timeout);
280
+ // also monitored
281
+ if (this._socket) {
282
+ // to do = intercept socket error as well
283
+ this._on_error_during_one_time_message_receiver = (err) => {
284
+ this._fulfill_pending_promises(new Error(`ERROR in waiting for data on socket ( timeout was = ${this.timeout} ms) ` + (err === null || err === void 0 ? void 0 : err.message)));
285
+ };
286
+ this._socket.on("close", this._on_error_during_one_time_message_receiver);
287
+ }
288
+ }
289
+ on_socket_closed(err) {
290
+ if (this._onSocketClosedHasBeenCalled) {
291
+ return;
292
+ }
293
+ (0, node_opcua_assert_1.assert)(!this._onSocketClosedHasBeenCalled);
294
+ this._onSocketClosedHasBeenCalled = true; // we don't want to send close event twice ...
295
+ /**
296
+ * notify the observers that the transport layer has been disconnected.
297
+ * @event socket_closed
298
+ * @param err the Error object or null
299
+ */
300
+ this.emit("socket_closed", err || null);
301
+ }
302
+ _on_socket_data(data) {
303
+ if (!this.packetAssembler) {
304
+ throw new Error("internal Error");
305
+ }
306
+ this.bytesRead += data.length;
307
+ if (data.length > 0) {
308
+ this.packetAssembler.feed(data);
309
+ }
310
+ }
311
+ _on_socket_close(hadError) {
312
+ // istanbul ignore next
313
+ if (doDebug) {
314
+ debugLog(chalk.red(" SOCKET CLOSE : "), chalk.yellow("had_error ="), chalk.cyan(hadError.toString()), this.name);
315
+ }
316
+ if (this._socket) {
317
+ debugLog(" remote address = ", this._socket.remoteAddress, " ", this._socket.remoteFamily, " ", this._socket.remotePort);
318
+ }
319
+ if (hadError) {
320
+ if (this._socket) {
321
+ this._socket.destroy();
322
+ }
323
+ }
324
+ const err = hadError ? new Error("ERROR IN SOCKET " + hadError.toString()) : undefined;
325
+ this.on_socket_closed(err);
326
+ this.dispose();
327
+ }
328
+ _on_socket_ended_message(err) {
329
+ if (this._disconnecting) {
330
+ return;
331
+ }
332
+ debugLog(chalk.red("Transport Connection ended") + " " + this.name);
333
+ (0, node_opcua_assert_1.assert)(!this._disconnecting);
334
+ err = err || new Error("_socket has been disconnected by third party");
335
+ this.on_socket_ended(err);
336
+ this._disconnecting = true;
337
+ debugLog(" bytesRead = ", this.bytesRead);
338
+ debugLog(" bytesWritten = ", this.bytesWritten);
339
+ this._fulfill_pending_promises(new Error("Connection aborted - ended by server : " + (err ? err.message : "")));
340
+ }
341
+ _on_socket_end(err) {
342
+ // istanbul ignore next
343
+ if (doDebug) {
344
+ debugLog(chalk.red(" SOCKET END : err="), chalk.yellow(err ? err.message : "null"), this.name);
345
+ }
346
+ this._on_socket_ended_message(err);
347
+ }
348
+ _on_socket_error(err) {
349
+ // istanbul ignore next
350
+ if (doDebug) {
351
+ debugLog(chalk.red(" SOCKET ERROR : "), chalk.yellow(err.message), this.name);
352
+ }
353
+ // node The "close" event will be called directly following this event.
354
+ }
355
+ }
356
+ exports.TCP_transport = TCP_transport;
357
+ TCP_transport.registry = new node_opcua_object_registry_1.ObjectRegistry();
358
358
  //# sourceMappingURL=tcp_transport.js.map