opcua_client/session/services/
method.rs1use std::time::Duration;
2
3use crate::{
4 session::{
5 process_unexpected_response,
6 request_builder::{builder_base, builder_error, RequestHeaderBuilder},
7 session_error,
8 },
9 AsyncSecureChannel, Session, UARequest,
10};
11use opcua_core::ResponseMessage;
12use opcua_types::{
13 CallMethodRequest, CallMethodResult, CallRequest, CallResponse, Error, IntegerId, MethodId,
14 NodeId, ObjectId, StatusCode, TryFromVariant, Variant,
15};
16use tracing::{debug_span, Instrument};
17
18#[derive(Debug, Clone)]
19pub struct Call {
23 methods: Vec<CallMethodRequest>,
24
25 header: RequestHeaderBuilder,
26}
27
28builder_base!(Call);
29
30impl Call {
31 pub fn new(session: &Session) -> Self {
33 Self {
34 methods: Vec::new(),
35 header: RequestHeaderBuilder::new_from_session(session),
36 }
37 }
38
39 pub fn new_manual(
41 session_id: u32,
42 timeout: Duration,
43 auth_token: NodeId,
44 request_handle: IntegerId,
45 ) -> Self {
46 Self {
47 methods: Vec::new(),
48 header: RequestHeaderBuilder::new(session_id, timeout, auth_token, request_handle),
49 }
50 }
51
52 pub fn methods_to_call(mut self, methods: Vec<CallMethodRequest>) -> Self {
54 self.methods = methods;
55 self
56 }
57
58 pub fn method(mut self, method: impl Into<CallMethodRequest>) -> Self {
60 self.methods.push(method.into());
61 self
62 }
63}
64
65impl UARequest for Call {
66 type Out = CallResponse;
67
68 async fn send<'a>(self, channel: &'a AsyncSecureChannel) -> Result<Self::Out, Error>
69 where
70 Self: 'a,
71 {
72 let span = debug_span!(
73 "Sending Call request",
74 num_method_calls = self.methods.len()
75 );
76 let cnt = self.methods.len();
77 let request = {
78 let _h = span.enter();
79 if self.methods.is_empty() {
80 builder_error!(self, "call(), was not supplied with any methods to call");
81 return Err(Error::new(
82 StatusCode::BadNothingToDo,
83 "call was not supplied with any methods to call",
84 ));
85 }
86
87 CallRequest {
88 request_header: self.header.header,
89 methods_to_call: Some(self.methods),
90 }
91 };
92
93 let response = channel
94 .send(request, self.header.timeout)
95 .instrument(span.clone())
96 .await?;
97 let _h = span.enter();
98 if let ResponseMessage::Call(response) = response {
99 if let Some(results) = &response.results {
100 if results.len() != cnt {
101 builder_error!(
102 self,
103 "call(), expecting {cnt} results from the call to the server, got {} results",
104 results.len()
105 );
106 Err(Error::new(StatusCode::BadUnexpectedError, format!("call(), expecting {cnt} results from the call to the server, got {} results", results.len())))
107 } else {
108 Ok(*response)
109 }
110 } else {
111 builder_error!(
112 self,
113 "call(), expecting a result from the call to the server, got nothing"
114 );
115 Err(Error::new(
116 StatusCode::BadUnexpectedError,
117 "call(), expecting a result from the call to the server, got nothing",
118 ))
119 }
120 } else {
121 Err(process_unexpected_response(response))
122 }
123 }
124}
125
126impl Session {
127 pub async fn call(
141 &self,
142 methods: Vec<CallMethodRequest>,
143 ) -> Result<Vec<CallMethodResult>, Error> {
144 Ok(Call::new(self)
145 .methods_to_call(methods)
146 .send(&self.channel)
147 .await?
148 .results
149 .unwrap_or_default())
150 }
151
152 pub async fn call_one(
168 &self,
169 method: impl Into<CallMethodRequest>,
170 ) -> Result<CallMethodResult, Error> {
171 Ok(self
172 .call(vec![method.into()])
173 .await?
174 .into_iter()
175 .next()
176 .unwrap())
177 }
178
179 pub async fn call_get_monitored_items(
191 &self,
192 subscription_id: u32,
193 ) -> Result<(Vec<u32>, Vec<u32>), Error> {
194 let args = Some(vec![Variant::from(subscription_id)]);
195 let object_id: NodeId = ObjectId::Server.into();
196 let method_id: NodeId = MethodId::Server_GetMonitoredItems.into();
197 let request: CallMethodRequest = (object_id, method_id, args).into();
198 let response = self.call_one(request).await?;
199 if let Some(mut result) = response.output_arguments {
200 if result.len() == 2 {
201 let server_handles = <Vec<u32>>::try_from_variant(result.remove(0))?;
202 let client_handles = <Vec<u32>>::try_from_variant(result.remove(0))?;
203 Ok((server_handles, client_handles))
204 } else {
205 session_error!(
206 self,
207 "Expected a result with 2 args but got {}",
208 result.len()
209 );
210 Err(Error::new(
211 StatusCode::BadUnexpectedError,
212 format!("Expected a result with 2 args but got {}", result.len()),
213 ))
214 }
215 } else {
216 session_error!(self, "Expected 2 output arguments but got null");
217 Err(Error::new(
218 StatusCode::BadUnexpectedError,
219 "Expected 2 output arguments but got null",
220 ))
221 }
222 }
223}