open_lark/service/im/v1/message/
mod.rs

1//! Message service module for IM v1 API
2//!
3//! This module provides functionality for creating, sending, and managing messages
4//! in the Lark/Feishu IM system.
5
6pub mod builders;
7pub mod content_types;
8pub mod list;
9pub mod send;
10pub mod types;
11
12// Re-export main types and services for easier imports
13pub use builders::{
14    CreateMessageRequest, CreateMessageRequestBody, CreateMessageRequestBodyBuilder,
15    CreateMessageRequestBuilder, UpdateMessageRequest, UpdateMessageRequestBuilder,
16};
17pub use content_types::*;
18pub use list::{ListMessageRequest, ListMessageRequestBuilder, ListMessageRespData};
19pub use types::{CreateMessageResp, ListMessageIterator, Message, SendMessageTrait};
20
21use crate::core::config::Config;
22use crate::impl_full_service;
23
24/// Message service
25///
26/// Provides core message functionality including creating, sending, and retrieving messages.
27/// Supports multiple message types: text, post, image, file, audio, media, sticker,
28/// interactive, share_chat, share_user.
29///
30/// Service 抽象接入:通过 `impl_full_service!` 为该服务实现
31/// `Service`/`ServiceObservability`/`ServiceBuilder`/`ServiceHealthCheck`/`ConfigurableService`
32/// 等核心能力,统一服务行为与可观测性。
33#[derive(Debug, Clone)]
34pub struct MessageService {
35    /// Service configuration
36    pub config: Config,
37}
38
39impl MessageService {
40    /// Create a new message service instance
41    pub fn new(config: Config) -> Self {
42        Self { config }
43    }
44}
45
46// 为 MessageService 一次性实现核心服务能力(标准样例)
47impl_full_service!(MessageService, "im.message", "v1");
48
49#[cfg(test)]
50#[allow(unused_variables, unused_unsafe)]
51mod tests {
52    use super::*;
53    use crate::core::config::Config;
54    use crate::core::trait_system::Service;
55
56    fn create_test_config() -> Config {
57        Config::default()
58    }
59
60    #[test]
61    fn test_message_service_creation() {
62        let config = create_test_config();
63        let service = MessageService::new(config.clone());
64
65        assert_eq!(service.config.app_id, config.app_id);
66        assert_eq!(service.config.app_secret, config.app_secret);
67        // 验证 Service 抽象静态信息
68        assert_eq!(MessageService::service_name(), "im.message");
69        assert_eq!(MessageService::service_version(), "v1");
70        // 验证 Service::config() 访问
71        assert_eq!(service.config().app_id, config.app_id);
72    }
73
74    #[test]
75    fn test_message_service_with_custom_config() {
76        let config = Config::builder()
77            .app_id("message_app")
78            .app_secret("message_secret")
79            .req_timeout(std::time::Duration::from_millis(16000))
80            .base_url("https://message.api.com")
81            .build();
82
83        let service = MessageService::new(config.clone());
84
85        assert_eq!(service.config.app_id, "message_app");
86        assert_eq!(service.config.app_secret, "message_secret");
87        assert_eq!(service.config.base_url, "https://message.api.com");
88        assert_eq!(
89            service.config.req_timeout,
90            Some(std::time::Duration::from_millis(16000))
91        );
92    }
93
94    #[test]
95    fn test_message_service_config_independence() {
96        let config1 = Config::builder()
97            .app_id("message1")
98            .app_secret("secret1")
99            .build();
100        let config2 = Config::builder()
101            .app_id("message2")
102            .app_secret("secret2")
103            .build();
104
105        let service1 = MessageService::new(config1);
106        let service2 = MessageService::new(config2);
107
108        assert_eq!(service1.config.app_id, "message1");
109        assert_eq!(service2.config.app_id, "message2");
110        assert_ne!(service1.config.app_id, service2.config.app_id);
111    }
112
113    #[test]
114    fn test_message_service_memory_layout() {
115        let config = create_test_config();
116        let service = MessageService::new(config);
117
118        let service_ptr = std::ptr::addr_of!(service) as *const u8;
119        let config_ptr = std::ptr::addr_of!(service.config) as *const u8;
120
121        assert!(
122            !service_ptr.is_null(),
123            "Service should have valid memory address"
124        );
125        assert!(
126            !config_ptr.is_null(),
127            "Config should have valid memory address"
128        );
129    }
130
131    #[test]
132    fn test_message_service_with_different_configurations() {
133        let test_configs = vec![
134            Config::builder()
135                .app_id("message_basic")
136                .app_secret("basic_secret")
137                .build(),
138            Config::builder()
139                .app_id("message_timeout")
140                .app_secret("timeout_secret")
141                .req_timeout(std::time::Duration::from_millis(13500))
142                .build(),
143            Config::builder()
144                .app_id("message_custom")
145                .app_secret("custom_secret")
146                .base_url("https://custom.message.com")
147                .build(),
148            Config::builder()
149                .app_id("message_full")
150                .app_secret("full_secret")
151                .req_timeout(std::time::Duration::from_millis(23000))
152                .base_url("https://full.message.com")
153                .enable_token_cache(false)
154                .build(),
155        ];
156
157        for config in test_configs {
158            let service = MessageService::new(config.clone());
159
160            assert_eq!(service.config.app_id, config.app_id);
161            assert_eq!(service.config.app_secret, config.app_secret);
162            assert_eq!(service.config.base_url, config.base_url);
163            assert_eq!(service.config.req_timeout, config.req_timeout);
164        }
165    }
166
167    #[test]
168    fn test_message_service_multiple_instances() {
169        let config = create_test_config();
170        let service1 = MessageService::new(config.clone());
171        let service2 = MessageService::new(config.clone());
172
173        assert_eq!(service1.config.app_id, service2.config.app_id);
174        assert_eq!(service1.config.app_secret, service2.config.app_secret);
175
176        let ptr1 = std::ptr::addr_of!(service1) as *const u8;
177        let ptr2 = std::ptr::addr_of!(service2) as *const u8;
178        assert_ne!(ptr1, ptr2, "Services should be independent instances");
179    }
180
181    #[test]
182    fn test_message_service_config_cloning() {
183        let original_config = create_test_config();
184        let cloned_config = original_config.clone();
185
186        let service = MessageService::new(cloned_config);
187
188        assert_eq!(service.config.app_id, original_config.app_id);
189        assert_eq!(service.config.app_secret, original_config.app_secret);
190    }
191
192    #[test]
193    fn test_message_service_with_empty_config() {
194        let config = Config::default();
195        let service = MessageService::new(config);
196
197        assert_eq!(service.config.app_id, "");
198        assert_eq!(service.config.app_secret, "");
199    }
200
201    #[test]
202    fn test_message_service_with_unicode_config() {
203        let config = Config::builder()
204            .app_id("消息应用")
205            .app_secret("消息密钥")
206            .base_url("https://消息.com")
207            .build();
208        let service = MessageService::new(config);
209
210        assert_eq!(service.config.app_id, "消息应用");
211        assert_eq!(service.config.app_secret, "消息密钥");
212        assert_eq!(service.config.base_url, "https://消息.com");
213    }
214
215    #[test]
216    fn test_message_service_with_extreme_timeout() {
217        let config = Config::builder()
218            .app_id("message_extreme")
219            .app_secret("extreme_secret")
220            .req_timeout(std::time::Duration::from_secs(10800))
221            .build();
222        let service = MessageService::new(config);
223
224        assert_eq!(
225            service.config.req_timeout,
226            Some(std::time::Duration::from_secs(10800))
227        );
228    }
229
230    #[test]
231    fn test_message_service_concurrent_creation() {
232        let configs = vec![
233            Config::builder()
234                .app_id("message_concurrent_1")
235                .app_secret("secret_1")
236                .build(),
237            Config::builder()
238                .app_id("message_concurrent_2")
239                .app_secret("secret_2")
240                .build(),
241            Config::builder()
242                .app_id("message_concurrent_3")
243                .app_secret("secret_3")
244                .build(),
245        ];
246
247        let mut services = Vec::new();
248        for config in configs {
249            let service = MessageService::new(config);
250            services.push(service);
251        }
252
253        assert_eq!(services.len(), 3);
254
255        for (i, service1) in services.iter().enumerate() {
256            for service2 in services.iter().skip(i + 1) {
257                let ptr1 = std::ptr::addr_of!(*service1) as *const u8;
258                let ptr2 = std::ptr::addr_of!(*service2) as *const u8;
259                assert_ne!(ptr1, ptr2, "Services should be independent instances");
260            }
261        }
262    }
263
264    #[test]
265    fn test_message_service_debug_trait() {
266        let config = create_test_config();
267        let service = MessageService::new(config);
268
269        let debug_output = format!("{:?}", service);
270        assert!(debug_output.contains("MessageService"));
271        assert!(debug_output.contains("config"));
272    }
273
274    #[test]
275    fn test_message_service_clone_trait() {
276        let config = create_test_config();
277        let service = MessageService::new(config);
278        let cloned_service = service.clone();
279
280        assert_eq!(service.config.app_id, cloned_service.config.app_id);
281        assert_eq!(service.config.app_secret, cloned_service.config.app_secret);
282
283        let ptr1 = std::ptr::addr_of!(service) as *const u8;
284        let ptr2 = std::ptr::addr_of!(cloned_service) as *const u8;
285        assert_ne!(ptr1, ptr2, "Cloned service should be a different instance");
286    }
287}