futu_mcp/tools/
authenticated_rest.rs1use std::sync::OnceLock;
4use std::time::Duration;
5
6use serde::Serialize;
7
8const OPEND_REST_FORWARD_TIMEOUT: Duration = Duration::from_secs(12);
11
12fn forward_client() -> anyhow::Result<&'static reqwest::Client> {
15 static CLIENT: OnceLock<reqwest::Client> = OnceLock::new();
16 if let Some(client) = CLIENT.get() {
17 return Ok(client);
18 }
19 let built = futu_core::http_client::webpki_builder()
20 .timeout(OPEND_REST_FORWARD_TIMEOUT)
21 .build()?;
22 Ok(CLIENT.get_or_init(|| built))
23}
24
25pub(super) async fn post_json<T: Serialize>(
26 base_url: &str,
27 path: &str,
28 bearer: &str,
29 c2s: &T,
30 operation: &str,
31) -> anyhow::Result<String> {
32 let response = forward_client()?
33 .post(format!("{}{}", base_url.trim_end_matches('/'), path))
34 .bearer_auth(bearer)
35 .json(c2s)
36 .send()
37 .await?;
38 let status = response.status();
39 let body = response.text().await?;
40 if !status.is_success() {
41 anyhow::bail!("OpenD REST {operation} failed with HTTP {status}: {body}");
42 }
43 let value: serde_json::Value = serde_json::from_str(&body)?;
44 Ok(serde_json::to_string_pretty(&value)?)
45}