clerk_fapi_rs/
clerk_http_client.rs1use log::{debug, error, warn};
2use parking_lot::RwLock;
3use reqwest::header::{HeaderMap, HeaderValue};
4use reqwest::{Client as ReqwestClient, Request, Response};
5use std::sync::Arc;
6
7use crate::{clerk_state::ClerkState, configuration::ClientKind};
8
9#[derive(Debug)]
11pub struct ClerkHttpClient {
12 inner: ReqwestClient,
13 state: Arc<RwLock<ClerkState>>,
14 client_kind: ClientKind,
15 dev_browser_token_id: RwLock<Option<String>>,
16}
17
18impl std::fmt::Display for ClerkHttpClient {
19 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
20 write!(f, "ClerkHttpClient")
21 }
22}
23
24impl ClerkHttpClient {
30 pub fn new(
32 client: ReqwestClient,
33 state: Arc<RwLock<ClerkState>>,
34 client_kind: ClientKind,
35 ) -> Self {
36 Self {
37 inner: client,
38 state,
39 client_kind,
40 dev_browser_token_id: RwLock::new(None),
41 }
42 }
43
44 pub fn set_dev_browser_token_id(&self, token_id: String) {
47 let mut write_guard = self.dev_browser_token_id.write();
48 *write_guard = Some(token_id);
49 }
50
51 fn process_request(&self, mut req: Request) -> Request {
53 let url = req.url_mut();
56 if self.client_kind == ClientKind::NonBrowser {
57 url.query_pairs_mut().append_pair("_is_native", "1");
58 }
59
60 let token_id = {
61 let read_guard = self.dev_browser_token_id.read();
62 read_guard.clone()
63 };
64
65 if let Some(dev_browser_token_id) = token_id {
66 url.query_pairs_mut()
67 .append_pair("__clerk_db_jwt", &dev_browser_token_id);
68 }
69
70 {
71 let mut state = self.state.write();
72 match state.authorization_header() {
73 Some(auth) => {
74 if let Ok(value) = HeaderValue::from_str(auth.as_str()) {
75 req.headers_mut().insert("Authorization", value);
76 } else {
77 error!("ClerkHttpClient: Failed to parse authorization header");
78 }
79 }
80 None => {
81 debug!("ClerkHttpClient: No authorization header available");
82 }
83 }
84 }
85
86 req
87 }
88
89 fn process_response(&self, resp: &Response) {
90 if let Some(auth_header) = resp.headers().get("Authorization") {
91 if let Ok(auth_str) = auth_header.to_str() {
92 let mut state = self.state.write();
93 state.set_authorization_header(Some(auth_str.to_string()));
94 } else {
95 error!("ClerkHttpClient: Failed to parse authorization header");
96 }
97 } else {
98 }
101 }
102
103 pub async fn execute(&self, request: Request) -> Result<Response, reqwest::Error> {
104 let processed_request = self.process_request(request);
110 let response = self.inner.execute(processed_request).await?;
111
112 self.process_response(&response);
128 Ok(response)
129 }
130
131 pub fn request<U: reqwest::IntoUrl>(
132 &self,
133 method: reqwest::Method,
134 url: U,
135 ) -> reqwest::RequestBuilder {
136 self.inner.request(method, url)
137 }
138
139 pub fn get<U: reqwest::IntoUrl>(&self, url: U) -> reqwest::RequestBuilder {
140 self.inner.get(url)
141 }
142
143 pub fn post<U: reqwest::IntoUrl>(&self, url: U) -> reqwest::RequestBuilder {
144 self.inner.post(url)
145 }
146
147 pub fn put<U: reqwest::IntoUrl>(&self, url: U) -> reqwest::RequestBuilder {
148 self.inner.put(url)
149 }
150
151 pub fn patch<U: reqwest::IntoUrl>(&self, url: U) -> reqwest::RequestBuilder {
152 self.inner.patch(url)
153 }
154
155 pub fn delete<U: reqwest::IntoUrl>(&self, url: U) -> reqwest::RequestBuilder {
156 self.inner.delete(url)
157 }
158
159 pub fn head<U: reqwest::IntoUrl>(&self, url: U) -> reqwest::RequestBuilder {
160 self.inner.head(url)
161 }
162}