diff --git a/mullvad-daemon/src/lib.rs b/mullvad-daemon/src/lib.rs index 53509f9ac2e2..6f59d0d24833 100644 --- a/mullvad-daemon/src/lib.rs +++ b/mullvad-daemon/src/lib.rs @@ -2447,75 +2447,41 @@ where tx: ResponseTx, access_method: mullvad_types::access_method::Id, ) { - let access_method_lookup = self - .get_api_access_method(access_method) - .map_err(Error::AccessMethodError); - - match access_method_lookup { - Ok(access_method) => { - let access_method_selector = self.connection_modes_handler.clone(); + use futures::{future, TryFutureExt}; + let access_method_selector = self.connection_modes_handler.clone(); + let access_method_lookup = future::ready( + self.get_api_access_method(access_method) + .map_err(Error::AccessMethodError), + ) + .and_then(|access_method| { + access_method_selector + .resolve(access_method) + .map_err(Error::ApiConnectionModeError) + }); - let api::ResolvedConnectionMode { - connection_mode, - endpoint, - setting, - } = match access_method_selector.resolve(access_method.clone()).await { - Ok(v) => v, - Err(err) => { - Self::oneshot_send( - tx, - Err(Error::ApiConnectionModeError(err)), - "on_test_api_access_method response", - ); - return; - } - }; + let reply = + |response| Self::oneshot_send(tx, response, "on_test_api_access_method response"); - let proxy_provider = connection_mode.into_repeat(); + match access_method_lookup.await { + Ok(test_subject) => { + let proxy_provider = test_subject.connection_mode.clone().into_repeat(); let rest_handle = self.api_runtime.mullvad_rest_handle(proxy_provider).await; let api_proxy = mullvad_api::ApiProxy::new(rest_handle); let daemon_event_sender = self.tx.to_specialized_sender(); + let access_method_selector = self.connection_modes_handler.clone(); tokio::spawn(async move { - // Send an internal daemon event which will punch a hole in the firewall for the connection mode we are testing. - let (event, update_finished_rx) = - api::NewAccessMethodEvent::new(setting, endpoint, false); - - // Wait on the daemon to finish. - let _ = daemon_event_sender.send(event); - let _ = update_finished_rx.await; - - // Send a HEAD request to some Mullvad API endpoint. We issue a HEAD - // request because we are *only* concerned with if we get a reply from - // the API, and not with the actual data that the endpoint returns. - let result = api_proxy - .api_addrs_available() - .await - .map_err(Error::RestError); - - // Tell the daemon to reset the hole we just punched to whatever was in place before. - let api::ResolvedConnectionMode { - endpoint, setting, .. - } = match access_method_selector.get_current().await { - Ok(v) => v, - Err(err) => { - Self::oneshot_send( - tx, - Err(Error::ApiConnectionModeError(err)), - "on_test_api_access_method response", - ); - return; - } - }; - let (event, update_finished_rx) = - api::NewAccessMethodEvent::new(setting, endpoint, false); - - let _ = daemon_event_sender.send(event); - let _ = update_finished_rx.await; + let result = Self::test_api_access_method_inner( + test_subject.clone(), + access_method_selector, + api_proxy, + daemon_event_sender, + ) + .await; log::debug!( "API access method {method} {result}", - method = access_method.name, + method = test_subject.setting.name, result = if result.as_ref().is_ok_and(|is_true| *is_true) { "could successfully connect to the Mullvad API".to_string() } else { @@ -2523,15 +2489,51 @@ where } ); - Self::oneshot_send(tx, result, "on_test_api_access_method response"); + reply(result); }); } - Err(err) => { - Self::oneshot_send(tx, Err(err), "on_test_api_access_method response"); - } + Err(err) => reply(Err(err)), }; } + async fn test_api_access_method_inner( + test_subject: api::ResolvedConnectionMode, + access_method_selector: api::AccessModeSelectorHandle, + api_proxy: mullvad_api::ApiProxy, + daemon_event_sender: DaemonEventSender, + ) -> Result { + // Send an internal daemon event which will punch a hole in the firewall + // for the connection mode we are testing. + let (event, update_finished_rx) = + api::NewAccessMethodEvent::new(test_subject.setting, test_subject.endpoint, false); + let _ = daemon_event_sender.send(event); + // Wait for the daemon to finish processing `event`. + let _ = update_finished_rx.await; + + // Send a HEAD request to some Mullvad API endpoint. We issue a HEAD + // request because we are *only* concerned with if we get a reply from + // the API, and not with the actual data that the endpoint returns. + let result = api_proxy + .api_addrs_available() + .await + .map_err(Error::RestError); + + // Tell the daemon to reset the hole we just punched to whatever was in + // place before. + let api::ResolvedConnectionMode { + endpoint, setting, .. + } = access_method_selector + .get_current() + .await + .map_err(Error::ApiConnectionModeError)?; + + let (event, update_finished_rx) = api::NewAccessMethodEvent::new(setting, endpoint, false); + let _ = daemon_event_sender.send(event); + // Wait for the daemon to finish processing `event`. + let _ = update_finished_rx.await; + result + } + fn on_get_settings(&self, tx: oneshot::Sender) { Self::oneshot_send(tx, self.settings.to_settings(), "get_settings response"); }