ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/salaryman/trunk/src/service.rs
Revision: 7
Committed: Wed Jun 4 04:45:58 2025 UTC (4 months ago) by yuzu
Original Path: trunk/src/model.rs
File size: 5294 byte(s)
Log Message:
Work on Service::stdout() and Service::stderr()

File Contents

# Content
1 use serde::{Deserialize, Serialize};
2
3 use std::{
4 fs::canonicalize,
5 io::{Read, BufRead, BufReader},
6 path::PathBuf,
7 process::{Child, Command, Stdio},
8 sync::{Arc, Mutex},
9 };
10
11 #[derive(Serialize, Deserialize, Clone, Debug)]
12 pub struct ServiceConf {
13 pub name: String,
14 command: String,
15 args: Option<String>,
16 directory: Option<PathBuf>,
17 pub autostart: bool,
18 }
19 impl ServiceConf {
20 pub fn new() -> Self {
21 Self {
22 name: String::new(),
23 command: String::new(),
24 args: None,
25 directory: None,
26 autostart: false,
27 }
28 }
29 pub fn from_parts(
30 name: String,
31 command: String,
32 args: Option<String>,
33 directory: Option<PathBuf>,
34 autostart: bool,
35 ) -> Self {
36 Self {
37 name,
38 command,
39 args,
40 directory,
41 autostart,
42 }
43 }
44 }
45
46 #[derive(Debug)]
47 pub struct Service {
48 pub config: ServiceConf,
49 process: Option<Mutex<Child>>,
50 }
51 impl Service {
52 pub fn new() -> Self {
53 Self {
54 config: ServiceConf::new(),
55 process: None,
56 }
57 }
58 pub fn from_conf(config: ServiceConf) -> Self {
59 Self {
60 config,
61 process: None,
62 }
63 }
64 pub fn start(&mut self) -> Result<(), Box<dyn std::error::Error>> {
65 if self.process.is_some() {
66 return Err(Box::new(std::io::Error::new(
67 std::io::ErrorKind::AlreadyExists,
68 "process already exists!",
69 )));
70 }
71 let command: &str = &self.config.command.as_str();
72 let args: Vec<String> = if let Some(a) = &self.config.args {
73 let mut v: Vec<String> = Vec::new();
74 for arg in a.split_whitespace() {
75 v.push(String::from(arg));
76 }
77 v
78 } else {
79 Vec::new()
80 };
81 if let Some(cwd) = &self.config.directory {
82 let child = Command::new(command)
83 .args(args)
84 .current_dir(canonicalize(cwd)?)
85 .stdin(Stdio::piped())
86 .stdout(Stdio::piped())
87 .stderr(Stdio::piped())
88 .spawn()?;
89 self.process = Some(Mutex::new(child));
90 } else {
91 let child = Command::new(command)
92 .args(args)
93 .stdin(Stdio::piped())
94 .stdout(Stdio::piped())
95 .stderr(Stdio::piped())
96 .spawn()?;
97 self.process = Some(Mutex::new(child));
98 };
99 Ok(())
100 }
101 pub fn stop(&mut self) -> Result<(), Box<dyn std::error::Error>> {
102 if let Some(process) = &self.process {
103 if let Ok(mut process) = process.lock() {
104 process.kill()?;
105 } else {
106 return Err(Box::new(std::io::Error::new(
107 std::io::ErrorKind::ResourceBusy,
108 "cannot acquire lock",
109 )))
110 }
111 } else {
112 return Err(Box::new(std::io::Error::new(
113 std::io::ErrorKind::NotFound,
114 "process already exists!",
115 )));
116 };
117 self.process = None;
118 Ok(())
119 }
120 //TODO: this function needs to fork and do message passing via mpsc channels.
121 pub fn stdout(&mut self) -> Result<String, Box<dyn std::error::Error>> {
122 if let Some(process) = &mut self.process {
123 if let Ok(mut process) = process.lock() {
124 if let Some(stdout) = process.stdout.as_mut() {
125 let reader = BufReader::new(stdout);
126 Ok(String::from(reader.lines().filter_map(|line| line.ok()).collect::<String>()))
127 } else {
128 Err(Box::new(std::io::Error::new(
129 std::io::ErrorKind::ResourceBusy,
130 "cannot acquire stdout",
131 )))
132 }
133 } else {
134 Err(Box::new(std::io::Error::new(
135 std::io::ErrorKind::ResourceBusy,
136 "cannot acquire lock",
137 )))
138 }
139 } else {
140 Err(Box::new(std::io::Error::new(
141 std::io::ErrorKind::NotFound,
142 "is the process started?",
143 )))
144 }
145 }
146 //TODO: this function needs to fork and do message passing via mpsc channels.
147 //TODO: this function needs to use a bufreader instead
148 pub fn stderr(&mut self) -> Result<String, Box<dyn std::error::Error>> {
149 if let Some(process) = &mut self.process {
150 if let Ok(mut process) = process.lock() {
151 let mut s = String::new();
152 if let Some(stderr) = process.stderr.as_mut() {
153 stderr.read_to_string(&mut s)?;
154 }
155 Ok(s)
156 } else {
157 Err(Box::new(std::io::Error::new(
158 std::io::ErrorKind::ResourceBusy,
159 "cannot acquire lock",
160 )))
161 }
162 } else {
163 Err(Box::new(std::io::Error::new(
164 std::io::ErrorKind::NotFound,
165 "is the process started?",
166 )))
167 }
168 }
169 }
170