unistore_http/
lib.rs

1//! # unistore-http: HTTP 客户端能力
2//!
3//! 提供开箱即用的 HTTP 客户端,支持自动重试和超时控制。
4//!
5//! ## 设计哲学
6//!
7//! **三层 API 设计**:从简单到复杂,满足不同场景需求。
8//!
9//! ```text
10//! ┌─────────────────────────────────────────────────────────────────┐
11//! │  Level 3: 便捷函数(一行代码)                                   │
12//! │  get(url) / post_json(url, body)                               │
13//! ├─────────────────────────────────────────────────────────────────┤
14//! │  Level 2: HttpClient(带配置的客户端)                          │
15//! │  HttpClient::new() / HttpClient::builder()                     │
16//! ├─────────────────────────────────────────────────────────────────┤
17//! │  Level 1: 底层访问(完全控制)                                   │
18//! │  client.inner() -> &reqwest::Client                            │
19//! └─────────────────────────────────────────────────────────────────┘
20//! ```
21//!
22//! ## 快速开始
23//!
24//! ```ignore
25//! use unistore_http::{get, get_json, HttpClient};
26//!
27//! // Level 3: 便捷函数
28//! let body = get("https://api.example.com/status").await?.text()?;
29//! let user: User = get_json("https://api.example.com/user/1").await?;
30//!
31//! // Level 2: 客户端实例
32//! let client = HttpClient::builder()
33//!     .timeout(Duration::from_secs(60))
34//!     .max_retries(5)
35//!     .build()?;
36//! let resp = client.get("https://api.example.com/data").await?;
37//! ```
38
39// ============================================================================
40// 内部模块
41// ============================================================================
42
43mod client;
44mod config;
45mod error;
46mod facade;
47mod request;
48mod response;
49
50// ============================================================================
51// 公开 API(sdk.rs 职责整合到 lib.rs)
52// ============================================================================
53
54// 核心类型
55pub use client::HttpClient;
56pub use config::{HttpClientConfig, HttpClientConfigBuilder, ProxyConfig, RetryStrategy};
57pub use error::HttpError;
58pub use response::Response;
59
60// 请求构建
61pub use request::{
62    CancellableRequest, CancellationToken, CancellationTrigger,
63    Method, RequestBuilder, cancellation_pair,
64};
65
66// 便捷函数(Level 3 API)
67pub use facade::{
68    delete, get, get_bytes, get_json, get_text, head, patch_json, post_form, post_json,
69    post_json_for_json, put_json,
70};
71
72// ============================================================================
73// Capability 实现
74// ============================================================================
75
76use async_trait::async_trait;
77use unistore_core::{Capability, CapabilityError, CapabilityInfo};
78
79/// HTTP 客户端能力
80///
81/// 实现 `Capability` trait,可被 UniStore 运行时管理
82pub struct HttpCapability {
83    client: Option<HttpClient>,
84    config: HttpClientConfig,
85}
86
87impl HttpCapability {
88    /// 创建 HTTP 能力实例
89    pub fn new() -> Self {
90        Self {
91            client: None,
92            config: HttpClientConfig::default(),
93        }
94    }
95
96    /// 使用自定义配置创建
97    pub fn with_config(config: HttpClientConfig) -> Self {
98        Self {
99            client: None,
100            config,
101        }
102    }
103
104    /// 获取客户端(能力必须已启动)
105    pub fn client(&self) -> Option<&HttpClient> {
106        self.client.as_ref()
107    }
108}
109
110impl Default for HttpCapability {
111    fn default() -> Self {
112        Self::new()
113    }
114}
115
116#[async_trait]
117impl Capability for HttpCapability {
118    fn info(&self) -> CapabilityInfo {
119        CapabilityInfo::new("http", env!("CARGO_PKG_VERSION"))
120            .with_description("HTTP client capability with retry and timeout support")
121            .with_author("UniStore Team")
122    }
123
124    async fn start(&mut self) -> Result<(), CapabilityError> {
125        if self.client.is_some() {
126            return Ok(()); // 已启动
127        }
128
129        let client = HttpClient::with_config(self.config.clone())
130            .map_err(|e| CapabilityError::start_failed("http", e.to_string()))?;
131        self.client = Some(client);
132        Ok(())
133    }
134
135    async fn stop(&mut self) -> Result<(), CapabilityError> {
136        self.client = None;
137        Ok(())
138    }
139
140    async fn health_check(&self) -> Result<(), CapabilityError> {
141        if self.client.is_none() {
142            return Err(CapabilityError::unhealthy("http", "客户端未初始化"));
143        }
144        Ok(())
145    }
146}