kcp/
conv.rs

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}