open_lark/core/trait_system/
service.rs

1use crate::core::{config::Config, observability::OperationTracker, SDKResult};
2use std::future::Future;
3
4/// 服务基础 trait
5///
6/// 定义所有 Lark 服务的通用行为和接口
7pub trait Service {
8    /// 获取服务配置
9    fn config(&self) -> &Config;
10
11    /// 获取服务名称,用于日志和监控
12    fn service_name() -> &'static str
13    where
14        Self: Sized;
15
16    /// 服务版本,用于 API 兼容性
17    fn service_version() -> &'static str
18    where
19        Self: Sized,
20    {
21        "v1"
22    }
23}
24
25/// 可观测性支持 trait
26///
27/// 为服务提供统一的日志、监控和跟踪接口
28pub trait ServiceObservability: Service {
29    /// 记录服务操作开始
30    fn log_operation_start(&self, operation: &str, params: Option<&str>)
31    where
32        Self: Sized,
33    {
34        tracing::debug!(
35            service_name = <Self as Service>::service_name(),
36            operation = operation,
37            params = params,
38            "Starting service operation"
39        );
40    }
41
42    /// 记录服务操作完成
43    fn log_operation_success(&self, operation: &str, duration_ms: u64)
44    where
45        Self: Sized,
46    {
47        tracing::info!(
48            service_name = <Self as Service>::service_name(),
49            operation = operation,
50            duration_ms = duration_ms,
51            "Service operation completed successfully"
52        );
53    }
54
55    /// 记录服务操作失败
56    fn log_operation_error(&self, operation: &str, error: &str, duration_ms: u64)
57    where
58        Self: Sized,
59    {
60        tracing::error!(
61            service_name = <Self as Service>::service_name(),
62            operation = operation,
63            duration_ms = duration_ms,
64            error = error,
65            "Service operation failed"
66        );
67    }
68}
69
70/// 异步服务操作 trait
71///
72/// 为异步操作提供统一的错误处理和重试机制
73pub trait AsyncServiceOperation<T, R>: Service
74where
75    T: Send + Sync,
76    R: Send + Sync,
77{
78    /// 执行带有观测性支持的异步操作
79    fn execute_with_observability<F, Fut>(
80        &self,
81        operation_name: &str,
82        operation: F,
83    ) -> impl Future<Output = SDKResult<R>> + Send
84    where
85        F: FnOnce() -> Fut + Send,
86        Fut: Future<Output = SDKResult<R>> + Send,
87        Self: ServiceObservability + Sync + Sized,
88    {
89        let service_name = <Self as Service>::service_name();
90        async move {
91            let tracker = OperationTracker::start(service_name, operation_name);
92
93            match operation().await {
94                Ok(result) => {
95                    tracker.success();
96                    Ok(result)
97                }
98                Err(err) => {
99                    tracker.error(&err.to_string());
100                    Err(err)
101                }
102            }
103        }
104    }
105}
106
107/// 服务构建器 trait
108///
109/// 提供统一的服务实例化接口
110pub trait ServiceBuilder<S: Service> {
111    /// 使用配置创建服务实例
112    fn build(config: Config) -> S;
113
114    /// 使用默认配置创建服务实例
115    fn build_default() -> S
116    where
117        Config: Default,
118    {
119        Self::build(Config::default())
120    }
121}
122
123/// 支持健康检查的服务 trait
124///
125/// 为服务提供健康状态监控能力
126pub trait ServiceHealthCheck: Service {
127    /// 检查服务健康状态
128    fn health_check(&self) -> impl Future<Output = SDKResult<ServiceHealthStatus>> + Send;
129
130    /// 获取服务状态摘要
131    fn status_summary(&self) -> ServiceStatusSummary
132    where
133        Self: Sized,
134    {
135        ServiceStatusSummary {
136            service_name: <Self as Service>::service_name().to_string(),
137            version: <Self as Service>::service_version().to_string(),
138            config_valid: self.is_config_valid(),
139        }
140    }
141
142    /// 验证配置是否有效
143    fn is_config_valid(&self) -> bool {
144        let config = self.config();
145        !config.app_id.is_empty() && !config.app_secret.is_empty()
146    }
147}
148
149/// 服务健康状态枚举
150#[derive(Debug, Clone, PartialEq)]
151pub enum ServiceHealthStatus {
152    /// 健康状态
153    Healthy,
154    /// 降级状态(部分功能可用)
155    Degraded(String),
156    /// 不健康状态
157    Unhealthy(String),
158}
159
160/// 服务状态摘要
161#[derive(Debug, Clone)]
162pub struct ServiceStatusSummary {
163    /// 服务名称
164    pub service_name: String,
165    /// 服务版本
166    pub version: String,
167    /// 配置是否有效
168    pub config_valid: bool,
169}
170
171/// 可配置的服务 trait
172///
173/// 为服务提供动态配置更新能力
174pub trait ConfigurableService: Service {
175    /// 更新服务配置
176    fn update_config(&mut self, new_config: Config) -> SDKResult<()>;
177
178    /// 验证新配置的有效性
179    fn validate_config(&self, config: &Config) -> SDKResult<()> {
180        if config.app_id.is_empty() {
181            return Err(crate::core::error::LarkAPIError::IllegalParamError(
182                "app_id cannot be empty".to_string(),
183            ));
184        }
185
186        if config.app_secret.is_empty() {
187            return Err(crate::core::error::LarkAPIError::IllegalParamError(
188                "app_secret cannot be empty".to_string(),
189            ));
190        }
191
192        Ok(())
193    }
194}
195
196/// 带缓存的服务 trait
197///
198/// 为服务提供缓存机制支持
199pub trait CacheableService: Service {
200    /// 缓存键类型
201    type CacheKey: Send + Sync + std::hash::Hash + Eq + Clone;
202    /// 缓存值类型
203    type CacheValue: Send + Sync + Clone;
204
205    /// 从缓存获取数据
206    fn get_from_cache(&self, key: &Self::CacheKey) -> Option<Self::CacheValue>;
207
208    /// 将数据存入缓存
209    fn put_to_cache(&self, key: Self::CacheKey, value: Self::CacheValue);
210
211    /// 清除缓存
212    fn clear_cache(&self);
213
214    /// 缓存过期时间(秒)
215    fn cache_ttl(&self) -> u64 {
216        300 // 默认 5 分钟
217    }
218}
219
220#[cfg(test)]
221mod tests {
222    use super::*;
223    use crate::core::config::Config;
224
225    // 测试用的简单服务实现
226    struct TestService {
227        config: Config,
228    }
229
230    impl Service for TestService {
231        fn config(&self) -> &Config {
232            &self.config
233        }
234
235        fn service_name() -> &'static str {
236            "test_service"
237        }
238
239        fn service_version() -> &'static str {
240            "v1.0"
241        }
242    }
243
244    impl ServiceObservability for TestService {}
245
246    impl ServiceBuilder<TestService> for TestService {
247        fn build(config: Config) -> TestService {
248            TestService { config }
249        }
250    }
251
252    impl AsyncServiceOperation<(), String> for TestService {}
253
254    #[test]
255    fn test_service_creation() {
256        let config = Config::builder()
257            .app_id("test_app")
258            .app_secret("test_secret")
259            .build();
260        let service = TestService::build(config.clone());
261
262        assert_eq!(service.config().app_id, "test_app");
263        assert_eq!(service.config().app_secret, "test_secret");
264        assert_eq!(TestService::service_name(), "test_service");
265        assert_eq!(TestService::service_version(), "v1.0");
266    }
267
268    #[test]
269    fn test_service_status_summary() {
270        let config = Config::builder()
271            .app_id("test_app")
272            .app_secret("test_secret")
273            .build();
274        let service = TestService::build(config);
275
276        // 需要手动实现 ServiceHealthCheck 来测试
277        struct HealthCheckableTestService {
278            inner: TestService,
279        }
280
281        impl Service for HealthCheckableTestService {
282            fn config(&self) -> &Config {
283                self.inner.config()
284            }
285
286            fn service_name() -> &'static str {
287                TestService::service_name()
288            }
289
290            fn service_version() -> &'static str {
291                TestService::service_version()
292            }
293        }
294
295        impl ServiceHealthCheck for HealthCheckableTestService {
296            async fn health_check(&self) -> SDKResult<ServiceHealthStatus> {
297                Ok(ServiceHealthStatus::Healthy)
298            }
299        }
300
301        let health_service = HealthCheckableTestService { inner: service };
302        let summary = health_service.status_summary();
303
304        assert_eq!(summary.service_name, "test_service");
305        assert_eq!(summary.version, "v1.0");
306        assert!(summary.config_valid);
307    }
308
309    #[test]
310    fn test_config_validation() {
311        let config = Config::builder()
312            .app_id("test_app")
313            .app_secret("test_secret")
314            .build();
315        let service = TestService::build(config);
316
317        struct ConfigurableTestService {
318            inner: TestService,
319        }
320
321        impl Service for ConfigurableTestService {
322            fn config(&self) -> &Config {
323                self.inner.config()
324            }
325
326            fn service_name() -> &'static str {
327                TestService::service_name()
328            }
329        }
330
331        impl ConfigurableService for ConfigurableTestService {
332            fn update_config(&mut self, new_config: Config) -> SDKResult<()> {
333                self.validate_config(&new_config)?;
334                self.inner.config = new_config;
335                Ok(())
336            }
337        }
338
339        let configurable_service = ConfigurableTestService { inner: service };
340
341        // 测试有效配置
342        let valid_config = Config::builder()
343            .app_id("new_app")
344            .app_secret("new_secret")
345            .build();
346        assert!(configurable_service.validate_config(&valid_config).is_ok());
347
348        // 测试无效配置 - 空 app_id
349        let invalid_config = Config::builder().app_id("").app_secret("secret").build();
350        assert!(configurable_service
351            .validate_config(&invalid_config)
352            .is_err());
353
354        // 测试无效配置 - 空 app_secret
355        let invalid_config = Config::builder().app_id("app").app_secret("").build();
356        assert!(configurable_service
357            .validate_config(&invalid_config)
358            .is_err());
359    }
360
361    #[test]
362    fn test_service_builder_default() {
363        // 由于我们的 Config 有 Default 实现,测试默认构建
364        let service = TestService::build_default();
365        // 默认配置应为空凭证,保持安全缺省
366        assert!(service.config().app_id.is_empty());
367    }
368
369    #[tokio::test]
370    async fn test_async_service_operation() {
371        let config = Config::builder()
372            .app_id("test_app")
373            .app_secret("test_secret")
374            .build();
375        let service = TestService::build(config);
376
377        // 测试成功操作
378        let result = service
379            .execute_with_observability("test_operation", || async { Ok("success".to_string()) })
380            .await;
381
382        assert!(result.is_ok());
383        assert_eq!(result.unwrap(), "success");
384
385        // 测试失败操作
386        let result = service
387            .execute_with_observability("test_operation_fail", || async {
388                Err(crate::core::error::LarkAPIError::IllegalParamError(
389                    "test error".to_string(),
390                ))
391            })
392            .await;
393
394        assert!(result.is_err());
395    }
396}