rocketmq_client_rust/base/
client_config_builder.rs1use cheetah_string::CheetahString;
21use rocketmq_common::common::tls_config::TlsConfig;
22use rocketmq_error::RocketMQResult;
23use rocketmq_remoting::protocol::LanguageCode;
24
25use super::access_channel::AccessChannel;
26use super::client_config::ClientConfig;
27use super::client_config_validation::ClientConfigValidator;
28
29pub struct ClientConfigBuilder {
45 config: ClientConfig,
46}
47
48impl Default for ClientConfigBuilder {
49 fn default() -> Self {
50 Self::new()
51 }
52}
53
54impl ClientConfigBuilder {
55 pub fn new() -> Self {
57 Self {
58 config: ClientConfig::new(),
59 }
60 }
61
62 pub fn namesrv_addr(mut self, addr: impl Into<CheetahString>) -> Self {
68 self.config.set_namesrv_addr(addr.into());
69 self
70 }
71
72 pub fn client_ip(mut self, ip: impl Into<CheetahString>) -> Self {
78 self.config.set_client_ip(ip.into());
79 self
80 }
81
82 pub fn instance_name(mut self, name: impl Into<CheetahString>) -> Self {
84 self.config.set_instance_name(name.into());
85 self
86 }
87
88 pub fn client_callback_executor_threads(mut self, threads: usize) -> Self {
95 self.config.set_client_callback_executor_threads(threads);
96 self
97 }
98
99 pub fn concurrent_heartbeat_thread_pool_size(mut self, size: usize) -> Self {
101 self.config.set_concurrent_heartbeat_thread_pool_size(size);
102 self
103 }
104
105 pub fn namespace(mut self, namespace: impl Into<CheetahString>) -> Self {
111 self.config.set_namespace(namespace.into());
112 self
113 }
114
115 pub fn namespace_v2(mut self, namespace: impl Into<CheetahString>) -> Self {
117 self.config.set_namespace_v2(namespace.into());
118 self
119 }
120
121 pub fn access_channel(mut self, channel: AccessChannel) -> Self {
127 self.config.set_access_channel(channel);
128 self
129 }
130
131 pub fn poll_name_server_interval(mut self, millis: u32) -> Self {
137 self.config.set_poll_name_server_interval(millis);
138 self
139 }
140
141 pub fn heartbeat_broker_interval(mut self, millis: u32) -> Self {
143 self.config.set_heartbeat_broker_interval(millis);
144 self
145 }
146
147 pub fn persist_consumer_offset_interval(mut self, millis: u32) -> Self {
149 self.config.set_persist_consumer_offset_interval(millis);
150 self
151 }
152
153 pub fn pull_time_delay_millis_when_exception(mut self, millis: u32) -> Self {
159 self.config.set_pull_time_delay_millis_when_exception(millis);
160 self
161 }
162
163 pub fn mq_client_api_timeout(mut self, millis: u64) -> Self {
165 self.config.set_mq_client_api_timeout(millis);
166 self
167 }
168
169 pub fn detect_timeout(mut self, millis: u32) -> Self {
171 self.config.set_detect_timeout(millis);
172 self
173 }
174
175 pub fn detect_interval(mut self, millis: u32) -> Self {
177 self.config.set_detect_interval(millis);
178 self
179 }
180
181 pub fn enable_unit_mode(mut self, enabled: bool) -> Self {
187 self.config.set_unit_mode(enabled);
188 self
189 }
190
191 pub fn enable_vip_channel(mut self, enabled: bool) -> Self {
193 self.config.set_vip_channel_enabled(enabled);
194 self
195 }
196
197 pub fn enable_heartbeat_v2(mut self, enabled: bool) -> Self {
199 self.config.set_use_heartbeat_v2(enabled);
200 self
201 }
202
203 pub fn enable_concurrent_heartbeat(mut self, enabled: bool) -> Self {
205 self.config.enable_concurrent_heartbeat = enabled;
206 self
207 }
208
209 pub fn enable_tls(mut self, enabled: bool) -> Self {
211 self.config.set_use_tls(enabled);
212 self
213 }
214
215 pub fn tls_config(mut self, tls_config: TlsConfig) -> Self {
217 self.config.set_tls_config(tls_config);
218 self
219 }
220
221 pub fn tls_test_mode_enable(mut self, enabled: bool) -> Self {
223 self.config.set_tls_test_mode_enable(enabled);
224 self
225 }
226
227 pub fn tls_client_auth_server(mut self, enabled: bool) -> Self {
229 self.config.set_tls_client_auth_server(enabled);
230 self
231 }
232
233 pub fn tls_client_trust_cert_path(mut self, path: impl Into<String>) -> Self {
235 self.config.set_tls_client_trust_cert_path(path);
236 self
237 }
238
239 pub fn tls_client_cert_path(mut self, path: impl Into<String>) -> Self {
241 self.config.set_tls_client_cert_path(path);
242 self
243 }
244
245 pub fn tls_client_key_path(mut self, path: impl Into<String>) -> Self {
247 self.config.set_tls_client_key_path(path);
248 self
249 }
250
251 pub fn enable_decode_read_body(mut self, enabled: bool) -> Self {
253 self.config.set_decode_read_body(enabled);
254 self
255 }
256
257 pub fn enable_decode_decompress_body(mut self, enabled: bool) -> Self {
259 self.config.set_decode_decompress_body(enabled);
260 self
261 }
262
263 pub fn enable_stream_request_type(mut self, enabled: bool) -> Self {
265 self.config.set_enable_stream_request_type(enabled);
266 self
267 }
268
269 pub fn enable_send_latency(mut self, enabled: bool) -> Self {
271 self.config.set_send_latency_enable(enabled);
272 self
273 }
274
275 pub fn enable_start_detector(mut self, enabled: bool) -> Self {
277 self.config.set_start_detector_enable(enabled);
278 self
279 }
280
281 pub fn enable_heartbeat_channel_event_listener(mut self, enabled: bool) -> Self {
283 self.config.set_enable_heartbeat_channel_event_listener(enabled);
284 self
285 }
286
287 pub fn enable_trace(mut self, enabled: bool) -> Self {
289 self.config.set_enable_trace(enabled);
290 self
291 }
292
293 pub fn unit_name(mut self, name: impl Into<CheetahString>) -> Self {
299 self.config.set_unit_name(name.into());
300 self
301 }
302
303 pub fn socks_proxy_config(mut self, config: impl Into<CheetahString>) -> Self {
305 self.config.set_socks_proxy_config(config.into());
306 self
307 }
308
309 pub fn language(mut self, language: LanguageCode) -> Self {
311 self.config.set_language(language);
312 self
313 }
314
315 pub fn trace_topic(mut self, topic: impl Into<CheetahString>) -> Self {
317 self.config.set_trace_topic(topic.into());
318 self
319 }
320
321 pub fn trace_msg_batch_num(mut self, num: usize) -> Self {
323 self.config.set_trace_msg_batch_num(num);
324 self
325 }
326
327 pub fn max_page_size_in_get_metadata(mut self, size: usize) -> Self {
329 self.config.set_max_page_size_in_get_metadata(size);
330 self
331 }
332
333 pub fn build(self) -> RocketMQResult<ClientConfig> {
343 self.validate()?;
345 Ok(self.config)
346 }
347
348 #[doc(hidden)]
355 pub fn build_unvalidated(self) -> ClientConfig {
356 self.config
357 }
358
359 fn validate(&self) -> RocketMQResult<()> {
361 ClientConfigValidator::validate_poll_name_server_interval(self.config.poll_name_server_interval)?;
363 ClientConfigValidator::validate_heartbeat_broker_interval(self.config.heartbeat_broker_interval)?;
364 ClientConfigValidator::validate_persist_consumer_offset_interval(self.config.persist_consumer_offset_interval)?;
365
366 ClientConfigValidator::validate_mq_client_api_timeout(self.config.mq_client_api_timeout)?;
368
369 ClientConfigValidator::validate_trace_msg_batch_num(self.config.trace_msg_batch_num)?;
371 ClientConfigValidator::validate_max_page_size_in_get_metadata(self.config.max_page_size_in_get_metadata)?;
372
373 ClientConfigValidator::validate_client_callback_executor_threads(self.config.client_callback_executor_threads)?;
375
376 if self.config.enable_concurrent_heartbeat {
378 ClientConfigValidator::validate_concurrent_heartbeat_thread_pool_size(
379 self.config.concurrent_heartbeat_thread_pool_size,
380 )?;
381 }
382
383 Ok(())
384 }
385}
386
387#[cfg(test)]
388mod tests {
389 use super::*;
390
391 #[test]
392 fn test_builder_basic() {
393 let config = ClientConfig::builder()
394 .namesrv_addr("localhost:9876")
395 .instance_name("test_instance")
396 .build()
397 .unwrap();
398
399 assert_eq!(config.get_namesrv_addr().unwrap().as_str(), "localhost:9876");
400 assert_eq!(config.get_instance_name().as_str(), "test_instance");
401 }
402
403 #[test]
404 fn test_builder_with_all_options() {
405 let config = ClientConfig::builder()
406 .namesrv_addr("localhost:9876")
407 .instance_name("test")
408 .client_ip("127.0.0.1")
409 .poll_name_server_interval(60_000)
410 .heartbeat_broker_interval(30_000)
411 .enable_tls(true)
412 .enable_concurrent_heartbeat(true)
413 .concurrent_heartbeat_thread_pool_size(4)
414 .build()
415 .unwrap();
416
417 assert_eq!(config.get_namesrv_addr().unwrap().as_str(), "localhost:9876");
418 assert_eq!(config.get_instance_name().as_str(), "test");
419 assert_eq!(config.get_client_ip().unwrap().as_str(), "127.0.0.1");
420 assert_eq!(config.poll_name_server_interval, 60_000);
421 assert_eq!(config.heartbeat_broker_interval, 30_000);
422 assert!(config.use_tls);
423 assert!(config.tls_config.enable);
424 assert!(config.enable_concurrent_heartbeat);
425 assert_eq!(config.concurrent_heartbeat_thread_pool_size, 4);
426 }
427
428 #[test]
429 fn builder_sets_tls_certificate_fields() {
430 let config = ClientConfig::builder()
431 .enable_tls(true)
432 .tls_client_auth_server(false)
433 .tls_client_trust_cert_path("/certs/ca.pem")
434 .tls_client_cert_path("/certs/client.pem")
435 .tls_client_key_path("/certs/client.key")
436 .build()
437 .unwrap();
438
439 assert!(config.use_tls);
440 assert!(config.tls_config.enable);
441 assert!(!config.tls_config.client.auth_server);
442 assert_eq!(
443 config.tls_config.client.trust_cert_path.as_deref(),
444 Some("/certs/ca.pem")
445 );
446 assert_eq!(config.tls_config.client.cert_path.as_deref(), Some("/certs/client.pem"));
447 assert_eq!(config.tls_config.client.key_path.as_deref(), Some("/certs/client.key"));
448 }
449
450 #[test]
451 fn test_builder_validation_invalid_poll_interval() {
452 let result = ClientConfig::builder()
453 .poll_name_server_interval(100) .build();
455
456 assert!(result.is_err());
457 }
458
459 #[test]
460 fn test_builder_validation_invalid_heartbeat_interval() {
461 let result = ClientConfig::builder()
462 .heartbeat_broker_interval(100) .build();
464
465 assert!(result.is_err());
466 }
467
468 #[test]
469 fn test_builder_validation_invalid_thread_pool_size() {
470 let result = ClientConfig::builder()
471 .enable_concurrent_heartbeat(true)
472 .concurrent_heartbeat_thread_pool_size(0) .build();
474
475 assert!(result.is_err());
476 }
477
478 #[test]
479 fn test_builder_validation_invalid_trace_msg_batch_num() {
480 let result = ClientConfig::builder().trace_msg_batch_num(0).build();
481
482 assert!(result.is_err());
483 }
484
485 #[test]
486 fn test_builder_unvalidated() {
487 let config = ClientConfig::builder()
489 .poll_name_server_interval(100) .build_unvalidated();
491
492 assert_eq!(config.poll_name_server_interval, 100);
493 }
494}