1use alloc::string::String;
11use alloc::vec::Vec;
12
13use zerodds_opcua_gateway::data_value::{DataValue, ExtensionObject, ExtensionObjectBody, Variant};
14use zerodds_opcua_gateway::node_id::{ExpandedNodeId, NodeId};
15use zerodds_opcua_gateway::types::{LocalizedText, QualifiedName};
16use zerodds_opcua_pubsub::uadp::datatypes::{ApplicationDescription, EndpointDescription};
17use zerodds_opcua_pubsub::{DecodeError, EncodeError, UaDecode, UaEncode, UaReader, UaWriter};
18
19use zerodds_opcua_uacp::securechannel::node_ids;
20use zerodds_opcua_uacp::securechannel::{RequestHeader, ResponseHeader, null_extension_object};
21
22use crate::wire::{
23 read_array, read_byte_string, read_string, read_string_array, read_u32_array,
24 skip_diagnostic_info_array, write_array, write_byte_string, write_empty_diagnostic_info_array,
25 write_string, write_string_array, write_u32_array,
26};
27
28pub const ATTRIBUTE_VALUE: u32 = 13;
30
31#[derive(Debug, Clone, PartialEq, Eq, Default)]
37pub struct SignatureData {
38 pub algorithm: String,
40 pub signature: Vec<u8>,
42}
43
44impl UaEncode for SignatureData {
45 fn encode(&self, w: &mut UaWriter) -> Result<(), EncodeError> {
46 write_string(w, &self.algorithm)?;
47 write_byte_string(w, &self.signature)?;
48 Ok(())
49 }
50}
51
52impl UaDecode for SignatureData {
53 fn decode(r: &mut UaReader<'_>) -> Result<Self, DecodeError> {
54 Ok(Self {
55 algorithm: read_string(r)?,
56 signature: read_byte_string(r)?,
57 })
58 }
59}
60
61#[derive(Debug, Clone, PartialEq)]
63pub struct ReadValueId {
64 pub node_id: NodeId,
66 pub attribute_id: u32,
68 pub index_range: String,
70 pub data_encoding: QualifiedName,
72}
73
74impl UaEncode for ReadValueId {
75 fn encode(&self, w: &mut UaWriter) -> Result<(), EncodeError> {
76 self.node_id.encode(w)?;
77 w.write_u32(self.attribute_id);
78 write_string(w, &self.index_range)?;
79 self.data_encoding.encode(w)?;
80 Ok(())
81 }
82}
83
84impl UaDecode for ReadValueId {
85 fn decode(r: &mut UaReader<'_>) -> Result<Self, DecodeError> {
86 Ok(Self {
87 node_id: NodeId::decode(r)?,
88 attribute_id: r.read_u32()?,
89 index_range: read_string(r)?,
90 data_encoding: QualifiedName::decode(r)?,
91 })
92 }
93}
94
95#[derive(Debug, Clone, PartialEq)]
97pub struct WriteValue {
98 pub node_id: NodeId,
100 pub attribute_id: u32,
102 pub index_range: String,
104 pub value: DataValue,
106}
107
108impl UaEncode for WriteValue {
109 fn encode(&self, w: &mut UaWriter) -> Result<(), EncodeError> {
110 self.node_id.encode(w)?;
111 w.write_u32(self.attribute_id);
112 write_string(w, &self.index_range)?;
113 self.value.encode(w)?;
114 Ok(())
115 }
116}
117
118impl UaDecode for WriteValue {
119 fn decode(r: &mut UaReader<'_>) -> Result<Self, DecodeError> {
120 Ok(Self {
121 node_id: NodeId::decode(r)?,
122 attribute_id: r.read_u32()?,
123 index_range: read_string(r)?,
124 value: DataValue::decode(r)?,
125 })
126 }
127}
128
129#[derive(Debug, Clone, PartialEq)]
131pub struct CallMethodRequest {
132 pub object_id: NodeId,
134 pub method_id: NodeId,
136 pub input_arguments: Vec<Variant>,
138}
139
140impl UaEncode for CallMethodRequest {
141 fn encode(&self, w: &mut UaWriter) -> Result<(), EncodeError> {
142 self.object_id.encode(w)?;
143 self.method_id.encode(w)?;
144 write_array(w, &self.input_arguments, "InputArguments")?;
145 Ok(())
146 }
147}
148
149impl UaDecode for CallMethodRequest {
150 fn decode(r: &mut UaReader<'_>) -> Result<Self, DecodeError> {
151 Ok(Self {
152 object_id: NodeId::decode(r)?,
153 method_id: NodeId::decode(r)?,
154 input_arguments: read_array::<Variant>(r)?,
155 })
156 }
157}
158
159#[derive(Debug, Clone, PartialEq)]
161pub struct CallMethodResult {
162 pub status_code: u32,
164 pub input_argument_results: Vec<u32>,
166 pub output_arguments: Vec<Variant>,
168}
169
170impl UaEncode for CallMethodResult {
171 fn encode(&self, w: &mut UaWriter) -> Result<(), EncodeError> {
172 w.write_u32(self.status_code);
173 write_u32_array(w, &self.input_argument_results)?;
174 write_empty_diagnostic_info_array(w); write_array(w, &self.output_arguments, "OutputArguments")?;
176 Ok(())
177 }
178}
179
180impl UaDecode for CallMethodResult {
181 fn decode(r: &mut UaReader<'_>) -> Result<Self, DecodeError> {
182 let status_code = r.read_u32()?;
183 let input_argument_results = read_u32_array(r)?;
184 skip_diagnostic_info_array(r)?;
185 let output_arguments = read_array::<Variant>(r)?;
186 Ok(Self {
187 status_code,
188 input_argument_results,
189 output_arguments,
190 })
191 }
192}
193
194#[derive(Debug, Clone, PartialEq)]
200pub struct CreateSessionRequest {
201 pub request_header: RequestHeader,
203 pub client_description: ApplicationDescription,
205 pub server_uri: String,
207 pub endpoint_url: String,
209 pub session_name: String,
211 pub client_nonce: Vec<u8>,
213 pub client_certificate: Vec<u8>,
215 pub requested_session_timeout: f64,
217 pub max_response_message_size: u32,
219}
220
221impl CreateSessionRequest {
222 fn decode_body(r: &mut UaReader<'_>) -> Result<Self, DecodeError> {
223 Ok(Self {
224 request_header: decode_request_header(r)?,
225 client_description: ApplicationDescription::decode(r)?,
226 server_uri: read_string(r)?,
227 endpoint_url: read_string(r)?,
228 session_name: read_string(r)?,
229 client_nonce: read_byte_string(r)?,
230 client_certificate: read_byte_string(r)?,
231 requested_session_timeout: r.read_f64()?,
232 max_response_message_size: r.read_u32()?,
233 })
234 }
235
236 fn encode_into(&self, w: &mut UaWriter) -> Result<(), EncodeError> {
237 node_ids::CREATE_SESSION_REQUEST.encode(w)?;
238 encode_request_header(&self.request_header, w)?;
239 self.client_description.encode(w)?;
240 write_string(w, &self.server_uri)?;
241 write_string(w, &self.endpoint_url)?;
242 write_string(w, &self.session_name)?;
243 write_byte_string(w, &self.client_nonce)?;
244 write_byte_string(w, &self.client_certificate)?;
245 w.write_f64(self.requested_session_timeout);
246 w.write_u32(self.max_response_message_size);
247 Ok(())
248 }
249}
250
251#[derive(Debug, Clone, PartialEq)]
253pub struct CreateSessionResponse {
254 pub response_header: ResponseHeader,
256 pub session_id: NodeId,
258 pub authentication_token: NodeId,
260 pub revised_session_timeout: f64,
262 pub server_nonce: Vec<u8>,
264 pub server_certificate: Vec<u8>,
266 pub server_endpoints: Vec<EndpointDescription>,
268 pub server_signature: SignatureData,
270 pub max_request_message_size: u32,
272}
273
274impl CreateSessionResponse {
275 fn decode_body(r: &mut UaReader<'_>) -> Result<Self, DecodeError> {
276 let response_header = decode_response_header(r)?;
277 let session_id = NodeId::decode(r)?;
278 let authentication_token = NodeId::decode(r)?;
279 let revised_session_timeout = r.read_f64()?;
280 let server_nonce = read_byte_string(r)?;
281 let server_certificate = read_byte_string(r)?;
282 let server_endpoints = read_array::<EndpointDescription>(r)?;
283 let _swc = r.read_i32()?;
285 let server_signature = SignatureData::decode(r)?;
286 let max_request_message_size = r.read_u32()?;
287 Ok(Self {
288 response_header,
289 session_id,
290 authentication_token,
291 revised_session_timeout,
292 server_nonce,
293 server_certificate,
294 server_endpoints,
295 server_signature,
296 max_request_message_size,
297 })
298 }
299
300 fn encode_into(&self, w: &mut UaWriter) -> Result<(), EncodeError> {
301 node_ids::CREATE_SESSION_RESPONSE.encode(w)?;
302 encode_response_header(&self.response_header, w)?;
303 self.session_id.encode(w)?;
304 self.authentication_token.encode(w)?;
305 w.write_f64(self.revised_session_timeout);
306 write_byte_string(w, &self.server_nonce)?;
307 write_byte_string(w, &self.server_certificate)?;
308 write_array(w, &self.server_endpoints, "ServerEndpoints")?;
309 w.write_i32(0); self.server_signature.encode(w)?;
311 w.write_u32(self.max_request_message_size);
312 Ok(())
313 }
314}
315
316#[derive(Debug, Clone, PartialEq)]
322pub struct ActivateSessionRequest {
323 pub request_header: RequestHeader,
325 pub client_signature: SignatureData,
327 pub locale_ids: Vec<String>,
329 pub user_identity_token: zerodds_opcua_gateway::data_value::ExtensionObject,
331 pub user_token_signature: SignatureData,
333}
334
335impl ActivateSessionRequest {
336 fn decode_body(r: &mut UaReader<'_>) -> Result<Self, DecodeError> {
337 let request_header = decode_request_header(r)?;
338 let client_signature = SignatureData::decode(r)?;
339 let _swc = r.read_i32()?;
341 let locale_ids = read_string_array(r)?;
342 let user_identity_token = zerodds_opcua_gateway::data_value::ExtensionObject::decode(r)?;
343 let user_token_signature = SignatureData::decode(r)?;
344 Ok(Self {
345 request_header,
346 client_signature,
347 locale_ids,
348 user_identity_token,
349 user_token_signature,
350 })
351 }
352
353 fn encode_into(&self, w: &mut UaWriter) -> Result<(), EncodeError> {
354 node_ids::ACTIVATE_SESSION_REQUEST.encode(w)?;
355 encode_request_header(&self.request_header, w)?;
356 self.client_signature.encode(w)?;
357 w.write_i32(0); write_string_array(w, &self.locale_ids)?;
359 self.user_identity_token.encode(w)?;
360 self.user_token_signature.encode(w)?;
361 Ok(())
362 }
363}
364
365#[derive(Debug, Clone, PartialEq)]
367pub struct ActivateSessionResponse {
368 pub response_header: ResponseHeader,
370 pub server_nonce: Vec<u8>,
372 pub results: Vec<u32>,
374}
375
376impl ActivateSessionResponse {
377 fn decode_body(r: &mut UaReader<'_>) -> Result<Self, DecodeError> {
378 let response_header = decode_response_header(r)?;
379 let server_nonce = read_byte_string(r)?;
380 let results = read_u32_array(r)?;
381 skip_diagnostic_info_array(r)?;
382 Ok(Self {
383 response_header,
384 server_nonce,
385 results,
386 })
387 }
388
389 fn encode_into(&self, w: &mut UaWriter) -> Result<(), EncodeError> {
390 node_ids::ACTIVATE_SESSION_RESPONSE.encode(w)?;
391 encode_response_header(&self.response_header, w)?;
392 write_byte_string(w, &self.server_nonce)?;
393 write_u32_array(w, &self.results)?;
394 write_empty_diagnostic_info_array(w);
395 Ok(())
396 }
397}
398
399#[derive(Debug, Clone, PartialEq)]
405pub struct CloseSessionRequest {
406 pub request_header: RequestHeader,
408 pub delete_subscriptions: bool,
410}
411
412impl CloseSessionRequest {
413 fn decode_body(r: &mut UaReader<'_>) -> Result<Self, DecodeError> {
414 Ok(Self {
415 request_header: decode_request_header(r)?,
416 delete_subscriptions: r.read_u8()? != 0,
417 })
418 }
419
420 fn encode_into(&self, w: &mut UaWriter) -> Result<(), EncodeError> {
421 node_ids::CLOSE_SESSION_REQUEST.encode(w)?;
422 encode_request_header(&self.request_header, w)?;
423 w.write_u8(u8::from(self.delete_subscriptions));
424 Ok(())
425 }
426}
427
428#[derive(Debug, Clone, PartialEq)]
430pub struct CloseSessionResponse {
431 pub response_header: ResponseHeader,
433}
434
435impl CloseSessionResponse {
436 fn decode_body(r: &mut UaReader<'_>) -> Result<Self, DecodeError> {
437 Ok(Self {
438 response_header: decode_response_header(r)?,
439 })
440 }
441
442 fn encode_into(&self, w: &mut UaWriter) -> Result<(), EncodeError> {
443 node_ids::CLOSE_SESSION_RESPONSE.encode(w)?;
444 encode_response_header(&self.response_header, w)?;
445 Ok(())
446 }
447}
448
449#[derive(Debug, Clone, PartialEq)]
455pub struct ReadRequest {
456 pub request_header: RequestHeader,
458 pub max_age: f64,
460 pub timestamps_to_return: i32,
462 pub nodes_to_read: Vec<ReadValueId>,
464}
465
466impl ReadRequest {
467 fn decode_body(r: &mut UaReader<'_>) -> Result<Self, DecodeError> {
468 Ok(Self {
469 request_header: decode_request_header(r)?,
470 max_age: r.read_f64()?,
471 timestamps_to_return: r.read_i32()?,
472 nodes_to_read: read_array::<ReadValueId>(r)?,
473 })
474 }
475
476 fn encode_into(&self, w: &mut UaWriter) -> Result<(), EncodeError> {
477 node_ids::READ_REQUEST.encode(w)?;
478 encode_request_header(&self.request_header, w)?;
479 w.write_f64(self.max_age);
480 w.write_i32(self.timestamps_to_return);
481 write_array(w, &self.nodes_to_read, "NodesToRead")?;
482 Ok(())
483 }
484}
485
486#[derive(Debug, Clone, PartialEq)]
488pub struct ReadResponse {
489 pub response_header: ResponseHeader,
491 pub results: Vec<DataValue>,
493}
494
495impl ReadResponse {
496 fn decode_body(r: &mut UaReader<'_>) -> Result<Self, DecodeError> {
497 let response_header = decode_response_header(r)?;
498 let results = read_array::<DataValue>(r)?;
499 skip_diagnostic_info_array(r)?;
500 Ok(Self {
501 response_header,
502 results,
503 })
504 }
505
506 fn encode_into(&self, w: &mut UaWriter) -> Result<(), EncodeError> {
507 node_ids::READ_RESPONSE.encode(w)?;
508 encode_response_header(&self.response_header, w)?;
509 write_array(w, &self.results, "Results")?;
510 write_empty_diagnostic_info_array(w);
511 Ok(())
512 }
513}
514
515#[derive(Debug, Clone, PartialEq)]
521pub struct WriteRequest {
522 pub request_header: RequestHeader,
524 pub nodes_to_write: Vec<WriteValue>,
526}
527
528impl WriteRequest {
529 fn decode_body(r: &mut UaReader<'_>) -> Result<Self, DecodeError> {
530 Ok(Self {
531 request_header: decode_request_header(r)?,
532 nodes_to_write: read_array::<WriteValue>(r)?,
533 })
534 }
535
536 fn encode_into(&self, w: &mut UaWriter) -> Result<(), EncodeError> {
537 node_ids::WRITE_REQUEST.encode(w)?;
538 encode_request_header(&self.request_header, w)?;
539 write_array(w, &self.nodes_to_write, "NodesToWrite")?;
540 Ok(())
541 }
542}
543
544#[derive(Debug, Clone, PartialEq)]
546pub struct WriteResponse {
547 pub response_header: ResponseHeader,
549 pub results: Vec<u32>,
551}
552
553impl WriteResponse {
554 fn decode_body(r: &mut UaReader<'_>) -> Result<Self, DecodeError> {
555 let response_header = decode_response_header(r)?;
556 let results = read_u32_array(r)?;
557 skip_diagnostic_info_array(r)?;
558 Ok(Self {
559 response_header,
560 results,
561 })
562 }
563
564 fn encode_into(&self, w: &mut UaWriter) -> Result<(), EncodeError> {
565 node_ids::WRITE_RESPONSE.encode(w)?;
566 encode_response_header(&self.response_header, w)?;
567 write_u32_array(w, &self.results)?;
568 write_empty_diagnostic_info_array(w);
569 Ok(())
570 }
571}
572
573#[derive(Debug, Clone, PartialEq)]
579pub struct CallRequest {
580 pub request_header: RequestHeader,
582 pub methods_to_call: Vec<CallMethodRequest>,
584}
585
586impl CallRequest {
587 fn decode_body(r: &mut UaReader<'_>) -> Result<Self, DecodeError> {
588 Ok(Self {
589 request_header: decode_request_header(r)?,
590 methods_to_call: read_array::<CallMethodRequest>(r)?,
591 })
592 }
593
594 fn encode_into(&self, w: &mut UaWriter) -> Result<(), EncodeError> {
595 node_ids::CALL_REQUEST.encode(w)?;
596 encode_request_header(&self.request_header, w)?;
597 write_array(w, &self.methods_to_call, "MethodsToCall")?;
598 Ok(())
599 }
600}
601
602#[derive(Debug, Clone, PartialEq)]
604pub struct CallResponse {
605 pub response_header: ResponseHeader,
607 pub results: Vec<CallMethodResult>,
609}
610
611impl CallResponse {
612 fn decode_body(r: &mut UaReader<'_>) -> Result<Self, DecodeError> {
613 let response_header = decode_response_header(r)?;
614 let results = read_array::<CallMethodResult>(r)?;
615 skip_diagnostic_info_array(r)?;
616 Ok(Self {
617 response_header,
618 results,
619 })
620 }
621
622 fn encode_into(&self, w: &mut UaWriter) -> Result<(), EncodeError> {
623 node_ids::CALL_RESPONSE.encode(w)?;
624 encode_response_header(&self.response_header, w)?;
625 write_array(w, &self.results, "Results")?;
626 write_empty_diagnostic_info_array(w);
627 Ok(())
628 }
629}
630
631#[derive(Debug, Clone, PartialEq)]
638pub struct ViewDescription {
639 pub view_id: NodeId,
641 pub timestamp: i64,
643 pub view_version: u32,
645}
646
647impl Default for ViewDescription {
648 fn default() -> Self {
649 Self {
650 view_id: NodeId::numeric(0, 0),
651 timestamp: 0,
652 view_version: 0,
653 }
654 }
655}
656
657impl UaEncode for ViewDescription {
658 fn encode(&self, w: &mut UaWriter) -> Result<(), EncodeError> {
659 self.view_id.encode(w)?;
660 w.write_i64(self.timestamp);
661 w.write_u32(self.view_version);
662 Ok(())
663 }
664}
665
666impl UaDecode for ViewDescription {
667 fn decode(r: &mut UaReader<'_>) -> Result<Self, DecodeError> {
668 Ok(Self {
669 view_id: NodeId::decode(r)?,
670 timestamp: r.read_i64()?,
671 view_version: r.read_u32()?,
672 })
673 }
674}
675
676#[derive(Debug, Clone, PartialEq)]
678pub struct BrowseDescription {
679 pub node_id: NodeId,
681 pub browse_direction: i32,
683 pub reference_type_id: NodeId,
685 pub include_subtypes: bool,
687 pub node_class_mask: u32,
689 pub result_mask: u32,
691}
692
693impl UaEncode for BrowseDescription {
694 fn encode(&self, w: &mut UaWriter) -> Result<(), EncodeError> {
695 self.node_id.encode(w)?;
696 w.write_i32(self.browse_direction);
697 self.reference_type_id.encode(w)?;
698 w.write_u8(u8::from(self.include_subtypes));
699 w.write_u32(self.node_class_mask);
700 w.write_u32(self.result_mask);
701 Ok(())
702 }
703}
704
705impl UaDecode for BrowseDescription {
706 fn decode(r: &mut UaReader<'_>) -> Result<Self, DecodeError> {
707 Ok(Self {
708 node_id: NodeId::decode(r)?,
709 browse_direction: r.read_i32()?,
710 reference_type_id: NodeId::decode(r)?,
711 include_subtypes: r.read_u8()? != 0,
712 node_class_mask: r.read_u32()?,
713 result_mask: r.read_u32()?,
714 })
715 }
716}
717
718#[derive(Debug, Clone, PartialEq)]
720pub struct ReferenceDescription {
721 pub reference_type_id: NodeId,
723 pub is_forward: bool,
725 pub node_id: ExpandedNodeId,
727 pub browse_name: QualifiedName,
729 pub display_name: LocalizedText,
731 pub node_class: i32,
733 pub type_definition: ExpandedNodeId,
735}
736
737impl UaEncode for ReferenceDescription {
738 fn encode(&self, w: &mut UaWriter) -> Result<(), EncodeError> {
739 self.reference_type_id.encode(w)?;
740 w.write_u8(u8::from(self.is_forward));
741 self.node_id.encode(w)?;
742 self.browse_name.encode(w)?;
743 self.display_name.encode(w)?;
744 w.write_i32(self.node_class);
745 self.type_definition.encode(w)?;
746 Ok(())
747 }
748}
749
750impl UaDecode for ReferenceDescription {
751 fn decode(r: &mut UaReader<'_>) -> Result<Self, DecodeError> {
752 Ok(Self {
753 reference_type_id: NodeId::decode(r)?,
754 is_forward: r.read_u8()? != 0,
755 node_id: ExpandedNodeId::decode(r)?,
756 browse_name: QualifiedName::decode(r)?,
757 display_name: LocalizedText::decode(r)?,
758 node_class: r.read_i32()?,
759 type_definition: ExpandedNodeId::decode(r)?,
760 })
761 }
762}
763
764#[derive(Debug, Clone, PartialEq)]
766pub struct BrowseResult {
767 pub status_code: u32,
769 pub continuation_point: Vec<u8>,
771 pub references: Vec<ReferenceDescription>,
773}
774
775impl UaEncode for BrowseResult {
776 fn encode(&self, w: &mut UaWriter) -> Result<(), EncodeError> {
777 w.write_u32(self.status_code);
778 write_byte_string(w, &self.continuation_point)?;
779 write_array(w, &self.references, "References")?;
780 Ok(())
781 }
782}
783
784impl UaDecode for BrowseResult {
785 fn decode(r: &mut UaReader<'_>) -> Result<Self, DecodeError> {
786 Ok(Self {
787 status_code: r.read_u32()?,
788 continuation_point: read_byte_string(r)?,
789 references: read_array::<ReferenceDescription>(r)?,
790 })
791 }
792}
793
794#[derive(Debug, Clone, PartialEq)]
796pub struct BrowseRequest {
797 pub request_header: RequestHeader,
799 pub view: ViewDescription,
801 pub requested_max_references_per_node: u32,
803 pub nodes_to_browse: Vec<BrowseDescription>,
805}
806
807impl BrowseRequest {
808 fn decode_body(r: &mut UaReader<'_>) -> Result<Self, DecodeError> {
809 Ok(Self {
810 request_header: decode_request_header(r)?,
811 view: ViewDescription::decode(r)?,
812 requested_max_references_per_node: r.read_u32()?,
813 nodes_to_browse: read_array::<BrowseDescription>(r)?,
814 })
815 }
816
817 fn encode_into(&self, w: &mut UaWriter) -> Result<(), EncodeError> {
818 node_ids::BROWSE_REQUEST.encode(w)?;
819 encode_request_header(&self.request_header, w)?;
820 self.view.encode(w)?;
821 w.write_u32(self.requested_max_references_per_node);
822 write_array(w, &self.nodes_to_browse, "NodesToBrowse")?;
823 Ok(())
824 }
825}
826
827#[derive(Debug, Clone, PartialEq)]
829pub struct BrowseResponse {
830 pub response_header: ResponseHeader,
832 pub results: Vec<BrowseResult>,
834}
835
836impl BrowseResponse {
837 fn decode_body(r: &mut UaReader<'_>) -> Result<Self, DecodeError> {
838 let response_header = decode_response_header(r)?;
839 let results = read_array::<BrowseResult>(r)?;
840 skip_diagnostic_info_array(r)?;
841 Ok(Self {
842 response_header,
843 results,
844 })
845 }
846
847 fn encode_into(&self, w: &mut UaWriter) -> Result<(), EncodeError> {
848 node_ids::BROWSE_RESPONSE.encode(w)?;
849 encode_response_header(&self.response_header, w)?;
850 write_array(w, &self.results, "Results")?;
851 write_empty_diagnostic_info_array(w);
852 Ok(())
853 }
854}
855
856#[derive(Debug, Clone, PartialEq)]
862pub struct GetEndpointsRequest {
863 pub request_header: RequestHeader,
865 pub endpoint_url: String,
867 pub locale_ids: Vec<String>,
869 pub profile_uris: Vec<String>,
871}
872
873impl GetEndpointsRequest {
874 fn decode_body(r: &mut UaReader<'_>) -> Result<Self, DecodeError> {
875 Ok(Self {
876 request_header: decode_request_header(r)?,
877 endpoint_url: read_string(r)?,
878 locale_ids: read_string_array(r)?,
879 profile_uris: read_string_array(r)?,
880 })
881 }
882
883 fn encode_into(&self, w: &mut UaWriter) -> Result<(), EncodeError> {
884 node_ids::GET_ENDPOINTS_REQUEST.encode(w)?;
885 encode_request_header(&self.request_header, w)?;
886 write_string(w, &self.endpoint_url)?;
887 write_string_array(w, &self.locale_ids)?;
888 write_string_array(w, &self.profile_uris)?;
889 Ok(())
890 }
891}
892
893#[derive(Debug, Clone, PartialEq)]
895pub struct GetEndpointsResponse {
896 pub response_header: ResponseHeader,
898 pub endpoints: Vec<EndpointDescription>,
900}
901
902impl GetEndpointsResponse {
903 fn decode_body(r: &mut UaReader<'_>) -> Result<Self, DecodeError> {
904 Ok(Self {
905 response_header: decode_response_header(r)?,
906 endpoints: read_array::<EndpointDescription>(r)?,
907 })
908 }
909
910 fn encode_into(&self, w: &mut UaWriter) -> Result<(), EncodeError> {
911 node_ids::GET_ENDPOINTS_RESPONSE.encode(w)?;
912 encode_response_header(&self.response_header, w)?;
913 write_array(w, &self.endpoints, "Endpoints")?;
914 Ok(())
915 }
916}
917
918#[derive(Debug, Clone, PartialEq)]
920pub struct FindServersRequest {
921 pub request_header: RequestHeader,
923 pub endpoint_url: String,
925 pub locale_ids: Vec<String>,
927 pub server_uris: Vec<String>,
929}
930
931impl FindServersRequest {
932 fn decode_body(r: &mut UaReader<'_>) -> Result<Self, DecodeError> {
933 Ok(Self {
934 request_header: decode_request_header(r)?,
935 endpoint_url: read_string(r)?,
936 locale_ids: read_string_array(r)?,
937 server_uris: read_string_array(r)?,
938 })
939 }
940
941 fn encode_into(&self, w: &mut UaWriter) -> Result<(), EncodeError> {
942 node_ids::FIND_SERVERS_REQUEST.encode(w)?;
943 encode_request_header(&self.request_header, w)?;
944 write_string(w, &self.endpoint_url)?;
945 write_string_array(w, &self.locale_ids)?;
946 write_string_array(w, &self.server_uris)?;
947 Ok(())
948 }
949}
950
951#[derive(Debug, Clone, PartialEq)]
953pub struct FindServersResponse {
954 pub response_header: ResponseHeader,
956 pub servers: Vec<ApplicationDescription>,
958}
959
960impl FindServersResponse {
961 fn decode_body(r: &mut UaReader<'_>) -> Result<Self, DecodeError> {
962 Ok(Self {
963 response_header: decode_response_header(r)?,
964 servers: read_array::<ApplicationDescription>(r)?,
965 })
966 }
967
968 fn encode_into(&self, w: &mut UaWriter) -> Result<(), EncodeError> {
969 node_ids::FIND_SERVERS_RESPONSE.encode(w)?;
970 encode_response_header(&self.response_header, w)?;
971 write_array(w, &self.servers, "Servers")?;
972 Ok(())
973 }
974}
975
976#[derive(Debug, Clone, PartialEq)]
982pub struct CreateSubscriptionRequest {
983 pub request_header: RequestHeader,
985 pub requested_publishing_interval: f64,
987 pub requested_lifetime_count: u32,
989 pub requested_max_keep_alive_count: u32,
991 pub max_notifications_per_publish: u32,
993 pub publishing_enabled: bool,
995 pub priority: u8,
997}
998
999impl CreateSubscriptionRequest {
1000 fn decode_body(r: &mut UaReader<'_>) -> Result<Self, DecodeError> {
1001 Ok(Self {
1002 request_header: decode_request_header(r)?,
1003 requested_publishing_interval: r.read_f64()?,
1004 requested_lifetime_count: r.read_u32()?,
1005 requested_max_keep_alive_count: r.read_u32()?,
1006 max_notifications_per_publish: r.read_u32()?,
1007 publishing_enabled: r.read_u8()? != 0,
1008 priority: r.read_u8()?,
1009 })
1010 }
1011
1012 fn encode_into(&self, w: &mut UaWriter) -> Result<(), EncodeError> {
1013 node_ids::CREATE_SUBSCRIPTION_REQUEST.encode(w)?;
1014 encode_request_header(&self.request_header, w)?;
1015 w.write_f64(self.requested_publishing_interval);
1016 w.write_u32(self.requested_lifetime_count);
1017 w.write_u32(self.requested_max_keep_alive_count);
1018 w.write_u32(self.max_notifications_per_publish);
1019 w.write_u8(u8::from(self.publishing_enabled));
1020 w.write_u8(self.priority);
1021 Ok(())
1022 }
1023}
1024
1025#[derive(Debug, Clone, PartialEq)]
1027pub struct CreateSubscriptionResponse {
1028 pub response_header: ResponseHeader,
1030 pub subscription_id: u32,
1032 pub revised_publishing_interval: f64,
1034 pub revised_lifetime_count: u32,
1036 pub revised_max_keep_alive_count: u32,
1038}
1039
1040impl CreateSubscriptionResponse {
1041 fn decode_body(r: &mut UaReader<'_>) -> Result<Self, DecodeError> {
1042 Ok(Self {
1043 response_header: decode_response_header(r)?,
1044 subscription_id: r.read_u32()?,
1045 revised_publishing_interval: r.read_f64()?,
1046 revised_lifetime_count: r.read_u32()?,
1047 revised_max_keep_alive_count: r.read_u32()?,
1048 })
1049 }
1050
1051 fn encode_into(&self, w: &mut UaWriter) -> Result<(), EncodeError> {
1052 node_ids::CREATE_SUBSCRIPTION_RESPONSE.encode(w)?;
1053 encode_response_header(&self.response_header, w)?;
1054 w.write_u32(self.subscription_id);
1055 w.write_f64(self.revised_publishing_interval);
1056 w.write_u32(self.revised_lifetime_count);
1057 w.write_u32(self.revised_max_keep_alive_count);
1058 Ok(())
1059 }
1060}
1061
1062#[derive(Debug, Clone, PartialEq)]
1064pub struct SetPublishingModeRequest {
1065 pub request_header: RequestHeader,
1067 pub publishing_enabled: bool,
1069 pub subscription_ids: Vec<u32>,
1071}
1072
1073impl SetPublishingModeRequest {
1074 fn decode_body(r: &mut UaReader<'_>) -> Result<Self, DecodeError> {
1075 Ok(Self {
1076 request_header: decode_request_header(r)?,
1077 publishing_enabled: r.read_u8()? != 0,
1078 subscription_ids: read_u32_array(r)?,
1079 })
1080 }
1081
1082 fn encode_into(&self, w: &mut UaWriter) -> Result<(), EncodeError> {
1083 node_ids::SET_PUBLISHING_MODE_REQUEST.encode(w)?;
1084 encode_request_header(&self.request_header, w)?;
1085 w.write_u8(u8::from(self.publishing_enabled));
1086 write_u32_array(w, &self.subscription_ids)?;
1087 Ok(())
1088 }
1089}
1090
1091#[derive(Debug, Clone, PartialEq)]
1093pub struct SetPublishingModeResponse {
1094 pub response_header: ResponseHeader,
1096 pub results: Vec<u32>,
1098}
1099
1100impl SetPublishingModeResponse {
1101 fn decode_body(r: &mut UaReader<'_>) -> Result<Self, DecodeError> {
1102 let response_header = decode_response_header(r)?;
1103 let results = read_u32_array(r)?;
1104 skip_diagnostic_info_array(r)?;
1105 Ok(Self {
1106 response_header,
1107 results,
1108 })
1109 }
1110
1111 fn encode_into(&self, w: &mut UaWriter) -> Result<(), EncodeError> {
1112 node_ids::SET_PUBLISHING_MODE_RESPONSE.encode(w)?;
1113 encode_response_header(&self.response_header, w)?;
1114 write_u32_array(w, &self.results)?;
1115 write_empty_diagnostic_info_array(w);
1116 Ok(())
1117 }
1118}
1119
1120#[derive(Debug, Clone, PartialEq)]
1122pub struct MonitoringParameters {
1123 pub client_handle: u32,
1125 pub sampling_interval: f64,
1127 pub filter: ExtensionObject,
1129 pub queue_size: u32,
1131 pub discard_oldest: bool,
1133}
1134
1135impl UaEncode for MonitoringParameters {
1136 fn encode(&self, w: &mut UaWriter) -> Result<(), EncodeError> {
1137 w.write_u32(self.client_handle);
1138 w.write_f64(self.sampling_interval);
1139 self.filter.encode(w)?;
1140 w.write_u32(self.queue_size);
1141 w.write_u8(u8::from(self.discard_oldest));
1142 Ok(())
1143 }
1144}
1145
1146impl UaDecode for MonitoringParameters {
1147 fn decode(r: &mut UaReader<'_>) -> Result<Self, DecodeError> {
1148 Ok(Self {
1149 client_handle: r.read_u32()?,
1150 sampling_interval: r.read_f64()?,
1151 filter: ExtensionObject::decode(r)?,
1152 queue_size: r.read_u32()?,
1153 discard_oldest: r.read_u8()? != 0,
1154 })
1155 }
1156}
1157
1158#[derive(Debug, Clone, PartialEq)]
1160pub struct MonitoredItemCreateRequest {
1161 pub item_to_monitor: ReadValueId,
1163 pub monitoring_mode: i32,
1165 pub requested_parameters: MonitoringParameters,
1167}
1168
1169impl UaEncode for MonitoredItemCreateRequest {
1170 fn encode(&self, w: &mut UaWriter) -> Result<(), EncodeError> {
1171 self.item_to_monitor.encode(w)?;
1172 w.write_i32(self.monitoring_mode);
1173 self.requested_parameters.encode(w)?;
1174 Ok(())
1175 }
1176}
1177
1178impl UaDecode for MonitoredItemCreateRequest {
1179 fn decode(r: &mut UaReader<'_>) -> Result<Self, DecodeError> {
1180 Ok(Self {
1181 item_to_monitor: ReadValueId::decode(r)?,
1182 monitoring_mode: r.read_i32()?,
1183 requested_parameters: MonitoringParameters::decode(r)?,
1184 })
1185 }
1186}
1187
1188#[derive(Debug, Clone, PartialEq)]
1190pub struct MonitoredItemCreateResult {
1191 pub status_code: u32,
1193 pub monitored_item_id: u32,
1195 pub revised_sampling_interval: f64,
1197 pub revised_queue_size: u32,
1199 pub filter_result: ExtensionObject,
1201}
1202
1203impl UaEncode for MonitoredItemCreateResult {
1204 fn encode(&self, w: &mut UaWriter) -> Result<(), EncodeError> {
1205 w.write_u32(self.status_code);
1206 w.write_u32(self.monitored_item_id);
1207 w.write_f64(self.revised_sampling_interval);
1208 w.write_u32(self.revised_queue_size);
1209 self.filter_result.encode(w)?;
1210 Ok(())
1211 }
1212}
1213
1214impl UaDecode for MonitoredItemCreateResult {
1215 fn decode(r: &mut UaReader<'_>) -> Result<Self, DecodeError> {
1216 Ok(Self {
1217 status_code: r.read_u32()?,
1218 monitored_item_id: r.read_u32()?,
1219 revised_sampling_interval: r.read_f64()?,
1220 revised_queue_size: r.read_u32()?,
1221 filter_result: ExtensionObject::decode(r)?,
1222 })
1223 }
1224}
1225
1226#[must_use]
1228pub fn null_filter() -> ExtensionObject {
1229 null_extension_object()
1230}
1231
1232#[derive(Debug, Clone, PartialEq)]
1234pub struct CreateMonitoredItemsRequest {
1235 pub request_header: RequestHeader,
1237 pub subscription_id: u32,
1239 pub timestamps_to_return: i32,
1241 pub items_to_create: Vec<MonitoredItemCreateRequest>,
1243}
1244
1245impl CreateMonitoredItemsRequest {
1246 fn decode_body(r: &mut UaReader<'_>) -> Result<Self, DecodeError> {
1247 Ok(Self {
1248 request_header: decode_request_header(r)?,
1249 subscription_id: r.read_u32()?,
1250 timestamps_to_return: r.read_i32()?,
1251 items_to_create: read_array::<MonitoredItemCreateRequest>(r)?,
1252 })
1253 }
1254
1255 fn encode_into(&self, w: &mut UaWriter) -> Result<(), EncodeError> {
1256 node_ids::CREATE_MONITORED_ITEMS_REQUEST.encode(w)?;
1257 encode_request_header(&self.request_header, w)?;
1258 w.write_u32(self.subscription_id);
1259 w.write_i32(self.timestamps_to_return);
1260 write_array(w, &self.items_to_create, "ItemsToCreate")?;
1261 Ok(())
1262 }
1263}
1264
1265#[derive(Debug, Clone, PartialEq)]
1267pub struct CreateMonitoredItemsResponse {
1268 pub response_header: ResponseHeader,
1270 pub results: Vec<MonitoredItemCreateResult>,
1272}
1273
1274impl CreateMonitoredItemsResponse {
1275 fn decode_body(r: &mut UaReader<'_>) -> Result<Self, DecodeError> {
1276 let response_header = decode_response_header(r)?;
1277 let results = read_array::<MonitoredItemCreateResult>(r)?;
1278 skip_diagnostic_info_array(r)?;
1279 Ok(Self {
1280 response_header,
1281 results,
1282 })
1283 }
1284
1285 fn encode_into(&self, w: &mut UaWriter) -> Result<(), EncodeError> {
1286 node_ids::CREATE_MONITORED_ITEMS_RESPONSE.encode(w)?;
1287 encode_response_header(&self.response_header, w)?;
1288 write_array(w, &self.results, "Results")?;
1289 write_empty_diagnostic_info_array(w);
1290 Ok(())
1291 }
1292}
1293
1294#[derive(Debug, Clone, PartialEq, Eq)]
1296pub struct SubscriptionAcknowledgement {
1297 pub subscription_id: u32,
1299 pub sequence_number: u32,
1301}
1302
1303impl UaEncode for SubscriptionAcknowledgement {
1304 fn encode(&self, w: &mut UaWriter) -> Result<(), EncodeError> {
1305 w.write_u32(self.subscription_id);
1306 w.write_u32(self.sequence_number);
1307 Ok(())
1308 }
1309}
1310
1311impl UaDecode for SubscriptionAcknowledgement {
1312 fn decode(r: &mut UaReader<'_>) -> Result<Self, DecodeError> {
1313 Ok(Self {
1314 subscription_id: r.read_u32()?,
1315 sequence_number: r.read_u32()?,
1316 })
1317 }
1318}
1319
1320#[derive(Debug, Clone, PartialEq)]
1322pub struct MonitoredItemNotification {
1323 pub client_handle: u32,
1325 pub value: DataValue,
1327}
1328
1329impl UaEncode for MonitoredItemNotification {
1330 fn encode(&self, w: &mut UaWriter) -> Result<(), EncodeError> {
1331 w.write_u32(self.client_handle);
1332 self.value.encode(w)?;
1333 Ok(())
1334 }
1335}
1336
1337impl UaDecode for MonitoredItemNotification {
1338 fn decode(r: &mut UaReader<'_>) -> Result<Self, DecodeError> {
1339 Ok(Self {
1340 client_handle: r.read_u32()?,
1341 value: DataValue::decode(r)?,
1342 })
1343 }
1344}
1345
1346#[derive(Debug, Clone, PartialEq)]
1349pub struct DataChangeNotification {
1350 pub monitored_items: Vec<MonitoredItemNotification>,
1352}
1353
1354impl DataChangeNotification {
1355 pub fn to_extension_object(&self) -> Result<ExtensionObject, EncodeError> {
1360 let mut w = UaWriter::new();
1361 write_array(&mut w, &self.monitored_items, "MonitoredItems")?;
1362 write_empty_diagnostic_info_array(&mut w);
1363 Ok(ExtensionObject {
1364 type_id: node_ids::DATA_CHANGE_NOTIFICATION,
1365 body: ExtensionObjectBody::ByteString(w.into_vec()),
1366 })
1367 }
1368
1369 pub fn from_extension_object(eo: &ExtensionObject) -> Result<Self, DecodeError> {
1374 match &eo.body {
1375 ExtensionObjectBody::ByteString(b) => {
1376 let mut r = UaReader::new(b);
1377 let monitored_items = read_array::<MonitoredItemNotification>(&mut r)?;
1378 skip_diagnostic_info_array(&mut r)?;
1379 Ok(Self { monitored_items })
1380 }
1381 _ => Err(DecodeError::MalformedMessage {
1382 message: "DataChangeNotification ExtensionObject is not a ByteString body",
1383 }),
1384 }
1385 }
1386}
1387
1388#[derive(Debug, Clone, PartialEq)]
1390pub struct NotificationMessage {
1391 pub sequence_number: u32,
1393 pub publish_time: i64,
1395 pub notification_data: Vec<ExtensionObject>,
1397}
1398
1399impl UaEncode for NotificationMessage {
1400 fn encode(&self, w: &mut UaWriter) -> Result<(), EncodeError> {
1401 w.write_u32(self.sequence_number);
1402 w.write_i64(self.publish_time);
1403 write_array(w, &self.notification_data, "NotificationData")?;
1404 Ok(())
1405 }
1406}
1407
1408impl UaDecode for NotificationMessage {
1409 fn decode(r: &mut UaReader<'_>) -> Result<Self, DecodeError> {
1410 Ok(Self {
1411 sequence_number: r.read_u32()?,
1412 publish_time: r.read_i64()?,
1413 notification_data: read_array::<ExtensionObject>(r)?,
1414 })
1415 }
1416}
1417
1418#[derive(Debug, Clone, PartialEq)]
1420pub struct PublishRequest {
1421 pub request_header: RequestHeader,
1423 pub subscription_acknowledgements: Vec<SubscriptionAcknowledgement>,
1425}
1426
1427impl PublishRequest {
1428 fn decode_body(r: &mut UaReader<'_>) -> Result<Self, DecodeError> {
1429 Ok(Self {
1430 request_header: decode_request_header(r)?,
1431 subscription_acknowledgements: read_array::<SubscriptionAcknowledgement>(r)?,
1432 })
1433 }
1434
1435 fn encode_into(&self, w: &mut UaWriter) -> Result<(), EncodeError> {
1436 node_ids::PUBLISH_REQUEST.encode(w)?;
1437 encode_request_header(&self.request_header, w)?;
1438 write_array(w, &self.subscription_acknowledgements, "Acks")?;
1439 Ok(())
1440 }
1441}
1442
1443#[derive(Debug, Clone, PartialEq)]
1445pub struct PublishResponse {
1446 pub response_header: ResponseHeader,
1448 pub subscription_id: u32,
1450 pub available_sequence_numbers: Vec<u32>,
1452 pub more_notifications: bool,
1454 pub notification_message: NotificationMessage,
1456 pub results: Vec<u32>,
1458}
1459
1460impl PublishResponse {
1461 fn decode_body(r: &mut UaReader<'_>) -> Result<Self, DecodeError> {
1462 let response_header = decode_response_header(r)?;
1463 let subscription_id = r.read_u32()?;
1464 let available_sequence_numbers = read_u32_array(r)?;
1465 let more_notifications = r.read_u8()? != 0;
1466 let notification_message = NotificationMessage::decode(r)?;
1467 let results = read_u32_array(r)?;
1468 skip_diagnostic_info_array(r)?;
1469 Ok(Self {
1470 response_header,
1471 subscription_id,
1472 available_sequence_numbers,
1473 more_notifications,
1474 notification_message,
1475 results,
1476 })
1477 }
1478
1479 fn encode_into(&self, w: &mut UaWriter) -> Result<(), EncodeError> {
1480 node_ids::PUBLISH_RESPONSE.encode(w)?;
1481 encode_response_header(&self.response_header, w)?;
1482 w.write_u32(self.subscription_id);
1483 write_u32_array(w, &self.available_sequence_numbers)?;
1484 w.write_u8(u8::from(self.more_notifications));
1485 self.notification_message.encode(w)?;
1486 write_u32_array(w, &self.results)?;
1487 write_empty_diagnostic_info_array(w);
1488 Ok(())
1489 }
1490}
1491
1492#[derive(Debug, Clone, PartialEq)]
1494pub struct DeleteSubscriptionsRequest {
1495 pub request_header: RequestHeader,
1497 pub subscription_ids: Vec<u32>,
1499}
1500
1501impl DeleteSubscriptionsRequest {
1502 fn decode_body(r: &mut UaReader<'_>) -> Result<Self, DecodeError> {
1503 Ok(Self {
1504 request_header: decode_request_header(r)?,
1505 subscription_ids: read_u32_array(r)?,
1506 })
1507 }
1508
1509 fn encode_into(&self, w: &mut UaWriter) -> Result<(), EncodeError> {
1510 node_ids::DELETE_SUBSCRIPTIONS_REQUEST.encode(w)?;
1511 encode_request_header(&self.request_header, w)?;
1512 write_u32_array(w, &self.subscription_ids)?;
1513 Ok(())
1514 }
1515}
1516
1517#[derive(Debug, Clone, PartialEq)]
1519pub struct DeleteSubscriptionsResponse {
1520 pub response_header: ResponseHeader,
1522 pub results: Vec<u32>,
1524}
1525
1526impl DeleteSubscriptionsResponse {
1527 fn decode_body(r: &mut UaReader<'_>) -> Result<Self, DecodeError> {
1528 let response_header = decode_response_header(r)?;
1529 let results = read_u32_array(r)?;
1530 skip_diagnostic_info_array(r)?;
1531 Ok(Self {
1532 response_header,
1533 results,
1534 })
1535 }
1536
1537 fn encode_into(&self, w: &mut UaWriter) -> Result<(), EncodeError> {
1538 node_ids::DELETE_SUBSCRIPTIONS_RESPONSE.encode(w)?;
1539 encode_response_header(&self.response_header, w)?;
1540 write_u32_array(w, &self.results)?;
1541 write_empty_diagnostic_info_array(w);
1542 Ok(())
1543 }
1544}
1545
1546#[derive(Debug, Clone, PartialEq)]
1552pub enum ServiceRequest {
1553 CreateSession(CreateSessionRequest),
1555 ActivateSession(ActivateSessionRequest),
1557 CloseSession(CloseSessionRequest),
1559 Read(ReadRequest),
1561 Write(WriteRequest),
1563 Browse(BrowseRequest),
1565 GetEndpoints(GetEndpointsRequest),
1567 FindServers(FindServersRequest),
1569 CreateSubscription(CreateSubscriptionRequest),
1571 SetPublishingMode(SetPublishingModeRequest),
1573 CreateMonitoredItems(CreateMonitoredItemsRequest),
1575 Publish(PublishRequest),
1577 DeleteSubscriptions(DeleteSubscriptionsRequest),
1579 Call(CallRequest),
1581}
1582
1583impl ServiceRequest {
1584 pub fn encode(&self) -> Result<Vec<u8>, EncodeError> {
1589 let mut w = UaWriter::new();
1590 match self {
1591 Self::CreateSession(m) => m.encode_into(&mut w)?,
1592 Self::ActivateSession(m) => m.encode_into(&mut w)?,
1593 Self::CloseSession(m) => m.encode_into(&mut w)?,
1594 Self::Read(m) => m.encode_into(&mut w)?,
1595 Self::Write(m) => m.encode_into(&mut w)?,
1596 Self::Browse(m) => m.encode_into(&mut w)?,
1597 Self::GetEndpoints(m) => m.encode_into(&mut w)?,
1598 Self::FindServers(m) => m.encode_into(&mut w)?,
1599 Self::CreateSubscription(m) => m.encode_into(&mut w)?,
1600 Self::SetPublishingMode(m) => m.encode_into(&mut w)?,
1601 Self::CreateMonitoredItems(m) => m.encode_into(&mut w)?,
1602 Self::Publish(m) => m.encode_into(&mut w)?,
1603 Self::DeleteSubscriptions(m) => m.encode_into(&mut w)?,
1604 Self::Call(m) => m.encode_into(&mut w)?,
1605 }
1606 Ok(w.into_vec())
1607 }
1608
1609 pub fn decode(body: &[u8]) -> Result<Self, DecodeError> {
1614 let mut r = UaReader::new(body);
1615 let type_id = NodeId::decode(&mut r)?;
1616 Ok(if type_id == node_ids::CREATE_SESSION_REQUEST {
1617 Self::CreateSession(CreateSessionRequest::decode_body(&mut r)?)
1618 } else if type_id == node_ids::ACTIVATE_SESSION_REQUEST {
1619 Self::ActivateSession(ActivateSessionRequest::decode_body(&mut r)?)
1620 } else if type_id == node_ids::CLOSE_SESSION_REQUEST {
1621 Self::CloseSession(CloseSessionRequest::decode_body(&mut r)?)
1622 } else if type_id == node_ids::READ_REQUEST {
1623 Self::Read(ReadRequest::decode_body(&mut r)?)
1624 } else if type_id == node_ids::WRITE_REQUEST {
1625 Self::Write(WriteRequest::decode_body(&mut r)?)
1626 } else if type_id == node_ids::BROWSE_REQUEST {
1627 Self::Browse(BrowseRequest::decode_body(&mut r)?)
1628 } else if type_id == node_ids::GET_ENDPOINTS_REQUEST {
1629 Self::GetEndpoints(GetEndpointsRequest::decode_body(&mut r)?)
1630 } else if type_id == node_ids::FIND_SERVERS_REQUEST {
1631 Self::FindServers(FindServersRequest::decode_body(&mut r)?)
1632 } else if type_id == node_ids::CREATE_SUBSCRIPTION_REQUEST {
1633 Self::CreateSubscription(CreateSubscriptionRequest::decode_body(&mut r)?)
1634 } else if type_id == node_ids::SET_PUBLISHING_MODE_REQUEST {
1635 Self::SetPublishingMode(SetPublishingModeRequest::decode_body(&mut r)?)
1636 } else if type_id == node_ids::CREATE_MONITORED_ITEMS_REQUEST {
1637 Self::CreateMonitoredItems(CreateMonitoredItemsRequest::decode_body(&mut r)?)
1638 } else if type_id == node_ids::PUBLISH_REQUEST {
1639 Self::Publish(PublishRequest::decode_body(&mut r)?)
1640 } else if type_id == node_ids::DELETE_SUBSCRIPTIONS_REQUEST {
1641 Self::DeleteSubscriptions(DeleteSubscriptionsRequest::decode_body(&mut r)?)
1642 } else if type_id == node_ids::CALL_REQUEST {
1643 Self::Call(CallRequest::decode_body(&mut r)?)
1644 } else {
1645 return Err(DecodeError::MalformedMessage {
1646 message: "unsupported OPC-UA service request type",
1647 });
1648 })
1649 }
1650}
1651
1652#[derive(Debug, Clone, PartialEq)]
1654pub enum ServiceResponse {
1655 CreateSession(CreateSessionResponse),
1657 ActivateSession(ActivateSessionResponse),
1659 CloseSession(CloseSessionResponse),
1661 Read(ReadResponse),
1663 Write(WriteResponse),
1665 Browse(BrowseResponse),
1667 GetEndpoints(GetEndpointsResponse),
1669 FindServers(FindServersResponse),
1671 CreateSubscription(CreateSubscriptionResponse),
1673 SetPublishingMode(SetPublishingModeResponse),
1675 CreateMonitoredItems(CreateMonitoredItemsResponse),
1677 Publish(PublishResponse),
1679 DeleteSubscriptions(DeleteSubscriptionsResponse),
1681 Call(CallResponse),
1683}
1684
1685impl ServiceResponse {
1686 pub fn encode(&self) -> Result<Vec<u8>, EncodeError> {
1691 let mut w = UaWriter::new();
1692 match self {
1693 Self::CreateSession(m) => m.encode_into(&mut w)?,
1694 Self::ActivateSession(m) => m.encode_into(&mut w)?,
1695 Self::CloseSession(m) => m.encode_into(&mut w)?,
1696 Self::Read(m) => m.encode_into(&mut w)?,
1697 Self::Write(m) => m.encode_into(&mut w)?,
1698 Self::Browse(m) => m.encode_into(&mut w)?,
1699 Self::GetEndpoints(m) => m.encode_into(&mut w)?,
1700 Self::FindServers(m) => m.encode_into(&mut w)?,
1701 Self::CreateSubscription(m) => m.encode_into(&mut w)?,
1702 Self::SetPublishingMode(m) => m.encode_into(&mut w)?,
1703 Self::CreateMonitoredItems(m) => m.encode_into(&mut w)?,
1704 Self::Publish(m) => m.encode_into(&mut w)?,
1705 Self::DeleteSubscriptions(m) => m.encode_into(&mut w)?,
1706 Self::Call(m) => m.encode_into(&mut w)?,
1707 }
1708 Ok(w.into_vec())
1709 }
1710
1711 pub fn decode(body: &[u8]) -> Result<Self, DecodeError> {
1716 let mut r = UaReader::new(body);
1717 let type_id = NodeId::decode(&mut r)?;
1718 Ok(if type_id == node_ids::CREATE_SESSION_RESPONSE {
1719 Self::CreateSession(CreateSessionResponse::decode_body(&mut r)?)
1720 } else if type_id == node_ids::ACTIVATE_SESSION_RESPONSE {
1721 Self::ActivateSession(ActivateSessionResponse::decode_body(&mut r)?)
1722 } else if type_id == node_ids::CLOSE_SESSION_RESPONSE {
1723 Self::CloseSession(CloseSessionResponse::decode_body(&mut r)?)
1724 } else if type_id == node_ids::READ_RESPONSE {
1725 Self::Read(ReadResponse::decode_body(&mut r)?)
1726 } else if type_id == node_ids::WRITE_RESPONSE {
1727 Self::Write(WriteResponse::decode_body(&mut r)?)
1728 } else if type_id == node_ids::BROWSE_RESPONSE {
1729 Self::Browse(BrowseResponse::decode_body(&mut r)?)
1730 } else if type_id == node_ids::GET_ENDPOINTS_RESPONSE {
1731 Self::GetEndpoints(GetEndpointsResponse::decode_body(&mut r)?)
1732 } else if type_id == node_ids::FIND_SERVERS_RESPONSE {
1733 Self::FindServers(FindServersResponse::decode_body(&mut r)?)
1734 } else if type_id == node_ids::CREATE_SUBSCRIPTION_RESPONSE {
1735 Self::CreateSubscription(CreateSubscriptionResponse::decode_body(&mut r)?)
1736 } else if type_id == node_ids::SET_PUBLISHING_MODE_RESPONSE {
1737 Self::SetPublishingMode(SetPublishingModeResponse::decode_body(&mut r)?)
1738 } else if type_id == node_ids::CREATE_MONITORED_ITEMS_RESPONSE {
1739 Self::CreateMonitoredItems(CreateMonitoredItemsResponse::decode_body(&mut r)?)
1740 } else if type_id == node_ids::PUBLISH_RESPONSE {
1741 Self::Publish(PublishResponse::decode_body(&mut r)?)
1742 } else if type_id == node_ids::DELETE_SUBSCRIPTIONS_RESPONSE {
1743 Self::DeleteSubscriptions(DeleteSubscriptionsResponse::decode_body(&mut r)?)
1744 } else if type_id == node_ids::CALL_RESPONSE {
1745 Self::Call(CallResponse::decode_body(&mut r)?)
1746 } else {
1747 return Err(DecodeError::MalformedMessage {
1748 message: "unsupported OPC-UA service response type",
1749 });
1750 })
1751 }
1752}
1753
1754fn encode_request_header(h: &RequestHeader, w: &mut UaWriter) -> Result<(), EncodeError> {
1757 h.authentication_token.encode(w)?;
1758 w.write_i64(h.timestamp);
1759 w.write_u32(h.request_handle);
1760 w.write_u32(h.return_diagnostics);
1761 write_string(w, &h.audit_entry_id)?;
1762 w.write_u32(h.timeout_hint);
1763 h.additional_header.encode(w)?;
1764 Ok(())
1765}
1766
1767fn decode_request_header(r: &mut UaReader<'_>) -> Result<RequestHeader, DecodeError> {
1768 Ok(RequestHeader {
1769 authentication_token: NodeId::decode(r)?,
1770 timestamp: r.read_i64()?,
1771 request_handle: r.read_u32()?,
1772 return_diagnostics: r.read_u32()?,
1773 audit_entry_id: read_string(r)?,
1774 timeout_hint: r.read_u32()?,
1775 additional_header: zerodds_opcua_gateway::data_value::ExtensionObject::decode(r)?,
1776 })
1777}
1778
1779fn encode_response_header(h: &ResponseHeader, w: &mut UaWriter) -> Result<(), EncodeError> {
1780 w.write_i64(h.timestamp);
1781 w.write_u32(h.request_handle);
1782 w.write_u32(h.service_result);
1783 w.write_u8(0); write_string_array(w, &h.string_table)?;
1785 h.additional_header.encode(w)?;
1786 Ok(())
1787}
1788
1789fn decode_response_header(r: &mut UaReader<'_>) -> Result<ResponseHeader, DecodeError> {
1790 let timestamp = r.read_i64()?;
1791 let request_handle = r.read_u32()?;
1792 let service_result = r.read_u32()?;
1793 crate::wire::skip_one_diagnostic_info(r)?;
1795 let string_table = read_string_array(r)?;
1796 let additional_header = zerodds_opcua_gateway::data_value::ExtensionObject::decode(r)?;
1797 Ok(ResponseHeader {
1798 timestamp,
1799 request_handle,
1800 service_result,
1801 string_table,
1802 additional_header,
1803 })
1804}
1805
1806#[cfg(test)]
1807mod tests {
1808 use super::*;
1809 use zerodds_opcua_gateway::data_value::VariantValue;
1810 use zerodds_opcua_uacp::securechannel::null_extension_object;
1811
1812 fn req_header() -> RequestHeader {
1813 RequestHeader::new(NodeId::numeric(0, 0), 1)
1814 }
1815
1816 #[test]
1817 fn read_request_round_trips() {
1818 let req = ServiceRequest::Read(ReadRequest {
1819 request_header: req_header(),
1820 max_age: 0.0,
1821 timestamps_to_return: 0,
1822 nodes_to_read: alloc::vec![ReadValueId {
1823 node_id: NodeId::numeric(1, 42),
1824 attribute_id: ATTRIBUTE_VALUE,
1825 index_range: String::new(),
1826 data_encoding: QualifiedName {
1827 namespace_index: 0,
1828 name: String::new(),
1829 },
1830 }],
1831 });
1832 let body = req.encode().expect("encode");
1833 assert_eq!(ServiceRequest::decode(&body).expect("decode"), req);
1834 }
1835
1836 #[test]
1837 fn read_response_round_trips() {
1838 let resp = ServiceResponse::Read(ReadResponse {
1839 response_header: ResponseHeader::new(1, 0),
1840 results: alloc::vec![DataValue::new_value(
1841 Variant::scalar(VariantValue::Int32(99)),
1842 0,
1843 0,
1844 )],
1845 });
1846 let body = resp.encode().expect("encode");
1847 assert_eq!(ServiceResponse::decode(&body).expect("decode"), resp);
1848 }
1849
1850 #[test]
1851 fn write_round_trips() {
1852 let req = ServiceRequest::Write(WriteRequest {
1853 request_header: req_header(),
1854 nodes_to_write: alloc::vec![WriteValue {
1855 node_id: NodeId::numeric(1, 7),
1856 attribute_id: ATTRIBUTE_VALUE,
1857 index_range: String::new(),
1858 value: DataValue::new_value(Variant::scalar(VariantValue::Int32(5)), 0, 0),
1859 }],
1860 });
1861 let body = req.encode().expect("encode");
1862 assert_eq!(ServiceRequest::decode(&body).expect("decode"), req);
1863
1864 let resp = ServiceResponse::Write(WriteResponse {
1865 response_header: ResponseHeader::new(1, 0),
1866 results: alloc::vec![0],
1867 });
1868 let rb = resp.encode().expect("encode");
1869 assert_eq!(ServiceResponse::decode(&rb).expect("decode"), resp);
1870 }
1871
1872 #[test]
1873 fn browse_round_trips() {
1874 let req = ServiceRequest::Browse(BrowseRequest {
1875 request_header: req_header(),
1876 view: ViewDescription::default(),
1877 requested_max_references_per_node: 100,
1878 nodes_to_browse: alloc::vec![BrowseDescription {
1879 node_id: NodeId::numeric(0, 85),
1880 browse_direction: 2,
1881 reference_type_id: NodeId::numeric(0, 33),
1882 include_subtypes: true,
1883 node_class_mask: 0,
1884 result_mask: 0x3F,
1885 }],
1886 });
1887 let body = req.encode().expect("encode");
1888 assert_eq!(ServiceRequest::decode(&body).expect("decode"), req);
1889
1890 let resp = ServiceResponse::Browse(BrowseResponse {
1891 response_header: ResponseHeader::new(1, 0),
1892 results: alloc::vec![BrowseResult {
1893 status_code: 0,
1894 continuation_point: Vec::new(),
1895 references: alloc::vec![ReferenceDescription {
1896 reference_type_id: NodeId::numeric(0, 35),
1897 is_forward: true,
1898 node_id: ExpandedNodeId {
1899 node_id: NodeId::numeric(1, 1),
1900 namespace_uri: String::new(),
1901 server_index: 0,
1902 },
1903 browse_name: QualifiedName {
1904 namespace_index: 1,
1905 name: String::from("Boiler"),
1906 },
1907 display_name: LocalizedText {
1908 locale: None,
1909 text: Some(String::from("Boiler")),
1910 },
1911 node_class: 1,
1912 type_definition: ExpandedNodeId {
1913 node_id: NodeId::numeric(0, 58),
1914 namespace_uri: String::new(),
1915 server_index: 0,
1916 },
1917 }],
1918 }],
1919 });
1920 let rb = resp.encode().expect("encode");
1921 assert_eq!(ServiceResponse::decode(&rb).expect("decode"), resp);
1922 }
1923
1924 #[test]
1925 fn discovery_requests_round_trip() {
1926 let ge = ServiceRequest::GetEndpoints(GetEndpointsRequest {
1927 request_header: req_header(),
1928 endpoint_url: String::from("opc.tcp://x:4840"),
1929 locale_ids: alloc::vec![String::from("en")],
1930 profile_uris: Vec::new(),
1931 });
1932 assert_eq!(
1933 ServiceRequest::decode(&ge.encode().expect("e")).expect("d"),
1934 ge
1935 );
1936
1937 let fs = ServiceRequest::FindServers(FindServersRequest {
1938 request_header: req_header(),
1939 endpoint_url: String::from("opc.tcp://x:4840"),
1940 locale_ids: Vec::new(),
1941 server_uris: alloc::vec![String::from("urn:server")],
1942 });
1943 assert_eq!(
1944 ServiceRequest::decode(&fs.encode().expect("e")).expect("d"),
1945 fs
1946 );
1947
1948 let ger = ServiceResponse::GetEndpoints(GetEndpointsResponse {
1950 response_header: ResponseHeader::new(1, 0),
1951 endpoints: Vec::new(),
1952 });
1953 assert_eq!(
1954 ServiceResponse::decode(&ger.encode().expect("e")).expect("d"),
1955 ger
1956 );
1957 }
1958
1959 #[test]
1960 fn subscription_round_trips() {
1961 let cs = ServiceRequest::CreateSubscription(CreateSubscriptionRequest {
1962 request_header: req_header(),
1963 requested_publishing_interval: 500.0,
1964 requested_lifetime_count: 6000,
1965 requested_max_keep_alive_count: 20,
1966 max_notifications_per_publish: 0,
1967 publishing_enabled: true,
1968 priority: 5,
1969 });
1970 assert_eq!(
1971 ServiceRequest::decode(&cs.encode().expect("e")).expect("d"),
1972 cs
1973 );
1974
1975 let cm = ServiceRequest::CreateMonitoredItems(CreateMonitoredItemsRequest {
1976 request_header: req_header(),
1977 subscription_id: 1,
1978 timestamps_to_return: 0,
1979 items_to_create: alloc::vec![MonitoredItemCreateRequest {
1980 item_to_monitor: ReadValueId {
1981 node_id: NodeId::numeric(1, 1),
1982 attribute_id: ATTRIBUTE_VALUE,
1983 index_range: String::new(),
1984 data_encoding: QualifiedName {
1985 namespace_index: 0,
1986 name: String::new(),
1987 },
1988 },
1989 monitoring_mode: 2,
1990 requested_parameters: MonitoringParameters {
1991 client_handle: 7,
1992 sampling_interval: 250.0,
1993 filter: null_filter(),
1994 queue_size: 4,
1995 discard_oldest: true,
1996 },
1997 }],
1998 });
1999 assert_eq!(
2000 ServiceRequest::decode(&cm.encode().expect("e")).expect("d"),
2001 cm
2002 );
2003 }
2004
2005 #[test]
2006 fn publish_data_change_notification_round_trips() {
2007 let dcn = DataChangeNotification {
2009 monitored_items: alloc::vec![MonitoredItemNotification {
2010 client_handle: 7,
2011 value: DataValue::new_value(Variant::scalar(VariantValue::Int32(99)), 0, 0),
2012 }],
2013 };
2014 let eo = dcn.to_extension_object().expect("wrap");
2015 assert_eq!(
2016 DataChangeNotification::from_extension_object(&eo).expect("unwrap"),
2017 dcn
2018 );
2019
2020 let resp = ServiceResponse::Publish(PublishResponse {
2022 response_header: ResponseHeader::new(1, 0),
2023 subscription_id: 3,
2024 available_sequence_numbers: alloc::vec![1],
2025 more_notifications: false,
2026 notification_message: NotificationMessage {
2027 sequence_number: 1,
2028 publish_time: 0,
2029 notification_data: alloc::vec![eo],
2030 },
2031 results: Vec::new(),
2032 });
2033 assert_eq!(
2034 ServiceResponse::decode(&resp.encode().expect("e")).expect("d"),
2035 resp
2036 );
2037 }
2038
2039 #[test]
2040 fn call_round_trips() {
2041 let req = ServiceRequest::Call(CallRequest {
2042 request_header: req_header(),
2043 methods_to_call: alloc::vec![CallMethodRequest {
2044 object_id: NodeId::numeric(0, 0),
2045 method_id: NodeId::numeric(1, 100),
2046 input_arguments: alloc::vec![Variant::scalar(VariantValue::String(String::from(
2047 "group-1"
2048 )))],
2049 }],
2050 });
2051 let body = req.encode().expect("encode");
2052 assert_eq!(ServiceRequest::decode(&body).expect("decode"), req);
2053
2054 let resp = ServiceResponse::Call(CallResponse {
2055 response_header: ResponseHeader::new(1, 0),
2056 results: alloc::vec![CallMethodResult {
2057 status_code: 0,
2058 input_argument_results: alloc::vec![0],
2059 output_arguments: alloc::vec![Variant::scalar(VariantValue::UInt32(7))],
2060 }],
2061 });
2062 let rb = resp.encode().expect("encode");
2063 assert_eq!(ServiceResponse::decode(&rb).expect("decode"), resp);
2064 }
2065
2066 #[test]
2067 fn session_lifecycle_round_trips() {
2068 let close = ServiceRequest::CloseSession(CloseSessionRequest {
2069 request_header: req_header(),
2070 delete_subscriptions: true,
2071 });
2072 assert_eq!(
2073 ServiceRequest::decode(&close.encode().expect("e")).expect("d"),
2074 close
2075 );
2076
2077 let act = ServiceResponse::ActivateSession(ActivateSessionResponse {
2078 response_header: ResponseHeader::new(1, 0),
2079 server_nonce: alloc::vec![1, 2, 3],
2080 results: alloc::vec![0],
2081 });
2082 let _ = null_extension_object();
2083 assert_eq!(
2084 ServiceResponse::decode(&act.encode().expect("e")).expect("d"),
2085 act
2086 );
2087 }
2088}