1use std::time::Duration;
2
3use crate::{
4 session::{
5 process_service_result, process_unexpected_response,
6 request_builder::{
7 builder_base, builder_debug, builder_error, builder_trace, RequestHeaderBuilder,
8 },
9 UARequest,
10 },
11 AsyncSecureChannel, Session,
12};
13use opcua_core::ResponseMessage;
14use opcua_types::{
15 DataValue, DeleteAtTimeDetails, DeleteEventDetails, DeleteRawModifiedDetails, Error,
16 ExtensionObject, HistoryReadRequest, HistoryReadResponse, HistoryReadResult,
17 HistoryReadValueId, HistoryUpdateRequest, HistoryUpdateResponse, HistoryUpdateResult,
18 IntegerId, NodeId, ReadAtTimeDetails, ReadEventDetails, ReadProcessedDetails,
19 ReadRawModifiedDetails, ReadRequest, ReadResponse, ReadValueId, StatusCode, TimestampsToReturn,
20 UpdateDataDetails, UpdateEventDetails, UpdateStructureDataDetails, WriteRequest, WriteResponse,
21 WriteValue,
22};
23use tracing::{debug_span, Instrument};
24
25#[derive(Debug, Clone)]
27pub enum HistoryReadAction {
28 ReadEventDetails(ReadEventDetails),
30 ReadRawModifiedDetails(ReadRawModifiedDetails),
32 ReadProcessedDetails(ReadProcessedDetails),
34 ReadAtTimeDetails(ReadAtTimeDetails),
36}
37
38impl From<HistoryReadAction> for ExtensionObject {
39 fn from(action: HistoryReadAction) -> Self {
40 match action {
41 HistoryReadAction::ReadEventDetails(v) => Self::from_message(v),
42 HistoryReadAction::ReadRawModifiedDetails(v) => Self::from_message(v),
43 HistoryReadAction::ReadProcessedDetails(v) => Self::from_message(v),
44 HistoryReadAction::ReadAtTimeDetails(v) => Self::from_message(v),
45 }
46 }
47}
48
49#[derive(Debug, Clone)]
51pub enum HistoryUpdateAction {
52 UpdateDataDetails(UpdateDataDetails),
54 UpdateStructureDataDetails(UpdateStructureDataDetails),
56 UpdateEventDetails(UpdateEventDetails),
58 DeleteRawModifiedDetails(DeleteRawModifiedDetails),
60 DeleteAtTimeDetails(DeleteAtTimeDetails),
62 DeleteEventDetails(DeleteEventDetails),
64}
65
66impl From<UpdateDataDetails> for HistoryUpdateAction {
67 fn from(value: UpdateDataDetails) -> Self {
68 Self::UpdateDataDetails(value)
69 }
70}
71impl From<UpdateStructureDataDetails> for HistoryUpdateAction {
72 fn from(value: UpdateStructureDataDetails) -> Self {
73 Self::UpdateStructureDataDetails(value)
74 }
75}
76impl From<UpdateEventDetails> for HistoryUpdateAction {
77 fn from(value: UpdateEventDetails) -> Self {
78 Self::UpdateEventDetails(value)
79 }
80}
81impl From<DeleteRawModifiedDetails> for HistoryUpdateAction {
82 fn from(value: DeleteRawModifiedDetails) -> Self {
83 Self::DeleteRawModifiedDetails(value)
84 }
85}
86impl From<DeleteAtTimeDetails> for HistoryUpdateAction {
87 fn from(value: DeleteAtTimeDetails) -> Self {
88 Self::DeleteAtTimeDetails(value)
89 }
90}
91impl From<DeleteEventDetails> for HistoryUpdateAction {
92 fn from(value: DeleteEventDetails) -> Self {
93 Self::DeleteEventDetails(value)
94 }
95}
96
97impl From<HistoryUpdateAction> for ExtensionObject {
98 fn from(action: HistoryUpdateAction) -> Self {
99 match action {
100 HistoryUpdateAction::UpdateDataDetails(v) => Self::from_message(v),
101 HistoryUpdateAction::UpdateStructureDataDetails(v) => Self::from_message(v),
102 HistoryUpdateAction::UpdateEventDetails(v) => Self::from_message(v),
103 HistoryUpdateAction::DeleteRawModifiedDetails(v) => Self::from_message(v),
104 HistoryUpdateAction::DeleteAtTimeDetails(v) => Self::from_message(v),
105 HistoryUpdateAction::DeleteEventDetails(v) => Self::from_message(v),
106 }
107 }
108}
109
110#[derive(Debug, Clone)]
114pub struct Read {
115 nodes_to_read: Vec<ReadValueId>,
116 timestamps_to_return: TimestampsToReturn,
117 max_age: f64,
118
119 header: RequestHeaderBuilder,
120}
121
122impl Read {
123 pub fn new(session: &Session) -> Self {
125 Self {
126 nodes_to_read: Vec::new(),
127 timestamps_to_return: TimestampsToReturn::Neither,
128 max_age: 0.0,
129 header: RequestHeaderBuilder::new_from_session(session),
130 }
131 }
132
133 pub fn new_manual(
135 session_id: u32,
136 timeout: Duration,
137 auth_token: NodeId,
138 request_handle: IntegerId,
139 ) -> Self {
140 Self {
141 nodes_to_read: Vec::new(),
142 timestamps_to_return: TimestampsToReturn::Neither,
143 max_age: 0.0,
144 header: RequestHeaderBuilder::new(session_id, timeout, auth_token, request_handle),
145 }
146 }
147
148 pub fn timestamps_to_return(mut self, timestamps: TimestampsToReturn) -> Self {
150 self.timestamps_to_return = timestamps;
151 self
152 }
153
154 pub fn max_age(mut self, max_age: f64) -> Self {
156 self.max_age = max_age;
157 self
158 }
159
160 pub fn nodes_to_read(mut self, nodes_to_read: Vec<ReadValueId>) -> Self {
162 self.nodes_to_read = nodes_to_read;
163 self
164 }
165
166 pub fn node(mut self, node: ReadValueId) -> Self {
168 self.nodes_to_read.push(node);
169 self
170 }
171}
172
173builder_base!(Read);
174
175impl UARequest for Read {
176 type Out = ReadResponse;
177
178 async fn send<'b>(self, channel: &'b AsyncSecureChannel) -> Result<Self::Out, Error>
179 where
180 Self: 'b,
181 {
182 let span = debug_span!(
183 "Sending Read request",
184 nodes_to_read = self.nodes_to_read.len(),
185 timestamps_to_return = ?self.timestamps_to_return,
186 max_age = self.max_age
187 );
188 let request = {
189 let _h = span.enter();
190 if self.nodes_to_read.is_empty() {
191 builder_error!(self, "read(), was not supplied with any nodes to read");
192 return Err(Error::new(
193 StatusCode::BadNothingToDo,
194 "read was not supplied with any nodes to read",
195 ));
196 }
197 ReadRequest {
198 request_header: self.header.header,
199 max_age: self.max_age,
200 timestamps_to_return: self.timestamps_to_return,
201 nodes_to_read: Some(self.nodes_to_read),
202 }
203 };
204
205 let response = channel
206 .send(request, self.header.timeout)
207 .instrument(span.clone())
208 .await?;
209
210 let _h = span.enter();
211 if let ResponseMessage::Read(response) = response {
212 builder_debug!(self, "read(), success");
213 process_service_result(&response.response_header)?;
214 Ok(*response)
215 } else {
216 builder_error!(self, "read() value failed");
217 Err(process_unexpected_response(response))
218 }
219 }
220}
221
222#[derive(Debug, Clone)]
223pub struct HistoryRead {
233 details: HistoryReadAction,
234 timestamps_to_return: TimestampsToReturn,
235 release_continuation_points: bool,
236 nodes_to_read: Vec<HistoryReadValueId>,
237
238 header: RequestHeaderBuilder,
239}
240
241builder_base!(HistoryRead);
242
243impl HistoryRead {
244 pub fn new(details: HistoryReadAction, session: &Session) -> Self {
246 Self {
247 details,
248 timestamps_to_return: TimestampsToReturn::Neither,
249 release_continuation_points: false,
250 nodes_to_read: Vec::new(),
251
252 header: RequestHeaderBuilder::new_from_session(session),
253 }
254 }
255
256 pub fn new_manual(
258 details: HistoryReadAction,
259 session_id: u32,
260 timeout: Duration,
261 auth_token: NodeId,
262 request_handle: IntegerId,
263 ) -> Self {
264 Self {
265 details,
266 timestamps_to_return: TimestampsToReturn::Neither,
267 release_continuation_points: false,
268 nodes_to_read: Vec::new(),
269 header: RequestHeaderBuilder::new(session_id, timeout, auth_token, request_handle),
270 }
271 }
272
273 pub fn timestamps_to_return(mut self, timestamps: TimestampsToReturn) -> Self {
275 self.timestamps_to_return = timestamps;
276 self
277 }
278
279 pub fn release_continuation_points(mut self, release_continuation_points: bool) -> Self {
283 self.release_continuation_points = release_continuation_points;
284 self
285 }
286
287 pub fn nodes_to_read(mut self, nodes_to_read: Vec<HistoryReadValueId>) -> Self {
289 self.nodes_to_read = nodes_to_read;
290 self
291 }
292
293 pub fn node(mut self, node: HistoryReadValueId) -> Self {
295 self.nodes_to_read.push(node);
296 self
297 }
298}
299
300impl UARequest for HistoryRead {
301 type Out = HistoryReadResponse;
302
303 async fn send<'b>(self, channel: &'b AsyncSecureChannel) -> Result<Self::Out, Error>
304 where
305 Self: 'b,
306 {
307 let span = debug_span!(
308 "Sending HistoryRead request",
309 details = ?self.details,
310 timestamps_to_return = ?self.timestamps_to_return,
311 release_continuation_points = self.release_continuation_points,
312 num_nodes_to_read = self.nodes_to_read.len()
313 );
314 let request = {
315 let _h = span.enter();
316 let history_read_details = ExtensionObject::from(self.details);
317 builder_trace!(
318 self,
319 "history_read() requested to read nodes {:?}",
320 self.nodes_to_read
321 );
322 HistoryReadRequest {
323 request_header: self.header.header,
324 history_read_details,
325 timestamps_to_return: self.timestamps_to_return,
326 release_continuation_points: self.release_continuation_points,
327 nodes_to_read: if self.nodes_to_read.is_empty() {
328 None
329 } else {
330 Some(self.nodes_to_read)
331 },
332 }
333 };
334
335 let response = channel
336 .send(request, self.header.timeout)
337 .instrument(span.clone())
338 .await?;
339 let _h = span.enter();
340 if let ResponseMessage::HistoryRead(response) = response {
341 builder_debug!(self, "history_read(), success");
342 process_service_result(&response.response_header)?;
343 Ok(*response)
344 } else {
345 builder_error!(self, "history_read() value failed");
346 Err(process_unexpected_response(response))
347 }
348 }
349}
350
351#[derive(Debug, Clone)]
352pub struct Write {
357 nodes_to_write: Vec<WriteValue>,
358
359 header: RequestHeaderBuilder,
360}
361
362builder_base!(Write);
363
364impl Write {
365 pub fn new(session: &Session) -> Self {
367 Self {
368 nodes_to_write: Vec::new(),
369 header: RequestHeaderBuilder::new_from_session(session),
370 }
371 }
372
373 pub fn new_manual(
375 session_id: u32,
376 timeout: Duration,
377 auth_token: NodeId,
378 request_handle: IntegerId,
379 ) -> Self {
380 Self {
381 nodes_to_write: Vec::new(),
382 header: RequestHeaderBuilder::new(session_id, timeout, auth_token, request_handle),
383 }
384 }
385
386 pub fn nodes_to_write(mut self, nodes_to_write: Vec<WriteValue>) -> Self {
388 self.nodes_to_write = nodes_to_write;
389 self
390 }
391
392 pub fn node(mut self, node: impl Into<WriteValue>) -> Self {
394 self.nodes_to_write.push(node.into());
395 self
396 }
397}
398
399impl UARequest for Write {
400 type Out = WriteResponse;
401
402 async fn send<'a>(self, channel: &'a AsyncSecureChannel) -> Result<Self::Out, Error>
403 where
404 Self: 'a,
405 {
406 let span = debug_span!(
407 "Sending Write request",
408 num_nodes_to_write = self.nodes_to_write.len()
409 );
410 let request = {
411 let _h = span.enter();
412 if self.nodes_to_write.is_empty() {
413 builder_error!(self, "write(), was not supplied with any nodes to write");
414 return Err(Error::new(
415 StatusCode::BadNothingToDo,
416 "write was not supplied with any nodes to write",
417 ));
418 }
419 WriteRequest {
420 request_header: self.header.header,
421 nodes_to_write: Some(self.nodes_to_write),
422 }
423 };
424 let response = channel
425 .send(request, self.header.timeout)
426 .instrument(span.clone())
427 .await?;
428 let _h = span.enter();
429 if let ResponseMessage::Write(response) = response {
430 builder_debug!(self, "write(), success");
431 process_service_result(&response.response_header)?;
432 Ok(*response)
433 } else {
434 builder_error!(self, "write() failed {:?}", response);
435 Err(process_unexpected_response(response))
436 }
437 }
438}
439
440#[derive(Debug, Clone)]
441pub struct HistoryUpdate {
453 details: Vec<HistoryUpdateAction>,
454
455 header: RequestHeaderBuilder,
456}
457
458builder_base!(HistoryUpdate);
459
460impl HistoryUpdate {
461 pub fn new(session: &Session) -> Self {
463 Self {
464 details: Vec::new(),
465
466 header: RequestHeaderBuilder::new_from_session(session),
467 }
468 }
469
470 pub fn new_manual(
472 session_id: u32,
473 timeout: Duration,
474 auth_token: NodeId,
475 request_handle: IntegerId,
476 ) -> Self {
477 Self {
478 details: Vec::new(),
479 header: RequestHeaderBuilder::new(session_id, timeout, auth_token, request_handle),
480 }
481 }
482
483 pub fn details(mut self, details: Vec<HistoryUpdateAction>) -> Self {
485 self.details = details;
486 self
487 }
488
489 pub fn action(mut self, action: impl Into<HistoryUpdateAction>) -> Self {
491 self.details.push(action.into());
492 self
493 }
494}
495
496impl UARequest for HistoryUpdate {
497 type Out = HistoryUpdateResponse;
498
499 async fn send<'a>(self, channel: &'a AsyncSecureChannel) -> Result<Self::Out, Error>
500 where
501 Self: 'a,
502 {
503 let span = debug_span!(
504 "Sending HistoryUpdate request",
505 num_details = self.details.len()
506 );
507 let request = {
508 let _h = span.enter();
509 if self.details.is_empty() {
510 builder_error!(
511 self,
512 "history_update(), was not supplied with any detail to update"
513 );
514 return Err(Error::new(
515 StatusCode::BadNothingToDo,
516 "history update was not supplied with any update details",
517 ));
518 }
519 let details = self
520 .details
521 .into_iter()
522 .map(ExtensionObject::from)
523 .collect();
524 HistoryUpdateRequest {
525 request_header: self.header.header,
526 history_update_details: Some(details),
527 }
528 };
529
530 let response = channel
531 .send(request, self.header.timeout)
532 .instrument(span.clone())
533 .await?;
534 let _h = span.enter();
535 if let ResponseMessage::HistoryUpdate(response) = response {
536 builder_error!(self, "history_update(), success");
537 process_service_result(&response.response_header)?;
538 Ok(*response)
539 } else {
540 builder_error!(self, "history_update() failed {:?}", response);
541 Err(process_unexpected_response(response))
542 }
543 }
544}
545
546impl Session {
547 pub async fn read(
566 &self,
567 nodes_to_read: &[ReadValueId],
568 timestamps_to_return: TimestampsToReturn,
569 max_age: f64,
570 ) -> Result<Vec<DataValue>, Error> {
571 Ok(Read::new(self)
572 .nodes_to_read(nodes_to_read.to_vec())
573 .timestamps_to_return(timestamps_to_return)
574 .max_age(max_age)
575 .send(&self.channel)
576 .await?
577 .results
578 .unwrap_or_default())
579 }
580
581 pub async fn history_read(
604 &self,
605 history_read_details: HistoryReadAction,
606 timestamps_to_return: TimestampsToReturn,
607 release_continuation_points: bool,
608 nodes_to_read: &[HistoryReadValueId],
609 ) -> Result<Vec<HistoryReadResult>, Error> {
610 Ok(HistoryRead::new(history_read_details, self)
611 .timestamps_to_return(timestamps_to_return)
612 .release_continuation_points(release_continuation_points)
613 .nodes_to_read(nodes_to_read.to_vec())
614 .send(&self.channel)
615 .await?
616 .results
617 .unwrap_or_default())
618 }
619
620 pub async fn write(&self, nodes_to_write: &[WriteValue]) -> Result<Vec<StatusCode>, Error> {
635 Ok(Write::new(self)
636 .nodes_to_write(nodes_to_write.to_vec())
637 .send(&self.channel)
638 .await?
639 .results
640 .unwrap_or_default())
641 }
642
643 pub async fn history_update(
665 &self,
666 history_update_details: &[HistoryUpdateAction],
667 ) -> Result<Vec<HistoryUpdateResult>, Error> {
668 Ok(HistoryUpdate::new(self)
669 .details(history_update_details.to_vec())
670 .send(&self.channel)
671 .await?
672 .results
673 .unwrap_or_default())
674 }
675}