1use bytes::{Buf, BytesMut};
2use tokio_util::codec::{Decoder, Encoder};
3
4use crate::frame::FutuFrame;
5use crate::header::{FutuHeader, HEADER_SIZE};
6
7pub const MAX_FRAME_PACKAGE_SIZE: usize = 12 * 1024 * 1024;
14
15pub struct FutuCodec;
20
21impl Decoder for FutuCodec {
22 type Item = FutuFrame;
23 type Error = futu_core::error::FutuError;
24
25 fn decode(&mut self, src: &mut BytesMut) -> Result<Option<Self::Item>, Self::Error> {
26 let header = match FutuHeader::peek(src)? {
28 Some(h) => h,
29 None => return Ok(None),
30 };
31
32 let body_len = header.body_len as usize;
33 let total_len = HEADER_SIZE.checked_add(body_len).ok_or_else(|| {
34 futu_core::error::FutuError::Codec("Futu frame length overflow".into())
35 })?;
36 if total_len > MAX_FRAME_PACKAGE_SIZE {
37 return Err(futu_core::error::FutuError::Codec(format!(
38 "Futu frame package too large: actual={total_len} max={MAX_FRAME_PACKAGE_SIZE}"
39 )));
40 }
41
42 if src.len() < total_len {
44 src.reserve(total_len - src.len());
45 return Ok(None);
46 }
47
48 src.advance(HEADER_SIZE);
50
51 let body = src.split_to(body_len).freeze();
53
54 let frame = FutuFrame { header, body };
55
56 Ok(Some(frame))
57 }
58}
59
60impl Encoder<FutuFrame> for FutuCodec {
61 type Error = futu_core::error::FutuError;
62
63 fn encode(&mut self, item: FutuFrame, dst: &mut BytesMut) -> Result<(), Self::Error> {
64 item.header.encode(dst);
65 dst.extend_from_slice(&item.body);
66 Ok(())
67 }
68}
69
70#[cfg(test)]
71mod tests;