turn/client/
periodic_timer.rs

1#[cfg(test)]
2mod periodic_timer_test;
3
4use std::sync::Arc;
5
6use async_trait::async_trait;
7use tokio::sync::{mpsc, Mutex};
8use tokio::time::Duration;
9
10#[derive(Default, Debug, Copy, Clone, PartialEq, Eq)]
11pub enum TimerIdRefresh {
12    #[default]
13    Alloc,
14    Perms,
15}
16
17/// `PeriodicTimerTimeoutHandler` is a handler called on timeout.
18#[async_trait]
19pub trait PeriodicTimerTimeoutHandler {
20    async fn on_timeout(&mut self, id: TimerIdRefresh);
21}
22
23/// `PeriodicTimer` is a periodic timer.
24#[derive(Default)]
25pub struct PeriodicTimer {
26    id: TimerIdRefresh,
27    interval: Duration,
28    close_tx: Mutex<Option<mpsc::Sender<()>>>,
29}
30
31impl PeriodicTimer {
32    /// create a new [`PeriodicTimer`].
33    pub fn new(id: TimerIdRefresh, interval: Duration) -> Self {
34        PeriodicTimer {
35            id,
36            interval,
37            close_tx: Mutex::new(None),
38        }
39    }
40
41    /// Starts the timer.
42    pub async fn start<T: 'static + PeriodicTimerTimeoutHandler + std::marker::Send>(
43        &self,
44        timeout_handler: Arc<Mutex<T>>,
45    ) -> bool {
46        // this is a noop if the timer is always running
47        {
48            let close_tx = self.close_tx.lock().await;
49            if close_tx.is_some() {
50                return false;
51            }
52        }
53
54        let (close_tx, mut close_rx) = mpsc::channel(1);
55        let interval = self.interval;
56        let id = self.id;
57
58        tokio::spawn(async move {
59            loop {
60                let timer = tokio::time::sleep(interval);
61                tokio::pin!(timer);
62
63                tokio::select! {
64                    _ = timer.as_mut() => {
65                        let mut handler = timeout_handler.lock().await;
66                        handler.on_timeout(id).await;
67                    }
68                    _ = close_rx.recv() => break,
69                }
70            }
71        });
72
73        {
74            let mut close = self.close_tx.lock().await;
75            *close = Some(close_tx);
76        }
77
78        true
79    }
80
81    /// Stops the timer.
82    pub async fn stop(&self) {
83        let mut close_tx = self.close_tx.lock().await;
84        close_tx.take();
85    }
86
87    /// Tests if the timer is running.
88    /// Debug purpose only.
89    pub async fn is_running(&self) -> bool {
90        let close_tx = self.close_tx.lock().await;
91        close_tx.is_some()
92    }
93}