cosmic-applets/cosmic-applet-status-area/src/subscriptions/status_notifier_watcher/client.rs
2024-05-18 01:38:41 +02:00

75 lines
2.6 KiB
Rust

// Copyright 2023 System76 <info@system76.com>
// SPDX-License-Identifier: GPL-3.0-only
use futures::{Stream, StreamExt};
use std::pin::Pin;
use super::Event;
use crate::subscriptions::status_notifier_item::StatusNotifierItem;
// TODO: Don't use trait object
pub type EventStream = Pin<Box<dyn Stream<Item = Event> + Send>>;
#[zbus::proxy(
interface = "org.kde.StatusNotifierWatcher",
default_service = "org.kde.StatusNotifierWatcher",
default_path = "/StatusNotifierWatcher"
)]
trait StatusNotifierWatcher {
fn register_status_notifier_host(&self, name: &str) -> zbus::Result<()>;
#[zbus(property)]
fn registered_status_notifier_items(&self) -> zbus::Result<Vec<String>>;
#[zbus(signal)]
fn status_notifier_item_registered(&self, name: &str) -> zbus::Result<()>;
#[zbus(signal)]
fn status_notifier_item_unregistered(&self, name: &str) -> zbus::Result<()>;
}
pub async fn watch(connection: &zbus::Connection) -> zbus::Result<EventStream> {
let watcher = StatusNotifierWatcherProxy::new(connection).await?;
let name = connection.unique_name().unwrap().as_str();
if let Err(err) = watcher.register_status_notifier_host(name).await {
eprintln!("Failed to register status notifier host: {}", err);
}
let connection_clone = connection.clone();
let registered_stream = watcher
.receive_status_notifier_item_registered()
.await?
.then(move |evt| Box::pin(item_registered(connection_clone.clone(), evt)));
let unregistered_stream = watcher
.receive_status_notifier_item_unregistered()
.await?
.map(|evt| match evt.args() {
Ok(args) => Event::Unregistered(args.name.to_string()),
Err(err) => Event::Error(err.to_string()),
});
let items = watcher.registered_status_notifier_items().await?;
let connection = connection.clone();
let items_stream = futures::stream::iter(items.into_iter())
.then(move |name| status_notifier_item(connection.clone(), name));
Ok(Box::pin(items_stream.chain(futures::stream_select!(
registered_stream,
unregistered_stream
))))
}
async fn item_registered(connection: zbus::Connection, evt: StatusNotifierItemRegistered) -> Event {
match evt.args() {
Ok(args) => status_notifier_item(connection, args.name.to_string()).await,
Err(err) => Event::Error(err.to_string()),
}
}
async fn status_notifier_item(connection: zbus::Connection, name: String) -> Event {
match StatusNotifierItem::new(&connection, name).await {
Ok(item) => Event::Registered(item),
Err(err) => Event::Error(err.to_string()),
}
}