1use std::time::Duration;
7
8#[derive(Debug, Clone)]
26pub struct TapConfig {
27 pub hostname: String,
31
32 pub admin_password: Option<String>,
36
37 pub send_acks: bool,
41
42 pub user_agent: String,
44
45 pub max_reconnect_attempts: Option<u32>,
49
50 pub initial_reconnect_delay: Duration,
54
55 pub max_reconnect_delay: Duration,
59
60 pub reconnect_backoff_multiplier: f64,
64
65 pub channel_buffer_size: usize,
70}
71
72impl Default for TapConfig {
73 fn default() -> Self {
74 Self {
75 hostname: "localhost:2480".to_string(),
76 admin_password: None,
77 send_acks: true,
78 user_agent: format!("atproto-tap/{}", env!("CARGO_PKG_VERSION")),
79 max_reconnect_attempts: None,
80 initial_reconnect_delay: Duration::from_secs(1),
81 max_reconnect_delay: Duration::from_secs(60),
82 reconnect_backoff_multiplier: 2.0,
83 channel_buffer_size: 32,
84 }
85 }
86}
87
88impl TapConfig {
89 pub fn builder() -> TapConfigBuilder {
91 TapConfigBuilder::default()
92 }
93
94 pub fn new(hostname: impl Into<String>) -> Self {
96 Self {
97 hostname: hostname.into(),
98 ..Default::default()
99 }
100 }
101
102 pub fn ws_url(&self) -> String {
104 format!("ws://{}/channel", self.hostname)
105 }
106
107 pub fn http_base_url(&self) -> String {
109 format!("http://{}", self.hostname)
110 }
111}
112
113#[derive(Debug, Clone, Default)]
115pub struct TapConfigBuilder {
116 config: TapConfig,
117}
118
119impl TapConfigBuilder {
120 pub fn hostname(mut self, hostname: impl Into<String>) -> Self {
122 self.config.hostname = hostname.into();
123 self
124 }
125
126 pub fn admin_password(mut self, password: impl Into<String>) -> Self {
128 self.config.admin_password = Some(password.into());
129 self
130 }
131
132 pub fn send_acks(mut self, send_acks: bool) -> Self {
134 self.config.send_acks = send_acks;
135 self
136 }
137
138 pub fn user_agent(mut self, user_agent: impl Into<String>) -> Self {
140 self.config.user_agent = user_agent.into();
141 self
142 }
143
144 pub fn max_reconnect_attempts(mut self, max: Option<u32>) -> Self {
148 self.config.max_reconnect_attempts = max;
149 self
150 }
151
152 pub fn initial_reconnect_delay(mut self, delay: Duration) -> Self {
154 self.config.initial_reconnect_delay = delay;
155 self
156 }
157
158 pub fn max_reconnect_delay(mut self, delay: Duration) -> Self {
160 self.config.max_reconnect_delay = delay;
161 self
162 }
163
164 pub fn reconnect_backoff_multiplier(mut self, multiplier: f64) -> Self {
166 self.config.reconnect_backoff_multiplier = multiplier;
167 self
168 }
169
170 pub fn channel_buffer_size(mut self, size: usize) -> Self {
172 self.config.channel_buffer_size = size;
173 self
174 }
175
176 pub fn build(self) -> TapConfig {
178 self.config
179 }
180}
181
182#[cfg(test)]
183mod tests {
184 use super::*;
185
186 #[test]
187 fn test_default_config() {
188 let config = TapConfig::default();
189 assert_eq!(config.hostname, "localhost:2480");
190 assert!(config.admin_password.is_none());
191 assert!(config.send_acks);
192 assert!(config.max_reconnect_attempts.is_none());
193 assert_eq!(config.initial_reconnect_delay, Duration::from_secs(1));
194 assert_eq!(config.max_reconnect_delay, Duration::from_secs(60));
195 assert!((config.reconnect_backoff_multiplier - 2.0).abs() < f64::EPSILON);
196 assert_eq!(config.channel_buffer_size, 32);
197 }
198
199 #[test]
200 fn test_builder() {
201 let config = TapConfig::builder()
202 .hostname("tap.example.com:2480")
203 .admin_password("secret123")
204 .send_acks(false)
205 .max_reconnect_attempts(Some(5))
206 .initial_reconnect_delay(Duration::from_millis(500))
207 .max_reconnect_delay(Duration::from_secs(30))
208 .reconnect_backoff_multiplier(1.5)
209 .build();
210
211 assert_eq!(config.hostname, "tap.example.com:2480");
212 assert_eq!(config.admin_password, Some("secret123".to_string()));
213 assert!(!config.send_acks);
214 assert_eq!(config.max_reconnect_attempts, Some(5));
215 assert_eq!(config.initial_reconnect_delay, Duration::from_millis(500));
216 assert_eq!(config.max_reconnect_delay, Duration::from_secs(30));
217 assert!((config.reconnect_backoff_multiplier - 1.5).abs() < f64::EPSILON);
218 }
219
220 #[test]
221 fn test_channel_buffer_size() {
222 let config = TapConfig::builder().channel_buffer_size(128).build();
223 assert_eq!(config.channel_buffer_size, 128);
224 }
225
226 #[test]
227 fn test_ws_url() {
228 let config = TapConfig::new("localhost:2480");
229 assert_eq!(config.ws_url(), "ws://localhost:2480/channel");
230
231 let config = TapConfig::new("tap.example.com:8080");
232 assert_eq!(config.ws_url(), "ws://tap.example.com:8080/channel");
233 }
234
235 #[test]
236 fn test_http_base_url() {
237 let config = TapConfig::new("localhost:2480");
238 assert_eq!(config.http_base_url(), "http://localhost:2480");
239 }
240}