opcua_client/session/services/
node_management.rs1use std::time::Duration;
2
3use crate::{
4 session::{
5 process_service_result, process_unexpected_response,
6 request_builder::{builder_base, builder_debug, builder_error, RequestHeaderBuilder},
7 },
8 Session, UARequest,
9};
10
11use opcua_core::ResponseMessage;
12use opcua_types::{
13 AddNodesItem, AddNodesRequest, AddNodesResponse, AddNodesResult, AddReferencesItem,
14 AddReferencesRequest, AddReferencesResponse, DeleteNodesItem, DeleteNodesRequest,
15 DeleteNodesResponse, DeleteReferencesItem, DeleteReferencesRequest, DeleteReferencesResponse,
16 Error, IntegerId, NodeId, StatusCode,
17};
18use tracing::{debug_span, Instrument};
19
20#[derive(Debug, Clone)]
21pub struct AddNodes {
25 nodes_to_add: Vec<AddNodesItem>,
26
27 header: RequestHeaderBuilder,
28}
29
30builder_base!(AddNodes);
31
32impl AddNodes {
33 pub fn new(session: &Session) -> Self {
35 Self {
36 nodes_to_add: Vec::new(),
37 header: RequestHeaderBuilder::new_from_session(session),
38 }
39 }
40
41 pub fn new_manual(
43 session_id: u32,
44 timeout: Duration,
45 auth_token: NodeId,
46 request_handle: IntegerId,
47 ) -> Self {
48 Self {
49 nodes_to_add: Vec::new(),
50 header: RequestHeaderBuilder::new(session_id, timeout, auth_token, request_handle),
51 }
52 }
53
54 pub fn nodes_to_add(mut self, nodes_to_add: Vec<AddNodesItem>) -> Self {
56 self.nodes_to_add = nodes_to_add;
57 self
58 }
59
60 pub fn node(mut self, node: impl Into<AddNodesItem>) -> Self {
62 self.nodes_to_add.push(node.into());
63 self
64 }
65}
66
67impl UARequest for AddNodes {
68 type Out = AddNodesResponse;
69
70 async fn send<'a>(self, channel: &'a crate::AsyncSecureChannel) -> Result<Self::Out, Error>
71 where
72 Self: 'a,
73 {
74 let span = debug_span!(
75 "Sending AddNodes request",
76 num_nodes_to_add = self.nodes_to_add.len()
77 );
78 let request = {
79 let _h = span.enter();
80 if self.nodes_to_add.is_empty() {
81 builder_error!(self, "add_nodes, called with no nodes to add");
82 return Err(Error::new(
83 StatusCode::BadNothingToDo,
84 "add_nodes called with no nodes to add",
85 ));
86 }
87 AddNodesRequest {
88 request_header: self.header.header,
89 nodes_to_add: Some(self.nodes_to_add),
90 }
91 };
92
93 let response = channel
94 .send(request, self.header.timeout)
95 .instrument(span.clone())
96 .await?;
97 let _h = span.enter();
98 if let ResponseMessage::AddNodes(response) = response {
99 builder_debug!(self, "add_nodes, success");
100 process_service_result(&response.response_header)?;
101 Ok(*response)
102 } else {
103 builder_error!(self, "add_nodes failed");
104 Err(process_unexpected_response(response))
105 }
106 }
107}
108
109#[derive(Debug, Clone)]
110pub struct AddReferences {
114 references_to_add: Vec<AddReferencesItem>,
115
116 header: RequestHeaderBuilder,
117}
118
119builder_base!(AddReferences);
120
121impl AddReferences {
122 pub fn new(session: &Session) -> Self {
124 Self {
125 references_to_add: Vec::new(),
126 header: RequestHeaderBuilder::new_from_session(session),
127 }
128 }
129
130 pub fn new_manual(
132 session_id: u32,
133 timeout: Duration,
134 auth_token: NodeId,
135 request_handle: IntegerId,
136 ) -> Self {
137 Self {
138 references_to_add: Vec::new(),
139 header: RequestHeaderBuilder::new(session_id, timeout, auth_token, request_handle),
140 }
141 }
142
143 pub fn references_to_add(mut self, references_to_add: Vec<AddReferencesItem>) -> Self {
145 self.references_to_add = references_to_add;
146 self
147 }
148
149 pub fn reference(mut self, reference: impl Into<AddReferencesItem>) -> Self {
151 self.references_to_add.push(reference.into());
152 self
153 }
154}
155
156impl UARequest for AddReferences {
157 type Out = AddReferencesResponse;
158
159 async fn send<'a>(self, channel: &'a crate::AsyncSecureChannel) -> Result<Self::Out, Error>
160 where
161 Self: 'a,
162 {
163 let span = debug_span!(
164 "Sending AddReferences request",
165 num_references_to_add = self.references_to_add.len()
166 );
167 let request = {
168 let _h = span.enter();
169 if self.references_to_add.is_empty() {
170 builder_error!(self, "add_references, called with no references to add");
171 return Err(Error::new(
172 StatusCode::BadNothingToDo,
173 "add_references called with no references to add",
174 ));
175 }
176 AddReferencesRequest {
177 request_header: self.header.header,
178 references_to_add: Some(self.references_to_add),
179 }
180 };
181 let response = channel
182 .send(request, self.header.timeout)
183 .instrument(span.clone())
184 .await?;
185 let _h = span.enter();
186 if let ResponseMessage::AddReferences(response) = response {
187 builder_debug!(self, "add_references, success");
188 process_service_result(&response.response_header)?;
189 Ok(*response)
190 } else {
191 builder_error!(self, "add_references failed");
192 Err(process_unexpected_response(response))
193 }
194 }
195}
196
197#[derive(Debug, Clone)]
198pub struct DeleteNodes {
202 nodes_to_delete: Vec<DeleteNodesItem>,
203
204 header: RequestHeaderBuilder,
205}
206
207builder_base!(DeleteNodes);
208
209impl DeleteNodes {
210 pub fn new(session: &Session) -> Self {
212 Self {
213 nodes_to_delete: Vec::new(),
214 header: RequestHeaderBuilder::new_from_session(session),
215 }
216 }
217
218 pub fn new_manual(
220 session_id: u32,
221 timeout: Duration,
222 auth_token: NodeId,
223 request_handle: IntegerId,
224 ) -> Self {
225 Self {
226 nodes_to_delete: Vec::new(),
227 header: RequestHeaderBuilder::new(session_id, timeout, auth_token, request_handle),
228 }
229 }
230
231 pub fn nodes_to_delete(mut self, nodes_to_delete: Vec<DeleteNodesItem>) -> Self {
233 self.nodes_to_delete = nodes_to_delete;
234 self
235 }
236
237 pub fn node(mut self, reference: impl Into<DeleteNodesItem>) -> Self {
239 self.nodes_to_delete.push(reference.into());
240 self
241 }
242}
243
244impl UARequest for DeleteNodes {
245 type Out = DeleteNodesResponse;
246
247 async fn send<'a>(self, channel: &'a crate::AsyncSecureChannel) -> Result<Self::Out, Error>
248 where
249 Self: 'a,
250 {
251 let span = debug_span!(
252 "Sending DeleteNodes request",
253 num_nodes_to_delete = self.nodes_to_delete.len()
254 );
255 let request = {
256 let _h = span.enter();
257 if self.nodes_to_delete.is_empty() {
258 builder_error!(self, "delete_nodes, called with no nodes to delete");
259 return Err(Error::new(
260 StatusCode::BadNothingToDo,
261 "delete_nodes called with no nodes to delete",
262 ));
263 }
264 DeleteNodesRequest {
265 request_header: self.header.header,
266 nodes_to_delete: Some(self.nodes_to_delete),
267 }
268 };
269
270 let response = channel
271 .send(request, self.header.timeout)
272 .instrument(span.clone())
273 .await?;
274 let _h = span.enter();
275 if let ResponseMessage::DeleteNodes(response) = response {
276 builder_debug!(self, "delete_nodes, success");
277 process_service_result(&response.response_header)?;
278 Ok(*response)
279 } else {
280 builder_error!(self, "delete_nodes failed");
281 Err(process_unexpected_response(response))
282 }
283 }
284}
285
286#[derive(Debug, Clone)]
287pub struct DeleteReferences {
291 references_to_delete: Vec<DeleteReferencesItem>,
292
293 header: RequestHeaderBuilder,
294}
295
296builder_base!(DeleteReferences);
297
298impl DeleteReferences {
299 pub fn new(session: &Session) -> Self {
301 Self {
302 references_to_delete: Vec::new(),
303 header: RequestHeaderBuilder::new_from_session(session),
304 }
305 }
306
307 pub fn new_manual(
309 session_id: u32,
310 timeout: Duration,
311 auth_token: NodeId,
312 request_handle: IntegerId,
313 ) -> Self {
314 Self {
315 references_to_delete: Vec::new(),
316 header: RequestHeaderBuilder::new(session_id, timeout, auth_token, request_handle),
317 }
318 }
319
320 pub fn references_to_delete(mut self, references_to_delete: Vec<DeleteReferencesItem>) -> Self {
322 self.references_to_delete = references_to_delete;
323 self
324 }
325
326 pub fn reference(mut self, reference: impl Into<DeleteReferencesItem>) -> Self {
328 self.references_to_delete.push(reference.into());
329 self
330 }
331}
332
333impl UARequest for DeleteReferences {
334 type Out = DeleteReferencesResponse;
335
336 async fn send<'a>(self, channel: &'a crate::AsyncSecureChannel) -> Result<Self::Out, Error>
337 where
338 Self: 'a,
339 {
340 let span = debug_span!(
341 "Sending DeleteReferences request",
342 num_references_to_delete = self.references_to_delete.len()
343 );
344 let request = {
345 let _h = span.enter();
346 if self.references_to_delete.is_empty() {
347 builder_error!(
348 self,
349 "delete_references, called with no references to delete"
350 );
351 return Err(Error::new(
352 StatusCode::BadNothingToDo,
353 "delete_references called with no references to delete",
354 ));
355 }
356 DeleteReferencesRequest {
357 request_header: self.header.header,
358 references_to_delete: Some(self.references_to_delete),
359 }
360 };
361 let response = channel
362 .send(request, self.header.timeout)
363 .instrument(span.clone())
364 .await?;
365 let _h = span.enter();
366 if let ResponseMessage::DeleteReferences(response) = response {
367 builder_debug!(self, "delete_references, success");
368 process_service_result(&response.response_header)?;
369 Ok(*response)
370 } else {
371 builder_error!(self, "delete_references failed");
372 Err(process_unexpected_response(response))
373 }
374 }
375}
376
377impl Session {
378 pub async fn add_nodes(
392 &self,
393 nodes_to_add: &[AddNodesItem],
394 ) -> Result<Vec<AddNodesResult>, Error> {
395 Ok(AddNodes::new(self)
396 .nodes_to_add(nodes_to_add.to_vec())
397 .send(&self.channel)
398 .await?
399 .results
400 .unwrap_or_default())
401 }
402
403 pub async fn add_references(
417 &self,
418 references_to_add: &[AddReferencesItem],
419 ) -> Result<Vec<StatusCode>, Error> {
420 Ok(AddReferences::new(self)
421 .references_to_add(references_to_add.to_vec())
422 .send(&self.channel)
423 .await?
424 .results
425 .unwrap_or_default())
426 }
427
428 pub async fn delete_nodes(
442 &self,
443 nodes_to_delete: &[DeleteNodesItem],
444 ) -> Result<Vec<StatusCode>, Error> {
445 Ok(DeleteNodes::new(self)
446 .nodes_to_delete(nodes_to_delete.to_vec())
447 .send(&self.channel)
448 .await?
449 .results
450 .unwrap_or_default())
451 }
452
453 pub async fn delete_references(
467 &self,
468 references_to_delete: &[DeleteReferencesItem],
469 ) -> Result<Vec<StatusCode>, Error> {
470 Ok(DeleteReferences::new(self)
471 .references_to_delete(references_to_delete.to_vec())
472 .send(&self.channel)
473 .await?
474 .results
475 .unwrap_or_default())
476 }
477}