1use crate::error::SdkError;
4use crate::network::{MemoryTransport, NetworkTransport, Peer, PeerId};
5use crate::session::Session;
6use parking_lot::RwLock;
7use std::collections::HashMap;
8use std::sync::Arc;
9
10#[derive(Clone, Debug)]
12pub struct ClientConfig {
13 pub user_name: String,
15 pub auto_reconnect: bool,
17 pub max_reconnect_attempts: u32,
19}
20
21impl Default for ClientConfig {
22 fn default() -> Self {
23 Self {
24 user_name: "Anonymous".to_string(),
25 auto_reconnect: true,
26 max_reconnect_attempts: 5,
27 }
28 }
29}
30
31pub struct ClientConfigBuilder {
33 config: ClientConfig,
34}
35
36impl ClientConfigBuilder {
37 pub fn new() -> Self {
39 Self {
40 config: ClientConfig::default(),
41 }
42 }
43
44 pub fn user_name(mut self, name: impl Into<String>) -> Self {
46 self.config.user_name = name.into();
47 self
48 }
49
50 pub fn auto_reconnect(mut self, enabled: bool) -> Self {
52 self.config.auto_reconnect = enabled;
53 self
54 }
55
56 pub fn max_reconnect_attempts(mut self, attempts: u32) -> Self {
58 self.config.max_reconnect_attempts = attempts;
59 self
60 }
61
62 pub fn build(self) -> ClientConfig {
64 self.config
65 }
66}
67
68impl Default for ClientConfigBuilder {
69 fn default() -> Self {
70 Self::new()
71 }
72}
73
74pub struct Client<T: NetworkTransport> {
98 peer_id: PeerId,
99 config: ClientConfig,
100 transport: Arc<T>,
101 sessions: Arc<RwLock<HashMap<String, Arc<Session<T>>>>>,
102}
103
104impl Client<MemoryTransport> {
105 pub fn new_with_memory_transport(config: ClientConfig) -> Self {
110 let peer_id = PeerId::new(format!("peer-{}", uuid_simple()));
111 let transport = Arc::new(MemoryTransport::new(peer_id.clone()));
112
113 Self {
114 peer_id,
115 config,
116 transport,
117 sessions: Arc::new(RwLock::new(HashMap::new())),
118 }
119 }
120}
121
122impl<T: NetworkTransport> Client<T> {
123 pub fn new(peer_id: PeerId, transport: Arc<T>, config: ClientConfig) -> Self {
128 Self {
129 peer_id,
130 config,
131 transport,
132 sessions: Arc::new(RwLock::new(HashMap::new())),
133 }
134 }
135
136 pub fn peer_id(&self) -> &PeerId {
138 &self.peer_id
139 }
140
141 pub fn user_name(&self) -> &str {
143 &self.config.user_name
144 }
145
146 pub fn transport(&self) -> &Arc<T> {
148 &self.transport
149 }
150
151 pub fn create_session(&self, session_id: impl Into<String>) -> Arc<Session<T>> {
155 let session_id = session_id.into();
156 let mut sessions = self.sessions.write();
157
158 if let Some(session) = sessions.get(&session_id) {
159 session.clone()
160 } else {
161 let session = Arc::new(Session::new(
162 session_id.clone(),
163 self.peer_id.clone(),
164 self.config.user_name.clone(),
165 self.transport.clone(),
166 ));
167 sessions.insert(session_id, session.clone());
168 session
169 }
170 }
171
172 pub fn get_session(&self, session_id: &str) -> Option<Arc<Session<T>>> {
174 self.sessions.read().get(session_id).cloned()
175 }
176
177 pub fn close_session(&self, session_id: &str) {
182 self.sessions.write().remove(session_id);
183 }
184
185 pub fn session_ids(&self) -> Vec<String> {
187 self.sessions.read().keys().cloned().collect()
188 }
189
190 pub async fn connect_peer(&self, peer_id: &PeerId) -> Result<(), SdkError> {
197 self.transport
198 .connect(peer_id)
199 .await
200 .map_err(|e| SdkError::ConnectionFailed(e.to_string()))
201 }
202
203 pub async fn disconnect_peer(&self, peer_id: &PeerId) -> Result<(), SdkError> {
210 self.transport
211 .disconnect(peer_id)
212 .await
213 .map_err(|e| SdkError::NetworkError(e.to_string()))
214 }
215
216 pub async fn connected_peers(&self) -> Vec<Peer> {
218 self.transport.connected_peers().await
219 }
220}
221
222fn uuid_simple() -> String {
224 use std::time::{SystemTime, UNIX_EPOCH};
225 let timestamp = SystemTime::now()
226 .duration_since(UNIX_EPOCH)
227 .unwrap()
228 .as_nanos();
229 format!("{:x}", timestamp)
230}
231
232pub mod quick {
234 use super::*;
235 use crate::network::create_network;
236
237 pub fn create_collaborative_clients(user_names: &[&str]) -> Vec<Client<MemoryTransport>> {
247 let network = create_network(user_names.len());
248
249 user_names
250 .iter()
251 .zip(network)
252 .map(|(name, transport)| {
253 let peer_id = transport.local_id().clone();
254 let config = ClientConfig {
255 user_name: name.to_string(),
256 ..Default::default()
257 };
258 Client::new(peer_id, Arc::new(transport), config)
259 })
260 .collect()
261 }
262}
263
264#[cfg(test)]
265mod tests {
266 use super::*;
267
268 #[test]
269 fn test_client_creation() {
270 let config = ClientConfig {
271 user_name: "Alice".to_string(),
272 ..Default::default()
273 };
274 let client = Client::new_with_memory_transport(config);
275
276 assert_eq!(client.user_name(), "Alice");
277 }
278
279 #[test]
280 fn test_session_management() {
281 let config = ClientConfig::default();
282 let client = Client::new_with_memory_transport(config);
283
284 let session1 = client.create_session("session-1");
285 let _session2 = client.create_session("session-2");
286
287 assert_eq!(client.session_ids().len(), 2);
288
289 let session1_again = client.create_session("session-1");
291 assert!(Arc::ptr_eq(&session1, &session1_again));
292
293 client.close_session("session-1");
295 assert_eq!(client.session_ids().len(), 1);
296 }
297
298 #[test]
299 fn test_config_builder() {
300 let config = ClientConfigBuilder::new()
301 .user_name("Bob")
302 .auto_reconnect(false)
303 .max_reconnect_attempts(3)
304 .build();
305
306 assert_eq!(config.user_name, "Bob");
307 assert!(!config.auto_reconnect);
308 assert_eq!(config.max_reconnect_attempts, 3);
309 }
310
311 #[test]
312 fn test_quick_collaborative_clients() {
313 let clients = quick::create_collaborative_clients(&["Alice", "Bob", "Charlie"]);
314
315 assert_eq!(clients.len(), 3);
316 assert_eq!(clients[0].user_name(), "Alice");
317 assert_eq!(clients[1].user_name(), "Bob");
318 assert_eq!(clients[2].user_name(), "Charlie");
319 }
320}