Skip to main content

flare_core/server/connection/manager/
lifecycle.rs

1use super::*;
2
3impl ConnectionManager {
4    /// 创建新的连接管理器
5    pub fn new() -> Self {
6        Self::with_send_timeout(DEFAULT_SEND_TIMEOUT)
7    }
8
9    /// 使用指定写超时创建连接管理器
10    pub fn with_send_timeout(send_timeout: Duration) -> Self {
11        Self::with_limits(send_timeout, DEFAULT_FANOUT_CONCURRENCY)
12    }
13
14    /// 使用指定写超时和 fanout 并发度创建连接管理器
15    pub fn with_limits(send_timeout: Duration, fanout_concurrency: usize) -> Self {
16        Self::with_write_queue_limits(
17            send_timeout,
18            fanout_concurrency,
19            DEFAULT_WRITE_QUEUE_CAPACITY,
20        )
21    }
22
23    /// 使用指定写超时、fanout 并发度和每连接写队列容量创建连接管理器。
24    pub fn with_write_queue_limits(
25        send_timeout: Duration,
26        fanout_concurrency: usize,
27        write_queue_capacity: usize,
28    ) -> Self {
29        Self {
30            connection_shards: Arc::new(
31                (0..CONNECTION_SHARD_COUNT)
32                    .map(|_| RwLock::new(HashMap::new()))
33                    .collect(),
34            ),
35            user_connection_shards: Arc::new(
36                (0..USER_CONNECTION_SHARD_COUNT)
37                    .map(|_| RwLock::new(HashMap::new()))
38                    .collect(),
39            ),
40            connection_count: Arc::new(AtomicUsize::new(0)),
41            user_count: Arc::new(AtomicUsize::new(0)),
42            send_timeout,
43            fanout_concurrency: fanout_concurrency.max(1),
44            write_queue_capacity: write_queue_capacity.max(1),
45        }
46    }
47
48    pub(super) fn removal_registry(&self) -> ConnectionRemovalRegistry {
49        ConnectionRemovalRegistry {
50            connection_shards: Arc::downgrade(&self.connection_shards),
51            user_connection_shards: Arc::downgrade(&self.user_connection_shards),
52            connection_count: Arc::clone(&self.connection_count),
53            user_count: Arc::clone(&self.user_count),
54        }
55    }
56
57    pub(super) fn new_connection_entry(
58        &self,
59        connection_id: &str,
60        connection: ConnectionHandle,
61        info: ConnectionInfo,
62    ) -> ConnectionEntry {
63        let writer = ConnectionWriteQueue::new(
64            connection_id.to_string(),
65            Arc::clone(&connection),
66            self.send_timeout,
67            self.write_queue_capacity,
68            self.removal_registry(),
69        );
70        (connection, writer, info)
71    }
72
73    pub(super) fn shard_index(key: &str, shard_count: usize) -> usize {
74        let mut hasher = DefaultHasher::new();
75        key.hash(&mut hasher);
76        hasher.finish() as usize % shard_count
77    }
78
79    pub(super) fn connection_shard_index(&self, connection_id: &str) -> usize {
80        Self::shard_index(connection_id, self.connection_shards.len())
81    }
82
83    pub(super) fn connection_shard(&self, connection_id: &str) -> &ConnectionShard {
84        &self.connection_shards[self.connection_shard_index(connection_id)]
85    }
86
87    pub(super) fn user_connection_shard_index(&self, user_id: &str) -> usize {
88        Self::shard_index(user_id, self.user_connection_shards.len())
89    }
90
91    pub(super) fn user_connection_shard(&self, user_id: &str) -> &UserConnectionShard {
92        &self.user_connection_shards[self.user_connection_shard_index(user_id)]
93    }
94
95    pub(super) fn reserve_connection_slot(&self, max_connections: usize) -> Result<()> {
96        loop {
97            let current = self.connection_count.load(Ordering::Relaxed);
98            if current >= max_connections {
99                return Err(FlareError::connection_failed(format!(
100                    "Connection limit exceeded: {}",
101                    max_connections
102                )));
103            }
104
105            if self
106                .connection_count
107                .compare_exchange_weak(current, current + 1, Ordering::AcqRel, Ordering::Relaxed)
108                .is_ok()
109            {
110                return Ok(());
111            }
112        }
113    }
114
115    pub(super) fn release_connection_slot(&self) {
116        self.connection_count.fetch_sub(1, Ordering::Relaxed);
117    }
118
119    pub(super) fn insert_user_connection(
120        &self,
121        user_id: String,
122        connection_id: &str,
123    ) -> Result<()> {
124        let mut user_connections = self
125            .user_connection_shard(&user_id)
126            .write()
127            .map_err(|_| FlareError::general_error("Failed to lock user_connection shard"))?;
128        if Self::insert_user_connection_index(&mut user_connections, user_id, connection_id) {
129            self.user_count.fetch_add(1, Ordering::Relaxed);
130        }
131        Ok(())
132    }
133
134    pub(super) fn remove_user_connection(&self, user_id: &str, connection_id: &str) -> Result<()> {
135        let mut user_connections = self
136            .user_connection_shard(user_id)
137            .write()
138            .map_err(|_| FlareError::general_error("Failed to lock user_connection shard"))?;
139        if Self::remove_user_connection_index(&mut user_connections, user_id, connection_id) {
140            self.user_count.fetch_sub(1, Ordering::Relaxed);
141        }
142        Ok(())
143    }
144
145    pub(super) fn insert_user_connection_index(
146        user_connections: &mut HashMap<String, Vec<String>>,
147        user_id: String,
148        connection_id: &str,
149    ) -> bool {
150        let is_new_user = !user_connections.contains_key(&user_id);
151        let conn_ids = user_connections.entry(user_id).or_default();
152        if !conn_ids.iter().any(|id| id == connection_id) {
153            conn_ids.push(connection_id.to_string());
154        }
155        is_new_user
156    }
157
158    pub(super) fn remove_user_connection_index(
159        user_connections: &mut HashMap<String, Vec<String>>,
160        user_id: &str,
161        connection_id: &str,
162    ) -> bool {
163        let Some(conn_ids) = user_connections.get_mut(user_id) else {
164            return false;
165        };
166
167        conn_ids.retain(|id| id != connection_id);
168        if conn_ids.is_empty() {
169            user_connections.remove(user_id);
170            true
171        } else {
172            false
173        }
174    }
175
176    /// 添加连接
177    ///
178    /// # 参数
179    /// - `connection_id`: 连接唯一标识符
180    /// - `connection`: 连接实例
181    /// - `user_id`: 可选的用户 ID(如果已认证)
182    /// - `requires_auth`: 是否需要认证(如果为 false,连接直接标记为已验证)
183    ///
184    /// # 返回
185    /// 如果连接 ID 已存在,返回错误
186    pub fn add_connection(
187        &self,
188        connection_id: String,
189        connection: Box<dyn Connection>,
190        user_id: Option<String>,
191        requires_auth: bool,
192    ) -> Result<()> {
193        self.add_connection_with_limit(
194            connection_id,
195            connection,
196            user_id,
197            requires_auth,
198            usize::MAX,
199        )
200    }
201
202    /// 添加连接,并在同一个写锁临界区内检查容量。
203    ///
204    /// 这个入口用于传输层新连接注册,避免先 `connection_count` 再 `add_connection`
205    /// 在高并发握手完成时产生超额注册。
206    pub fn add_connection_with_limit(
207        &self,
208        connection_id: String,
209        connection: Box<dyn Connection>,
210        user_id: Option<String>,
211        requires_auth: bool,
212        max_connections: usize,
213    ) -> Result<()> {
214        self.reserve_connection_slot(max_connections)?;
215
216        let mut shard = match self.connection_shard(&connection_id).write() {
217            Ok(shard) => shard,
218            Err(_) => {
219                self.release_connection_slot();
220                return Err(FlareError::general_error("Failed to lock connection shard"));
221            }
222        };
223
224        if shard.contains_key(&connection_id) {
225            self.release_connection_slot();
226            return Err(FlareError::protocol_error(format!(
227                "Connection {} already exists",
228                connection_id
229            )));
230        }
231
232        let mut info = ConnectionInfo::new(connection_id.clone(), requires_auth);
233        info.user_id = user_id.clone();
234
235        let connection = Arc::new(Mutex::new(connection));
236        let entry = self.new_connection_entry(&connection_id, connection, info);
237        shard.insert(connection_id.clone(), entry);
238
239        // 如果提供了用户 ID,添加到用户连接映射
240        if let Some(user_id) = user_id
241            && let Err(err) = self.insert_user_connection(user_id, &connection_id)
242        {
243            shard.remove(&connection_id);
244            self.release_connection_slot();
245            return Err(err);
246        }
247
248        Ok(())
249    }
250
251    /// 移除连接
252    ///
253    /// # 参数
254    /// - `connection_id`: 要移除的连接 ID
255    ///
256    /// # 返回
257    /// 如果连接不存在,返回错误
258    pub fn remove_connection(&self, connection_id: &str) -> Result<()> {
259        let mut shard = self
260            .connection_shard(connection_id)
261            .write()
262            .map_err(|_| FlareError::general_error("Failed to lock connection shard"))?;
263
264        let (_, writer, info) = shard.remove(connection_id).ok_or_else(|| {
265            FlareError::protocol_error(format!("Connection {} not found", connection_id))
266        })?;
267        writer.close_underlying_in_background();
268        self.release_connection_slot();
269
270        // 如果连接关联了用户,从用户连接映射中移除
271        if let Some(user_id) = info.user_id {
272            self.remove_user_connection(&user_id, connection_id)?;
273        }
274
275        Ok(())
276    }
277
278    /// 获取连接
279    ///
280    /// # 参数
281    /// - `connection_id`: 连接 ID
282    ///
283    /// # 返回
284    /// 连接实例和连接信息的元组,如果不存在则返回 None
285    #[allow(clippy::type_complexity)]
286    pub fn get_connection(
287        &self,
288        connection_id: &str,
289    ) -> Option<(ConnectionHandle, ConnectionInfo)> {
290        let shard = self.connection_shard(connection_id).read().ok()?;
291        let (conn, _, info) = shard.get(connection_id)?;
292        let conn_clone = Arc::clone(conn);
293        let info_clone = info.clone();
294        drop(shard);
295        Some((conn_clone, info_clone))
296    }
297
298    pub(super) fn get_connection_snapshot(
299        &self,
300        connection_id: &str,
301    ) -> Option<ConnectionSnapshot> {
302        let shard = self.connection_shard(connection_id).read().ok()?;
303        let (_, writer, info) = shard.get(connection_id)?;
304        Some((connection_id.to_string(), Arc::clone(writer), info.clone()))
305    }
306
307    pub(super) fn connection_handles(&self) -> Vec<ConnectionHandleSnapshot> {
308        self.connection_shards
309            .iter()
310            .flat_map(|shard| {
311                shard
312                    .read()
313                    .ok()
314                    .map(|connections| {
315                        connections
316                            .iter()
317                            .map(|(id, (_, writer, _))| (id.clone(), Arc::clone(writer)))
318                            .collect::<Vec<_>>()
319                    })
320                    .unwrap_or_default()
321            })
322            .collect()
323    }
324
325    pub(super) fn connection_handles_except(
326        &self,
327        exclude_connection_id: &str,
328    ) -> Vec<ConnectionHandleSnapshot> {
329        self.connection_shards
330            .iter()
331            .flat_map(|shard| {
332                shard
333                    .read()
334                    .ok()
335                    .map(|connections| {
336                        connections
337                            .iter()
338                            .filter(|(id, _)| id.as_str() != exclude_connection_id)
339                            .map(|(id, (_, writer, _))| (id.clone(), Arc::clone(writer)))
340                            .collect::<Vec<_>>()
341                    })
342                    .unwrap_or_default()
343            })
344            .collect()
345    }
346
347    pub(super) fn connection_handles_for_ids(
348        &self,
349        connection_ids: Vec<String>,
350    ) -> Vec<ConnectionHandleSnapshot> {
351        let mut ids_by_shard = vec![Vec::new(); self.connection_shards.len()];
352        for connection_id in connection_ids {
353            let shard_index = self.connection_shard_index(&connection_id);
354            ids_by_shard[shard_index].push(connection_id);
355        }
356
357        ids_by_shard
358            .into_iter()
359            .enumerate()
360            .flat_map(|(shard_index, ids)| {
361                if ids.is_empty() {
362                    return Vec::new();
363                }
364
365                self.connection_shards[shard_index]
366                    .read()
367                    .ok()
368                    .map(|connections| {
369                        ids.into_iter()
370                            .filter_map(|id| {
371                                connections
372                                    .get(&id)
373                                    .map(|(_, writer, _)| (id, Arc::clone(writer)))
374                            })
375                            .collect::<Vec<_>>()
376                    })
377                    .unwrap_or_default()
378            })
379            .collect()
380    }
381
382    pub(super) fn connection_auth_snapshots(&self) -> Vec<ConnectionAuthSnapshot> {
383        self.connection_shards
384            .iter()
385            .flat_map(|shard| {
386                shard
387                    .read()
388                    .ok()
389                    .map(|connections| {
390                        connections
391                            .iter()
392                            .map(|(id, (_, writer, info))| {
393                                (id.clone(), Arc::clone(writer), info.authenticated)
394                            })
395                            .collect::<Vec<_>>()
396                    })
397                    .unwrap_or_default()
398            })
399            .collect()
400    }
401
402    pub(super) fn connection_auth_snapshots_except(
403        &self,
404        exclude_connection_id: &str,
405    ) -> Vec<ConnectionAuthSnapshot> {
406        self.connection_shards
407            .iter()
408            .flat_map(|shard| {
409                shard
410                    .read()
411                    .ok()
412                    .map(|connections| {
413                        connections
414                            .iter()
415                            .filter(|(id, _)| id.as_str() != exclude_connection_id)
416                            .map(|(id, (_, writer, info))| {
417                                (id.clone(), Arc::clone(writer), info.authenticated)
418                            })
419                            .collect::<Vec<_>>()
420                    })
421                    .unwrap_or_default()
422            })
423            .collect()
424    }
425
426    pub(super) fn connection_auth_snapshots_for_ids(
427        &self,
428        connection_ids: Vec<String>,
429    ) -> Vec<ConnectionAuthSnapshot> {
430        let mut ids_by_shard = vec![Vec::new(); self.connection_shards.len()];
431        for connection_id in connection_ids {
432            let shard_index = self.connection_shard_index(&connection_id);
433            ids_by_shard[shard_index].push(connection_id);
434        }
435
436        ids_by_shard
437            .into_iter()
438            .enumerate()
439            .flat_map(|(shard_index, ids)| {
440                if ids.is_empty() {
441                    return Vec::new();
442                }
443
444                self.connection_shards[shard_index]
445                    .read()
446                    .ok()
447                    .map(|connections| {
448                        ids.into_iter()
449                            .filter_map(|id| {
450                                connections.get(&id).map(|(_, writer, info)| {
451                                    (id, Arc::clone(writer), info.authenticated)
452                                })
453                            })
454                            .collect::<Vec<_>>()
455                    })
456                    .unwrap_or_default()
457            })
458            .collect()
459    }
460
461    pub(super) fn connection_snapshots(&self) -> Vec<ConnectionSnapshot> {
462        self.connection_shards
463            .iter()
464            .flat_map(|shard| {
465                shard
466                    .read()
467                    .ok()
468                    .map(|connections| {
469                        connections
470                            .iter()
471                            .map(|(id, (_, writer, info))| {
472                                (id.clone(), Arc::clone(writer), info.clone())
473                            })
474                            .collect::<Vec<_>>()
475                    })
476                    .unwrap_or_default()
477            })
478            .collect()
479    }
480
481    pub(super) fn connection_snapshots_except(
482        &self,
483        exclude_connection_id: &str,
484    ) -> Vec<ConnectionSnapshot> {
485        self.connection_shards
486            .iter()
487            .flat_map(|shard| {
488                shard
489                    .read()
490                    .ok()
491                    .map(|connections| {
492                        connections
493                            .iter()
494                            .filter(|(id, _)| id.as_str() != exclude_connection_id)
495                            .map(|(id, (_, writer, info))| {
496                                (id.clone(), Arc::clone(writer), info.clone())
497                            })
498                            .collect::<Vec<_>>()
499                    })
500                    .unwrap_or_default()
501            })
502            .collect()
503    }
504
505    pub(super) fn connection_snapshots_for_ids(
506        &self,
507        connection_ids: Vec<String>,
508    ) -> Vec<ConnectionSnapshot> {
509        let mut ids_by_shard = vec![Vec::new(); self.connection_shards.len()];
510        for connection_id in connection_ids {
511            let shard_index = self.connection_shard_index(&connection_id);
512            ids_by_shard[shard_index].push(connection_id);
513        }
514
515        ids_by_shard
516            .into_iter()
517            .enumerate()
518            .flat_map(|(shard_index, ids)| {
519                if ids.is_empty() {
520                    return Vec::new();
521                }
522
523                self.connection_shards[shard_index]
524                    .read()
525                    .ok()
526                    .map(|connections| {
527                        ids.into_iter()
528                            .filter_map(|id| {
529                                connections
530                                    .get(&id)
531                                    .map(|(_, writer, info)| (id, Arc::clone(writer), info.clone()))
532                            })
533                            .collect::<Vec<_>>()
534                    })
535                    .unwrap_or_default()
536            })
537            .collect()
538    }
539
540    pub(super) fn timeout_connection_snapshots(
541        &self,
542        timeout: Duration,
543    ) -> Vec<TimeoutConnectionSnapshot> {
544        self.connection_shards
545            .iter()
546            .flat_map(|shard| {
547                shard
548                    .read()
549                    .ok()
550                    .map(|connections| {
551                        connections
552                            .iter()
553                            .filter(|(_, (_, _, info))| info.is_timeout(timeout))
554                            .map(|(id, (connection, _, info))| {
555                                (id.clone(), Arc::clone(connection), info.user_id.clone())
556                            })
557                            .collect::<Vec<_>>()
558                    })
559                    .unwrap_or_default()
560            })
561            .collect()
562    }
563
564    pub(super) fn remove_connection_snapshots<I>(&self, connection_ids: I) -> Vec<String>
565    where
566        I: IntoIterator<Item = String>,
567    {
568        let mut ids_by_shard = vec![Vec::new(); self.connection_shards.len()];
569        for connection_id in connection_ids {
570            let shard_index = self.connection_shard_index(&connection_id);
571            ids_by_shard[shard_index].push(connection_id);
572        }
573
574        let mut removed_ids = Vec::new();
575        let mut removed_user_connections = Vec::new();
576
577        for (shard_index, ids) in ids_by_shard.into_iter().enumerate() {
578            if ids.is_empty() {
579                continue;
580            }
581
582            let Ok(mut shard) = self.connection_shards[shard_index].write() else {
583                continue;
584            };
585
586            for connection_id in ids {
587                if let Some((_, writer, info)) = shard.remove(&connection_id) {
588                    writer.close_underlying_in_background();
589                    if let Some(user_id) = info.user_id {
590                        removed_user_connections.push((user_id, connection_id.clone()));
591                    }
592                    removed_ids.push(connection_id);
593                }
594            }
595        }
596
597        if !removed_ids.is_empty() {
598            self.connection_count
599                .fetch_sub(removed_ids.len(), Ordering::Relaxed);
600        }
601
602        self.remove_user_connections_batch(removed_user_connections);
603
604        removed_ids
605    }
606
607    pub(super) fn remove_user_connections_batch<I>(&self, user_connections: I)
608    where
609        I: IntoIterator<Item = (String, String)>,
610    {
611        let mut entries_by_shard = vec![Vec::new(); self.user_connection_shards.len()];
612        for (user_id, connection_id) in user_connections {
613            let shard_index = self.user_connection_shard_index(&user_id);
614            entries_by_shard[shard_index].push((user_id, connection_id));
615        }
616
617        let removed_users = entries_by_shard
618            .into_iter()
619            .enumerate()
620            .map(|(shard_index, entries)| {
621                if entries.is_empty() {
622                    return 0;
623                }
624
625                let Ok(mut shard) = self.user_connection_shards[shard_index].write() else {
626                    return 0;
627                };
628
629                entries
630                    .into_iter()
631                    .filter(|(user_id, connection_id)| {
632                        Self::remove_user_connection_index(&mut shard, user_id, connection_id)
633                    })
634                    .count()
635            })
636            .sum::<usize>();
637
638        if removed_users > 0 {
639            self.user_count.fetch_sub(removed_users, Ordering::Relaxed);
640        }
641    }
642}