Skip to main content

agentlink_native/
http.rs

1//! Native HTTP Client Implementation
2//!
3//! Uses reqwest for HTTP requests.
4
5use 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
13/// Native HTTP client using reqwest
14pub 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    /// Get auth token (synchronous version for internal use)
49    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        // Add default headers
70        req_builder = req_builder.header("Accept", "application/json");
71        req_builder = req_builder.header("Content-Type", "application/json");
72
73        // Add auth token if available
74        if let Some(token) = self.get_token() {
75            req_builder = req_builder.header("Authorization", format!("Bearer {}", token));
76        }
77
78        // Add request headers
79        for (key, value) in request.headers {
80            req_builder = req_builder.header(key, value);
81        }
82
83        // Add body if present
84        if let Some(body) = &request.body {
85            eprintln!("[NativeHttpClient] 请求体: {}", body);
86            req_builder = req_builder.body(body.clone());
87        }
88
89        // Send request
90        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}