diff --git a/Cargo.toml b/Cargo.toml index 2ccfae0..4ec8924 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,6 +6,6 @@ edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -nix = {version = "0.27.1", features = ["process", "signal"]} +nix = {version = "0.27.1", features = ["process", "signal", "fs"]} tokio = { version = "1.34.0", features = ["full"] } tokio-util = "0.7.10" diff --git a/src/bin/init.rs b/src/bin/init.rs index 8500fa4..1fd7ce2 100644 --- a/src/bin/init.rs +++ b/src/bin/init.rs @@ -4,5 +4,5 @@ use wingmate_rs::init; #[tokio::main] async fn main() -> Result<(), Box> { - init::daemon::start().await + init::start().await } \ No newline at end of file diff --git a/src/init.rs b/src/init.rs index 7b1b652..e87b3ae 100644 --- a/src/init.rs +++ b/src/init.rs @@ -1 +1,10 @@ -pub mod daemon; \ No newline at end of file +mod daemon; +mod config; +pub(crate) mod error; + +use std::error as std_err; + +pub async fn start() -> Result<(), Box> { + let _config = config::Config::find(vec![String::from("/etc/wingmate")])?; + daemon::start().await +} \ No newline at end of file diff --git a/src/init/config.rs b/src/init/config.rs new file mode 100644 index 0000000..31dff45 --- /dev/null +++ b/src/init/config.rs @@ -0,0 +1,65 @@ +use std::fs; +use std::path::PathBuf; +use std::error as std_error; +use crate::init::error as wingmate_error; +use nix::unistd::{access, AccessFlags}; + +pub enum Command { + ShellPrefixed(String), + Direct(String) +} + +pub struct Config { + pub services: Vec, +} + +impl Config { + pub fn find(search_path: Vec) -> Result> { + if search_path.is_empty() { + return Err(wingmate_error::InvalidConfigSearchPathError.into()); + } + + let mut svc_commands: Vec = Vec::new(); + for p in search_path { + let mut buf = PathBuf::new(); + buf.push(p); + if let Ok(m) = fs::metadata(buf.as_path()) { + if m.is_dir() { + let svc = buf.join("services"); + if let Ok(svc_iter) = fs::read_dir(svc.as_path()) { + for entry in svc_iter { + if let Ok(dirent) = entry { + let ep = dirent.path(); + if let Ok(_) = access(ep.as_path(), AccessFlags::X_OK) { + // execute directly + svc_commands.push(Command::Direct(String::from(ep.as_path().to_string_lossy()))); + } else { + // call with shell + svc_commands.push(Command::ShellPrefixed(String::from(ep.as_path().to_string_lossy()))); + } + } + } + } + + let cron = buf.join("cron"); + if let Ok(cron_iter) = fs::read_dir(cron.as_path()) { + for entry in cron_iter { + if let Ok(_dirent) = entry { + // read the cron file + } + } + } + } else { + // reserve for future use; when we have a centralized config file + } + } + } + + if svc_commands.is_empty() { + return Err(wingmate_error::NoServiceOrCronFoundError.into()); + } + + let config = Config { services: svc_commands }; + Ok(config) + } +} \ No newline at end of file diff --git a/src/init/daemon/starter.rs b/src/init/daemon/starter.rs index cc2778c..6494b63 100644 --- a/src/init/daemon/starter.rs +++ b/src/init/daemon/starter.rs @@ -47,6 +47,8 @@ pub fn start_process(ts: &mut JoinSet { diff --git a/src/init/error.rs b/src/init/error.rs new file mode 100644 index 0000000..ff3f14a --- /dev/null +++ b/src/init/error.rs @@ -0,0 +1,25 @@ +use std::fmt; +use std::error; + +#[derive(Debug, Clone)] +pub struct InvalidConfigSearchPathError; + +impl fmt::Display for InvalidConfigSearchPathError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "invalid config search path") + } +} + +impl error::Error for InvalidConfigSearchPathError {} + + +#[derive(Debug,Clone)] +pub struct NoServiceOrCronFoundError; + +impl fmt::Display for NoServiceOrCronFoundError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "no service or cron found") + } +} + +impl error::Error for NoServiceOrCronFoundError {} \ No newline at end of file