node-opcua-alias-name-client 2.176.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.
@@ -0,0 +1,89 @@
1
+ /**
2
+ * @module node-opcua-alias-name-client
3
+ *
4
+ * Turning the `ServerIndex` of a returned `ExpandedNodeId` into something a
5
+ * Client can act on.
6
+ */
7
+
8
+ import { VariableIds } from "node-opcua-constants";
9
+ import { AttributeIds } from "node-opcua-data-model";
10
+ import { type ExpandedNodeId, resolveNodeId } from "node-opcua-nodeid";
11
+ import type { IBasicSessionAsync } from "node-opcua-pseudo-session";
12
+
13
+ /** The Server's own entry in the ServerArray is always index 0 (OPC 10000-5). */
14
+ export const LOCAL_SERVER_INDEX = 0;
15
+
16
+ /**
17
+ * Resolves `ServerIndex` values against a Server's `ServerArray`, caching it.
18
+ *
19
+ * `FindAlias` may return an `ExpandedNodeId` whose `serverIndex` is not 0, which
20
+ * says only "this Node is on a different Server" — the index is meaningless
21
+ * without the `ServerArray` that gives it a URI (OPC 10000-17 Annex A walks
22
+ * through exactly this). Every Client consuming AliasNames from a Server that
23
+ * aggregates has to do this step, so it lives here rather than in each caller.
24
+ *
25
+ * The `ServerArray` is read once and cached. It is not expected to change during
26
+ * a session; call {@link invalidate} if the Client has reason to believe it has.
27
+ */
28
+ export class ServerIndexResolver {
29
+ private readonly session: IBasicSessionAsync;
30
+ private serverArray?: string[];
31
+
32
+ constructor(session: IBasicSessionAsync) {
33
+ this.session = session;
34
+ }
35
+
36
+ /** The Server's `ServerArray`, read once and cached. */
37
+ public async getServerArray(): Promise<string[]> {
38
+ if (this.serverArray) {
39
+ return this.serverArray;
40
+ }
41
+ const dataValue = await this.session.read({
42
+ nodeId: resolveNodeId(VariableIds.Server_ServerArray),
43
+ attributeId: AttributeIds.Value
44
+ });
45
+ const value = dataValue.value?.value;
46
+ this.serverArray = Array.isArray(value) ? (value as string[]) : [];
47
+ return this.serverArray;
48
+ }
49
+
50
+ /** Forget the cached `ServerArray`. */
51
+ public invalidate(): void {
52
+ this.serverArray = undefined;
53
+ }
54
+
55
+ /**
56
+ * The URI for a `ServerIndex`, or `null` when the index is not in the
57
+ * `ServerArray`.
58
+ *
59
+ * An index the array does not cover is a Server defect, but a Client has to
60
+ * survive it, so it is reported as `null` rather than thrown.
61
+ */
62
+ public async resolveServerIndex(serverIndex: number): Promise<string | null> {
63
+ const serverArray = await this.getServerArray();
64
+ return serverArray[serverIndex] ?? null;
65
+ }
66
+
67
+ /** True when the ExpandedNodeId names a Node on the Server that answered. */
68
+ public isLocal(expandedNodeId: ExpandedNodeId): boolean {
69
+ return (expandedNodeId.serverIndex ?? LOCAL_SERVER_INDEX) === LOCAL_SERVER_INDEX;
70
+ }
71
+
72
+ /**
73
+ * Describe where a returned Node lives.
74
+ *
75
+ * `serverUri` is `null` for a Node on the Server that answered the call —
76
+ * which is every Node these packages publish, since aggregating other
77
+ * Servers is out of scope. It is non-null only when talking to a Server that
78
+ * does aggregate.
79
+ */
80
+ public async locate(
81
+ expandedNodeId: ExpandedNodeId
82
+ ): Promise<{ local: boolean; serverIndex: number; serverUri: string | null }> {
83
+ const serverIndex = expandedNodeId.serverIndex ?? LOCAL_SERVER_INDEX;
84
+ if (serverIndex === LOCAL_SERVER_INDEX) {
85
+ return { local: true, serverIndex, serverUri: null };
86
+ }
87
+ return { local: false, serverIndex, serverUri: await this.resolveServerIndex(serverIndex) };
88
+ }
89
+ }