1use crate::protocol::Kcp;
2
3use ::hashlink::LinkedHashMap;
4use ::parking_lot::Mutex;
5use ::std::{
6 sync::Arc,
7 time::{Duration, Instant},
8};
9
10#[derive(Clone)]
11pub struct ConvCache(Arc<Mutex<Inner>>);
12
13struct Inner {
14 map: LinkedHashMap<u32, Instant>,
15 timeout: Duration,
16}
17
18impl ConvCache {
19 pub fn new(capacity: usize, timeout: Duration) -> Self {
20 Self(Arc::new(Mutex::new(Inner {
21 map: if capacity == 0 {
22 LinkedHashMap::new()
23 } else {
24 LinkedHashMap::with_capacity(capacity)
25 },
26 timeout,
27 })))
28 }
29
30 pub fn allocate(&self, exists: impl Fn(&u32) -> bool) -> u32 {
31 let mut guard = self.0.lock();
32 Self::update(&mut guard, Instant::now());
33 loop {
34 let conv = Kcp::rand_conv();
35 if !exists(&conv) && !guard.map.contains_key(&conv) {
36 break conv;
37 }
38 }
39 }
40
41 pub fn add(&self, conv: u32) {
42 let mut guard = self.0.lock();
43 let now = Instant::now();
44 Self::update(&mut guard, now);
45 if Kcp::is_valid_conv(conv) {
46 guard.map.insert(conv, now);
47 }
48 }
49
50 pub fn fill<T>(&self, iter: T)
51 where
52 T: IntoIterator<Item = u32>,
53 {
54 let mut guard = self.0.lock();
55 let now = Instant::now();
56 Self::update(&mut guard, now);
57 for conv in iter {
58 if Kcp::is_valid_conv(conv) {
59 guard.map.insert(conv, now);
60 }
61 }
62 }
63
64 pub fn dump(&self) -> Vec<u32> {
65 let mut guard = self.0.lock();
66 Self::update(&mut guard, Instant::now());
67 guard.map.keys().copied().collect()
68 }
69
70 fn update(this: &mut Inner, now: Instant) {
71 while let Some((_, time)) = this.map.front() {
72 if now.duration_since(*time) < this.timeout {
73 break;
74 }
75 this.map.pop_front();
76 }
77 }
78}