Skip to main content

opcua_server/node_manager/
node_management.rs

1use opcua_types::{
2    AddNodeAttributes, AddNodesItem, AddNodesResult, AddReferencesItem, DeleteNodesItem,
3    DeleteReferencesItem, DiagnosticBits, DiagnosticInfo, ExpandedNodeId, NodeClass, NodeId,
4    QualifiedName, StatusCode,
5};
6
7use super::IntoResult;
8
9#[derive(Debug, Clone)]
10/// Container for a single node being added in an `AddNode` service call.
11pub struct AddNodeItem {
12    parent_node_id: ExpandedNodeId,
13    reference_type_id: NodeId,
14    requested_new_node_id: NodeId,
15    browse_name: QualifiedName,
16    node_class: NodeClass,
17    node_attributes: AddNodeAttributes,
18    type_definition_id: ExpandedNodeId,
19    diagnostic_bits: DiagnosticBits,
20
21    result_node_id: NodeId,
22    status: StatusCode,
23    diagnostic_info: Option<DiagnosticInfo>,
24}
25
26impl AddNodeItem {
27    pub(crate) fn new(item: AddNodesItem, diagnostic_bits: DiagnosticBits) -> Self {
28        let mut status = StatusCode::BadNotSupported;
29        let attributes = match AddNodeAttributes::from_extension_object(item.node_attributes) {
30            Ok(attr) => attr,
31            Err(e) => {
32                status = e;
33                AddNodeAttributes::None
34            }
35        };
36        if item.requested_new_node_id.server_index != 0 {
37            status = StatusCode::BadNodeIdRejected;
38        }
39
40        Self::validate_attributes(item.node_class, &attributes, &mut status);
41
42        if item.reference_type_id.is_null() {
43            status = StatusCode::BadReferenceTypeIdInvalid;
44        }
45        if item.parent_node_id.is_null() {
46            status = StatusCode::BadParentNodeIdInvalid;
47        }
48
49        match (item.node_class, item.type_definition.is_null()) {
50            (NodeClass::Object | NodeClass::Variable, true) => {
51                status = StatusCode::BadTypeDefinitionInvalid
52            }
53            (NodeClass::Object | NodeClass::Variable, false) => (),
54            (_, false) => status = StatusCode::BadTypeDefinitionInvalid,
55            _ => (),
56        }
57
58        Self {
59            parent_node_id: item.parent_node_id,
60            reference_type_id: item.reference_type_id,
61            requested_new_node_id: item.requested_new_node_id.node_id,
62            browse_name: item.browse_name,
63            node_class: item.node_class,
64            node_attributes: attributes,
65            type_definition_id: item.type_definition,
66            result_node_id: NodeId::null(),
67            status,
68            diagnostic_info: None,
69            diagnostic_bits,
70        }
71    }
72
73    fn validate_attributes(
74        node_class: NodeClass,
75        attributes: &AddNodeAttributes,
76        status: &mut StatusCode,
77    ) {
78        match (node_class, attributes) {
79            (NodeClass::Object, AddNodeAttributes::Object(_))
80            | (NodeClass::Variable, AddNodeAttributes::Variable(_))
81            | (NodeClass::Method, AddNodeAttributes::Method(_))
82            | (NodeClass::ObjectType, AddNodeAttributes::ObjectType(_))
83            | (NodeClass::VariableType, AddNodeAttributes::VariableType(_))
84            | (NodeClass::ReferenceType, AddNodeAttributes::ReferenceType(_))
85            | (NodeClass::DataType, AddNodeAttributes::DataType(_))
86            | (NodeClass::View, AddNodeAttributes::View(_)) => {}
87            (NodeClass::Unspecified, _) => *status = StatusCode::BadNodeClassInvalid,
88            (_, AddNodeAttributes::None | AddNodeAttributes::Generic(_)) => {}
89            _ => *status = StatusCode::BadNodeAttributesInvalid,
90        }
91    }
92
93    /// Set the result of the operation. `node_id` is the node ID of the created node.
94    pub fn set_result(&mut self, node_id: NodeId, status: StatusCode) {
95        self.result_node_id = node_id;
96        self.status = status;
97    }
98
99    /// The requested parent node ID.
100    pub fn parent_node_id(&self) -> &ExpandedNodeId {
101        &self.parent_node_id
102    }
103
104    /// The requested reference type ID.
105    pub fn reference_type_id(&self) -> &NodeId {
106        &self.reference_type_id
107    }
108
109    /// The requested new node ID. May be null, in which case the node manager picks the new
110    /// node ID.
111    pub fn requested_new_node_id(&self) -> &NodeId {
112        &self.requested_new_node_id
113    }
114
115    /// Requested browse name of the new node.
116    pub fn browse_name(&self) -> &QualifiedName {
117        &self.browse_name
118    }
119
120    /// Requested node class of the new node.
121    pub fn node_class(&self) -> NodeClass {
122        self.node_class
123    }
124
125    /// Collection of requested attributes for the new node.
126    pub fn node_attributes(&self) -> &AddNodeAttributes {
127        &self.node_attributes
128    }
129
130    /// Requested type definition ID.
131    pub fn type_definition_id(&self) -> &ExpandedNodeId {
132        &self.type_definition_id
133    }
134
135    /// Current result status code.
136    pub fn status(&self) -> StatusCode {
137        self.status
138    }
139
140    /// Header diagnostic bits for requesting operation-level diagnostics.
141    pub fn diagnostic_bits(&self) -> DiagnosticBits {
142        self.diagnostic_bits
143    }
144
145    /// Set diagnostic infos, you don't need to do this if
146    /// `diagnostic_bits` are not set.
147    pub fn set_diagnostic_info(&mut self, diagnostic_info: DiagnosticInfo) {
148        self.diagnostic_info = Some(diagnostic_info);
149    }
150}
151
152impl IntoResult for AddNodeItem {
153    type Result = AddNodesResult;
154
155    fn into_result(self) -> (Self::Result, Option<DiagnosticInfo>) {
156        (
157            AddNodesResult {
158                status_code: self.status,
159                added_node_id: self.result_node_id,
160            },
161            self.diagnostic_info,
162        )
163    }
164}
165
166#[derive(Debug, Clone)]
167/// Container for a single reference being added in an `AddReferences` service call.
168pub struct AddReferenceItem {
169    source_node_id: NodeId,
170    reference_type_id: NodeId,
171    target_node_id: ExpandedNodeId,
172    is_forward: bool,
173    diagnostic_bits: DiagnosticBits,
174
175    source_status: StatusCode,
176    target_status: StatusCode,
177    diagnostic_info: Option<DiagnosticInfo>,
178}
179
180impl AddReferenceItem {
181    pub(crate) fn new(item: AddReferencesItem, diagnostic_bits: DiagnosticBits) -> Self {
182        let mut status = StatusCode::BadNotSupported;
183        if item.source_node_id.is_null() {
184            status = StatusCode::BadSourceNodeIdInvalid;
185        }
186        if item.target_node_id.is_null() {
187            status = StatusCode::BadTargetNodeIdInvalid;
188        }
189        if item.reference_type_id.is_null() {
190            status = StatusCode::BadReferenceTypeIdInvalid;
191        }
192        if !item.target_server_uri.is_null() || item.target_node_id.server_index != 0 {
193            status = StatusCode::BadReferenceLocalOnly;
194        }
195        Self {
196            source_node_id: item.source_node_id,
197            reference_type_id: item.reference_type_id,
198            target_node_id: item.target_node_id,
199            is_forward: item.is_forward,
200            source_status: status,
201            target_status: status,
202            diagnostic_bits,
203            diagnostic_info: None,
204        }
205    }
206
207    /// Requested source node ID.
208    pub fn source_node_id(&self) -> &NodeId {
209        &self.source_node_id
210    }
211
212    /// Requested reference type ID.
213    pub fn reference_type_id(&self) -> &NodeId {
214        &self.reference_type_id
215    }
216
217    /// Requested target node ID.
218    pub fn target_node_id(&self) -> &ExpandedNodeId {
219        &self.target_node_id
220    }
221
222    /// Current result status, as a summary of source status and target status.
223    pub(crate) fn result_status(&self) -> StatusCode {
224        if self.source_status.is_good() {
225            return self.source_status;
226        }
227        if self.target_status.is_good() {
228            return self.target_status;
229        }
230        self.source_status
231    }
232
233    /// Set the result of this operation for the _source_ end of the reference.
234    pub fn set_source_result(&mut self, status: StatusCode) {
235        self.source_status = status;
236    }
237
238    /// Set the result of this operation for the _target_ end of the reference.
239    pub fn set_target_result(&mut self, status: StatusCode) {
240        self.target_status = status;
241    }
242
243    /// Requested reference direction.
244    pub fn is_forward(&self) -> bool {
245        self.is_forward
246    }
247
248    /// Current target status.
249    pub fn target_status(&self) -> StatusCode {
250        self.target_status
251    }
252
253    /// Current source status.
254    pub fn source_status(&self) -> StatusCode {
255        self.source_status
256    }
257
258    /// Header diagnostic bits for requesting operation-level diagnostics.
259    pub fn diagnostic_bits(&self) -> DiagnosticBits {
260        self.diagnostic_bits
261    }
262
263    /// Set diagnostic infos, you don't need to do this if
264    /// `diagnostic_bits` are not set.
265    pub fn set_diagnostic_info(&mut self, diagnostic_info: DiagnosticInfo) {
266        self.diagnostic_info = Some(diagnostic_info);
267    }
268}
269
270impl IntoResult for AddReferenceItem {
271    type Result = StatusCode;
272
273    fn into_result(self) -> (Self::Result, Option<DiagnosticInfo>) {
274        (self.result_status(), self.diagnostic_info)
275    }
276}
277
278#[derive(Debug)]
279/// Container for a single item in a `DeleteNodes` service call.
280pub struct DeleteNodeItem {
281    node_id: NodeId,
282    delete_target_references: bool,
283    diagnostic_bits: DiagnosticBits,
284
285    status: StatusCode,
286    diagnostic_info: Option<DiagnosticInfo>,
287}
288
289impl DeleteNodeItem {
290    pub(crate) fn new(item: DeleteNodesItem, diagnostic_bits: DiagnosticBits) -> Self {
291        let mut status = StatusCode::BadNodeIdUnknown;
292        if item.node_id.is_null() {
293            status = StatusCode::BadNodeIdInvalid;
294        }
295
296        Self {
297            node_id: item.node_id,
298            delete_target_references: item.delete_target_references,
299            status,
300            diagnostic_bits,
301            diagnostic_info: None,
302        }
303    }
304
305    /// Current status of the operation.
306    pub fn status(&self) -> StatusCode {
307        self.status
308    }
309
310    /// Set the result of the node deletion operation.
311    pub fn set_result(&mut self, status: StatusCode) {
312        self.status = status;
313    }
314
315    /// Whether the request should delete references that point to this node or not.
316    pub fn delete_target_references(&self) -> bool {
317        self.delete_target_references
318    }
319
320    /// Node ID to delete.
321    pub fn node_id(&self) -> &NodeId {
322        &self.node_id
323    }
324
325    /// Header diagnostic bits for requesting operation-level diagnostics.
326    pub fn diagnostic_bits(&self) -> DiagnosticBits {
327        self.diagnostic_bits
328    }
329
330    /// Set diagnostic infos, you don't need to do this if
331    /// `diagnostic_bits` are not set.
332    pub fn set_diagnostic_info(&mut self, diagnostic_info: DiagnosticInfo) {
333        self.diagnostic_info = Some(diagnostic_info);
334    }
335}
336
337impl IntoResult for DeleteNodeItem {
338    type Result = StatusCode;
339
340    fn into_result(self) -> (Self::Result, Option<DiagnosticInfo>) {
341        (self.status(), self.diagnostic_info)
342    }
343}
344
345#[derive(Debug)]
346/// Container for a single reference being deleted in an `DeleteReferences` service call.
347pub struct DeleteReferenceItem {
348    source_node_id: NodeId,
349    reference_type_id: NodeId,
350    is_forward: bool,
351    target_node_id: ExpandedNodeId,
352    delete_bidirectional: bool,
353    diagnostic_bits: DiagnosticBits,
354
355    source_status: StatusCode,
356    target_status: StatusCode,
357    diagnostic_info: Option<DiagnosticInfo>,
358}
359
360impl DeleteReferenceItem {
361    pub(crate) fn new(item: DeleteReferencesItem, diagnostic_bits: DiagnosticBits) -> Self {
362        let mut status = StatusCode::BadNotSupported;
363        if item.source_node_id.is_null() {
364            status = StatusCode::BadSourceNodeIdInvalid;
365        }
366        if item.target_node_id.is_null() {
367            status = StatusCode::BadTargetNodeIdInvalid;
368        }
369        if item.reference_type_id.is_null() {
370            status = StatusCode::BadReferenceTypeIdInvalid;
371        }
372        if item.target_node_id.server_index != 0 {
373            status = StatusCode::BadReferenceLocalOnly;
374        }
375
376        Self {
377            source_node_id: item.source_node_id,
378            reference_type_id: item.reference_type_id,
379            is_forward: item.is_forward,
380            target_node_id: item.target_node_id,
381            delete_bidirectional: item.delete_bidirectional,
382            diagnostic_bits,
383
384            source_status: status,
385            target_status: status,
386            diagnostic_info: None,
387        }
388    }
389
390    /// Source node ID of the reference being deleted.
391    pub fn source_node_id(&self) -> &NodeId {
392        &self.source_node_id
393    }
394
395    /// Reference type ID of the reference being deleted.
396    pub fn reference_type_id(&self) -> &NodeId {
397        &self.reference_type_id
398    }
399
400    /// Target node ID of the reference being deleted.
401    pub fn target_node_id(&self) -> &ExpandedNodeId {
402        &self.target_node_id
403    }
404
405    pub(crate) fn result_status(&self) -> StatusCode {
406        if self.source_status.is_good() {
407            return self.source_status;
408        }
409        if self.target_status.is_good() {
410            return self.target_status;
411        }
412        self.source_status
413    }
414
415    /// Set the result of this operation for the _source_ end of the reference.
416    pub fn set_source_result(&mut self, status: StatusCode) {
417        self.source_status = status;
418    }
419
420    /// Set the result of this operation for the _target_ end of the reference.
421    pub fn set_target_result(&mut self, status: StatusCode) {
422        self.target_status = status;
423    }
424
425    /// Direction of the reference being deleted.
426    pub fn is_forward(&self) -> bool {
427        self.is_forward
428    }
429
430    /// Current target status.
431    pub fn target_status(&self) -> StatusCode {
432        self.target_status
433    }
434
435    /// Current source status.
436    pub fn source_status(&self) -> StatusCode {
437        self.source_status
438    }
439
440    /// Whether to delete the reference in both directions.
441    pub fn delete_bidirectional(&self) -> bool {
442        self.delete_bidirectional
443    }
444
445    /// Header diagnostic bits for requesting operation-level diagnostics.
446    pub fn diagnostic_bits(&self) -> DiagnosticBits {
447        self.diagnostic_bits
448    }
449
450    /// Set diagnostic infos, you don't need to do this if
451    /// `diagnostic_bits` are not set.
452    pub fn set_diagnostic_info(&mut self, diagnostic_info: DiagnosticInfo) {
453        self.diagnostic_info = Some(diagnostic_info);
454    }
455}
456
457impl IntoResult for DeleteReferenceItem {
458    type Result = StatusCode;
459
460    fn into_result(self) -> (Self::Result, Option<DiagnosticInfo>) {
461        (self.result_status(), self.diagnostic_info)
462    }
463}