Skip to content

Commit

Permalink
feat(power): implement periodic update for connected devices
Browse files Browse the repository at this point in the history
  • Loading branch information
uvera authored Feb 12, 2025
1 parent 442589f commit c76fd47
Show file tree
Hide file tree
Showing 4 changed files with 118 additions and 3 deletions.
11 changes: 11 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions cosmic-settings/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ rustix = "0.38.41"
gettext-rs = { version = "0.7.2", features = [
"gettext-system",
], optional = true }
async-fn-stream = "0.2.2"

[dependencies.cosmic-settings-subscriptions]
git = "https://github.com/pop-os/cosmic-settings-subscriptions"
Expand Down
54 changes: 51 additions & 3 deletions cosmic-settings/src/pages/power/backend/mod.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
use chrono::{Duration, TimeDelta};
use futures::future::join_all;
use futures::FutureExt;
use futures::{future::join_all, FutureExt, Stream, StreamExt};
use upower_dbus::{BatteryState, BatteryType, DeviceProxy};
use zbus::Connection;
use zbus::{zvariant::ObjectPath, Connection};

mod ppdaemon;
mod s76powerdaemon;
Expand Down Expand Up @@ -239,6 +238,7 @@ pub struct ConnectedDevice {
pub model: String,
pub device_icon: &'static str,
pub battery: Battery,
pub device_path: String,
}

async fn get_device_proxy<'a>() -> Result<upower_dbus::DeviceProxy<'a>, zbus::Error> {
Expand Down Expand Up @@ -406,6 +406,7 @@ impl Battery {
impl ConnectedDevice {
async fn from_device_maybe(proxy: DeviceProxy<'_>) -> Option<Self> {
let device_type = proxy.type_().await.unwrap_or(BatteryType::Unknown);
let device_path = proxy.clone().into_inner().path().to_string();
if matches!(
device_type,
BatteryType::Unknown | BatteryType::LinePower | BatteryType::Battery
Expand Down Expand Up @@ -445,9 +446,56 @@ impl ConnectedDevice {
model,
device_icon,
battery,
device_path,
})
}

pub async fn device_removed_stream(
connection: &'_ Connection,
) -> Result<impl Stream<Item = String> + '_, zbus::Error> {
let proxy = upower_dbus::UPowerProxy::new(connection).await?;
let stream = proxy.receive_device_removed().await?;

let transformed_stream = stream.filter_map(move |device_removed| async move {
let device_path: ObjectPath<'static> = match device_removed.args() {
Ok(args) => args.device().to_owned(),
Err(e) => {
tracing::error!("Failed to get DeviceRemoved arguments: {e}");
return None;
}
};
Some(device_path.to_string())
});

Ok(transformed_stream)
}

pub async fn device_added_stream(
connection: &'_ Connection,
) -> Result<impl futures::Stream<Item = ConnectedDevice> + '_, zbus::Error> {
let proxy = upower_dbus::UPowerProxy::new(connection).await?;
let stream = proxy.receive_device_added().await?;

let transformed_stream = stream.filter_map(move |device_added| async move {
let device_path: ObjectPath<'static> = match device_added.args() {
Ok(args) => args.device().to_owned(),
Err(e) => {
tracing::error!("Failed to get DeviceAdded arguments: {e}");
return None;
}
};
match DeviceProxy::new(connection, &device_path).await {
Ok(device) => ConnectedDevice::from_device_maybe(device).await,
Err(e) => {
tracing::error!("Failed to create DeviceProxy from {device_path}: {e}");
None
}
}
});

Ok(transformed_stream)
}

pub async fn update_connected_devices() -> Vec<Self> {
let proxy = enumerate_devices().await;

Expand Down
55 changes: 55 additions & 0 deletions cosmic-settings/src/pages/power/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ use cosmic::Task;
use cosmic_config::{Config, CosmicConfigEntry};
use cosmic_idle_config::CosmicIdleConfig;
use cosmic_settings_page::{self as page, section, Section};
use futures::StreamExt;
use itertools::Itertools;
use slab::Slab;
use slotmap::SlotMap;
Expand Down Expand Up @@ -123,6 +124,52 @@ impl page::Page<crate::pages::Message> for Page {
let devices = ConnectedDevice::update_connected_devices().await;
Message::UpdateConnectedDevices(devices)
}),
cosmic::Task::run(
async_fn_stream::fn_stream(|emitter| async move {
let span = tracing::span!(tracing::Level::INFO, "power::device_stream task");
let _span_handle = span.enter();

let Ok(connection) = zbus::Connection::system().await else {
tracing::error!("could not established zbus connection to system");
return;
};

let added_stream = ConnectedDevice::device_added_stream(&connection).await;
let removed_stream = ConnectedDevice::device_removed_stream(&connection).await;

let added_future = async {
match added_stream {
Ok(stream) => {
futures::pin_mut!(stream);
while let Some(device) = stream.next().await {
tracing::info!(device = device.model, "device added");
emitter.emit(Message::DeviceConnect(device)).await;
}
}
Err(err) => tracing::error!(?err, "cannot establish added stream"),
}
};

let removed_future = async {
match removed_stream {
Ok(stream) => {
futures::pin_mut!(stream);
while let Some(device_path) = stream.next().await {
tracing::info!(device_path, "device removed");
emitter.emit(Message::DeviceDisconnect(device_path)).await;
}
}
Err(err) => tracing::error!(?err, "cannot establish removed stream"),
}
};

futures::pin_mut!(added_future);
futures::pin_mut!(removed_future);

futures::future::select(added_future, removed_future).await;
}),
|msg| msg,
),
];

let (task, handle) = cosmic::Task::batch(futures)
Expand All @@ -147,6 +194,8 @@ pub enum Message {
PowerProfileChange(PowerProfile),
UpdateBattery(Battery),
UpdateConnectedDevices(Vec<ConnectedDevice>),
DeviceDisconnect(String),
DeviceConnect(ConnectedDevice),
ScreenOffTimeChange(Option<Duration>),
SuspendOnAcTimeChange(Option<Duration>),
SuspendOnBatteryTimeChange(Option<Duration>),
Expand Down Expand Up @@ -192,6 +241,12 @@ impl Page {
tracing::error!("failed to set suspend on battery time: {}", err)
}
}
Message::DeviceDisconnect(device_path) => self
.connected_devices
.retain(|device| device.device_path != device_path),
Message::DeviceConnect(connected_device) => {
self.connected_devices.push(connected_device)
}
};
}
}
Expand Down

0 comments on commit c76fd47

Please sign in to comment.