use crate::error::SystemdTransientError;
use crate::watch::exit_of;
use crate::{SystemdTransientManager, TransientUnitHandle, UnitExit, UnitProperty, UnitStatus};
#[derive(Debug)]
pub struct ReusableTransientUnit {
pub(crate) name: String,
pub(crate) props: Vec<UnitProperty>,
pub(crate) unit_handle: Option<TransientUnitHandle>,
pub(crate) systemd_manager: SystemdTransientManager,
}
impl ReusableTransientUnit {
pub async fn start(&mut self) -> Result<(), SystemdTransientError> {
if let Some(handle) = &self.unit_handle
&& exit_of(&handle.unit.active_state().await?).is_none()
{
return Err(SystemdTransientError::UnitAlreadyRunning {
name: handle.name.clone(),
});
}
self.release().await?;
let handle = self
.systemd_manager
.start(&self.name, self.props.clone())
.await?;
self.unit_handle = Some(handle);
Ok(())
}
pub async fn adopt(&mut self) -> Result<bool, SystemdTransientError> {
if self.unit_handle.is_none() {
self.unit_handle = self.systemd_manager.adopt(&self.name).await?;
}
Ok(self.unit_handle.is_some())
}
pub async fn stop(&mut self) -> Result<UnitExit, SystemdTransientError> {
let exit = self.handle()?.stop().await?;
self.release().await?;
Ok(exit)
}
pub async fn wait_for_exit(&self) -> Result<UnitExit, SystemdTransientError> {
self.handle()?.wait_for_exit().await
}
pub fn status(&self) -> UnitStatus {
match &self.unit_handle {
None => UnitStatus::Idle,
Some(h) => h.watch.current().into(),
}
}
pub async fn release(&mut self) -> Result<(), SystemdTransientError> {
if let Some(h) = self.unit_handle.take() {
h.release().await?;
}
Ok(())
}
fn handle(&self) -> Result<&TransientUnitHandle, SystemdTransientError> {
self
.unit_handle
.as_ref()
.ok_or_else(|| SystemdTransientError::UnitNotRunning {
name: self.name.clone(),
})
}
}