ashpd/flatpak/
update_monitor.rs

1//! # Examples
2//!
3//! How to monitor if there's a new update and install it.
4//! Only available for Flatpak applications.
5//!
6//! ```rust,no_run
7//! use ashpd::flatpak::Flatpak;
8//! use futures_util::StreamExt;
9//!
10//! async fn run() -> ashpd::Result<()> {
11//!     let proxy = Flatpak::new().await?;
12//!
13//!     let monitor = proxy.create_update_monitor().await?;
14//!     let info = monitor.receive_update_available().await?;
15//!
16//!     monitor.update(None).await?;
17//!     let progress = monitor
18//!         .receive_progress()
19//!         .await?
20//!         .next()
21//!         .await
22//!         .expect("Stream exhausted");
23//!     println!("{:#?}", progress);
24//!
25//!     Ok(())
26//! }
27//! ```
28
29use futures_util::Stream;
30use serde_repr::{Deserialize_repr, Serialize_repr};
31use zbus::zvariant::{DeserializeDict, ObjectPath, SerializeDict, Type};
32
33use crate::{proxy::Proxy, Error, WindowIdentifier};
34
35#[derive(SerializeDict, Type, Debug, Default)]
36/// Specified options for a [`UpdateMonitor::update`] request.
37///
38/// Currently there are no possible options yet.
39#[zvariant(signature = "dict")]
40struct UpdateOptions {}
41
42#[derive(DeserializeDict, Type, Debug)]
43/// A response containing the update information when an update is available.
44#[zvariant(signature = "dict")]
45pub struct UpdateInfo {
46    #[zvariant(rename = "running-commit")]
47    running_commit: String,
48    #[zvariant(rename = "local-commit")]
49    local_commit: String,
50    #[zvariant(rename = "remote-commit")]
51    remote_commit: String,
52}
53
54impl UpdateInfo {
55    /// The currently running OSTree commit.
56    pub fn running_commit(&self) -> &str {
57        &self.running_commit
58    }
59
60    /// The locally installed OSTree commit.
61    pub fn local_commit(&self) -> &str {
62        &self.local_commit
63    }
64
65    /// The available commit to install.
66    pub fn remote_commit(&self) -> &str {
67        &self.remote_commit
68    }
69}
70
71#[cfg_attr(feature = "glib", derive(glib::Enum))]
72#[cfg_attr(feature = "glib", enum_type(name = "AshpdUpdateStatus"))]
73#[derive(Serialize_repr, Deserialize_repr, PartialEq, Eq, Copy, Clone, Debug, Type)]
74#[repr(u32)]
75/// The update status.
76pub enum UpdateStatus {
77    #[doc(alias = "XDP_UPDATE_STATUS_RUNNING")]
78    /// Running.
79    Running = 0,
80    #[doc(alias = "XDP_UPDATE_STATUS_EMPTY")]
81    /// No update to install.
82    Empty = 1,
83    #[doc(alias = "XDP_UPDATE_STATUS_DONE")]
84    /// Done.
85    Done = 2,
86    #[doc(alias = "XDP_UPDATE_STATUS_FAILED")]
87    /// Failed.
88    Failed = 3,
89}
90
91#[derive(DeserializeDict, Type, Debug)]
92/// A response of the update progress signal.
93#[zvariant(signature = "dict")]
94pub struct UpdateProgress {
95    /// The number of operations that the update consists of.
96    pub n_ops: Option<u32>,
97    /// The position of the currently active operation.
98    pub op: Option<u32>,
99    /// The progress of the currently active operation, as a number between 0
100    /// and 100.
101    pub progress: Option<u32>,
102    /// The overall status of the update.
103    pub status: Option<UpdateStatus>,
104    /// The error name, sent when status is `UpdateStatus::Failed`.
105    pub error: Option<String>,
106    /// The error message, sent when status is `UpdateStatus::Failed`.
107    pub error_message: Option<String>,
108}
109
110/// The interface exposes some interactions with Flatpak on the host to the
111/// sandbox. For example, it allows you to restart the applications or start a
112/// more sandboxed instance.
113///
114/// Wrapper of the DBus interface: [`org.freedesktop.portal.Flatpak.UpdateMonitor`](https://docs.flatpak.org/en/latest/portal-api-reference.html#gdbus-org.freedesktop.portal.Flatpak.UpdateMonitor).
115#[derive(Debug)]
116#[doc(alias = "org.freedesktop.portal.Flatpak.UpdateMonitor")]
117pub struct UpdateMonitor<'a>(Proxy<'a>);
118
119impl<'a> UpdateMonitor<'a> {
120    /// Create a new instance of [`UpdateMonitor`].
121    ///
122    /// **Note** A [`UpdateMonitor`] is not supposed to be created
123    /// manually.
124    pub(crate) async fn new(path: ObjectPath<'a>) -> Result<UpdateMonitor<'a>, Error> {
125        let proxy =
126            Proxy::new_flatpak_with_path("org.freedesktop.portal.Flatpak.UpdateMonitor", path)
127                .await?;
128        Ok(Self(proxy))
129    }
130
131    /// A signal received when there's progress during the application update.
132    ///
133    /// # Specifications
134    ///
135    /// See also [`Progress`](https://docs.flatpak.org/en/latest/portal-api-reference.html#gdbus-signal-org-freedesktop-portal-Flatpak-UpdateMonitor.Progress).
136    #[doc(alias = "Progress")]
137    #[doc(alias = "XdpPortal::update-progress")]
138    pub async fn receive_progress(&self) -> Result<impl Stream<Item = UpdateProgress>, Error> {
139        self.0.signal("Progress").await
140    }
141
142    /// A signal received when there's an application update.
143    ///
144    /// # Specifications
145    ///
146    /// See also [`UpdateAvailable`](https://docs.flatpak.org/en/latest/portal-api-reference.html#gdbus-signal-org-freedesktop-portal-Flatpak-UpdateMonitor.UpdateAvailable).
147    #[doc(alias = "UpdateAvailable")]
148    #[doc(alias = "XdpPortal::update-available")]
149    pub async fn receive_update_available(&self) -> Result<impl Stream<Item = UpdateInfo>, Error> {
150        self.0.signal("UpdateAvailable").await
151    }
152
153    /// Asks to install an update of the calling app.
154    ///
155    /// **Note** updates are only allowed if the new version has the same
156    /// permissions (or less) than the currently installed version.
157    ///
158    /// # Specifications
159    ///
160    /// See also [`Update`](https://docs.flatpak.org/en/latest/portal-api-reference.html#gdbus-method-org-freedesktop-portal-Flatpak-UpdateMonitor.Update).
161    #[doc(alias = "Update")]
162    #[doc(alias = "xdp_portal_update_install")]
163    pub async fn update(&self, identifier: Option<&WindowIdentifier>) -> Result<(), Error> {
164        let options = UpdateOptions::default();
165        let identifier = identifier.map(|i| i.to_string()).unwrap_or_default();
166
167        self.0.call("Update", &(&identifier, options)).await
168    }
169
170    /// Ends the update monitoring and cancels any ongoing installation.
171    ///
172    /// # Specifications
173    ///
174    /// See also [`Close`](https://docs.flatpak.org/en/latest/portal-api-reference.html#gdbus-method-org-freedesktop-portal-Flatpak-UpdateMonitor.Close).
175    #[doc(alias = "Close")]
176    pub async fn close(&self) -> Result<(), Error> {
177        self.0.call("Close", &()).await
178    }
179}
180
181impl<'a> std::ops::Deref for UpdateMonitor<'a> {
182    type Target = zbus::Proxy<'a>;
183
184    fn deref(&self) -> &Self::Target {
185        &self.0
186    }
187}