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