Skip to main content

opcua_client/session/services/
node_management.rs

1use 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    IntegerId, NodeId, StatusCode,
17};
18
19#[derive(Debug, Clone)]
20/// Add nodes by sending a [`AddNodesRequest`] to the server.
21///
22/// See OPC UA Part 4 - Services 5.7.2 for complete description of the service and error responses.
23pub struct AddNodes {
24    nodes_to_add: Vec<AddNodesItem>,
25
26    header: RequestHeaderBuilder,
27}
28
29builder_base!(AddNodes);
30
31impl AddNodes {
32    /// Construct a new call to the `AddNodes` service.
33    pub fn new(session: &Session) -> Self {
34        Self {
35            nodes_to_add: Vec::new(),
36            header: RequestHeaderBuilder::new_from_session(session),
37        }
38    }
39
40    /// Construct a new call to the `AddNodes` service, setting header parameters manually.
41    pub fn new_manual(
42        session_id: u32,
43        timeout: Duration,
44        auth_token: NodeId,
45        request_handle: IntegerId,
46    ) -> Self {
47        Self {
48            nodes_to_add: Vec::new(),
49            header: RequestHeaderBuilder::new(session_id, timeout, auth_token, request_handle),
50        }
51    }
52
53    /// Set nodes to add, overwriting any that were set previously.
54    pub fn nodes_to_add(mut self, nodes_to_add: Vec<AddNodesItem>) -> Self {
55        self.nodes_to_add = nodes_to_add;
56        self
57    }
58
59    /// Add a node to create.
60    pub fn node(mut self, node: impl Into<AddNodesItem>) -> Self {
61        self.nodes_to_add.push(node.into());
62        self
63    }
64}
65
66impl UARequest for AddNodes {
67    type Out = AddNodesResponse;
68
69    async fn send<'a>(self, channel: &'a crate::AsyncSecureChannel) -> Result<Self::Out, StatusCode>
70    where
71        Self: 'a,
72    {
73        if self.nodes_to_add.is_empty() {
74            builder_error!(self, "add_nodes, called with no nodes to add");
75            return Err(StatusCode::BadNothingToDo);
76        }
77        let request = AddNodesRequest {
78            request_header: self.header.header,
79            nodes_to_add: Some(self.nodes_to_add),
80        };
81        let response = channel.send(request, self.header.timeout).await?;
82        if let ResponseMessage::AddNodes(response) = response {
83            builder_debug!(self, "add_nodes, success");
84            process_service_result(&response.response_header)?;
85            Ok(*response)
86        } else {
87            builder_error!(self, "add_nodes failed");
88            Err(process_unexpected_response(response))
89        }
90    }
91}
92
93#[derive(Debug, Clone)]
94/// Add references by sending a [`AddReferencesRequest`] to the server.
95///
96/// See OPC UA Part 4 - Services 5.7.3 for complete description of the service and error responses.
97pub struct AddReferences {
98    references_to_add: Vec<AddReferencesItem>,
99
100    header: RequestHeaderBuilder,
101}
102
103builder_base!(AddReferences);
104
105impl AddReferences {
106    /// Construct a new call to the `AddReferences` service.
107    pub fn new(session: &Session) -> Self {
108        Self {
109            references_to_add: Vec::new(),
110            header: RequestHeaderBuilder::new_from_session(session),
111        }
112    }
113
114    /// Construct a new call to the `AddReferences` service, setting header parameters manually.
115    pub fn new_manual(
116        session_id: u32,
117        timeout: Duration,
118        auth_token: NodeId,
119        request_handle: IntegerId,
120    ) -> Self {
121        Self {
122            references_to_add: Vec::new(),
123            header: RequestHeaderBuilder::new(session_id, timeout, auth_token, request_handle),
124        }
125    }
126
127    /// Set references to add, overwriting any that were set previously.
128    pub fn references_to_add(mut self, references_to_add: Vec<AddReferencesItem>) -> Self {
129        self.references_to_add = references_to_add;
130        self
131    }
132
133    /// Add a reference to create.
134    pub fn reference(mut self, reference: impl Into<AddReferencesItem>) -> Self {
135        self.references_to_add.push(reference.into());
136        self
137    }
138}
139
140impl UARequest for AddReferences {
141    type Out = AddReferencesResponse;
142
143    async fn send<'a>(self, channel: &'a crate::AsyncSecureChannel) -> Result<Self::Out, StatusCode>
144    where
145        Self: 'a,
146    {
147        if self.references_to_add.is_empty() {
148            builder_error!(self, "add_references, called with no references to add");
149            return Err(StatusCode::BadNothingToDo);
150        }
151        let request = AddReferencesRequest {
152            request_header: self.header.header,
153            references_to_add: Some(self.references_to_add),
154        };
155        let response = channel.send(request, self.header.timeout).await?;
156        if let ResponseMessage::AddReferences(response) = response {
157            builder_debug!(self, "add_references, success");
158            process_service_result(&response.response_header)?;
159            Ok(*response)
160        } else {
161            builder_error!(self, "add_references failed");
162            Err(process_unexpected_response(response))
163        }
164    }
165}
166
167#[derive(Debug, Clone)]
168/// Delete nodes by sending a [`DeleteNodesRequest`] to the server.
169///
170/// See OPC UA Part 4 - Services 5.7.4 for complete description of the service and error responses.
171pub struct DeleteNodes {
172    nodes_to_delete: Vec<DeleteNodesItem>,
173
174    header: RequestHeaderBuilder,
175}
176
177builder_base!(DeleteNodes);
178
179impl DeleteNodes {
180    /// Construct a new call to the `DeleteNodes` service.
181    pub fn new(session: &Session) -> Self {
182        Self {
183            nodes_to_delete: Vec::new(),
184            header: RequestHeaderBuilder::new_from_session(session),
185        }
186    }
187
188    /// Construct a new call to the `DeleteNodes` service, setting header parameters manually.
189    pub fn new_manual(
190        session_id: u32,
191        timeout: Duration,
192        auth_token: NodeId,
193        request_handle: IntegerId,
194    ) -> Self {
195        Self {
196            nodes_to_delete: Vec::new(),
197            header: RequestHeaderBuilder::new(session_id, timeout, auth_token, request_handle),
198        }
199    }
200
201    /// Set nodes to delete, overwriting any that were set previously.
202    pub fn nodes_to_delete(mut self, nodes_to_delete: Vec<DeleteNodesItem>) -> Self {
203        self.nodes_to_delete = nodes_to_delete;
204        self
205    }
206
207    /// Add a node to delete.
208    pub fn node(mut self, reference: impl Into<DeleteNodesItem>) -> Self {
209        self.nodes_to_delete.push(reference.into());
210        self
211    }
212}
213
214impl UARequest for DeleteNodes {
215    type Out = DeleteNodesResponse;
216
217    async fn send<'a>(self, channel: &'a crate::AsyncSecureChannel) -> Result<Self::Out, StatusCode>
218    where
219        Self: 'a,
220    {
221        if self.nodes_to_delete.is_empty() {
222            builder_error!(self, "delete_nodes, called with no nodes to delete");
223            return Err(StatusCode::BadNothingToDo);
224        }
225        let request = DeleteNodesRequest {
226            request_header: self.header.header,
227            nodes_to_delete: Some(self.nodes_to_delete),
228        };
229        let response = channel.send(request, self.header.timeout).await?;
230        if let ResponseMessage::DeleteNodes(response) = response {
231            builder_debug!(self, "delete_nodes, success");
232            process_service_result(&response.response_header)?;
233            Ok(*response)
234        } else {
235            builder_error!(self, "delete_nodes failed");
236            Err(process_unexpected_response(response))
237        }
238    }
239}
240
241#[derive(Debug, Clone)]
242/// Delete references by sending a [`DeleteReferencesRequest`] to the server.
243///
244/// See OPC UA Part 4 - Services 5.7.5 for complete description of the service and error responses.
245pub struct DeleteReferences {
246    references_to_delete: Vec<DeleteReferencesItem>,
247
248    header: RequestHeaderBuilder,
249}
250
251builder_base!(DeleteReferences);
252
253impl DeleteReferences {
254    /// Construct a new call to the `DeleteReferences` service.
255    pub fn new(session: &Session) -> Self {
256        Self {
257            references_to_delete: Vec::new(),
258            header: RequestHeaderBuilder::new_from_session(session),
259        }
260    }
261
262    /// Construct a new call to the `DeleteReferences` service, setting header parameters manually.
263    pub fn new_manual(
264        session_id: u32,
265        timeout: Duration,
266        auth_token: NodeId,
267        request_handle: IntegerId,
268    ) -> Self {
269        Self {
270            references_to_delete: Vec::new(),
271            header: RequestHeaderBuilder::new(session_id, timeout, auth_token, request_handle),
272        }
273    }
274
275    /// Set nodes to delete, overwriting any that were set previously.
276    pub fn references_to_delete(mut self, references_to_delete: Vec<DeleteReferencesItem>) -> Self {
277        self.references_to_delete = references_to_delete;
278        self
279    }
280
281    /// Add a reference to delete.
282    pub fn reference(mut self, reference: impl Into<DeleteReferencesItem>) -> Self {
283        self.references_to_delete.push(reference.into());
284        self
285    }
286}
287
288impl UARequest for DeleteReferences {
289    type Out = DeleteReferencesResponse;
290
291    async fn send<'a>(self, channel: &'a crate::AsyncSecureChannel) -> Result<Self::Out, StatusCode>
292    where
293        Self: 'a,
294    {
295        if self.references_to_delete.is_empty() {
296            builder_error!(
297                self,
298                "delete_references, called with no references to delete"
299            );
300            return Err(StatusCode::BadNothingToDo);
301        }
302        let request = DeleteReferencesRequest {
303            request_header: self.header.header,
304            references_to_delete: Some(self.references_to_delete),
305        };
306        let response = channel.send(request, self.header.timeout).await?;
307        if let ResponseMessage::DeleteReferences(response) = response {
308            builder_debug!(self, "delete_references, success");
309            process_service_result(&response.response_header)?;
310            Ok(*response)
311        } else {
312            builder_error!(self, "delete_references failed");
313            Err(process_unexpected_response(response))
314        }
315    }
316}
317
318impl Session {
319    /// Add nodes by sending a [`AddNodesRequest`] to the server.
320    ///
321    /// See OPC UA Part 4 - Services 5.7.2 for complete description of the service and error responses.
322    ///
323    /// # Arguments
324    ///
325    /// * `nodes_to_add` - A list of [`AddNodesItem`] to be added to the server.
326    ///
327    /// # Returns
328    ///
329    /// * `Ok(Vec<AddNodesResult>)` - A list of [`AddNodesResult`] corresponding to each add node operation.
330    /// * `Err(StatusCode)` - Request failed, [Status code](StatusCode) is the reason for failure.
331    ///
332    pub async fn add_nodes(
333        &self,
334        nodes_to_add: &[AddNodesItem],
335    ) -> Result<Vec<AddNodesResult>, StatusCode> {
336        Ok(AddNodes::new(self)
337            .nodes_to_add(nodes_to_add.to_vec())
338            .send(&self.channel)
339            .await?
340            .results
341            .unwrap_or_default())
342    }
343
344    /// Add references by sending a [`AddReferencesRequest`] to the server.
345    ///
346    /// See OPC UA Part 4 - Services 5.7.3 for complete description of the service and error responses.
347    ///
348    /// # Arguments
349    ///
350    /// * `references_to_add` - A list of [`AddReferencesItem`] to be sent to the server.
351    ///
352    /// # Returns
353    ///
354    /// * `Ok(Vec<StatusCode>)` - A list of `StatusCode` corresponding to each add reference operation.
355    /// * `Err(StatusCode)` - Request failed, [Status code](StatusCode) is the reason for failure.
356    ///
357    pub async fn add_references(
358        &self,
359        references_to_add: &[AddReferencesItem],
360    ) -> Result<Vec<StatusCode>, StatusCode> {
361        Ok(AddReferences::new(self)
362            .references_to_add(references_to_add.to_vec())
363            .send(&self.channel)
364            .await?
365            .results
366            .unwrap_or_default())
367    }
368
369    /// Delete nodes by sending a [`DeleteNodesRequest`] to the server.
370    ///
371    /// See OPC UA Part 4 - Services 5.7.4 for complete description of the service and error responses.
372    ///
373    /// # Arguments
374    ///
375    /// * `nodes_to_delete` - A list of [`DeleteNodesItem`] to be sent to the server.
376    ///
377    /// # Returns
378    ///
379    /// * `Ok(Vec<StatusCode>)` - A list of `StatusCode` corresponding to each delete node operation.
380    /// * `Err(StatusCode)` - Request failed, [Status code](StatusCode) is the reason for failure.
381    ///
382    pub async fn delete_nodes(
383        &self,
384        nodes_to_delete: &[DeleteNodesItem],
385    ) -> Result<Vec<StatusCode>, StatusCode> {
386        Ok(DeleteNodes::new(self)
387            .nodes_to_delete(nodes_to_delete.to_vec())
388            .send(&self.channel)
389            .await?
390            .results
391            .unwrap_or_default())
392    }
393
394    /// Delete references by sending a [`DeleteReferencesRequest`] to the server.
395    ///
396    /// See OPC UA Part 4 - Services 5.7.5 for complete description of the service and error responses.
397    ///
398    /// # Arguments
399    ///
400    /// * `nodes_to_delete` - A list of [`DeleteReferencesItem`] to be sent to the server.
401    ///
402    /// # Returns
403    ///
404    /// * `Ok(Vec<StatusCode>)` - A list of `StatusCode` corresponding to each delete node operation.
405    /// * `Err(StatusCode)` - Request failed, [Status code](StatusCode) is the reason for failure.
406    ///
407    pub async fn delete_references(
408        &self,
409        references_to_delete: &[DeleteReferencesItem],
410    ) -> Result<Vec<StatusCode>, StatusCode> {
411        Ok(DeleteReferences::new(self)
412            .references_to_delete(references_to_delete.to_vec())
413            .send(&self.channel)
414            .await?
415            .results
416            .unwrap_or_default())
417    }
418}