futu_backend/auth/
http_client.rs1use futu_core::error::{FutuError, Result};
10
11pub fn build_http_client(client_type: u8) -> Result<reqwest::Client> {
12 build_http_client_with_resolve(client_type, None)
13}
14
15pub(crate) fn build_http_client_with_resolve(
16 client_type: u8,
17 resolve: Option<(&str, std::net::SocketAddr)>,
18) -> Result<reqwest::Client> {
19 let mut default_headers = reqwest::header::HeaderMap::new();
38 default_headers.insert(
39 "X-Futu-Client-Type",
40 http_header_value("X-Futu-Client-Type", client_type)?,
41 );
42 default_headers.insert(
43 "X-Futu-Client-Version",
44 http_header_value(
45 "X-Futu-Client-Version",
46 crate::conn::BackendConn::CLIENT_VER_FTGTW,
47 )?,
48 );
49 default_headers.insert(
50 "X-Futu-Client-Lang",
51 reqwest::header::HeaderValue::from_static("sc"),
52 );
53 default_headers.insert(
54 "Content-Type",
55 reqwest::header::HeaderValue::from_static("application/json"),
56 );
57
58 let mut builder = reqwest::Client::builder()
59 .timeout(std::time::Duration::from_secs(15))
60 .default_headers(default_headers);
61 if let Some((domain, addr)) = resolve {
62 builder = builder.resolve(domain, addr);
63 }
64 builder
65 .build()
66 .map_err(|e| FutuError::Encryption(format!("http client: {e}")))
67}
68
69fn http_header_value(
70 name: &'static str,
71 value: impl std::fmt::Display,
72) -> Result<reqwest::header::HeaderValue> {
73 reqwest::header::HeaderValue::from_str(&value.to_string())
74 .map_err(|e| FutuError::Codec(format!("{name}: invalid header value: {e}")))
75}