longbridge_httpcli/
client.rs1use std::sync::{Arc, LazyLock};
2
3use longbridge_geo::DcRegion;
4use reqwest::{
5 Client, Method,
6 header::{HeaderMap, HeaderName, HeaderValue},
7};
8use serde::Deserialize;
9
10use crate::{
11 AuthConfig, HttpClientConfig, HttpClientError, HttpClientResult, Json, RequestBuilder,
12};
13
14static SHARED_HTTP_CLIENT: LazyLock<Client> = LazyLock::new(Client::new);
24
25#[derive(Clone)]
27pub struct HttpClient {
28 pub(crate) http_cli: Client,
29 pub(crate) config: Arc<HttpClientConfig>,
30 pub(crate) default_headers: HeaderMap,
31}
32
33impl HttpClient {
34 pub fn new(config: HttpClientConfig) -> Self {
36 Self {
37 http_cli: SHARED_HTTP_CLIENT.clone(),
38 config: Arc::new(config),
39 default_headers: HeaderMap::new(),
40 }
41 }
42
43 pub fn header<K, V>(mut self, key: K, value: V) -> Self
45 where
46 K: TryInto<HeaderName>,
47 V: TryInto<HeaderValue>,
48 {
49 let key = key.try_into();
50 let value = value.try_into();
51 if let (Ok(key), Ok(value)) = (key, value) {
52 self.default_headers.insert(key, value);
53 }
54 self
55 }
56
57 pub async fn dc_region(&self) -> DcRegion {
61 match &self.config.auth {
62 AuthConfig::ApiKey {
63 app_key,
64 app_secret,
65 access_token,
66 } => DcRegion::from_credentials(&[app_key, access_token, app_secret]),
67 AuthConfig::OAuth(oauth) => oauth
68 .access_token()
69 .await
70 .map(|token| DcRegion::from_credential(&token))
71 .unwrap_or(DcRegion::Ap),
72 }
73 }
74
75 #[inline]
77 pub fn request(
78 &self,
79 method: Method,
80 path: impl Into<String>,
81 ) -> RequestBuilder<'_, (), (), ()> {
82 RequestBuilder::new(self, method, path)
83 }
84
85 pub async fn get_otp(&self) -> HttpClientResult<String> {
89 #[derive(Debug, Deserialize)]
90 struct Response {
91 otp: String,
92 limit: i32,
93 online: i32,
94 }
95
96 let resp = self
97 .request(Method::GET, "/v1/socket/token")
98 .response::<Json<Response>>()
99 .send()
100 .await?
101 .0;
102 tracing::info!(limit = resp.limit, online = resp.online, "create otp");
103
104 if resp.online >= resp.limit {
105 return Err(HttpClientError::ConnectionLimitExceeded {
106 limit: resp.limit,
107 online: resp.online,
108 });
109 }
110
111 Ok(resp.otp)
112 }
113}