diff options
| author | Oskar <oskar@mullvad.net> | 2025-07-04 15:27:29 +0200 |
|---|---|---|
| committer | Oskar <oskar@mullvad.net> | 2025-07-04 15:27:29 +0200 |
| commit | 3e982cca836db5b7e859f59589b280afeb98bd3a (patch) | |
| tree | 0036d05dfa1d6d68d8d52e04c3d4fa6c287b3c58 | |
| parent | 4fb0191a259a62efc1264ae71135a9114ce99fd7 (diff) | |
| parent | b16514e001a7d51772a36f3fd929f471124334ec (diff) | |
| download | mullvadvpn-3e982cca836db5b7e859f59589b280afeb98bd3a.tar.xz mullvadvpn-3e982cca836db5b7e859f59589b280afeb98bd3a.zip | |
Merge branch 'add-info-icon-with-information-about-where-the-installer-is-des-2293'
12 files changed, 127 insertions, 3 deletions
diff --git a/desktop/packages/mullvad-vpn/locales/messages.pot b/desktop/packages/mullvad-vpn/locales/messages.pot index 324264959d..b21fd8317c 100644 --- a/desktop/packages/mullvad-vpn/locales/messages.pot +++ b/desktop/packages/mullvad-vpn/locales/messages.pot @@ -749,6 +749,10 @@ msgctxt "app-upgrade-view" msgid "Installer quit unexpectedly, please try again or send a problem report." msgstr "" +msgctxt "app-upgrade-view" +msgid "Installer will be downloaded to <b>%(cacheDir)s</b>." +msgstr "" + #. Text displayed when there are no updates for this platform in the next app version msgctxt "app-upgrade-view" msgid "No updates or changes were made in this release for this platform." diff --git a/desktop/packages/mullvad-vpn/src/main/app-upgrade.ts b/desktop/packages/mullvad-vpn/src/main/app-upgrade.ts index ff50218d5e..3dbe7df04f 100644 --- a/desktop/packages/mullvad-vpn/src/main/app-upgrade.ts +++ b/desktop/packages/mullvad-vpn/src/main/app-upgrade.ts @@ -30,6 +30,8 @@ export default class AppUpgrade { ); } }); + + IpcMainEventChannel.app.handleGetUpgradeCacheDir(() => this.daemonRpc.getAppUpgradeCacheDir()); } public subscribeEvents() { diff --git a/desktop/packages/mullvad-vpn/src/main/daemon-rpc.ts b/desktop/packages/mullvad-vpn/src/main/daemon-rpc.ts index 35c1f775f4..aed89bb3c9 100644 --- a/desktop/packages/mullvad-vpn/src/main/daemon-rpc.ts +++ b/desktop/packages/mullvad-vpn/src/main/daemon-rpc.ts @@ -148,6 +148,11 @@ export class DaemonRpc extends GrpcClient { void this.callEmpty(this.client.appUpgradeAbort); } + public async getAppUpgradeCacheDir(): Promise<string> { + const response = await this.callEmpty<StringValue>(this.client.getAppUpgradeCacheDir); + return response.getValue(); + } + public unsubscribeAppUpgradeEventListener(listener: SubscriptionListener<DaemonAppUpgradeEvent>) { const id = listener.subscriptionId; if (id !== undefined) { diff --git a/desktop/packages/mullvad-vpn/src/renderer/app.tsx b/desktop/packages/mullvad-vpn/src/renderer/app.tsx index e705f76661..368654e475 100644 --- a/desktop/packages/mullvad-vpn/src/renderer/app.tsx +++ b/desktop/packages/mullvad-vpn/src/renderer/app.tsx @@ -445,6 +445,7 @@ export default class AppRenderer { public daemonPrepareRestart = (shutdown: boolean): void => { IpcRendererEventChannel.daemon.prepareRestart(shutdown); }; + public getAppUpgradeCacheDir = () => IpcRendererEventChannel.app.getUpgradeCacheDir(); public tryStartDaemon = () => { if (window.env.platform === 'win32') IpcRendererEventChannel.daemon.tryStart(); diff --git a/desktop/packages/mullvad-vpn/src/renderer/components/views/app-upgrade/components/upgrade-details/UpgradeDetails.tsx b/desktop/packages/mullvad-vpn/src/renderer/components/views/app-upgrade/components/upgrade-details/UpgradeDetails.tsx index cac6f59b9c..4d227496de 100644 --- a/desktop/packages/mullvad-vpn/src/renderer/components/views/app-upgrade/components/upgrade-details/UpgradeDetails.tsx +++ b/desktop/packages/mullvad-vpn/src/renderer/components/views/app-upgrade/components/upgrade-details/UpgradeDetails.tsx @@ -1,17 +1,22 @@ +import { sprintf } from 'sprintf-js'; + import { messages } from '../../../../../../shared/gettext'; import { Container, Flex, TitleBig, TitleLarge } from '../../../../../lib/components'; +import { formatHtml } from '../../../../../lib/html-formatter'; import { AppNavigationHeader } from '../../../../app-navigation-header'; import { ChangelogList } from '../../../../changelog-list'; import { SettingsContainer } from '../../../../Layout'; import { NavigationContainer } from '../../../../NavigationContainer'; import { NavigationScrollbars } from '../../../../NavigationScrollbars'; +import { HeaderSubTitle } from '../../../../SettingsHeader'; import { NoChangelogUpdates } from './components'; -import { useChangelog, useShowChangelogList, useTitle } from './hooks'; +import { useCacheDir, useChangelog, useShowChangelogList, useTitle } from './hooks'; export function UpgradeDetails() { const changelog = useChangelog(); const showChangelogList = useShowChangelogList(); const title = useTitle(); + const cacheDir = useCacheDir(); return ( <SettingsContainer> @@ -24,13 +29,26 @@ export function UpgradeDetails() { /> <NavigationScrollbars> <Flex $flexDirection="column" $gap="large" $padding={{ bottom: 'medium' }}> - <Container size="4"> + <Container size="4" $flexDirection="column" $gap="small"> <TitleBig as="h2"> { // TRANSLATORS: Main title for the update available view messages.pgettext('app-upgrade-view', 'Update available') } </TitleBig> + {cacheDir !== undefined && ( + <HeaderSubTitle> + {formatHtml( + sprintf( + messages.pgettext( + 'app-upgrade-view', + 'Installer will be downloaded to <b>%(cacheDir)s</b>.', + ), + { cacheDir }, + ), + )} + </HeaderSubTitle> + )} </Container> <Flex $flexDirection="column" $gap="small"> <Container size="4"> diff --git a/desktop/packages/mullvad-vpn/src/renderer/components/views/app-upgrade/components/upgrade-details/hooks/index.ts b/desktop/packages/mullvad-vpn/src/renderer/components/views/app-upgrade/components/upgrade-details/hooks/index.ts index 41cfba9f0a..158c43eeac 100644 --- a/desktop/packages/mullvad-vpn/src/renderer/components/views/app-upgrade/components/upgrade-details/hooks/index.ts +++ b/desktop/packages/mullvad-vpn/src/renderer/components/views/app-upgrade/components/upgrade-details/hooks/index.ts @@ -1,3 +1,4 @@ export * from './useChangelog'; export * from './useShowChangelogList'; +export * from './useCacheDir'; export * from './useTitle'; diff --git a/desktop/packages/mullvad-vpn/src/renderer/components/views/app-upgrade/components/upgrade-details/hooks/useCacheDir.ts b/desktop/packages/mullvad-vpn/src/renderer/components/views/app-upgrade/components/upgrade-details/hooks/useCacheDir.ts new file mode 100644 index 0000000000..296b33e999 --- /dev/null +++ b/desktop/packages/mullvad-vpn/src/renderer/components/views/app-upgrade/components/upgrade-details/hooks/useCacheDir.ts @@ -0,0 +1,29 @@ +import { useEffect, useState } from 'react'; + +import log from '../../../../../../../shared/logging'; +import { useAppContext } from '../../../../../../context'; +import { useMounted } from '../../../../../../lib/utility-hooks'; + +export function useCacheDir() { + const { getAppUpgradeCacheDir } = useAppContext(); + const [cacheDir, setCacheDir] = useState<string>(); + const isMounted = useMounted(); + + useEffect(() => { + const fetchCacheDir = async () => { + try { + const cacheDir = await getAppUpgradeCacheDir(); + if (isMounted()) { + setCacheDir(cacheDir); + } + } catch (e) { + const error = e as Error; + log.warn(`Failed to fetch cache dir: ${error.message}`); + } + }; + + void fetchCacheDir(); + }, [getAppUpgradeCacheDir, isMounted]); + + return cacheDir; +} diff --git a/desktop/packages/mullvad-vpn/src/shared/ipc-schema.ts b/desktop/packages/mullvad-vpn/src/shared/ipc-schema.ts index 4f2c9da0fd..48148d9498 100644 --- a/desktop/packages/mullvad-vpn/src/shared/ipc-schema.ts +++ b/desktop/packages/mullvad-vpn/src/shared/ipc-schema.ts @@ -176,6 +176,7 @@ export const ipcSchema = { upgradeEvent: notifyRenderer<AppUpgradeEvent>(), upgradeError: notifyRenderer<AppUpgradeError>(), upgradeInstallerStart: send<string>(), + getUpgradeCacheDir: invoke<void, string>(), }, tunnel: { '': notifyRenderer<TunnelState>(), diff --git a/mullvad-daemon/src/lib.rs b/mullvad-daemon/src/lib.rs index 5550ef3a8a..efdbea5cc6 100644 --- a/mullvad-daemon/src/lib.rs +++ b/mullvad-daemon/src/lib.rs @@ -427,6 +427,8 @@ pub enum DaemonCommand { AppUpgrade(ResponseTx<(), version::Error>), /// Prompt the daemon to abort the current upgrade. AppUpgradeAbort(ResponseTx<(), version::Error>), + /// Return the storage path for the installers during in-app upgrades. + GetAppUpgradeCacheDir(ResponseTx<PathBuf, version::Error>), } /// All events that can happen in the daemon. Sent from various threads and exposed interfaces. @@ -1511,6 +1513,7 @@ impl Daemon { EnableRelay { relay, tx } => self.on_toggle_relay(relay, true, tx), AppUpgrade(tx) => self.on_app_upgrade(tx).await, AppUpgradeAbort(tx) => self.on_app_upgrade_abort(tx).await, + GetAppUpgradeCacheDir(tx) => self.on_get_app_upgrade_cache_dir(tx).await, } } @@ -3326,6 +3329,27 @@ impl Daemon { }; } + #[cfg_attr(not(in_app_upgrade), allow(clippy::unused_async))] + async fn on_get_app_upgrade_cache_dir(&self, tx: ResponseTx<PathBuf, version::Error>) { + #[cfg(in_app_upgrade)] + { + let result = self.version_handle.get_cache_dir().await; + Self::oneshot_send(tx, result, "on_get_app_upgrade_cache_dir response"); + } + #[cfg(not(in_app_upgrade))] + { + log::warn!( + "Can't get cache dir for app upgrades since in-app upgrades are disabled on this OS" + ); + + Self::oneshot_send( + tx, + Ok(PathBuf::new()), + "on_get_app_upgrade_cache_dir response", + ) + }; + } + /// Set the target state of the client. If it changed trigger the operations needed to /// progress towards that state. /// Returns a bool representing whether a state change was initiated. diff --git a/mullvad-daemon/src/management_interface.rs b/mullvad-daemon/src/management_interface.rs index aef1d17c45..a578b67610 100644 --- a/mullvad-daemon/src/management_interface.rs +++ b/mullvad-daemon/src/management_interface.rs @@ -1217,6 +1217,23 @@ impl ManagementService for ManagementServiceImpl { Box::new(upgrade_event_stream) as Self::AppUpgradeEventsListenStream )) } + + async fn get_app_upgrade_cache_dir(&self, _: Request<()>) -> ServiceResult<String> { + log::debug!("get_app_upgrade_cache_dir"); + + let (tx, rx) = oneshot::channel(); + self.send_command_to_daemon(DaemonCommand::GetAppUpgradeCacheDir(tx))?; + + let path = self + .wait_for_result(rx) + .await? + .map_err(map_version_check_error)?; + + path.into_os_string() + .into_string() + .map_err(|_| Status::internal("Failed to convert OsString to String")) + .map(Response::new) + } } impl ManagementServiceImpl { diff --git a/mullvad-daemon/src/version/router.rs b/mullvad-daemon/src/version/router.rs index 7a10c90bcf..a1b81ebabe 100644 --- a/mullvad-daemon/src/version/router.rs +++ b/mullvad-daemon/src/version/router.rs @@ -67,6 +67,15 @@ impl VersionRouterHandle { .map_err(|_| Error::VersionRouterClosed)?; result_rx.await.map_err(|_| Error::VersionRouterClosed) } + + #[cfg(in_app_upgrade)] + pub async fn get_cache_dir(&self) -> Result<PathBuf> { + let (result_tx, result_rx) = oneshot::channel(); + self.tx + .send(Message::GetCacheDir { result_tx }) + .map_err(|_| Error::VersionRouterClosed)?; + result_rx.await.map_err(|_| Error::VersionRouterClosed) + } } // These wrapper traits and type aliases exist to help feature gate the module @@ -106,6 +115,8 @@ struct VersionRouter<S = DaemonEventSender<AppVersionInfo>, D = DefaultDownloade /// Broadcast channel for app upgrade events #[cfg(in_app_upgrade)] app_upgrade_broadcast: AppUpgradeBroadcast, + #[cfg(in_app_upgrade)] + cache_dir: PathBuf, /// Type used to spawn the downloader task, replaced when testing _phantom: std::marker::PhantomData<D>, } @@ -124,6 +135,9 @@ enum Message { /// Cancel the ongoing update #[cfg(in_app_upgrade)] CancelUpdate { result_tx: oneshot::Sender<()> }, + /// Get the cache dir + #[cfg(in_app_upgrade)] + GetCacheDir { result_tx: oneshot::Sender<PathBuf> }, } #[derive(Debug)] @@ -215,7 +229,7 @@ pub(crate) fn spawn_version_router( VersionUpdater::spawn( api_handle, availability_handle, - cache_dir, + cache_dir.clone(), new_version_tx, refresh_version_check_rx, ) @@ -230,6 +244,8 @@ pub(crate) fn spawn_version_router( version_request_channels: vec![], #[cfg(in_app_upgrade)] app_upgrade_broadcast, + #[cfg(in_app_upgrade)] + cache_dir, refresh_version_check_tx, _phantom: std::marker::PhantomData::<DefaultDownloader>, } @@ -298,6 +314,10 @@ where self.cancel_upgrade(); let _ = result_tx.send(()); } + #[cfg(in_app_upgrade)] + Message::GetCacheDir { result_tx } => { + let _ = result_tx.send(self.cache_dir.clone()); + } } } @@ -723,6 +743,7 @@ mod test { version_request_channels: vec![], app_upgrade_broadcast, refresh_version_check_tx, + cache_dir: PathBuf::new(), _phantom: std::marker::PhantomData::<D>, }, VersionRouterChannels { diff --git a/mullvad-management-interface/proto/management_interface.proto b/mullvad-management-interface/proto/management_interface.proto index 14a11fff4e..6d0577ebf0 100644 --- a/mullvad-management-interface/proto/management_interface.proto +++ b/mullvad-management-interface/proto/management_interface.proto @@ -140,6 +140,7 @@ service ManagementService { rpc AppUpgrade(google.protobuf.Empty) returns (google.protobuf.Empty) {} rpc AppUpgradeAbort(google.protobuf.Empty) returns (google.protobuf.Empty) {} rpc AppUpgradeEventsListen(google.protobuf.Empty) returns (stream AppUpgradeEvent) {} + rpc GetAppUpgradeCacheDir(google.protobuf.Empty) returns (google.protobuf.StringValue) {} } message AppUpgradeEvent { |
