node-opcua-packet-analyzer 2.164.0 → 2.167.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.
@@ -1,24 +1,27 @@
1
- import { inspect, types } from "util";
1
+ import { inspect } from "node:util";
2
2
  import chalk from "chalk";
3
3
  import { assert } from "node-opcua-assert";
4
4
 
5
5
  import { decodeByte, decodeExpandedNodeId, decodeNodeId, decodeUInt32 } from "node-opcua-basic-types";
6
6
  import { BinaryStream } from "node-opcua-binary-stream";
7
7
  import { hexDump } from "node-opcua-debug";
8
- import { BaseUAObject, getStandardDataTypeFactory } from "node-opcua-factory";
8
+ import { type ConstructorFunc, getStandardDataTypeFactory, type IBaseUAObject } from "node-opcua-factory";
9
+ import type { ExpandedNodeId } from "node-opcua-nodeid";
9
10
  import { buffer_ellipsis } from "node-opcua-utils";
10
11
 
11
- const spaces =
12
- " ";
12
+ const displayWidth = 132;
13
+ const separator = "-".repeat(49);
13
14
 
14
- function f(n: number, width: number): string {
15
- const s = n.toString();
16
- return (s + " ").substring(0, Math.max(s.length, width));
15
+ function padNumber(n: number, width: number): string {
16
+ return n.toString().padEnd(width);
17
17
  }
18
18
 
19
- function display_encoding_mask(padding: string, encodingMask: any, encodingInfo: any) {
19
+ /** Encoding info maps enum key names ↔ bitmask values */
20
+ type EncodingInfo = Record<string, number | string>;
21
+
22
+ function display_encoding_mask(padding: string, encodingMask: number, encodingInfo: EncodingInfo): void {
20
23
  for (const v in encodingInfo) {
21
- if (!Object.prototype.hasOwnProperty.call(encodingInfo, v)) {
24
+ if (!Object.hasOwn(encodingInfo, v)) {
22
25
  continue;
23
26
  }
24
27
  const enumKey = encodingInfo[v];
@@ -26,85 +29,117 @@ function display_encoding_mask(padding: string, encodingMask: any, encodingInfo:
26
29
  continue;
27
30
  }
28
31
 
29
- const mask = encodingInfo[enumKey];
32
+ const mask = encodingInfo[enumKey] as number;
30
33
  const bit = Math.log(mask) / Math.log(2);
31
34
 
32
- const bits = [".", ".", ".", ".", ".", ".", ".", ".", "."];
35
+ const bits = Array<string>(9).fill(".");
33
36
  bits[bit] = (encodingMask & mask) === mask ? "Y" : "n";
34
37
 
35
- console.log(padding + " ", bits.join(""), " <- has " + enumKey + " 0x" + mask.toString(16));
38
+ console.log(`${padding} ${bits.join("")}` + ` <- has ${enumKey} 0x${mask.toString(16)}`);
36
39
  }
37
- // DataValueEncodingByte
38
40
  }
39
41
 
40
- function hex_block(start: number, end: number, buffer: Buffer) {
42
+ function hex_block(start: number, end: number, buffer: Buffer): string {
41
43
  const n = end - start;
42
44
  const strBuf = buffer_ellipsis(buffer);
43
45
  return (
44
- chalk.cyan("s:") + f(start, 4) + chalk.cyan(" e:") + f(end, 4) + chalk.cyan(" n:") + f(n, 4) + " " + chalk.yellow(strBuf)
46
+ chalk.cyan("s:") +
47
+ padNumber(start, 4) +
48
+ chalk.cyan(" e:") +
49
+ padNumber(end, 4) +
50
+ chalk.cyan(" n:") +
51
+ padNumber(n, 4) +
52
+ " " +
53
+ chalk.yellow(strBuf)
45
54
  );
46
55
  }
47
56
 
57
+ type TraceOperation = "start" | "end" | "start_array" | "end_array" | "start_element" | "end_element" | "member";
58
+
59
+ interface TracerMethods {
60
+ dump: (title: string, value: unknown) => void;
61
+ encoding_byte: (encodingMask: number, valueEnum: EncodingInfo, start: number, end: number) => void;
62
+ trace: (operation: TraceOperation, name: string, value: unknown, start: number, end: number, fieldType: string) => void;
63
+ }
64
+
48
65
  interface Tracer {
49
66
  name?: string;
50
- tracer: {
51
- dump: (title: string, value: any) => void;
52
- encoding_byte: (encodingMask: any, valueEnum: any, start: number, end: number) => void;
53
- trace: (operation: any, name: any, value: any, start: number, end: number, fieldType: string) => void;
54
- };
67
+ tracer: TracerMethods;
68
+ }
69
+
70
+ interface Encodeable {
71
+ encodingDefaultBinary: unknown;
72
+ encode?: (stream: BinaryStream) => void;
55
73
  }
74
+
75
+ function isEncodeable(val: unknown): val is Encodeable {
76
+ return val != null && typeof (val as Encodeable).encode === "function";
77
+ }
78
+
56
79
  function make_tracer(buffer: Buffer, padding: number, offset?: number): Tracer {
57
- padding = !padding ? 0 : padding;
58
- offset = offset || 0;
80
+ padding ??= 0;
81
+ offset ??= 0;
59
82
 
60
- const pad = () => " ".substring(0, padding);
83
+ const pad = (): string => "".padEnd(padding);
61
84
 
62
- function _display(str: string, hexInfo?: string) {
63
- hexInfo = hexInfo || "";
85
+ function _display(str: string, hexInfo?: string): void {
86
+ hexInfo ??= "";
64
87
  // account for ESC codes for colors
65
- const nbColorAttributes = [...str.split("")].filter((c) => c === "\u001b").length;
88
+ const nbColorAttributes = str.split("").filter((c) => c === "\u001b").length;
66
89
  const extra = nbColorAttributes * 5;
67
- console.log((pad() + str + spaces).substring(0, 132 + extra) + "|" + hexInfo);
90
+ const line = (pad() + str).padEnd(displayWidth + extra);
91
+ console.log(`${line}|${hexInfo}`);
68
92
  }
69
- function display(str: string, hexInfo?: string) {
70
- const lines = str.split("\n");
71
- for (const line of lines) {
93
+
94
+ function display(str: string, hexInfo?: string): void {
95
+ for (const line of str.split("\n")) {
72
96
  _display(line, hexInfo);
73
97
  }
74
98
  }
75
99
 
76
- function display_encodeable(value: any, buffer1: Buffer, start: number, end: number) {
100
+ function display_encodeable(value: Encodeable, buffer1: Buffer, start: number, end: number): void {
77
101
  const bufferExtract = buffer1.subarray(start, end);
78
102
  const stream = new BinaryStream(bufferExtract);
79
103
  const nodeId = decodeNodeId(stream);
80
- const encodingMask = decodeByte(stream); // 1 bin 2: xml
104
+ const encodingMask = decodeByte(stream);
81
105
  const length = decodeUInt32(stream);
82
106
 
83
- display(chalk.green(" ExpandedNodId =") + " " + nodeId);
84
- display(chalk.green(" encoding mask =") + " " + encodingMask);
85
- display(chalk.green(" length =") + " " + length);
86
- analyzePacket(bufferExtract.subarray(stream.length), value.encodingDefaultBinary, padding + 2, start + stream.length);
107
+ display(`${chalk.green(" ExpandedNodId =")} ${nodeId}`);
108
+ display(`${chalk.green(" encoding mask =")} ${encodingMask}`);
109
+ display(`${chalk.green(" length =")} ${length}`);
110
+ analyzePacket(
111
+ bufferExtract.subarray(stream.length),
112
+ value.encodingDefaultBinary as ObjectMessage,
113
+ padding + 2,
114
+ start + stream.length
115
+ );
87
116
  }
88
117
 
89
118
  return {
90
119
  tracer: {
91
- dump: (title: string, value: any) => display(title + " " + chalk.green(value.toString())),
120
+ dump: (title: string, value: unknown): void => display(`${title} ${chalk.green(String(value))}`),
92
121
 
93
- encoding_byte: (encodingMask: any, valueEnum: any, start: number, end: number) => {
122
+ encoding_byte: (encodingMask: number, valueEnum: EncodingInfo, start: number, end: number): void => {
94
123
  assert(valueEnum);
95
124
  const b = buffer.subarray(start, end);
96
125
  display(" 012345678", hex_block(start, end, b));
97
126
  display_encoding_mask(pad(), encodingMask, valueEnum);
98
127
  },
99
128
 
100
- trace: (operation: any, name: any, value: any, start: number, end: number, fieldType: string) => {
129
+ trace: (
130
+ operation: TraceOperation,
131
+ name: string,
132
+ value: unknown,
133
+ start: number,
134
+ end: number,
135
+ fieldType: string
136
+ ): void => {
101
137
  const b = buffer.subarray(start, end);
102
- let _hexDump = "";
103
138
 
104
139
  switch (operation) {
105
140
  case "start":
106
141
  padding += 2;
107
- display(name.toString());
142
+ display(name);
108
143
  break;
109
144
 
110
145
  case "end":
@@ -112,58 +147,58 @@ function make_tracer(buffer: Buffer, padding: number, offset?: number): Tracer {
112
147
  break;
113
148
 
114
149
  case "start_array":
115
- display("." + name + " (length = " + value + ") " + "[", hex_block(start, end, b));
150
+ display(`.${name} (length = ${value}) [`, hex_block(start, end, b));
116
151
  padding += 2;
117
152
  break;
118
153
 
119
154
  case "end_array":
120
155
  padding -= 2;
121
- display("] // " + name);
156
+ display(`] // ${name}`);
122
157
  break;
123
158
 
124
159
  case "start_element":
125
- display(" #" + value + " {");
160
+ display(` #${value} {`);
126
161
  padding += 2;
127
162
  break;
128
163
 
129
164
  case "end_element":
130
165
  padding -= 2;
131
- display(" } // # " + value);
166
+ display(` } // # ${value}`);
132
167
  break;
133
168
 
134
- case "member":
135
- display("." + name + " : " + fieldType);
169
+ case "member": {
170
+ display(`.${name} : ${fieldType}`);
136
171
 
137
- _hexDump = "";
138
172
  if (value instanceof Buffer) {
139
- _hexDump = hexDump(value);
140
- console.log(_hexDump);
173
+ console.log(hexDump(value));
141
174
  value = "<BUFFER>";
142
175
  }
143
176
 
144
- if (value && value.encode) {
177
+ if (isEncodeable(value)) {
145
178
  if (fieldType === "ExtensionObject") {
146
179
  display_encodeable(value, buffer, start, end);
147
180
  } else {
148
- const str = value.toString() || "<empty>";
149
- display(str);
181
+ display(String(value) || "<empty>");
150
182
  }
151
183
  } else {
152
- display(" " + value, hex_block(start, end, b));
184
+ display(` ${value}`, hex_block(start, end, b));
153
185
  }
154
186
  break;
187
+ }
155
188
  }
156
189
  }
157
190
  }
158
191
  };
159
192
  }
160
193
 
161
- interface AnalyzePacketOptions {}
194
+ export interface AnalyzePacketOptions {
195
+ [key: string]: unknown;
196
+ }
162
197
 
163
198
  export interface ObjectMessage {
164
199
  encode(stream: BinaryStream): void;
165
200
  decode(stream: BinaryStream): void;
166
- decodeDebug(stream: BinaryStream, options: any): void;
201
+ decodeDebug(stream: BinaryStream, options: Tracer): void;
167
202
  }
168
203
 
169
204
  export function analyzePacket(
@@ -184,15 +219,15 @@ export function analyseExtensionObject(
184
219
  customOptions?: AnalyzePacketOptions
185
220
  ): void {
186
221
  const stream = new BinaryStream(buffer);
187
- let id;
188
- let objMessage;
222
+ let id: ExpandedNodeId | undefined;
223
+ let objMessage: ObjectMessage | undefined;
189
224
  try {
190
225
  id = decodeExpandedNodeId(stream);
191
- objMessage = getStandardDataTypeFactory().constructObject(id);
226
+ objMessage = getStandardDataTypeFactory().constructObject(id) as unknown as ObjectMessage;
192
227
  } catch (err) {
193
228
  console.log(id);
194
229
  console.log(err);
195
- console.log("Cannot read decodeExpandedNodeId on stream " + stream.buffer.toString("hex"));
230
+ console.log("Cannot read decodeExpandedNodeId on stream " + stream.buffer.toString("hex"));
196
231
  }
197
232
  _internalAnalyzePacket(buffer, stream, objMessage, padding, customOptions, offset);
198
233
  }
@@ -204,10 +239,12 @@ function _internalAnalyzePacket(
204
239
  padding: number,
205
240
  customOptions?: AnalyzePacketOptions,
206
241
  offset?: number
207
- ) {
242
+ ): void {
208
243
  let options = make_tracer(buffer, padding, offset);
209
244
  options.name = "message";
210
- if (customOptions) options = { ...options, ...customOptions };
245
+ if (customOptions) {
246
+ options = { ...options, ...customOptions };
247
+ }
211
248
  try {
212
249
  if (objMessage) {
213
250
  objMessage.decodeDebug(stream, options);
@@ -216,29 +253,30 @@ function _internalAnalyzePacket(
216
253
  }
217
254
  } catch (err) {
218
255
  console.log(" Error in ", err);
219
- if (types.isNativeError(err)) {
256
+ if (err instanceof Error) {
220
257
  console.log(" Error in ", err.stack);
221
258
  }
222
259
  console.log(" objMessage ", inspect(objMessage, { colors: true }));
223
260
  }
224
261
  }
225
262
 
226
- export function analyze_object_binary_encoding(obj: BaseUAObject): void {
263
+ export function analyze_object_binary_encoding(obj: IBaseUAObject): void {
227
264
  assert(obj);
228
265
 
229
266
  const size = obj.binaryStoreSize();
230
- console.log("-------------------------------------------------");
267
+ console.log(separator);
231
268
  console.log(" size = ", size);
232
269
  const stream = new BinaryStream(size);
233
270
  obj.encode(stream);
234
271
 
235
272
  stream.rewind();
236
- console.log("-------------------------------------------------");
273
+ console.log(separator);
237
274
  if (stream.buffer.length < 256) {
238
275
  console.log(hexDump(stream.buffer));
239
- console.log("-------------------------------------------------");
276
+ console.log(separator);
240
277
  }
241
278
 
242
- const reloadedObject = new (obj.constructor as any)();
243
- analyzePacket(stream.buffer, reloadedObject, 0);
279
+ const Ctor = obj.constructor as ConstructorFunc;
280
+ const reloadedObject = new Ctor();
281
+ analyzePacket(stream.buffer, reloadedObject as unknown as ObjectMessage, 0);
244
282
  }