1use crate::address::ensure_protocol;
4use crate::client::OxiaClient;
5use crate::client_options::OxiaClientOptions;
6use crate::errors::OxiaError;
7use std::time::Duration;
8
9#[derive(Debug, Clone, Default)]
39#[must_use = "builders do nothing unless built"]
40pub struct OxiaClientBuilder {
41 service_address: Option<String>,
42 namespace: Option<String>,
43 identity: Option<String>,
44 batch_max_size: Option<u32>,
45 max_requests_per_batch: Option<u32>,
46 max_write_batches_in_flight: Option<u32>,
47 max_read_batches_in_flight: Option<u32>,
48 session_timeout: Option<Duration>,
49 session_keep_alive: Option<Duration>,
50 request_timeout: Option<Duration>,
51}
52
53impl OxiaClientBuilder {
54 pub fn new() -> Self {
56 OxiaClientBuilder::default()
57 }
58
59 pub fn service_address(mut self, service_address: impl Into<String>) -> Self {
62 self.service_address = Some(ensure_protocol(service_address.into()));
63 self
64 }
65
66 pub fn namespace(mut self, namespace: impl Into<String>) -> Self {
68 self.namespace = Some(namespace.into());
69 self
70 }
71
72 pub fn identity(mut self, identity: impl Into<String>) -> Self {
75 self.identity = Some(identity.into());
76 self
77 }
78
79 pub fn max_write_batches_in_flight(mut self, max: u32) -> Self {
87 self.max_write_batches_in_flight = Some(max);
88 self
89 }
90
91 pub fn max_read_batches_in_flight(mut self, max: u32) -> Self {
95 self.max_read_batches_in_flight = Some(max);
96 self
97 }
98
99 pub fn batch_max_size(mut self, batch_max_size: u32) -> Self {
101 self.batch_max_size = Some(batch_max_size);
102 self
103 }
104
105 pub fn max_requests_per_batch(mut self, max_requests_per_batch: u32) -> Self {
107 self.max_requests_per_batch = Some(max_requests_per_batch);
108 self
109 }
110
111 pub fn session_timeout(mut self, session_timeout: Duration) -> Self {
114 self.session_timeout = Some(session_timeout);
115 self
116 }
117
118 pub fn session_keep_alive(mut self, session_keep_alive: Duration) -> Self {
121 self.session_keep_alive = Some(session_keep_alive);
122 self
123 }
124
125 pub fn request_timeout(mut self, request_timeout: Duration) -> Self {
127 self.request_timeout = Some(request_timeout);
128 self
129 }
130
131 fn assemble_options(self) -> OxiaClientOptions {
132 let mut options = OxiaClientOptions::default();
133 if let Some(service_address) = self.service_address {
134 options.service_address = service_address
135 }
136 if let Some(namespace) = self.namespace {
137 options.namespace = namespace;
138 }
139 if let Some(identity) = self.identity {
140 options.identity = identity;
141 }
142 if let Some(batch_max_size) = self.batch_max_size {
143 options.batch_max_size = batch_max_size;
144 }
145 if let Some(max_requests_per_batch) = self.max_requests_per_batch {
146 options.max_requests_per_batch = max_requests_per_batch;
147 }
148 if let Some(max) = self.max_write_batches_in_flight {
149 options.max_write_batches_in_flight = max;
150 }
151 if let Some(max) = self.max_read_batches_in_flight {
152 options.max_read_batches_in_flight = max;
153 }
154 if let Some(session_timeout) = self.session_timeout {
155 options.session_timeout = session_timeout;
156 }
157 options.session_keep_alive = self
160 .session_keep_alive
161 .unwrap_or(options.session_timeout / 10);
162 if let Some(request_timeout) = self.request_timeout {
163 options.request_timeout = request_timeout;
164 }
165 options
166 }
167
168 pub async fn build(self) -> Result<OxiaClient, OxiaError> {
174 let options = self.assemble_options();
175 if options.max_write_batches_in_flight == 0 || options.max_read_batches_in_flight == 0 {
176 return Err(OxiaError::InvalidArgument(
177 "max batches in flight must be at least 1".to_string(),
178 ));
179 }
180 OxiaClient::new(options).await
181 }
182}
183
184#[cfg(test)]
185mod tests {
186 use super::*;
187
188 #[test]
189 fn keep_alive_defaults_to_a_tenth_of_the_session_timeout() {
190 let options = OxiaClientBuilder::new()
191 .session_timeout(Duration::from_secs(30))
192 .assemble_options();
193 assert_eq!(options.session_keep_alive, Duration::from_secs(3));
194 }
195
196 #[test]
197 fn keep_alive_can_be_overridden() {
198 let options = OxiaClientBuilder::new()
199 .session_timeout(Duration::from_secs(30))
200 .session_keep_alive(Duration::from_millis(500))
201 .assemble_options();
202 assert_eq!(options.session_keep_alive, Duration::from_millis(500));
203 }
204
205 #[test]
206 fn default_keep_alive_tracks_the_default_session_timeout() {
207 let options = OxiaClientBuilder::new().assemble_options();
208 assert_eq!(options.session_keep_alive, options.session_timeout / 10);
209 }
210}