Page Menu
Home
Phorge
Search
Configure Global Search
Log In
Files
F2708081
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Flag For Later
Award Token
Size
4 KB
Referenced Files
None
Subscribers
None
View Options
diff --git a/Cargo.toml b/Cargo.toml
index 68ffe33..43fc476 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -1,12 +1,15 @@
[package]
name = "pawd"
version = "0.1.0"
edition = "2021"
license = "MIT"
repository = "https://lab.themackabu.dev/crates/pawd"
description = "Process analysis & watcher daemon"
[dependencies]
psutil = { version = "3.2.2", features = ["serde"] }
serde = "1.0.192"
serde_derive = "1.0.192"
+
+[dev-dependencies]
+assert_matches = "1.5.0"
\ No newline at end of file
diff --git a/src/lib.rs b/src/lib.rs
index 8bd63b1..08a4f2e 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -1,103 +1,110 @@
mod structs;
use psutil::process::{MemoryInfo, Process};
use std::io::{self, Read};
use std::process::{Command, Stdio};
use std::thread::{sleep, spawn};
use std::time::{Duration, Instant};
use structs::{PawDone, PawInfo, PawProcess, PawResult};
/// Represents a process watcher that monitors the resource usage of a child process.
#[derive(Debug, Clone)]
pub struct Paw {
command: String,
arguments: Vec<String>,
duration: Duration,
}
impl Paw {
/// Creates a new `Paw` instance with the specified command, arguments, and duration.
pub fn new<T: AsRef<str>>(command: &str, arguments: &[T], duration: u64) -> Paw {
Paw {
command: command.to_string(),
arguments: arguments.iter().map(|s| s.as_ref().to_string()).collect(),
duration: Duration::from_millis(duration),
}
}
/// Watches the process and calls the provided callback with the result at regular intervals.
///
/// # Arguments
///
/// * `callback` - A callback function that takes a `PawResult` as its parameter.
///
/// # Returns
///
/// Returns a `Result` containing a `PawDone` indicating the completion status.
pub fn watch<F: Fn(PawResult) + Send + 'static>(&self, callback: F) -> Result<PawDone, Box<dyn std::error::Error>> {
let mut child = Command::new(&self.command).args(&self.arguments).stdout(Stdio::piped()).spawn()?;
let done: PawDone;
let pid = child.id();
let start_time = Instant::now();
let stdout_handle = child.stdout.take().unwrap();
let stdout_thread = spawn(move || {
let mut buffer = String::new();
let mut reader = io::BufReader::new(stdout_handle);
reader.read_to_string(&mut buffer).unwrap();
buffer
});
loop {
let uptime = start_time.elapsed().as_millis();
let mut memory_usage: Option<MemoryInfo> = None;
let mut cpu_percent: Option<f32> = None;
if let Ok(mut process) = Process::new(pid) {
memory_usage = process.memory_info().ok();
cpu_percent = process.cpu_percent().ok();
}
let result = PawResult {
info: PawInfo { memory_usage, cpu_percent, uptime },
process: PawProcess {
cmd: self.command.clone(),
args: self.arguments.clone(),
},
};
callback(result);
sleep(self.duration);
if let Some(status) = child.try_wait()? {
done = PawDone {
stdout: stdout_thread.join().unwrap(),
code: status.code(),
};
break;
}
}
Ok(done)
}
}
#[cfg(test)]
mod tests {
use super::*;
+ use assert_matches::assert_matches;
#[test]
fn watch() {
let paw = Paw::new("node", &["tests/test.js"], 500);
let callback = move |result: PawResult| {
- println!("{:?}", result);
+ assert_matches!(
+ result,
+ PawResult {
+ info: PawInfo { .. },
+ process: PawProcess { .. }
+ }
+ );
};
match paw.watch(callback) {
- Ok(result) => println!("{:?}", result),
- Err(error) => println!("{error}"),
+ Ok(result) => assert_matches!(result, PawDone { .. }),
+ Err(error) => panic!("{error}"),
}
}
}
File Metadata
Details
Attached
Mime Type
text/x-diff
Expires
Sun, Feb 1, 7:50 PM (1 d, 17 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
494903
Default Alt Text
(4 KB)
Attached To
Mode
R7 Paw
Attached
Detach File
Event Timeline
Log In to Comment