1use std::{self, fmt};
2
3use tracing::error;
4
5use crate::{
6 argument::Argument,
7 attribute::AttributeId,
8 byte_string::ByteString,
9 constants,
10 localized_text::LocalizedText,
11 node_id::NodeId,
12 profiles,
13 qualified_name::QualifiedName,
14 response_header::{AsRequestHandle, ResponseHeader},
15 status_code::StatusCode,
16 string::UAString,
17 variant::Variant,
18 AnonymousIdentityToken, ApplicationDescription, CallMethodRequest, DataTypeId, DataValue,
19 EndpointDescription, Error, ExpandedNodeId, HistoryUpdateType, IdentityCriteriaType,
20 MessageSecurityMode, MonitoredItemCreateRequest, MonitoringMode, MonitoringParameters,
21 NumericRange, ObjectId, ReadValueId, ServiceCounterDataType, ServiceFault, SignatureData,
22 UserNameIdentityToken, UserTokenPolicy, UserTokenType, WriteValue,
23};
24
25use super::PerformUpdateType;
26
27pub trait MessageInfo {
29 fn type_id(&self) -> ObjectId;
31 fn json_type_id(&self) -> ObjectId;
33 fn xml_type_id(&self) -> ObjectId;
35 fn data_type_id(&self) -> DataTypeId;
37}
38
39pub trait ExpandedMessageInfo {
41 fn full_type_id(&self) -> ExpandedNodeId;
43 fn full_json_type_id(&self) -> ExpandedNodeId;
45 fn full_xml_type_id(&self) -> ExpandedNodeId;
47 fn full_data_type_id(&self) -> ExpandedNodeId;
49}
50
51impl<T> ExpandedMessageInfo for T
52where
53 T: MessageInfo,
54{
55 fn full_type_id(&self) -> ExpandedNodeId {
56 self.type_id().into()
57 }
58
59 fn full_json_type_id(&self) -> ExpandedNodeId {
60 self.json_type_id().into()
61 }
62
63 fn full_xml_type_id(&self) -> ExpandedNodeId {
64 self.xml_type_id().into()
65 }
66
67 fn full_data_type_id(&self) -> ExpandedNodeId {
68 self.data_type_id().into()
69 }
70}
71
72impl ServiceFault {
73 pub fn new(request_header: impl AsRequestHandle, service_result: StatusCode) -> ServiceFault {
75 ServiceFault {
76 response_header: ResponseHeader::new_service_result(request_header, service_result),
77 }
78 }
79}
80
81impl UserTokenPolicy {
82 pub fn anonymous() -> UserTokenPolicy {
84 UserTokenPolicy {
85 policy_id: UAString::from("anonymous"),
86 token_type: UserTokenType::Anonymous,
87 issued_token_type: UAString::null(),
88 issuer_endpoint_url: UAString::null(),
89 security_policy_uri: UAString::null(),
90 }
91 }
92}
93
94impl EndpointDescription {
95 pub fn find_policy(&self, token_type: UserTokenType) -> Option<&UserTokenPolicy> {
97 if let Some(ref policies) = self.user_identity_tokens {
98 policies.iter().find(|t| t.token_type == token_type)
99 } else {
100 None
101 }
102 }
103
104 pub fn find_policy_by_id(&self, policy_id: &str) -> Option<&UserTokenPolicy> {
106 if let Some(ref policies) = self.user_identity_tokens {
107 policies.iter().find(|t| t.policy_id.as_ref() == policy_id)
108 } else {
109 None
110 }
111 }
112}
113
114impl UserNameIdentityToken {
115 pub fn is_valid(&self) -> bool {
117 !self.user_name.is_null() && !self.password.is_null()
118 }
119
120 pub fn plaintext_password(&self) -> Result<String, Error> {
122 if !self.encryption_algorithm.is_empty() {
123 return Err(Error::new(
125 StatusCode::BadSecurityChecksFailed,
126 "Password is encrypted",
127 ));
128 }
129 String::from_utf8(self.password.as_ref().to_vec())
130 .map_err(|e| Error::new(StatusCode::BadSecurityChecksFailed, e))
131 }
132}
133
134impl<'a> From<&'a NodeId> for ReadValueId {
135 fn from(node_id: &'a NodeId) -> Self {
136 Self::from(node_id.clone())
137 }
138}
139
140impl From<NodeId> for ReadValueId {
141 fn from(node_id: NodeId) -> Self {
142 ReadValueId {
143 node_id,
144 attribute_id: AttributeId::Value as u32,
145 index_range: NumericRange::None,
146 data_encoding: QualifiedName::null(),
147 }
148 }
149}
150
151impl<'a> From<(u16, &'a str)> for ReadValueId {
152 fn from(v: (u16, &'a str)) -> Self {
153 Self::from(NodeId::from(v))
154 }
155}
156
157impl ReadValueId {
158 pub fn new(node_id: NodeId, attribute_id: AttributeId) -> Self {
160 Self {
161 node_id,
162 attribute_id: attribute_id as u32,
163 ..Default::default()
164 }
165 }
166
167 pub fn new_value(node_id: NodeId) -> Self {
169 Self {
170 node_id,
171 attribute_id: AttributeId::Value as u32,
172 ..Default::default()
173 }
174 }
175}
176
177impl Default for AnonymousIdentityToken {
178 fn default() -> Self {
179 AnonymousIdentityToken {
180 policy_id: UAString::from(profiles::SECURITY_USER_TOKEN_POLICY_ANONYMOUS),
181 }
182 }
183}
184
185impl SignatureData {
186 pub fn null() -> SignatureData {
188 SignatureData {
189 algorithm: UAString::null(),
190 signature: ByteString::null(),
191 }
192 }
193}
194
195impl From<NodeId> for MonitoredItemCreateRequest {
196 fn from(value: NodeId) -> Self {
197 Self::new(
198 value.into(),
199 MonitoringMode::Reporting,
200 MonitoringParameters::default(),
201 )
202 }
203}
204
205impl MonitoredItemCreateRequest {
206 pub fn new(
208 item_to_monitor: ReadValueId,
209 monitoring_mode: MonitoringMode,
210 requested_parameters: MonitoringParameters,
211 ) -> MonitoredItemCreateRequest {
212 MonitoredItemCreateRequest {
213 item_to_monitor,
214 monitoring_mode,
215 requested_parameters,
216 }
217 }
218}
219
220impl From<(NodeId, NodeId, Option<Vec<Variant>>)> for CallMethodRequest {
221 fn from(value: (NodeId, NodeId, Option<Vec<Variant>>)) -> Self {
222 Self {
223 object_id: value.0,
224 method_id: value.1,
225 input_arguments: value.2,
226 }
227 }
228}
229
230impl<'a> From<&'a str> for EndpointDescription {
231 fn from(v: &'a str) -> Self {
232 EndpointDescription::from((
233 v,
234 constants::SECURITY_POLICY_NONE_URI,
235 MessageSecurityMode::None,
236 ))
237 }
238}
239
240impl<'a> From<(&'a str, &'a str, MessageSecurityMode)> for EndpointDescription {
241 fn from(v: (&'a str, &'a str, MessageSecurityMode)) -> Self {
242 EndpointDescription::from((v.0, v.1, v.2, None))
243 }
244}
245
246impl<'a> From<(&'a str, &'a str, MessageSecurityMode, UserTokenPolicy)> for EndpointDescription {
247 fn from(v: (&'a str, &'a str, MessageSecurityMode, UserTokenPolicy)) -> Self {
248 EndpointDescription::from((v.0, v.1, v.2, Some(vec![v.3])))
249 }
250}
251
252impl<'a> From<(&'a str, &'a str, MessageSecurityMode, Vec<UserTokenPolicy>)>
253 for EndpointDescription
254{
255 fn from(v: (&'a str, &'a str, MessageSecurityMode, Vec<UserTokenPolicy>)) -> Self {
256 EndpointDescription::from((v.0, v.1, v.2, Some(v.3)))
257 }
258}
259
260impl<'a>
261 From<(
262 &'a str,
263 &'a str,
264 MessageSecurityMode,
265 Option<Vec<UserTokenPolicy>>,
266 )> for EndpointDescription
267{
268 fn from(
269 v: (
270 &'a str,
271 &'a str,
272 MessageSecurityMode,
273 Option<Vec<UserTokenPolicy>>,
274 ),
275 ) -> Self {
276 EndpointDescription {
277 endpoint_url: UAString::from(v.0),
278 security_policy_uri: UAString::from(v.1),
279 security_mode: v.2,
280 server: ApplicationDescription::default(),
281 security_level: 0,
282 server_certificate: ByteString::null(),
283 transport_profile_uri: UAString::null(),
284 user_identity_tokens: v.3,
285 }
286 }
287}
288
289impl From<String> for EndpointDescription {
290 fn from(v: String) -> Self {
291 EndpointDescription::from(v.as_str())
292 }
293}
294
295const MESSAGE_SECURITY_MODE_NONE: &str = "None";
296const MESSAGE_SECURITY_MODE_SIGN: &str = "Sign";
297const MESSAGE_SECURITY_MODE_SIGN_AND_ENCRYPT: &str = "SignAndEncrypt";
298
299impl fmt::Display for MessageSecurityMode {
300 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
301 let name = match self {
302 MessageSecurityMode::None => MESSAGE_SECURITY_MODE_NONE,
303 MessageSecurityMode::Sign => MESSAGE_SECURITY_MODE_SIGN,
304 MessageSecurityMode::SignAndEncrypt => MESSAGE_SECURITY_MODE_SIGN_AND_ENCRYPT,
305 _ => "",
306 };
307 write!(f, "{name}")
308 }
309}
310
311impl From<MessageSecurityMode> for String {
312 fn from(security_mode: MessageSecurityMode) -> Self {
313 security_mode.to_string()
314 }
315}
316
317impl<'a> From<&'a str> for MessageSecurityMode {
318 fn from(str: &'a str) -> Self {
319 match str {
320 MESSAGE_SECURITY_MODE_NONE => MessageSecurityMode::None,
321 MESSAGE_SECURITY_MODE_SIGN => MessageSecurityMode::Sign,
322 MESSAGE_SECURITY_MODE_SIGN_AND_ENCRYPT => MessageSecurityMode::SignAndEncrypt,
323 _ => {
324 error!("Specified security mode \"{}\" is not recognized", str);
325 MessageSecurityMode::Invalid
326 }
327 }
328 }
329}
330
331impl From<(&str, DataTypeId)> for Argument {
332 fn from(v: (&str, DataTypeId)) -> Self {
333 Argument {
334 name: UAString::from(v.0),
335 data_type: v.1.into(),
336 value_rank: -1,
337 array_dimensions: None,
338 description: LocalizedText::null(),
339 }
340 }
341}
342
343impl ServiceCounterDataType {
344 pub fn success(&mut self) {
346 self.total_count += 1;
347 }
348
349 pub fn error(&mut self) {
351 self.total_count += 1;
352 self.error_count += 1;
353 }
354}
355
356#[allow(clippy::derivable_impls, reason = "This is for generated code")]
357impl Default for PerformUpdateType {
358 fn default() -> Self {
359 Self::Insert
360 }
361}
362
363#[allow(clippy::derivable_impls, reason = "This is for generated code")]
364impl Default for HistoryUpdateType {
365 fn default() -> Self {
366 Self::Insert
367 }
368}
369
370#[allow(clippy::derivable_impls, reason = "This is for generated code")]
371impl Default for IdentityCriteriaType {
372 fn default() -> Self {
373 Self::Anonymous
374 }
375}
376
377impl WriteValue {
378 pub fn new(
380 node_id: NodeId,
381 attribute_id: AttributeId,
382 index_range: NumericRange,
383 value: DataValue,
384 ) -> Self {
385 Self {
386 node_id,
387 attribute_id: attribute_id as u32,
388 index_range,
389 value,
390 }
391 }
392
393 pub fn value_attr(node_id: NodeId, val: Variant) -> Self {
396 Self {
397 node_id,
398 attribute_id: AttributeId::Value as u32,
399 index_range: NumericRange::None,
400 value: val.into(),
401 }
402 }
403}