Skip to main content

futu_backend/
crypto_trade_notify_push.rs

1//! C++ release-compatible decoders for CMD20648/CMD20635 crypto trade pushes.
2
3use futu_core::error::{FutuError, Result};
4use prost::Message;
5
6#[derive(Debug, Clone, PartialEq, Eq)]
7pub struct CryptoOrderNotifyHeader {
8    pub req_id: Option<Vec<u8>>,
9    pub account_id: Option<u64>,
10    pub exchange: Option<String>,
11    pub security_type: Option<u32>,
12}
13
14#[derive(Debug, Clone, PartialEq, Eq)]
15pub struct CryptoOrderOpResult {
16    pub code: Option<i32>,
17    pub msg: Option<String>,
18}
19
20#[derive(Debug, Clone, PartialEq, Eq)]
21pub struct CryptoOrderNotifyPush {
22    pub header: Option<CryptoOrderNotifyHeader>,
23    pub notice_type: Option<u32>,
24    pub order_ids: Vec<String>,
25    pub order_fill_ids: Vec<String>,
26    pub op_result: Option<CryptoOrderOpResult>,
27}
28
29#[derive(Debug, Clone, PartialEq, Eq)]
30pub struct CryptoAssetNotifyHeader {
31    pub req_id: Option<Vec<u8>>,
32    pub account_id: Option<u64>,
33}
34
35#[derive(Debug, Clone, PartialEq, Eq)]
36pub struct CryptoAssetNotifyPush {
37    pub notice_header: Option<CryptoAssetNotifyHeader>,
38    pub notice_type: Option<i32>,
39    pub ext_msg: Option<String>,
40}
41
42pub fn decode_crypto_order_notify_push(body: &[u8]) -> Result<CryptoOrderNotifyPush> {
43    let wire = CryptoOrderNotifyWire::decode(body)
44        .map_err(|error| FutuError::Codec(format!("CMD20648 decode: {error}")))?;
45    Ok(CryptoOrderNotifyPush {
46        header: wire.header.map(CryptoOrderNotifyHeader::from),
47        notice_type: wire.notice_type,
48        order_ids: wire.order_ids,
49        order_fill_ids: wire.order_fill_ids,
50        op_result: wire.op_result.map(CryptoOrderOpResult::from),
51    })
52}
53
54pub fn decode_crypto_asset_notify_push(body: &[u8]) -> Result<CryptoAssetNotifyPush> {
55    let wire = CryptoAssetNotifyWire::decode(body)
56        .map_err(|error| FutuError::Codec(format!("CMD20635 decode: {error}")))?;
57    Ok(CryptoAssetNotifyPush {
58        notice_header: wire.notice_header.map(CryptoAssetNotifyHeader::from),
59        notice_type: wire.notice_type,
60        ext_msg: wire.ext_msg,
61    })
62}
63
64impl From<CryptoOrderNotifyHeaderWire> for CryptoOrderNotifyHeader {
65    fn from(wire: CryptoOrderNotifyHeaderWire) -> Self {
66        Self {
67            req_id: wire.req_id,
68            account_id: wire.account_id,
69            exchange: wire.exchange,
70            security_type: wire.security_type,
71        }
72    }
73}
74
75impl From<CryptoOrderOpResultWire> for CryptoOrderOpResult {
76    fn from(wire: CryptoOrderOpResultWire) -> Self {
77        Self {
78            code: wire.code,
79            msg: wire.msg,
80        }
81    }
82}
83
84impl From<CryptoAssetNotifyHeaderWire> for CryptoAssetNotifyHeader {
85    fn from(wire: CryptoAssetNotifyHeaderWire) -> Self {
86        Self {
87            req_id: wire.req_id,
88            account_id: wire.account_id,
89        }
90    }
91}
92
93#[derive(Clone, PartialEq, Message)]
94struct CryptoOrderNotifyWire {
95    #[prost(message, optional, tag = "1")]
96    header: Option<CryptoOrderNotifyHeaderWire>,
97    #[prost(uint32, optional, tag = "2")]
98    notice_type: Option<u32>,
99    #[prost(string, repeated, tag = "3")]
100    order_ids: Vec<String>,
101    #[prost(string, repeated, tag = "4")]
102    order_fill_ids: Vec<String>,
103    #[prost(message, optional, tag = "5")]
104    op_result: Option<CryptoOrderOpResultWire>,
105}
106
107#[derive(Clone, PartialEq, Eq, Message)]
108struct CryptoOrderNotifyHeaderWire {
109    /// C++ protobuf parsing accepts opaque proto2 string bytes. The handler
110    /// does not consume req_id, so retaining bytes avoids a stricter Rust-only
111    /// UTF-8 admission rule.
112    #[prost(bytes = "vec", optional, tag = "1")]
113    req_id: Option<Vec<u8>>,
114    #[prost(uint64, optional, tag = "2")]
115    account_id: Option<u64>,
116    #[prost(string, optional, tag = "3")]
117    exchange: Option<String>,
118    #[prost(uint32, optional, tag = "4")]
119    security_type: Option<u32>,
120}
121
122#[derive(Clone, PartialEq, Eq, Message)]
123struct CryptoOrderOpResultWire {
124    #[prost(int32, optional, tag = "1")]
125    code: Option<i32>,
126    #[prost(string, optional, tag = "2")]
127    msg: Option<String>,
128}
129
130#[derive(Clone, PartialEq, Message)]
131struct CryptoAssetNotifyWire {
132    #[prost(message, optional, tag = "1")]
133    notice_header: Option<CryptoAssetNotifyHeaderWire>,
134    #[prost(int32, optional, tag = "2")]
135    notice_type: Option<i32>,
136    #[prost(string, optional, tag = "3")]
137    ext_msg: Option<String>,
138}
139
140#[derive(Clone, PartialEq, Eq, Message)]
141struct CryptoAssetNotifyHeaderWire {
142    /// Same opaque req-id rule as CMD20648.
143    #[prost(bytes = "vec", optional, tag = "1")]
144    req_id: Option<Vec<u8>>,
145    #[prost(uint64, optional, tag = "2")]
146    account_id: Option<u64>,
147}