aerosocket_client/
connection.rs

1//! WebSocket client connection handling for AeroSocket
2//!
3//! This module provides connection management for WebSocket clients.
4
5use aerosocket_core::prelude::Bytes;
6use aerosocket_core::{Message, Result};
7use std::net::SocketAddr;
8
9/// Represents a WebSocket client connection
10#[derive(Debug)]
11pub struct ClientConnection {
12    /// Server address
13    remote_addr: SocketAddr,
14    /// Connection state
15    state: ConnectionState,
16    /// Connection metadata
17    metadata: ConnectionMetadata,
18}
19
20/// Connection state
21#[derive(Debug, Clone, Copy, PartialEq, Eq)]
22pub enum ConnectionState {
23    /// Connection is being established
24    Connecting,
25    /// Connection is established and ready
26    Connected,
27    /// Connection is closing
28    Closing,
29    /// Connection is closed
30    Closed,
31}
32
33/// Connection metadata
34#[derive(Debug, Clone)]
35pub struct ConnectionMetadata {
36    /// WebSocket subprotocol
37    pub subprotocol: Option<String>,
38    /// WebSocket extensions
39    pub extensions: Vec<String>,
40    /// Connection established time
41    pub established_at: std::time::Instant,
42    /// Last activity time
43    pub last_activity_at: std::time::Instant,
44    /// Messages sent count
45    pub messages_sent: u64,
46    /// Messages received count
47    pub messages_received: u64,
48    /// Bytes sent count
49    pub bytes_sent: u64,
50    /// Bytes received count
51    pub bytes_received: u64,
52}
53
54impl ClientConnection {
55    /// Create a new client connection
56    pub fn new(remote_addr: SocketAddr) -> Self {
57        Self {
58            remote_addr,
59            state: ConnectionState::Connecting,
60            metadata: ConnectionMetadata {
61                subprotocol: None,
62                extensions: Vec::new(),
63                established_at: std::time::Instant::now(),
64                last_activity_at: std::time::Instant::now(),
65                messages_sent: 0,
66                messages_received: 0,
67                bytes_sent: 0,
68                bytes_received: 0,
69            },
70        }
71    }
72
73    /// Get the remote address
74    pub fn remote_addr(&self) -> SocketAddr {
75        self.remote_addr
76    }
77
78    /// Get the connection state
79    pub fn state(&self) -> ConnectionState {
80        self.state
81    }
82
83    /// Get the connection metadata
84    pub fn metadata(&self) -> &ConnectionMetadata {
85        &self.metadata
86    }
87
88    /// Send a message
89    pub async fn send(&mut self, message: Message) -> Result<()> {
90        // TODO: Implement actual message sending
91        self.metadata.messages_sent += 1;
92        let message_len = match &message {
93            Message::Text(text) => text.len(),
94            Message::Binary(data) => data.len(),
95            Message::Ping(data) => data.len(),
96            Message::Pong(data) => data.len(),
97            Message::Close(close_msg) => close_msg.len(),
98        };
99        self.metadata.bytes_sent += message_len as u64;
100        self.metadata.last_activity_at = std::time::Instant::now();
101        Ok(())
102    }
103
104    /// Send a text message
105    pub async fn send_text(&mut self, text: impl AsRef<str>) -> Result<()> {
106        let message = Message::text(text.as_ref().to_string());
107        self.send(message).await
108    }
109
110    /// Send a binary message
111    pub async fn send_binary(&mut self, data: impl Into<Bytes>) -> Result<()> {
112        let message = Message::binary(data);
113        self.send(message).await
114    }
115
116    /// Send a ping message
117    pub async fn ping(&mut self, data: Option<&[u8]>) -> Result<()> {
118        let message = Message::ping(data.map(|d| d.to_vec()));
119        self.send(message).await
120    }
121
122    /// Send a pong message
123    pub async fn pong(&mut self, data: Option<&[u8]>) -> Result<()> {
124        let message = Message::pong(data.map(|d| d.to_vec()));
125        self.send(message).await
126    }
127
128    /// Receive the next message
129    pub async fn next(&mut self) -> Result<Option<Message>> {
130        // TODO: Implement actual message receiving
131        Ok(None)
132    }
133
134    /// Close the connection
135    pub async fn close(&mut self, code: Option<u16>, reason: Option<&str>) -> Result<()> {
136        self.state = ConnectionState::Closing;
137        let message = Message::close(code, reason.map(|s| s.to_string()));
138        self.send(message).await?;
139        self.state = ConnectionState::Closed;
140        Ok(())
141    }
142
143    /// Check if the connection is established
144    pub fn is_connected(&self) -> bool {
145        self.state == ConnectionState::Connected
146    }
147
148    /// Check if the connection is closed
149    pub fn is_closed(&self) -> bool {
150        self.state == ConnectionState::Closed
151    }
152
153    /// Get the connection age
154    pub fn age(&self) -> std::time::Duration {
155        self.metadata.established_at.elapsed()
156    }
157
158    /// Get the time since last activity
159    pub fn idle_time(&self) -> std::time::Duration {
160        self.metadata.last_activity_at.elapsed()
161    }
162
163    /// Set the connection as connected
164    pub fn set_connected(&mut self) {
165        self.state = ConnectionState::Connected;
166        self.metadata.established_at = std::time::Instant::now();
167        self.metadata.last_activity_at = std::time::Instant::now();
168    }
169
170    /// Set the subprotocol
171    pub fn set_subprotocol(&mut self, subprotocol: String) {
172        self.metadata.subprotocol = Some(subprotocol);
173    }
174
175    /// Add an extension
176    pub fn add_extension(&mut self, extension: String) {
177        self.metadata.extensions.push(extension);
178    }
179}
180
181/// Connection handle for managing connections
182#[derive(Debug)]
183pub struct ClientConnectionHandle {
184    /// Connection ID
185    id: u64,
186    /// Connection reference
187    connection: std::sync::Arc<std::sync::Mutex<ClientConnection>>,
188}
189
190impl ClientConnectionHandle {
191    /// Create a new connection handle
192    pub fn new(id: u64, connection: ClientConnection) -> Self {
193        Self {
194            id,
195            connection: std::sync::Arc::new(std::sync::Mutex::new(connection)),
196        }
197    }
198
199    /// Get the connection ID
200    pub fn id(&self) -> u64 {
201        self.id
202    }
203
204    /// Get a reference to the connection
205    pub fn connection(&self) -> &std::sync::Arc<std::sync::Mutex<ClientConnection>> {
206        &self.connection
207    }
208
209    /// Try to lock the connection
210    pub fn try_lock(&self) -> aerosocket_core::Result<std::sync::MutexGuard<'_, ClientConnection>> {
211        self.connection
212            .try_lock()
213            .map_err(|e| aerosocket_core::Error::Other(format!("Poison error: {}", e)))
214    }
215}
216
217impl Clone for ClientConnectionHandle {
218    fn clone(&self) -> Self {
219        Self {
220            id: self.id,
221            connection: self.connection.clone(),
222        }
223    }
224}
225
226#[cfg(test)]
227mod tests {
228    use super::*;
229
230    #[test]
231    fn test_client_connection_creation() {
232        let remote = "127.0.0.1:8080".parse().unwrap();
233        let conn = ClientConnection::new(remote);
234
235        assert_eq!(conn.remote_addr(), remote);
236        assert_eq!(conn.state(), ConnectionState::Connecting);
237        assert!(!conn.is_connected());
238        assert!(!conn.is_closed());
239    }
240
241    #[test]
242    fn test_client_connection_handle() {
243        let remote = "127.0.0.1:8080".parse().unwrap();
244        let conn = ClientConnection::new(remote);
245        let handle = ClientConnectionHandle::new(1, conn);
246
247        assert_eq!(handle.id(), 1);
248        assert!(handle.try_lock().is_ok());
249    }
250
251    #[test]
252    fn test_connection_state_transitions() {
253        let remote = "127.0.0.1:8080".parse().unwrap();
254        let mut conn = ClientConnection::new(remote);
255
256        assert_eq!(conn.state(), ConnectionState::Connecting);
257
258        conn.set_connected();
259        assert_eq!(conn.state(), ConnectionState::Connected);
260        assert!(conn.is_connected());
261    }
262
263    #[tokio::test]
264    async fn test_message_sending() {
265        let remote = "127.0.0.1:8080".parse().unwrap();
266        let mut conn = ClientConnection::new(remote);
267
268        // These should not fail even without actual implementation
269        assert!(conn.send_text("Hello").await.is_ok());
270        assert!(conn.send_binary(&[1u8, 2, 3][..]).await.is_ok());
271        assert!(conn.ping(None).await.is_ok());
272        assert!(conn.pong(None).await.is_ok());
273    }
274}