Network Monitoring in wmii

I’ve recently been playing around with wmii, a very minimal window manager for Linux. It uses a virtual filesystem to allow third party scripts to interact with it, in the style of procfs or Plan 9. ruby-wmii is just such a system for Ruby, and I’ve been spending an interesting time trying it out.

I’m not sure whether I like wmii yet, but I’m willing to give it a chance. It’s very minimal, but it’s nice to be able to have windows automatically tile, and I rather wish there were some way of doing it in GNOME or KDE. Maybe I’ll come to like the minimalism as well, but for now it seems there are a few things missing that could be rather useful.

One of these useful but missing things is a way to monitor network traffic, but it’s not too hard to add it. I’m just surprised that someone hasn’t created a plugin for it already. Briefly, then, here’s the class I use to poll for traffic information…

class NetworkMonitor
  def initialize
    @traffic = read_traffic
    @time    = Time.now
  end
 
  def poll
    new_traffic = read_traffic
    new_time    = Time.now
 
    # Calculate difference between traffic records
    traffic_diff = @traffic.merge(new_traffic) { |dev, before, after| {
      :recv => (after[:recv] - before[:recv]) / (new_time - @time),
      :sent => (after[:sent] - before[:sent]) / (new_time - @time)
    } }
 
    # Update records
    @time = new_time
    @traffic.update(new_traffic)
 
    return traffic_diff
  end
 
  protected 
    def read_traffic
      traffic = {}
      File.open "/proc/net/dev" do |file|
        # Remove header
        file.gets; file.gets
 
        # Parse lines
        file.each do |line|
          dev, data = line.split /:/
          data = data.strip.split /\s+/
 
          traffic[dev.strip] = {
            :recv => data[0].to_i,
            :sent => data[8].to_i
          }
        end
      end
      return traffic
    end
end

And here’s the code for the bar applet I use to display the information in wmii:

bar_applet("network-traffic", 100) do |wmii, bar|
  monitor = NetworkMonitor.new
  address = "weavejester@weavejester.com:network-traffic"
 
  devices = wmii.plugin_config[address]["devices"] || ["wlan0"]
  format  = wmii.plugin_config[address]["format"]
 
  format ||= lambda do |dev, recv, sent|
    sprintf "R %.2fK, S %.2fK", recv / 1024.0, sent / 1024.0
  end
 
  Thread.new do
    loop do
      text = ""
      for dev in devices
        data = monitor.poll[dev]
        text << format[dev, data[:recv], data[:sent]]
      end
      bar.data = text
      sleep 1
    end
  end  
end