1use crate::protocol::{message::Message, Header};
7
8#[derive(Debug, PartialEq, Clone)]
29pub struct Packet {
30 pub header: Header,
32
33 pub data: Vec<u8>,
35
36 pub parsed: Option<Message>,
38}
39
40impl Packet {
41 pub fn from_data(h: Header, d: &[u8]) -> Packet {
43 Packet {
44 header: h,
45 data: d.to_vec(),
46 parsed: None,
47 }
48 }
49
50 pub fn from_bytes(bytes: &[u8]) -> Self {
79 if bytes.len() < 10 {
81 return Packet {
82 header: Header::default(),
83 data: Vec::new(),
84 parsed: None,
85 };
86 }
87
88 let has_timecode = (bytes[0] & 0b00010000) != 0;
90 let header_size = if has_timecode { 14 } else { 10 };
91
92 if bytes.len() < header_size {
94 return Packet {
95 header: Header::default(),
96 data: Vec::new(),
97 parsed: None,
98 };
99 }
100
101 let header_bytes = &bytes[0..header_size];
102 let header = Header::from(header_bytes);
103 let data = &bytes[header_size..];
104
105 let mut parsed: Option<Message> = None;
106
107 if header.packet_type.reply {
108 parsed = match match header.id {
110 crate::protocol::ID::Control => match serde_json::from_slice(data) {
111 Ok(v) => Some(Message::Control(v)),
112 Err(_) => None,
113 },
114 crate::protocol::ID::Config => match serde_json::from_slice(data) {
115 Ok(v) => Some(Message::Config(v)),
116 Err(_) => None,
117 },
118 crate::protocol::ID::Status => match serde_json::from_slice(data) {
119 Ok(v) => Some(Message::Status(v)),
120 Err(_) => None,
121 },
122 _ => None,
123 } {
124 Some(v) => Some(v),
126
127 None => match header.id {
129 crate::protocol::ID::Control
130 | crate::protocol::ID::Config
131 | crate::protocol::ID::Status => match serde_json::from_slice(data) {
132 Ok(v) => Some(Message::Parsed((header.id, v))),
134 Err(_) => match std::str::from_utf8(data) {
136 Ok(v) => Some(Message::Unparsed((header.id, v.to_string()))),
137 Err(_) => None,
139 },
140 },
141 _ => None,
142 },
143 }
144 }
145 Packet {
146 header,
147 data: data.to_vec(),
148 parsed,
149 }
150 }
151}
152
153#[cfg(test)]
154mod tests {
155 use super::*;
156
157 #[test]
158 fn test_json() {
159 {
160 let data = vec![
161 0x44, 0x00, 0x0D, 0xFA, 0x00, 0x00, 0x00, 0x00, 0x01, 0x8E, 0x7b, 0x0a, 0x20, 0x20,
162 0x20, 0x20, 0x22, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x22, 0x3a, 0x0a, 0x20, 0x20,
163 0x20, 0x20, 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x67,
164 0x77, 0x22, 0x3a, 0x20, 0x22, 0x61, 0x2e, 0x62, 0x2e, 0x63, 0x2e, 0x64, 0x22, 0x2c,
165 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x69, 0x70, 0x22, 0x3a,
166 0x20, 0x22, 0x61, 0x2e, 0x62, 0x2e, 0x63, 0x2e, 0x64, 0x22, 0x2c, 0x0a, 0x20, 0x20,
167 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x6e, 0x6d, 0x22, 0x3a, 0x20, 0x22, 0x61,
168 0x2e, 0x62, 0x2e, 0x63, 0x2e, 0x64, 0x22, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20,
169 0x20, 0x20, 0x20, 0x22, 0x70, 0x6f, 0x72, 0x74, 0x73, 0x22, 0x3a, 0x0a, 0x20, 0x20,
170 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x5b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
171 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
172 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x6c, 0x22, 0x3a,
173 0x20, 0x33, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
174 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x70, 0x6f, 0x72, 0x74, 0x22, 0x3a, 0x20,
175 0x31, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
176 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x73, 0x73, 0x22, 0x3a, 0x20, 0x34, 0x2c, 0x0a,
177 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
178 0x20, 0x20, 0x22, 0x74, 0x73, 0x22, 0x3a, 0x20, 0x32, 0x0a, 0x20, 0x20, 0x20, 0x20,
179 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7d, 0x2c, 0x0a, 0x20, 0x20, 0x20,
180 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7b, 0x0a, 0x20, 0x20, 0x20,
181 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22,
182 0x6c, 0x22, 0x3a, 0x20, 0x37, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
183 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x70, 0x6f, 0x72, 0x74,
184 0x22, 0x3a, 0x20, 0x35, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
185 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x73, 0x73, 0x22, 0x3a, 0x20,
186 0x38, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
187 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x74, 0x73, 0x22, 0x3a, 0x20, 0x36, 0x0a, 0x20,
188 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7d, 0x0a, 0x20,
189 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x5d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x7d,
190 0x0a, 0x7d,
191 ];
192 let packet = Packet::from_bytes(&data);
193
194 assert_eq!(packet.header.length, 398);
195
196 match packet.parsed {
197 Some(p) => match p {
198 Message::Config(c) => {
199 assert_eq!(c.config.gw.unwrap(), "a.b.c.d");
200 assert_eq!(c.config.nm.unwrap(), "a.b.c.d");
201 assert_eq!(c.config.ports.len(), 2);
202 }
203 _ => panic!("not the right packet parsed"),
204 },
205 None => panic!("Packet parsing failed"),
206 }
207 }
208 }
209
210 #[test]
211 fn test_untyped() {
212 {
213 let data = vec![
214 0x44, 0x00, 0x0D, 0xFA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0x7B, 0x22, 0x68, 0x65,
215 0x6C, 0x6C, 0x6F, 0x22, 0x3A, 0x20, 0x22, 0x6F, 0x6B, 0x22, 0x7D,
216 ];
217 let packet = Packet::from_bytes(&data);
218
219 match packet.parsed {
220 Some(p) => match p {
221 Message::Parsed((_, p)) => {
222 assert_eq!(p["hello"], "ok");
223 }
224 _ => panic!("not the right packet parsed"),
225 },
226 None => panic!("Packet parsing failed"),
227 }
228 }
229 }
230
231 #[test]
232 fn test_unparsed() {
233 {
234 let data = vec![
235 0x44, 0x00, 0x0D, 0xFA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0E, 0x53, 0x4C, 0x49, 0x43,
236 0x4B, 0x44, 0x45, 0x4E, 0x49, 0x53, 0x34, 0x30, 0x30, 0x30,
237 ];
238 let packet = Packet::from_bytes(&data);
239
240 match packet.parsed {
241 Some(p) => match p {
242 Message::Unparsed((_, p)) => {
243 assert_eq!(p, "SLICKDENIS4000");
244 }
245 _ => panic!("not the right packet parsed"),
246 },
247 None => panic!("Packet parsing failed"),
248 }
249 }
250 }
251
252 use proptest::prelude::*;
254
255 proptest! {
256 #[test]
257 fn test_packet_header_roundtrip(
258 version in 0u8..4,
259 seq_num in 0u8..=15,
260 pixel_config in 0u8..=255,
261 id in 0u8..=255,
262 offset in 0u32..1000000,
263 length in 0u16..1500,
264 ) {
265 let mut packet_bytes = vec![
267 (version << 6) | 0b00000001, seq_num,
269 pixel_config,
270 id,
271 ];
272 packet_bytes.extend_from_slice(&offset.to_be_bytes());
273 packet_bytes.extend_from_slice(&length.to_be_bytes());
274
275 let data = vec![0u8; length.min(100) as usize];
277 packet_bytes.extend_from_slice(&data);
278
279 let packet = Packet::from_bytes(&packet_bytes);
281
282 prop_assert_eq!(packet.header.sequence_number, seq_num);
284 prop_assert_eq!(packet.header.offset, offset);
285 prop_assert_eq!(packet.header.length, length);
286 }
287
288 #[test]
289 fn test_packet_with_arbitrary_data(
290 data_len in 0usize..500,
291 seq_num in 1u8..=15,
292 ) {
293 let data: Vec<u8> = (0..data_len).map(|i| (i % 256) as u8).collect();
295
296 let mut packet_bytes = vec![
298 0x41, seq_num,
300 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, ];
304 let length = data.len() as u16;
305 packet_bytes.extend_from_slice(&length.to_be_bytes());
306 packet_bytes.extend_from_slice(&data);
307
308 let packet = Packet::from_bytes(&packet_bytes);
310
311 prop_assert_eq!(packet.data, data);
313 prop_assert_eq!(packet.header.sequence_number, seq_num);
314 }
315
316 #[test]
317 fn test_packet_parsing_never_panics(
318 bytes in prop::collection::vec(any::<u8>(), 10..1500)
319 ) {
320 let _ = Packet::from_bytes(&bytes);
323 }
324
325 #[test]
326 fn test_packet_with_timecode_roundtrip(
327 timecode in any::<u32>(),
328 seq_num in 1u8..=15,
329 data_len in 0usize..100,
330 ) {
331 let mut packet_bytes = vec![
333 0x51, seq_num,
335 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, ];
339
340 let data: Vec<u8> = (0..data_len).map(|i| (i % 256) as u8).collect();
341 let length = data.len() as u16;
342 packet_bytes.extend_from_slice(&length.to_be_bytes());
343 packet_bytes.extend_from_slice(&timecode.to_be_bytes());
344 packet_bytes.extend_from_slice(&data);
345
346 let packet = Packet::from_bytes(&packet_bytes);
347
348 prop_assert_eq!(packet.header.time_code.0, Some(timecode));
349 prop_assert_eq!(packet.data, data);
350 }
351
352 #[test]
353 fn test_offset_values_preserved(
354 offset in 0u32..4000000,
355 ) {
356 let mut packet_bytes = vec![
357 0x41, 1, 0x00, 0x01,
358 ];
359 packet_bytes.extend_from_slice(&offset.to_be_bytes());
360 packet_bytes.extend_from_slice(&[0x00, 0x03]); packet_bytes.extend_from_slice(&[255, 0, 0]); let packet = Packet::from_bytes(&packet_bytes);
364 prop_assert_eq!(packet.header.offset, offset);
365 }
366 }
367
368 #[test]
370 fn test_full_packet_roundtrip() {
371 use crate::protocol::{Header, PacketType, PixelConfig, ID, timecode::TimeCode};
372
373 let header = Header {
375 packet_type: PacketType {
376 version: 1,
377 timecode: false,
378 storage: false,
379 reply: false,
380 query: false,
381 push: true,
382 },
383 sequence_number: 5,
384 pixel_config: PixelConfig::default(),
385 id: ID::default(),
386 offset: 0,
387 length: 9,
388 time_code: TimeCode(None),
389 };
390
391 let data = vec![255, 0, 0, 0, 255, 0, 0, 0, 255];
393
394 let header_bytes: [u8; 10] = header.into();
396
397 let mut packet_bytes = header_bytes.to_vec();
399 packet_bytes.extend_from_slice(&data);
400
401 let parsed_packet = Packet::from_bytes(&packet_bytes);
403
404 assert_eq!(parsed_packet.header.sequence_number, 5);
406 assert_eq!(parsed_packet.header.length, 9);
407 assert_eq!(parsed_packet.data, data);
408 }
409
410 #[test]
411 fn test_packet_with_timecode_integration() {
412 use crate::protocol::{Header, PacketType, PixelConfig, ID, timecode::TimeCode};
413
414 let header = Header {
416 packet_type: PacketType {
417 version: 1,
418 timecode: true,
419 storage: false,
420 reply: false,
421 query: false,
422 push: true,
423 },
424 sequence_number: 3,
425 pixel_config: PixelConfig::default(),
426 id: ID::default(),
427 offset: 100,
428 length: 6,
429 time_code: TimeCode(Some(12345)),
430 };
431
432 let data = vec![128, 128, 128, 64, 64, 64];
434
435 let header_bytes: [u8; 14] = header.into();
437
438 let mut packet_bytes = header_bytes.to_vec();
440 packet_bytes.extend_from_slice(&data);
441
442 let parsed_packet = Packet::from_bytes(&packet_bytes);
444
445 assert_eq!(parsed_packet.header.sequence_number, 3);
447 assert_eq!(parsed_packet.header.length, 6);
448 assert_eq!(parsed_packet.header.offset, 100);
449 assert_eq!(parsed_packet.header.time_code.0, Some(12345));
450 assert_eq!(parsed_packet.data, data);
451 }
452
453 #[test]
454 fn test_packet_with_config_message_integration() {
455 use crate::protocol::{Header, PacketType, PixelConfig, ID, timecode::TimeCode};
456
457 let json = r#"{"config":{"gw":"192.168.1.1","ip":"192.168.1.100"}}"#;
458
459 let header = Header {
460 packet_type: PacketType {
461 version: 1,
462 timecode: false,
463 storage: false,
464 reply: true,
465 query: false,
466 push: false,
467 },
468 sequence_number: 1,
469 pixel_config: PixelConfig::default(),
470 id: ID::Config,
471 offset: 0,
472 length: json.len() as u16,
473 time_code: TimeCode(None),
474 };
475
476 let header_bytes: [u8; 10] = header.into();
477 let mut packet_bytes = header_bytes.to_vec();
478 packet_bytes.extend_from_slice(json.as_bytes());
479
480 let parsed_packet = Packet::from_bytes(&packet_bytes);
481
482 assert_eq!(parsed_packet.header.id, ID::Config);
483 assert!(parsed_packet.parsed.is_some());
484 }
485
486 #[test]
487 fn test_multiple_packets_different_sequences_integration() {
488 use crate::protocol::{Header, PacketType, PixelConfig, ID, timecode::TimeCode};
489
490 let test_cases = vec![
492 (1, vec![255, 0, 0]),
493 (5, vec![0, 255, 0]),
494 (10, vec![0, 0, 255]),
495 (15, vec![128, 128, 128]),
496 ];
497
498 for (seq_num, data) in test_cases {
499 let header = Header {
500 packet_type: PacketType {
501 version: 1,
502 timecode: false,
503 storage: false,
504 reply: false,
505 query: false,
506 push: true,
507 },
508 sequence_number: seq_num,
509 pixel_config: PixelConfig::default(),
510 id: ID::default(),
511 offset: 0,
512 length: data.len() as u16,
513 time_code: TimeCode(None),
514 };
515
516 let header_bytes: [u8; 10] = header.into();
517 let mut packet_bytes = header_bytes.to_vec();
518 packet_bytes.extend_from_slice(&data);
519
520 let parsed = Packet::from_bytes(&packet_bytes);
521 assert_eq!(parsed.header.sequence_number, seq_num);
522 assert_eq!(parsed.data, data);
523 }
524 }
525
526 #[test]
527 fn test_large_pixel_data_integration() {
528 use crate::protocol::{Header, PacketType, PixelConfig, ID, timecode::TimeCode};
529
530 let num_pixels = 480; let mut data = Vec::with_capacity(num_pixels * 3);
533
534 for i in 0..num_pixels {
535 data.push((i % 256) as u8);
536 data.push(((i * 2) % 256) as u8);
537 data.push(((i * 3) % 256) as u8);
538 }
539
540 let header = Header {
541 packet_type: PacketType {
542 version: 1,
543 timecode: false,
544 storage: false,
545 reply: false,
546 query: false,
547 push: true,
548 },
549 sequence_number: 1,
550 pixel_config: PixelConfig::default(),
551 id: ID::default(),
552 offset: 0,
553 length: data.len() as u16,
554 time_code: TimeCode(None),
555 };
556
557 let header_bytes: [u8; 10] = header.into();
558 let mut packet_bytes = header_bytes.to_vec();
559 packet_bytes.extend_from_slice(&data);
560
561 let parsed = Packet::from_bytes(&packet_bytes);
562 assert_eq!(parsed.data.len(), data.len());
563 assert_eq!(parsed.data, data);
564 }
565}