1use super::broker::*;
16use super::group::*;
17use super::security::*;
18use super::topic::*;
19use super::*;
20
21#[allow(unused_variables, reason = "trait contracts reserve parameters")]
22#[allow(unused_mut)]
23impl RouteAdmin for DefaultMQAdminExtImpl {
24 async fn examine_broker_cluster_info(&self) -> crate::ClientResult<ClusterInfo> {
25 self.mq_client_api()?
26 .get_broker_cluster_info(self.remoting_timeout_millis()?)
27 .await
28 }
29
30 async fn get_name_server_address_list(&self) -> Vec<CheetahString> {
31 self.client_instance
32 .as_ref()
33 .map(|client_instance| {
34 client_instance
35 .get_mq_client_api_impl()
36 .map(|mq_client_api| mq_client_api.get_name_server_address_list().to_vec())
37 .unwrap_or_default()
38 })
39 .unwrap_or_default()
40 }
41
42 async fn put_kv_config(&self, namespace: CheetahString, key: CheetahString, value: CheetahString) {
43 if let Err(error) = self.create_and_update_kv_config(namespace, key, value).await {
44 warn!("put_kv_config failed: {}", error);
45 }
46 }
47
48 async fn get_kv_config(&self, namespace: CheetahString, key: CheetahString) -> crate::ClientResult<CheetahString> {
49 Ok(self
50 .client_instance
51 .as_ref()
52 .ok_or(crate::ClientError::not_started())?
53 .get_mq_client_api_impl()?
54 .get_kvconfig_value(namespace, key, self.remoting_timeout_millis()?)
55 .await?
56 .unwrap_or_default())
57 }
58
59 async fn get_kv_list_by_namespace(&self, namespace: CheetahString) -> crate::ClientResult<KVTable> {
60 self.mq_client_api()?
61 .get_kvlist_by_namespace(namespace, self.remoting_timeout_millis()?)
62 .await
63 }
64
65 async fn create_and_update_kv_config(
66 &self,
67 namespace: CheetahString,
68 key: CheetahString,
69 value: CheetahString,
70 ) -> crate::ClientResult<()> {
71 self.mq_client_api()?
72 .put_kvconfig_value(namespace, key, value, self.remoting_timeout_millis()?)
73 .await
74 }
75
76 async fn delete_kv_config(&self, namespace: CheetahString, key: CheetahString) -> crate::ClientResult<()> {
77 self.mq_client_api()?
78 .delete_kvconfig_value(namespace, key, self.remoting_timeout_millis()?)
79 .await
80 }
81
82 async fn get_cluster_list(&self, topic: String) -> crate::ClientResult<HashSet<CheetahString>> {
83 self.get_topic_cluster_list(topic).await
84 }
85
86 async fn update_name_server_config(
87 &self,
88 properties: HashMap<CheetahString, CheetahString>,
89 name_servers: Option<Vec<CheetahString>>,
90 ) -> crate::ClientResult<()> {
91 self.mq_client_api()?
92 .update_name_server_config(properties, name_servers, self.remoting_timeout_millis()?)
93 .await
94 }
95
96 async fn get_name_server_config(
97 &self,
98 name_servers: Vec<CheetahString>,
99 ) -> crate::ClientResult<HashMap<CheetahString, HashMap<CheetahString, CheetahString>>> {
100 Ok(self
101 .mq_client_api()?
102 .get_name_server_config(Some(name_servers), self.timeout_millis)
103 .await?
104 .unwrap_or_default())
105 }
106
107 async fn probe_name_server(&self, name_server: CheetahString) -> crate::ClientResult<()> {
108 self.client_instance
109 .as_ref()
110 .ok_or(crate::ClientError::not_started())?
111 .get_mq_client_api_impl()?
112 .probe_name_server(&name_server, self.timeout_millis)
113 .await
114 }
115}
116
117#[allow(unused_variables, reason = "trait contracts reserve parameters")]
118#[allow(unused_mut)]
119impl TopicAdmin for DefaultMQAdminExtImpl {
120 async fn create_and_update_topic_config(
121 &self,
122 addr: CheetahString,
123 config: TopicConfig,
124 ) -> crate::ClientResult<()> {
125 let topic = config
126 .topic_name
127 .clone()
128 .ok_or_else(|| crate::ClientError::illegal_argument("Topic name is required"))?;
129 let attributes = encode_topic_attributes(&config.attributes);
130 let request_header = CreateTopicRequestHeader {
131 topic,
132 default_topic: CheetahString::from_static_str(TopicValidator::AUTO_CREATE_TOPIC_KEY_TOPIC),
133 read_queue_nums: config.read_queue_nums as i32,
134 write_queue_nums: config.write_queue_nums as i32,
135 perm: config.perm as i32,
136 topic_filter_type: CheetahString::from_static_str(config.topic_filter_type.as_str()),
137 topic_sys_flag: Some(config.topic_sys_flag as i32),
138 order: config.order,
139 attributes,
140 force: Some(false),
141 topic_request_header: None,
142 };
143
144 self.mq_client_api()?
145 .update_or_create_topic(&addr, request_header, self.remoting_timeout_millis()?)
146 .await
147 }
148
149 async fn create_and_update_topic_config_list(
150 &self,
151 addr: CheetahString,
152 topic_config_list: Vec<TopicConfig>,
153 ) -> crate::ClientResult<()> {
154 for config in topic_config_list {
155 self.create_and_update_topic_config(addr.clone(), config).await?;
156 }
157 Ok(())
158 }
159
160 async fn examine_topic_stats(
161 &self,
162 topic: CheetahString,
163 broker_addr: Option<CheetahString>,
164 ) -> crate::ClientResult<TopicStatsTable> {
165 let timeout = self.remoting_timeout_millis()?;
166 let request_header = GetTopicStatsInfoRequestHeader {
167 topic: topic.clone(),
168 topic_request_header: None,
169 };
170 if let Some(addr) = broker_addr {
171 return self
172 .mq_client_api()?
173 .get_topic_stats_info(&addr, request_header, timeout)
174 .await;
175 }
176
177 let topic_route = self.examine_topic_route_info(topic).await?;
178 let mut result = TopicStatsTable::new();
179 if let Some(route_data) = topic_route {
180 for broker_data in &route_data.broker_datas {
181 if let Some(master_addr) = broker_data.broker_addrs().get(&mix_all::MASTER_ID) {
182 let stats = self
183 .mq_client_api()?
184 .get_topic_stats_info(master_addr, request_header.clone(), timeout)
185 .await?;
186 result.get_offset_table_mut().extend(stats.into_offset_table());
187 }
188 }
189 }
190
191 Ok(result)
192 }
193
194 async fn examine_topic_stats_concurrent(&self, topic: CheetahString) -> AdminToolResult<TopicStatsTable> {
195 match self.examine_topic_stats(topic, None).await {
196 Ok(stats) => AdminToolResult::success(stats),
197 Err(error) => AdminToolResult::failure(
198 crate::common::admin_tools_result_code_enum::AdminToolsResultCodeEnum::RemotingError,
199 error.to_string(),
200 ),
201 }
202 }
203
204 async fn fetch_all_topic_list(&self) -> crate::ClientResult<TopicList> {
205 self.mq_client_api()?
206 .get_all_topic_list_from_name_server(self.remoting_timeout_millis()?)
207 .await
208 }
209
210 async fn fetch_topics_by_cluster(&self, cluster_name: CheetahString) -> crate::ClientResult<TopicList> {
211 self.mq_client_api()?
212 .get_topics_by_cluster(cluster_name, self.remoting_timeout_millis()?)
213 .await
214 }
215
216 async fn examine_topic_route_info(&self, topic: CheetahString) -> crate::ClientResult<Option<TopicRouteData>> {
217 self.mq_client_api()?
218 .get_topic_route_info_from_name_server(&topic, self.remoting_timeout_millis()?)
219 .await
220 }
221
222 async fn delete_topic(&self, topic_name: CheetahString, cluster_name: CheetahString) -> crate::ClientResult<()> {
223 let cluster_info = self.examine_broker_cluster_info().await?;
224 let mut broker_addrs = HashSet::new();
225 if let Some(cluster_addr_table) = cluster_info.cluster_addr_table.as_ref() {
226 if let Some(broker_names) = cluster_addr_table.get(&cluster_name) {
227 if let Some(broker_addr_table) = cluster_info.broker_addr_table.as_ref() {
228 for broker_name in broker_names {
229 if let Some(broker_data) = broker_addr_table.get(broker_name) {
230 broker_addrs.extend(broker_data.broker_addrs().values().cloned());
231 }
232 }
233 }
234 }
235 }
236 self.delete_topic_in_broker(broker_addrs, topic_name.clone()).await?;
237
238 let namesrv_addrs: HashSet<CheetahString> = self.get_name_server_address_list().await.into_iter().collect();
239 self.delete_topic_in_name_server(namesrv_addrs, Some(cluster_name), topic_name)
240 .await
241 }
242
243 async fn delete_topic_in_broker(
244 &self,
245 addrs: HashSet<CheetahString>,
246 topic: CheetahString,
247 ) -> crate::ClientResult<()> {
248 let request_header = DeleteTopicRequestHeader {
249 topic: topic.clone(),
250 topic_request_header: None,
251 };
252 let api = self.mq_client_api()?;
253 let timeout = self.remoting_timeout_millis()?;
254 for addr in addrs {
255 api.delete_topic_in_broker(
256 &addr,
257 DeleteTopicRequestHeader {
258 topic: request_header.topic.clone(),
259 topic_request_header: None,
260 },
261 timeout,
262 )
263 .await?;
264 }
265 Ok(())
266 }
267
268 async fn delete_topic_in_broker_list(
269 &self,
270 addrs: HashSet<CheetahString>,
271 topics: Vec<CheetahString>,
272 ) -> crate::ClientResult<()> {
273 let api = self.mq_client_api()?;
274 let timeout = self.remoting_timeout_millis()?;
275 for addr in addrs {
276 api.delete_topic_in_broker_list(&addr, topics.clone(), timeout).await?;
277 }
278 Ok(())
279 }
280
281 async fn delete_topic_in_name_server(
282 &self,
283 addrs: HashSet<CheetahString>,
284 cluster_name: Option<CheetahString>,
285 topic: CheetahString,
286 ) -> crate::ClientResult<()> {
287 let request_header = DeleteTopicFromNamesrvRequestHeader::new(topic, cluster_name);
288 let api = self.mq_client_api()?;
289 let timeout = self.remoting_timeout_millis()?;
290 for addr in addrs {
291 api.delete_topic_in_nameserver(&addr, request_header.clone(), timeout)
292 .await?;
293 }
294 Ok(())
295 }
296
297 async fn create_or_update_order_conf(
298 &self,
299 key: CheetahString,
300 value: CheetahString,
301 is_cluster: bool,
302 ) -> crate::ClientResult<()> {
303 if is_cluster {
304 return self
305 .mq_client_api()?
306 .put_kvconfig_value(
307 CheetahString::from_static_str(NAMESPACE_ORDER_TOPIC_CONFIG),
308 key,
309 value,
310 self.remoting_timeout_millis()?,
311 )
312 .await;
313 }
314
315 let existing = self
316 .mq_client_api()?
317 .get_kvconfig_value(
318 CheetahString::from_static_str(NAMESPACE_ORDER_TOPIC_CONFIG),
319 key.clone(),
320 self.remoting_timeout_millis()?,
321 )
322 .await?
323 .unwrap_or_default();
324
325 let merged_order_conf = merge_order_conf_entries(existing.as_str(), value.as_str());
326
327 self.mq_client_api()?
328 .put_kvconfig_value(
329 CheetahString::from_static_str(NAMESPACE_ORDER_TOPIC_CONFIG),
330 key,
331 merged_order_conf.into(),
332 self.remoting_timeout_millis()?,
333 )
334 .await
335 }
336
337 async fn query_topic_consume_by_who(&self, topic: CheetahString) -> crate::ClientResult<GroupList> {
338 let topic_route = self
339 .mq_client_api()?
340 .get_topic_route_info_from_name_server(&topic, self.remoting_timeout_millis()?)
341 .await?;
342
343 if let Some(route_data) = topic_route {
344 for bd in &route_data.broker_datas {
345 if let Some(master_addr) = bd.broker_addrs().get(&rocketmq_model::common::mix_all::MASTER_ID) {
346 let request_header = QueryTopicConsumeByWhoRequestHeader {
347 topic: topic.clone(),
348 topic_request_header: None,
349 };
350 return self
351 .mq_client_api()?
352 .query_topic_consume_by_who(master_addr, request_header, self.remoting_timeout_millis()?)
353 .await;
354 }
355 }
356 }
357
358 Ok(GroupList::default())
359 }
360
361 async fn query_topics_by_consumer(&self, group: CheetahString) -> crate::ClientResult<TopicList> {
362 self.query_topics_by_consumer_from_route(group).await
363 }
364
365 async fn query_topics_by_consumer_concurrent(&self, group: CheetahString) -> AdminToolResult<TopicList> {
366 let timeout = match self.remoting_timeout_millis() {
367 Ok(timeout) => timeout,
368 Err(error) => return AdminToolResult::failure(admin_result_code_for_error(&error), error.to_string()),
369 };
370 let retry_topic: CheetahString = mix_all::get_retry_topic(&group).into();
371 let api = match self.mq_client_api() {
372 Ok(api) => api,
373 Err(error) => {
374 return AdminToolResult::failure(AdminToolsResultCodeEnum::MQClientError, error.to_string());
375 }
376 };
377 let topic_route = match api.get_topic_route_info_from_name_server(&retry_topic, timeout).await {
378 Ok(Some(route_data)) if !route_data.broker_datas.is_empty() => route_data,
379 Ok(_) => {
380 return AdminToolResult::failure(
381 AdminToolsResultCodeEnum::TopicRouteInfoNotExist,
382 "router info not found.".to_string(),
383 )
384 }
385 Err(error) => {
386 return AdminToolResult::failure(AdminToolsResultCodeEnum::MQClientError, error.to_string());
387 }
388 };
389
390 let mut result = TopicList::default();
391 for broker_data in &topic_route.broker_datas {
392 let Some(addr) = broker_data.select_broker_addr() else {
393 continue;
394 };
395 match api
396 .query_topics_by_consumer(&addr, QueryTopicsByConsumerRequestHeader::new(group.clone()), timeout)
397 .await
398 {
399 Ok(topic_list) => {
400 for topic in topic_list.topic_list {
401 if !result.topic_list.contains(&topic) {
402 result.topic_list.push(topic);
403 }
404 }
405 }
406 Err(error) => {
407 warn!("query_topics_by_consumer error. group={}, error={}", group, error);
408 }
409 }
410 }
411
412 AdminToolResult::success(result)
413 }
414
415 async fn clean_unused_topic(
416 &self,
417 cluster: Option<CheetahString>,
418 addr: Option<CheetahString>,
419 ) -> crate::ClientResult<bool> {
420 self.execute_broker_cleanup_operation(cluster, addr, BrokerCleanupOperation::CleanUnusedTopic)
421 .await
422 }
423
424 async fn clean_unused_topic_by_addr(&self, addr: CheetahString) -> crate::ClientResult<bool> {
425 self.clean_unused_topic(None, Some(addr)).await
426 }
427
428 async fn get_topic_cluster_list(&self, topic: String) -> crate::ClientResult<HashSet<CheetahString>> {
429 let cluster_info = self.examine_broker_cluster_info().await?;
430 let topic_route_data = self
431 .examine_topic_route_info(topic.clone().into())
432 .await?
433 .ok_or_else(|| mq_client_err!(format!("Topic route not found for: {topic}")))?;
434 let broker_data = topic_route_data
435 .broker_datas
436 .first()
437 .ok_or_else(|| mq_client_err!("Broker datas is empty"))?;
438 let mut cluster_set = HashSet::new();
439 let broker_name = broker_data.broker_name();
440 if let Some(cluster_addr_table) = cluster_info.cluster_addr_table.as_ref() {
441 cluster_set.extend(
442 cluster_addr_table
443 .iter()
444 .filter(|(cluster_name, broker_names)| broker_names.contains(broker_name))
445 .map(|(cluster_name, broker_names)| cluster_name.clone()),
446 );
447 }
448 Ok(cluster_set)
449 }
450
451 async fn get_all_topic_config(
452 &self,
453 broker_addr: CheetahString,
454 timeout_millis: u64,
455 ) -> crate::ClientResult<TopicConfigSerializeWrapper> {
456 self.mq_client_api()?
457 .get_all_topic_config(&broker_addr, timeout_millis)
458 .await
459 }
460
461 async fn set_message_request_mode(
462 &self,
463 broker_addr: CheetahString,
464 topic: CheetahString,
465 consumer_group: CheetahString,
466 mode: MessageRequestMode,
467 pop_work_group_size: i32,
468 timeout_millis: u64,
469 ) -> crate::ClientResult<()> {
470 let mq_client_api = self.mq_client_api()?;
471 match mq_client_api
472 .set_message_request_mode(
473 &broker_addr,
474 &topic,
475 &consumer_group,
476 mode,
477 pop_work_group_size,
478 timeout_millis,
479 )
480 .await
481 {
482 Ok(_) => Ok(()),
483 Err(e) => Err(e),
484 }
485 }
486
487 async fn examine_topic_config(
488 &self,
489 addr: CheetahString,
490 topic: CheetahString,
491 ) -> crate::ClientResult<TopicConfig> {
492 self.client_instance
493 .as_ref()
494 .ok_or(crate::ClientError::not_started())?
495 .get_topic_config(&addr, topic, self.remoting_timeout_millis()?)
496 .await
497 }
498
499 async fn create_static_topic(
500 &self,
501 addr: CheetahString,
502 default_topic: CheetahString,
503 topic_config: TopicConfig,
504 mapping_detail: TopicQueueMappingDetail,
505 force: bool,
506 ) -> crate::ClientResult<()> {
507 self.mq_client_api()?
508 .create_static_topic(
509 &addr,
510 default_topic,
511 topic_config,
512 mapping_detail,
513 force,
514 self.remoting_timeout_millis()?,
515 )
516 .await
517 }
518
519 async fn create_lite_pull_topic(
520 &self,
521 addr: CheetahString,
522 topic: CheetahString,
523 queue_num: i32,
524 topic_sys_flag: i32,
525 read_queue_nums: i32,
526 write_queue_nums: i32,
527 ) -> crate::ClientResult<()> {
528 let config = lite_pull_topic_config(
529 topic,
530 queue_num,
531 topic_sys_flag,
532 read_queue_nums,
533 write_queue_nums,
534 false,
535 )?;
536 self.create_and_update_topic_config(addr, config).await
537 }
538
539 async fn update_lite_pull_topic(
540 &self,
541 addr: CheetahString,
542 topic: CheetahString,
543 read_queue_nums: i32,
544 write_queue_nums: i32,
545 ) -> crate::ClientResult<()> {
546 let config = lite_pull_topic_config(topic, 0, 0, read_queue_nums, write_queue_nums, true)?;
547 self.create_and_update_topic_config(addr, config).await
548 }
549
550 async fn get_lite_pull_topic(&self, addr: CheetahString, topic: CheetahString) -> crate::ClientResult<TopicConfig> {
551 let lite_info = self
552 .mq_client_api()?
553 .get_broker_lite_info(&addr, self.remoting_timeout_millis()?)
554 .await?;
555 if !lite_info.get_topic_meta().contains_key(&topic) {
556 return Err(mq_client_err!(format!("Lite pull topic not found: {topic}")));
557 }
558 self.examine_topic_config(addr, topic).await
559 }
560
561 async fn delete_lite_pull_topic(
562 &self,
563 addr: CheetahString,
564 cluster_name: CheetahString,
565 topic: CheetahString,
566 ) -> crate::ClientResult<()> {
567 self.delete_topic_in_broker(HashSet::from([addr]), topic.clone())
568 .await?;
569 if cluster_name.is_empty() {
570 return Ok(());
571 }
572 let namesrv_addrs = self.get_name_server_address_list().await.into_iter().collect();
573 self.delete_topic_in_name_server(namesrv_addrs, Some(cluster_name), topic)
574 .await
575 }
576
577 async fn query_lite_pull_topic_list(&self, addr: CheetahString) -> crate::ClientResult<TopicList> {
578 let lite_info = self
579 .mq_client_api()?
580 .get_broker_lite_info(&addr, self.remoting_timeout_millis()?)
581 .await?;
582 Ok(lite_topic_list_from_broker_lite_info(Some(addr), &lite_info))
583 }
584
585 async fn query_lite_pull_topic_by_cluster(&self, cluster_name: CheetahString) -> crate::ClientResult<TopicList> {
586 let timeout_millis = self.remoting_timeout_millis()?;
587 let api = self.mq_client_api()?;
588 let cluster_info = api.get_broker_cluster_info(timeout_millis).await?;
589 let mut topic_names = HashSet::new();
590
591 for broker_addr in broker_addrs_for_cluster(&cluster_info, &cluster_name) {
592 let lite_info = api.get_broker_lite_info(&broker_addr, timeout_millis).await?;
593 topic_names.extend(lite_info.get_topic_meta().keys().cloned());
594 }
595
596 Ok(topic_list_from_lite_topic_names(None, topic_names))
597 }
598
599 async fn get_topic_config_by_topic_name(
600 &self,
601 broker_addr: CheetahString,
602 topic_name: CheetahString,
603 ) -> crate::ClientResult<TopicConfig> {
604 self.client_instance
605 .as_ref()
606 .ok_or(crate::ClientError::not_started())?
607 .get_topic_config(&broker_addr, topic_name, self.remoting_timeout_millis()?)
608 .await
609 }
610
611 async fn get_topic_stats_info(
612 &self,
613 broker_addr: CheetahString,
614 topic: CheetahString,
615 ) -> crate::ClientResult<TopicStatsTable> {
616 self.mq_client_api()?
617 .get_topic_stats_info(
618 &broker_addr,
619 GetTopicStatsInfoRequestHeader {
620 topic,
621 topic_request_header: None,
622 },
623 self.remoting_timeout_millis()?,
624 )
625 .await
626 }
627
628 async fn query_broker_has_topic(
629 &self,
630 broker_addr: CheetahString,
631 topic: CheetahString,
632 ) -> crate::ClientResult<bool> {
633 map_topic_config_lookup_result(self.get_topic_config_by_topic_name(broker_addr, topic).await)
634 }
635
636 async fn get_system_topic_list_from_broker(&self, broker_addr: CheetahString) -> crate::ClientResult<TopicList> {
637 self.mq_client_api()?
638 .get_system_topic_list_from_broker(&broker_addr, self.remoting_timeout_millis()?)
639 .await
640 }
641
642 async fn examine_topic_route_info_with_timeout(
643 &self,
644 topic: CheetahString,
645 timeout_millis: u64,
646 ) -> crate::ClientResult<Option<TopicRouteData>> {
647 self.mq_client_api()?
648 .get_topic_route_info_from_name_server(&topic, timeout_millis)
649 .await
650 }
651 #[allow(deprecated)]
652 async fn delete_topic_in_broker_concurrent(
653 &self,
654 addrs: HashSet<CheetahString>,
655 topic: CheetahString,
656 ) -> AdminToolResult<BrokerOperatorResult> {
657 let api = match self.mq_client_api() {
658 Ok(api) => api,
659 Err(error) => {
660 return AdminToolResult::failure(admin_result_code_for_error(&error), error.to_string());
661 }
662 };
663 let timeout = match self.remoting_timeout_millis() {
664 Ok(timeout) => timeout,
665 Err(error) => return AdminToolResult::failure(admin_result_code_for_error(&error), error.to_string()),
666 };
667 let mut success_list = Vec::new();
668 let mut failure_list = Vec::new();
669
670 for addr in addrs {
671 let request_header = DeleteTopicRequestHeader {
672 topic: topic.clone(),
673 topic_request_header: None,
674 };
675 match api.delete_topic_in_broker(&addr, request_header, timeout).await {
676 Ok(()) => success_list.push(addr),
677 Err(error) => {
678 warn!("deleteTopicInBroker error. topic={}, broker={}, {}", topic, addr, error);
679 failure_list.push(addr);
680 }
681 }
682 }
683
684 AdminToolResult::success(broker_operator_result(success_list, failure_list))
685 }
686
687 async fn get_parent_topic_info(
688 &self,
689 broker_addr: CheetahString,
690 topic: CheetahString,
691 ) -> crate::ClientResult<GetParentTopicInfoResponseBody> {
692 self.mq_client_api()?
693 .get_parent_topic_info(&broker_addr, topic, self.remoting_timeout_millis()?)
694 .await
695 }
696
697 async fn get_lite_topic_info(
698 &self,
699 broker_addr: CheetahString,
700 parent_topic: CheetahString,
701 lite_topic: CheetahString,
702 ) -> crate::ClientResult<GetLiteTopicInfoResponseBody> {
703 if let Some(ref mq_client_instance) = self.client_instance {
704 mq_client_instance
705 .get_mq_client_api_impl()?
706 .get_lite_topic_info(
707 &broker_addr,
708 &parent_topic,
709 &lite_topic,
710 self.remoting_timeout_millis()?,
711 )
712 .await
713 } else {
714 Err(crate::ClientError::not_started())
715 }
716 }
717}
718
719#[allow(unused_variables, reason = "trait contracts reserve parameters")]
720#[allow(unused_mut)]
721impl ConsumerAdmin for DefaultMQAdminExtImpl {
722 async fn create_and_update_subscription_group_config(
723 &self,
724 addr: CheetahString,
725 config: SubscriptionGroupConfig,
726 ) -> crate::ClientResult<()> {
727 self.client_instance
728 .as_ref()
729 .ok_or(crate::ClientError::not_started())?
730 .get_mq_client_api_impl()?
731 .create_subscription_group(&addr, &config, self.remoting_timeout_millis()?)
732 .await
733 }
734
735 async fn create_and_update_subscription_group_config_list(
736 &self,
737 broker_addr: CheetahString,
738 configs: Vec<SubscriptionGroupConfig>,
739 ) -> crate::ClientResult<()> {
740 for config in configs {
741 self.create_and_update_subscription_group_config(broker_addr.clone(), config)
742 .await?;
743 }
744 Ok(())
745 }
746
747 async fn examine_subscription_group_config(
748 &self,
749 addr: CheetahString,
750 group: CheetahString,
751 ) -> crate::ClientResult<SubscriptionGroupConfig> {
752 self.mq_client_api()?
753 .get_subscription_group_config(&addr, group, self.remoting_timeout_millis()?)
754 .await
755 }
756
757 async fn examine_consume_stats(
758 &self,
759 consumer_group: CheetahString,
760 topic: Option<CheetahString>,
761 cluster_name: Option<CheetahString>,
762 broker_addr: Option<CheetahString>,
763 timeout_millis: Option<u64>,
764 ) -> crate::ClientResult<ConsumeStats> {
765 let timeout = timeout_millis.unwrap_or(self.remoting_timeout_millis()?);
766 let topic_str = topic.clone().unwrap_or_default();
767
768 if let Some(addr) = broker_addr {
769 let request_header = GetConsumeStatsRequestHeader {
770 consumer_group,
771 topic: topic_str,
772 topic_list: None,
773 topic_request_header: None,
774 };
775 return self
776 .mq_client_api()?
777 .get_consume_stats(&addr, request_header, timeout)
778 .await;
779 }
780
781 let retry_topic: CheetahString = rocketmq_model::common::mix_all::get_retry_topic(&consumer_group).into();
782 let topic_route = self
783 .mq_client_api()?
784 .get_topic_route_info_from_name_server(&retry_topic, timeout)
785 .await?;
786
787 let mut result = ConsumeStats::new();
788
789 if let Some(route_data) = topic_route {
790 for bd in &route_data.broker_datas {
791 if let Some(master_addr) = bd.broker_addrs().get(&rocketmq_model::common::mix_all::MASTER_ID) {
792 let request_header = GetConsumeStatsRequestHeader {
793 consumer_group: consumer_group.clone(),
794 topic: topic_str.clone(),
795 topic_list: None,
796 topic_request_header: None,
797 };
798 let cs = self
799 .mq_client_api()?
800 .get_consume_stats(master_addr, request_header, timeout)
801 .await?;
802
803 result.get_offset_table_mut().extend(cs.offset_table);
804 let new_tps = result.get_consume_tps() + cs.consume_tps;
805 result.set_consume_tps(new_tps);
806 }
807 }
808 }
809
810 Ok(result)
811 }
812
813 async fn examine_consumer_connection_info(
814 &self,
815 consumer_group: CheetahString,
816 broker_addr: Option<CheetahString>,
817 ) -> crate::ClientResult<ConsumerConnection> {
818 let mut result = ConsumerConnection::new();
819 let timeout = self.remoting_timeout_millis()?;
820
821 let selected_addr = if let Some(broker_addr) = broker_addr {
822 Some(broker_addr)
823 } else {
824 let topic = CheetahString::from_string(mix_all::get_retry_topic(consumer_group.as_str()));
825 let topic_route_data = self
826 .mq_client_api()?
827 .get_topic_route_info_from_name_server(&topic, timeout)
828 .await?;
829
830 topic_route_data.and_then(|topic_route_data| {
831 topic_route_data
832 .broker_datas
833 .choose(&mut rand::rng())
834 .and_then(|broker_data| broker_data.select_broker_addr())
835 })
836 };
837
838 if let Some(broker_addr) = selected_addr {
839 result = self
840 .mq_client_api()?
841 .get_consumer_connection_list(broker_addr.as_str(), consumer_group.clone(), timeout)
842 .await?;
843 }
844
845 if result.get_connection_set().is_empty() {
846 return Err(mq_client_err!(
847 rocketmq_protocol::code::response_code::ResponseCode::ConsumerNotOnline,
848 "Not found the consumer group connection"
849 ));
850 }
851
852 Ok(result)
853 }
854
855 async fn examine_producer_connection_info(
856 &self,
857 producer_group: CheetahString,
858 topic: CheetahString,
859 ) -> crate::ClientResult<ProducerConnection> {
860 let mut result = ProducerConnection::new();
861 let timeout = self.remoting_timeout_millis()?;
862
863 if let Some(topic_route_data) = self.examine_topic_route_info(topic).await? {
864 let brokers = &topic_route_data.broker_datas;
865 let selected_addr = brokers
866 .choose(&mut rand::rng())
867 .and_then(|broker_data| broker_data.select_broker_addr());
868 if let Some(addr) = selected_addr {
869 result = self
870 .mq_client_api()?
871 .get_producer_connection_list(addr.as_str(), producer_group.clone(), timeout)
872 .await?;
873 }
874 }
875
876 if result.connection_set().is_empty() {
877 return Err(mq_client_err!("Not found the producer group connection"));
878 }
879
880 Ok(result)
881 }
882
883 async fn get_all_producer_info(&self, broker_addr: CheetahString) -> crate::ClientResult<ProducerTableInfo> {
884 self.mq_client_api()?
885 .get_all_producer_info(broker_addr.as_str(), self.remoting_timeout_millis()?)
886 .await
887 }
888
889 async fn delete_subscription_group(
890 &self,
891 addr: CheetahString,
892 group_name: CheetahString,
893 remove_offset: Option<bool>,
894 ) -> crate::ClientResult<()> {
895 self.mq_client_api()?
896 .delete_subscription_group(
897 &addr,
898 group_name,
899 remove_offset.unwrap_or(false),
900 self.remoting_timeout_millis()?,
901 )
902 .await
903 }
904
905 async fn delete_subscription_group_list(
906 &self,
907 addr: CheetahString,
908 group_names: Vec<CheetahString>,
909 clean_offset: bool,
910 ) -> crate::ClientResult<()> {
911 self.mq_client_api()?
912 .delete_subscription_group_list(&addr, group_names, clean_offset, self.remoting_timeout_millis()?)
913 .await
914 }
915
916 async fn get_consume_status(
917 &self,
918 topic: CheetahString,
919 group: CheetahString,
920 client_addr: CheetahString,
921 ) -> crate::ClientResult<HashMap<CheetahString, HashMap<MessageQueue, u64>>> {
922 let Some(route_data) = self.examine_topic_route_info(topic.clone()).await? else {
923 return Ok(HashMap::new());
924 };
925
926 let api = self.mq_client_api()?;
927 let timeout = self.remoting_timeout_millis()?;
928 let mut merged = HashMap::new();
929 let mut queried = false;
930 let mut last_error = None;
931
932 for broker_data in &route_data.broker_datas {
933 let Some(addr) = broker_data.select_broker_addr() else {
934 continue;
935 };
936 queried = true;
937 match api
938 .invoke_broker_to_get_consumer_status(
939 addr.as_str(),
940 topic.clone(),
941 group.clone(),
942 client_addr.clone(),
943 timeout,
944 )
945 .await
946 {
947 Ok(result) => merge_consume_status_result(&mut merged, result)?,
948 Err(error) => {
949 warn!("get_consume_status failed on broker {}: {}", addr, error);
950 last_error = Some(error);
951 }
952 }
953 }
954
955 if !merged.is_empty() || last_error.is_none() || !queried {
956 return Ok(merged);
957 }
958
959 if let Some(error) = last_error {
960 Err(error)
961 } else {
962 Ok(merged)
963 }
964 }
965
966 async fn query_subscription(
967 &self,
968 group: CheetahString,
969 topic: CheetahString,
970 ) -> crate::ClientResult<SubscriptionData> {
971 let timeout = self.remoting_timeout_millis()?;
972 let api = self.mq_client_api()?;
973 let topic_route = api.get_topic_route_info_from_name_server(&topic, timeout).await?;
974 let Some(route_data) = topic_route else {
975 return Err(mq_client_err!(format!("Topic route not found for: {topic}")));
976 };
977
978 for broker_data in &route_data.broker_datas {
979 let Some(addr) = broker_data.select_broker_addr() else {
980 continue;
981 };
982 let request_header = QuerySubscriptionByConsumerRequestHeader {
983 group: group.clone(),
984 topic: topic.clone(),
985 topic_request_header: None,
986 };
987 return api.query_subscription_by_consumer(&addr, request_header, timeout).await;
988 }
989
990 Err(mq_client_err!(format!("Broker address not found for topic: {topic}")))
991 }
992
993 async fn clean_expired_consumer_queue(
994 &self,
995 cluster: Option<CheetahString>,
996 addr: Option<CheetahString>,
997 ) -> crate::ClientResult<bool> {
998 self.execute_broker_cleanup_operation(cluster, addr, BrokerCleanupOperation::CleanExpiredConsumerQueue)
999 .await
1000 }
1001
1002 async fn clean_expired_consumer_queue_by_addr(&self, addr: CheetahString) -> crate::ClientResult<bool> {
1003 self.clean_expired_consumer_queue(None, Some(addr)).await
1004 }
1005
1006 async fn get_consumer_running_info(
1007 &self,
1008 consumer_group: CheetahString,
1009 client_id: CheetahString,
1010 jstack: bool,
1011 _metrics: Option<bool>,
1012 ) -> crate::ClientResult<ConsumerRunningInfo> {
1013 let retry_topic = CheetahString::from_string(mix_all::get_retry_topic(&consumer_group));
1014 let route = self
1015 .examine_topic_route_info(retry_topic.clone())
1016 .await?
1017 .ok_or_else(|| admin_route_not_found(&retry_topic))?;
1018 let api = self.mq_client_api()?;
1019 let timeout = self.remoting_timeout_millis()?;
1020 let mut last_error = None;
1021 for broker in &route.broker_datas {
1025 let Some(address) = broker.select_broker_addr() else {
1026 continue;
1027 };
1028 match api
1029 .get_consumer_running_info(&address, consumer_group.clone(), client_id.clone(), jstack, timeout)
1030 .await
1031 {
1032 Ok(info) => return Ok(info),
1033 Err(error) => last_error = Some(error),
1034 }
1035 }
1036 Err(last_error.unwrap_or_else(|| admin_route_not_found(&retry_topic)))
1037 }
1038
1039 async fn consume_message_directly(
1040 &self,
1041 consumer_group: CheetahString,
1042 client_id: CheetahString,
1043 topic: CheetahString,
1044 msg_id: CheetahString,
1045 ) -> crate::ClientResult<ConsumeMessageDirectlyResult> {
1046 let message =
1047 ConsumerAdmin::query_message(self, CheetahString::default(), topic.clone(), msg_id.clone()).await?;
1048 let broker_addr = CheetahString::from(message.store_host().to_string());
1053 let consumer_connection = self
1054 .examine_consumer_connection_info(consumer_group.clone(), Some(broker_addr.clone()))
1055 .await?;
1056 let (resolved_client_id, _) =
1057 select_consumer_direct_connection(&consumer_group, &consumer_connection, Some(&client_id))?;
1058 let request_header = ConsumeMessageDirectlyResultRequestHeader {
1059 consumer_group,
1060 client_id: Some(resolved_client_id),
1061 msg_id: Some(msg_id),
1062 broker_name: (!message.broker_name().is_empty()).then(|| message.broker_name.clone()),
1063 topic: Some(topic),
1064 topic_sys_flag: None,
1065 group_sys_flag: None,
1066 topic_request_header: None,
1067 };
1068
1069 self.client_instance
1070 .as_ref()
1071 .ok_or(crate::ClientError::not_started())?
1072 .get_mq_client_api_impl()?
1073 .consume_message_directly(&broker_addr, request_header, &message, self.remoting_timeout_millis()?)
1074 .await
1075 }
1076
1077 async fn consume_message_directly_ext(
1078 &self,
1079 _cluster_name: CheetahString,
1080 consumer_group: CheetahString,
1081 client_id: CheetahString,
1082 topic: CheetahString,
1083 msg_id: CheetahString,
1084 ) -> crate::ClientResult<ConsumeMessageDirectlyResult> {
1085 self.consume_message_directly(consumer_group, client_id, topic, msg_id)
1086 .await
1087 }
1088
1089 async fn update_cold_data_flow_ctr_group_config(
1090 &self,
1091 broker_addr: CheetahString,
1092 properties: HashMap<CheetahString, CheetahString>,
1093 ) -> crate::ClientResult<()> {
1094 self.mq_client_api()?
1095 .update_cold_data_flow_ctr_group_config(broker_addr, properties, self.remoting_timeout_millis()?)
1096 .await
1097 }
1098
1099 async fn remove_cold_data_flow_ctr_group_config(
1100 &self,
1101 broker_addr: CheetahString,
1102 consumer_group: CheetahString,
1103 ) -> crate::ClientResult<()> {
1104 self.mq_client_api()?
1105 .remove_cold_data_flow_ctr_group_config(broker_addr, consumer_group, self.remoting_timeout_millis()?)
1106 .await
1107 }
1108
1109 async fn query_lite_pull_subscription_list(
1110 &self,
1111 addr: CheetahString,
1112 topic: CheetahString,
1113 ) -> crate::ClientResult<GroupList> {
1114 let lite_info = self
1115 .mq_client_api()?
1116 .get_broker_lite_info(&addr, self.remoting_timeout_millis()?)
1117 .await?;
1118 Ok(lite_subscription_group_list_from_broker_lite_info(&topic, &lite_info))
1119 }
1120
1121 async fn examine_consume_stats_with_queue(
1122 &self,
1123 consumer_group: CheetahString,
1124 topic: Option<CheetahString>,
1125 queue_id: Option<i32>,
1126 ) -> crate::ClientResult<ConsumeStats> {
1127 let mut stats = self
1128 .examine_consume_stats(consumer_group, topic.clone(), None, None, None)
1129 .await?;
1130 filter_consume_stats(&mut stats, topic.as_ref(), queue_id);
1131 Ok(stats)
1132 }
1133
1134 async fn examine_consume_stats_concurrent(
1135 &self,
1136 consumer_group: CheetahString,
1137 topic: Option<CheetahString>,
1138 ) -> AdminToolResult<ConsumeStats> {
1139 match self
1140 .examine_consume_stats(consumer_group, topic, None, None, None)
1141 .await
1142 {
1143 Ok(stats) => AdminToolResult::success(stats),
1144 Err(error) => AdminToolResult::failure(admin_result_code_for_error(&error), error.to_string()),
1145 }
1146 }
1147
1148 async fn examine_consume_stats_concurrent_with_cluster(
1149 &self,
1150 consumer_group: CheetahString,
1151 topic: Option<CheetahString>,
1152 cluster_name: Option<CheetahString>,
1153 ) -> AdminToolResult<ConsumeStats> {
1154 match self
1155 .examine_consume_stats(consumer_group, topic, cluster_name, None, None)
1156 .await
1157 {
1158 Ok(stats) => AdminToolResult::success(stats),
1159 Err(error) => AdminToolResult::failure(admin_result_code_for_error(&error), error.to_string()),
1160 }
1161 }
1162
1163 async fn sync_broker_member_group(
1164 &self,
1165 controller_addr: CheetahString,
1166 cluster_name: CheetahString,
1167 broker_name: CheetahString,
1168 ) -> crate::ClientResult<()> {
1169 if !controller_addr.is_empty() {
1170 return Err(ClientError::illegal_argument(
1171 "syncBrokerMemberGroup uses NameServer; controllerAddr is not supported by this facade",
1172 ));
1173 }
1174
1175 self.mq_client_api()?
1176 .sync_broker_member_group(&cluster_name, &broker_name, false)
1177 .await?;
1178 Ok(())
1179 }
1180 #[allow(deprecated)]
1181 async fn message_track_detail(&self, msg: MessageExt) -> crate::ClientResult<Vec<MessageTrack>> {
1182 let group_list = self.query_topic_consume_by_who(msg.topic().clone()).await?;
1183 let mut result = Vec::with_capacity(group_list.get_group_list().len());
1184
1185 for group in group_list.get_group_list() {
1186 let mut track = build_message_track(group.as_str());
1187 let consumer_connection = match self.examine_consumer_connection_info(group.clone(), None).await {
1188 Ok(connection) => connection,
1189 Err(error) => {
1190 apply_track_error(&mut track, &error);
1191 result.push(track);
1192 continue;
1193 }
1194 };
1195
1196 match consumer_connection.get_consume_type() {
1197 Some(ConsumeType::ConsumeActively) => {
1198 track.set_track_type(TrackType::Pull);
1199 }
1200 Some(ConsumeType::ConsumePassively) => {
1201 if consumer_connection.get_message_model() == Some(MessageModel::Broadcasting) {
1202 track.set_track_type(TrackType::ConsumeBroadcasting);
1203 result.push(track);
1204 continue;
1205 }
1206
1207 let consumed = match self.message_consumed_by_group(&msg, group).await {
1208 Ok(consumed) => consumed,
1209 Err(error) => {
1210 apply_track_error(&mut track, &error);
1211 result.push(track);
1212 continue;
1213 }
1214 };
1215
1216 if consumed {
1217 track.set_track_type(resolve_consumed_track_type(&msg, &consumer_connection));
1218 } else {
1219 track.set_track_type(TrackType::NotConsumedYet);
1220 }
1221 }
1222 _ => {}
1223 }
1224
1225 result.push(track);
1226 }
1227
1228 result.sort_by(|left, right| left.consumer_group.cmp(&right.consumer_group));
1229 Ok(result)
1230 }
1231 #[allow(deprecated)]
1232 async fn message_track_detail_concurrent(&self, msg: MessageExt) -> AdminToolResult<Vec<MessageTrack>> {
1233 match self.message_track_detail(msg).await {
1234 Ok(data) => AdminToolResult::success(data),
1235 Err(error) => AdminToolResult::failure(admin_result_code_for_error(&error), error.to_string()),
1236 }
1237 }
1238
1239 async fn fetch_consume_stats_in_broker(
1240 &self,
1241 broker_addr: CheetahString,
1242 is_order: bool,
1243 timeout_millis: u64,
1244 ) -> crate::ClientResult<ConsumeStatsList> {
1245 self.mq_client_api()?
1246 .fetch_consume_stats_in_broker(&broker_addr, GetConsumeStatsInBrokerHeader { is_order }, timeout_millis)
1247 .await
1248 }
1249
1250 async fn get_all_subscription_group(
1251 &self,
1252 broker_addr: CheetahString,
1253 timeout_millis: u64,
1254 ) -> crate::ClientResult<SubscriptionGroupWrapper> {
1255 self.mq_client_api()?
1256 .get_all_subscription_group_config(&broker_addr, timeout_millis)
1257 .await
1258 }
1259
1260 async fn query_consume_queue(
1261 &self,
1262 broker_addr: CheetahString,
1263 topic: CheetahString,
1264 queue_id: i32,
1265 index: u64,
1266 count: i32,
1267 consumer_group: CheetahString,
1268 ) -> crate::ClientResult<QueryConsumeQueueResponseBody> {
1269 let index = query_consume_queue_index_to_java_long(index)?;
1270 self.mq_client_api()?
1271 .query_consume_queue(
1272 &broker_addr,
1273 topic,
1274 queue_id,
1275 index,
1276 count,
1277 consumer_group,
1278 self.remoting_timeout_millis()?,
1279 )
1280 .await
1281 }
1282
1283 async fn update_and_get_group_read_forbidden(
1284 &self,
1285 broker_addr: CheetahString,
1286 group_name: CheetahString,
1287 topic_name: CheetahString,
1288 readable: Option<bool>,
1289 ) -> crate::ClientResult<GroupForbidden> {
1290 let client_instance = self.client_instance.as_ref().ok_or(crate::ClientError::not_started())?;
1291 let request_header = update_group_forbidden_request_header(group_name, topic_name, readable);
1292
1293 client_instance
1294 .get_mq_client_api_impl()?
1295 .update_and_get_group_forbidden(&broker_addr, request_header, self.remoting_timeout_millis()?)
1296 .await
1297 }
1298
1299 async fn query_message(
1300 &self,
1301 _cluster_name: CheetahString,
1302 topic: CheetahString,
1303 msg_id: CheetahString,
1304 ) -> crate::ClientResult<MessageExt> {
1305 let client_instance = self.client_instance.as_ref().ok_or(crate::ClientError::not_started())?;
1306
1307 let msg_id_str = msg_id.as_str();
1308
1309 if let Err(e) = MessageDecoder::validate_message_id(msg_id_str) {
1310 return Err(crate::ClientError::illegal_argument(format!(
1311 "Invalid message ID: {}",
1312 e
1313 )));
1314 }
1315
1316 let message_id = MessageDecoder::decode_message_id(msg_id_str)
1317 .map_err(|e| crate::ClientError::illegal_argument(format!("Failed to decode message ID: {}", e)))?;
1318 let broker_addr =
1319 CheetahString::from_string(format!("{}:{}", message_id.address.ip(), message_id.address.port()));
1320
1321 let request_header = ViewMessageRequestHeader {
1322 topic: Some(topic),
1323 offset: message_id.offset,
1324 };
1325
1326 client_instance
1327 .get_mq_client_api_impl()?
1328 .view_message(&broker_addr, request_header, self.remoting_timeout_millis()?)
1329 .await
1330 }
1331
1332 async fn get_lite_group_info(
1333 &self,
1334 broker_addr: CheetahString,
1335 group: CheetahString,
1336 lite_topic: CheetahString,
1337 top_k: i32,
1338 ) -> crate::ClientResult<GetLiteGroupInfoResponseBody> {
1339 self.mq_client_api()?
1340 .get_lite_group_info(&broker_addr, group, lite_topic, top_k, self.remoting_timeout_millis()?)
1341 .await
1342 }
1343}
1344
1345#[allow(unused_variables, reason = "trait contracts reserve parameters")]
1346#[allow(unused_mut)]
1347impl BrokerAdmin for DefaultMQAdminExtImpl {
1348 async fn start(&mut self) -> crate::ClientResult<()> {
1349 self.start_admin().await
1350 }
1351
1352 async fn shutdown(&mut self) {
1353 self.shutdown_admin().await;
1354 }
1355
1356 async fn add_broker_to_container(
1357 &self,
1358 broker_container_addr: CheetahString,
1359 broker_config: CheetahString,
1360 ) -> crate::ClientResult<()> {
1361 if let Some(ref mq_client_instance) = self.client_instance {
1362 mq_client_instance
1363 .get_mq_client_api_impl()?
1364 .add_broker(&broker_container_addr, broker_config, self.remoting_timeout_millis()?)
1365 .await
1366 } else {
1367 Err(crate::ClientError::not_started())
1368 }
1369 }
1370
1371 async fn remove_broker_from_container(
1372 &self,
1373 broker_container_addr: CheetahString,
1374 cluster_name: CheetahString,
1375 broker_name: CheetahString,
1376 broker_id: u64,
1377 ) -> crate::ClientResult<()> {
1378 if let Some(ref mq_client_instance) = self.client_instance {
1379 mq_client_instance
1380 .get_mq_client_api_impl()?
1381 .remove_broker(
1382 &broker_container_addr,
1383 cluster_name,
1384 broker_name,
1385 broker_id,
1386 self.remoting_timeout_millis()?,
1387 )
1388 .await
1389 } else {
1390 Err(crate::ClientError::not_started())
1391 }
1392 }
1393
1394 async fn update_broker_config(
1395 &self,
1396 broker_addr: CheetahString,
1397 properties: HashMap<CheetahString, CheetahString>,
1398 ) -> crate::ClientResult<()> {
1399 let validator_input = properties
1400 .iter()
1401 .map(|(key, value)| (key.to_string(), value.to_string()))
1402 .collect::<HashMap<String, String>>();
1403 Validators::check_broker_config(&validator_input)?;
1404
1405 if let Some(ref mq_client_instance) = self.client_instance {
1406 mq_client_instance
1407 .get_mq_client_api_impl()?
1408 .update_broker_config(&broker_addr, properties, self.remoting_timeout_millis()?)
1409 .await
1410 } else {
1411 Err(crate::ClientError::not_started())
1412 }
1413 }
1414
1415 async fn get_broker_config(
1416 &self,
1417 broker_addr: CheetahString,
1418 ) -> crate::ClientResult<HashMap<CheetahString, CheetahString>> {
1419 if let Some(ref mq_client_instance) = self.client_instance {
1420 mq_client_instance
1421 .get_mq_client_api_impl()?
1422 .get_broker_config(&broker_addr, self.remoting_timeout_millis()?)
1423 .await
1424 } else {
1425 Err(crate::ClientError::not_started())
1426 }
1427 }
1428
1429 async fn fetch_broker_runtime_stats(&self, broker_addr: CheetahString) -> crate::ClientResult<KVTable> {
1430 self.mq_client_api()?
1431 .get_broker_runtime_info(&broker_addr, self.remoting_timeout_millis()?)
1432 .await
1433 }
1434
1435 async fn check_rocksdb_cq_write_progress(
1436 &self,
1437 broker_addr: CheetahString,
1438 topic: CheetahString,
1439 check_store_time: i64,
1440 ) -> crate::ClientResult<CheckRocksdbCqWriteResult> {
1441 self.mq_client_api()?
1442 .check_rocksdb_cq_write_progress(&broker_addr, topic, check_store_time, self.remoting_timeout_millis()?)
1443 .await
1444 }
1445
1446 async fn wipe_write_perm_of_broker(
1447 &self,
1448 namesrv_addr: CheetahString,
1449 broker_name: CheetahString,
1450 ) -> crate::ClientResult<i32> {
1451 self.mq_client_api()?
1452 .wipe_write_perm_of_broker(namesrv_addr, broker_name, self.remoting_timeout_millis()?)
1453 .await
1454 }
1455
1456 async fn add_write_perm_of_broker(
1457 &self,
1458 namesrv_addr: CheetahString,
1459 broker_name: CheetahString,
1460 ) -> crate::ClientResult<i32> {
1461 self.mq_client_api()?
1462 .add_write_perm_of_broker(namesrv_addr, broker_name, self.remoting_timeout_millis()?)
1463 .await
1464 }
1465
1466 async fn resume_check_half_message(
1467 &self,
1468 topic: CheetahString,
1469 msg_id: CheetahString,
1470 ) -> crate::ClientResult<bool> {
1471 let message = self
1472 .query_message(CheetahString::default(), topic.clone(), msg_id.clone())
1473 .await?;
1474 let broker_addr = CheetahString::from_string(message.store_host().to_string());
1475 let broker_msg_id = if message
1476 .property(&CheetahString::from_static_str(
1477 MessageConst::PROPERTY_UNIQ_CLIENT_MESSAGE_ID_KEYIDX,
1478 ))
1479 .is_some()
1480 {
1481 message.msg_id().clone()
1482 } else {
1483 msg_id
1484 };
1485
1486 self.mq_client_api()?
1487 .resume_check_half_message(&broker_addr, topic, broker_msg_id, self.remoting_timeout_millis()?)
1488 .await
1489 }
1490
1491 async fn get_controller_meta_data(
1492 &self,
1493 controller_addr: CheetahString,
1494 ) -> crate::ClientResult<GetMetaDataResponseHeader> {
1495 if let Some(ref mq_client_instance) = self.client_instance {
1496 Ok(mq_client_instance
1497 .get_mq_client_api_impl()?
1498 .get_controller_metadata(controller_addr, self.remoting_timeout_millis()?)
1499 .await?)
1500 } else {
1501 Err(crate::ClientError::not_started())
1502 }
1503 }
1504
1505 async fn get_controller_config(
1506 &self,
1507 controller_servers: Vec<CheetahString>,
1508 ) -> crate::ClientResult<HashMap<CheetahString, HashMap<CheetahString, CheetahString>>> {
1509 if let Some(ref mq_client_instance) = self.client_instance {
1510 let mut result: HashMap<CheetahString, HashMap<CheetahString, CheetahString>> = HashMap::new();
1511 let mq_client_api = mq_client_instance.get_mq_client_api_impl()?;
1512 let timeout_millis = self.remoting_timeout_millis()?;
1513 let controller_servers =
1514 controller_servers_or_namesrv(controller_servers, &mq_client_api.get_name_server_address_list());
1515
1516 for controller_addr in controller_servers {
1517 let config = mq_client_api
1518 .get_controller_config(controller_addr.clone(), timeout_millis)
1519 .await?;
1520 result.insert(controller_addr, config);
1521 }
1522
1523 Ok(result)
1524 } else {
1525 Err(crate::ClientError::not_started())
1526 }
1527 }
1528
1529 async fn update_controller_config(
1530 &self,
1531 properties: HashMap<CheetahString, CheetahString>,
1532 controllers: Vec<CheetahString>,
1533 ) -> crate::ClientResult<()> {
1534 if let Some(ref mq_client_instance) = self.client_instance {
1535 mq_client_instance
1536 .get_mq_client_api_impl()?
1537 .update_controller_config(properties, controllers, self.remoting_timeout_millis()?)
1538 .await
1539 } else {
1540 Err(crate::ClientError::not_started())
1541 }
1542 }
1543
1544 async fn clean_controller_broker_data(
1545 &self,
1546 controller_addr: CheetahString,
1547 cluster_name: CheetahString,
1548 broker_name: CheetahString,
1549 broker_controller_ids_to_clean: Option<CheetahString>,
1550 is_clean_living_broker: bool,
1551 ) -> crate::ClientResult<()> {
1552 if let Some(ref mq_client_instance) = self.client_instance {
1553 mq_client_instance
1554 .get_mq_client_api_impl()?
1555 .clean_controller_broker_data(
1556 controller_addr,
1557 cluster_name,
1558 broker_name,
1559 broker_controller_ids_to_clean,
1560 is_clean_living_broker,
1561 self.remoting_timeout_millis()?,
1562 )
1563 .await
1564 } else {
1565 Err(crate::ClientError::not_started())
1566 }
1567 }
1568
1569 async fn get_cold_data_flow_ctr_info(&self, broker_addr: CheetahString) -> crate::ClientResult<CheetahString> {
1570 self.mq_client_api()?
1571 .get_cold_data_flow_ctr_info(broker_addr, self.remoting_timeout_millis()?)
1572 .await
1573 }
1574
1575 async fn notify_min_broker_id_changed(
1576 &self,
1577 cluster_name: CheetahString,
1578 broker_name: CheetahString,
1579 min_broker_id: u64,
1580 min_broker_addr: CheetahString,
1581 offline_broker_addr: Option<CheetahString>,
1582 ha_broker_addr: Option<CheetahString>,
1583 ) -> crate::ClientResult<()> {
1584 let request_header = notify_min_broker_id_change_request_header(
1585 min_broker_id,
1586 min_broker_addr,
1587 offline_broker_addr,
1588 ha_broker_addr,
1589 )?;
1590 let mq_client_api = self.mq_client_api()?;
1591 let broker_member_group = mq_client_api
1592 .sync_broker_member_group(&cluster_name, &broker_name, false)
1593 .await?
1594 .unwrap_or_else(|| BrokerMemberGroup::new(cluster_name.clone(), broker_name.clone()));
1595 let broker_addrs = choose_min_broker_notify_addrs(
1596 &broker_member_group.broker_addrs,
1597 min_broker_id,
1598 request_header.offline_broker_addr.as_ref(),
1599 );
1600
1601 if broker_addrs.is_empty() {
1602 return Err(ClientError::illegal_argument(format!(
1603 "notifyMinBrokerIdChanged cannot resolve broker addresses for cluster `{}` broker `{}`",
1604 cluster_name, broker_name
1605 )));
1606 }
1607
1608 for broker_addr in broker_addrs {
1609 mq_client_api
1610 .notify_min_broker_id_changed(&broker_addr, request_header.clone(), 300)
1611 .await?;
1612 }
1613 Ok(())
1614 }
1615
1616 async fn export_pop_records(&self, broker_addr: CheetahString, timeout: u64) -> crate::ClientResult<()> {
1617 self.mq_client_api()?.export_pop_record(broker_addr, timeout).await
1618 }
1619
1620 async fn switch_timer_engine(
1621 &self,
1622 broker_addr: CheetahString,
1623 des_timer_engine: CheetahString,
1624 ) -> crate::ClientResult<()> {
1625 self.mq_client_api()?
1626 .switch_timer_engine(&broker_addr, des_timer_engine, self.remoting_timeout_millis()?)
1627 .await
1628 }
1629
1630 async fn trigger_lite_dispatch(
1631 &self,
1632 broker_addr: CheetahString,
1633 group: CheetahString,
1634 client_id: CheetahString,
1635 ) -> crate::ClientResult<()> {
1636 self.mq_client_api()?
1637 .trigger_lite_dispatch(&broker_addr, group, client_id, self.remoting_timeout_millis()?)
1638 .await
1639 }
1640
1641 async fn view_broker_stats_data(
1642 &self,
1643 broker_addr: CheetahString,
1644 stats_name: CheetahString,
1645 stats_key: CheetahString,
1646 ) -> crate::ClientResult<BrokerStatsData> {
1647 let request_header = ViewBrokerStatsDataRequestHeader { stats_name, stats_key };
1648 self.mq_client_api()?
1649 .view_broker_stats_data(&broker_addr, request_header, self.remoting_timeout_millis()?)
1650 .await
1651 }
1652
1653 async fn get_broker_ha_status(&self, broker_addr: CheetahString) -> crate::ClientResult<HARuntimeInfo> {
1654 if let Some(ref mq_client_instance) = self.client_instance {
1655 Ok(mq_client_instance
1656 .get_mq_client_api_impl()?
1657 .get_broker_ha_status(broker_addr, self.remoting_timeout_millis()?)
1658 .await?)
1659 } else {
1660 Err(crate::ClientError::not_started())
1661 }
1662 }
1663
1664 async fn get_in_sync_state_data(
1665 &self,
1666 controller_address: CheetahString,
1667 brokers: Vec<CheetahString>,
1668 ) -> crate::ClientResult<BrokerReplicasInfo> {
1669 if let Some(ref mq_client_instance) = self.client_instance {
1670 Ok(mq_client_instance
1671 .get_mq_client_api_impl()?
1672 .get_in_sync_state_data(controller_address, brokers, self.remoting_timeout_millis()?)
1673 .await?)
1674 } else {
1675 Err(crate::ClientError::not_started())
1676 }
1677 }
1678
1679 async fn get_broker_epoch_cache(&self, broker_addr: CheetahString) -> crate::ClientResult<EpochEntryCache> {
1680 if let Some(ref mq_client_instance) = self.client_instance {
1681 Ok(mq_client_instance
1682 .get_mq_client_api_impl()?
1683 .get_broker_epoch_cache(broker_addr, self.remoting_timeout_millis()?)
1684 .await?)
1685 } else {
1686 Err(crate::ClientError::not_started())
1687 }
1688 }
1689
1690 async fn elect_master(
1691 &self,
1692 controller_addr: CheetahString,
1693 cluster_name: CheetahString,
1694 broker_name: CheetahString,
1695 broker_id: Option<u64>,
1696 ) -> crate::ClientResult<(ElectMasterResponseHeader, BrokerMemberGroup)> {
1697 if let Some(ref mq_client_instance) = self.client_instance {
1698 mq_client_instance
1699 .get_mq_client_api_impl()?
1700 .elect_master(
1701 controller_addr,
1702 cluster_name,
1703 broker_name,
1704 broker_id,
1705 self.remoting_timeout_millis()?,
1706 )
1707 .await
1708 } else {
1709 Err(crate::ClientError::not_started())
1710 }
1711 }
1712
1713 async fn get_broker_lite_info(
1714 &self,
1715 broker_addr: CheetahString,
1716 ) -> crate::ClientResult<GetBrokerLiteInfoResponseBody> {
1717 if let Some(ref mq_client_instance) = self.client_instance {
1718 mq_client_instance
1719 .get_mq_client_api_impl()?
1720 .get_broker_lite_info(&broker_addr, self.remoting_timeout_millis()?)
1721 .await
1722 } else {
1723 Err(crate::ClientError::not_started())
1724 }
1725 }
1726
1727 async fn get_lite_client_info(
1728 &self,
1729 broker_addr: CheetahString,
1730 parent_topic: CheetahString,
1731 group: CheetahString,
1732 client_id: CheetahString,
1733 ) -> crate::ClientResult<GetLiteClientInfoResponseBody> {
1734 self.mq_client_api()?
1735 .get_lite_client_info(
1736 &broker_addr,
1737 parent_topic,
1738 group,
1739 client_id,
1740 self.remoting_timeout_millis()?,
1741 )
1742 .await
1743 }
1744
1745 async fn export_rocksdb_config_to_json(
1746 &self,
1747 broker_addr: CheetahString,
1748 config_types: Vec<CheetahString>,
1749 ) -> crate::ClientResult<()> {
1750 if let Some(ref mq_client_instance) = self.client_instance {
1751 mq_client_instance
1752 .get_mq_client_api_impl()?
1753 .export_rocksdb_config_to_json(broker_addr, config_types, self.remoting_timeout_millis()?)
1754 .await
1755 } else {
1756 Err(crate::ClientError::not_started())
1757 }
1758 }
1759}
1760
1761#[allow(unused_variables, reason = "trait contracts reserve parameters")]
1762#[allow(unused_mut)]
1763impl AuthAdmin for DefaultMQAdminExtImpl {
1764 async fn create_and_update_plain_access_config(
1765 &self,
1766 addr: CheetahString,
1767 config: PlainAccessConfig,
1768 ) -> crate::ClientResult<()> {
1769 self.mq_client_api()?
1770 .create_and_update_plain_access_config(addr, &config, self.remoting_timeout_millis()?)
1771 .await
1772 }
1773
1774 async fn delete_plain_access_config(
1775 &self,
1776 addr: CheetahString,
1777 access_key: CheetahString,
1778 ) -> crate::ClientResult<()> {
1779 self.mq_client_api()?
1780 .delete_plain_access_config(addr, access_key, self.remoting_timeout_millis()?)
1781 .await
1782 }
1783
1784 async fn update_global_white_addr_config(
1785 &self,
1786 addr: CheetahString,
1787 global_white_addrs: CheetahString,
1788 acl_file_full_path: Option<CheetahString>,
1789 ) -> crate::ClientResult<()> {
1790 let mq_client_api = self.mq_client_api()?;
1791
1792 validate_acl_file_path_for_global_white_addr_config(acl_file_full_path.as_ref())?;
1793
1794 mq_client_api
1795 .update_global_white_addrs_config(addr, global_white_addrs, self.remoting_timeout_millis()?)
1796 .await
1797 }
1798
1799 async fn examine_broker_cluster_acl_version_info(&self, addr: CheetahString) -> crate::ClientResult<CheetahString> {
1800 let version_info = self
1801 .mq_client_api()?
1802 .get_broker_cluster_acl_version_info(addr, self.remoting_timeout_millis()?)
1803 .await?;
1804 serde_json::to_string(&version_info)
1805 .map(CheetahString::from_string)
1806 .map_err(|error| ClientError::response_process_source("encode ClusterAclVersionInfo", error))
1807 }
1808
1809 async fn get_user_topic_config(
1810 &self,
1811 broker_addr: CheetahString,
1812 special_topic: bool,
1813 timeout_millis: u64,
1814 ) -> crate::ClientResult<TopicConfigSerializeWrapper> {
1815 let mut topic_config_wrapper = self.get_all_topic_config(broker_addr.clone(), timeout_millis).await?;
1816 let system_topic_list = self.get_system_topic_list_from_broker(broker_addr).await?;
1817
1818 if let Some(ref mut topic_table) = topic_config_wrapper.topic_config_table_mut() {
1819 retain_java_user_topic_config(topic_table, &system_topic_list.topic_list, special_topic);
1820 }
1821
1822 Ok(topic_config_wrapper)
1823 }
1824
1825 async fn create_user(
1826 &self,
1827 broker_addr: CheetahString,
1828 username: CheetahString,
1829 password: CheetahString,
1830 user_type: CheetahString,
1831 ) -> crate::ClientResult<()> {
1832 let user_info = UserInfo {
1833 username: Some(username),
1834 user_type: Some(user_type),
1835 password: Some(password),
1836 user_status: None,
1837 };
1838
1839 if let Some(ref mq_client_instance) = self.client_instance {
1840 let mq_client_api = mq_client_instance.get_mq_client_api_impl()?;
1841 let timeout_millis = self.remoting_timeout_millis()?;
1842 mq_client_api
1843 .create_user(broker_addr, &user_info, timeout_millis)
1844 .await?;
1845 Ok(())
1846 } else {
1847 Err(crate::ClientError::not_started())
1848 }
1849 }
1850
1851 async fn update_user(
1852 &self,
1853 broker_addr: CheetahString,
1854 username: CheetahString,
1855 password: CheetahString,
1856 user_type: CheetahString,
1857 user_status: CheetahString,
1858 ) -> crate::ClientResult<()> {
1859 let mut user_info = UserInfo {
1860 username: Some(username),
1861 user_type: Some(user_type),
1862 password: Some(password),
1863 user_status: Some(user_status),
1864 };
1865
1866 if let Some(ref mq_client_instance) = self.client_instance {
1867 let mq_client_api = mq_client_instance.get_mq_client_api_impl()?;
1868 let timeout_millis = self.remoting_timeout_millis()?;
1869 mq_client_api
1870 .update_user(broker_addr, &user_info, timeout_millis)
1871 .await?;
1872 Ok(())
1873 } else {
1874 Err(crate::ClientError::not_started())
1875 }
1876 }
1877
1878 async fn delete_user(&self, broker_addr: CheetahString, username: CheetahString) -> crate::ClientResult<()> {
1879 if let Some(ref mq_client_instance) = self.client_instance {
1880 let mq_client_api = mq_client_instance.get_mq_client_api_impl()?;
1881 let timeout_millis = self.remoting_timeout_millis()?;
1882 mq_client_api.delete_user(broker_addr, username, timeout_millis).await?;
1883 Ok(())
1884 } else {
1885 Err(crate::ClientError::not_started())
1886 }
1887 }
1888
1889 async fn create_acl(
1890 &self,
1891 broker_addr: CheetahString,
1892 subject: CheetahString,
1893 resources: Vec<CheetahString>,
1894 actions: Vec<CheetahString>,
1895 source_ips: Vec<CheetahString>,
1896 decision: CheetahString,
1897 ) -> crate::ClientResult<()> {
1898 let acl_info = build_acl_info(subject, resources, actions, source_ips, decision);
1899 if let Some(ref mq_client_instance) = self.client_instance {
1900 mq_client_instance
1901 .get_mq_client_api_impl()?
1902 .create_acl(broker_addr, &acl_info, self.remoting_timeout_millis()?)
1903 .await
1904 } else {
1905 Err(crate::ClientError::not_started())
1906 }
1907 }
1908
1909 async fn update_acl(
1910 &self,
1911 broker_addr: CheetahString,
1912 subject: CheetahString,
1913 resources: Vec<CheetahString>,
1914 actions: Vec<CheetahString>,
1915 source_ips: Vec<CheetahString>,
1916 decision: CheetahString,
1917 ) -> crate::ClientResult<()> {
1918 let acl_info = build_acl_info(subject, resources, actions, source_ips, decision);
1919 if let Some(ref mq_client_instance) = self.client_instance {
1920 mq_client_instance
1921 .get_mq_client_api_impl()?
1922 .update_acl(broker_addr, &acl_info, self.remoting_timeout_millis()?)
1923 .await
1924 } else {
1925 Err(crate::ClientError::not_started())
1926 }
1927 }
1928
1929 async fn delete_acl_entry(
1930 &self,
1931 broker_addr: CheetahString,
1932 subject: CheetahString,
1933 policy_type: CheetahString,
1934 resource: CheetahString,
1935 ) -> crate::ClientResult<()> {
1936 if let Some(ref client_instance) = self.client_instance {
1937 client_instance
1938 .get_mq_client_api_impl()?
1939 .delete_acl_entry(
1940 broker_addr,
1941 subject,
1942 policy_type,
1943 resource,
1944 self.remoting_timeout_millis()?,
1945 )
1946 .await
1947 } else {
1948 Err(crate::ClientError::not_started())
1949 }
1950 }
1951
1952 async fn delete_acl(
1953 &self,
1954 broker_addr: CheetahString,
1955 subject: CheetahString,
1956 resource: CheetahString,
1957 ) -> crate::ClientResult<()> {
1958 if let Some(ref client_instance) = self.client_instance {
1959 let mq_client_api = client_instance.get_mq_client_api_impl()?;
1960 mq_client_api
1961 .delete_acl(broker_addr, subject, resource, self.remoting_timeout_millis()?)
1962 .await
1963 } else {
1964 Err(crate::ClientError::not_started())
1965 }
1966 }
1967
1968 async fn get_user_subscription_group(
1969 &self,
1970 broker_addr: CheetahString,
1971 timeout_millis: u64,
1972 ) -> crate::ClientResult<SubscriptionGroupWrapper> {
1973 let mut subscription_group_wrapper = self.get_all_subscription_group(broker_addr, timeout_millis).await?;
1974
1975 let system_group_set = get_system_group_set();
1976 let table = subscription_group_wrapper.get_subscription_group_table_mut();
1977 table.retain(|key, _| !mix_all::is_sys_consumer_group(key.as_str()) && !system_group_set.contains(key));
1979
1980 Ok(subscription_group_wrapper)
1981 }
1982
1983 async fn create_user_with_info(
1984 &self,
1985 broker_addr: CheetahString,
1986 username: CheetahString,
1987 password: CheetahString,
1988 ) -> crate::ClientResult<()> {
1989 let user_info = UserInfo {
1990 username: Some(username),
1991 password: Some(password),
1992 user_type: None,
1993 user_status: None,
1994 };
1995
1996 self.mq_client_api()?
1997 .create_user(broker_addr, &user_info, self.remoting_timeout_millis()?)
1998 .await
1999 }
2000
2001 async fn update_user_with_info(
2002 &self,
2003 broker_addr: CheetahString,
2004 username: CheetahString,
2005 password: CheetahString,
2006 ) -> crate::ClientResult<()> {
2007 let user_info = UserInfo {
2008 username: Some(username),
2009 password: Some(password),
2010 user_type: None,
2011 user_status: None,
2012 };
2013
2014 self.mq_client_api()?
2015 .update_user(broker_addr, &user_info, self.remoting_timeout_millis()?)
2016 .await
2017 }
2018
2019 async fn get_user(
2020 &self,
2021 broker_addr: CheetahString,
2022 username: CheetahString,
2023 ) -> crate::ClientResult<Option<UserInfo>> {
2024 if let Some(ref mq_client_instance) = self.client_instance {
2025 let mq_client_api = mq_client_instance.get_mq_client_api_impl()?;
2026 let timeout_millis = self.remoting_timeout_millis()?;
2027 let result = mq_client_api.get_user(broker_addr, username, timeout_millis).await?;
2028 Ok(result)
2029 } else {
2030 Err(crate::ClientError::not_started())
2031 }
2032 }
2033
2034 async fn list_users(
2035 &self,
2036 broker_addr: CheetahString,
2037 filter: CheetahString,
2038 ) -> crate::ClientResult<Vec<UserInfo>> {
2039 if let Some(ref mq_client_instance) = self.client_instance {
2040 let mq_client_api = mq_client_instance.get_mq_client_api_impl()?;
2041 let timeout_millis = self.remoting_timeout_millis()?;
2042 let result = mq_client_api.list_users(broker_addr, filter, timeout_millis).await?;
2043 Ok(result)
2044 } else {
2045 Err(crate::ClientError::not_started())
2046 }
2047 }
2048
2049 async fn create_acl_with_info(
2050 &self,
2051 broker_addr: CheetahString,
2052 subject: CheetahString,
2053 ) -> crate::ClientResult<()> {
2054 self.create_acl_with_acl_info(
2055 broker_addr,
2056 AclInfo {
2057 subject: Some(subject),
2058 policies: None,
2059 },
2060 )
2061 .await
2062 }
2063
2064 async fn update_acl_with_info(
2065 &self,
2066 broker_addr: CheetahString,
2067 subject: CheetahString,
2068 ) -> crate::ClientResult<()> {
2069 self.update_acl_with_acl_info(
2070 broker_addr,
2071 AclInfo {
2072 subject: Some(subject),
2073 policies: None,
2074 },
2075 )
2076 .await
2077 }
2078
2079 async fn get_acl(&self, broker_addr: CheetahString, subject: CheetahString) -> crate::ClientResult<AclInfo> {
2080 let acl_infos = self
2081 .list_acl(broker_addr.clone(), subject.clone(), CheetahString::default())
2082 .await?;
2083 acl_infos
2084 .into_iter()
2085 .find(|acl_info| acl_info.subject.as_ref() == Some(&subject))
2086 .ok_or_else(|| {
2087 ClientError::illegal_argument(format!(
2088 "ACL with subject {} was not found on broker {}",
2089 subject, broker_addr
2090 ))
2091 })
2092 }
2093
2094 async fn list_acl(
2095 &self,
2096 broker_addr: CheetahString,
2097 subject_filter: CheetahString,
2098 resource_filter: CheetahString,
2099 ) -> crate::ClientResult<Vec<AclInfo>> {
2100 if let Some(ref mq_client_instance) = self.client_instance {
2101 let mq_client_api = mq_client_instance.get_mq_client_api_impl()?;
2102 let timeout_millis = self.remoting_timeout_millis()?;
2103 let result = mq_client_api
2104 .list_acl(broker_addr, subject_filter, resource_filter, timeout_millis)
2105 .await?;
2106 Ok(result)
2107 } else {
2108 Err(crate::ClientError::not_started())
2109 }
2110 }
2111}
2112
2113#[allow(unused_variables, reason = "trait contracts reserve parameters")]
2114#[allow(unused_mut)]
2115impl OffsetAdmin for DefaultMQAdminExtImpl {
2116 async fn reset_offset_by_timestamp(
2117 &self,
2118 cluster_name: Option<CheetahString>,
2119 topic: CheetahString,
2120 group: CheetahString,
2121 timestamp: u64,
2122 is_force: bool,
2123 ) -> crate::ClientResult<HashMap<MessageQueue, u64>> {
2124 let timestamp = timestamp_to_java_long("resetOffsetByTimestamp", timestamp)?;
2125 let topic_route = self.examine_topic_route_info(topic.clone()).await?;
2126 let mut offset_table = HashMap::new();
2127 let timeout = self.remoting_timeout_millis()?;
2128
2129 if let Some(route_data) = topic_route {
2130 for broker_data in &route_data.broker_datas {
2131 if let Some(expected_cluster) = cluster_name.as_ref() {
2132 if broker_data.cluster() != expected_cluster {
2133 continue;
2134 }
2135 }
2136 if let Some(master_addr) = broker_data.broker_addrs().get(&mix_all::MASTER_ID) {
2137 let request_header = ResetOffsetRequestHeader {
2138 topic: topic.clone(),
2139 group: group.clone(),
2140 queue_id: -1,
2141 offset: Some(-1),
2142 timestamp,
2143 is_force,
2144 topic_request_header: None,
2145 };
2146 let offsets = self
2147 .mq_client_api()?
2148 .invoke_broker_to_reset_offset(master_addr, request_header, timeout)
2149 .await?;
2150 for (mq, offset) in offsets {
2151 offset_table.insert(mq, java_long_to_u64("resetOffsetByTimestamp", "offset", offset)?);
2152 }
2153 }
2154 }
2155 }
2156
2157 Ok(offset_table)
2158 }
2159
2160 async fn reset_offset_new(
2161 &self,
2162 consumer_group: CheetahString,
2163 topic: CheetahString,
2164 timestamp: u64,
2165 ) -> crate::ClientResult<()> {
2166 match self
2167 .reset_offset_by_timestamp(None, topic.clone(), consumer_group.clone(), timestamp, true)
2168 .await
2169 {
2170 Ok(_) => Ok(()),
2171 Err(error) if is_consumer_not_online_error(&error) => {
2172 self.reset_offset_by_timestamp_old(None, consumer_group, topic, timestamp, true)
2173 .await?;
2174 Ok(())
2175 }
2176 Err(error) => Err(error),
2177 }
2178 }
2179
2180 async fn delete_expired_commit_log(
2181 &self,
2182 cluster: Option<CheetahString>,
2183 addr: Option<CheetahString>,
2184 ) -> crate::ClientResult<bool> {
2185 self.execute_broker_cleanup_operation(cluster, addr, BrokerCleanupOperation::DeleteExpiredCommitLog)
2186 .await
2187 }
2188
2189 async fn delete_expired_commit_log_by_addr(&self, addr: CheetahString) -> crate::ClientResult<bool> {
2190 self.delete_expired_commit_log(None, Some(addr)).await
2191 }
2192
2193 async fn clone_group_offset(
2194 &self,
2195 src_group: CheetahString,
2196 dest_group: CheetahString,
2197 topic: CheetahString,
2198 is_offline: bool,
2199 ) -> crate::ClientResult<()> {
2200 let retry_topic: CheetahString = mix_all::get_retry_topic(src_group.as_str()).into();
2201 let topic_route_data = self
2202 .examine_topic_route_info(retry_topic.clone())
2203 .await?
2204 .ok_or_else(|| mq_client_err!(format!("Topic route not found for retry topic: {retry_topic}")))?;
2205 let timeout = self.remoting_timeout_millis()?;
2206 let api = self.mq_client_api()?;
2207
2208 for broker_data in &topic_route_data.broker_datas {
2209 if let Some(addr) = broker_data.select_broker_addr() {
2210 api.clone_group_offset(
2211 &addr,
2212 src_group.clone(),
2213 dest_group.clone(),
2214 topic.clone(),
2215 is_offline,
2216 timeout,
2217 )
2218 .await?;
2219 }
2220 }
2221
2222 Ok(())
2223 }
2224
2225 async fn update_consume_offset(
2226 &self,
2227 broker_addr: CheetahString,
2228 consume_group: CheetahString,
2229 mq: MessageQueue,
2230 offset: u64,
2231 ) -> crate::ClientResult<()> {
2232 let request_header = update_consume_offset_request_header(consume_group, &mq, offset)?;
2233 let client_instance = self.client_instance.as_ref().ok_or(crate::ClientError::not_started())?;
2234
2235 client_instance
2236 .get_mq_client_api_impl()?
2237 .update_consumer_offset(&broker_addr, request_header, self.remoting_timeout_millis()?)
2238 .await
2239 }
2240
2241 async fn reset_offset_by_queue_id(
2242 &self,
2243 broker_addr: CheetahString,
2244 consumer_group: CheetahString,
2245 topic_name: CheetahString,
2246 queue_id: i32,
2247 reset_offset: u64,
2248 ) -> crate::ClientResult<()> {
2249 let (update_header, reset_header) =
2250 reset_offset_by_queue_id_request_headers(consumer_group, topic_name, queue_id, reset_offset)?;
2251 let client_instance = self.client_instance.as_ref().ok_or(crate::ClientError::not_started())?;
2252 let timeout_millis = self.remoting_timeout_millis()?;
2253
2254 client_instance
2255 .get_mq_client_api_impl()?
2256 .update_consumer_offset(&broker_addr, update_header, timeout_millis)
2257 .await?;
2258
2259 let offsets = client_instance
2260 .get_mq_client_api_impl()?
2261 .invoke_broker_to_reset_offset(&broker_addr, reset_header, timeout_millis)
2262 .await?;
2263
2264 for (mq, old_offset) in offsets {
2265 info!(
2266 "Reset single message queue {} offset from {} to {}",
2267 mq, old_offset, reset_offset
2268 );
2269 }
2270
2271 Ok(())
2272 }
2273
2274 async fn reset_master_flush_offset(
2275 &self,
2276 broker_addr: CheetahString,
2277 master_flush_offset: u64,
2278 ) -> crate::ClientResult<()> {
2279 if let Some(ref mq_client_instance) = self.client_instance {
2280 let master_flush_offset = master_flush_offset_to_java_long(master_flush_offset)?;
2281 mq_client_instance
2282 .get_mq_client_api_impl()?
2283 .reset_master_flush_offset(&broker_addr, master_flush_offset)
2284 .await
2285 } else {
2286 Err(crate::ClientError::not_started())
2287 }
2288 }
2289
2290 async fn set_commit_log_read_ahead_mode(
2291 &self,
2292 broker_addr: CheetahString,
2293 mode: CheetahString,
2294 ) -> crate::ClientResult<CheetahString> {
2295 self.mq_client_api()?
2296 .set_commit_log_read_ahead_mode(broker_addr, mode, self.remoting_timeout_millis()?)
2297 .await
2298 }
2299
2300 async fn update_lite_pull_consumer_offset(
2301 &self,
2302 addr: CheetahString,
2303 topic: CheetahString,
2304 group: CheetahString,
2305 queue_id: i32,
2306 offset: u64,
2307 ) -> crate::ClientResult<()> {
2308 let request_header = lite_pull_update_consumer_offset_request_header(topic, group, queue_id, offset)?;
2309 self.mq_client_api()?
2310 .update_consumer_offset(&addr, request_header, self.remoting_timeout_millis()?)
2311 .await
2312 }
2313
2314 async fn export_rocksdb_consumer_offset_to_json(
2315 &self,
2316 broker_addr: CheetahString,
2317 file_path: CheetahString,
2318 ) -> crate::ClientResult<()> {
2319 if !file_path.is_empty() {
2320 return Err(ClientError::illegal_argument(
2321 "exportRocksDB consumerOffsets filePath is local-mode only and cannot be sent over RPC",
2322 ));
2323 }
2324
2325 self.mq_client_api()?
2326 .export_rocksdb_config_to_json(
2327 broker_addr,
2328 vec![CheetahString::from_static_str(ROCKSDB_CONFIG_TYPE_CONSUMER_OFFSETS)],
2329 self.remoting_timeout_millis()?,
2330 )
2331 .await
2332 }
2333
2334 async fn export_rocksdb_consumer_offset_from_memory(
2335 &self,
2336 broker_addr: CheetahString,
2337 ) -> crate::ClientResult<CheetahString> {
2338 self.mq_client_api()?
2339 .get_all_consumer_offset_json(broker_addr, self.remoting_timeout_millis()?)
2340 .await
2341 }
2342
2343 async fn reset_offset_by_timestamp_old(
2344 &self,
2345 cluster_name: Option<CheetahString>,
2346 consumer_group: CheetahString,
2347 topic: CheetahString,
2348 timestamp: u64,
2349 force: bool,
2350 ) -> crate::ClientResult<Vec<RollbackStats>> {
2351 let timestamp = timestamp_to_java_long("resetOffsetByTimestampOld", timestamp)?;
2352 let mut route_topic = topic.clone();
2353 if !topic.is_empty()
2354 && (mix_all::is_lmq(Some(topic.as_str()))
2355 || topic.as_str() == format!("{}wheel_timer", TopicValidator::SYSTEM_TOPIC_PREFIX))
2356 && cluster_name.as_ref().is_some_and(|name| !name.is_empty())
2357 {
2358 if let Some(cluster_name) = cluster_name {
2359 route_topic = cluster_name;
2360 }
2361 }
2362 let topic_route_data = self.examine_topic_route_info(route_topic).await?;
2363 let mut rollback_stats_list = Vec::new();
2364
2365 if let Some(route_data) = topic_route_data {
2366 let mut topic_route_map = HashMap::new();
2367 for queue_data in &route_data.queue_datas {
2368 topic_route_map.insert(queue_data.broker_name().to_string(), queue_data.clone());
2369 }
2370
2371 for broker_data in &route_data.broker_datas {
2372 if let Some(addr) = broker_data.select_broker_addr() {
2373 if let Some(queue_data) = topic_route_map.get(broker_data.broker_name().as_str()) {
2374 let mut rollback_stats = self
2375 .reset_offset_by_timestamp_old_on_broker(
2376 addr,
2377 queue_data,
2378 consumer_group.clone(),
2379 topic.clone(),
2380 timestamp,
2381 force,
2382 )
2383 .await?;
2384 rollback_stats_list.append(&mut rollback_stats);
2385 }
2386 }
2387 }
2388 }
2389
2390 Ok(rollback_stats_list)
2391 }
2392 #[allow(deprecated)]
2393 async fn reset_offset_new_concurrent(
2394 &self,
2395 group: CheetahString,
2396 topic: CheetahString,
2397 timestamp: u64,
2398 ) -> AdminToolResult<BrokerOperatorResult> {
2399 let timestamp = match timestamp_to_java_long("resetOffsetNewConcurrent", timestamp) {
2400 Ok(timestamp) => timestamp,
2401 Err(error) => return AdminToolResult::failure(admin_result_code_for_error(&error), error.to_string()),
2402 };
2403 let api = match self.mq_client_api() {
2404 Ok(api) => api,
2405 Err(error) => return AdminToolResult::failure(admin_result_code_for_error(&error), error.to_string()),
2406 };
2407 let timeout = match self.remoting_timeout_millis() {
2408 Ok(timeout) => timeout,
2409 Err(error) => return AdminToolResult::failure(admin_result_code_for_error(&error), error.to_string()),
2410 };
2411 let route_data = match api.get_topic_route_info_from_name_server(&topic, timeout).await {
2412 Ok(Some(route_data)) if !route_data.broker_datas.is_empty() => route_data,
2413 Ok(_) => {
2414 return AdminToolResult::failure(
2415 AdminToolsResultCodeEnum::TopicRouteInfoNotExist,
2416 "topic router info not found".to_string(),
2417 );
2418 }
2419 Err(error) => return AdminToolResult::failure(admin_result_code_for_error(&error), error.to_string()),
2420 };
2421
2422 let mut topic_route_map = HashMap::new();
2423 for queue_data in &route_data.queue_datas {
2424 topic_route_map.insert(queue_data.broker_name().clone(), queue_data.clone());
2425 }
2426
2427 let mut success_list = Vec::new();
2428 let mut failure_list = Vec::new();
2429 for broker_data in &route_data.broker_datas {
2430 let Some(addr) = broker_data.select_broker_addr() else {
2431 continue;
2432 };
2433
2434 let reset_header = ResetOffsetRequestHeader {
2435 topic: topic.clone(),
2436 group: group.clone(),
2437 queue_id: -1,
2438 offset: Some(-1),
2439 timestamp,
2440 is_force: true,
2441 topic_request_header: None,
2442 };
2443
2444 match api.invoke_broker_to_reset_offset(&addr, reset_header, timeout).await {
2445 Ok(_) => success_list.push(addr),
2446 Err(error) if is_consumer_not_online_error(&error) => {
2447 match topic_route_map.get(broker_data.broker_name()) {
2448 Some(queue_data) => {
2449 match self
2450 .reset_offset_by_timestamp_old_on_broker(
2451 addr.clone(),
2452 queue_data,
2453 group.clone(),
2454 topic.clone(),
2455 timestamp,
2456 true,
2457 )
2458 .await
2459 {
2460 Ok(_) => success_list.push(addr),
2461 Err(error) => {
2462 warn!(
2463 "resetOffsetByTimestampOld error. addr={}, topic={}, group={}, timestamp={}, \
2464 {}",
2465 addr, topic, group, timestamp, error
2466 );
2467 failure_list.push(addr);
2468 }
2469 }
2470 }
2471 None => {
2472 warn!(
2473 "resetOffsetByTimestampOld error. addr={}, topic={}, group={}, timestamp={}, missing \
2474 queue data for broker {}",
2475 addr,
2476 topic,
2477 group,
2478 timestamp,
2479 broker_data.broker_name()
2480 );
2481 failure_list.push(addr);
2482 }
2483 }
2484 }
2485 Err(error) if response_code_from_error(&error) == Some(ResponseCode::SystemError) => {
2486 success_list.push(addr);
2487 }
2488 Err(error) => {
2489 warn!(
2490 "resetOffsetNewConcurrent error. addr={}, topic={}, group={}, timestamp={}, {}",
2491 addr, topic, group, timestamp, error
2492 );
2493 failure_list.push(addr);
2494 }
2495 }
2496 }
2497
2498 let success = success_list.len() == route_data.broker_datas.len();
2499 let result = broker_operator_result(success_list, failure_list);
2500 if success {
2501 AdminToolResult::success(result)
2502 } else {
2503 AdminToolResult::failure_with_data(
2504 AdminToolsResultCodeEnum::MQBrokerError,
2505 "operator failure".into(),
2506 result,
2507 )
2508 }
2509 }
2510
2511 async fn query_consume_time_span(
2512 &self,
2513 topic: CheetahString,
2514 group: CheetahString,
2515 ) -> crate::ClientResult<Vec<QueueTimeSpan>> {
2516 let timeout = self.remoting_timeout_millis()?;
2517 let mut result = Vec::new();
2518 if let Some(route_data) = self.examine_topic_route_info(topic.clone()).await? {
2519 for broker_data in &route_data.broker_datas {
2520 if let Some(master_addr) = broker_data.broker_addrs().get(&mix_all::MASTER_ID) {
2521 let spans = self
2522 .mq_client_api()?
2523 .query_consume_time_span(
2524 master_addr,
2525 QueryConsumeTimeSpanRequestHeader {
2526 topic: topic.clone(),
2527 group: group.clone(),
2528 topic_request_header: None,
2529 },
2530 timeout,
2531 )
2532 .await?;
2533 result.extend(spans);
2534 }
2535 }
2536 }
2537 Ok(result)
2538 }
2539
2540 async fn query_consume_time_span_concurrent(
2541 &self,
2542 topic: CheetahString,
2543 group: CheetahString,
2544 ) -> AdminToolResult<Vec<QueueTimeSpan>> {
2545 match self.query_consume_time_span(topic, group).await {
2546 Ok(spans) => AdminToolResult::success(spans),
2547 Err(error) => AdminToolResult::failure(admin_result_code_for_error(&error), error.to_string()),
2548 }
2549 }
2550
2551 async fn search_offset(
2552 &self,
2553 broker_addr: CheetahString,
2554 topic_name: CheetahString,
2555 queue_id: i32,
2556 timestamp: u64,
2557 timeout_millis: u64,
2558 ) -> crate::ClientResult<u64> {
2559 let timestamp = search_offset_timestamp_to_java_long(timestamp)?;
2560 let mq = MessageQueue::from_parts(&topic_name, "", queue_id);
2561 let offset = self
2562 .mq_client_api()?
2563 .search_offset_by_timestamp(
2564 broker_addr.as_str(),
2565 &mq,
2566 timestamp,
2567 rocketmq_model::common::boundary_type::BoundaryType::Lower,
2568 timeout_millis,
2569 )
2570 .await?;
2571 java_long_to_u64("searchOffset", "offset", offset)
2572 }
2573
2574 async fn min_offset(
2575 &self,
2576 broker_addr: CheetahString,
2577 message_queue: MessageQueue,
2578 timeout_millis: u64,
2579 ) -> crate::ClientResult<i64> {
2580 self.mq_client_api()?
2581 .get_min_offset(broker_addr.as_str(), &message_queue, timeout_millis)
2582 .await
2583 }
2584
2585 async fn max_offset(
2586 &self,
2587 broker_addr: CheetahString,
2588 message_queue: MessageQueue,
2589 timeout_millis: u64,
2590 ) -> crate::ClientResult<i64> {
2591 self.mq_client_api()?
2592 .get_max_offset(broker_addr.as_str(), &message_queue, timeout_millis)
2593 .await
2594 }
2595}