1use std::sync::{Arc, Mutex};
6use std::time::Duration;
7
8use async_trait::async_trait;
9use agentlink_core::http::{HttpClient, HttpMethod, HttpRequest, HttpResponse};
10use agentlink_core::error::SdkResult;
11use reqwest::{Client, Method};
12
13pub struct NativeHttpClient {
15 client: Client,
16 base_url: String,
17 auth_token: Arc<Mutex<Option<String>>>,
18}
19
20impl NativeHttpClient {
21 pub fn new(base_url: impl Into<String>) -> Self {
22 let client = Client::builder()
23 .timeout(Duration::from_secs(30))
24 .connect_timeout(Duration::from_secs(10))
25 .http1_only()
26 .user_agent("AgentLink-SDK-Native/1.0")
27 .no_proxy()
28 .build()
29 .expect("Failed to create HTTP client");
30
31 Self {
32 client,
33 base_url: base_url.into(),
34 auth_token: Arc::new(Mutex::new(None)),
35 }
36 }
37
38 fn method_to_reqwest(method: HttpMethod) -> Method {
39 match method {
40 HttpMethod::Get => Method::GET,
41 HttpMethod::Post => Method::POST,
42 HttpMethod::Put => Method::PUT,
43 HttpMethod::Delete => Method::DELETE,
44 HttpMethod::Patch => Method::PATCH,
45 }
46 }
47
48 fn get_token(&self) -> Option<String> {
50 self.auth_token.lock().unwrap().clone()
51 }
52}
53
54#[async_trait]
55impl HttpClient for NativeHttpClient {
56 async fn request(&self, request: HttpRequest) -> SdkResult<HttpResponse> {
57 let url = if request.url.starts_with("http") {
58 request.url.clone()
59 } else {
60 format!("{}{}", self.base_url, request.url)
61 };
62
63 eprintln!("[NativeHttpClient] 发送请求: {:?} {}", request.method, url);
64 eprintln!("[NativeHttpClient] Base URL: {}", self.base_url);
65
66 let method = Self::method_to_reqwest(request.method);
67 let mut req_builder = self.client.request(method.clone(), &url);
68
69 req_builder = req_builder.header("Accept", "application/json");
71 req_builder = req_builder.header("Content-Type", "application/json");
72
73 if let Some(token) = self.get_token() {
75 req_builder = req_builder.header("Authorization", format!("Bearer {}", token));
76 }
77
78 for (key, value) in request.headers {
80 req_builder = req_builder.header(key, value);
81 }
82
83 if let Some(body) = &request.body {
85 eprintln!("[NativeHttpClient] 请求体: {}", body);
86 req_builder = req_builder.body(body.clone());
87 }
88
89 eprintln!("[NativeHttpClient] 正在发送请求...");
91 let response = match req_builder.send().await {
92 Ok(resp) => resp,
93 Err(e) => {
94 eprintln!("[NativeHttpClient] 请求发送失败: {}", e);
95 return Err(agentlink_core::error::SdkError::Http(format!("请求发送失败: {}", e)));
96 }
97 };
98
99 let status = response.status().as_u16();
100 eprintln!("[NativeHttpClient] 响应状态码: {}", status);
101
102 let headers: Vec<(String, String)> = response
103 .headers()
104 .iter()
105 .filter_map(|(k, v)| {
106 Some((k.to_string(), v.to_str().ok()?.to_string()))
107 })
108 .collect();
109
110 let body = match response.text().await {
111 Ok(text) => {
112 eprintln!("[NativeHttpClient] 响应体: {}", text);
113 text
114 }
115 Err(e) => {
116 eprintln!("[NativeHttpClient] 读取响应体失败: {}", e);
117 return Err(agentlink_core::error::SdkError::Http(format!("读取响应体失败: {}", e)));
118 }
119 };
120
121 Ok(HttpResponse {
122 status,
123 headers,
124 body,
125 })
126 }
127
128 fn set_auth_token(&mut self, token: String) {
129 *self.auth_token.lock().unwrap() = Some(token);
130 }
131
132 fn auth_token(&self) -> Option<String> {
133 self.get_token()
134 }
135}
136
137impl Clone for NativeHttpClient {
138 fn clone(&self) -> Self {
139 Self {
140 client: self.client.clone(),
141 base_url: self.base_url.clone(),
142 auth_token: Arc::new(Mutex::new(
143 self.auth_token.lock().unwrap().clone()
144 )),
145 }
146 }
147}