orchestra_toolkit/hgtp/
message.rs

1/* Copyright 2024-2025 LEDR Technologies Inc.
2* This file is part of the Orchestra library, which helps developer use our Orchestra technology which is based on AvesTerra, owned and developped by Georgetown University, under license agreement with LEDR Technologies Inc.
3*
4* The Orchestra library is a free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or any later version.
5*
6* The Orchestra library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
7*
8* You should have received a copy of the GNU Lesser General Public License along with the Orchestra library. If not, see <https://www.gnu.org/licenses/>.
9*
10* If you have any questions, feedback or issues about the Orchestra library, you can contact us at support@ledr.io.
11*/
12
13use std::fmt::Debug;
14
15use crate::{
16    Aspect, Attribute, Category, Class, Command, Condition, Context, Entity, Event, HGTPError,
17    Method, Mode, Report, State, Tag, Token,
18};
19
20///
21/// Any message we send or receive over an HGTP stream
22///
23pub struct HGTPMessage {
24    pub frame: [u8; 1024],
25    pub unbounded: Vec<u8>,
26}
27
28impl Default for HGTPMessage {
29    fn default() -> Self {
30        Self {
31            frame: [0; 1024],
32            unbounded: Vec::new(),
33        }
34    }
35}
36
37mod packer;
38mod unpacker;
39
40pub use unpacker::*;
41
42impl Debug for HGTPMessage {
43    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
44        let bytes_raw_field_name = format!("bytes (hex  , len={})", self.unpack_bytes().len());
45        let bytes_str = String::from_utf8_lossy(self.unpack_bytes());
46        let bytes_str_field_name = format!("bytes (utf-8, len={})", bytes_str.len());
47
48        f.debug_struct("HGTPMessage")
49            .field("command", &self.unpack_command())
50            .field("error", &self.unpack_error_code())
51            .field("version", &self.unpack_version())
52            .field("report", &self.unpack_report())
53            .field("method", &self.unpack_method())
54            .field("attribute", &self.unpack_attribute())
55            .field("event", &self.unpack_event())
56            .field("mode", &self.unpack_mode())
57            .field("category", &self.unpack_category())
58            .field("class", &self.unpack_class())
59            .field("context", &self.unpack_context())
60            .field("aspect", &self.unpack_aspect())
61            .field("state", &self.unpack_state())
62            .field("precedence", &self.unpack_precedence())
63            .field("tag", &self.unpack_tag())
64            .field("condition", &self.unpack_condition())
65            .field("instance", &self.unpack_instance())
66            .field("offset", &self.unpack_offset())
67            .field("time", &self.unpack_time())
68            .field("index", &self.unpack_index())
69            .field("count", &self.unpack_count())
70            .field("parameter", &self.unpack_parameter())
71            .field("resultant", &self.unpack_resultant())
72            .field("timeout", &self.unpack_timeout())
73            // reserved
74            .field("entity", &self.unpack_entity())
75            .field("outlet", &self.unpack_outlet())
76            .field("auxiliary", &self.unpack_auxiliary())
77            .field("ancillary", &self.unpack_ancillary())
78            .field("authorization", &self.unpack_authorization())
79            .field("authority", &self.unpack_authority())
80            .field("name", &self.unpack_name())
81            .field("key", &self.unpack_key())
82            .field("extension", &self.unpack_extension())
83            .field(&bytes_raw_field_name, &hex::encode(self.unpack_bytes()))
84            .field(&bytes_str_field_name, &bytes_str)
85            .finish()
86    }
87}
88
89impl HGTPMessage {
90    pub fn pretty_print(&self) -> String {
91        let mut res = String::new();
92
93        match self.unpack_command() {
94            Ok(Command::Bye) => {}
95            Ok(command) => res.push_str(&format!("Command:     {:?}\n", command)),
96            Err(e) => res.push_str(&e.to_string()),
97        }
98
99        let mut did_print_error = false;
100        match self.unpack_error_code() {
101            Ok(HGTPError::Ok) => {}
102            Ok(error) => {
103                res.push_str(&format!("Error:       {:?}\n", error));
104                res.push_str(&format!("Extension:   {}\n", self.unpack_extension()));
105                res.push_str(&format!(
106                    "Error msg:   {}\n",
107                    String::from_utf8_lossy(self.unpack_bytes())
108                ));
109                did_print_error = true
110            }
111            Err(e) => res.push_str(&e.to_string()),
112        }
113
114        match self.unpack_version() {
115            0 => {}
116            version => res.push_str(&format!("Version:     {}\n", version)),
117        }
118
119        match self.unpack_report() {
120            Ok(Report::Null) => {}
121            Ok(report) => res.push_str(&format!("Report:      {:?}\n", report)),
122            Err(e) => res.push_str(&e.to_string()),
123        }
124
125        match self.unpack_method() {
126            Ok(Method::Null) => {}
127            Ok(method) => res.push_str(&format!("Method:      {:?}\n", method)),
128            Err(e) => res.push_str(&e.to_string()),
129        }
130
131        match self.unpack_attribute() {
132            Ok(Attribute::Null) => {}
133            Ok(attribute) => res.push_str(&format!("Attribute:   {:?}\n", attribute)),
134            Err(e) => res.push_str(&e.to_string()),
135        }
136
137        match self.unpack_event() {
138            Ok(Event::Null) => {}
139            Ok(event) => res.push_str(&format!("Event:       {:?}\n", event)),
140            Err(e) => res.push_str(&e.to_string()),
141        }
142
143        match self.unpack_mode() {
144            Ok(Mode::Null) => {}
145            Ok(mode) => res.push_str(&format!("Mode:        {:?}\n", mode)),
146            Err(e) => res.push_str(&e.to_string()),
147        }
148
149        match self.unpack_category() {
150            Ok(Category::Null) => {}
151            Ok(category) => res.push_str(&format!("Category:    {:?}\n", category)),
152            Err(e) => res.push_str(&e.to_string()),
153        }
154
155        match self.unpack_class() {
156            Ok(Class::Null) => {}
157            Ok(class) => res.push_str(&format!("Class:       {:?}\n", class)),
158            Err(e) => res.push_str(&e.to_string()),
159        }
160
161        match self.unpack_context() {
162            Ok(Context::Null) => {}
163            Ok(context) => res.push_str(&format!("Context:     {:?}\n", context)),
164            Err(e) => res.push_str(&e.to_string()),
165        }
166
167        match self.unpack_aspect() {
168            Ok(Aspect::Null) => {}
169            Ok(aspect) => res.push_str(&format!("Aspect:      {:?}\n", aspect)),
170            Err(e) => res.push_str(&e.to_string()),
171        }
172
173        match self.unpack_state() {
174            Ok(State::Null) => {}
175            Ok(state) => res.push_str(&format!("State:       {:?}\n", state)),
176            Err(e) => res.push_str(&e.to_string()),
177        }
178
179        match self.unpack_precedence() {
180            0 => {}
181            precedence => res.push_str(&format!("Precedence:  {}\n", precedence)),
182        }
183
184        match self.unpack_condition() {
185            Ok(Condition::Null) => {}
186            Ok(condition) => res.push_str(&format!("Condition:   {:?}\n", condition)),
187            Err(e) => res.push_str(&e.to_string()),
188        }
189
190        match self.unpack_instance() {
191            0 => {}
192            instance => res.push_str(&format!("Instance:    {}\n", instance)),
193        }
194
195        match self.unpack_offset() {
196            0 => {}
197            offset => res.push_str(&format!("Offset:      {}\n", offset)),
198        }
199
200        match self.unpack_time() {
201            Ok(time) => {
202                if time.unix_timestamp() != 0 {
203                    res.push_str(&format!("Time:        {}\n", time))
204                }
205            }
206            Err(e) => res.push_str(&e.to_string()),
207        }
208
209        match self.unpack_index() {
210            0 => {}
211            index => res.push_str(&format!("Index:       {}\n", index)),
212        }
213
214        match self.unpack_count() {
215            0 => {}
216            count => res.push_str(&format!("Count:       {}\n", count)),
217        }
218
219        match self.unpack_parameter() {
220            0 => {}
221            parameter => res.push_str(&format!("Parameter:   {}\n", parameter)),
222        }
223
224        match self.unpack_resultant() {
225            0 => {}
226            resultant => res.push_str(&format!("Resultant:   {}\n", resultant)),
227        }
228
229        match self.unpack_timeout() {
230            0 => {}
231            timeout => res.push_str(&format!("Timeout:     {}\n", timeout)),
232        }
233
234        match self.unpack_entity() {
235            Entity::NULL => {}
236            entity => res.push_str(&format!("Entity:      {}\n", entity)),
237        }
238
239        match self.unpack_outlet() {
240            Entity::NULL => {}
241            outlet => res.push_str(&format!("Outlet:      {}\n", outlet)),
242        }
243
244        match self.unpack_auxiliary() {
245            Entity::NULL => {}
246            auxiliary => res.push_str(&format!("Auxiliary:   {}\n", auxiliary)),
247        }
248
249        match self.unpack_ancillary() {
250            Entity::NULL => {}
251            ancillary => res.push_str(&format!("Ancillary:   {}\n", ancillary)),
252        }
253
254        match self.unpack_authorization() {
255            Token::NULL => {}
256            authorization => res.push_str(&format!("Authorization: {:?}\n", authorization)),
257        }
258
259        match self.unpack_authority() {
260            Token::NULL => {}
261            authority => res.push_str(&format!("Authority:   {:?}\n", authority)),
262        }
263
264        match self.unpack_name() {
265            Ok(name) => {
266                if !name.is_null() {
267                    res.push_str(&format!("Name:        {}\n", name))
268                }
269            }
270            Err(e) => res.push_str(&e.to_string()),
271        }
272
273        match self.unpack_key() {
274            Ok(key) => {
275                if !key.is_null() {
276                    res.push_str(&format!("Key:         {}\n", key))
277                }
278            }
279            Err(e) => res.push_str(&e.to_string()),
280        }
281
282        if !did_print_error {
283            match self.unpack_value() {
284                Ok(value) => {
285                    if value.get_tag() != Tag::Null || !value.get_bytes().is_empty() {
286                        res.push_str(&format!("Value:       {}\n", value))
287                    }
288                }
289                Err(e) => res.push_str(&e.to_string()),
290            }
291        }
292
293        if res.is_empty() {
294            res.push_str("< All fields are null >\n")
295        }
296
297        res
298    }
299}