flare_core/server/connection/manager/
mod.rs1use crate::common::error::{FlareError, Result};
7use crate::server::connection::r#trait::{
8 ConnectionManagerTrait, ConnectionStats as TraitConnectionStats,
9};
10use crate::transport::connection::Connection;
11use async_trait::async_trait;
12use futures_util::stream::{self, StreamExt};
13use std::collections::{HashMap, hash_map::DefaultHasher};
14use std::hash::{Hash, Hasher};
15use std::sync::{
16 Arc, RwLock, Weak,
17 atomic::{AtomicUsize, Ordering},
18};
19use std::time::{Duration, Instant};
20use tokio::sync::{Mutex, mpsc};
21
22const DEFAULT_FANOUT_CONCURRENCY: usize = 256;
23const DEFAULT_SEND_TIMEOUT: Duration = Duration::from_secs(10);
24const DEFAULT_WRITE_QUEUE_CAPACITY: usize = 1024;
25const CONNECTION_SHARD_COUNT: usize = 64;
26const USER_CONNECTION_SHARD_COUNT: usize = 64;
27
28type ConnectionHandle = Arc<Mutex<Box<dyn Connection>>>;
29type ConnectionWriteHandle = Arc<ConnectionWriteQueue>;
30type ConnectionEntry = (ConnectionHandle, ConnectionWriteHandle, ConnectionInfo);
31type ConnectionHandleSnapshot = (String, ConnectionWriteHandle);
32type ConnectionAuthSnapshot = (String, ConnectionWriteHandle, bool);
33type ConnectionSnapshot = (String, ConnectionWriteHandle, ConnectionInfo);
34type TimeoutConnectionSnapshot = (String, ConnectionHandle, Option<String>);
35type ConnectionShard = RwLock<HashMap<String, ConnectionEntry>>;
36type UserConnectionShard = RwLock<HashMap<String, Vec<String>>>;
37
38struct QueuedWrite {
39 data: Vec<u8>,
40}
41
42#[derive(Clone)]
43struct ConnectionRemovalRegistry {
44 connection_shards: Weak<Vec<ConnectionShard>>,
45 user_connection_shards: Weak<Vec<UserConnectionShard>>,
46 connection_count: Arc<AtomicUsize>,
47 user_count: Arc<AtomicUsize>,
48}
49
50impl ConnectionRemovalRegistry {
51 fn remove_connection(&self, connection_id: &str) -> bool {
52 let Some(connection_shards) = self.connection_shards.upgrade() else {
53 return false;
54 };
55 let shard_index = ConnectionManager::shard_index(connection_id, connection_shards.len());
56
57 let Ok(mut shard) = connection_shards[shard_index].write() else {
58 return false;
59 };
60
61 let Some((_, _, info)) = shard.remove(connection_id) else {
62 return false;
63 };
64 drop(shard);
65
66 self.connection_count.fetch_sub(1, Ordering::Relaxed);
67
68 if let Some(user_id) = info.user_id {
69 self.remove_user_connection(&user_id, connection_id);
70 }
71
72 true
73 }
74
75 fn remove_user_connection(&self, user_id: &str, connection_id: &str) {
76 let Some(user_connection_shards) = self.user_connection_shards.upgrade() else {
77 return;
78 };
79 let shard_index = ConnectionManager::shard_index(user_id, user_connection_shards.len());
80
81 let Ok(mut shard) = user_connection_shards[shard_index].write() else {
82 return;
83 };
84
85 if ConnectionManager::remove_user_connection_index(&mut shard, user_id, connection_id) {
86 self.user_count.fetch_sub(1, Ordering::Relaxed);
87 }
88 }
89}
90
91struct ConnectionWriteQueue {
92 sender: mpsc::Sender<QueuedWrite>,
93 receiver: std::sync::Mutex<Option<mpsc::Receiver<QueuedWrite>>>,
94 connection: ConnectionHandle,
95 closed: Arc<std::sync::atomic::AtomicBool>,
96 writer_started: std::sync::atomic::AtomicBool,
97 connection_id: String,
98 send_timeout: Duration,
99 removal_registry: ConnectionRemovalRegistry,
100}
101
102impl ConnectionWriteQueue {
103 fn new(
104 connection_id: String,
105 connection: ConnectionHandle,
106 send_timeout: Duration,
107 queue_capacity: usize,
108 removal_registry: ConnectionRemovalRegistry,
109 ) -> ConnectionWriteHandle {
110 let (sender, receiver) = mpsc::channel(queue_capacity.max(1));
111 let closed = Arc::new(std::sync::atomic::AtomicBool::new(false));
112 Arc::new(Self {
113 sender,
114 receiver: std::sync::Mutex::new(Some(receiver)),
115 connection: Arc::clone(&connection),
116 closed: Arc::clone(&closed),
117 connection_id,
118 send_timeout,
119 removal_registry,
120 writer_started: std::sync::atomic::AtomicBool::new(false),
121 })
122 }
123
124 fn ensure_writer_started(&self) -> Result<()> {
125 if self.writer_started.load(Ordering::Acquire) {
126 return Ok(());
127 }
128
129 let handle = tokio::runtime::Handle::try_current().map_err(|_| {
130 FlareError::connection_failed("Connection write queue requires a Tokio runtime")
131 })?;
132
133 if self
134 .writer_started
135 .compare_exchange(false, true, Ordering::AcqRel, Ordering::Acquire)
136 .is_err()
137 {
138 return Ok(());
139 }
140
141 let Some(receiver) = self
142 .receiver
143 .lock()
144 .ok()
145 .and_then(|mut receiver| receiver.take())
146 else {
147 self.closed.store(true, Ordering::Release);
148 return Err(FlareError::connection_closed(
149 "Connection write queue receiver is unavailable",
150 ));
151 };
152
153 handle.spawn(Self::writer_task(
154 self.connection_id.clone(),
155 Arc::clone(&self.connection),
156 receiver,
157 self.send_timeout,
158 Arc::clone(&self.closed),
159 self.removal_registry.clone(),
160 ));
161
162 Ok(())
163 }
164
165 fn try_enqueue(&self, data: &[u8]) -> Result<()> {
166 if self.closed.load(Ordering::Acquire) {
167 return Err(FlareError::connection_closed(
168 "Connection write queue is closed",
169 ));
170 }
171 self.ensure_writer_started()?;
172
173 self.sender
174 .try_send(QueuedWrite {
175 data: data.to_vec(),
176 })
177 .map_err(|err| match err {
178 mpsc::error::TrySendError::Full(_) => {
179 FlareError::connection_timeout("Connection write queue is full")
180 }
181 mpsc::error::TrySendError::Closed(_) => {
182 FlareError::connection_closed("Connection write queue is closed")
183 }
184 })
185 }
186
187 fn mark_closed(&self) -> bool {
188 !self.closed.swap(true, Ordering::AcqRel)
189 }
190
191 fn close_underlying_in_background(&self) {
192 if !self.mark_closed() {
193 return;
194 }
195
196 if tokio::runtime::Handle::try_current().is_err() {
197 return;
198 }
199
200 let connection = Arc::clone(&self.connection);
201 tokio::spawn(async move {
202 let mut conn = connection.lock().await;
203 let _ = conn.close().await;
204 });
205 }
206
207 async fn writer_task(
208 connection_id: String,
209 connection: ConnectionHandle,
210 mut receiver: mpsc::Receiver<QueuedWrite>,
211 send_timeout: Duration,
212 closed: Arc<std::sync::atomic::AtomicBool>,
213 removal_registry: ConnectionRemovalRegistry,
214 ) {
215 while let Some(write) = receiver.recv().await {
216 if closed.load(Ordering::Acquire) {
217 break;
218 }
219
220 let result = {
221 let mut conn = connection.lock().await;
222 tokio::time::timeout(send_timeout, conn.send(&write.data)).await
223 };
224
225 match result {
226 Ok(Ok(())) => {}
227 Ok(Err(err)) => {
228 closed.store(true, Ordering::Release);
229 tracing::warn!(
230 connection_id = %connection_id,
231 error = ?err,
232 "Connection writer failed; isolating connection"
233 );
234 let mut conn = connection.lock().await;
235 let _ = conn.close().await;
236 removal_registry.remove_connection(&connection_id);
237 break;
238 }
239 Err(_) => {
240 closed.store(true, Ordering::Release);
241 tracing::warn!(
242 connection_id = %connection_id,
243 timeout = ?send_timeout,
244 "Connection writer timed out; isolating connection"
245 );
246 let mut conn = connection.lock().await;
247 let _ = conn.close().await;
248 removal_registry.remove_connection(&connection_id);
249 break;
250 }
251 }
252 }
253 }
254}
255
256#[derive(Clone)]
258pub struct ConnectionInfo {
259 pub connection_id: String,
261 pub user_id: Option<String>,
263 pub created_at: Instant,
265 pub last_active: Instant,
267 pub metadata: HashMap<String, String>,
269 pub device_info: Option<crate::common::device::DeviceInfo>,
271 pub serialization_format: crate::common::protocol::SerializationFormat,
273 pub compression: crate::common::compression::CompressionAlgorithm,
275 pub encryption: crate::common::encryption::EncryptionAlgorithm,
277 pub authenticated: bool,
279 pub authenticated_at: Option<u64>,
281 pub negotiation_completed: bool,
283 pub negotiation_confirmed: bool,
286 pub cached_parser: Option<std::sync::Arc<crate::common::MessageParser>>,
288 pub cached_pipeline: Option<std::sync::Arc<crate::common::message::pipeline::MessagePipeline>>,
290}
291
292impl ConnectionInfo {
293 pub fn new(connection_id: String, requires_auth: bool) -> Self {
299 let now = Instant::now();
300 let authenticated = !requires_auth; Self {
302 connection_id,
303 user_id: None,
304 created_at: now,
305 last_active: now,
306 metadata: HashMap::new(),
307 device_info: None,
308 serialization_format: crate::common::protocol::SerializationFormat::Json,
310 compression: crate::common::compression::CompressionAlgorithm::None,
311 encryption: crate::common::encryption::EncryptionAlgorithm::None,
312 authenticated,
313 authenticated_at: authenticated.then(|| {
314 std::time::SystemTime::now()
315 .duration_since(std::time::UNIX_EPOCH)
316 .unwrap_or_default()
317 .as_secs()
318 }),
319 negotiation_completed: false, negotiation_confirmed: false, cached_parser: None, cached_pipeline: None, }
324 }
325
326 pub fn set_authenticated(&mut self, user_id: Option<String>) {
328 self.authenticated = true;
329 self.authenticated_at = Some(
330 std::time::SystemTime::now()
331 .duration_since(std::time::UNIX_EPOCH)
332 .unwrap_or_default()
333 .as_secs(),
334 );
335 if let Some(uid) = user_id {
336 self.user_id = Some(uid);
337 }
338 }
339
340 pub fn is_authenticated(&self) -> bool {
342 self.authenticated
343 }
344
345 pub fn with_device_info(mut self, device_info: crate::common::device::DeviceInfo) -> Self {
347 self.device_info = Some(device_info);
348 self
349 }
350
351 pub fn with_serialization_format(
353 mut self,
354 format: crate::common::protocol::SerializationFormat,
355 ) -> Self {
356 self.serialization_format = format;
357 self
358 }
359
360 pub fn with_compression(
362 mut self,
363 compression: crate::common::compression::CompressionAlgorithm,
364 ) -> Self {
365 self.compression = compression;
366 self
367 }
368
369 pub fn is_timeout(&self, timeout: Duration) -> bool {
371 self.last_active.elapsed() > timeout
372 }
373
374 pub fn update_active(&mut self) {
376 self.last_active = Instant::now();
377 }
378}
379
380pub struct ConnectionManager {
384 connection_shards: Arc<Vec<ConnectionShard>>,
386 user_connection_shards: Arc<Vec<UserConnectionShard>>,
388 connection_count: Arc<AtomicUsize>,
390 user_count: Arc<AtomicUsize>,
392 send_timeout: Duration,
394 fanout_concurrency: usize,
396 write_queue_capacity: usize,
398}
399
400impl Default for ConnectionManager {
401 fn default() -> Self {
402 Self::new()
403 }
404}
405
406mod lifecycle;
407mod ops;
408#[cfg(test)]
409mod tests;
410mod trait_impl;