Skip to main content

openlark_client/client/
builder.rs

1use super::Client;
2use crate::Result;
3use openlark_core::config::{Config, ConfigBuilder};
4use openlark_core::error::ErrorTrait;
5use std::fmt;
6use std::time::Duration;
7
8/// 🏗️ 客户端构建器 - 流畅API
9///
10/// 提供链式调用的客户端构建方式。配置状态委托给 core [`ConfigBuilder`],
11/// Client 仅叠加 30 秒默认超时与构建期严格校验策略。
12///
13/// # 示例
14/// ```rust,no_run
15/// use openlark_client::Client;
16/// use openlark_client::Result;
17/// use std::time::Duration;
18///
19/// fn main() -> Result<()> {
20///     let _client = Client::builder()
21///         .app_id("your_app_id")
22///         .app_secret("your_app_secret")
23///         .base_url("<https://open.feishu.cn>")
24///         .timeout(Duration::from_secs(30))
25///         .build()?;
26///     Ok(())
27/// }
28/// ```
29#[derive(Clone)]
30pub struct ClientBuilder {
31    config: ConfigBuilder,
32}
33
34impl fmt::Debug for ClientBuilder {
35    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
36        // 复用 ConfigBuilder 脱敏 Debug(secret / header 值 / token provider 不输出)
37        f.debug_struct("ClientBuilder")
38            .field("config", &self.config)
39            .finish()
40    }
41}
42
43impl ClientBuilder {
44    /// 🆕 创建新的构建器实例
45    ///
46    /// 在 core 默认值之上应用 Client 策略:默认请求超时 30 秒。
47    pub fn new() -> Self {
48        Self {
49            config: Config::builder().req_timeout(Duration::from_secs(30)),
50        }
51    }
52
53    /// 🆔 设置应用ID
54    pub fn app_id<S: Into<String>>(self, app_id: S) -> Self {
55        Self {
56            config: self.config.app_id(app_id),
57        }
58    }
59
60    /// 🔑 设置应用密钥
61    pub fn app_secret<S: Into<String>>(self, app_secret: S) -> Self {
62        Self {
63            config: self.config.app_secret(app_secret),
64        }
65    }
66
67    /// 🏷️ 设置应用类型(自建 / 商店)
68    pub fn app_type(self, app_type: openlark_core::constants::AppType) -> Self {
69        Self {
70            config: self.config.app_type(app_type),
71        }
72    }
73
74    /// 🔐 设置是否允许自动获取 token(默认 true)
75    pub fn enable_token_cache(self, enable: bool) -> Self {
76        Self {
77            config: self.config.enable_token_cache(enable),
78        }
79    }
80
81    /// 🌐 设置基础URL
82    pub fn base_url<S: Into<String>>(self, base_url: S) -> Self {
83        Self {
84            config: self.config.base_url(base_url),
85        }
86    }
87
88    /// 🔓 允许自定义 base_url 域名
89    pub fn allow_custom_base_url(self, allow: bool) -> Self {
90        Self {
91            config: self.config.allow_custom_base_url(allow),
92        }
93    }
94
95    /// ⏱️ 设置请求超时时间
96    pub fn timeout(self, timeout: Duration) -> Self {
97        Self {
98            config: self.config.req_timeout(timeout),
99        }
100    }
101
102    /// 🔄 设置重试次数
103    pub fn retry_count(self, retry_count: u32) -> Self {
104        Self {
105            config: self.config.retry_count(retry_count),
106        }
107    }
108
109    /// 📝 启用或禁用日志
110    pub fn enable_log(self, enable: bool) -> Self {
111        Self {
112            config: self.config.enable_log(enable),
113        }
114    }
115
116    /// 设置响应体最大大小限制(字节)
117    pub fn max_response_size(self, size: u64) -> Self {
118        Self {
119            config: self.config.max_response_size(size),
120        }
121    }
122
123    /// 🔧 添加自定义 HTTP header
124    pub fn add_header<K, V>(self, key: K, value: V) -> Self
125    where
126        K: Into<String>,
127        V: Into<String>,
128    {
129        Self {
130            config: self.config.add_header(key, value),
131        }
132    }
133
134    /// 🌍 从环境变量加载配置
135    ///
136    /// 在链式调用当前位置叠加 `OPENLARK_*` 环境变量;后写覆盖前写。
137    pub fn from_env(self) -> Self {
138        Self {
139            config: self.config.load_from_env(),
140        }
141    }
142
143    /// 🔨 构建客户端实例
144    ///
145    /// 与 [`Client::with_core_config`] 共用同一私有 checked 构造 seam。
146    ///
147    /// # 返回值
148    /// 返回配置好的客户端实例或验证错误
149    ///
150    /// # 错误
151    /// 如果配置验证失败,会返回相应的错误信息,包含用户友好的恢复建议
152    pub fn build(self) -> Result<Client> {
153        let result = Client::with_checked_core_config(self.config.build(), "ClientBuilder::build");
154        if let Err(ref error) = result {
155            tracing::error!(
156                "客户端构建失败: {}",
157                error.user_message().unwrap_or("未知错误")
158            );
159        }
160        result
161    }
162}
163
164impl Default for ClientBuilder {
165    fn default() -> Self {
166        Self::new()
167    }
168}