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}