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