eutils_rs/proc/
snmp.rs

1use anyhow::{bail, Result};
2use std::collections::HashMap;
3use std::fs::{read_to_string, File};
4use std::io::{self, BufRead};
5use std::ops::Sub;
6use std::path::Path;
7use std::str::FromStr;
8
9#[derive(Default, Debug, Clone)]
10pub struct Snmp {
11    hm: HashMap<(String, String), isize>,
12}
13
14impl FromStr for Snmp {
15    type Err = anyhow::Error;
16    fn from_str(content: &str) -> Result<Self> {
17        let mut snmp = Snmp::default();
18
19        let lines = content.split('\n').collect::<Vec<&str>>();
20
21        for i in 0..lines.len() / 2 {
22            let line1 = lines[i * 2];
23            let line2 = lines[i * 2 + 1];
24
25            let mut iter1 = line1.split_whitespace();
26            let mut iter2 = line2.split_whitespace();
27
28            let prefix;
29            if let Some(x) = iter1.next() {
30                prefix = x.to_string();
31            } else {
32                bail!("failed to parse: prefix not found")
33            }
34            iter2.next();
35            loop {
36                let k;
37                let v: isize;
38                if let Some(x) = iter1.next() {
39                    k = x;
40                } else {
41                    break;
42                }
43
44                if let Some(x) = iter2.next() {
45                    v = x.parse()?;
46                } else {
47                    bail!("failed to parse: number of item is not match.")
48                }
49
50                snmp.insert((prefix.clone(), k.to_string()), v);
51            }
52        }
53
54        Ok(snmp)
55    }
56}
57
58impl Sub for Snmp {
59    type Output = Self;
60
61    fn sub(self, other: Self) -> Self {
62        let mut snmp = Snmp::default();
63
64        for (k, v) in self.hm.iter() {
65            assert_eq!(other.hm.contains_key(k), true);
66            snmp.insert(k.clone(), v - other.hm[k]);
67        }
68
69        snmp
70    }
71}
72
73impl Snmp {
74    pub fn from_file<P>(path: P) -> Result<Snmp>
75    where
76        P: AsRef<Path>,
77    {
78        let string = read_to_string(path)?;
79        Snmp::from_str(&string)
80    }
81
82    pub fn insert(&mut self, k: (String, String), v: isize) {
83        self.hm.insert(k, v);
84    }
85
86    pub fn lookup(&self, k: &(String, String)) -> Option<&isize> {
87        self.hm.get(k)
88    }
89
90    pub fn show_non_zero(&self) {
91        for (k, v) in &self.hm {
92            if *v != 0 {
93                print!("{}{}: {} ", k.0, k.1, v);
94            }
95        }
96        println!();
97    }
98}
99
100#[cfg(test)]
101mod tests {
102    use super::*;
103    #[test]
104    fn test_snmp_from_file() {
105        let snmp = Snmp::from_file("/proc/net/snmp");
106        assert_eq!(snmp.is_ok(), true);
107    }
108
109    #[test]
110    fn test_snmp_ops_sub() {
111        let snmp1 = Snmp::from_file("/proc/net/snmp").unwrap();
112        let snmp2 = Snmp::from_file("/proc/net/snmp").unwrap();
113        let delta = snmp1 - snmp2;
114    }
115
116    #[test]
117    fn test_snmp_show_non_zero() {
118        let snmp1 = Snmp::from_file("/proc/net/snmp").unwrap();
119        let snmp2 = Snmp::from_file("/proc/net/snmp").unwrap();
120        let delta = snmp1 - snmp2;
121        delta.show_non_zero();
122    }
123}