opcua_server/node_manager/
history.rs1use crate::session::{continuation_points::ContinuationPoint, instance::Session};
2use opcua_crypto::random;
3use opcua_types::{
4 match_extension_object_owned, ByteString, DeleteAtTimeDetails, DeleteEventDetails,
5 DeleteRawModifiedDetails, DynEncodable, ExtensionObject, HistoryData, HistoryEvent,
6 HistoryModifiedData, HistoryReadResult, HistoryReadValueId, HistoryUpdateResult, NodeId,
7 NumericRange, ObjectId, QualifiedName, ReadAnnotationDataDetails, ReadAtTimeDetails,
8 ReadEventDetails, ReadProcessedDetails, ReadRawModifiedDetails, StatusCode, UpdateDataDetails,
9 UpdateEventDetails, UpdateStructureDataDetails,
10};
11
12pub struct HistoryNode {
14 node_id: NodeId,
15 index_range: NumericRange,
16 data_encoding: QualifiedName,
17 input_continuation_point: Option<ContinuationPoint>,
18 next_continuation_point: Option<ContinuationPoint>,
19 result: Option<ExtensionObject>,
20 status: StatusCode,
21}
22
23pub(crate) enum HistoryReadDetails {
24 RawModified(ReadRawModifiedDetails),
25 AtTime(ReadAtTimeDetails),
26 Processed(ReadProcessedDetails),
27 Events(ReadEventDetails),
28 Annotations(ReadAnnotationDataDetails),
29}
30
31impl HistoryReadDetails {
32 pub(crate) fn from_extension_object(obj: ExtensionObject) -> Result<Self, StatusCode> {
33 match_extension_object_owned!(obj,
34 v: ReadRawModifiedDetails => Ok(Self::RawModified(v)),
35 v: ReadAtTimeDetails => Ok(Self::AtTime(v)),
36 v: ReadProcessedDetails => Ok(Self::Processed(v)),
37 v: ReadEventDetails => Ok(Self::Events(v)),
38 v: ReadAnnotationDataDetails => Ok(Self::Annotations(v)),
39 _ => Err(StatusCode::BadHistoryOperationInvalid)
40 )
41 }
42}
43
44#[derive(Debug, Clone)]
46pub enum HistoryUpdateDetails {
47 UpdateData(UpdateDataDetails),
49 UpdateStructureData(UpdateStructureDataDetails),
51 UpdateEvent(UpdateEventDetails),
53 DeleteRawModified(DeleteRawModifiedDetails),
55 DeleteAtTime(DeleteAtTimeDetails),
57 DeleteEvent(DeleteEventDetails),
59}
60
61impl HistoryUpdateDetails {
62 pub fn from_extension_object(obj: ExtensionObject) -> Result<Self, StatusCode> {
64 match_extension_object_owned!(obj,
65 v: UpdateDataDetails => Ok(Self::UpdateData(v)),
66 v: UpdateStructureDataDetails => Ok(Self::UpdateStructureData(v)),
67 v: UpdateEventDetails => Ok(Self::UpdateEvent(v)),
68 v: DeleteRawModifiedDetails => Ok(Self::DeleteRawModified(v)),
69 v: DeleteAtTimeDetails => Ok(Self::DeleteAtTime(v)),
70 v: DeleteEventDetails => Ok(Self::DeleteEvent(v)),
71 _ => Err(StatusCode::BadHistoryOperationInvalid)
72 )
73 }
74
75 pub fn node_id(&self) -> &NodeId {
77 match self {
78 HistoryUpdateDetails::UpdateData(d) => &d.node_id,
79 HistoryUpdateDetails::UpdateStructureData(d) => &d.node_id,
80 HistoryUpdateDetails::UpdateEvent(d) => &d.node_id,
81 HistoryUpdateDetails::DeleteRawModified(d) => &d.node_id,
82 HistoryUpdateDetails::DeleteAtTime(d) => &d.node_id,
83 HistoryUpdateDetails::DeleteEvent(d) => &d.node_id,
84 }
85 }
86}
87
88pub trait HistoryResult: DynEncodable + Sized {
90 fn into_extension_object(self) -> ExtensionObject {
92 ExtensionObject::from_message(self)
93 }
94}
95
96impl HistoryResult for HistoryData {}
97impl HistoryResult for HistoryModifiedData {}
98impl HistoryResult for HistoryEvent {}
99impl HistoryNode {
102 pub(crate) fn new(
103 node: HistoryReadValueId,
104 is_events: bool,
105 cp: Option<ContinuationPoint>,
106 ) -> Self {
107 let mut status = StatusCode::BadNodeIdUnknown;
108
109 if !matches!(node.index_range, NumericRange::None) && is_events {
110 status = StatusCode::BadIndexRangeDataMismatch;
111 }
112
113 Self {
114 node_id: node.node_id,
115 index_range: node.index_range,
116 data_encoding: node.data_encoding,
117 input_continuation_point: cp,
118 next_continuation_point: None,
119 result: None,
120 status,
121 }
122 }
123
124 pub fn node_id(&self) -> &NodeId {
126 &self.node_id
127 }
128
129 pub fn index_range(&self) -> &NumericRange {
131 &self.index_range
132 }
133
134 pub fn data_encoding(&self) -> &QualifiedName {
136 &self.data_encoding
137 }
138
139 pub fn continuation_point(&self) -> Option<&ContinuationPoint> {
141 self.input_continuation_point.as_ref()
142 }
143
144 pub fn next_continuation_point(&self) -> Option<&ContinuationPoint> {
146 self.next_continuation_point.as_ref()
147 }
148
149 pub fn set_next_continuation_point(&mut self, continuation_point: Option<ContinuationPoint>) {
151 self.next_continuation_point = continuation_point;
152 }
153
154 pub fn set_result<T: HistoryResult>(&mut self, result: T) {
156 self.result = Some(result.into_extension_object());
157 }
158
159 pub fn set_status(&mut self, status: StatusCode) {
161 self.status = status;
162 }
163
164 pub fn status(&self) -> StatusCode {
166 self.status
167 }
168
169 pub(crate) fn into_result(mut self, session: &mut Session) -> HistoryReadResult {
170 let cp = match self.next_continuation_point {
171 Some(p) => {
172 let id = random::byte_string(6);
173 if session.add_history_continuation_point(&id, p).is_err() {
174 self.status = StatusCode::BadNoContinuationPoints;
175 ByteString::null()
176 } else {
177 id
178 }
179 }
180 None => ByteString::null(),
181 };
182
183 HistoryReadResult {
184 status_code: self.status,
185 continuation_point: cp,
186 history_data: self.result.unwrap_or_else(ExtensionObject::null),
187 }
188 }
189}
190
191pub struct HistoryUpdateNode {
193 details: HistoryUpdateDetails,
194 status: StatusCode,
195 operation_results: Option<Vec<StatusCode>>,
196}
197
198impl HistoryUpdateNode {
199 pub(crate) fn new(details: HistoryUpdateDetails) -> Self {
200 Self {
201 details,
202 status: StatusCode::BadNodeIdUnknown,
203 operation_results: None,
204 }
205 }
206
207 pub fn set_status(&mut self, status: StatusCode) {
209 self.status = status;
210 }
211
212 pub fn status(&self) -> StatusCode {
214 self.status
215 }
216
217 pub fn set_operation_results(&mut self, operation_results: Option<Vec<StatusCode>>) {
220 self.operation_results = operation_results;
221 }
222
223 pub(crate) fn into_result(mut self) -> HistoryUpdateResult {
224 if self.details.node_id() == &ObjectId::Server
226 && matches!(self.status, StatusCode::BadNodeIdUnknown)
227 {
228 self.status = StatusCode::BadHistoryOperationUnsupported;
229 }
230 HistoryUpdateResult {
231 diagnostic_infos: None,
232 status_code: self.status,
233 operation_results: self.operation_results,
234 }
235 }
236
237 pub fn details(&self) -> &HistoryUpdateDetails {
240 &self.details
241 }
242}