diff options
author | yuzu <yuzu@b9215c17-b818-4693-b096-d1e41a411fef> | 2025-06-04 04:45:58 +0000 |
---|---|---|
committer | yuzu <yuzu@b9215c17-b818-4693-b096-d1e41a411fef> | 2025-06-04 04:45:58 +0000 |
commit | 8880b0afd01bd9afb4a47a76d90e8b90e5cbff1e (patch) | |
tree | 96ee3e699a64ca44644cc53e19904444deb051a4 /src/model.rs | |
parent | 288842e0621eb3e07a0790ba328727939c480884 (diff) | |
download | salaryman-8880b0afd01bd9afb4a47a76d90e8b90e5cbff1e.tar.gz salaryman-8880b0afd01bd9afb4a47a76d90e8b90e5cbff1e.tar.bz2 salaryman-8880b0afd01bd9afb4a47a76d90e8b90e5cbff1e.zip |
Work on Service::stdout() and Service::stderr()
git-svn-id: svn+ssh://diminuette.aengel.lesbianunix.dev/salaryman/trunk@7 b9215c17-b818-4693-b096-d1e41a411fef
Diffstat (limited to 'src/model.rs')
-rw-r--r-- | src/model.rs | 170 |
1 files changed, 170 insertions, 0 deletions
diff --git a/src/model.rs b/src/model.rs new file mode 100644 index 0000000..52408fc --- /dev/null +++ b/src/model.rs @@ -0,0 +1,170 @@ +use serde::{Deserialize, Serialize}; + +use std::{ + fs::canonicalize, + io::{Read, BufRead, BufReader}, + path::PathBuf, + process::{Child, Command, Stdio}, + sync::{Arc, Mutex}, +}; + +#[derive(Serialize, Deserialize, Clone, Debug)] +pub struct ServiceConf { + pub name: String, + command: String, + args: Option<String>, + directory: Option<PathBuf>, + pub autostart: bool, +} +impl ServiceConf { + pub fn new() -> Self { + Self { + name: String::new(), + command: String::new(), + args: None, + directory: None, + autostart: false, + } + } + pub fn from_parts( + name: String, + command: String, + args: Option<String>, + directory: Option<PathBuf>, + autostart: bool, + ) -> Self { + Self { + name, + command, + args, + directory, + autostart, + } + } +} + +#[derive(Debug)] +pub struct Service { + pub config: ServiceConf, + process: Option<Mutex<Child>>, +} +impl Service { + pub fn new() -> Self { + Self { + config: ServiceConf::new(), + process: None, + } + } + pub fn from_conf(config: ServiceConf) -> Self { + Self { + config, + process: None, + } + } + pub fn start(&mut self) -> Result<(), Box<dyn std::error::Error>> { + if self.process.is_some() { + return Err(Box::new(std::io::Error::new( + std::io::ErrorKind::AlreadyExists, + "process already exists!", + ))); + } + let command: &str = &self.config.command.as_str(); + let args: Vec<String> = if let Some(a) = &self.config.args { + let mut v: Vec<String> = Vec::new(); + for arg in a.split_whitespace() { + v.push(String::from(arg)); + } + v + } else { + Vec::new() + }; + if let Some(cwd) = &self.config.directory { + let child = Command::new(command) + .args(args) + .current_dir(canonicalize(cwd)?) + .stdin(Stdio::piped()) + .stdout(Stdio::piped()) + .stderr(Stdio::piped()) + .spawn()?; + self.process = Some(Mutex::new(child)); + } else { + let child = Command::new(command) + .args(args) + .stdin(Stdio::piped()) + .stdout(Stdio::piped()) + .stderr(Stdio::piped()) + .spawn()?; + self.process = Some(Mutex::new(child)); + }; + Ok(()) + } + pub fn stop(&mut self) -> Result<(), Box<dyn std::error::Error>> { + if let Some(process) = &self.process { + if let Ok(mut process) = process.lock() { + process.kill()?; + } else { + return Err(Box::new(std::io::Error::new( + std::io::ErrorKind::ResourceBusy, + "cannot acquire lock", + ))) + } + } else { + return Err(Box::new(std::io::Error::new( + std::io::ErrorKind::NotFound, + "process already exists!", + ))); + }; + self.process = None; + Ok(()) + } + //TODO: this function needs to fork and do message passing via mpsc channels. + pub fn stdout(&mut self) -> Result<String, Box<dyn std::error::Error>> { + if let Some(process) = &mut self.process { + if let Ok(mut process) = process.lock() { + if let Some(stdout) = process.stdout.as_mut() { + let reader = BufReader::new(stdout); + Ok(String::from(reader.lines().filter_map(|line| line.ok()).collect::<String>())) + } else { + Err(Box::new(std::io::Error::new( + std::io::ErrorKind::ResourceBusy, + "cannot acquire stdout", + ))) + } + } else { + Err(Box::new(std::io::Error::new( + std::io::ErrorKind::ResourceBusy, + "cannot acquire lock", + ))) + } + } else { + Err(Box::new(std::io::Error::new( + std::io::ErrorKind::NotFound, + "is the process started?", + ))) + } + } + //TODO: this function needs to fork and do message passing via mpsc channels. + //TODO: this function needs to use a bufreader instead + pub fn stderr(&mut self) -> Result<String, Box<dyn std::error::Error>> { + if let Some(process) = &mut self.process { + if let Ok(mut process) = process.lock() { + let mut s = String::new(); + if let Some(stderr) = process.stderr.as_mut() { + stderr.read_to_string(&mut s)?; + } + Ok(s) + } else { + Err(Box::new(std::io::Error::new( + std::io::ErrorKind::ResourceBusy, + "cannot acquire lock", + ))) + } + } else { + Err(Box::new(std::io::Error::new( + std::io::ErrorKind::NotFound, + "is the process started?", + ))) + } + } +} + |