Skip to content

Commit

Permalink
Add versioned methods (#163)
Browse files Browse the repository at this point in the history
We throw an error on our side when an interface is called from our side
with the wrong version.

Co-authored-by: Bilal Elmoussaoui <[email protected]>
  • Loading branch information
A6GibKm and bilelmoussaoui authored Oct 7, 2023
1 parent 1395bf2 commit 35cb22d
Show file tree
Hide file tree
Showing 8 changed files with 77 additions and 19 deletions.
3 changes: 2 additions & 1 deletion src/desktop/background.rs
Original file line number Diff line number Diff line change
Expand Up @@ -110,11 +110,12 @@ impl<'a> BackgroundProxy<'a> {
pub async fn set_status(&self, message: &str) -> Result<(), Error> {
self.0
.call(
.call_versioned(
"SetStatus",
&(SetStatusOptions {
message: message.to_owned(),
}),
2,
)
.await
}
Expand Down
12 changes: 7 additions & 5 deletions src/desktop/network_monitor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,9 @@ impl<'a> NetworkMonitor<'a> {
/// See also [`CanReach`](https://flatpak.github.io/xdg-desktop-portal/index.html#gdbus-method-org-freedesktop-portal-NetworkMonitor.CanReach).
#[doc(alias = "CanReach")]
pub async fn can_reach(&self, hostname: &str, port: u32) -> Result<bool, Error> {
self.0.call("CanReach", &(hostname, port)).await
self.0
.call_versioned("CanReach", &(hostname, port), 3)
.await
}

/// Returns whether the network is considered available.
Expand All @@ -123,7 +125,7 @@ impl<'a> NetworkMonitor<'a> {
#[doc(alias = "GetAvailable")]
#[doc(alias = "get_available")]
pub async fn is_available(&self) -> Result<bool, Error> {
self.0.call("GetAvailable", &()).await
self.0.call_versioned("GetAvailable", &(), 2).await
}

/// Returns more detailed information about the host's network connectivity.
Expand All @@ -134,7 +136,7 @@ impl<'a> NetworkMonitor<'a> {
#[doc(alias = "GetConnectivity")]
#[doc(alias = "get_connectivity")]
pub async fn connectivity(&self) -> Result<Connectivity, Error> {
self.0.call("GetConnectivity", &()).await
self.0.call_versioned("GetConnectivity", &(), 2).await
}

/// Returns whether the network is considered metered.
Expand All @@ -147,7 +149,7 @@ impl<'a> NetworkMonitor<'a> {
#[doc(alias = "GetMetered")]
#[doc(alias = "get_metered")]
pub async fn is_metered(&self) -> Result<bool, Error> {
self.0.call("GetMetered", &()).await
self.0.call_versioned("GetMetered", &(), 2).await
}

/// Returns the three values all at once.
Expand All @@ -158,7 +160,7 @@ impl<'a> NetworkMonitor<'a> {
#[doc(alias = "GetStatus")]
#[doc(alias = "get_status")]
pub async fn status(&self) -> Result<NetworkStatus, Error> {
self.0.call("GetStatus", &()).await
self.0.call_versioned("GetStatus", &(), 3).await
}

/// Emitted when the network configuration changes.
Expand Down
2 changes: 1 addition & 1 deletion src/desktop/remote_desktop.rs
Original file line number Diff line number Diff line change
Expand Up @@ -632,7 +632,7 @@ impl<'a> RemoteDesktop<'a> {
let options: HashMap<&str, Value<'_>> = HashMap::new();
let fd = self
.0
.call::<OwnedFd>("ConnectToEIS", &(session, options))
.call_versioned::<OwnedFd>("ConnectToEIS", &(session, options), 2)
.await?;
Ok(fd.into_raw_fd())
}
Expand Down
2 changes: 1 addition & 1 deletion src/desktop/screencast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -424,7 +424,7 @@ impl<'a> Screencast<'a> {
/// See also [`AvailableCursorModes`](https://flatpak.github.io/xdg-desktop-portal/index.html#gdbus-property-org-freedesktop-portal-ScreenCast.AvailableCursorModes).
#[doc(alias = "AvailableCursorModes")]
pub async fn available_cursor_modes(&self) -> Result<BitFlags<CursorMode>, Error> {
self.0.property("AvailableCursorModes").await
self.0.property_versioned("AvailableCursorModes", 2).await
}

/// Available source types.
Expand Down
5 changes: 3 additions & 2 deletions src/documents/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -220,7 +220,7 @@ impl<'a> Documents<'a> {
let o_path: Vec<Fd> = o_path_fds.iter().map(|f| Fd::from(f.as_raw_fd())).collect();
let app_id = app_id.as_deref().unwrap_or("");
self.0
.call("AddFull", &(o_path, flags, app_id, permissions))
.call_versioned("AddFull", &(o_path, flags, app_id, permissions), 2)
.await
}

Expand Down Expand Up @@ -295,7 +295,7 @@ impl<'a> Documents<'a> {
let app_id = app_id.as_deref().unwrap_or("");
let filename = FilePath::new(filename)?;
self.0
.call(
.call_versioned(
"AddNamedFull",
&(
Fd::from(o_path_fd.as_raw_fd()),
Expand All @@ -304,6 +304,7 @@ impl<'a> Documents<'a> {
app_id,
permissions,
),
3,
)
.await
}
Expand Down
8 changes: 8 additions & 0 deletions src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,11 @@ pub enum Error {
InvalidAppID,
/// An error indicating that an interior nul byte was found
NulTerminated(usize),
/// Requires a newer interface version.
///
/// The inner fields are the required version and the version advertised by
/// the interface.
RequiresVersion(u32, u32),
/// An error indicating that a Icon::Bytes was expected but wrong type was
/// passed
UnexpectedIcon,
Expand All @@ -73,6 +78,9 @@ impl std::fmt::Display for Error {
Self::ParseError(e) => f.write_str(e),
Self::InvalidAppID => f.write_str("Invalid app id"),
Self::NulTerminated(u) => write!(f, "Nul byte found in provided data at position {u}"),
Self::RequiresVersion(required, current) => write!(

Check failure on line 81 in src/error.rs

View workflow job for this annotation

GitHub Actions / Rustfmt

mismatched closing delimiter: `}`

Check failure on line 81 in src/error.rs

View workflow job for this annotation

GitHub Actions / build-deploy

mismatched closing delimiter: `}`

Check failure on line 81 in src/error.rs

View workflow job for this annotation

GitHub Actions / Test Suite

mismatched closing delimiter: `}`

Check failure on line 81 in src/error.rs

View workflow job for this annotation

GitHub Actions / Clippy

mismatched closing delimiter: `}`

Check failure on line 81 in src/error.rs

View workflow job for this annotation

GitHub Actions / Check

mismatched closing delimiter: `}`
f,
"This interface requires version {required}, but {current} is available"
Self::UnexpectedIcon => write!(
f,
"Expected icon of type Icon::Bytes but a different type was used."
Expand Down
6 changes: 4 additions & 2 deletions src/flatpak/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -265,7 +265,7 @@ impl<'a> Flatpak<'a> {
let options = CreateMonitorOptions::default();
let path = self
.0
.call::<OwnedObjectPath>("CreateUpdateMonitor", &(options))
.call_versioned::<OwnedObjectPath>("CreateUpdateMonitor", &(options), 2)
.await?;

UpdateMonitor::new(path.into_inner()).await
Expand Down Expand Up @@ -362,7 +362,9 @@ impl<'a> Flatpak<'a> {
///
/// See also [`supports`](https://flatpak.github.io/xdg-desktop-portal/index.html#gdbus-property-org-freedesktop-portal-Flatpak.supports).
pub async fn supports(&self) -> Result<BitFlags<SupportsFlags>, Error> {
self.0.property::<BitFlags<SupportsFlags>>("supports").await
self.0
.property_versioned::<BitFlags<SupportsFlags>>("supports", 3)
.await
}
}

Expand Down
58 changes: 51 additions & 7 deletions src/proxy.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,10 @@ pub(crate) const FLATPAK_PATH: &str = "/org/freedesktop/portal/Flatpak";
static SESSION: OnceCell<zbus::Connection> = OnceCell::new();

#[derive(Debug)]
pub struct Proxy<'a>(zbus::Proxy<'a>);
pub struct Proxy<'a> {
inner: zbus::Proxy<'a>,
version: u32,
}

impl<'a> Proxy<'a> {
pub(crate) async fn connection() -> zbus::Result<zbus::Connection> {
Expand Down Expand Up @@ -58,13 +61,15 @@ impl<'a> Proxy<'a> {
P::Error: Into<zbus::Error>,
{
let connection = Self::connection().await?;
let proxy = zbus::ProxyBuilder::new_bare(&connection)
let inner: zbus::Proxy = zbus::ProxyBuilder::new_bare(&connection)
.interface(interface)?
.path(path)?
.destination(destination)?
.build()
.await?;
Ok(Self(proxy))
let version = inner.get_property::<u32>("version").await.unwrap_or(1);

Ok(Self { inner, version })
}

pub async fn new_desktop_with_path<P>(interface: &'a str, path: P) -> Result<Proxy<'a>, Error>
Expand Down Expand Up @@ -122,6 +127,11 @@ impl<'a> Proxy<'a> {
self.request(handle_token, method_name, body).await
}

/// Returns the version of the interface
pub fn version(&self) -> u32 {
self.version
}

pub(crate) async fn call<R>(
&self,
method_name: &'static str,
Expand All @@ -145,17 +155,51 @@ impl<'a> Proxy<'a> {
Ok(reply)
}

pub(crate) async fn call_versioned<R>(
&self,
method_name: &'static str,
body: impl Serialize + Type + Debug,
req_version: u32,
) -> Result<R, Error>
where
R: for<'de> Deserialize<'de> + Type,
{
let version = self.version();
if version >= req_version {
self.call::<R>(method_name, body).await
} else {
Err(Error::RequiresVersion(req_version, version))
}
}

pub async fn property<T>(&self, property_name: &'static str) -> Result<T, Error>
where
T: TryFrom<OwnedValue>,
zbus::Error: From<<T as TryFrom<OwnedValue>>::Error>,
{
self.0
self.inner
.get_property::<T>(property_name)
.await
.map_err(From::from)
}

pub(crate) async fn property_versioned<T>(
&self,
property_name: &'static str,
req_version: u32,
) -> Result<T, Error>
where
T: TryFrom<OwnedValue>,
zbus::Error: From<<T as TryFrom<OwnedValue>>::Error>,
{
let version = self.version();
if version >= req_version {
self.property::<T>(property_name).await
} else {
Err(Error::RequiresVersion(req_version, version))
}
}

pub(crate) async fn signal_with_args<I>(
&self,
name: &'static str,
Expand All @@ -165,7 +209,7 @@ impl<'a> Proxy<'a> {
I: for<'de> Deserialize<'de> + Type + Debug,
{
Ok(self
.0
.inner
.receive_signal_with_args(name, args)
.await?
.filter_map({
Expand All @@ -185,7 +229,7 @@ impl<'a> Proxy<'a> {
where
I: for<'de> Deserialize<'de> + Type + Debug,
{
Ok(self.0.receive_signal(name).await?.filter_map({
Ok(self.inner.receive_signal(name).await?.filter_map({
#[cfg(not(feature = "tracing"))]
{
move |msg| ready(msg.body().ok())
Expand Down Expand Up @@ -221,6 +265,6 @@ impl<'a> Deref for Proxy<'a> {
type Target = zbus::Proxy<'a>;

fn deref(&self) -> &Self::Target {
&self.0
&self.inner
}
}

0 comments on commit 35cb22d

Please sign in to comment.