abar 0.6.2

An interface for creating dynamic, "blocks"-style status strings
Documentation
use std::io::Read;
use std::net::TcpListener;
use std::sync::mpsc;

pub type MonitorSender = mpsc::SyncSender<Command>;
pub type MonitorReceiver = mpsc::Receiver<Command>;

/// Represents a command that can be sent to the meta framework.
pub enum Command {
    Refresh,
    Shutdown,
    Update(Vec<String>),
}

/// A struct for monitoring and reacting to external input over TCP.
pub struct Monitor {
    listener: TcpListener,
    tx:       MonitorSender,
}

impl Monitor {
    /// Trt to bind to the given port and return a new Monitor.
    pub fn new(tx: MonitorSender, port: usize) -> Self {
        let listener = TcpListener::bind(format!("127.0.0.1:{}", port));

        if listener.is_err() {
            eprintln!(
                "Could not bind to port {}! Another bar instance is probably \
                 running.",
                port
            );
            std::process::exit(1);
        }

        Self { listener: listener.unwrap(), tx }
    }

    /// Listen for incoming connections, and pipe any received commands into
    /// self.tx.
    pub fn run(self) {
        use Command::*;

        for stream in self.listener.incoming() {
            // Unpack data from the stream.
            let mut stream = stream.unwrap();
            let mut data = String::new();
            stream.read_to_string(&mut data).unwrap();

            // Check the first statement in the command.
            let mut data = data.split(" ");
            let result = match data.next() {
                Some("refresh") => self.tx.send(Refresh),
                Some("shutdown") => self.tx.send(Shutdown),
                Some("update") => {
                    // Treat the rest of the arguments as block names and
                    // forward them back to the framework to be updated.
                    let names =
                        data.map(|name| name.to_string()).collect::<Vec<_>>();
                    self.tx.send(Update(names))
                },
                _ => Ok(()),
            };

            // TODO: What to do if the listener encounters an error?
            if let Err(_err) = result {
                unimplemented!("Monitor panicked!")
            }
        }
    }
}