diff --git a/com.steampowered.SteamOSManager1.xml b/com.steampowered.SteamOSManager1.xml
index d34a7dc..1c2b1d1 100644
--- a/com.steampowered.SteamOSManager1.xml
+++ b/com.steampowered.SteamOSManager1.xml
@@ -405,4 +405,12 @@
+
+
+
+
+
+
+
+
diff --git a/src/job.rs b/src/job.rs
index ad07219..0ab3586 100644
--- a/src/job.rs
+++ b/src/job.rs
@@ -15,16 +15,17 @@ use std::os::unix::process::ExitStatusExt;
use std::process::ExitStatus;
use tokio::process::{Child, Command};
use tracing::error;
-use zbus::{fdo, interface, zvariant, Connection};
+use zbus::{fdo, interface, zvariant, Connection, InterfaceRef, SignalContext};
use crate::error::to_zbus_fdo_error;
-const JOB_PREFIX: &str = "/com/steampowered/SteamOSManager1/Job";
+const JOB_PREFIX: &str = "/com/steampowered/SteamOSManager1/Jobs";
pub struct JobManager {
// This object manages exported jobs. It spawns processes, numbers them, and
// keeps a handle to the zbus connection to expose the name over the bus.
connection: Connection,
+ jm_iface: InterfaceRef,
next_job: u32,
}
@@ -34,12 +35,23 @@ struct Job {
exit_code: Option,
}
+struct JobManagerInterface {}
+
impl JobManager {
- pub fn new(conn: Connection) -> JobManager {
- JobManager {
- connection: conn,
+ pub async fn new(connection: Connection) -> Result {
+ let jm_iface = JobManagerInterface {};
+ let jm_iface: InterfaceRef = {
+ // This object needs to be dropped to appease the borrow checker
+ let object_server = connection.object_server();
+ object_server.at(JOB_PREFIX, jm_iface).await?;
+
+ object_server.interface(JOB_PREFIX).await?
+ };
+ Ok(JobManager {
+ connection,
+ jm_iface,
next_job: 0,
- }
+ })
}
pub async fn run_process(
@@ -49,7 +61,7 @@ impl JobManager {
operation_name: &str,
) -> fdo::Result {
// Run the given executable and give back an object path
- let path = format!("{}{}", JOB_PREFIX, self.next_job);
+ let path = format!("{}/{}", JOB_PREFIX, self.next_job);
self.next_job += 1;
let job = Job::spawn(executable, args)
.await
@@ -59,10 +71,23 @@ impl JobManager {
.object_server()
.at(path.as_str(), job)
.await?;
- zvariant::OwnedObjectPath::try_from(path).map_err(to_zbus_fdo_error)
+
+ let object_path = zvariant::OwnedObjectPath::try_from(path).map_err(to_zbus_fdo_error)?;
+ JobManagerInterface::job_started(self.jm_iface.signal_context(), object_path.as_ref())
+ .await?;
+ Ok(object_path)
}
}
+#[interface(name = "com.steampowered.SteamOSManager1.JobManager")]
+impl JobManagerInterface {
+ #[zbus(signal)]
+ async fn job_started(
+ signal_ctxt: &SignalContext<'_>,
+ job: zvariant::ObjectPath<'_>,
+ ) -> zbus::Result<()>;
+}
+
impl Job {
async fn spawn(executable: &str, args: &[impl AsRef]) -> Result {
let child = Command::new(executable).args(args).spawn()?;
@@ -176,8 +201,55 @@ impl Job {
#[cfg(test)]
pub(crate) mod test {
use super::*;
+ use crate::proxy::JobManagerProxy;
use crate::testing;
+ use anyhow::anyhow;
use nix::sys::signal::Signal;
+ use tokio::sync::oneshot;
+ use tokio_stream::StreamExt;
+ use zbus::ConnectionBuilder;
+
+ #[tokio::test]
+ async fn test_job_emitted() {
+ let _h = testing::start();
+
+ let connection = ConnectionBuilder::session()
+ .expect("session")
+ .build()
+ .await
+ .expect("connection");
+ let sender = connection.unique_name().unwrap().to_owned();
+ let mut pm = JobManager::new(connection).await.expect("pm");
+
+ let (tx, rx) = oneshot::channel::<()>();
+
+ let job = tokio::spawn(async move {
+ let connection = ConnectionBuilder::session()?.build().await?;
+ let jm = JobManagerProxy::builder(&connection)
+ .destination(sender)?
+ .build()
+ .await?;
+ let mut spawned = jm.receive_job_started().await?;
+ let next = spawned.next();
+ let _ = tx.send(());
+
+ next.await.ok_or(anyhow!("nothing"))
+ });
+
+ rx.await.expect("rx");
+
+ let object = pm
+ .run_process("/usr/bin/true", &[] as &[&OsStr], "")
+ .await
+ .expect("path");
+ assert_eq!(object.as_ref(), "/com/steampowered/SteamOSManager1/Jobs/0");
+
+ let job = job.await.expect("job");
+ let job = job.expect("job2");
+ let path = job.args().expect("args").job;
+
+ assert_eq!(object.as_ref(), path);
+ }
#[tokio::test]
async fn test_job_manager() {
diff --git a/src/manager/root.rs b/src/manager/root.rs
index f7cb5c8..b6804c4 100644
--- a/src/manager/root.rs
+++ b/src/manager/root.rs
@@ -55,7 +55,7 @@ impl SteamOSManager {
fan_control: FanControl::new(connection.clone()),
wifi_debug_mode: WifiDebugMode::Off,
should_trace: variant().await? == HardwareVariant::Galileo,
- job_manager: JobManager::new(connection.clone()),
+ job_manager: JobManager::new(connection.clone()).await?,
connection,
channel,
})
diff --git a/src/proxy.rs b/src/proxy.rs
index 9895c2f..5698269 100644
--- a/src/proxy.rs
+++ b/src/proxy.rs
@@ -176,3 +176,14 @@ trait Job {
/// Wait method
fn wait(&self) -> zbus::Result;
}
+
+#[proxy(
+ default_service = "com.steampowered.SteamOSManager1",
+ default_path = "/com/steampowered/SteamOSManager1/Jobs",
+ interface = "com.steampowered.SteamOSManager1.JobManager"
+)]
+trait JobManager {
+ /// JobStarted signal
+ #[zbus(signal)]
+ fn job_started(&self, job: zbus::zvariant::ObjectPath<'_>) -> zbus::Result<()>;
+}