rocketmq_client_rust/base/
client_options.rs1use crate::ClientError;
16use crate::ClientResult;
17use cheetah_string::CheetahString;
18use rocketmq_protocol::protocol::remoting_command_defaults::RemotingCommandFactory;
19
20use super::client_config::ClientConfig;
21use crate::nameserver_discovery::NameServerDiscoveryConfig;
22
23#[derive(Clone)]
25pub struct ClientOptions {
26 client: ClientConfig,
27 nameserver_discovery: Option<NameServerDiscoveryConfig>,
28 remoting_command_factory: Option<RemotingCommandFactory>,
29}
30
31impl ClientOptions {
32 #[must_use]
34 pub fn legacy(client: ClientConfig) -> Self {
35 Self {
36 client,
37 nameserver_discovery: None,
38 remoting_command_factory: None,
39 }
40 }
41
42 #[must_use]
44 pub fn with_nameserver_discovery(mut self, discovery: NameServerDiscoveryConfig) -> Self {
45 self.nameserver_discovery = Some(discovery);
46 self
47 }
48
49 #[must_use]
51 pub fn with_remoting_command_factory(mut self, factory: RemotingCommandFactory) -> Self {
52 self.remoting_command_factory = Some(factory);
53 self
54 }
55
56 #[must_use]
58 pub fn client_config(&self) -> &ClientConfig {
59 &self.client
60 }
61
62 #[must_use]
64 pub fn nameserver_discovery(&self) -> Option<&NameServerDiscoveryConfig> {
65 self.nameserver_discovery.as_ref()
66 }
67
68 #[must_use]
70 pub fn remoting_command_factory(&self) -> Option<RemotingCommandFactory> {
71 self.remoting_command_factory
72 }
73
74 pub(crate) fn from_parts(client: ClientConfig, nameserver_discovery: Option<NameServerDiscoveryConfig>) -> Self {
75 Self {
76 client,
77 nameserver_discovery,
78 remoting_command_factory: None,
79 }
80 }
81
82 pub(crate) fn into_normalized_parts(
83 mut self,
84 ) -> ClientResult<(
85 ClientConfig,
86 Option<NameServerDiscoveryConfig>,
87 Option<RemotingCommandFactory>,
88 )> {
89 let remoting_command_factory = self.remoting_command_factory;
90 let Some(discovery) = self.nameserver_discovery else {
91 self.client.normalize_namesrv_addr()?;
92 return Ok((self.client, None, remoting_command_factory));
93 };
94
95 if let Some(legacy) = self.client.namesrv_addr.as_ref() {
96 return Err(ClientError::config_invalid(
97 "nameserver_discovery",
98 discovery.fingerprint(),
99 format!("typed NameServer discovery cannot be combined with legacy namesrv_addr={legacy}"),
100 ));
101 }
102 discovery.validate()?;
103 if let Some(canonical) = discovery.static_canonical() {
104 self.client.namesrv_addr = Some(CheetahString::from_string(canonical));
105 }
106 Ok((self.client, Some(discovery), remoting_command_factory))
107 }
108}
109
110impl Default for ClientOptions {
111 fn default() -> Self {
112 Self::legacy(ClientConfig::default())
113 }
114}
115
116impl From<ClientConfig> for ClientOptions {
117 fn from(value: ClientConfig) -> Self {
118 Self::legacy(value)
119 }
120}
121
122#[cfg(test)]
123mod tests {
124 use super::*;
125 use crate::nameserver_discovery::NameServerSource;
126
127 #[test]
128 fn legacy_options_preserve_existing_configuration() {
129 let options = ClientOptions::legacy(ClientConfig::default());
130 assert!(options.nameserver_discovery().is_none());
131 }
132
133 #[test]
134 fn typed_discovery_conflicts_with_legacy_address() {
135 let client = ClientConfig {
136 namesrv_addr: Some(CheetahString::from_static_str("ns-a:9876")),
137 ..Default::default()
138 };
139 let discovery = NameServerDiscoveryConfig::new(NameServerSource::dns("namesrv.default.svc", 9876).unwrap());
140 assert!(ClientOptions::legacy(client)
141 .with_nameserver_discovery(discovery)
142 .into_normalized_parts()
143 .is_err());
144 }
145}