rustenium_core/
process.rs1use std::process::Stdio;
2
3use regex::Regex;
4use tokio::io::{AsyncBufReadExt, BufReader};
5use tokio::process::{Child, Command};
6use tokio::time::{timeout, Duration};
7
8pub struct Process {
9 child: Option<Child>,
10}
11
12impl Process {
13 pub fn create<S, I>(exe_path: S, args: I) -> Process
14 where
15 S: AsRef<str>,
16 I: IntoIterator<Item = String>,
17 {
18 let child = Command::new(exe_path.as_ref())
19 .args(args.into_iter().map(|s| s))
20 .stdout(Stdio::piped())
21 .stderr(Stdio::piped())
22 .spawn()
23 .expect("Failed to start process");
24
25 let child = Some(child);
26
27 return Self { child };
28 }
29
30 #[deprecated]
31 pub async fn wait_for_pattern(&mut self, pattern: &str, timeout_secs: Option<u64>) -> String {
32 let timeout_secs = timeout_secs.unwrap_or(20);
33 let regex = Regex::new(pattern).expect("Invalid regex pattern");
34 let child = self.child.as_mut().unwrap();
35
36 let stdout = child.stdout.as_mut().expect("Failed to access stdout");
37 let stderr = child.stderr.as_mut().expect("Failed to access stderr");
38
39 let mut stdout_lines = BufReader::new(stdout).lines();
40 let mut stderr_lines = BufReader::new(stderr).lines();
41
42 let check_line = |_label: &str, line: Result<Option<String>, _>| -> Option<String> {
43 if let Ok(Some(line)) = line {
44 if let Some(captures) = regex.captures(&line) {
45 if let Some(url) = captures.get(1) {
46 return Some(url.as_str().into());
47 }
48 }
49 }
50 None
51 };
52
53 let timeout_duration = Duration::from_secs(timeout_secs);
54
55 let timeout_result = timeout(timeout_duration, async {
56 loop {
57 tokio::select! {
58 stdout_line = stdout_lines.next_line() => {
59 if let Some(line) = check_line("stdout", stdout_line) {
60 return Some(line);
61 }
62 },
63 stderr_line = stderr_lines.next_line() => {
64 if let Some(line) = check_line("stderr", stderr_line) {
65 return Some(line);
66 }
67 }
68 }
69 }
70 })
71 .await;
72
73 match timeout_result {
74 Ok(Some(matched)) => matched,
75 Ok(None) => panic!("Found a pattern but None"),
76 Err(_) => panic!("Timeout reached without finding pattern"),
77 }
78 }
79}
80
81impl Drop for Process {
82 fn drop(&mut self) {
83 if let Some(mut child) = self.child.take() {
84 let _ = child.kill(); }
86 }
87}