1use std::{collections::HashMap, sync::Arc, time::Duration};
2
3use async_trait::async_trait;
4use opcua_core::{trace_read_lock, trace_write_lock};
5use opcua_nodes::{HasNodeId, NodeSetImport};
6
7use crate::{
8 address_space::{read_node_value, write_node_value, AddressSpace},
9 node_manager::{
10 DefaultTypeTree, MethodCall, MonitoredItemRef, MonitoredItemUpdateRef, NodeManagerBuilder,
11 NodeManagersRef, ParsedReadValueId, RequestContext, ServerContext, SyncSampler, WriteNode,
12 },
13 CreateMonitoredItem,
14};
15use opcua_core::sync::RwLock;
16use opcua_types::{
17 AttributeId, DataValue, MonitoringMode, NodeClass, NodeId, NumericRange, StatusCode,
18 TimestampsToReturn, Variant,
19};
20
21use super::{
22 InMemoryNodeManager, InMemoryNodeManagerBuilder, InMemoryNodeManagerImpl,
23 InMemoryNodeManagerImplBuilder, NamespaceMetadata,
24};
25
26pub type SimpleNodeManager = InMemoryNodeManager<SimpleNodeManagerImpl>;
29
30type WriteCB = Arc<dyn Fn(DataValue, &NumericRange) -> StatusCode + Send + Sync + 'static>;
31type ReadCB = Arc<
32 dyn Fn(&NumericRange, TimestampsToReturn, f64) -> Result<DataValue, StatusCode>
33 + Send
34 + Sync
35 + 'static,
36>;
37type MethodCB = Arc<dyn Fn(&[Variant]) -> Result<Vec<Variant>, StatusCode> + Send + Sync + 'static>;
38
39pub struct SimpleNodeManagerBuilder {
41 namespaces: Vec<NamespaceMetadata>,
42 imports: Vec<Box<dyn NodeSetImport>>,
43 name: String,
44}
45
46impl SimpleNodeManagerBuilder {
47 pub fn new(namespace: NamespaceMetadata, name: &str) -> Self {
50 Self {
51 namespaces: vec![namespace],
52 imports: Vec::new(),
53 name: name.to_owned(),
54 }
55 }
56
57 pub fn new_imports(imports: Vec<Box<dyn NodeSetImport>>, name: &str) -> Self {
60 Self {
61 namespaces: Vec::new(),
62 imports,
63 name: name.to_owned(),
64 }
65 }
66}
67
68impl InMemoryNodeManagerImplBuilder for SimpleNodeManagerBuilder {
69 type Impl = SimpleNodeManagerImpl;
70
71 fn build(mut self, context: ServerContext, address_space: &mut AddressSpace) -> Self::Impl {
72 {
73 let mut type_tree = context.type_tree.write();
74 for import in self.imports {
75 address_space.import_node_set(&*import, type_tree.namespaces_mut());
76 let nss = import.get_own_namespaces();
77 for ns in nss {
78 if !self.namespaces.iter().any(|n| n.namespace_uri == ns) {
79 self.namespaces.push(NamespaceMetadata {
80 namespace_uri: ns,
81 ..Default::default()
82 });
83 }
84 }
85 }
86 for ns in &mut self.namespaces {
87 ns.namespace_index = type_tree.namespaces_mut().add_namespace(&ns.namespace_uri);
88 }
89 }
90 for ns in &self.namespaces {
91 address_space.add_namespace(&ns.namespace_uri, ns.namespace_index);
92 }
93 SimpleNodeManagerImpl::new(self.namespaces, &self.name, context.node_managers.clone())
94 }
95}
96
97pub fn simple_node_manager(namespace: NamespaceMetadata, name: &str) -> impl NodeManagerBuilder {
100 InMemoryNodeManagerBuilder::new(SimpleNodeManagerBuilder::new(namespace, name))
101}
102
103pub fn simple_node_manager_imports(
106 imports: Vec<Box<dyn NodeSetImport>>,
107 name: &str,
108) -> impl NodeManagerBuilder {
109 InMemoryNodeManagerBuilder::new(SimpleNodeManagerBuilder::new_imports(imports, name))
110}
111
112pub struct SimpleNodeManagerImpl {
120 write_cbs: RwLock<HashMap<NodeId, WriteCB>>,
121 read_cbs: RwLock<HashMap<NodeId, ReadCB>>,
122 method_cbs: RwLock<HashMap<NodeId, MethodCB>>,
123 namespaces: Vec<NamespaceMetadata>,
124 #[allow(unused)]
125 node_managers: NodeManagersRef,
126 name: String,
127 samplers: SyncSampler,
128}
129
130#[async_trait]
131impl InMemoryNodeManagerImpl for SimpleNodeManagerImpl {
132 async fn init(&self, _address_space: &mut AddressSpace, context: ServerContext) {
133 self.samplers.run(
134 Duration::from_micros(
135 (context
141 .info
142 .config
143 .limits
144 .subscriptions
145 .min_sampling_interval_ms
146 .max(100.0)
147 * 1000.0) as u64,
148 ),
149 context.subscriptions.clone(),
150 );
151 }
152
153 fn namespaces(&self) -> Vec<NamespaceMetadata> {
154 self.namespaces.clone()
155 }
156
157 fn name(&self) -> &str {
158 &self.name
159 }
160
161 async fn read_values(
162 &self,
163 context: &RequestContext,
164 address_space: &RwLock<AddressSpace>,
165 nodes: &[&ParsedReadValueId],
166 max_age: f64,
167 timestamps_to_return: TimestampsToReturn,
168 ) -> Vec<DataValue> {
169 let address_space = address_space.read();
170 let cbs = trace_read_lock!(self.read_cbs);
171
172 nodes
173 .iter()
174 .map(|n| {
175 self.read_node_value(
176 &cbs,
177 context,
178 &address_space,
179 n,
180 max_age,
181 timestamps_to_return,
182 )
183 })
184 .collect()
185 }
186
187 async fn create_value_monitored_items(
188 &self,
189 context: &RequestContext,
190 address_space: &RwLock<AddressSpace>,
191 items: &mut [&mut &mut CreateMonitoredItem],
192 ) {
193 let to_read: Vec<_> = items.iter().map(|r| r.item_to_monitor()).collect();
194 let values = self
195 .read_values(
196 context,
197 address_space,
198 &to_read,
199 0.0,
200 TimestampsToReturn::Both,
201 )
202 .await;
203
204 let cbs = trace_read_lock!(self.read_cbs);
205
206 for (value, node) in values.into_iter().zip(items.iter_mut()) {
207 if value.status() != StatusCode::BadAttributeIdInvalid {
208 node.set_initial_value(value);
209 }
210 node.set_status(StatusCode::Good);
211 let rf = &node.item_to_monitor().node_id;
212
213 if let Some(cb) = cbs.get(rf).cloned() {
214 let tss = node.timestamps_to_return();
215 let index_range = node.item_to_monitor().index_range.clone();
216
217 self.samplers.add_sampler(
218 node.item_to_monitor().node_id.clone(),
219 AttributeId::Value,
220 move || {
221 Some(match cb(&index_range, tss, 0.0) {
222 Err(e) => DataValue {
223 status: Some(e),
224 ..Default::default()
225 },
226 Ok(v) => v,
227 })
228 },
229 node.monitoring_mode(),
230 node.handle(),
231 Duration::from_millis(node.sampling_interval() as u64),
232 )
233 }
234 }
235 }
236
237 async fn modify_monitored_items(
238 &self,
239 _context: &RequestContext,
240 items: &[&MonitoredItemUpdateRef],
241 ) {
242 for it in items {
243 self.samplers.update_sampler(
244 it.node_id(),
245 it.attribute(),
246 it.handle(),
247 Duration::from_millis(it.update().revised_sampling_interval as u64),
248 );
249 }
250 }
251
252 async fn set_monitoring_mode(
253 &self,
254 _context: &RequestContext,
255 mode: MonitoringMode,
256 items: &[&MonitoredItemRef],
257 ) {
258 for it in items {
259 self.samplers
260 .set_sampler_mode(it.node_id(), it.attribute(), it.handle(), mode);
261 }
262 }
263
264 async fn delete_monitored_items(&self, _context: &RequestContext, items: &[&MonitoredItemRef]) {
265 for it in items {
266 self.samplers
267 .remove_sampler(it.node_id(), it.attribute(), it.handle());
268 }
269 }
270
271 async fn write(
272 &self,
273 context: &RequestContext,
274 address_space: &RwLock<AddressSpace>,
275 nodes_to_write: &mut [&mut WriteNode],
276 ) -> Result<(), StatusCode> {
277 let mut address_space = trace_write_lock!(address_space);
278 let type_tree = trace_read_lock!(context.type_tree);
279 let cbs = trace_read_lock!(self.write_cbs);
280
281 for write in nodes_to_write {
282 self.write_node_value(&cbs, context, &mut address_space, &type_tree, write);
283 }
284
285 Ok(())
286 }
287
288 async fn call(
289 &self,
290 _context: &RequestContext,
291 _address_space: &RwLock<AddressSpace>,
292 methods_to_call: &mut [&mut &mut MethodCall],
293 ) -> Result<(), StatusCode> {
294 let cbs = trace_read_lock!(self.method_cbs);
295 for method in methods_to_call {
296 if let Some(cb) = cbs.get(method.method_id()) {
297 match cb(method.arguments()) {
298 Ok(r) => {
299 method.set_outputs(r);
300 method.set_status(StatusCode::Good);
301 }
302 Err(e) => method.set_status(e),
303 }
304 }
305 }
306
307 Ok(())
308 }
309}
310
311impl SimpleNodeManagerImpl {
312 fn new(namespaces: Vec<NamespaceMetadata>, name: &str, node_managers: NodeManagersRef) -> Self {
313 Self {
314 write_cbs: Default::default(),
315 read_cbs: Default::default(),
316 method_cbs: Default::default(),
317 namespaces,
318 name: name.to_owned(),
319 node_managers,
320 samplers: SyncSampler::new(),
321 }
322 }
323
324 fn read_node_value(
325 &self,
326 cbs: &HashMap<NodeId, ReadCB>,
327 context: &RequestContext,
328 address_space: &AddressSpace,
329 node_to_read: &ParsedReadValueId,
330 max_age: f64,
331 timestamps_to_return: TimestampsToReturn,
332 ) -> DataValue {
333 let mut result_value = DataValue::null();
334 let node = match address_space.validate_node_read(context, node_to_read) {
336 Ok(n) => n,
337 Err(e) => {
338 result_value.status = Some(e);
339 return result_value;
340 }
341 };
342
343 if let Some(cb) = cbs.get(&node_to_read.node_id) {
345 match cb(&node_to_read.index_range, timestamps_to_return, max_age) {
346 Err(e) => DataValue {
347 status: Some(e),
348 ..Default::default()
349 },
350 Ok(v) => v,
351 }
352 } else {
353 read_node_value(node, context, node_to_read, max_age, timestamps_to_return)
355 }
356 }
357
358 fn write_node_value(
359 &self,
360 cbs: &HashMap<NodeId, WriteCB>,
361 context: &RequestContext,
362 address_space: &mut AddressSpace,
363 type_tree: &DefaultTypeTree,
364 write: &mut WriteNode,
365 ) {
366 let node = match address_space.validate_node_write(context, write.value(), type_tree) {
367 Ok(v) => v,
368 Err(e) => {
369 write.set_status(e);
370 return;
371 }
372 };
373
374 if node.node_class() != NodeClass::Variable
375 || write.value().attribute_id != AttributeId::Value
376 {
377 write.set_status(StatusCode::BadNotWritable);
378 return;
379 }
380
381 if let Some(cb) = cbs.get(node.as_node().node_id()) {
382 write.set_status(cb(write.value().value.clone(), &write.value().index_range));
384 } else if write.value().value.value.is_some() {
385 match write_node_value(node, write.value()) {
387 Ok(_) => write.set_status(StatusCode::Good),
388 Err(e) => write.set_status(e),
389 }
390 } else {
391 write.set_status(StatusCode::BadNothingToDo);
393 }
394 if write.status().is_good() {
395 if let Some(val) = node.as_mut_node().get_attribute(
396 TimestampsToReturn::Both,
397 write.value().attribute_id,
398 &NumericRange::None,
399 &opcua_types::DataEncoding::Binary,
400 ) {
401 context.subscriptions.notify_data_change(
402 [(val, node.node_id(), write.value().attribute_id)].into_iter(),
403 );
404 }
405 }
406 }
407
408 pub fn add_write_callback(
410 &self,
411 id: NodeId,
412 cb: impl Fn(DataValue, &NumericRange) -> StatusCode + Send + Sync + 'static,
413 ) {
414 let mut cbs = trace_write_lock!(self.write_cbs);
415 cbs.insert(id, Arc::new(cb));
416 }
417
418 pub fn add_read_callback(
420 &self,
421 id: NodeId,
422 cb: impl Fn(&NumericRange, TimestampsToReturn, f64) -> Result<DataValue, StatusCode>
423 + Send
424 + Sync
425 + 'static,
426 ) {
427 let mut cbs = trace_write_lock!(self.read_cbs);
428 cbs.insert(id, Arc::new(cb));
429 }
430
431 pub fn add_method_callback(
433 &self,
434 id: NodeId,
435 cb: impl Fn(&[Variant]) -> Result<Vec<Variant>, StatusCode> + Send + Sync + 'static,
436 ) {
437 let mut cbs = trace_write_lock!(self.method_cbs);
438 cbs.insert(id, Arc::new(cb));
439 }
440}