synchronizer 0.1.1

Little daemon service to synchronize all your containers across devices - Keep Your Cluster in Harmony
Documentation
use checks::Dependencies;
use error::SyncError;
use logic::{ip, Synchronizer};
use std::{
    env::{home_dir, temp_dir},
    fs::{read_to_string, write},
    path::Path,
    process::Command,
};
mod checks;
mod error;
mod logic;
fn main() -> Result<(), SyncError> {
    if let Ok(dep) = checks::Dependencies::new().installed() {
        if dep {
            println!("Dependencies met, let's go!")
        }
    }
    if let Ok(container) = Dependencies::new().container() {
        if container {
            println!("This is running in a container");
        }
    }
    let mut tgt_comparison = vec![];
    let path = Path::new(&home_dir().unwrap()).join(".synchronizer.yml");
    if !path.exists() {
        let contents = serde_yaml::to_string(&Synchronizer::new()).unwrap();
        write(path, contents).map_err(|_| SyncError::DirectoryDoesntExist)?;
    } else {
        let decoded: Synchronizer = serde_yaml::from_str(&*read_to_string(path).unwrap()).unwrap();
        let addr = match ip(&*decoded.hosts[0].1) {
            Ok(it) => it,
            Err(err) => return Err(err),
        };
        println!("Making backup and for diffing on the main host");
        let default_file = Path::new(&home_dir().unwrap())
            .join("docker-compose.yml")
            .to_str()
            .unwrap()
            .to_owned();
        let cfg_file = decoded.file.clone().unwrap_or(default_file);
        Command::new("ssh")
            .args([
                &*format!("{}@{}", decoded.hosts[0].0, addr),
                "cp",
                &cfg_file,
                Path::new(&temp_dir()).join("orig.yml").to_str().unwrap(),
            ])
            .status()
            .map_err(|_| SyncError::NoHostsConfigured)?;
        println!("Copying the original file to the other hosts");
        for host in 1..decoded.hosts.len() {
            let addr_str = &decoded.hosts[host].1;
            Command::new("scp")
                .args([
                    format!("{}@{}:{}", decoded.hosts[0].0, decoded.hosts[0].1, cfg_file),
                    format!("{}@{}:{}", decoded.hosts[host].0, addr_str, cfg_file),
                ])
                .status()
                .map_err(|_| SyncError::NoHostsConfigured)?;
        }
        for host in &decoded.hosts {
            tgt_comparison.push(
                Command::new("ssh")
                    .args([&*format!("{}@{}", host.0, host.1), "cat", &cfg_file])
                    .output()
                    .map_err(|_| SyncError::NoHostsConfigured)?
                    .status
                    .to_string(),
            );
        }

        loop {
            let orig = Command::new("ssh")
                .args([
                    &*format!("{}@{}", decoded.hosts[0].0, ip(&decoded.hosts[0].1)?),
                    "cat",
                    &cfg_file,
                ])
                .output()
                .map_err(|_| SyncError::NoHostsConfigured)?
                .status
                .to_string();
            for cfgs in &tgt_comparison {
                if *cfgs != orig {
                    println!("Propagating changes");
                    for host in 1..decoded.hosts.len() { // 0th host is the main one
                        match decoded.backend {
                            logic::Backend::Podman => {
                                Command::new("ssh")
                                    .arg(format!("{}@{}", decoded.hosts[host].0, decoded.hosts[host].1))
                                    .args(["podman", "compose","-f", &cfg_file, "up", "-d"])
                                    .status()
                                    .map_err(|_| SyncError::NoHostsConfigured)?;
                            }
                            logic::Backend::Docker => {
                                Command::new("ssh")
                                    .arg(format!("{}@{}", decoded.hosts[host].0, decoded.hosts[host].1))
                                    .args(["docker", "compose","-f", &cfg_file, "up", "-d"])
                                    .status()
                                    .map_err(|_| SyncError::NoHostsConfigured)?;
                            }
                        }
                    }
                } else {
                    // nothing to do, and that's great
                    continue;
                }
            }
        }
    }
    Ok(())
}