|  | @@ -1,10 +1,9 @@
 | 
	
		
			
				|  |  | -use comm;
 | 
	
		
			
				|  |  | -use comm::Channel;
 | 
	
		
			
				|  |  | -use config::Config;
 | 
	
		
			
				|  |  | +extern crate time;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |  use std::fs::File;
 | 
	
		
			
				|  |  |  use std::io::prelude::*;
 | 
	
		
			
				|  |  |  use std::io;
 | 
	
		
			
				|  |  | -use std::thread;
 | 
	
		
			
				|  |  | +use super::Sensor;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  struct StatFiles {
 | 
	
		
			
				|  |  |      rx: File,
 | 
	
	
		
			
				|  | @@ -12,47 +11,59 @@ struct StatFiles {
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  struct Stats {
 | 
	
		
			
				|  |  | -    rx: u32,
 | 
	
		
			
				|  |  | -    tx: u32
 | 
	
		
			
				|  |  | +    rx: i64,
 | 
	
		
			
				|  |  | +    tx: i64
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +pub struct NetSpeedSensor {
 | 
	
		
			
				|  |  | +    files: Vec<StatFiles>,
 | 
	
		
			
				|  |  | +    stats: Option<Stats>,
 | 
	
		
			
				|  |  | +    last_time: i64
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +impl NetSpeedSensor {
 | 
	
		
			
				|  |  | +    pub fn new(devices: &Vec<&str>) -> NetSpeedSensor {
 | 
	
		
			
				|  |  | +        let files: Vec<StatFiles> = devices.iter()
 | 
	
		
			
				|  |  | +            .flat_map(|dev| open_stats(&dev).ok())
 | 
	
		
			
				|  |  | +            .collect();
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        NetSpeedSensor {
 | 
	
		
			
				|  |  | +            files: files,
 | 
	
		
			
				|  |  | +            stats: None,
 | 
	
		
			
				|  |  | +            last_time: 0
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -pub fn netspeed(tx: &Channel, config: &Config) {
 | 
	
		
			
				|  |  | -    let devices = parse_config(config);
 | 
	
		
			
				|  |  | -    let mut files : Vec<StatFiles> = devices.iter()
 | 
	
		
			
				|  |  | -        .flat_map(|dev| open_stats(&dev).ok())
 | 
	
		
			
				|  |  | -        .collect();
 | 
	
		
			
				|  |  | +impl Sensor for NetSpeedSensor {
 | 
	
		
			
				|  |  | +    fn status(&mut self) -> String {
 | 
	
		
			
				|  |  | +        let curr_time = time::get_time().sec;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -    let mut prev_stats : Option<Stats> = None;
 | 
	
		
			
				|  |  | -    loop {
 | 
	
		
			
				|  |  | -        let stats = files
 | 
	
		
			
				|  |  | +        let stats = self.files
 | 
	
		
			
				|  |  |              .iter_mut()
 | 
	
		
			
				|  |  |              .flat_map(|file| read_stats(file).ok())
 | 
	
		
			
				|  |  |              .fold(Stats { rx: 0, tx: 0 }, |acc, elem| Stats {
 | 
	
		
			
				|  |  |                  rx: acc.rx + elem.rx,
 | 
	
		
			
				|  |  |                  tx: acc.tx + elem.tx
 | 
	
		
			
				|  |  |              });
 | 
	
		
			
				|  |  | -        let output = match prev_stats {
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        let output = match self.stats.as_ref() {
 | 
	
		
			
				|  |  |              Some(pstats) => {
 | 
	
		
			
				|  |  | -                let rx = format_bytes(stats.rx - pstats.rx);
 | 
	
		
			
				|  |  | -                let tx = format_bytes(stats.tx - pstats.tx);
 | 
	
		
			
				|  |  | -                format!("{}↓ {}↑", rx, tx)
 | 
	
		
			
				|  |  | +                let rx = (stats.rx - pstats.rx) / (curr_time - self.last_time);
 | 
	
		
			
				|  |  | +                let tx = (stats.tx - pstats.tx) / (curr_time - self.last_time);
 | 
	
		
			
				|  |  | +                format!("{}↓ {}↑", format_bytes(rx), format_bytes(tx))
 | 
	
		
			
				|  |  |              },
 | 
	
		
			
				|  |  |              None => "?".to_string()
 | 
	
		
			
				|  |  |          };
 | 
	
		
			
				|  |  | -        prev_stats = Some(stats);
 | 
	
		
			
				|  |  | -        comm::send(tx, "netspeed", &output);
 | 
	
		
			
				|  |  | -        thread::sleep_ms(1000);
 | 
	
		
			
				|  |  | -    }
 | 
	
		
			
				|  |  | -}
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -fn parse_config(cfg: &Config) -> Vec<&str> {
 | 
	
		
			
				|  |  | -    let val = cfg.lookup("netspeed.devices").unwrap();
 | 
	
		
			
				|  |  | -    let arr = val.as_slice().unwrap();
 | 
	
		
			
				|  |  | -    let arr: Vec<&str> = arr.iter().flat_map(|elem| elem.as_str()).collect();
 | 
	
		
			
				|  |  | -    arr
 | 
	
		
			
				|  |  | +        self.last_time = curr_time;
 | 
	
		
			
				|  |  | +        self.stats = Some(stats);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        output
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -fn format_bytes(bytes: u32) -> String {
 | 
	
		
			
				|  |  | +fn format_bytes(bytes: i64) -> String {
 | 
	
		
			
				|  |  |      let kib = bytes >> 10;
 | 
	
		
			
				|  |  |      if kib > 1024 {
 | 
	
		
			
				|  |  |          format!("{:.*} M", 1, (kib as f32) / 1024.0)
 | 
	
	
		
			
				|  | @@ -79,10 +90,10 @@ fn read_stats(files: &mut StatFiles) -> Result<Stats, io::Error> {
 | 
	
		
			
				|  |  |      })
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -fn read_bytes(f: &mut File) -> u32 {
 | 
	
		
			
				|  |  | +fn read_bytes(f: &mut File) -> i64 {
 | 
	
		
			
				|  |  |      let mut s = String::new();
 | 
	
		
			
				|  |  |      assert!(f.read_to_string(&mut s).is_ok());
 | 
	
		
			
				|  |  | -    let i : u32 = s.trim().parse().unwrap();
 | 
	
		
			
				|  |  | +    let i : i64 = s.trim().parse().unwrap();
 | 
	
		
			
				|  |  |      assert!(f.seek(io::SeekFrom::Start(0)).is_ok());
 | 
	
		
			
				|  |  |      i
 | 
	
		
			
				|  |  |  }
 |