1#[macro_use]
6mod macros;
7
8mod builder;
9mod error_handling;
10#[cfg(test)]
11mod tests;
12
13pub use builder::ClientBuilder;
14pub use error_handling::ClientErrorHandling;
15
16#[allow(deprecated)]
17use crate::Config;
18use crate::{
19 DefaultServiceRegistry, Result,
20 client_build_config::{ClientBuildConfig, validate_core_config},
21 error::{with_context, with_operation_context},
22 traits::LarkClient,
23};
24use std::sync::Arc;
25
26#[cfg(feature = "auth")]
28#[derive(Debug, Clone)]
29pub struct AuthClient {
30 pub app: openlark_auth::AuthService,
32 pub user: openlark_auth::AuthenService,
34 pub oauth: openlark_auth::OAuthService,
36}
37
38#[cfg(feature = "auth")]
39impl AuthClient {
40 fn new(config: openlark_core::config::Config) -> Self {
41 Self {
42 app: openlark_auth::AuthService::new(config.clone()),
43 user: openlark_auth::AuthenService::new(config.clone()),
44 oauth: openlark_auth::OAuthService::new(config),
45 }
46 }
47}
48
49declare_client! {
50 {
51 feature: "cardkit",
52 field: cardkit,
53 ty: openlark_cardkit::CardkitClient,
54 doc: "CardKit meta 调用链:client.cardkit.v1.card.create(...)",
55 init: |_core_config, _base_core_config| {
56 openlark_cardkit::CardkitClient::new(_core_config.clone())
57 },
58 },
59 {
60 feature: "auth",
61 field: auth,
62 ty: AuthClient,
63 doc: "Auth meta 调用链入口:client.auth.app / client.auth.user / client.auth.oauth",
64 init: |_core_config, _base_core_config| {
65 AuthClient::new(_base_core_config.clone())
66 },
67 },
68 {
69 feature: "docs",
70 field: docs,
71 ty: openlark_docs::DocsClient,
72 doc: "Docs meta 调用链入口:client.docs.ccm / client.docs.base ...",
73 init: |_core_config, _base_core_config| {
74 openlark_docs::DocsClient::new(_core_config.clone())
75 },
76 },
77 {
78 feature: "communication",
79 field: communication,
80 ty: openlark_communication::CommunicationClient,
81 doc: "Communication meta 调用链入口:client.communication.im / client.communication.contact ...",
82 init: |_core_config, _base_core_config| {
83 openlark_communication::CommunicationClient::new(_core_config.clone())
84 },
85 },
86 {
87 feature: "hr",
88 field: hr,
89 ty: openlark_hr::HrClient,
90 doc: "HR meta 调用链入口:client.hr.attendance / client.hr.corehr / client.hr.hire ...",
91 init: |_core_config, _base_core_config| {
92 openlark_hr::HrClient::new(_core_config.clone())
93 },
94 },
95 {
96 feature: "meeting",
97 field: meeting,
98 ty: openlark_meeting::MeetingClient,
99 doc: "Meeting meta 调用链入口:client.meeting.vc.v1.room.create() ...",
100 init: |_core_config, _base_core_config| {
101 openlark_meeting::MeetingClient::new(_core_config.clone())
102 },
103 },
104 {
105 feature: "ai",
106 field: ai,
107 ty: openlark_ai::AiClient,
108 doc: "AI meta 调用链入口:client.ai.chat.create() ...",
109 init: |_core_config, _base_core_config| {
110 openlark_ai::AiClient::new(_core_config.clone())
111 },
112 },
113 {
114 feature: "workflow",
115 field: workflow,
116 ty: crate::WorkflowClient,
117 doc: "Workflow meta 调用链入口:client.workflow.task.create() ...",
118 init: |_core_config, _base_core_config| {
119 crate::WorkflowClient::new(_core_config.clone())
120 },
121 },
122 {
123 feature: "platform",
124 field: platform,
125 ty: crate::PlatformClient,
126 doc: "Platform meta 调用链入口:client.platform.app_engine... ...",
127 init: |_core_config, _base_core_config| {
128 crate::PlatformClient::new(_core_config.clone())?
129 },
130 },
131 {
132 feature: "application",
133 field: application,
134 ty: crate::ApplicationClient,
135 doc: "Application meta 调用链入口:client.application.applet... ...",
136 init: |_core_config, _base_core_config| {
137 crate::ApplicationClient::new(_core_config.clone())
138 },
139 },
140 {
141 feature: "helpdesk",
142 field: helpdesk,
143 ty: crate::HelpdeskClient,
144 doc: "Helpdesk meta 调用链入口:client.helpdesk.ticket... ...",
145 init: |_core_config, _base_core_config| {
146 crate::HelpdeskClient::new(_core_config.clone())
147 },
148 },
149 {
150 feature: "mail",
151 field: mail,
152 ty: crate::MailClient,
153 doc: "Mail meta 调用链入口:client.mail.group... ...",
154 init: |_core_config, _base_core_config| {
155 crate::MailClient::new(_core_config.clone())
156 },
157 },
158 {
159 feature: "analytics",
160 field: analytics,
161 ty: crate::AnalyticsClient,
162 doc: "Analytics meta 调用链入口:client.analytics.report... ...",
163 init: |_core_config, _base_core_config| {
164 crate::AnalyticsClient::new(_core_config.clone())?
165 },
166 },
167 {
168 feature: "user",
169 field: user,
170 ty: crate::UserClient,
171 doc: "User meta 调用链入口:client.user.setting... ...",
172 init: |_core_config, _base_core_config| {
173 crate::UserClient::new(_core_config.clone())?
174 },
175 },
176 {
177 feature: "security",
178 field: security,
179 ty: crate::SecurityClient,
180 doc: "Security meta 调用链入口:client.security.acs... ...",
181 init: |_core_config, _base_core_config| {
182 let security_config = openlark_security::models::SecurityConfig::new(
183 _core_config.app_id().to_string(),
184 _core_config.app_secret().to_string(),
185 )
186 .with_base_url(_core_config.base_url());
187 openlark_security::SecurityClient::new(security_config)
188 },
189 },
190}
191
192impl Client {
193 pub fn from_env() -> Result<Self> {
213 Self::builder().from_env().build()
214 }
215
216 pub fn builder() -> ClientBuilder {
218 ClientBuilder::new()
219 }
220
221 pub fn config(&self) -> &openlark_core::config::Config {
223 &self.config
224 }
225
226 pub fn registry(&self) -> &DefaultServiceRegistry {
228 &self.registry
229 }
230
231 pub fn core_config(&self) -> &openlark_core::config::Config {
235 &self.config
236 }
237
238 pub fn api_config(&self) -> &openlark_core::config::Config {
244 &self.config
245 }
246
247 pub fn is_configured(&self) -> bool {
249 !self.config.app_id().is_empty() && !self.config.app_secret().is_empty()
250 }
251
252 #[allow(deprecated)]
254 pub fn with_config(config: Config) -> Result<Self> {
255 let build_config = ClientBuildConfig::from(config);
256 if let Err(err) = build_config.validate() {
257 return with_context(Err(err), "operation", "Client::with_config");
258 }
259
260 Self::with_validated_core_config(build_config.build_core_config(), "Client::with_config")
261 }
262
263 pub fn with_core_config(config: openlark_core::config::Config) -> Result<Self> {
265 if let Err(err) = validate_core_config(&config) {
266 return with_context(Err(err), "operation", "Client::with_core_config");
267 }
268
269 Self::with_validated_core_config(config, "Client::with_core_config")
270 }
271
272 pub(crate) fn with_validated_core_config(
273 base_core_config: openlark_core::config::Config,
274 operation: &str,
275 ) -> Result<Self> {
276 let mut registry = DefaultServiceRegistry::new();
277
278 if let Err(err) = crate::registry::bootstrap::register_compiled_services(&mut registry) {
279 return with_operation_context(Err(err), operation, "service_loading");
280 }
281
282 let registry = Arc::new(registry);
283
284 #[cfg(feature = "auth")]
285 let core_config = {
286 use openlark_auth::AuthTokenProvider;
287 let provider = AuthTokenProvider::new(base_core_config.clone());
288 base_core_config.with_token_provider(provider)
289 };
290 #[cfg(not(feature = "auth"))]
291 let core_config = base_core_config.clone();
292
293 Self::from_parts(registry, base_core_config, core_config)
294 }
295
296 pub async fn execute_with_context<F, T>(&self, operation: &str, f: F) -> Result<T>
298 where
299 F: std::future::Future<Output = Result<T>>,
300 {
301 let result = f.await;
302 with_operation_context(result, operation, "Client")
303 }
304}
305
306impl LarkClient for Client {
307 fn config(&self) -> &openlark_core::config::Config {
308 &self.config
309 }
310
311 fn is_configured(&self) -> bool {
312 self.is_configured()
313 }
314}