use anyhow::Error;
use std::process::{Child, ExitStatus};
use std::time::Duration;
use std::{fmt, fs};
use tracing::instrument;
use crate::config_commands::ConfigCommands;
use crate::config_git::ConfigGit;
use crate::config_quadit::ConfigQuadit;
use crate::config_reload::ConfigReload;
use crate::file_manager::FileManager;
use crate::git_manager::GitManager;
const SYSTEMCTL_PATH: &str = "/usr/bin/systemctl";
const USER: bool = true;
pub struct ServiceManager {
pub git_manager: GitManager,
pub target_configs: Vec<ConfigGit>,
pub config_reload: Option<ConfigReload>,
pub systemd_commands: Option<Vec<ConfigCommands>>,
}
impl fmt::Debug for ServiceManager {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "Service Manager")
}
}
impl ServiceManager {
#[instrument]
pub async fn configured() -> Result<ServiceManager, anyhow::Error> {
if !FileManager::boot_url().is_empty() {
FileManager::from_url(FileManager::boot_url()).await?;
}
let conf = FileManager::load_quadit_config()?;
let quad = ConfigQuadit::from_yaml(conf)?;
let tconfigs = quad.target_configs.clone();
Ok(ServiceManager {
git_manager: GitManager::from_target_configs(quad.target_configs).await?,
target_configs: tconfigs,
config_reload: quad.config_reload,
systemd_commands: quad.systemd_commands,
})
}
#[instrument]
pub async fn run(&mut self) -> Result<(), Error> {
self.git_manager.start().await?;
loop {
let mut sleep: u64 = 100;
if self.config_reload.is_some() {
sleep = self.config_reload.as_ref().unwrap().interval;
}
std::thread::sleep(Duration::from_millis(sleep));
if self.config_reload.is_some() {
let changed = FileManager::from_url(
self.config_reload.as_ref().unwrap().config_u_r_l.as_str(),
)
.await?;
if changed {
self.git_manager.stop().await?;
let configs = self.target_configs.clone();
self.git_manager = GitManager::from_target_configs(configs).await?;
self.git_manager.start().await?;
}
}
}
}
#[instrument]
pub async fn reload() -> Result<(), Error> {
if FileManager::boot_url().is_empty() {
FileManager::from_url(FileManager::boot_url()).await?;
}
loop {
std::thread::sleep(Duration::from_millis(100));
}
}
pub fn restart(unit: &str) -> std::io::Result<ExitStatus> {
ServiceManager::systemctl(vec!["restart", unit])
}
pub fn remove(unit: &str, deployment_path: &str) -> std::io::Result<ExitStatus> {
ServiceManager::systemctl(vec!["stop", unit])?;
fs::remove_file(deployment_path)?;
ServiceManager::daemon_reload()
}
pub fn daemon_reload() -> std::io::Result<ExitStatus> {
ServiceManager::systemctl(vec!["daemon-reload"])
}
fn spawn_child(args: Vec<&str>) -> std::io::Result<Child> {
std::process::Command::new(std::env::var("SYSTEMCTL_PATH").unwrap_or(SYSTEMCTL_PATH.into()))
.args(args)
.stdout(std::process::Stdio::piped())
.stderr(std::process::Stdio::piped())
.spawn()
}
fn systemctl(mut args: Vec<&str>) -> std::io::Result<ExitStatus> {
if USER {
let mut first_arg = vec!["--user"];
first_arg.append(&mut args);
ServiceManager::spawn_child(first_arg)?.wait()
} else {
ServiceManager::spawn_child(args)?.wait()
}
}
}