diff options
| author | David Lönnhager <david.l@mullvad.net> | 2022-04-29 10:39:09 +0200 |
|---|---|---|
| committer | David Lönnhager <david.l@mullvad.net> | 2022-04-29 10:39:09 +0200 |
| commit | 2028e5b78ddc90d8d1df7e9ac830346cf912388a (patch) | |
| tree | 899a2df22beaa94d2a0827e6502b6f3188486c88 | |
| parent | 5937149e6a2c231dba0efaf37c5b0f9eb37224fb (diff) | |
| parent | df5bb986a485ec0a79ce3b6171fe94126a8d11e6 (diff) | |
| download | mullvadvpn-2028e5b78ddc90d8d1df7e9ac830346cf912388a.tar.xz mullvadvpn-2028e5b78ddc90d8d1df7e9ac830346cf912388a.zip | |
Merge branch 'pause-inactive-daemon'
| -rw-r--r-- | CHANGELOG.md | 1 | ||||
| -rw-r--r-- | mullvad-api/src/availability.rs | 108 | ||||
| -rw-r--r-- | mullvad-daemon/src/lib.rs | 15 | ||||
| -rw-r--r-- | mullvad-types/src/states.rs | 8 |
4 files changed, 121 insertions, 11 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md index 112922a2af..4413af951f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -50,6 +50,7 @@ Line wrap the file at 100 chars. Th - Randomize bridge selection with a bias in favor of close bridges. - Make login field keep previous value when submitting an incorrect account number in desktop app. - Decrease the time it takes to connect to WireGuard relays by sending an ICMP packet immediately. +- Pause API interactions when the daemon has not been used for 3 days. ### Fixed - Fix the sometimes incorrect time added text after adding time to the account. diff --git a/mullvad-api/src/availability.rs b/mullvad-api/src/availability.rs index 2cf40cf53b..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,53 +86,115 @@ 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) { - log::debug!("Suspending API requests"); let mut state = self.state.lock().unwrap(); if !state.suspended { + log::debug!("Suspending API requests"); + state.suspended = true; let _ = self.tx.send(*state); } } pub fn unsuspend(&self) { - log::debug!("Unsuspending API requests"); let mut state = self.state.lock().unwrap(); if state.suspended { + log::debug!("Unsuspending API requests"); + state.suspended = false; let _ = self.tx.send(*state); } } pub fn pause_background(&self) { - log::debug!("Pausing background API requests"); let mut state = self.state.lock().unwrap(); if !state.pause_background { + log::debug!("Pausing background API requests"); + state.pause_background = true; let _ = self.tx.send(*state); } } pub fn resume_background(&self) { - log::debug!("Resuming background API requests"); + 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); } } - pub fn set_offline(&self, offline: bool) { - if offline { - log::debug!("Pausing API requests due to being offline"); - } else { - log::debug!("Resuming API requests due to coming online"); + 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 { + if offline { + log::debug!("Pausing API requests due to being offline"); + } else { + log::debug!("Resuming API requests due to coming online"); + } + state.offline = offline; let _ = self.tx.send(*state); } diff --git a/mullvad-daemon/src/lib.rs b/mullvad-daemon/src/lib.rs index 19f17e3e45..c34820d78c 100644 --- a/mullvad-daemon/src/lib.rs +++ b/mullvad-daemon/src/lib.rs @@ -970,6 +970,16 @@ where } log::debug!("New tunnel state: {:?}", tunnel_state); + + match tunnel_state { + TunnelState::Disconnected => { + self.api_handle.availability.reset_inactivity_timer(); + } + _ => { + self.api_handle.availability.stop_inactivity_timer(); + } + } + match tunnel_state { TunnelState::Disconnected => self.state.disconnected(), TunnelState::Error(ref error_state) => { @@ -1172,6 +1182,11 @@ where log::trace!("Dropping daemon command because the daemon is shutting down",); return; } + + if self.tunnel_state.is_disconnected() { + self.api_handle.availability.reset_inactivity_timer(); + } + match command { SetTargetState(tx, state) => self.on_set_target_state(tx, state).await, Reconnect(tx) => self.on_reconnect(tx), diff --git a/mullvad-types/src/states.rs b/mullvad-types/src/states.rs index 86d9e816fe..700b83582f 100644 --- a/mullvad-types/src/states.rs +++ b/mullvad-types/src/states.rs @@ -63,4 +63,12 @@ impl TunnelState { _ => false, } } + + /// Returns true if the tunnel state is in the disconnected state. + pub fn is_disconnected(&self) -> bool { + match self { + TunnelState::Disconnected => true, + _ => false, + } + } } |
