use crate::{
SystemdTransientManager, UnitExit,
dbus::unit::UnitProxy,
error::SystemdTransientError,
watch::{ExitWatch, WatchState},
};
#[derive(Debug)]
pub struct TransientUnitHandle {
pub(crate) name: String,
pub(crate) manager: SystemdTransientManager,
pub(crate) unit: UnitProxy<'static>,
pub(crate) invocation_id: Vec<u8>,
pub(crate) watch: ExitWatch,
pub(crate) released: bool,
}
impl TransientUnitHandle {
pub async fn stop(&self) -> Result<UnitExit, SystemdTransientError> {
if let WatchState::Exited(exit) = self.watch.current() {
return Ok(exit);
}
if self.unit.invocation_id().await? != self.invocation_id {
return match self.watch.current() {
WatchState::Exited(exit) => Ok(exit),
_ => Err(SystemdTransientError::UnitRestarted {
name: self.name.clone(),
}),
};
}
self.manager.stop_job(&self.name).await?;
self.watch.wait().await
}
pub fn name(&self) -> &str {
&self.name
}
pub async fn wait_for_exit(&self) -> Result<UnitExit, SystemdTransientError> {
self.watch.wait().await
}
pub async fn release(mut self) -> Result<(), SystemdTransientError> {
self.released = true;
self.unit.unref().await?;
Ok(())
}
}
impl Drop for TransientUnitHandle {
fn drop(&mut self) {
if self.released {
return;
}
if let Ok(rt) = tokio::runtime::Handle::try_current() {
let unit = self.unit.clone();
rt.spawn(async move {
if let Err(err) = unit.unref().await {
tracing::warn!("releasing unit {} failed: {}", unit.inner().path(), err);
}
});
}
}
}