1use crate::error::Error;
10use crate::types::{ClientLocation, Server};
11use async_trait::async_trait;
12
13#[async_trait]
18pub trait ServerFetcher: Send + Sync {
19 async fn fetch_servers(&self) -> Result<(Vec<Server>, Option<ClientLocation>), Error>;
20}
21
22#[async_trait]
23pub trait ServerPinger: Send + Sync {
24 async fn ping_server(&self, server: &Server) -> Result<(f64, f64, f64, Vec<f64>), Error>;
25}
26
27pub trait ServerSelector: Send + Sync {
28 fn select_best(&self, servers: &[Server]) -> Result<Server, Error>;
29}
30
31pub trait ServerService: ServerFetcher + ServerPinger + ServerSelector + Send + Sync {}
32
33#[async_trait]
38pub trait IpDiscoverer: Send + Sync {
39 async fn discover_ip(&self) -> Result<String, Error>;
40}
41
42#[async_trait]
47pub trait LatencyMonitor: Send + Sync {
48 async fn measure_latency_under_load(
49 &self,
50 server_url: String,
51 samples: std::sync::Arc<std::sync::Mutex<Vec<f64>>>,
52 stop: std::sync::Arc<std::sync::atomic::AtomicBool>,
53 );
54}
55
56#[derive(Clone, Debug)]
61pub struct DefaultServerService {
62 client: reqwest::Client,
63}
64
65impl DefaultServerService {
66 pub fn new(client: reqwest::Client) -> Self {
67 Self { client }
68 }
69}
70
71#[async_trait]
72impl ServerFetcher for DefaultServerService {
73 async fn fetch_servers(&self) -> Result<(Vec<Server>, Option<ClientLocation>), Error> {
74 crate::servers::fetch(&self.client).await
75 }
76}
77
78#[async_trait]
79impl ServerPinger for DefaultServerService {
80 async fn ping_server(&self, server: &Server) -> Result<(f64, f64, f64, Vec<f64>), Error> {
81 crate::servers::ping_test(&self.client, server).await
82 }
83}
84
85impl ServerSelector for DefaultServerService {
86 fn select_best(&self, servers: &[Server]) -> Result<Server, Error> {
87 crate::servers::select_best_server(servers)
88 }
89}
90
91impl ServerService for DefaultServerService {}
92
93#[derive(Clone, Debug)]
94pub struct DefaultIpService {
95 client: reqwest::Client,
96}
97
98impl DefaultIpService {
99 pub fn new(client: reqwest::Client) -> Self {
100 Self { client }
101 }
102}
103
104#[async_trait]
105impl IpDiscoverer for DefaultIpService {
106 async fn discover_ip(&self) -> Result<String, Error> {
107 crate::http::discover_client_ip(&self.client).await
108 }
109}
110
111#[derive(Clone, Debug)]
112pub struct DefaultLatencyMonitor {
113 client: reqwest::Client,
114}
115
116impl DefaultLatencyMonitor {
117 pub fn new(client: reqwest::Client) -> Self {
118 Self { client }
119 }
120}
121
122#[async_trait]
123impl LatencyMonitor for DefaultLatencyMonitor {
124 async fn measure_latency_under_load(
125 &self,
126 server_url: String,
127 samples: std::sync::Arc<std::sync::Mutex<Vec<f64>>>,
128 stop: std::sync::Arc<std::sync::atomic::AtomicBool>,
129 ) {
130 crate::servers::measure_latency_under_load(self.client.clone(), server_url, samples, stop)
131 .await;
132 }
133}
134
135pub trait Services: Send + Sync {
141 fn server_service(&self) -> &dyn ServerService;
142 fn ip_service(&self) -> &dyn IpDiscoverer;
143}
144
145#[derive(Clone)]
148pub struct ServiceContainer {
149 server: std::sync::Arc<dyn ServerService>,
150 ip: std::sync::Arc<dyn IpDiscoverer>,
151}
152
153impl Services for ServiceContainer {
154 fn server_service(&self) -> &dyn ServerService {
155 self.server.as_ref()
156 }
157
158 fn ip_service(&self) -> &dyn IpDiscoverer {
159 self.ip.as_ref()
160 }
161}
162
163impl std::fmt::Debug for ServiceContainer {
164 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
165 f.debug_struct("ServiceContainer")
166 .field("server", &"dyn ServerService")
167 .field("ip", &"dyn IpDiscoverer")
168 .finish()
169 }
170}
171
172impl ServiceContainer {
173 pub fn new(client: reqwest::Client) -> Self {
175 Self {
176 server: std::sync::Arc::new(DefaultServerService::new(client.clone())),
177 ip: std::sync::Arc::new(DefaultIpService::new(client)),
178 }
179 }
180
181 pub fn with_server(mut self, server: impl ServerService + 'static) -> Self {
182 self.server = std::sync::Arc::new(server);
183 self
184 }
185
186 pub fn with_ip(mut self, ip: impl IpDiscoverer + 'static) -> Self {
187 self.ip = std::sync::Arc::new(ip);
188 self
189 }
190}
191
192#[cfg(test)]
193mod tests {
194 use super::*;
195
196 fn make_client() -> reqwest::Client {
197 reqwest::Client::new()
198 }
199
200 #[test]
201 fn test_default_service_container_creation() {
202 let container = ServiceContainer::new(make_client());
203 let _server = container.server_service();
204 let _ip = container.ip_service();
205 }
206
207 #[test]
208 fn test_service_container_with_custom() {
209 let client = make_client();
210 let container = ServiceContainer::new(client)
211 .with_server(DefaultServerService::new(make_client()))
212 .with_ip(DefaultIpService::new(make_client()));
213 let _server = container.server_service();
214 let _ip = container.ip_service();
215 }
216}