diff options
| author | David Lönnhager <david.l@mullvad.net> | 2022-04-27 15:23:46 +0200 |
|---|---|---|
| committer | David Lönnhager <david.l@mullvad.net> | 2022-04-29 10:38:11 +0200 |
| commit | 18da51d971eebb19ff889d4ff8e6bc6b955a8a4f (patch) | |
| tree | 520192429fab3612d73560cd25ce75945bec7bce /mullvad-api/src | |
| parent | 9014cb5201fb8b47a495ac23abb9dbc309dff25b (diff) | |
| download | mullvadvpn-18da51d971eebb19ff889d4ff8e6bc6b955a8a4f.tar.xz mullvadvpn-18da51d971eebb19ff889d4ff8e6bc6b955a8a4f.zip | |
Pause API requests when the daemon hasn't received any commands for 3 days
Diffstat (limited to 'mullvad-api/src')
| -rw-r--r-- | mullvad-api/src/availability.rs | 87 |
1 files changed, 84 insertions, 3 deletions
diff --git a/mullvad-api/src/availability.rs b/mullvad-api/src/availability.rs index 23c5e9f32b..f66fb4053a 100644 --- a/mullvad-api/src/availability.rs +++ b/mullvad-api/src/availability.rs @@ -1,11 +1,16 @@ use std::{ future::Future, sync::{Arc, Mutex}, + time::Duration, }; use tokio::sync::broadcast; const CHANNEL_CAPACITY: usize = 100; +/// Pause background requests if [ApiAvailabilityHandle::reset_inactivity_timer] hasn't been +/// called for this long. +const INACTIVITY_TIME: Duration = Duration::from_secs(3 * 24 * 60 * 60); + #[derive(err_derive::Error, Debug)] pub enum Error { /// The [`ApiAvailability`] instance was dropped, or the receiver lagged behind. @@ -18,6 +23,7 @@ pub struct State { suspended: bool, pause_background: bool, offline: bool, + inactive: bool, } impl State { @@ -26,7 +32,7 @@ impl State { } pub fn is_background_paused(&self) -> bool { - self.offline || self.pause_background || self.suspended + self.offline || self.pause_background || self.suspended || self.inactive } pub fn is_offline(&self) -> bool { @@ -37,13 +43,22 @@ impl State { pub struct ApiAvailability { state: Arc<Mutex<State>>, tx: broadcast::Sender<State>, + + inactivity_timer: Arc<Mutex<Option<tokio::task::JoinHandle<()>>>>, } impl ApiAvailability { pub fn new(initial_state: State) -> Self { let (tx, _rx) = broadcast::channel(CHANNEL_CAPACITY); let state = Arc::new(Mutex::new(initial_state)); - ApiAvailability { state, tx } + + let availability = ApiAvailability { + state, + tx, + inactivity_timer: Arc::new(Mutex::new(None)), + }; + availability.handle().reset_inactivity_timer(); + availability } pub fn get_state(&self) -> State { @@ -54,6 +69,15 @@ impl ApiAvailability { ApiAvailabilityHandle { state: self.state.clone(), tx: self.tx.clone(), + inactivity_timer: self.inactivity_timer.clone(), + } + } +} + +impl Drop for ApiAvailability { + fn drop(&mut self) { + if let Some(timer) = self.inactivity_timer.lock().unwrap().take() { + timer.abort(); } } } @@ -62,9 +86,45 @@ impl ApiAvailability { pub struct ApiAvailabilityHandle { state: Arc<Mutex<State>>, tx: broadcast::Sender<State>, + inactivity_timer: Arc<Mutex<Option<tokio::task::JoinHandle<()>>>>, } impl ApiAvailabilityHandle { + /// Reset task that automatically pauses API requests due inactivity, + /// starting it if it's not currently running. + pub fn reset_inactivity_timer(&self) { + log::trace!("Restarting API inactivity check"); + + let self_ = self.clone(); + + let mut inactivity_timer = self.inactivity_timer.lock().unwrap(); + if let Some(timer) = inactivity_timer.take() { + timer.abort(); + } + + self.set_active(); + + *inactivity_timer = Some(tokio::spawn(async move { + talpid_time::sleep(INACTIVITY_TIME).await; + self_.set_inactive(); + })); + } + + /// Stops timer that pauses API requests due to inactivity. + pub fn stop_inactivity_timer(&self) { + log::trace!("Stopping API inactivity check"); + + let mut inactivity_timer = self.inactivity_timer.lock().unwrap(); + if let Some(timer) = inactivity_timer.take() { + timer.abort(); + } + self.set_active(); + } + + fn inactivity_timer_running(&self) -> bool { + self.inactivity_timer.lock().unwrap().is_some() + } + pub fn suspend(&self) { let mut state = self.state.lock().unwrap(); if !state.suspended { @@ -96,15 +156,36 @@ impl ApiAvailabilityHandle { } pub fn resume_background(&self) { + if self.inactivity_timer_running() { + self.reset_inactivity_timer(); + } + let mut state = self.state.lock().unwrap(); if state.pause_background { log::debug!("Resuming background API requests"); - state.pause_background = false; let _ = self.tx.send(*state); } } + fn set_inactive(&self) { + let mut state = self.state.lock().unwrap(); + if !state.inactive { + log::debug!("Pausing background API requests due to inactivity"); + state.inactive = true; + let _ = self.tx.send(*state); + } + } + + fn set_active(&self) { + let mut state = self.state.lock().unwrap(); + if state.inactive { + log::debug!("Resuming background API requests due to activity"); + state.inactive = false; + let _ = self.tx.send(*state); + } + } + pub fn set_offline(&self, offline: bool) { let mut state = self.state.lock().unwrap(); if state.offline != offline { |
