1use serde::{Deserialize, Serialize};
31
32use crate::constants::protocol_header_value;
33
34pub const FRAME_HELLO: u8 = 0x01;
40pub const FRAME_HELLO_OK: u8 = 0x02;
42pub const FRAME_LIST_REQ: u8 = 0x10;
44pub const FRAME_LIST_REPLY: u8 = 0x11;
46pub const FRAME_META_REQ: u8 = 0x12;
48pub const FRAME_META_REPLY: u8 = 0x13;
50pub const FRAME_START: u8 = 0x20;
52pub const FRAME_READY: u8 = 0x21;
54pub const FRAME_BLOCK: u8 = 0x30;
56pub const FRAME_NAK: u8 = 0x31;
58pub const FRAME_REQ: u8 = 0x32;
61pub const FRAME_WAVE_DONE: u8 = 0x33;
63pub const FRAME_COMPLETE: u8 = 0x34;
65pub const FRAME_ERROR: u8 = 0xFF;
67
68pub fn frame_type(frame: &[u8]) -> Option<u8> {
70 frame.first().copied()
71}
72
73pub fn frame_payload(frame: &[u8]) -> &[u8] {
75 frame.get(1..).unwrap_or(&[])
76}
77
78pub fn control_frame<T: Serialize>(kind: u8, payload: &T) -> Vec<u8> {
84 let json = serde_json::to_vec(payload).unwrap_or_default();
85 let mut out = Vec::with_capacity(1 + json.len());
86 out.push(kind);
87 out.extend_from_slice(&json);
88 out
89}
90
91pub fn parse_control<'a, T: Deserialize<'a>>(frame: &'a [u8], kind: u8) -> Option<T> {
93 if frame.first() != Some(&kind) {
94 return None;
95 }
96 serde_json::from_slice(frame.get(1..)?).ok()
97}
98
99#[derive(Debug, Clone, Serialize, Deserialize)]
101pub struct Hello {
102 pub protocol: String,
104 pub token: String,
106}
107
108impl Hello {
109 pub fn new(token: &str) -> Self {
111 Hello {
112 protocol: protocol_header_value().to_string(),
113 token: token.to_string(),
114 }
115 }
116}
117
118#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
120#[serde(rename_all = "lowercase")]
121pub enum TransferKind {
122 Upload,
123 Download,
124}
125
126#[derive(Debug, Clone, Serialize, Deserialize)]
128pub struct StartRequest {
129 pub kind: TransferKind,
131 pub path: String,
133 #[serde(default)]
135 pub size: u64,
136 #[serde(default)]
138 pub mtime: u64,
139 #[serde(default)]
142 pub etag: String,
143 #[serde(default)]
145 pub compress: bool,
146 #[serde(default)]
148 pub mode: String,
149 #[serde(default)]
151 pub offset: u64,
152 #[serde(default)]
154 pub block_size: u64,
155 #[serde(default)]
161 pub window: u32,
162}
163
164#[derive(Debug, Clone, Serialize, Deserialize)]
166pub struct ReadyReply {
167 pub kind: TransferKind,
169 pub path: String,
171 #[serde(default)]
173 pub size: u64,
174 #[serde(default)]
176 pub mtime: u64,
177 #[serde(default)]
179 pub etag: String,
180 #[serde(default)]
182 pub compress: bool,
183 pub block_size: u64,
185 pub total_blocks: u32,
187 #[serde(default)]
189 pub offset: u64,
190 #[serde(default)]
193 pub received: Vec<[u64; 2]>,
194}
195
196#[derive(Debug, Clone, Serialize, Deserialize)]
198pub struct CompleteMessage {
199 pub ok: bool,
201 #[serde(default)]
203 pub size: u64,
204 #[serde(default, skip_serializing_if = "Option::is_none")]
206 pub error: Option<String>,
207}
208
209impl CompleteMessage {
210 pub fn ok(size: u64) -> Self {
212 CompleteMessage {
213 ok: true,
214 size,
215 error: None,
216 }
217 }
218
219 pub fn err(message: impl Into<String>) -> Self {
221 CompleteMessage {
222 ok: false,
223 size: 0,
224 error: Some(message.into()),
225 }
226 }
227}
228
229#[derive(Debug, Clone, Serialize, Deserialize)]
231pub struct ErrorMessage {
232 pub code: String,
234 pub message: String,
236}
237
238#[derive(Debug, Clone)]
244pub struct Block {
245 pub index: u32,
247 pub crc: u32,
249 pub raw_len: u32,
251 pub data: Vec<u8>,
253}
254
255pub fn block_frame(index: u32, crc: u32, raw_len: u32, data: &[u8]) -> Vec<u8> {
257 let mut out = Vec::with_capacity(1 + 12 + data.len());
258 out.push(FRAME_BLOCK);
259 out.extend_from_slice(&index.to_be_bytes());
260 out.extend_from_slice(&crc.to_be_bytes());
261 out.extend_from_slice(&raw_len.to_be_bytes());
262 out.extend_from_slice(data);
263 out
264}
265
266pub fn parse_block(frame: &[u8]) -> Option<Block> {
268 if frame.first() != Some(&FRAME_BLOCK) || frame.len() < 13 {
269 return None;
270 }
271 Some(Block {
272 index: u32::from_be_bytes(frame[1..5].try_into().ok()?),
273 crc: u32::from_be_bytes(frame[5..9].try_into().ok()?),
274 raw_len: u32::from_be_bytes(frame[9..13].try_into().ok()?),
275 data: frame[13..].to_vec(),
276 })
277}
278
279pub fn nak_frame(index: u32) -> Vec<u8> {
281 let mut out = vec![FRAME_NAK];
282 out.extend_from_slice(&index.to_be_bytes());
283 out
284}
285
286pub fn req_frame(indices: &[u32]) -> Vec<u8> {
288 let mut out = Vec::with_capacity(5 + indices.len() * 4);
289 out.push(FRAME_REQ);
290 out.extend_from_slice(&(indices.len() as u32).to_be_bytes());
291 for i in indices {
292 out.extend_from_slice(&i.to_be_bytes());
293 }
294 out
295}
296
297pub fn parse_req(frame: &[u8]) -> Option<Vec<u32>> {
299 if frame.first() != Some(&FRAME_REQ) || frame.len() < 5 {
300 return None;
301 }
302 let count = u32::from_be_bytes(frame[1..5].try_into().ok()?) as usize;
303 let mut out = Vec::with_capacity(count);
304 let mut off = 5usize;
305 for _ in 0..count {
306 if off + 4 > frame.len() {
307 return None;
308 }
309 out.push(u32::from_be_bytes(frame[off..off + 4].try_into().ok()?));
310 off += 4;
311 }
312 Some(out)
313}
314
315pub fn parse_nak(frame: &[u8]) -> Option<u32> {
317 if frame.first() != Some(&FRAME_NAK) || frame.len() < 5 {
318 return None;
319 }
320 Some(u32::from_be_bytes(frame[1..5].try_into().ok()?))
321}
322
323pub fn wave_done_frame() -> Vec<u8> {
325 vec![FRAME_WAVE_DONE]
326}
327
328pub fn crc32(data: &[u8]) -> u32 {
334 crc32fast::hash(data)
335}
336
337pub fn block_count(size: u64, block_size: u64) -> u32 {
343 let bs = block_size.max(1);
344 if size == 0 {
345 1
346 } else {
347 (size.div_ceil(bs)) as u32
348 }
349}
350
351pub fn block_bounds(index: u32, block_size: u64, size: u64) -> (u64, u64) {
353 let start = index as u64 * block_size;
354 let end = (start + block_size).min(size);
355 (start, end)
356}
357
358pub fn block_offset(index: u32, block_size: u64, offset: u64) -> u64 {
361 offset.saturating_add(index as u64 * block_size)
362}
363
364#[derive(Debug, Clone, Default)]
374pub struct BlockSet {
375 bits: Vec<u64>,
376 total: u32,
377 count: u32,
378}
379
380impl BlockSet {
381 pub fn new(total: u32) -> Self {
383 BlockSet {
384 bits: vec![0; (total as usize).div_ceil(64)],
385 total,
386 count: 0,
387 }
388 }
389
390 pub fn insert(&mut self, index: u32) {
392 if index >= self.total {
393 return;
394 }
395 let word = (index / 64) as usize;
396 let bit = 1u64 << (index % 64);
397 if self.bits[word] & bit == 0 {
398 self.bits[word] |= bit;
399 self.count += 1;
400 }
401 }
402
403 pub fn contains(&self, index: u32) -> bool {
405 index < self.total && (self.bits[(index / 64) as usize] & (1u64 << (index % 64))) != 0
406 }
407
408 pub fn count(&self) -> u32 {
410 self.count
411 }
412
413 pub fn total(&self) -> u32 {
415 self.total
416 }
417
418 pub fn missing(&self) -> Vec<u32> {
420 let mut out = Vec::new();
421 for i in 0..self.total {
422 if !self.contains(i) {
423 out.push(i);
424 }
425 }
426 out
427 }
428
429 pub fn seed_from_ranges(&mut self, block_size: u64, ranges: &[(u64, u64)]) {
432 let bs = block_size.max(1);
433 for &(start, end) in ranges {
434 if end <= start {
435 continue;
436 }
437 let first = (start / bs) as u32;
438 let last = ((end - 1) / bs) as u32; for i in first..=last {
440 self.insert(i);
441 }
442 }
443 }
444}
445
446pub fn missing_blocks(size: u64, block_size: u64, received: &[(u64, u64)]) -> Vec<u32> {
450 let total = block_count(size, block_size);
451 let mut set = BlockSet::new(total);
452 set.seed_from_ranges(block_size, received);
453 set.missing()
454}
455
456#[cfg(test)]
457mod tests {
458 use super::*;
459
460 #[test]
461 fn block_count_and_bounds() {
462 assert_eq!(block_count(0, 4), 1);
463 assert_eq!(block_count(10, 4), 3);
464 assert_eq!(block_count(8, 4), 2);
465 assert_eq!(block_bounds(1, 4, 10), (4, 8));
466 assert_eq!(block_bounds(2, 4, 10), (8, 10));
467 assert_eq!(block_offset(2, 4, 100), 108);
468 }
469
470 #[test]
471 fn crc_roundtrip_detects_corruption() {
472 let data = b"hello libfw block";
473 let crc = crc32(data);
474 let mut bad = data.to_vec();
475 bad[0] ^= 0xFF;
476 assert_ne!(crc, crc32(&bad));
477 assert_eq!(crc, crc32(data));
478 }
479
480 #[test]
481 fn block_frame_roundtrip() {
482 let data = vec![7u8; 100];
483 let frame = block_frame(42, 12345, 100, &data);
484 let parsed = parse_block(&frame).unwrap();
485 assert_eq!(parsed.index, 42);
486 assert_eq!(parsed.crc, 12345);
487 assert_eq!(parsed.raw_len, 100);
488 assert_eq!(parsed.data, data);
489 assert_eq!(frame_type(&frame), Some(FRAME_BLOCK));
490 }
491
492 #[test]
493 fn req_and_nak_roundtrip() {
494 let req = req_frame(&[0, 3, 7, 9]);
495 assert_eq!(parse_req(&req), Some(vec![0, 3, 7, 9]));
496 let nak = nak_frame(5);
497 assert_eq!(parse_nak(&nak), Some(5));
498 }
499
500 #[test]
501 fn block_set_tracks_verified_and_missing() {
502 let mut set = BlockSet::new(10);
503 assert_eq!(set.total(), 10);
504 set.insert(0);
505 set.insert(3);
506 set.insert(3); assert_eq!(set.count(), 2);
508 assert!(set.contains(0));
509 assert!(!set.contains(1));
510 assert_eq!(set.missing(), vec![1, 2, 4, 5, 6, 7, 8, 9]);
511 }
512
513 #[test]
514 fn seed_from_ranges_marks_overlapping_blocks() {
515 let mut set = BlockSet::new(3);
517 set.seed_from_ranges(4, &[(0, 4)]);
518 assert!(set.contains(0));
519 assert!(!set.contains(1));
520 let mut set = BlockSet::new(3);
521 set.seed_from_ranges(4, &[(4, 10)]);
522 assert!(set.contains(1));
523 assert!(set.contains(2));
524 assert!(!set.contains(0));
525 }
526
527 #[test]
528 fn missing_blocks_from_received_ranges() {
529 assert_eq!(missing_blocks(10, 4, &[(0, 4)]), vec![1, 2]);
531 assert_eq!(missing_blocks(10, 4, &[]), vec![0, 1, 2]);
533 assert_eq!(missing_blocks(10, 4, &[(0, 10)]), Vec::<u32>::new());
535 }
536
537 #[test]
538 fn control_frame_roundtrip() {
539 let hello = Hello::new("tok");
540 let frame = control_frame(FRAME_HELLO, &hello);
541 assert_eq!(frame_type(&frame), Some(FRAME_HELLO));
542 let parsed: Hello = parse_control(&frame, FRAME_HELLO).unwrap();
543 assert_eq!(parsed.token, "tok");
544 assert_eq!(parsed.protocol, protocol_header_value());
545 }
546}