1use bytes::Bytes;
2
3use crate::header::{FutuHeader, ProtoFmtType};
4
5#[derive(Debug, Clone)]
9pub struct FutuFrame {
10 pub header: FutuHeader,
11 pub body: Bytes,
12}
13
14impl FutuFrame {
15 pub fn new(proto_id: u32, serial_no: u32, body: Bytes) -> Self {
17 use sha1::{Digest, Sha1};
18
19 let mut hasher = Sha1::new();
20 hasher.update(&body);
21 let sha1_result = hasher.finalize();
22 let mut body_sha1 = [0u8; 20];
23 body_sha1.copy_from_slice(&sha1_result);
24
25 Self {
26 header: FutuHeader {
27 proto_id,
28 proto_fmt_type: ProtoFmtType::Protobuf,
29 proto_ver: 0,
30 serial_no,
31 body_len: body.len() as u32,
32 body_sha1,
33 },
34 body,
35 }
36 }
37
38 pub fn verify_sha1(&self) -> bool {
40 use sha1::{Digest, Sha1};
41
42 let mut hasher = Sha1::new();
43 hasher.update(&self.body);
44 let computed = hasher.finalize();
45 computed.as_slice() == self.header.body_sha1
46 }
47}
48
49#[cfg(test)]
50mod tests {
51 use super::*;
52
53 #[test]
54 fn test_frame_sha1_verification() {
55 let body = Bytes::from_static(b"hello futu");
56 let frame = FutuFrame::new(1001, 1, body);
57 assert!(frame.verify_sha1());
58 }
59
60 #[test]
61 fn test_frame_sha1_mismatch() {
62 let body = Bytes::from_static(b"hello futu");
63 let mut frame = FutuFrame::new(1001, 1, body);
64 frame.header.body_sha1[0] ^= 0xFF; assert!(!frame.verify_sha1());
66 }
67}