#[macro_use]
mod macros;
mod builder;
#[cfg(test)]
#[macro_use]
mod catalog_contract_support;
#[cfg(test)]
mod catalog_contract_foundational;
#[cfg(test)]
mod catalog_contract_listing;
#[cfg(test)]
mod catalog_contract_remaining;
mod error_handling;
#[cfg(test)]
mod tests;
pub use builder::ClientBuilder;
pub use error_handling::ClientErrorHandling;
use crate::{
DefaultServiceRegistry, Result,
error::{with_context, with_operation_context},
traits::LarkClient,
validation_error,
};
use std::sync::Arc;
#[cfg(feature = "auth")]
#[derive(Debug, Clone)]
pub struct AuthClient {
pub app: openlark_auth::AuthService,
pub user: openlark_auth::AuthenService,
pub oauth: openlark_auth::OAuthService,
}
#[cfg(feature = "auth")]
impl AuthClient {
fn new(config: openlark_core::config::Config) -> Self {
Self {
app: openlark_auth::AuthService::new(config.clone()),
user: openlark_auth::AuthenService::new(config.clone()),
oauth: openlark_auth::OAuthService::new(config),
}
}
}
macro_rules! append_catalog_entries {
($({
feature: $c_feature:literal,
field: $c_field:ident,
ty: $c_ty:ty,
doc: $c_doc:literal,
init: |$c_core:ident, $c_base:ident| $c_init:block,
// 诊断字段:由 registry 投影消费;此处仅匹配统一条目形状
name: $_name:literal,
description: $_description:literal,
dependencies: [$( $_dep:literal ),* $(,)?],
provides: [$( $_cap:literal ),* $(,)?],
priority: $_priority:literal $(,)?
}),* $(,)?) => {
declare_client! {
$(
{
feature: $c_feature,
field: $c_field,
ty: $c_ty,
doc: $c_doc,
init: |$c_core, $c_base| $c_init,
},
)*
}
};
}
crate::capability::for_each_compiled_capability!(append_catalog_entries);
impl Client {
pub fn from_env() -> Result<Self> {
Self::builder().from_env().build()
}
pub fn builder() -> ClientBuilder {
ClientBuilder::new()
}
pub fn config(&self) -> &openlark_core::config::Config {
&self.config
}
pub fn registry(&self) -> &DefaultServiceRegistry {
&self.registry
}
pub fn core_config(&self) -> &openlark_core::config::Config {
&self.config
}
pub fn api_config(&self) -> &openlark_core::config::Config {
&self.config
}
pub fn is_configured(&self) -> bool {
!self.config.app_id().is_empty() && !self.config.app_secret().is_empty()
}
pub fn with_core_config(config: openlark_core::config::Config) -> Result<Self> {
Self::with_checked_core_config(config, "Client::with_core_config")
}
pub(crate) fn with_checked_core_config(
base_core_config: openlark_core::config::Config,
operation: &str,
) -> Result<Self> {
if let Err(err) = base_core_config.validate() {
return with_context(Err(err), "operation", operation);
}
if base_core_config
.req_timeout()
.is_some_and(|timeout| timeout.is_zero())
{
return with_context(
Err(validation_error("timeout", "timeout必须大于0")),
"operation",
operation,
);
}
let mut registry = DefaultServiceRegistry::new();
if let Err(err) = crate::registry::bootstrap::register_compiled_services(&mut registry) {
return with_operation_context(Err(err), operation, "service_loading");
}
let registry = Arc::new(registry);
#[cfg(feature = "auth")]
let core_config = {
use openlark_auth::AuthTokenProvider;
let provider = AuthTokenProvider::new(base_core_config.clone());
base_core_config.with_token_provider(provider)
};
#[cfg(not(feature = "auth"))]
let core_config = base_core_config.clone();
Self::from_parts(registry, base_core_config, core_config)
}
pub async fn execute_with_context<F, T>(&self, operation: &str, f: F) -> Result<T>
where
F: std::future::Future<Output = Result<T>>,
{
let result = f.await;
with_operation_context(result, operation, "Client")
}
}
impl LarkClient for Client {
fn config(&self) -> &openlark_core::config::Config {
&self.config
}
fn is_configured(&self) -> bool {
self.is_configured()
}
}