1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162
// OPCUA for Rust
// SPDX-License-Identifier: MPL-2.0
// Copyright (C) 2017-2020 Adam Lock
//! Provides callback traits and concrete implementations that the client can use to register for notifications
//! with the client api.
//!
//! For example, the client must supply an [`OnSubscriptionNotification`] implementation when it calls `Session::create_subscription`.
//! It could implement this trait for itself, or it can use the concrete implementations in [`DataChangeCallback`] and [`EventCallback`].
//!
//! [`DataChangeCallback`]: ./struct.DataChangeCallback.html
//! [`EventCallback`]: ./struct.EventCallback.html
use std::fmt;
use opcua_types::{
service_types::EventNotificationList,
status_code::StatusCode,
};
use crate::subscription::MonitoredItem;
/// The `OnSubscriptionNotification` trait is the callback registered along with a new subscription to
/// receive subscription notification callbacks.
///
/// Unless your subscription contains a mix of items which are monitoring data and events
/// you probably only need to implement either `data_change()`, or `event()` and leave the default,
/// no-op implementation for the other.
///
/// There are concrete implementations of this trait in [`DataChangeCallback`] and [`EventCallback`].
///
/// [`DataChangeCallback`]: ./struct.DataChangeCallback.html
/// [`EventCallback`]: ./struct.EventCallback.html
///
pub trait OnSubscriptionNotification {
/// Called by the subscription after a `DataChangeNotification`. The default implementation
/// does nothing.
fn on_data_change(&mut self, _data_change_items: Vec<&MonitoredItem>) {}
/// Called by the subscription after a `EventNotificationList`. The notifications contained within
/// are individual `EventFieldList` structs filled from the select clause criteria from when the
/// event was constructed. The default implementation does nothing.
fn on_event(&mut self, _events: &EventNotificationList) {}
}
/// The `OnConnectionStatusChange` trait can be used to register on the session to be notified
/// of connection status change notifications.
pub trait OnConnectionStatusChange {
/// Called when the connection status changes from connected to disconnected or vice versa
fn on_connection_status_change(&mut self, connected: bool);
}
/// The `OnSessionClosed` trait can be used to register on a session and called to notify the client
/// that the session has closed.
pub trait OnSessionClosed {
/// Called when the connection closed (in addition to a status change event). The status
/// code should be checked to see if the closure was a graceful terminate (`Good`), or the result
/// of a network or protocol error.
///
/// If no session retry policy has been created for the client session, the server implementation
/// might choose to reconnect in response to a bad status code by itself, however it should
/// avoid retrying too quickly or indefinitely in case the error is permanent.
fn on_session_closed(&mut self, status_code: StatusCode);
}
/// This is a concrete implementation of [`OnSubscriptionNotification`] that calls a function when
/// a data change occurs.
pub struct DataChangeCallback {
/// The actual call back
cb: Box<dyn Fn(Vec<&MonitoredItem>) + Send + Sync + 'static>
}
impl OnSubscriptionNotification for DataChangeCallback {
fn on_data_change(&mut self, data_change_items: Vec<&MonitoredItem>) {
(self.cb)(data_change_items);
}
}
impl DataChangeCallback {
/// Constructs a callback from the supplied function
pub fn new<CB>(cb: CB) -> Self where CB: Fn(Vec<&MonitoredItem>) + Send + Sync + 'static {
Self {
cb: Box::new(cb)
}
}
}
/// This is a concrete implementation of [`OnSubscriptionNotification`] that calls a function
/// when an event occurs.
pub struct EventCallback {
/// The actual call back
cb: Box<dyn Fn(&EventNotificationList) + Send + Sync + 'static>
}
impl OnSubscriptionNotification for EventCallback {
fn on_event(&mut self, events: &EventNotificationList) {
(self.cb)(events);
}
}
impl EventCallback {
/// Constructs a callback from the supplied function
pub fn new<CB>(cb: CB) -> Self where CB: Fn(&EventNotificationList) + Send + Sync + 'static {
Self {
cb: Box::new(cb)
}
}
}
/// This is a concrete implementation of [`OnConnectionStatusChange`] that calls the supplied function.
pub struct ConnectionStatusCallback {
cb: Box<dyn FnMut(bool) + Send + Sync + 'static>,
}
impl fmt::Debug for ConnectionStatusCallback {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "[callback]")
}
}
impl OnConnectionStatusChange for ConnectionStatusCallback {
fn on_connection_status_change(&mut self, connected: bool) {
if connected {
debug!("Received OPC UA connected event");
} else {
debug!("Received OPC UA disconnected event");
}
(self.cb)(connected);
}
}
impl ConnectionStatusCallback {
// Constructor
pub fn new<CB>(cb: CB) -> Self where CB: FnMut(bool) + Send + Sync + 'static {
Self {
cb: Box::new(cb)
}
}
}
/// This is a concrete implementation of `OnSessionClosed` that will call the supplied
/// function.
pub struct SessionClosedCallback {
cb: Box<dyn FnMut(StatusCode) + Send + Sync + 'static>,
}
impl OnSessionClosed for SessionClosedCallback {
fn on_session_closed(&mut self, status_code: StatusCode) {
(self.cb)(status_code);
}
}
impl SessionClosedCallback {
// Constructor
pub fn new<CB>(cb: CB) -> Self where CB: FnMut(StatusCode) + Send + Sync + 'static {
Self {
cb: Box::new(cb)
}
}
}