rocketmq_client_rust/hook/
namespace_rpc_hook.rs1use std::net::SocketAddr;
16
17use rocketmq_model::common::mix_all;
18use rocketmq_protocol::protocol::remoting_command::RemotingCommand;
19use rocketmq_transport::api::RPCHook;
20
21use crate::base::client_config::ClientConfig;
22
23pub struct NamespaceRpcHook {
46 client_config: ClientConfig,
47}
48
49impl NamespaceRpcHook {
50 pub fn new(client_config: ClientConfig) -> Self {
55 Self { client_config }
56 }
57
58 pub fn client_config(&self) -> &ClientConfig {
60 &self.client_config
61 }
62}
63
64impl RPCHook for NamespaceRpcHook {
65 fn do_before_request(
71 &self,
72 _remote_addr: SocketAddr,
73 request: &mut RemotingCommand,
74 ) -> Result<(), rocketmq_error::SharedError> {
75 if let Some(namespace_v2) = self.client_config.get_namespace_v2() {
76 request.ensure_ext_fields_initialized();
77
78 request.add_ext_field(mix_all::RPC_REQUEST_HEADER_NAMESPACED_FIELD, "true");
79 request.add_ext_field(mix_all::RPC_REQUEST_HEADER_NAMESPACE_FIELD, namespace_v2.as_str());
80 }
81 Ok(())
82 }
83
84 fn do_after_response(
88 &self,
89 _remote_addr: SocketAddr,
90 _request: &RemotingCommand,
91 _response: &mut RemotingCommand,
92 ) -> Result<(), rocketmq_error::SharedError> {
93 Ok(())
94 }
95}
96
97#[cfg(test)]
98mod tests {
99 use std::net::SocketAddr;
100
101 use cheetah_string::CheetahString;
102 use rocketmq_protocol::protocol::remoting_command::RemotingCommand;
103 use rocketmq_transport::api::RPCHook;
104
105 use super::*;
106
107 #[test]
108 fn test_namespace_rpc_hook_adds_headers_when_namespace_configured() {
109 let mut config = ClientConfig::default();
110 config.set_namespace_v2(CheetahString::from_static_str("test-namespace"));
111
112 let hook = NamespaceRpcHook::new(config);
113 let mut request = RemotingCommand::create_remoting_command(1);
114 let addr: SocketAddr = "127.0.0.1:8080".parse().unwrap();
115
116 hook.do_before_request(addr, &mut request).unwrap();
117
118 assert_eq!(
119 request
120 .ext_fields()
121 .unwrap()
122 .get(mix_all::RPC_REQUEST_HEADER_NAMESPACED_FIELD),
123 Some(&CheetahString::from_static_str("true"))
124 );
125 assert_eq!(
126 request
127 .ext_fields()
128 .unwrap()
129 .get(mix_all::RPC_REQUEST_HEADER_NAMESPACE_FIELD),
130 Some(&CheetahString::from_static_str("test-namespace"))
131 );
132 }
133
134 #[test]
135 fn test_namespace_rpc_hook_no_headers_when_namespace_not_configured() {
136 let config = ClientConfig::default();
137 let hook = NamespaceRpcHook::new(config);
138 let mut request = RemotingCommand::create_remoting_command(1);
139 let addr: SocketAddr = "127.0.0.1:8080".parse().unwrap();
140
141 hook.do_before_request(addr, &mut request).unwrap();
142
143 assert_eq!(request.ext_fields(), None);
144 }
145
146 #[test]
147 fn test_do_after_response_does_nothing() {
148 let config = ClientConfig::default();
149 let hook = NamespaceRpcHook::new(config);
150 let request = RemotingCommand::create_remoting_command(1);
151 let mut response = RemotingCommand::create_success_response_command();
152 let addr: SocketAddr = "127.0.0.1:8080".parse().unwrap();
153
154 let result = hook.do_after_response(addr, &request, &mut response);
155 assert!(result.is_ok());
156 }
157
158 #[test]
159 fn test_client_config_accessor() {
160 let mut config = ClientConfig::default();
161 config.set_namespace_v2(CheetahString::from_static_str("test-namespace"));
162
163 let hook = NamespaceRpcHook::new(config.clone());
164
165 assert_eq!(
166 hook.client_config().get_namespace_v2(),
167 Some(&CheetahString::from_static_str("test-namespace"))
168 );
169 }
170
171 #[test]
172 fn test_ensure_ext_fields_preserves_existing_data() {
173 let mut config = ClientConfig::default();
174 config.set_namespace_v2(CheetahString::from_static_str("test-ns"));
175
176 let hook = NamespaceRpcHook::new(config);
177 let mut request = RemotingCommand::create_remoting_command(100);
178
179 let original_opaque = request.opaque();
181
182 request.ensure_ext_fields_initialized();
184 request.add_ext_field("existing-key", "existing-value");
185
186 let addr: SocketAddr = "127.0.0.1:8080".parse().unwrap();
187
188 hook.do_before_request(addr, &mut request).unwrap();
190
191 assert_eq!(request.opaque(), original_opaque);
193
194 assert_eq!(
196 request
197 .ext_fields()
198 .unwrap()
199 .get(&CheetahString::from_static_str("existing-key")),
200 Some(&CheetahString::from_static_str("existing-value"))
201 );
202
203 assert_eq!(
205 request
206 .ext_fields()
207 .unwrap()
208 .get(mix_all::RPC_REQUEST_HEADER_NAMESPACED_FIELD),
209 Some(&CheetahString::from_static_str("true"))
210 );
211 assert_eq!(
212 request
213 .ext_fields()
214 .unwrap()
215 .get(mix_all::RPC_REQUEST_HEADER_NAMESPACE_FIELD),
216 Some(&CheetahString::from_static_str("test-ns"))
217 );
218 }
219}