Skip to main content

futu_rest/adapter/
state.rs

1//! Split from adapter.rs: state.
2//!
3//! pub items: RestState.
4
5use std::sync::Arc;
6
7use super::*;
8
9/// REST 服务共享状态
10#[derive(Clone)]
11pub struct RestState {
12    /// 复用 OpenD 的请求路由器
13    pub router: Arc<RequestRouter>,
14    /// WebSocket 推送广播器
15    pub ws_broadcaster: Arc<WsBroadcaster>,
16    /// Bearer Token KeyStore(未配置 → is_configured() == false,WS 握手也放行)
17    pub key_store: Arc<KeyStore>,
18    /// v1.2:handler 层 full CheckCtx 用的限额计数器(与 auth middleware
19    /// 共享同一份 Arc,rate window 跨 auth/handler 一致)
20    pub counters: Arc<futu_auth::RuntimeCounters>,
21    /// v1.4.104 阶段 7-1: 跨 surface response filter 注册表 (proto 2001
22    /// TRD_GET_ACC_LIST 默认装入). 替代 routes/trd.rs::get_acc_list 内联
23    /// JSON-level filter (35 LoC), 走 proto-bytes-level filter unified with
24    /// gRPC + WS surface (FilterRegistry::apply). 加新 filter 只在 registry
25    /// 注册一次, 4 surface 自动生效.
26    pub filter_registry: Arc<futu_auth_pipeline::FilterRegistry>,
27    /// v1.4.32+ daemon admin 状态快照 provider(`/api/admin/status` 用)
28    pub admin_status_provider: Option<AdminStatusProvider>,
29    /// v1.4.32+ daemon admin reload handler(`/api/admin/reload` 用)
30    pub admin_reload_handler: Option<AdminReloadHandler>,
31    /// v1.4.83 §9 Phase 2 F5: Push channel health snapshot provider
32    /// (`/api/push-subscriber-info` 真实 state — 不是 stub 文案)
33    pub push_health_snapshot_provider: Option<PushHealthSnapshotProvider>,
34    /// v1.4.105 D12 (Phase 2): card_num → acc_ids 解析器, REST trade handler
35    /// 在 dispatch 前用于解析 user 传 `card_num` 字段 → acc_id. 未注入 →
36    /// trade endpoint 收到 card_num 字段时 503 reject (loud — 让 user 知道
37    /// daemon 配置问题, 不 silent fall back acc_id).
38    pub card_num_resolver: Option<CardNumResolver>,
39    /// 虚拟连接 ID 分配器(REST 请求从 10_000_000 开始)
40    conn_id_counter: Arc<AtomicU64>,
41    /// 序列号分配器
42    serial_counter: Arc<AtomicU32>,
43    /// v1.4.102 codex 46 F2/F3 (P1): REST sub-acc-push 状态 (per API key).
44    ///
45    /// 之前 REST sub-acc-push 透 dispatch 到 gateway SubscriptionManager 但用
46    /// REST 临时虚拟 conn_id, unsub 用新 conn_id 删不到; 即使 sub OK, REST
47    /// WsBroadcaster 也没基于这个 state 过滤 trade push (只按 scope), 等于
48    /// 所有 acc:read 持有者收所有 trade push, sub-acc-push/unsub-acc-push 是空操作.
49    ///
50    /// 此 map 是 REST 层 per-key acc subscription 真相源:
51    /// - `/api/sub-acc-push` 写入 (key_id → set of acc_id)
52    /// - `/api/unsub-acc-push` 删除
53    /// - WsBroadcaster trade push delivery 检查: key 已 sub 此 acc 才 forward
54    ///
55    /// `None` (key 未 sub-acc-push) → 默认 deliver 所有 acc:read scope 的 push
56    /// (向后兼容, 兼容未升级老 client).
57    pub rest_acc_subscriptions: RestAccSubscriptions,
58}
59
60impl RestState {
61    pub fn new(router: Arc<RequestRouter>, ws_broadcaster: Arc<WsBroadcaster>) -> Self {
62        Self::with_key_store(router, ws_broadcaster, Arc::new(KeyStore::empty()))
63    }
64
65    pub fn with_key_store(
66        router: Arc<RequestRouter>,
67        ws_broadcaster: Arc<WsBroadcaster>,
68        key_store: Arc<KeyStore>,
69    ) -> Self {
70        Self::with_auth(
71            router,
72            ws_broadcaster,
73            key_store,
74            Arc::new(futu_auth::RuntimeCounters::new()),
75        )
76    }
77
78    /// v1.2 推荐入口:同时接 KeyStore + 共享 RuntimeCounters
79    pub fn with_auth(
80        router: Arc<RequestRouter>,
81        ws_broadcaster: Arc<WsBroadcaster>,
82        key_store: Arc<KeyStore>,
83        counters: Arc<futu_auth::RuntimeCounters>,
84    ) -> Self {
85        Self {
86            router,
87            ws_broadcaster,
88            key_store,
89            counters,
90            filter_registry: Arc::new(futu_auth_pipeline::FilterRegistry::with_defaults()),
91            admin_status_provider: None,
92            admin_reload_handler: None,
93            push_health_snapshot_provider: None,
94            card_num_resolver: None,
95            conn_id_counter: Arc::new(AtomicU64::new(10_000_000)),
96            serial_counter: Arc::new(AtomicU32::new(1)),
97            rest_acc_subscriptions: Arc::new(RwLock::new(HashMap::new())),
98        }
99    }
100
101    /// v1.4.104 阶段 7-1: 注入显式 FilterRegistry (跨 surface 共享同一份).
102    /// 默认 with_defaults 已注册 proto 2001; 此 setter 让调用方覆盖.
103    pub fn with_filter_registry(
104        mut self,
105        registry: Arc<futu_auth_pipeline::FilterRegistry>,
106    ) -> Self {
107        self.filter_registry = registry;
108        self
109    }
110
111    /// v1.4.32+ 注入 admin status provider(一般在 futu-opend main 里
112    /// 注入一个捕获 `Arc<GatewayBridge>` 的 closure)。
113    pub fn with_admin_status_provider(mut self, provider: AdminStatusProvider) -> Self {
114        self.admin_status_provider = Some(provider);
115        self
116    }
117
118    /// v1.4.32+ 注入 admin reload handler
119    pub fn with_admin_reload_handler(mut self, handler: AdminReloadHandler) -> Self {
120        self.admin_reload_handler = Some(handler);
121        self
122    }
123
124    /// v1.4.83 §9 Phase 2 F5: 注入 push health snapshot provider.
125    pub fn with_push_health_snapshot_provider(
126        mut self,
127        provider: PushHealthSnapshotProvider,
128    ) -> Self {
129        self.push_health_snapshot_provider = Some(provider);
130        self
131    }
132
133    /// v1.4.105 D12 (Phase 2): 注入 card_num → acc_ids 解析器 closure.
134    /// opend 启动时由 main.rs 注入捕获 `bridge.caches.trd_cache` 的 closure. 未注入
135    /// → trade endpoint 收 card_num 字段时 503 reject (loud).
136    pub fn with_card_num_resolver(mut self, resolver: CardNumResolver) -> Self {
137        self.card_num_resolver = Some(resolver);
138        self
139    }
140
141    /// 分配虚拟连接 ID
142    pub fn next_conn_id(&self) -> u64 {
143        self.conn_id_counter.fetch_add(1, Ordering::Relaxed)
144    }
145
146    /// 分配序列号
147    pub fn next_serial(&self) -> u32 {
148        self.serial_counter.fetch_add(1, Ordering::Relaxed)
149    }
150}