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