Skip to main content

futu_backend/
proto_handler.rs

1// 内部协议处理框架。
2//
3// 管理内部 NN cmd_id 到处理函数的映射。C++ 对应两类注册点:
4// `M_NNProto_RegisterCallBack_OnPush(...)` 与
5// `M_NNProto_RegisterCallBack_OnReply(...)`,命令号来自
6// `FutuOpenD/Src/NNBase/NNBase_Define_ProtoCmd.h`。
7//
8// 这个 Rust registry 只负责 cmd_id → handler 分发,不在这里做 API proto
9// 与 backend proto 的双向翻译;翻译仍由各业务模块负责,避免形成第二套
10// 隐式协议映射表。
11
12use std::collections::HashMap;
13use std::sync::Arc;
14
15use async_trait::async_trait;
16use bytes::Bytes;
17use parking_lot::RwLock;
18
19/// 内部协议命令 ID 常量(对应 C++ NNBase_Define_ProtoCmd.h)
20pub mod nn_cmd {
21    // 登录/连接
22    pub const MAIN_LOGIN: u16 = 1001;
23    pub const SUB_LOGIN: u16 = 6001;
24    pub const MAIN_HEARTBEAT: u16 = 1003;
25    pub const SUB_HEARTBEAT: u16 = 6003;
26    pub const SESSION_KEY: u16 = 1004;
27    pub const SVR_NOTIFY: u16 = 1005;
28    pub const ERROR_CODE: u16 = 1306;
29    pub const PING: u16 = 1316;
30    pub const CONN_POINT: u16 = 1321;
31
32    // 行情
33    pub const QOT_PUSH: u16 = 6212;
34    pub const QOT_RIGHT: u16 = 6006;
35    pub const QOT_SUB: u16 = 6211;
36    pub const QOT_PULL_TICKER: u16 = 6128;
37    pub const QOT_PULL_TIMESHARE: u16 = 6160;
38    pub const QOT_PULL_KLINE: u16 = 6161;
39    pub const QOT_PULL_SEC_LIST: u16 = 6515;
40    pub const QOT_PULL_CAPITAL_DIST: u16 = 6514;
41    pub const QOT_PULL_CAPITAL_FLOW: u16 = 6516;
42    pub const QOT_MARKET_STATUS: u16 = 6823;
43
44    // 交易
45    pub const QUERY_ACC_LIST: u16 = 2008;
46    pub const TRD_HK_ORDER_PLACE: u16 = 2211;
47    pub const TRD_HK_ORDER_CHANGE: u16 = 2212;
48    pub const TRD_HK_ORDER_LIST: u16 = 2201;
49    pub const TRD_HK_DEAL_LIST: u16 = 2101;
50    pub const TRD_HK_ACC_INFO: u16 = 2023;
51}
52
53/// 推送处理器 trait
54#[async_trait]
55pub trait NNPushHandler: Send + Sync + 'static {
56    /// 处理后端推送
57    async fn on_push(&self, cmd_id: u16, body: Bytes);
58}
59
60/// 内部协议处理器注册表
61pub struct NNProtoRegistry {
62    push_handlers: RwLock<HashMap<u16, Arc<dyn NNPushHandler>>>,
63}
64
65impl NNProtoRegistry {
66    pub fn new() -> Self {
67        Self {
68            push_handlers: RwLock::new(HashMap::new()),
69        }
70    }
71
72    /// 注册推送处理器
73    pub fn register_push_handler(&self, cmd_id: u16, handler: Arc<dyn NNPushHandler>) {
74        self.push_handlers.write().insert(cmd_id, handler);
75    }
76
77    /// 分发推送
78    pub async fn dispatch_push(&self, cmd_id: u16, body: Bytes) {
79        let handler = {
80            let handlers = self.push_handlers.read();
81            handlers.get(&cmd_id).cloned()
82        };
83
84        if let Some(h) = handler {
85            h.on_push(cmd_id, body).await;
86        } else {
87            tracing::debug!(cmd_id = cmd_id, "unhandled backend push");
88        }
89    }
90}
91
92impl Default for NNProtoRegistry {
93    fn default() -> Self {
94        Self::new()
95    }
96}