Skip to main content

futu_codec/
frame.rs

1use bytes::Bytes;
2
3use crate::header::{FutuHeader, ProtoFmtType};
4
5/// **Stable API** — FutuOpenD 协议帧(帧头 + body)。
6///
7/// 44 字节 [`FutuHeader`] + 变长 [`bytes::Bytes`] body。SHA1 基于 body 明文
8/// 在 [`FutuFrame::new`] 中自动计算。加密在更上层(`futu-net`)完成。
9#[derive(Debug, Clone)]
10pub struct FutuFrame {
11    pub header: FutuHeader,
12    pub body: Bytes,
13}
14
15impl FutuFrame {
16    /// **Stable API** — 构造新协议帧,自动计算 body SHA1 + 填帧头。
17    pub fn new(proto_id: u32, serial_no: u32, body: Bytes) -> Self {
18        use sha1::{Digest, Sha1};
19
20        let mut hasher = Sha1::new();
21        hasher.update(&body);
22        let sha1_result = hasher.finalize();
23        let mut body_sha1 = [0u8; 20];
24        body_sha1.copy_from_slice(&sha1_result);
25
26        Self {
27            header: FutuHeader {
28                proto_id,
29                proto_fmt_type: ProtoFmtType::Protobuf,
30                proto_ver: 0,
31                serial_no,
32                body_len: body.len() as u32,
33                body_sha1,
34            },
35            body,
36        }
37    }
38
39    /// **Stable API** — 校验 body 的 SHA1 是否与帧头中的一致。
40    ///
41    /// 解密后立即调用,失败返 false → 上层报 `FutuError::Sha1Mismatch`。
42    #[must_use]
43    pub fn verify_sha1(&self) -> bool {
44        use sha1::{Digest, Sha1};
45
46        let mut hasher = Sha1::new();
47        hasher.update(&self.body);
48        let computed = hasher.finalize();
49        computed.as_slice() == self.header.body_sha1
50    }
51}
52
53#[cfg(test)]
54mod tests;