rocketmq_admin_core/cli/
validators.rs1use crate::core::RocketMQError;
20use crate::core::RocketMQResult;
21use crate::core::ToolsError;
22
23pub fn validate_namesrv_addr(addr: &str) -> RocketMQResult<()> {
29 if addr.is_empty() {
30 return Err(RocketMQError::Tools(ToolsError::ValidationError {
31 field: "namesrv_addr".to_string(),
32 reason: "NameServer address cannot be empty".to_string(),
33 }));
34 }
35
36 for single_addr in addr.split(';').map(str::trim).filter(|s| !s.is_empty()) {
38 let parts: Vec<&str> = single_addr.split(':').collect();
40
41 if parts.len() != 2 {
42 return Err(RocketMQError::Tools(ToolsError::ValidationError {
43 field: "namesrv_addr".to_string(),
44 reason: format!("Invalid format '{single_addr}', expected 'host:port'"),
45 }));
46 }
47
48 parts[1].parse::<u16>().map_err(|_| {
50 RocketMQError::Tools(ToolsError::ValidationError {
51 field: "namesrv_addr".to_string(),
52 reason: format!("Invalid port '{}' in address '{single_addr}'", parts[1]),
53 })
54 })?;
55 }
56
57 Ok(())
58}
59
60pub fn validate_topic_name(topic: &str) -> RocketMQResult<()> {
62 if topic.is_empty() {
63 return Err(RocketMQError::Tools(ToolsError::ValidationError {
64 field: "topic".to_string(),
65 reason: "Topic name cannot be empty".to_string(),
66 }));
67 }
68
69 if topic.len() > 127 {
71 return Err(RocketMQError::Tools(ToolsError::ValidationError {
72 field: "topic".to_string(),
73 reason: format!("Name '{topic}' exceeds maximum length of 127 characters"),
74 }));
75 }
76
77 const INVALID_CHARS: &[char] = &['/', '\\', '|', '<', '>', '?', '*', '"', ':'];
79
80 if let Some(ch) = topic.chars().find(|c| INVALID_CHARS.contains(c)) {
81 return Err(RocketMQError::Tools(ToolsError::ValidationError {
82 field: "topic".to_string(),
83 reason: format!("Name '{topic}' contains invalid character '{ch}'"),
84 }));
85 }
86
87 Ok(())
88}
89
90pub fn validate_queue_nums(nums: i32, name: &str) -> RocketMQResult<()> {
92 match nums {
93 n if n <= 0 => Err(RocketMQError::Tools(ToolsError::ValidationError {
94 field: name.to_string(),
95 reason: format!("must be positive, got {nums}"),
96 })),
97 n if n > 1024 => Err(RocketMQError::Tools(ToolsError::ValidationError {
98 field: name.to_string(),
99 reason: format!("exceeds maximum value of 1024, got {nums}"),
100 })),
101 _ => Ok(()),
102 }
103}
104
105pub fn validate_perm(perm: i32) -> RocketMQResult<()> {
107 match perm {
109 2 | 4 | 6 => Ok(()),
110 _ => Err(RocketMQError::Tools(ToolsError::ValidationError {
111 field: "perm".to_string(),
112 reason: format!("Invalid value {perm}, valid values are: 2 (read), 4 (write), 6 (read+write)"),
113 })),
114 }
115}
116
117pub fn validate_broker_name(name: &str) -> RocketMQResult<()> {
119 match name {
120 "" => Err(RocketMQError::Tools(ToolsError::ValidationError {
121 field: "broker_name".to_string(),
122 reason: "Broker name cannot be empty".to_string(),
123 })),
124 n if n.len() > 127 => Err(RocketMQError::Tools(ToolsError::ValidationError {
125 field: "broker_name".to_string(),
126 reason: format!("Name '{name}' exceeds maximum length of 127 characters"),
127 })),
128 _ => Ok(()),
129 }
130}
131
132#[cfg(test)]
133mod tests {
134 use super::*;
135
136 #[test]
137 fn test_validate_namesrv_addr() {
138 assert!(validate_namesrv_addr("192.168.0.1:9876").is_ok());
140
141 assert!(validate_namesrv_addr("192.168.0.1:9876;192.168.0.2:9876").is_ok());
143
144 assert!(validate_namesrv_addr("").is_err());
146
147 assert!(validate_namesrv_addr("192.168.0.1").is_err());
149
150 assert!(validate_namesrv_addr("192.168.0.1:abc").is_err());
152 }
153
154 #[test]
155 fn test_validate_topic_name() {
156 assert!(validate_topic_name("test_topic").is_ok());
158 assert!(validate_topic_name("TopicTest").is_ok());
159
160 assert!(validate_topic_name("").is_err());
162
163 assert!(validate_topic_name(&"a".repeat(128)).is_err());
165
166 assert!(validate_topic_name("topic/name").is_err());
168 assert!(validate_topic_name("topic\\name").is_err());
169 }
170
171 #[test]
172 fn test_validate_queue_nums() {
173 assert!(validate_queue_nums(8, "read_queue_nums").is_ok());
175
176 assert!(validate_queue_nums(-1, "read_queue_nums").is_err());
178
179 assert!(validate_queue_nums(0, "read_queue_nums").is_err());
181
182 assert!(validate_queue_nums(2000, "read_queue_nums").is_err());
184 }
185
186 #[test]
187 fn test_validate_perm() {
188 assert!(validate_perm(2).is_ok());
190 assert!(validate_perm(4).is_ok());
191 assert!(validate_perm(6).is_ok());
192
193 assert!(validate_perm(0).is_err());
195 assert!(validate_perm(1).is_err());
196 assert!(validate_perm(3).is_err());
197 assert!(validate_perm(8).is_err());
198 }
199
200 #[test]
201 fn test_validate_broker_name() {
202 assert!(validate_broker_name("broker-a").is_ok());
204
205 assert!(validate_broker_name("").is_err());
207
208 assert!(validate_broker_name(&"a".repeat(128)).is_err());
210 }
211}