Skip to content

Commit

Permalink
backend: Add a builder pattern for exporting dbus ifaces implementations
Browse files Browse the repository at this point in the history
Helps moving all the boilerplate internally, to simplify implementations, tests or demos.
Currently, by doing this, we hide the Interface struct so we can't no longer easily emit changed
signals, so we would need some other mechanism for doing that
  • Loading branch information
bilelmoussaoui committed Oct 27, 2024
1 parent fc3e5f6 commit 72446a6
Show file tree
Hide file tree
Showing 16 changed files with 301 additions and 111 deletions.
39 changes: 6 additions & 33 deletions backend-demo/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,41 +23,14 @@ async fn main() -> ashpd::Result<()> {
// Enable debug with `RUST_LOG=ashpd_backend_demo=debug COMMAND`.
tracing_subscriber::fmt::init();

let cnx = zbus::connection::Builder::session()?
.name(NAME)?
ashpd::backend::Builder::new(NAME)?
.account(Account)
.screenshot(Screenshot)
.secret(Secret)
.settings(Settings::default())
.wallpaper(Wallpaper)
.build()
.await?;
let object_server = cnx.object_server();

let portal = ashpd::backend::account::AccountInterface::new(Account, cnx.clone());
tracing::debug!("Serving interface `org.freedesktop.impl.portal.Account`");
object_server
.at("/org/freedesktop/portal/desktop", portal)
.await?;

let portal = ashpd::backend::screenshot::ScreenshotInterface::new(Screenshot, cnx.clone());
tracing::debug!("Serving interface `org.freedesktop.impl.portal.Screenshot`");
object_server
.at("/org/freedesktop/portal/desktop", portal)
.await?;

let portal = ashpd::backend::secret::SecretInterface::new(Secret, cnx.clone());
tracing::debug!("Serving interface `org.freedesktop.impl.portal.Secret`");
object_server
.at("/org/freedesktop/portal/desktop", portal)
.await?;

let portal = ashpd::backend::settings::SettingsInterface::new(Settings::default(), cnx.clone());
tracing::debug!("Serving interface `org.freedesktop.impl.portal.Settings`");
object_server
.at("/org/freedesktop/portal/desktop", portal)
.await?;

let portal = ashpd::backend::wallpaper::WallpaperInterface::new(Wallpaper, cnx.clone());
tracing::debug!("Serving interface `org.freedesktop.impl.portal.Wallpaper`");
object_server
.at("/org/freedesktop/portal/desktop", portal)
.await?;

loop {
pending::<()>().await;
Expand Down
9 changes: 3 additions & 6 deletions src/backend/access.rs
Original file line number Diff line number Diff line change
Expand Up @@ -74,17 +74,14 @@ pub trait AccessImpl: RequestImpl {
) -> Result<AccessResponse>;
}

pub struct AccessInterface {
pub(crate) struct AccessInterface {
imp: Arc<dyn AccessImpl>,
cnx: zbus::Connection,
}

impl AccessInterface {
pub fn new(imp: impl AccessImpl + 'static, cnx: zbus::Connection) -> Self {
Self {
imp: Arc::new(imp),
cnx,
}
pub fn new(imp: Arc<dyn AccessImpl>, cnx: zbus::Connection) -> Self {
Self { imp, cnx }
}
}

Expand Down
9 changes: 3 additions & 6 deletions src/backend/account.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,17 +34,14 @@ pub trait AccountImpl: RequestImpl {
) -> Result<UserInformation>;
}

pub struct AccountInterface {
pub(crate) struct AccountInterface {
imp: Arc<dyn AccountImpl>,
cnx: zbus::Connection,
}

impl AccountInterface {
pub fn new(imp: impl AccountImpl + 'static, cnx: zbus::Connection) -> Self {
Self {
imp: Arc::new(imp),
cnx,
}
pub fn new(imp: Arc<dyn AccountImpl>, cnx: zbus::Connection) -> Self {
Self { imp, cnx }
}
}

Expand Down
9 changes: 3 additions & 6 deletions src/backend/app_chooser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -92,17 +92,14 @@ pub trait AppChooserImpl: RequestImpl {
) -> Result<(), PortalError>;
}

pub struct AppChooserInterface {
pub(crate) struct AppChooserInterface {
imp: Arc<dyn AppChooserImpl>,
cnx: zbus::Connection,
}

impl AppChooserInterface {
pub fn new(imp: impl AppChooserImpl + 'static, cnx: zbus::Connection) -> Self {
Self {
imp: Arc::new(imp),
cnx,
}
pub fn new(imp: Arc<dyn AppChooserImpl>, cnx: zbus::Connection) -> Self {
Self { imp, cnx }
}
}

Expand Down
9 changes: 3 additions & 6 deletions src/backend/background.rs
Original file line number Diff line number Diff line change
Expand Up @@ -63,17 +63,14 @@ pub trait BackgroundImpl: RequestImpl {
) -> Result<bool, PortalError>;
}

pub struct BackgroundInterface {
pub(crate) struct BackgroundInterface {
imp: Arc<dyn BackgroundImpl>,
cnx: zbus::Connection,
}

impl BackgroundInterface {
pub fn new(imp: impl BackgroundImpl + 'static, cnx: zbus::Connection) -> Self {
Self {
imp: Arc::new(imp),
cnx,
}
pub fn new(imp: Arc<dyn BackgroundImpl>, cnx: zbus::Connection) -> Self {
Self { imp, cnx }
}

pub async fn changed(&self) -> zbus::Result<()> {

Check warning on line 76 in src/backend/background.rs

View workflow job for this annotation

GitHub Actions / Check

method `changed` is never used

Check warning on line 76 in src/backend/background.rs

View workflow job for this annotation

GitHub Actions / Clippy

method `changed` is never used

Check warning on line 76 in src/backend/background.rs

View workflow job for this annotation

GitHub Actions / Test Suite

method `changed` is never used

Check failure on line 76 in src/backend/background.rs

View workflow job for this annotation

GitHub Actions / Clippy

method `changed` is never used

Check warning on line 76 in src/backend/background.rs

View workflow job for this annotation

GitHub Actions / Check

method `changed` is never used

Check warning on line 76 in src/backend/background.rs

View workflow job for this annotation

GitHub Actions / Test Suite

method `changed` is never used
Expand Down
254 changes: 254 additions & 0 deletions src/backend/builder.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,254 @@
use std::sync::Arc;

use zbus::names::{OwnedWellKnownName, WellKnownName};

use crate::backend::{
access::{AccessImpl, AccessInterface},
account::{AccountImpl, AccountInterface},
app_chooser::{AppChooserImpl, AppChooserInterface},
background::{BackgroundImpl, BackgroundInterface},
email::{EmailImpl, EmailInterface},
file_chooser::{FileChooserImpl, FileChooserInterface},
lockdown::{LockdownImpl, LockdownInterface},
permission_store::{PermissionStoreImpl, PermissionStoreInterface},
print::{PrintImpl, PrintInterface},
screenshot::{ScreenshotImpl, ScreenshotInterface},
secret::{SecretImpl, SecretInterface},
settings::{SettingsImpl, SettingsInterface},
wallpaper::{WallpaperImpl, WallpaperInterface},
Result,
};

pub struct Builder {
name: OwnedWellKnownName,
account_impl: Option<Arc<dyn AccountImpl>>,
access_impl: Option<Arc<dyn AccessImpl>>,
app_chooser_impl: Option<Arc<dyn AppChooserImpl>>,
background_impl: Option<Arc<dyn BackgroundImpl>>,
email_impl: Option<Arc<dyn EmailImpl>>,
file_chooser_impl: Option<Arc<dyn FileChooserImpl>>,
lockdown_impl: Option<Arc<dyn LockdownImpl>>,
permission_store_impl: Option<Arc<dyn PermissionStoreImpl>>,
print_impl: Option<Arc<dyn PrintImpl>>,
screenshot_impl: Option<Arc<dyn ScreenshotImpl>>,
secret_impl: Option<Arc<dyn SecretImpl>>,
settings_impl: Option<Arc<dyn SettingsImpl>>,
wallpaper_impl: Option<Arc<dyn WallpaperImpl>>,
}

impl Builder {
pub fn new<'a, W>(well_known_name: W) -> zbus::Result<Self>
where
W: TryInto<WellKnownName<'a>>,
<W as TryInto<WellKnownName<'a>>>::Error: Into<zbus::Error>,
{
let well_known_name = well_known_name.try_into().map_err(Into::into)?;
Ok(Self {
name: well_known_name.into(),
account_impl: None,
access_impl: None,
app_chooser_impl: None,
background_impl: None,
email_impl: None,
file_chooser_impl: None,
lockdown_impl: None,
permission_store_impl: None,
print_impl: None,
screenshot_impl: None,
secret_impl: None,
settings_impl: None,
wallpaper_impl: None,
})
}

pub fn account(mut self, imp: impl AccountImpl + 'static) -> Self {
self.account_impl = Some(Arc::new(imp));
self
}

pub fn access(mut self, imp: impl AccessImpl + 'static) -> Self {
self.access_impl = Some(Arc::new(imp));
self
}

pub fn app_chooser(mut self, imp: impl AppChooserImpl + 'static) -> Self {
self.app_chooser_impl = Some(Arc::new(imp));
self
}

pub fn background(mut self, imp: impl BackgroundImpl + 'static) -> Self {
self.background_impl = Some(Arc::new(imp));
self
}

pub fn email(mut self, imp: impl EmailImpl + 'static) -> Self {
self.email_impl = Some(Arc::new(imp));
self
}

pub fn file_chooser(mut self, imp: impl FileChooserImpl + 'static) -> Self {
self.file_chooser_impl = Some(Arc::new(imp));
self
}

pub fn lockdown(mut self, imp: impl LockdownImpl + 'static) -> Self {
self.lockdown_impl = Some(Arc::new(imp));
self
}

pub fn permission_store(mut self, imp: impl PermissionStoreImpl + 'static) -> Self {
self.permission_store_impl = Some(Arc::new(imp));
self
}

pub fn print(mut self, imp: impl PrintImpl + 'static) -> Self {
self.print_impl = Some(Arc::new(imp));
self
}

pub fn screenshot(mut self, imp: impl ScreenshotImpl + 'static) -> Self {
self.screenshot_impl = Some(Arc::new(imp));
self
}

pub fn secret(mut self, imp: impl SecretImpl + 'static) -> Self {
self.secret_impl = Some(Arc::new(imp));
self
}

pub fn settings(mut self, imp: impl SettingsImpl + 'static) -> Self {
self.settings_impl = Some(Arc::new(imp));
self
}

pub fn wallpaper(mut self, imp: impl WallpaperImpl + 'static) -> Self {
self.wallpaper_impl = Some(Arc::new(imp));
self
}

pub async fn build(self) -> Result<()> {
let cnx = zbus::connection::Builder::session()?
.name(self.name)?
.build()
.await?;
let object_server = cnx.object_server();
if let Some(imp) = self.account_impl {
let portal = AccountInterface::new(imp, cnx.clone());
#[cfg(feature = "tracing")]
tracing::debug!("Serving interface `org.freedesktop.impl.portal.Account`");
object_server
.at("/org/freedesktop/portal/desktop", portal)
.await?;
}

if let Some(imp) = self.access_impl {
let portal = AccessInterface::new(imp, cnx.clone());
#[cfg(feature = "tracing")]
tracing::debug!("Serving interface `org.freedesktop.impl.portal.Access`");
object_server
.at("/org/freedesktop/portal/desktop", portal)
.await?;
}

if let Some(imp) = self.app_chooser_impl {
let portal = AppChooserInterface::new(imp, cnx.clone());
#[cfg(feature = "tracing")]
tracing::debug!("Serving interface `org.freedesktop.impl.portal.AppChooser`");
object_server
.at("/org/freedesktop/portal/desktop", portal)
.await?;
}

if let Some(imp) = self.background_impl {
let portal = BackgroundInterface::new(imp, cnx.clone());
#[cfg(feature = "tracing")]
tracing::debug!("Serving interface `org.freedesktop.impl.portal.Background`");
object_server
.at("/org/freedesktop/portal/desktop", portal)
.await?;
}

if let Some(imp) = self.email_impl {
let portal = EmailInterface::new(imp, cnx.clone());
#[cfg(feature = "tracing")]
tracing::debug!("Serving interface `org.freedesktop.impl.portal.Email`");
object_server
.at("/org/freedesktop/portal/desktop", portal)
.await?;
}

if let Some(imp) = self.file_chooser_impl {
let portal = FileChooserInterface::new(imp, cnx.clone());
#[cfg(feature = "tracing")]
tracing::debug!("Serving interface `org.freedesktop.impl.portal.FileChooser`");
object_server
.at("/org/freedesktop/portal/desktop", portal)
.await?;
}

if let Some(imp) = self.lockdown_impl {
let portal = LockdownInterface::new(imp, cnx.clone());
#[cfg(feature = "tracing")]
tracing::debug!("Serving interface `org.freedesktop.impl.portal.Lockdown`");
object_server
.at("/org/freedesktop/portal/desktop", portal)
.await?;
}

if let Some(imp) = self.permission_store_impl {
let portal = PermissionStoreInterface::new(imp, cnx.clone());
#[cfg(feature = "tracing")]
tracing::debug!("Serving interface `org.freedesktop.impl.portal.PermissionStore`");
object_server
.at("/org/freedesktop/portal/desktop", portal)
.await?;
}

if let Some(imp) = self.print_impl {
let portal = PrintInterface::new(imp, cnx.clone());
#[cfg(feature = "tracing")]
tracing::debug!("Serving interface `org.freedesktop.impl.portal.Print`");
object_server
.at("/org/freedesktop/portal/desktop", portal)
.await?;
}

if let Some(imp) = self.screenshot_impl {
let portal = ScreenshotInterface::new(imp, cnx.clone());
#[cfg(feature = "tracing")]
tracing::debug!("Serving interface `org.freedesktop.impl.portal.Screenshot`");
object_server
.at("/org/freedesktop/portal/desktop", portal)
.await?;
}

if let Some(imp) = self.secret_impl {
let portal = SecretInterface::new(imp, cnx.clone());
#[cfg(feature = "tracing")]
tracing::debug!("Serving interface `org.freedesktop.impl.portal.Secret`");
object_server
.at("/org/freedesktop/portal/desktop", portal)
.await?;
}

if let Some(imp) = self.settings_impl {
let portal = SettingsInterface::new(imp, cnx.clone());
#[cfg(feature = "tracing")]
tracing::debug!("Serving interface `org.freedesktop.impl.portal.Settings`");
object_server
.at("/org/freedesktop/portal/desktop", portal)
.await?;
}

if let Some(imp) = self.wallpaper_impl {
let portal = WallpaperInterface::new(imp, cnx.clone());
#[cfg(feature = "tracing")]
tracing::debug!("Serving interface `org.freedesktop.impl.portal.Wallpaper`");
object_server
.at("/org/freedesktop/portal/desktop", portal)
.await?;
}

Ok(())
}
}
Loading

0 comments on commit 72446a6

Please sign in to comment.