Skip to main content

opcua_server/node_manager/memory/
memory_mgr_impl.rs

1use async_trait::async_trait;
2
3use crate::{
4    address_space::AddressSpace,
5    diagnostics::NamespaceMetadata,
6    node_manager::{
7        AddNodeItem, AddReferenceItem, DeleteNodeItem, DeleteReferenceItem, HistoryNode,
8        HistoryUpdateNode, MethodCall, MonitoredItemRef, MonitoredItemUpdateRef, ParsedReadValueId,
9        RegisterNodeItem, RequestContext, ServerContext, WriteNode,
10    },
11    subscriptions::CreateMonitoredItem,
12};
13use opcua_core::sync::RwLock;
14use opcua_types::{
15    DataValue, ExpandedNodeId, MonitoringMode, NodeId, ReadAnnotationDataDetails,
16    ReadAtTimeDetails, ReadEventDetails, ReadProcessedDetails, ReadRawModifiedDetails, StatusCode,
17    TimestampsToReturn,
18};
19
20/// Trait for constructing an [InMemoryNodeManagerImpl].
21///
22/// Note that this is called with the lock on the [AddressSpace] held,
23/// if you try to lock it again, it will deadlock.
24pub trait InMemoryNodeManagerImplBuilder {
25    /// Type implementing [InMemoryNodeManagerImpl] constructed by this builder.
26    type Impl: InMemoryNodeManagerImpl;
27
28    /// Build the node manager impl.
29    fn build(self, context: ServerContext, address_space: &mut AddressSpace) -> Self::Impl;
30}
31
32impl<T, R: InMemoryNodeManagerImpl> InMemoryNodeManagerImplBuilder for T
33where
34    T: FnOnce(ServerContext, &mut AddressSpace) -> R,
35{
36    type Impl = R;
37
38    fn build(self, context: ServerContext, address_space: &mut AddressSpace) -> Self::Impl {
39        self(context, address_space)
40    }
41}
42
43#[async_trait]
44#[allow(unused)]
45/// Trait for user-provided implementation of the [InMemoryNodeManager](crate::node_manager::memory::InMemoryNodeManager)
46pub trait InMemoryNodeManagerImpl: Send + Sync + 'static {
47    /// Populate the address space.
48    async fn init(&self, address_space: &mut AddressSpace, context: ServerContext);
49
50    /// Name of this node manager, for debug purposes.
51    fn name(&self) -> &str;
52
53    /// Return the static list of namespaces this node manager uses.
54    fn namespaces(&self) -> Vec<NamespaceMetadata>;
55
56    /// Return whether this node should handle requests to create a node
57    /// for the given parent ID. This is only called if no new node ID is
58    /// requested, otherwise owns_node is called on the requested node ID.
59    fn owns_server_events(&self) -> bool {
60        false
61    }
62
63    /// Return `true` if a node with no requested node ID and parent `parent_id`
64    /// should be created using this node manager.
65    ///
66    /// This does not commit to actually allowing the node to be created, it just means
67    /// that no other node managers will be called to create the node.
68    fn handle_new_node(&self, parent_id: &ExpandedNodeId) -> bool {
69        false
70    }
71
72    /// Perform the register nodes service. The default behavior for this service is to
73    /// do nothing and pretend the nodes were registered.
74    async fn register_nodes(
75        &self,
76        context: &RequestContext,
77        address_space: &RwLock<AddressSpace>,
78        nodes: &mut [&mut RegisterNodeItem],
79    ) -> Result<(), StatusCode> {
80        for node in nodes {
81            node.set_registered(true);
82        }
83
84        Ok(())
85    }
86
87    /// Read for variable values. Other attributes are handled by the parent
88    /// node ID. This should return a list of data values with the same length
89    /// and order as `nodes`.
90    async fn read_values(
91        &self,
92        context: &RequestContext,
93        address_space: &RwLock<AddressSpace>,
94        nodes: &[&ParsedReadValueId],
95        max_age: f64,
96        timestamps_to_return: TimestampsToReturn,
97    ) -> Vec<DataValue> {
98        let address_space = address_space.read();
99        nodes
100            .iter()
101            .map(|n| address_space.read(context, n, max_age, timestamps_to_return))
102            .collect()
103    }
104
105    /// Create monitored items for the Value attribute, as needed.
106    /// This should, at the very least, read the current value of the nodes,
107    /// and set appropriate status on the monitored item request, see
108    /// default implementation.
109    ///
110    /// It may also begin sampling as given by the monitored item request.
111    async fn create_value_monitored_items(
112        &self,
113        context: &RequestContext,
114        address_space: &RwLock<AddressSpace>,
115        items: &mut [&mut &mut CreateMonitoredItem],
116    ) {
117        let to_read: Vec<_> = items.iter().map(|r| r.item_to_monitor()).collect();
118        let values = self
119            .read_values(
120                context,
121                address_space,
122                &to_read,
123                0.0,
124                TimestampsToReturn::Both,
125            )
126            .await;
127
128        for (value, node) in values.into_iter().zip(items.iter_mut()) {
129            if value.status() != StatusCode::BadAttributeIdInvalid {
130                node.set_initial_value(value);
131            }
132            node.set_status(StatusCode::Good);
133        }
134    }
135
136    /// Create monitored items for events.
137    ///
138    /// This does not need to do anything.
139    async fn create_event_monitored_items(
140        &self,
141        context: &RequestContext,
142        address_space: &RwLock<AddressSpace>,
143        items: &mut [&mut &mut CreateMonitoredItem],
144    ) {
145        // This is just a no-op by default.
146    }
147
148    /// Handle the SetMonitoringMode request, to pause or resume sampling.
149    ///
150    /// This will only get monitored items for events or value.
151    async fn set_monitoring_mode(
152        &self,
153        context: &RequestContext,
154        mode: MonitoringMode,
155        items: &[&MonitoredItemRef],
156    ) {
157    }
158
159    /// Handle modification of monitored items, this may adjust
160    /// sampling intervals or filters, and require action to update background
161    /// processes.
162    async fn modify_monitored_items(
163        &self,
164        context: &RequestContext,
165        items: &[&MonitoredItemUpdateRef],
166    ) {
167    }
168
169    /// Handle deletion of monitored items.
170    async fn delete_monitored_items(&self, context: &RequestContext, items: &[&MonitoredItemRef]) {}
171
172    /// Perform the unregister nodes service. The default behavior for this service is to
173    /// do nothing.
174    async fn unregister_nodes(
175        &self,
176        context: &RequestContext,
177        address_space: &RwLock<AddressSpace>,
178        nodes: &[&NodeId],
179    ) -> Result<(), StatusCode> {
180        // Again, just do nothing
181        Ok(())
182    }
183
184    /// Perform the history read raw modified service. This should write results
185    /// to the `nodes` list of type either `HistoryData` or `HistoryModifiedData`
186    ///
187    /// Nodes are verified to be readable before this is called.
188    async fn history_read_raw_modified(
189        &self,
190        context: &RequestContext,
191        details: &ReadRawModifiedDetails,
192        nodes: &mut [&mut &mut HistoryNode],
193        timestamps_to_return: TimestampsToReturn,
194    ) -> Result<(), StatusCode> {
195        Err(StatusCode::BadHistoryOperationUnsupported)
196    }
197
198    /// Perform the history read processed service. This should write results
199    /// to the `nodes` list of type `HistoryData`.
200    ///
201    /// Nodes are verified to be readable before this is called.
202    async fn history_read_processed(
203        &self,
204        context: &RequestContext,
205        details: &ReadProcessedDetails,
206        nodes: &mut [&mut &mut HistoryNode],
207        timestamps_to_return: TimestampsToReturn,
208    ) -> Result<(), StatusCode> {
209        Err(StatusCode::BadHistoryOperationUnsupported)
210    }
211
212    /// Perform the history read processed service. This should write results
213    /// to the `nodes` list of type `HistoryData`.
214    ///
215    /// Nodes are verified to be readable before this is called.
216    async fn history_read_at_time(
217        &self,
218        context: &RequestContext,
219        details: &ReadAtTimeDetails,
220        nodes: &mut [&mut &mut HistoryNode],
221        timestamps_to_return: TimestampsToReturn,
222    ) -> Result<(), StatusCode> {
223        Err(StatusCode::BadHistoryOperationUnsupported)
224    }
225
226    /// Perform the history read events service. This should write results
227    /// to the `nodes` list of type `HistoryEvent`.
228    ///
229    /// Nodes are verified to be readable before this is called.
230    async fn history_read_events(
231        &self,
232        context: &RequestContext,
233        details: &ReadEventDetails,
234        nodes: &mut [&mut &mut HistoryNode],
235        timestamps_to_return: TimestampsToReturn,
236    ) -> Result<(), StatusCode> {
237        Err(StatusCode::BadHistoryOperationUnsupported)
238    }
239
240    /// Perform the history read annotations data service. This should write
241    /// results to the `nodes` list of type `Annotation`.
242    ///
243    /// Nodes are verified to be readable before this is called.
244    async fn history_read_annotations(
245        &self,
246        context: &RequestContext,
247        details: &ReadAnnotationDataDetails,
248        nodes: &mut [&mut &mut HistoryNode],
249        timestamps_to_return: TimestampsToReturn,
250    ) -> Result<(), StatusCode> {
251        Err(StatusCode::BadHistoryOperationUnsupported)
252    }
253
254    /// Perform the HistoryUpdate service. This should write result
255    /// status codes to the `nodes` list as appropriate.
256    ///
257    /// Nodes are verified to be writable before this is called.
258    async fn history_update(
259        &self,
260        context: &RequestContext,
261        nodes: &mut [&mut &mut HistoryUpdateNode],
262    ) -> Result<(), StatusCode> {
263        Err(StatusCode::BadHistoryOperationUnsupported)
264    }
265
266    /// Perform the write service. This should write results
267    /// to the `nodes_to_write` list. The default result is `BadNodeIdUnknown`
268    ///
269    /// Writing is left almost entirely up to the node manager impl. If you do write
270    /// values you should call `context.subscriptions.notify_data_change` to trigger
271    /// any monitored items subscribed to the updated values.
272    async fn write(
273        &self,
274        context: &RequestContext,
275        address_space: &RwLock<AddressSpace>,
276        nodes_to_write: &mut [&mut WriteNode],
277    ) -> Result<(), StatusCode> {
278        Err(StatusCode::BadServiceUnsupported)
279    }
280
281    /// Call a list of methods.
282    ///
283    /// The methods have already had their arguments verified to have valid length
284    /// and the method is verified to exist on the given object. This should try
285    /// to execute the methods, and set the result.
286    async fn call(
287        &self,
288        context: &RequestContext,
289        address_space: &RwLock<AddressSpace>,
290        methods_to_call: &mut [&mut &mut MethodCall],
291    ) -> Result<(), StatusCode> {
292        Err(StatusCode::BadServiceUnsupported)
293    }
294
295    /// Add a list of nodes.
296    ///
297    /// This should create the nodes, or set a failed status as appropriate.
298    /// If a node was created, the status should be set to Good.
299    async fn add_nodes(
300        &self,
301        context: &RequestContext,
302        address_space: &RwLock<AddressSpace>,
303        nodes_to_add: &mut [&mut AddNodeItem],
304    ) -> Result<(), StatusCode> {
305        Err(StatusCode::BadServiceUnsupported)
306    }
307
308    /// Add a list of references.
309    ///
310    /// This will be given all references where the source _or_
311    /// target belongs to this node manager. A reference is
312    /// considered successfully added if either source_status
313    /// or target_status are Good.
314    ///
315    /// If you want to explicitly set the reference to failed,
316    /// set both source and target status. Note that it may
317    /// already have been added in a different node manager, you are
318    /// responsible for any cleanup if you do this.
319    async fn add_references(
320        &self,
321        context: &RequestContext,
322        address_space: &RwLock<AddressSpace>,
323        references_to_add: &mut [&mut AddReferenceItem],
324    ) -> Result<(), StatusCode> {
325        Err(StatusCode::BadServiceUnsupported)
326    }
327
328    /// Delete a list of nodes.
329    ///
330    /// This will be given all nodes that belong to this node manager.
331    ///
332    /// Typically, you also want to implement `delete_node_references` if
333    /// there are other node managers that support deletes.
334    async fn delete_nodes(
335        &self,
336        context: &RequestContext,
337        address_space: &RwLock<AddressSpace>,
338        nodes_to_delete: &mut [&mut DeleteNodeItem],
339    ) -> Result<(), StatusCode> {
340        Err(StatusCode::BadServiceUnsupported)
341    }
342
343    /// Delete references for the given list of nodes.
344    /// The node manager should respect `delete_target_references`.
345    ///
346    /// This is not allowed to fail, you should make it impossible to delete
347    /// nodes with immutable references.
348    async fn delete_node_references(
349        &self,
350        context: &RequestContext,
351        address_space: &RwLock<AddressSpace>,
352        to_delete: &[&DeleteNodeItem],
353    ) {
354    }
355
356    /// Delete a list of references.
357    ///
358    /// This will be given all references where the source _or_
359    /// target belongs to this node manager. A reference is
360    /// considered successfully added if either source_status
361    /// or target_status are Good.
362    ///
363    /// If you want to explicitly set the reference to failed,
364    /// set both source and target status. Note that it may
365    /// already have been deleted in a different node manager, you are
366    /// responsible for any cleanup if you do this.
367    async fn delete_references(
368        &self,
369        context: &RequestContext,
370        address_space: &RwLock<AddressSpace>,
371        references_to_delete: &mut [&mut DeleteReferenceItem],
372    ) -> Result<(), StatusCode> {
373        Err(StatusCode::BadServiceUnsupported)
374    }
375}