node-opcua-client 2.173.1 → 2.174.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.
- package/README.md +67 -33
- package/dist/client_session.d.ts +75 -3
- package/dist/opcua_client.d.ts +139 -5
- package/dist/opcua_client.js +40 -0
- package/dist/opcua_client.js.map +1 -1
- package/dist/private/client_session_impl.d.ts +1 -0
- package/dist/private/client_session_impl.js +1 -0
- package/dist/private/client_session_impl.js.map +1 -1
- package/dist/private/opcua_client_impl.js +6 -2
- package/dist/private/opcua_client_impl.js.map +1 -1
- package/dist/private/reconnection/client_publish_engine_reconnection.js +41 -7
- package/dist/private/reconnection/client_publish_engine_reconnection.js.map +1 -1
- package/dist/private/reconnection/reconnection.js +12 -0
- package/dist/private/reconnection/reconnection.js.map +1 -1
- package/package.json +38 -38
- package/source/client_session.ts +75 -3
- package/source/opcua_client.ts +139 -6
- package/source/private/client_session_impl.ts +15 -15
- package/source/private/opcua_client_impl.ts +19 -18
- package/source/private/reconnection/client_publish_engine_reconnection.ts +43 -8
- package/source/private/reconnection/reconnection.ts +13 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "node-opcua-client",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.174.0",
|
|
4
4
|
"description": "pure nodejs OPCUA SDK - module client",
|
|
5
5
|
"scripts": {
|
|
6
6
|
"clean": "npx rimraf -g node_modules dist *.tsbuildinfo certificates",
|
|
@@ -16,56 +16,56 @@
|
|
|
16
16
|
"dependencies": {
|
|
17
17
|
"@ster5/global-mutex": "^3.3.0",
|
|
18
18
|
"chalk": "4.1.2",
|
|
19
|
-
"node-opcua-alarm-condition": "2.
|
|
19
|
+
"node-opcua-alarm-condition": "2.174.0",
|
|
20
20
|
"node-opcua-assert": "2.164.0",
|
|
21
|
-
"node-opcua-basic-types": "2.
|
|
21
|
+
"node-opcua-basic-types": "2.174.0",
|
|
22
22
|
"node-opcua-buffer-utils": "2.173.0",
|
|
23
|
-
"node-opcua-certificate-manager": "2.
|
|
24
|
-
"node-opcua-client-dynamic-extension-object": "2.
|
|
25
|
-
"node-opcua-common": "2.
|
|
26
|
-
"node-opcua-constants": "2.
|
|
23
|
+
"node-opcua-certificate-manager": "2.174.0",
|
|
24
|
+
"node-opcua-client-dynamic-extension-object": "2.174.0",
|
|
25
|
+
"node-opcua-common": "2.174.0",
|
|
26
|
+
"node-opcua-constants": "2.174.0",
|
|
27
27
|
"node-opcua-crypto": "5.3.6",
|
|
28
|
-
"node-opcua-data-model": "2.
|
|
29
|
-
"node-opcua-data-value": "2.
|
|
30
|
-
"node-opcua-date-time": "2.
|
|
28
|
+
"node-opcua-data-model": "2.174.0",
|
|
29
|
+
"node-opcua-data-value": "2.174.0",
|
|
30
|
+
"node-opcua-date-time": "2.174.0",
|
|
31
31
|
"node-opcua-debug": "2.172.0",
|
|
32
|
-
"node-opcua-extension-object": "2.
|
|
32
|
+
"node-opcua-extension-object": "2.174.0",
|
|
33
33
|
"node-opcua-hostname": "2.167.0",
|
|
34
|
-
"node-opcua-nodeid": "2.
|
|
35
|
-
"node-opcua-numeric-range": "2.
|
|
34
|
+
"node-opcua-nodeid": "2.174.0",
|
|
35
|
+
"node-opcua-numeric-range": "2.174.0",
|
|
36
36
|
"node-opcua-object-registry": "2.172.0",
|
|
37
|
-
"node-opcua-pki": "6.
|
|
38
|
-
"node-opcua-pseudo-session": "2.
|
|
39
|
-
"node-opcua-schemas": "2.
|
|
40
|
-
"node-opcua-secure-channel": "2.
|
|
41
|
-
"node-opcua-service-browse": "2.
|
|
42
|
-
"node-opcua-service-call": "2.
|
|
43
|
-
"node-opcua-service-discovery": "2.
|
|
44
|
-
"node-opcua-service-endpoints": "2.
|
|
45
|
-
"node-opcua-service-filter": "2.
|
|
46
|
-
"node-opcua-service-history": "2.
|
|
47
|
-
"node-opcua-service-query": "2.
|
|
48
|
-
"node-opcua-service-read": "2.
|
|
49
|
-
"node-opcua-service-register-node": "2.
|
|
50
|
-
"node-opcua-service-secure-channel": "2.
|
|
51
|
-
"node-opcua-service-session": "2.
|
|
52
|
-
"node-opcua-service-subscription": "2.
|
|
53
|
-
"node-opcua-service-translate-browse-path": "2.
|
|
54
|
-
"node-opcua-service-write": "2.
|
|
37
|
+
"node-opcua-pki": "6.18.0",
|
|
38
|
+
"node-opcua-pseudo-session": "2.174.0",
|
|
39
|
+
"node-opcua-schemas": "2.174.0",
|
|
40
|
+
"node-opcua-secure-channel": "2.174.0",
|
|
41
|
+
"node-opcua-service-browse": "2.174.0",
|
|
42
|
+
"node-opcua-service-call": "2.174.0",
|
|
43
|
+
"node-opcua-service-discovery": "2.174.0",
|
|
44
|
+
"node-opcua-service-endpoints": "2.174.0",
|
|
45
|
+
"node-opcua-service-filter": "2.174.0",
|
|
46
|
+
"node-opcua-service-history": "2.174.0",
|
|
47
|
+
"node-opcua-service-query": "2.174.0",
|
|
48
|
+
"node-opcua-service-read": "2.174.0",
|
|
49
|
+
"node-opcua-service-register-node": "2.174.0",
|
|
50
|
+
"node-opcua-service-secure-channel": "2.174.0",
|
|
51
|
+
"node-opcua-service-session": "2.174.0",
|
|
52
|
+
"node-opcua-service-subscription": "2.174.0",
|
|
53
|
+
"node-opcua-service-translate-browse-path": "2.174.0",
|
|
54
|
+
"node-opcua-service-write": "2.174.0",
|
|
55
55
|
"node-opcua-status-code": "2.173.0",
|
|
56
|
-
"node-opcua-transport": "2.
|
|
57
|
-
"node-opcua-types": "2.
|
|
56
|
+
"node-opcua-transport": "2.174.0",
|
|
57
|
+
"node-opcua-types": "2.174.0",
|
|
58
58
|
"node-opcua-utils": "2.173.0",
|
|
59
|
-
"node-opcua-variant": "2.
|
|
59
|
+
"node-opcua-variant": "2.174.0",
|
|
60
60
|
"thenify-ex": "4.4.0"
|
|
61
61
|
},
|
|
62
62
|
"devDependencies": {
|
|
63
63
|
"dequeue": "^1.0.5",
|
|
64
|
-
"node-opcua-address-space": "2.
|
|
64
|
+
"node-opcua-address-space": "2.174.0",
|
|
65
65
|
"node-opcua-binary-stream": "2.173.0",
|
|
66
|
-
"node-opcua-factory": "2.
|
|
66
|
+
"node-opcua-factory": "2.174.0",
|
|
67
67
|
"node-opcua-leak-detector": "2.172.0",
|
|
68
|
-
"node-opcua-nodesets": "2.
|
|
68
|
+
"node-opcua-nodesets": "2.174.0"
|
|
69
69
|
},
|
|
70
70
|
"eslintConfig": {
|
|
71
71
|
"env": {
|
|
@@ -87,7 +87,7 @@
|
|
|
87
87
|
"internet of things"
|
|
88
88
|
],
|
|
89
89
|
"homepage": "http://node-opcua.github.io/",
|
|
90
|
-
"gitHead": "
|
|
90
|
+
"gitHead": "011657a3a4805ad106df7381c24ed84e2a18d8f1",
|
|
91
91
|
"files": [
|
|
92
92
|
"dist",
|
|
93
93
|
"source"
|
package/source/client_session.ts
CHANGED
|
@@ -121,7 +121,21 @@ export interface ClientSessionBase {
|
|
|
121
121
|
* the session name
|
|
122
122
|
*/
|
|
123
123
|
name: string;
|
|
124
|
+
/**
|
|
125
|
+
* the StatusCode returned by the last ActivateSession — usually `Good`, but
|
|
126
|
+
* e.g. `Good_PasswordChangeRequired` when the user must change the password
|
|
127
|
+
* (OPC 10000-18 §5.2.8). Lets a Client react without server-side access.
|
|
128
|
+
*/
|
|
129
|
+
lastActivateSessionStatusCode: StatusCode;
|
|
124
130
|
|
|
131
|
+
/**
|
|
132
|
+
* Close the session.
|
|
133
|
+
*
|
|
134
|
+
* @param deleteSubscription - if `true` (the default), all
|
|
135
|
+
* subscriptions created on this session are deleted on
|
|
136
|
+
* the server. Set to `false` to preserve subscriptions
|
|
137
|
+
* for later transfer to a new session.
|
|
138
|
+
*/
|
|
125
139
|
close(callback: ErrorCallback): void;
|
|
126
140
|
|
|
127
141
|
close(deleteSubscription: boolean, callback: ErrorCallback): void;
|
|
@@ -129,6 +143,40 @@ export interface ClientSessionBase {
|
|
|
129
143
|
close(deleteSubscription?: boolean): Promise<void>;
|
|
130
144
|
}
|
|
131
145
|
|
|
146
|
+
/**
|
|
147
|
+
* An active session to an OPC UA server.
|
|
148
|
+
*
|
|
149
|
+
* `ClientSession` provides access to all OPC UA services:
|
|
150
|
+
* reading and writing node values, browsing the address space,
|
|
151
|
+
* calling methods, and creating subscriptions for data change
|
|
152
|
+
* or event notifications.
|
|
153
|
+
*
|
|
154
|
+
* Sessions are created via {@link OPCUAClient.createSession} or
|
|
155
|
+
* {@link OPCUAClient.create} followed by `client.createSession()`.
|
|
156
|
+
*
|
|
157
|
+
* @example
|
|
158
|
+
* ```typescript
|
|
159
|
+
* const session = await client.createSession();
|
|
160
|
+
*
|
|
161
|
+
* // Read a value
|
|
162
|
+
* const dataValue = await session.read({
|
|
163
|
+
* nodeId: "ns=0;i=2258",
|
|
164
|
+
* attributeId: AttributeIds.Value,
|
|
165
|
+
* });
|
|
166
|
+
*
|
|
167
|
+
* // Browse the root folder
|
|
168
|
+
* const browseResult = await session.browse("RootFolder");
|
|
169
|
+
*
|
|
170
|
+
* // Write a value
|
|
171
|
+
* await session.write({
|
|
172
|
+
* nodeId: "ns=1;s=MyVariable",
|
|
173
|
+
* attributeId: AttributeIds.Value,
|
|
174
|
+
* value: { value: { dataType: DataType.Double, value: 42.0 } },
|
|
175
|
+
* });
|
|
176
|
+
*
|
|
177
|
+
* await session.close();
|
|
178
|
+
* ```
|
|
179
|
+
*/
|
|
132
180
|
export interface ClientSession extends ClientSessionBase {
|
|
133
181
|
/* */
|
|
134
182
|
serverEndpoints: EndpointDescription[];
|
|
@@ -152,11 +200,17 @@ export interface ClientSession extends EventEmitter {
|
|
|
152
200
|
}
|
|
153
201
|
|
|
154
202
|
// browse services
|
|
203
|
+
/**
|
|
204
|
+
* Browse service — navigate the OPC UA address space.
|
|
205
|
+
*
|
|
206
|
+
* The `browse()` and `browseNext()` methods are inherited from
|
|
207
|
+
* {@link node-opcua-pseudo-session!IBasicSessionBrowse}.
|
|
208
|
+
*/
|
|
155
209
|
export interface ClientSessionBrowseService extends IBasicSessionBrowse, IBasicSessionBrowseNext {
|
|
156
210
|
/**
|
|
157
|
-
*
|
|
158
|
-
*
|
|
159
|
-
* with browseNext
|
|
211
|
+
* The maximum number of references the server should return
|
|
212
|
+
* per browse result. If the server has more, it returns a
|
|
213
|
+
* continuation point to retrieve the rest with `browseNext()`.
|
|
160
214
|
*/
|
|
161
215
|
requestedMaxReferencesPerNode: number;
|
|
162
216
|
}
|
|
@@ -172,7 +226,19 @@ export interface ClientSessionQueryService {
|
|
|
172
226
|
}
|
|
173
227
|
|
|
174
228
|
// call services
|
|
229
|
+
/**
|
|
230
|
+
* Call service — invoke methods on server objects.
|
|
231
|
+
*
|
|
232
|
+
* The `call()` method is inherited from
|
|
233
|
+
* {@link node-opcua-pseudo-session!IBasicSessionCall}.
|
|
234
|
+
*/
|
|
175
235
|
export interface ClientSessionCallService extends IBasicSessionCall {
|
|
236
|
+
/**
|
|
237
|
+
* Retrieve the input and output argument definitions of a method.
|
|
238
|
+
*
|
|
239
|
+
* @param methodId - the NodeId of the method
|
|
240
|
+
* @returns the argument definitions (input and output)
|
|
241
|
+
*/
|
|
176
242
|
getArgumentDefinition(methodId: MethodId): Promise<ArgumentDefinition>;
|
|
177
243
|
getArgumentDefinition(methodId: MethodId, callback: (err: Error | null, args?: ArgumentDefinition) => void): void;
|
|
178
244
|
}
|
|
@@ -222,6 +288,12 @@ export interface ClientSessionWriteService extends IBasicSessionWrite {
|
|
|
222
288
|
}
|
|
223
289
|
|
|
224
290
|
// raw subscription services
|
|
291
|
+
/**
|
|
292
|
+
* Raw subscription service — low-level OPC UA subscription management.
|
|
293
|
+
*
|
|
294
|
+
* For a higher-level API, use {@link ClientSubscription} via
|
|
295
|
+
* `ClientSession.createSubscription2()`.
|
|
296
|
+
*/
|
|
225
297
|
export interface ClientSessionRawSubscriptionService {
|
|
226
298
|
/**
|
|
227
299
|
*
|
package/source/opcua_client.ts
CHANGED
|
@@ -61,31 +61,90 @@ export type WithSessionFuncP<T> = (session: ClientSession) => Promise<T>;
|
|
|
61
61
|
export type WithSubscriptionFunc = (session: ClientSession, subscription: ClientSubscription) => Promise<void>;
|
|
62
62
|
export type WithSubscriptionFuncP<T> = (session: ClientSession, subscription: ClientSubscription) => Promise<T>;
|
|
63
63
|
|
|
64
|
+
/**
|
|
65
|
+
* The OPC UA client interface.
|
|
66
|
+
*
|
|
67
|
+
* `OPCUAClient` provides methods to connect to an OPC UA server,
|
|
68
|
+
* create sessions, and manage the client lifecycle.
|
|
69
|
+
*
|
|
70
|
+
* Use {@link OPCUAClient.create} to instantiate a client.
|
|
71
|
+
*
|
|
72
|
+
* @example
|
|
73
|
+
* ```typescript
|
|
74
|
+
* const client = OPCUAClient.create({ endpointMustExist: false });
|
|
75
|
+
* await client.connect("opc.tcp://localhost:26543");
|
|
76
|
+
* const session = await client.createSession();
|
|
77
|
+
* // ... use the session ...
|
|
78
|
+
* await session.close();
|
|
79
|
+
* await client.disconnect();
|
|
80
|
+
* ```
|
|
81
|
+
*/
|
|
64
82
|
export interface OPCUAClient<Events extends OPCUAClientBaseEvents = OPCUAClientBaseEvents> extends OPCUAClientBase<Events> {
|
|
83
|
+
/**
|
|
84
|
+
* Connect the client to the specified OPC UA server endpoint.
|
|
85
|
+
*
|
|
86
|
+
* The client will establish a secure channel, negotiate security
|
|
87
|
+
* parameters, and verify the server certificate.
|
|
88
|
+
*
|
|
89
|
+
* @param endpointUrl - the OPC UA endpoint URL (e.g. `"opc.tcp://host:4840"`)
|
|
90
|
+
*/
|
|
65
91
|
connect(endpointUrl: string): Promise<void>;
|
|
66
92
|
connect(endpointUrl: string, callback: ErrorCallback): void;
|
|
67
93
|
|
|
94
|
+
/**
|
|
95
|
+
* Disconnect the client from the server.
|
|
96
|
+
*
|
|
97
|
+
* This closes all active sessions, subscriptions, and the
|
|
98
|
+
* underlying secure channel.
|
|
99
|
+
*/
|
|
68
100
|
disconnect(): Promise<void>;
|
|
69
101
|
disconnect(callback: ErrorCallback): void;
|
|
70
102
|
|
|
103
|
+
/**
|
|
104
|
+
* Retrieve the list of endpoints exposed by the server.
|
|
105
|
+
*
|
|
106
|
+
* @param options - optional filter criteria for the endpoint query
|
|
107
|
+
* @returns the array of endpoint descriptions advertised by the server
|
|
108
|
+
*/
|
|
71
109
|
getEndpoints(options?: GetEndpointsOptions): Promise<EndpointDescription[]>;
|
|
72
110
|
|
|
73
111
|
getEndpoints(options: GetEndpointsOptions, callback: ResponseCallback<EndpointDescription[]>): void;
|
|
74
112
|
|
|
75
113
|
getEndpoints(callback: ResponseCallback<EndpointDescription[]>): void;
|
|
76
114
|
|
|
115
|
+
/**
|
|
116
|
+
* Discover OPC UA servers registered on the network.
|
|
117
|
+
*
|
|
118
|
+
* @param options - optional filter criteria for the discovery query
|
|
119
|
+
* @returns the array of discovered server application descriptions
|
|
120
|
+
*/
|
|
77
121
|
findServers(options?: FindServersRequestLike): Promise<ApplicationDescription[]>;
|
|
78
122
|
|
|
79
123
|
findServers(options: FindServersRequestLike, callback: ResponseCallback<ApplicationDescription[]>): void;
|
|
80
124
|
|
|
81
125
|
findServers(callback: ResponseCallback<ApplicationDescription[]>): void;
|
|
82
126
|
|
|
127
|
+
/**
|
|
128
|
+
* Create a new session on the connected server.
|
|
129
|
+
*
|
|
130
|
+
* If `userIdentityInfo` is not provided, an anonymous session
|
|
131
|
+
* is created.
|
|
132
|
+
*
|
|
133
|
+
* @param userIdentityInfo - optional credentials for user authentication
|
|
134
|
+
* @returns the newly created client session
|
|
135
|
+
*/
|
|
83
136
|
createSession(userIdentityInfo?: UserIdentityInfo): Promise<ClientSession>;
|
|
84
137
|
|
|
85
138
|
createSession(userIdentityInfo: UserIdentityInfo, callback: (err: Error | null, session?: ClientSession) => void): void;
|
|
86
139
|
|
|
87
140
|
createSession(callback: (err: Error | null, session?: ClientSession) => void): void;
|
|
88
141
|
|
|
142
|
+
/**
|
|
143
|
+
* Create a new session, using createSession2 service (OPC UA 1.04+).
|
|
144
|
+
*
|
|
145
|
+
* @param userIdentityInfo - optional credentials for user authentication
|
|
146
|
+
* @returns the newly created client session
|
|
147
|
+
*/
|
|
89
148
|
createSession2(userIdentityInfo?: UserIdentityInfo): Promise<ClientSession>;
|
|
90
149
|
|
|
91
150
|
createSession2(userIdentityInfo: UserIdentityInfo, callback: (err: Error | null, session?: ClientSession) => void): void;
|
|
@@ -96,29 +155,63 @@ export interface OPCUAClient<Events extends OPCUAClientBaseEvents = OPCUAClientB
|
|
|
96
155
|
changeSessionIdentity(session: ClientSession, userIdentityInfo: UserIdentityInfo): Promise<StatusCode>;
|
|
97
156
|
changeSessionIdentity(session: ClientSession, userIdentityInfo: UserIdentityInfo, callback: CallbackT<StatusCode>): void;
|
|
98
157
|
|
|
158
|
+
/**
|
|
159
|
+
* Close a previously created session.
|
|
160
|
+
*
|
|
161
|
+
* @param session - the session to close
|
|
162
|
+
* @param deleteSubscriptions - if `true`, all subscriptions
|
|
163
|
+
* associated with the session are deleted on the server
|
|
164
|
+
*/
|
|
99
165
|
closeSession(session: ClientSession, deleteSubscriptions: boolean): Promise<void>;
|
|
100
166
|
|
|
101
167
|
closeSession(session: ClientSession, deleteSubscriptions: boolean, callback: (err?: Error) => void): void;
|
|
102
168
|
|
|
169
|
+
/**
|
|
170
|
+
* Reactivate a session that was previously transferred or
|
|
171
|
+
* disconnected.
|
|
172
|
+
*
|
|
173
|
+
* @param session - the session to reactivate
|
|
174
|
+
*/
|
|
103
175
|
reactivateSession(session: ClientSession): Promise<void>;
|
|
104
176
|
|
|
105
177
|
reactivateSession(session: ClientSession, callback: (err?: Error) => void): void;
|
|
106
178
|
|
|
107
|
-
|
|
179
|
+
/** @internal */
|
|
108
180
|
createDefaultCertificate(): Promise<void>;
|
|
109
181
|
|
|
110
182
|
/**
|
|
183
|
+
* Connect to a server, execute an async function within a session,
|
|
184
|
+
* then automatically close the session and disconnect.
|
|
185
|
+
*
|
|
186
|
+
* This is a convenience method for simple one-shot operations.
|
|
187
|
+
*
|
|
188
|
+
* @param endpointUrl - the server endpoint URL or endpoint with credentials
|
|
189
|
+
* @param inner_func - the async function to execute with the session
|
|
190
|
+
* @returns the value returned by `inner_func`
|
|
111
191
|
*
|
|
112
|
-
* @
|
|
113
|
-
*
|
|
192
|
+
* @example
|
|
193
|
+
* ```typescript
|
|
194
|
+
* const result = await client.withSessionAsync(
|
|
195
|
+
* "opc.tcp://localhost:26543",
|
|
196
|
+
* async (session) => {
|
|
197
|
+
* return await session.read({ nodeId: "ns=0;i=2258",
|
|
198
|
+
* attributeId: AttributeIds.Value });
|
|
199
|
+
* }
|
|
200
|
+
* );
|
|
201
|
+
* ```
|
|
114
202
|
*/
|
|
115
203
|
withSessionAsync<T>(endpointUrl: string | EndpointWithUserIdentity, inner_func: WithSessionFuncP<T>): Promise<T>;
|
|
116
204
|
|
|
117
205
|
/**
|
|
206
|
+
* Connect to a server, create a session and a subscription,
|
|
207
|
+
* execute an async function, then clean up everything.
|
|
118
208
|
*
|
|
119
|
-
*
|
|
120
|
-
*
|
|
121
|
-
* @param
|
|
209
|
+
* This is a convenience method for subscription-based operations.
|
|
210
|
+
*
|
|
211
|
+
* @param endpointUrl - the server endpoint URL or endpoint with credentials
|
|
212
|
+
* @param parameters - subscription creation parameters
|
|
213
|
+
* @param inner_func - the async function to execute with the session and subscription
|
|
214
|
+
* @returns the value returned by `inner_func`
|
|
122
215
|
*/
|
|
123
216
|
withSubscriptionAsync<T>(
|
|
124
217
|
endpointUrl: string | EndpointWithUserIdentity,
|
|
@@ -127,10 +220,50 @@ export interface OPCUAClient<Events extends OPCUAClientBaseEvents = OPCUAClientB
|
|
|
127
220
|
): Promise<T>;
|
|
128
221
|
}
|
|
129
222
|
|
|
223
|
+
/**
|
|
224
|
+
* Factory class for creating OPC UA client instances.
|
|
225
|
+
*
|
|
226
|
+
* @example
|
|
227
|
+
* ```typescript
|
|
228
|
+
* import { OPCUAClient } from "node-opcua-client";
|
|
229
|
+
*
|
|
230
|
+
* const client = OPCUAClient.create({
|
|
231
|
+
* endpointMustExist: false,
|
|
232
|
+
* requestedSessionTimeout: 60000,
|
|
233
|
+
* });
|
|
234
|
+
* ```
|
|
235
|
+
*/
|
|
130
236
|
export class OPCUAClient {
|
|
237
|
+
/**
|
|
238
|
+
* Create a new OPC UA client instance.
|
|
239
|
+
*
|
|
240
|
+
* @param options - client configuration options
|
|
241
|
+
* @returns a configured OPC UA client ready to connect
|
|
242
|
+
*/
|
|
131
243
|
public static create(options: OPCUAClientOptions): OPCUAClient {
|
|
132
244
|
return new OPCUAClientImpl(options) as unknown as OPCUAClient;
|
|
133
245
|
}
|
|
246
|
+
/**
|
|
247
|
+
* Convenience method to create a client, connect, and establish
|
|
248
|
+
* a session in one call.
|
|
249
|
+
*
|
|
250
|
+
* @param endpointUrl - the OPC UA endpoint URL
|
|
251
|
+
* @param userIdentity - optional user credentials
|
|
252
|
+
* @param clientOptions - optional client configuration
|
|
253
|
+
* @returns a connected client session
|
|
254
|
+
*
|
|
255
|
+
* @example
|
|
256
|
+
* ```typescript
|
|
257
|
+
* const session = await OPCUAClient.createSession(
|
|
258
|
+
* "opc.tcp://localhost:26543"
|
|
259
|
+
* );
|
|
260
|
+
* const dataValue = await session.read({
|
|
261
|
+
* nodeId: "ns=0;i=2258",
|
|
262
|
+
* attributeId: AttributeIds.Value,
|
|
263
|
+
* });
|
|
264
|
+
* await session.close(true); // deleteSubscriptions = true
|
|
265
|
+
* ```
|
|
266
|
+
*/
|
|
134
267
|
public static async createSession(
|
|
135
268
|
endpointUrl: string,
|
|
136
269
|
userIdentity?: UserIdentityInfo,
|
|
@@ -205,6 +205,7 @@ export class ClientSessionImpl extends EventEmitter implements ClientSession, Re
|
|
|
205
205
|
public serverNonce?: Nonce;
|
|
206
206
|
public serverSignature?: SignatureData; // todo : remove ?
|
|
207
207
|
public serverEndpoints: EndpointDescription[] = [];
|
|
208
|
+
public lastActivateSessionStatusCode: StatusCode = StatusCodes.Good;
|
|
208
209
|
public _client: IClientBase | null;
|
|
209
210
|
public _closed: boolean;
|
|
210
211
|
|
|
@@ -278,7 +279,6 @@ export class ClientSessionImpl extends EventEmitter implements ClientSession, Re
|
|
|
278
279
|
};
|
|
279
280
|
}
|
|
280
281
|
|
|
281
|
-
|
|
282
282
|
public [Symbol.for("nodejs.util.inspect.custom")](): string {
|
|
283
283
|
return this.toString();
|
|
284
284
|
}
|
|
@@ -420,8 +420,8 @@ export class ClientSessionImpl extends EventEmitter implements ClientSession, Re
|
|
|
420
420
|
if (r.references && r.references.length > this.requestedMaxReferencesPerNode) {
|
|
421
421
|
warningLog(
|
|
422
422
|
chalk.yellow("warning") +
|
|
423
|
-
|
|
424
|
-
|
|
423
|
+
" BrowseResponse : the server didn't take into" +
|
|
424
|
+
" account our requestedMaxReferencesPerNode "
|
|
425
425
|
);
|
|
426
426
|
warningLog(" this.requestedMaxReferencesPerNode= " + this.requestedMaxReferencesPerNode);
|
|
427
427
|
warningLog(" got " + r.references.length + "for " + nodesToBrowse[i].nodeId.toString());
|
|
@@ -430,7 +430,7 @@ export class ClientSessionImpl extends EventEmitter implements ClientSession, Re
|
|
|
430
430
|
}
|
|
431
431
|
}
|
|
432
432
|
for (const r of results) {
|
|
433
|
-
r.references = r.references || /* c8 ignore next */[];
|
|
433
|
+
r.references = r.references || /* c8 ignore next */ [];
|
|
434
434
|
}
|
|
435
435
|
assert(results[0] instanceof BrowseResult);
|
|
436
436
|
return callback(null, isArray ? results : results[0]);
|
|
@@ -725,7 +725,7 @@ export class ClientSessionImpl extends EventEmitter implements ClientSession, Re
|
|
|
725
725
|
return callback(new Error(response.responseHeader.serviceResult.toString()));
|
|
726
726
|
}
|
|
727
727
|
|
|
728
|
-
response.results = response.results || /* c8 ignore next */[];
|
|
728
|
+
response.results = response.results || /* c8 ignore next */ [];
|
|
729
729
|
|
|
730
730
|
// perform ExtensionObject resolution
|
|
731
731
|
const promises = response.results.map(async (result) => {
|
|
@@ -870,7 +870,7 @@ export class ClientSessionImpl extends EventEmitter implements ClientSession, Re
|
|
|
870
870
|
return callback(new Error(response.responseHeader.serviceResult.toString()));
|
|
871
871
|
}
|
|
872
872
|
|
|
873
|
-
response.results = response.results || /* c8 ignore next */[];
|
|
873
|
+
response.results = response.results || /* c8 ignore next */ [];
|
|
874
874
|
|
|
875
875
|
assert(nodesToRead.length === response.results.length);
|
|
876
876
|
|
|
@@ -1009,7 +1009,7 @@ export class ClientSessionImpl extends EventEmitter implements ClientSession, Re
|
|
|
1009
1009
|
if (response.responseHeader.serviceResult.isNot(StatusCodes.Good)) {
|
|
1010
1010
|
return callback(new Error(response.responseHeader.serviceResult.toString()));
|
|
1011
1011
|
}
|
|
1012
|
-
response.results = response.results || /* c8 ignore next */[];
|
|
1012
|
+
response.results = response.results || /* c8 ignore next */ [];
|
|
1013
1013
|
assert(nodesToWrite.length === response.results.length);
|
|
1014
1014
|
callback(null, isArray ? response.results : response.results[0]);
|
|
1015
1015
|
});
|
|
@@ -1204,7 +1204,7 @@ export class ClientSessionImpl extends EventEmitter implements ClientSession, Re
|
|
|
1204
1204
|
warningLog(
|
|
1205
1205
|
chalk.yellow(
|
|
1206
1206
|
"please make sure to refactor your code and check that " +
|
|
1207
|
-
|
|
1207
|
+
"the second argument of your callback function is named"
|
|
1208
1208
|
),
|
|
1209
1209
|
chalk.cyan("dataValue" + (isArray ? "s" : ""))
|
|
1210
1210
|
);
|
|
@@ -1238,7 +1238,7 @@ export class ClientSessionImpl extends EventEmitter implements ClientSession, Re
|
|
|
1238
1238
|
// perform ExtensionObject resolution
|
|
1239
1239
|
promoteOpaqueStructure(this, response.results!)
|
|
1240
1240
|
.then(() => {
|
|
1241
|
-
response.results = response.results || /* c8 ignore next */[];
|
|
1241
|
+
response.results = response.results || /* c8 ignore next */ [];
|
|
1242
1242
|
callback(null, isArray ? response.results : response.results[0]);
|
|
1243
1243
|
})
|
|
1244
1244
|
.catch((err) => {
|
|
@@ -1416,7 +1416,7 @@ export class ClientSessionImpl extends EventEmitter implements ClientSession, Re
|
|
|
1416
1416
|
if (!response) {
|
|
1417
1417
|
return callback(new Error("Internal Error"));
|
|
1418
1418
|
}
|
|
1419
|
-
response.results = response.results || /* c8 ignore next */[];
|
|
1419
|
+
response.results = response.results || /* c8 ignore next */ [];
|
|
1420
1420
|
callback(err, isArray ? response.results : response.results[0]);
|
|
1421
1421
|
}
|
|
1422
1422
|
);
|
|
@@ -1452,7 +1452,7 @@ export class ClientSessionImpl extends EventEmitter implements ClientSession, Re
|
|
|
1452
1452
|
if (!response || !(response instanceof TranslateBrowsePathsToNodeIdsResponse)) {
|
|
1453
1453
|
return callback(new Error("Internal Error"));
|
|
1454
1454
|
}
|
|
1455
|
-
response.results = response.results || /* c8 ignore next */[];
|
|
1455
|
+
response.results = response.results || /* c8 ignore next */ [];
|
|
1456
1456
|
|
|
1457
1457
|
callback(null, isArray ? response.results : response.results[0]);
|
|
1458
1458
|
});
|
|
@@ -1601,9 +1601,9 @@ export class ClientSessionImpl extends EventEmitter implements ClientSession, Re
|
|
|
1601
1601
|
if (response.responseHeader.serviceResult.isNot(StatusCodes.Good)) {
|
|
1602
1602
|
err = new Error(
|
|
1603
1603
|
" ServiceResult is " +
|
|
1604
|
-
|
|
1605
|
-
|
|
1606
|
-
|
|
1604
|
+
response.responseHeader.serviceResult.toString() +
|
|
1605
|
+
" request was " +
|
|
1606
|
+
request.constructor.name
|
|
1607
1607
|
);
|
|
1608
1608
|
|
|
1609
1609
|
if (response && response.responseHeader.serviceDiagnostics) {
|
|
@@ -1852,7 +1852,7 @@ export class ClientSessionImpl extends EventEmitter implements ClientSession, Re
|
|
|
1852
1852
|
return callback(new Error("Internal Error"));
|
|
1853
1853
|
}
|
|
1854
1854
|
|
|
1855
|
-
response.registeredNodeIds = response.registeredNodeIds || /* c8 ignore next */[];
|
|
1855
|
+
response.registeredNodeIds = response.registeredNodeIds || /* c8 ignore next */ [];
|
|
1856
1856
|
|
|
1857
1857
|
callback(null, response.registeredNodeIds);
|
|
1858
1858
|
});
|
|
@@ -21,6 +21,7 @@ import {
|
|
|
21
21
|
import { LocalizedText } from "node-opcua-data-model";
|
|
22
22
|
import { checkDebugFlag, make_debugLog, make_errorLog, make_warningLog } from "node-opcua-debug";
|
|
23
23
|
import { extractFullyQualifiedDomainName } from "node-opcua-hostname";
|
|
24
|
+
import type { NodeId } from "node-opcua-nodeid";
|
|
24
25
|
import { readNamespaceArray } from "node-opcua-pseudo-session";
|
|
25
26
|
import {
|
|
26
27
|
type ClientSecureChannelLayer,
|
|
@@ -48,7 +49,6 @@ import {
|
|
|
48
49
|
import { type Callback, type CallbackT, type StatusCode, StatusCodes } from "node-opcua-status-code";
|
|
49
50
|
import type { SignatureDataOptions, UserIdentityToken } from "node-opcua-types";
|
|
50
51
|
import { isNullOrUndefined, matchUri, randomBytes } from "node-opcua-utils";
|
|
51
|
-
import type { NodeId } from "node-opcua-nodeid";
|
|
52
52
|
import type { OPCUAClientBaseEvents } from "../client_base";
|
|
53
53
|
import type { ClientSession } from "../client_session";
|
|
54
54
|
import type { ClientSubscriptionOptions } from "../client_subscription";
|
|
@@ -563,11 +563,7 @@ export class OPCUAClientImpl extends ClientBaseImpl<OPCUAClientBaseEvents> {
|
|
|
563
563
|
clearTimeout(this._retryCreateSessionTimer);
|
|
564
564
|
this._retryCreateSessionTimer = undefined;
|
|
565
565
|
}
|
|
566
|
-
super.closeSession(
|
|
567
|
-
session as unknown as ClientSessionImpl,
|
|
568
|
-
deleteSubscriptions,
|
|
569
|
-
callback as (err?: Error) => void
|
|
570
|
-
);
|
|
566
|
+
super.closeSession(session as unknown as ClientSessionImpl, deleteSubscriptions, callback as (err?: Error) => void);
|
|
571
567
|
}
|
|
572
568
|
|
|
573
569
|
public toJSON(): Record<string, string | number | boolean | undefined> {
|
|
@@ -733,11 +729,11 @@ export class OPCUAClientImpl extends ClientBaseImpl<OPCUAClientBaseEvents> {
|
|
|
733
729
|
return callback?.(
|
|
734
730
|
new Error(
|
|
735
731
|
" End point must exist " +
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
732
|
+
this._secureChannel?.endpointUrl +
|
|
733
|
+
" securityMode = " +
|
|
734
|
+
MessageSecurityMode[this.securityMode] +
|
|
735
|
+
" securityPolicy = " +
|
|
736
|
+
this.securityPolicy
|
|
741
737
|
)
|
|
742
738
|
);
|
|
743
739
|
}
|
|
@@ -968,7 +964,9 @@ export class OPCUAClientImpl extends ClientBaseImpl<OPCUAClientBaseEvents> {
|
|
|
968
964
|
// clientCertificate. The SignatureAlgorithm shall be the AsymmetricSignatureAlgorithm
|
|
969
965
|
// specified in the SecurityPolicy for the Endpoint. The SignatureData type is defined in 7.30.
|
|
970
966
|
|
|
971
|
-
clientSignature:
|
|
967
|
+
clientSignature:
|
|
968
|
+
this.computeClientSignature(this._secureChannel as ClientSecureChannelLayer, serverCertificate, serverNonce) ||
|
|
969
|
+
undefined,
|
|
972
970
|
|
|
973
971
|
// These are the SoftwareCertificates which have been issued to the Client application.
|
|
974
972
|
// The productUri contained in the SoftwareCertificates shall match the productUri in the
|
|
@@ -1013,7 +1011,7 @@ export class OPCUAClientImpl extends ClientBaseImpl<OPCUAClientBaseEvents> {
|
|
|
1013
1011
|
session.lastRequestSentTime = new Date();
|
|
1014
1012
|
|
|
1015
1013
|
this.performMessageTransaction(request, (err1: Error | null, response?: Response) => {
|
|
1016
|
-
if (!err1 && response && response.responseHeader.serviceResult
|
|
1014
|
+
if (!err1 && response && response.responseHeader.serviceResult.isGoodish()) {
|
|
1017
1015
|
/* c8 ignore next */
|
|
1018
1016
|
if (!(response instanceof ActivateSessionResponse)) {
|
|
1019
1017
|
return callback(new Error("Internal Error"));
|
|
@@ -1023,6 +1021,9 @@ export class OPCUAClientImpl extends ClientBaseImpl<OPCUAClientBaseEvents> {
|
|
|
1023
1021
|
return callback(new Error("Invalid server Nonce"));
|
|
1024
1022
|
}
|
|
1025
1023
|
session._client = this;
|
|
1024
|
+
// capture the activation outcome (e.g. Good_PasswordChangeRequired,
|
|
1025
|
+
// OPC 10000-18 §5.2.8) so a Client can react without server access.
|
|
1026
|
+
session.lastActivateSessionStatusCode = response.responseHeader.serviceResult;
|
|
1026
1027
|
session.serverNonce = response.serverNonce;
|
|
1027
1028
|
session.lastResponseReceivedTime = new Date();
|
|
1028
1029
|
if (this.keepSessionAlive) {
|
|
@@ -1152,11 +1153,11 @@ export class OPCUAClientImpl extends ClientBaseImpl<OPCUAClientBaseEvents> {
|
|
|
1152
1153
|
return callback(
|
|
1153
1154
|
new Error(
|
|
1154
1155
|
" End point must exist " +
|
|
1155
|
-
|
|
1156
|
-
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
|
|
1156
|
+
this._secureChannel?.endpointUrl +
|
|
1157
|
+
" securityMode = " +
|
|
1158
|
+
MessageSecurityMode[this.securityMode] +
|
|
1159
|
+
" securityPolicy = " +
|
|
1160
|
+
this.securityPolicy
|
|
1160
1161
|
)
|
|
1161
1162
|
);
|
|
1162
1163
|
}
|