futu_backend/
valid_brokers.rs1use futu_core::error::{FutuError, Result};
22use prost::Message;
23
24use crate::conn::BackendConn;
25use crate::proto_internal::ft_conn_bind::{GetValidBrokerListReq, GetValidBrokerListRsp};
26
27pub const CMD_FETCH_VALID_BROKER_LIST: u16 = 20176;
29
30pub async fn fetch_valid_broker_list(backend: &BackendConn, uid: u64) -> Result<Vec<u32>> {
33 let req = GetValidBrokerListReq { uid: Some(uid) };
34 let body = req.encode_to_vec();
35 tracing::debug!(
36 uid,
37 body_len = body.len(),
38 "sending CMD20176 GetValidBrokerListReq"
39 );
40
41 let resp = backend.request(CMD_FETCH_VALID_BROKER_LIST, body).await?;
42
43 let rsp = GetValidBrokerListRsp::decode(resp.body.as_ref())
44 .map_err(|e| FutuError::Codec(format!("CMD20176 decode: {e}")))?;
45
46 let ret_code = rsp.ret_code.unwrap_or(-1);
47 if ret_code != 0 {
48 return Err(FutuError::ServerError {
49 ret_type: ret_code,
50 msg: format!(
51 "CMD20176 ret_code={ret_code} msg={:?}",
52 rsp.ret_msg.as_deref().unwrap_or("")
53 ),
54 });
55 }
56
57 tracing::info!(
58 uid = rsp.uid.unwrap_or(0),
59 count = rsp.broker_ids.len(),
60 broker_ids = ?rsp.broker_ids,
61 "CMD20176 valid broker list received"
62 );
63 Ok(rsp.broker_ids)
64}
65
66pub fn diff_broker_sources(auth_code_broker_ids: &[u32], cmd20176_broker_ids: &[u32]) -> Vec<u32> {
72 use std::collections::HashSet;
73 let auth_set: HashSet<u32> = auth_code_broker_ids.iter().copied().collect();
74 let cmd_set: HashSet<u32> = cmd20176_broker_ids.iter().copied().collect();
75
76 let only_auth: Vec<u32> = auth_set.difference(&cmd_set).copied().collect();
77 let only_cmd: Vec<u32> = cmd_set.difference(&auth_set).copied().collect();
78
79 if !only_auth.is_empty() || !only_cmd.is_empty() {
80 tracing::warn!(
81 only_in_auth_code_list = ?only_auth,
82 only_in_cmd20176 = ?only_cmd,
83 "broker source mismatch: HTTP auth_code_list vs CMD20176 differ — \
84 using auth_code_list as authority (MVP)"
85 );
86 } else {
87 tracing::debug!(
88 count = auth_code_broker_ids.len(),
89 "broker source consistent between auth_code_list and CMD20176"
90 );
91 }
92
93 auth_code_broker_ids.to_vec()
95}
96
97#[cfg(test)]
98mod tests;