use crate::util::read_to_string_mut;
use std::{fs, io};
use std::path::Path;
use std::time::Duration;
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Uptime {
raw: String
}
impl Uptime {
fn path() -> &'static Path {
Path::new("/proc/uptime")
}
#[cfg(test)]
fn from_string(raw: String) -> Self {
Self {raw}
}
pub fn read() -> io::Result<Self> {
Ok(Self {
raw: fs::read_to_string(Self::path())?
})
}
pub fn reload(&mut self) -> io::Result<()> {
read_to_string_mut(Self::path(), &mut self.raw)
}
pub fn all_infos<'a>(&'a self) -> impl Iterator<Item=Duration> + 'a {
self.raw.split(' ')
.filter_map(|v| v.trim().parse().ok())
.map(Duration::from_secs_f64)
}
pub fn uptime(&self) -> Option<Duration> {
self.all_infos().next()
}
pub fn idletime(&self) -> Option<Duration> {
self.all_infos().nth(1)
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Hostname {
raw: String
}
impl Hostname {
fn path() -> &'static Path {
Path::new("/proc/sys/kernel/hostname")
}
#[cfg(test)]
fn from_string(raw: String) -> Self {
Self {raw}
}
pub fn read() -> io::Result<Self> {
Ok(Self {
raw: fs::read_to_string(Self::path())?
})
}
pub fn reload(&mut self) -> io::Result<()> {
read_to_string_mut(Self::path(), &mut self.raw)
}
pub fn hostname(&self) -> &str {
self.raw.trim()
}
pub fn into_string(self) -> String {
self.raw
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct OsRelease {
raw: String
}
impl OsRelease {
fn path() -> &'static Path {
Path::new("/proc/sys/kernel/osrelease")
}
#[cfg(test)]
fn from_string(raw: String) -> Self {
Self {raw}
}
pub fn read() -> io::Result<Self> {
Ok(Self {
raw: fs::read_to_string(Self::path())?
})
}
pub fn reload(&mut self) -> io::Result<()> {
read_to_string_mut(Self::path(), &mut self.raw)
}
pub fn full_str(&self) -> &str {
self.raw.trim()
}
pub fn into_string(self) -> String {
self.raw
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct LoadAvg {
raw: String
}
impl LoadAvg {
fn path() -> &'static Path {
Path::new("/proc/loadavg")
}
#[cfg(test)]
fn from_string(raw: String) -> Self {
Self {raw}
}
pub fn read() -> io::Result<Self> {
Ok(Self {
raw: fs::read_to_string(Self::path())?
})
}
pub fn reload(&mut self) -> io::Result<()> {
read_to_string_mut(Self::path(), &mut self.raw)
}
pub fn values<'a>(&'a self) -> impl Iterator<Item=&'a str> {
self.raw.split(' ')
.map(str::trim)
}
pub fn average(&self) -> Option<(f32, f32, f32)> {
let mut vals = self.values()
.take(3)
.map(|v| v.parse().ok());
Some((vals.next()??, vals.next()??, vals.next()??))
}
pub fn threads(&self) -> Option<(usize, usize)> {
let mut vals = self.values()
.nth(3)?
.split('/')
.map(|v| v.parse().ok());
Some((vals.next()??, vals.next()??))
}
pub fn newest_pid(&self) -> Option<u32> {
self.values().last()?
.parse().ok()
}
}
#[cfg(test)]
mod tests {
use super::*;
fn uptime() -> Uptime {
Uptime::from_string("220420.83 5275548.45\n".into())
}
#[test]
fn uptime_methods() {
assert_eq!(uptime().uptime().unwrap().as_secs(), 220420);
assert_eq!(uptime().idletime().unwrap().as_secs(), 5275548);
}
#[test]
fn hostname() {
let name = Hostname::from_string("test-hostname\n".into());
assert_eq!(name.hostname(), "test-hostname");
}
#[test]
fn os_release() {
let name = OsRelease::from_string("test-hostname\n".into());
assert_eq!(name.full_str(), "test-hostname");
}
#[test]
fn load_avg() {
let s = LoadAvg::from_string("13.37 15.82 16.64 14/1444 436826\n".into());
assert_eq!(s.average().unwrap(), (13.37, 15.82, 16.64));
assert_eq!(s.threads().unwrap(), (14, 1444));
assert_eq!(s.newest_pid().unwrap(), 436826);
}
}