<commit_before>//! Provides the server and handles the incomming requests
//! All ports are handled by the same function

// System modules:
use std::net::{TcpListener, TcpStream, SocketAddr};
use std::thread::spawn;
use std::io::prelude::*;
use std::sync::{Arc, Mutex};
use std::fs::OpenOptions;
use std::io::BufWriter;
use std::io::Result;
use time::{now, Tm};

// Internal modules:
use configuration::{Configuration, HEADER_LENGTH};
use data_parser::{parse_text_data, StationDataType};

fn write_xml_data(tm: Tm, local_port: u16, data: &StationDataType, file_name: &str) -> Result<()> {
    let mut file_handle = BufWriter::new(try!(OpenOptions::new()
        .write(true).create(true).append(true).open(format!("{}.xml", file_name))));

    let current_date_time = tm.strftime("%Y.%m.%d - %H:%M:%S").unwrap();

    try!(write!(file_handle, "<measure>\n"));
    try!(write!(file_handle, "<port>{}</port>\n", local_port));
    try!(write!(file_handle, "<date_time>{}</date_time>\n", &current_date_time));
    try!(write!(file_handle, "<data>\n"));

    // try!(write!(file_handle, "{:?}\n", data));

    match data {
        &StationDataType::SingleData(time_stamp_tm, voltage) => {
            if let Ok(time_stamp) = time_stamp_tm.strftime("%Y-%m-%d %H:%M:%S") {
                try!(write!(file_handle, "    <time_stamp>{}</time_stamp>\n", time_stamp));
                try!(write!(file_handle, "    <voltage>{}</voltage>\n", voltage));
            }
        },
        &StationDataType::MultipleData(ref full_data_set) => {
            if let Ok(time_stamp) = full_data_set.time_stamp.strftime("%Y-%m-%d %H:%M:%S") {
                try!(write!(file_handle, "    <time_stamp>{}</time_stamp>\n", time_stamp));
                try!(write!(file_handle, "    <air_temperature>{}</air_temperature>\n", full_data_set.air_temperature));
                try!(write!(file_handle, "    <air_relative_humidity>{}</air_relative_humidity>\n", full_data_set.air_relative_humidity));
                try!(write!(file_handle, "    <solar_radiation>{}</solar_radiation>\n", full_data_set.solar_radiation));
                try!(write!(file_handle, "    <soil_water_content>{}</soil_water_content>\n", full_data_set.soil_water_content));
                try!(write!(file_handle, "    <soil_temperature>{}</soil_temperature>\n", full_data_set.soil_temperature));
                try!(write!(file_handle, "    <wind_speed>{}</wind_speed>\n", full_data_set.wind_speed));
                try!(write!(file_handle, "    <wind_max>{}</wind_max>\n", full_data_set.wind_max));
                try!(write!(file_handle, "    <wind_direction>{}</wind_direction>\n", full_data_set.wind_direction));
                try!(write!(file_handle, "    <percipitation>{}</percipitation>\n", full_data_set.percipitation));
                try!(write!(file_handle, "    <air_pressure>{}</air_pressure>\n", full_data_set.air_pressure));
            }
        }
    }

    try!(write!(file_handle, "</data>\n"));
    try!(write!(file_handle, "</measure>\n\n"));

    Ok(())
}

fn write_csv_data(data: &StationDataType, file_name: &str) -> Result<()> {
    let mut file_handle = BufWriter::new(try!(OpenOptions::new()
        .write(true).create(true).append(true).open(format!("{}.csv", file_name))));

        match data {
            &StationDataType::SingleData(time_stamp_tm, voltage) => {
                if let Ok(time_stamp) = time_stamp_tm.strftime("%Y-%m-%d %H:%M:%S") {
                    try!(write!(file_handle, "\"{}\", {}\n", time_stamp, voltage));
                }
            },
            &StationDataType::MultipleData(ref full_data_set) => {
                if let Ok(time_stamp) = full_data_set.time_stamp.strftime("%Y-%m-%d %H:%M:%S") {
                    try!(write!(file_handle, "\"{}\", {}, {}, {}, {}, {}, {}, {}, {}, {}, {}\n",
                        time_stamp,
                        full_data_set.air_temperature,
                        full_data_set.air_relative_humidity,
                        full_data_set.solar_radiation,
                        full_data_set.soil_water_content,
                        full_data_set.soil_temperature,
                        full_data_set.wind_speed,
                        full_data_set.wind_max,
                        full_data_set.wind_direction,
                        full_data_set.percipitation,
                        full_data_set.air_pressure
                    ));
                }
            }
        }

    Ok(())
}

fn port_to_station(port: u16) -> String{
    match port {
        2100 => "2100_Na".to_string(),
        2101 => "2101_SG".to_string(),
        2102 => "2102_PdA".to_string(),
        2103 => "2103_LC".to_string(),
        2104 => "2104_Tue".to_string(),
        _ => "unknown".to_string()
    }
}

fn handle_client(stream: &mut TcpStream, remote_addr: &SocketAddr,
    all_data_file: &Arc<Mutex<String>>, monthly_data_folder: &Arc<Mutex<String>>) -> Result<()> {
    info!("Client socket address: {}", remote_addr);

    let local_addr = try!(stream.local_addr());

    let local_port = match local_addr {
        SocketAddr::V4(local_addr) => local_addr.port(),
        SocketAddr::V6(local_addr) => local_addr.port()
    };

    info!("Port: {}", local_port);

    let mut buffer = Vec::new();

    let len = try!(stream.read_to_end(&mut buffer));
    info!("Number of bytes received: {}", len);

    if buffer.len() > HEADER_LENGTH {
        let (buffer_left, buffer_right) = buffer.split_at(HEADER_LENGTH);

        let str_header = String::from_utf8_lossy(buffer_left);
        let str_data = String::from_utf8_lossy(buffer_right);

        info!("Header: {:?}", buffer_left);
        info!("Data: {:?}", buffer_right);

        info!("Header (ASCII): '{}'", str_header);
        info!("Data (ASCII): '{}'", str_data);

        let station_folder = port_to_station(local_port);

        match parse_text_data(&buffer_right) {
            Ok(parsed_data) => {
                info!("Data parsed correctly");
                match all_data_file.lock() {
                    Ok(all_data_file) => {
                        let tm = now();
                        let file_name = format!("{}/{}", station_folder, *all_data_file);
                        try!(write_xml_data(tm, local_port, &parsed_data, &file_name));
                        try!(write_csv_data(&parsed_data, &file_name));
                    },
                    Err(e) => info!("Mutex (poison) error (all_data_file): {}", e)
                }

                match monthly_data_folder.lock() {
                    Ok(monthly_data_folder) => {
                        let tm = now();
                        let current_year = tm.strftime("%Y").unwrap();
                        let current_month = tm.strftime("%m").unwrap();
                        // TODO: create separate folder for year and month in Rust
                        let file_name = format!("{}/{}/{}_{}", *monthly_data_folder, station_folder, current_year, current_month);
                        try!(write_xml_data(tm, local_port, &parsed_data, &file_name));
                        try!(write_csv_data(&parsed_data, &file_name));
                    },
                    Err(e) => info!("Mutex (poison) error (monthly_data_folder): {}", e)
                }

            },
            Err(e) => {
                info!("Could not parse data: {}", e);
            }
        }
    } else if buffer.len() < HEADER_LENGTH {
        info!("Invalid header (less than {} bytes received)!", HEADER_LENGTH);
        info!("Bytes: {:?}", buffer);
        info!("Bytes (ASCII): '{}'", String::from_utf8_lossy(&buffer));
    } else { // buffer.len() == HEADER_LENGTH -> no data, only header
        info!("No data received, just header.");
        info!("Bytes: {:?}", buffer);
        info!("Bytes (ASCII): '{}'", String::from_utf8_lossy(&buffer));
    }

    info!("handle_client finished")

    Ok(())
}

pub fn start_service(config: Configuration) {
    let mut listeners = Vec::new();

    for port in config.ports {
        match TcpListener::bind(("0.0.0.0", port)) {
            Ok(listener) => {
                info!("Create listener for port {}", port);
                listeners.push(listener);
            },
            Err(e) => info!("Network error: {}", e)
        }
    }

    let all_data_file = Arc::new(Mutex::new(config.all_data_file.clone()));
    let monthly_data_folder = Arc::new(Mutex::new(config.monthly_data_folder.clone()));

    for listener in listeners {
        let all_data_file = all_data_file.clone();
        let monthly_data_folder = monthly_data_folder.clone();
        spawn(move|| {
            loop {
                let result = listener.accept();
                if let Ok(result) = result {
                    let (mut stream, addr) = result;
                    if let Err(io_error) = handle_client(&mut stream, &addr,
                            &all_data_file, &monthly_data_folder) {
                        info!("IOError: {}", io_error);
                    }
                }
            }
        });
    }
}
<commit_msg>fix missing semikolon<commit_after>//! Provides the server and handles the incomming requests
//! All ports are handled by the same function

// System modules:
use std::net::{TcpListener, TcpStream, SocketAddr};
use std::thread::spawn;
use std::io::prelude::*;
use std::sync::{Arc, Mutex};
use std::fs::OpenOptions;
use std::io::BufWriter;
use std::io::Result;
use time::{now, Tm};

// Internal modules:
use configuration::{Configuration, HEADER_LENGTH};
use data_parser::{parse_text_data, StationDataType};

fn write_xml_data(tm: Tm, local_port: u16, data: &StationDataType, file_name: &str) -> Result<()> {
    let mut file_handle = BufWriter::new(try!(OpenOptions::new()
        .write(true).create(true).append(true).open(format!("{}.xml", file_name))));

    let current_date_time = tm.strftime("%Y.%m.%d - %H:%M:%S").unwrap();

    try!(write!(file_handle, "<measure>\n"));
    try!(write!(file_handle, "<port>{}</port>\n", local_port));
    try!(write!(file_handle, "<date_time>{}</date_time>\n", &current_date_time));
    try!(write!(file_handle, "<data>\n"));

    // try!(write!(file_handle, "{:?}\n", data));

    match data {
        &StationDataType::SingleData(time_stamp_tm, voltage) => {
            if let Ok(time_stamp) = time_stamp_tm.strftime("%Y-%m-%d %H:%M:%S") {
                try!(write!(file_handle, "    <time_stamp>{}</time_stamp>\n", time_stamp));
                try!(write!(file_handle, "    <voltage>{}</voltage>\n", voltage));
            }
        },
        &StationDataType::MultipleData(ref full_data_set) => {
            if let Ok(time_stamp) = full_data_set.time_stamp.strftime("%Y-%m-%d %H:%M:%S") {
                try!(write!(file_handle, "    <time_stamp>{}</time_stamp>\n", time_stamp));
                try!(write!(file_handle, "    <air_temperature>{}</air_temperature>\n", full_data_set.air_temperature));
                try!(write!(file_handle, "    <air_relative_humidity>{}</air_relative_humidity>\n", full_data_set.air_relative_humidity));
                try!(write!(file_handle, "    <solar_radiation>{}</solar_radiation>\n", full_data_set.solar_radiation));
                try!(write!(file_handle, "    <soil_water_content>{}</soil_water_content>\n", full_data_set.soil_water_content));
                try!(write!(file_handle, "    <soil_temperature>{}</soil_temperature>\n", full_data_set.soil_temperature));
                try!(write!(file_handle, "    <wind_speed>{}</wind_speed>\n", full_data_set.wind_speed));
                try!(write!(file_handle, "    <wind_max>{}</wind_max>\n", full_data_set.wind_max));
                try!(write!(file_handle, "    <wind_direction>{}</wind_direction>\n", full_data_set.wind_direction));
                try!(write!(file_handle, "    <percipitation>{}</percipitation>\n", full_data_set.percipitation));
                try!(write!(file_handle, "    <air_pressure>{}</air_pressure>\n", full_data_set.air_pressure));
            }
        }
    }

    try!(write!(file_handle, "</data>\n"));
    try!(write!(file_handle, "</measure>\n\n"));

    Ok(())
}

fn write_csv_data(data: &StationDataType, file_name: &str) -> Result<()> {
    let mut file_handle = BufWriter::new(try!(OpenOptions::new()
        .write(true).create(true).append(true).open(format!("{}.csv", file_name))));

        match data {
            &StationDataType::SingleData(time_stamp_tm, voltage) => {
                if let Ok(time_stamp) = time_stamp_tm.strftime("%Y-%m-%d %H:%M:%S") {
                    try!(write!(file_handle, "\"{}\", {}\n", time_stamp, voltage));
                }
            },
            &StationDataType::MultipleData(ref full_data_set) => {
                if let Ok(time_stamp) = full_data_set.time_stamp.strftime("%Y-%m-%d %H:%M:%S") {
                    try!(write!(file_handle, "\"{}\", {}, {}, {}, {}, {}, {}, {}, {}, {}, {}\n",
                        time_stamp,
                        full_data_set.air_temperature,
                        full_data_set.air_relative_humidity,
                        full_data_set.solar_radiation,
                        full_data_set.soil_water_content,
                        full_data_set.soil_temperature,
                        full_data_set.wind_speed,
                        full_data_set.wind_max,
                        full_data_set.wind_direction,
                        full_data_set.percipitation,
                        full_data_set.air_pressure
                    ));
                }
            }
        }

    Ok(())
}

fn port_to_station(port: u16) -> String{
    match port {
        2100 => "2100_Na".to_string(),
        2101 => "2101_SG".to_string(),
        2102 => "2102_PdA".to_string(),
        2103 => "2103_LC".to_string(),
        2104 => "2104_Tue".to_string(),
        _ => "unknown".to_string()
    }
}

fn handle_client(stream: &mut TcpStream, remote_addr: &SocketAddr,
    all_data_file: &Arc<Mutex<String>>, monthly_data_folder: &Arc<Mutex<String>>) -> Result<()> {
    info!("Client socket address: {}", remote_addr);

    let local_addr = try!(stream.local_addr());

    let local_port = match local_addr {
        SocketAddr::V4(local_addr) => local_addr.port(),
        SocketAddr::V6(local_addr) => local_addr.port()
    };

    info!("Port: {}", local_port);

    let mut buffer = Vec::new();

    let len = try!(stream.read_to_end(&mut buffer));
    info!("Number of bytes received: {}", len);

    if buffer.len() > HEADER_LENGTH {
        let (buffer_left, buffer_right) = buffer.split_at(HEADER_LENGTH);

        let str_header = String::from_utf8_lossy(buffer_left);
        let str_data = String::from_utf8_lossy(buffer_right);

        info!("Header: {:?}", buffer_left);
        info!("Data: {:?}", buffer_right);

        info!("Header (ASCII): '{}'", str_header);
        info!("Data (ASCII): '{}'", str_data);

        let station_folder = port_to_station(local_port);

        match parse_text_data(&buffer_right) {
            Ok(parsed_data) => {
                info!("Data parsed correctly");
                match all_data_file.lock() {
                    Ok(all_data_file) => {
                        let tm = now();
                        let file_name = format!("{}/{}", station_folder, *all_data_file);
                        try!(write_xml_data(tm, local_port, &parsed_data, &file_name));
                        try!(write_csv_data(&parsed_data, &file_name));
                    },
                    Err(e) => info!("Mutex (poison) error (all_data_file): {}", e)
                }

                match monthly_data_folder.lock() {
                    Ok(monthly_data_folder) => {
                        let tm = now();
                        let current_year = tm.strftime("%Y").unwrap();
                        let current_month = tm.strftime("%m").unwrap();
                        // TODO: create separate folder for year and month in Rust
                        let file_name = format!("{}/{}/{}_{}", *monthly_data_folder, station_folder, current_year, current_month);
                        try!(write_xml_data(tm, local_port, &parsed_data, &file_name));
                        try!(write_csv_data(&parsed_data, &file_name));
                    },
                    Err(e) => info!("Mutex (poison) error (monthly_data_folder): {}", e)
                }

            },
            Err(e) => {
                info!("Could not parse data: {}", e);
            }
        }
    } else if buffer.len() < HEADER_LENGTH {
        info!("Invalid header (less than {} bytes received)!", HEADER_LENGTH);
        info!("Bytes: {:?}", buffer);
        info!("Bytes (ASCII): '{}'", String::from_utf8_lossy(&buffer));
    } else { // buffer.len() == HEADER_LENGTH -> no data, only header
        info!("No data received, just header.");
        info!("Bytes: {:?}", buffer);
        info!("Bytes (ASCII): '{}'", String::from_utf8_lossy(&buffer));
    }

    info!("handle_client finished");

    Ok(())
}

pub fn start_service(config: Configuration) {
    let mut listeners = Vec::new();

    for port in config.ports {
        match TcpListener::bind(("0.0.0.0", port)) {
            Ok(listener) => {
                info!("Create listener for port {}", port);
                listeners.push(listener);
            },
            Err(e) => info!("Network error: {}", e)
        }
    }

    let all_data_file = Arc::new(Mutex::new(config.all_data_file.clone()));
    let monthly_data_folder = Arc::new(Mutex::new(config.monthly_data_folder.clone()));

    for listener in listeners {
        let all_data_file = all_data_file.clone();
        let monthly_data_folder = monthly_data_folder.clone();
        spawn(move|| {
            loop {
                let result = listener.accept();
                if let Ok(result) = result {
                    let (mut stream, addr) = result;
                    if let Err(io_error) = handle_client(&mut stream, &addr,
                            &all_data_file, &monthly_data_folder) {
                        info!("IOError: {}", io_error);
                    }
                }
            }
        });
    }
}
<|endoftext|>


<commit_before>extern crate serialize;
extern crate sync;

use std::comm::Data;
use std::io::{Acceptor,InvalidInput,IoError,IoResult,Listener,Timer};
use std::io::timer;
use std::io::net::ip::{Ipv4Addr,SocketAddr};
use std::io::net::tcp::{TcpListener,TcpStream};
use std::sync::atomics::{AtomicBool,AcqRel,INIT_ATOMIC_BOOL};

// use std::comm::{Empty, Data, Disconnected};

use log::Log;
use serror::{InvalidArgument,InvalidState,SError};

mod log;
mod log_entry;
pub mod serror;

// static DEFAULT_HEARTBEAT_INTERVAL: uint = 50;   // in millis
// static DEFAULT_ELECTION_TIMEOUT  : uint = 150;  // in millis

static mut stop: AtomicBool = INIT_ATOMIC_BOOL;

/* ---[ data structures ]--- */

#[deriving(Clone, Eq)]
pub enum State {
    Stopped,
    Follower,
    Candidate,
    Leader,
    Snapshotting
}

pub struct Server {
    ip: ~str,
    tcpport: uint,
    name: ~str,
    path: Path,
    state: State,
    current_term: u64,
	conx_str: ~str,

    priv log: ~Log,  // TODO: should this just be Log (on stack => can it be copied arnd?)

    c: Sender<~Event>,  // TODO: keep chan or port?
    p: Receiver<~Event>,
    // more later
}

pub struct Event {
    msg: ~str,  // bogus => just to get started
    // target: ??,
    // return_val: ??,
    // c: Sender<SError>,   // TODO: chan or port?  // TODO: what errors?
}

/* ---[ functions ]--- */

impl Server {
    pub fn new(name: ~str, logpath: Path, ipaddr: ~str, tcpport: uint) -> IoResult<~Server> {

        if name == ~"" {
            return Err(IoError{
                kind: InvalidInput,
                desc: "server name cannot be blank",
                detail: None,
            });
        }
        let (ch, pt): (Sender<~Event>, Receiver<~Event>) = channel();

        let lg = try!(Log::new(logpath.clone()));
        let conx_str = format!("{}:{:u}", &ipaddr, tcpport);

        let s = ~Server {
            ip: ipaddr,
            tcpport: tcpport,  // TODO: could we use udp instead? are we doing our own ACKs at the app protocol level?
            name: name,
            path: logpath,
            state: Stopped,
            current_term: 0,
            conx_str: conx_str,  // TODO: what the hell is this for? (from goraft)
            log: lg,
            c: ch,
            p: pt,
        };

        Ok(s)
    }

    ///
    /// Central method that sets things up and then runs the server threads/tasks
    ///
    pub fn run(&mut self) -> Result<(), SError> {
        if self.state != Stopped {
            return Err(InvalidState(~"schooner.Server: Server already running"));
        }

        self.current_term = self.log.curr_term;
        self.state = Follower;

        let event_chan = self.c.clone();
        let conx_str = self.conx_str.clone();
        spawn(proc() {
            // needs to be a separate file/impl
            network_listener(conx_str, event_chan);
        });

        self.serve_loop();

        Ok(())
    }

    fn serve_loop(&mut self) {
        println!("Now serving => loop until Stopped");
        loop {
            match self.state {
                Follower     => self.follower_loop(),
                Candidate    => self.candidate_loop(),
                Leader       => self.leader_loop(),
                Snapshotting => self.snapshotting_loop(),
                Stopped      => break
            }
            std::io::timer::sleep(1);
        }
        println!("Serve_loop END");
    }

    fn follower_loop(&mut self) {
        // let mut stopsig = unsafe{ stop.load(AcqRel) };
        // let mut timer = Timer::new().unwrap();

        loop {
            println!("FLW: DEBUG 0");

            // TODO: use select with timeout so doesn't block forever?
            let ev = self.p.recv();
            println!("follower: event message: {}", ev.msg);
            println!("FLW: DEBUG 1 {:?} :: {:?}", ev.msg, is_stop_msg(ev.msg));

            if is_stop_msg(ev.msg) {
                println!("FLW: DEBUG 2");
                unsafe{ stop.store(true, AcqRel); }
                self.state = Stopped;
                break;
            }
            println!("FLW: DEBUG 3");
        }

        // while !stopsig {
            //     let timeout = timer.oneshot(1000);
            //     // TODO: need a select! stmt here with a timeout channel
            //     select! (
            //         ev = self.p.recv() => println!("event message: {}", ev.msg),
            //         () = timeout.recv() => {}
            //     )
            //     stopsig = unsafe{ stop.load(AcqRel) };
            //     println!("follower loop; stop signal is: {:?}", stopsig);
            // }
    }

    fn candidate_loop(&mut self) {
        println!("candidate loop");
        self.state = Leader;
    }

    fn leader_loop(&mut self) {
        println!("leader loop");
        self.state = Snapshotting;
    }
    fn snapshotting_loop(&mut self) {
        println!("snapshotting loop");
        self.state = Follower;
    }
}

fn network_listener(conx_str: ~str, chan: Sender<~Event>) {
    let addr = from_str::<SocketAddr>(conx_str).expect("Address error.");
    let mut acceptor = TcpListener::bind(addr).unwrap().listen();
    println!("server <name> listening on {:}", addr);

    for mut stream in acceptor.incoming() {
        println!("NL: DEBUG 0");
        // TODO: only handling one request at a time for now => spawn threads later?
        match stream.read_to_str() {
            Ok(input)  => {
                if is_stop_msg(input) {
                    println!("NL: DEBUG 1");
                    unsafe { stop.store(true, AcqRel) }
                }
                let ev = ~Event{msg: input};
                chan.send(ev);
                println!("NL: DEBUG 2");
            },
            Err(ioerr) => println!("ERROR: {:?}", ioerr)
        }
        unsafe {
            println!("NL: DEBUG 3: {:?}", stop.load(AcqRel));
            if stop.load(AcqRel) {
                println!("NL: DEBUG 4");
                break;
            }
            println!("NL: DEBUG 5");
        }
    }

    println!("network listener shutting down ...");
}

fn is_stop_msg(s: &str) -> bool {
    s == "STOP"
}

fn test_client(ipaddr: ~str, port: uint) {
    println!("{:?}", ipaddr);
    println!("{:?}", port);

    spawn(proc() {
        timer::sleep(2888);
        println!("Client sending stop message");

        let addr = SocketAddr { ip: Ipv4Addr(127, 0, 0, 1), port: port as u16 };
        let mut stream = TcpStream::connect(addr);

        let result = stream.write_str("STOP");
        if result.is_err() {
            println!("Client ERROR: {:?}", result.err());
        }
        drop(stream); // close the connection
    });
}

fn main() {
    let name = ~"S1";
    let path = Path::new(~"datalog/S1");
    let ipaddr = ~"127.0.0.1";
    let port = 23158;

    println!("Now starting test client");
    test_client(ipaddr.clone(), port);

    let result = Server::new(name, path, ipaddr, port);
    if result.is_err() {
        error!("{:?}", result.err());
        return;
    }

    let mut s = result.unwrap();
    match s.run() {
        Ok(_) => (),
        Err(e) => println!("ERROR: {:?}", e)
    }

}
<commit_msg>Have timeout channel and manual Select in follower_loop.<commit_after>extern crate serialize;
extern crate sync;

use std::comm::Select;
use std::io::{Acceptor,InvalidInput,IoError,IoResult,Listener,Timer};
use std::io::timer;
use std::io::net::ip::{Ipv4Addr,SocketAddr};
use std::io::net::tcp::{TcpListener,TcpStream};
use std::sync::atomics::{AtomicBool,AcqRel,INIT_ATOMIC_BOOL};

// use std::comm::{Empty, Data, Disconnected};

use log::Log;
use serror::{InvalidArgument,InvalidState,SError};

mod log;
mod log_entry;
pub mod serror;

// static DEFAULT_HEARTBEAT_INTERVAL: uint = 50;   // in millis
// static DEFAULT_ELECTION_TIMEOUT  : uint = 150;  // in millis

static mut stop: AtomicBool = INIT_ATOMIC_BOOL;

/* ---[ data structures ]--- */

#[deriving(Clone, Eq)]
pub enum State {
    Stopped,
    Follower,
    Candidate,
    Leader,
    Snapshotting
}

pub struct Server {
    ip: ~str,
    tcpport: uint,
    name: ~str,
    path: Path,
    state: State,
    current_term: u64,
	conx_str: ~str,

    priv log: ~Log,  // TODO: should this just be Log (on stack => can it be copied arnd?)

    c: Sender<~Event>,  // TODO: keep chan or port?
    p: Receiver<~Event>,
    // more later
}

pub struct Event {
    msg: ~str,  // bogus => just to get started
    // target: ??,
    // return_val: ??,
    // c: Sender<SError>,   // TODO: chan or port?  // TODO: what errors?
}

/* ---[ functions ]--- */

impl Server {
    pub fn new(name: ~str, logpath: Path, ipaddr: ~str, tcpport: uint) -> IoResult<~Server> {

        if name == ~"" {
            return Err(IoError{
                kind: InvalidInput,
                desc: "server name cannot be blank",
                detail: None,
            });
        }
        let (ch, pt): (Sender<~Event>, Receiver<~Event>) = channel();

        let lg = try!(Log::new(logpath.clone()));
        let conx_str = format!("{}:{:u}", &ipaddr, tcpport);

        let s = ~Server {
            ip: ipaddr,
            tcpport: tcpport,  // TODO: could we use udp instead? are we doing our own ACKs at the app protocol level?
            name: name,
            path: logpath,
            state: Stopped,
            current_term: 0,
            conx_str: conx_str,  // TODO: what the hell is this for? (from goraft)
            log: lg,
            c: ch,
            p: pt,
        };

        Ok(s)
    }

    ///
    /// Central method that sets things up and then runs the server threads/tasks
    ///
    pub fn run(&mut self) -> Result<(), SError> {
        if self.state != Stopped {
            return Err(InvalidState(~"schooner.Server: Server already running"));
        }

        self.current_term = self.log.curr_term;
        self.state = Follower;

        let event_chan = self.c.clone();
        let conx_str = self.conx_str.clone();
        spawn(proc() {
            // needs to be a separate file/impl
            network_listener(conx_str, event_chan);
        });

        self.serve_loop();

        Ok(())
    }

    fn serve_loop(&mut self) {
        println!("Now serving => loop until Stopped");
        loop {
            match self.state {
                Follower     => self.follower_loop(),
                Candidate    => self.candidate_loop(),
                Leader       => self.leader_loop(),
                Snapshotting => self.snapshotting_loop(),
                Stopped      => break
            }
            std::io::timer::sleep(1);
        }
        println!("Serve_loop END");
    }

    fn follower_loop(&mut self) {
        // let mut stopsig = unsafe{ stop.load(AcqRel) };
        let mut timer = Timer::new().unwrap();

        loop {
            println!("FLW: DEBUG 0");
            let timeout = timer.oneshot(1000); // use for detecting lost leader

            let sel = Select::new();
            let mut pt = sel.handle(&self.p);
            let mut timeout = sel.handle(&timeout);
            unsafe{
                pt.add();
                timeout.add();
            }
            let ret = sel.wait();

            if ret == timeout.id() {
                let () = timeout.recv(); // TODO: hvae to capture output?
                println!("FWL: TIMEOUT!! => change state to Candidate");
                self.state = Candidate;
                break;

            } else if ret == pt.id() {
                let ev = pt.recv();
                println!("follower: event message: {}", ev.msg);
                println!("FLW: DEBUG 1 {:?} :: {:?}", ev.msg, is_stop_msg(ev.msg));
                if is_stop_msg(ev.msg) {
                    println!("FLW: DEBUG 2");
                    unsafe{ stop.store(true, AcqRel); }
                    self.state = Stopped;
                    break;
                }
                println!("FLW: DEBUG 3");
            }
        }
    }

    fn candidate_loop(&mut self) {
        println!("candidate loop");
        self.state = Leader;
    }

    fn leader_loop(&mut self) {
        println!("leader loop");
        self.state = Snapshotting;
    }
    fn snapshotting_loop(&mut self) {
        println!("snapshotting loop");
        self.state = Follower;
    }
}

fn network_listener(conx_str: ~str, chan: Sender<~Event>) {
    let addr = from_str::<SocketAddr>(conx_str).expect("Address error.");
    let mut acceptor = TcpListener::bind(addr).unwrap().listen();
    println!("server <name> listening on {:}", addr);

    for mut stream in acceptor.incoming() {
        println!("NL: DEBUG 0");
        // TODO: only handling one request at a time for now => spawn threads later?
        match stream.read_to_str() {
            Ok(input)  => {
                if is_stop_msg(input) {
                    println!("NL: DEBUG 1");
                    unsafe { stop.store(true, AcqRel) }
                }
                let ev = ~Event{msg: input};
                chan.send(ev);
                println!("NL: DEBUG 2");
            },
            Err(ioerr) => println!("ERROR: {:?}", ioerr)
        }
        unsafe {
            println!("NL: DEBUG 3: {:?}", stop.load(AcqRel));
            if stop.load(AcqRel) {
                println!("NL: DEBUG 4");
                break;
            }
            println!("NL: DEBUG 5");
        }
    }

    println!("network listener shutting down ...");
}

fn is_stop_msg(s: &str) -> bool {
    s == "STOP"
}

fn test_client(ipaddr: ~str, port: uint) {
    println!("{:?}", ipaddr);
    println!("{:?}", port);

    spawn(proc() {
        timer::sleep(1299);
        println!("Client sending stop message");

        let addr = SocketAddr { ip: Ipv4Addr(127, 0, 0, 1), port: port as u16 };
        let mut stream = TcpStream::connect(addr);

        let result = stream.write_str("STOP");
        if result.is_err() {
            println!("Client ERROR: {:?}", result.err());
        }
        drop(stream); // close the connection
    });
}

fn main() {
    let name = ~"S1";
    let path = Path::new(~"datalog/S1");
    let ipaddr = ~"127.0.0.1";
    let port = 23158;

    println!("Now starting test client");
    test_client(ipaddr.clone(), port);

    let result = Server::new(name, path, ipaddr, port);
    if result.is_err() {
        error!("{:?}", result.err());
        return;
    }

    let mut s = result.unwrap();
    match s.run() {
        Ok(_) => (),
        Err(e) => println!("ERROR: {:?}", e)
    }

}
<|endoftext|>


<commit_before>use std::thread;
use std::net::SocketAddr;
use std::net::ToSocketAddrs;
use std::collections::HashMap;
use std::sync::mpsc;
use std::sync::Arc;
use std::sync::Mutex;
use std::io;

use tls_api;

use tokio_core::reactor;
use tokio_core::net::TcpListener;

use futures::future;
use futures::future::Future;
use futures::future::join_all;
use futures::stream;
use futures::stream::Stream;

use futures_cpupool;

use exec::CpuPoolOption;

use error::Error;
use result::Result;

use solicit_async::*;

use futures_misc::*;

use net2;

use tls_api::TlsAcceptor;
use tls_api_stub;

use super::server_conn::*;
use super::common::*;

use service::Service;
use service_paths::ServicePaths;

use server_conf::*;

pub use server_tls::ServerTlsOption;

struct LoopToServer {
    local_addr: SocketAddr,
}

pub struct ServerBuilder<A : tls_api::TlsAcceptor = tls_api_stub::TlsAcceptor> {
    pub conf: ServerConf,
    pub cpu_pool: CpuPoolOption,
    pub tls: ServerTlsOption<A>,
    pub addr: Option<SocketAddr>,
    pub service: ServicePaths,
}

impl ServerBuilder<tls_api_stub::TlsAcceptor> {
    /// New server builder with defaults.
    ///
    /// Port must be set, other properties are optional.
    pub fn new_plain() -> ServerBuilder<tls_api_stub::TlsAcceptor> {
        ServerBuilder::new()
    }
}

impl<A : tls_api::TlsAcceptor> ServerBuilder<A> {
    /// New server builder with defaults.
    ///
    /// To call this function `ServerBuilder` must be parameterized with TLS acceptor.
    /// If TLS is not needed, `ServerBuilder::new_plain` function can be used.
    ///
    /// Port must be set, other properties are optional.
    pub fn new() -> ServerBuilder<A> {
        ServerBuilder {
            conf: ServerConf::new(),
            cpu_pool: CpuPoolOption::SingleThread,
            tls: ServerTlsOption::Plain,
            addr: None,
            service: ServicePaths::new(),
        }
    }

    /// Create a CPU pool, and use it in HTTP server
    pub fn set_cpu_pool_threads(&mut self, threads: usize) {
        let cpu_pool = futures_cpupool::Builder::new()
            .pool_size(threads)
            .name_prefix("httpbis-server-")
            .create();
        self.cpu_pool = CpuPoolOption::CpuPool(cpu_pool);
    }

    pub fn set_tls(&mut self, acceptor: A) {
        self.tls = ServerTlsOption::Tls(Arc::new(acceptor));
    }

    /// Set port server listens on.
    /// Can be zero to bind on any available port,
    /// which can be later obtained by `Server::local_addr`.
    pub fn set_port(&mut self, port: u16) {
        self.set_addr(("::", port)).expect("set_addr");
    }

    /// Set port server listens on.
    pub fn set_addr<S : ToSocketAddrs>(&mut self, addr: S) -> Result<()> {
        let addrs: Vec<_> = addr.to_socket_addrs()?.collect();
        if addrs.is_empty() {
            return Err(Error::Other("addr is resolved to empty list"));
        } else if addrs.len() > 1 {
            return Err(Error::Other("addr is resolved to more than one addr"));
        }
        self.addr = Some(addrs.into_iter().next().unwrap());
        Ok(())
    }

    pub fn build(self) -> Result<Server> {
        let addr = self.addr.expect("listen addr is unset");

        let listen_addr = addr.to_socket_addrs()?.next().unwrap();

        let (get_from_loop_tx, get_from_loop_rx) = mpsc::channel();
        let (alive_tx, alive_rx) = mpsc::channel();

        let state: Arc<Mutex<ServerState>> = Default::default();

        let state_copy = state.clone();

        let (shutdown_signal, shutdown_future) = shutdown_signal();

        let join_handle = thread::Builder::new()
            .name(self.conf.thread_name.clone().unwrap_or_else(|| "http2-server-loop".to_owned()).to_string())
            .spawn(move || {
                run_server_event_loop(
                    listen_addr,
                    state_copy,
                    self.tls,
                    self.cpu_pool,
                    shutdown_future,
                    self.conf,
                    self.service,
                    get_from_loop_tx,
                    alive_tx);
            })?;

        let loop_to_server = get_from_loop_rx.recv()
            .map_err(|_| Error::Other("failed to recv from event loop"))?;

        Ok(Server {
            state: state,
            shutdown: shutdown_signal,
            loop_to_server: loop_to_server,
            thread_join_handle: Some(join_handle),
            alive_rx: alive_rx,
        })
    }
}

pub struct Server {
    state: Arc<Mutex<ServerState>>,
    loop_to_server: LoopToServer,
    shutdown: ShutdownSignal,
    alive_rx: mpsc::Receiver<()>,
    thread_join_handle: Option<thread::JoinHandle<()>>,
}

#[derive(Default)]
struct ServerState {
    last_conn_id: u64,
    conns: HashMap<u64, ServerConnection>,
}

impl ServerState {
    fn snapshot(&self) -> HttpFutureSend<ServerStateSnapshot> {
        let futures: Vec<_> = self.conns.iter()
            .map(|(&id, conn)| conn.dump_state().map(move |state| (id, state)))
            .collect();

        Box::new(join_all(futures)
            .map(|states| ServerStateSnapshot {
                conns: states.into_iter().collect(),
            }))
    }
}

pub struct ServerStateSnapshot {
    pub conns: HashMap<u64, ConnectionStateSnapshot>,
}

impl ServerStateSnapshot {
    pub fn single_conn(&self) -> (u64, &ConnectionStateSnapshot) {
        let mut iter = self.conns.iter();
        let (&id, conn) = iter.next().expect("no conns");
        assert!(iter.next().is_none(), "more than one conn");
        (id, conn)
    }
}

#[cfg(unix)]
fn configure_tcp(tcp: &net2::TcpBuilder, conf: &ServerConf) -> io::Result<()> {
    use net2::unix::UnixTcpBuilderExt;
    if let Some(reuse_port) = conf.reuse_port {
        tcp.reuse_port(reuse_port)?;
    }
    Ok(())
}

#[cfg(windows)]
fn configure_tcp(_tcp: &net2::TcpBuilder, conf: &ServerConf) -> io::Result<()> {
    Ok(())
}

fn listener(
    addr: &SocketAddr,
    handle: &reactor::Handle,
    conf: &ServerConf)
        -> io::Result<TcpListener>
{
    let listener = match *addr {
        SocketAddr::V4(_) => net2::TcpBuilder::new_v4()?,
        SocketAddr::V6(_) => net2::TcpBuilder::new_v6()?,
    };
    configure_tcp(&listener, conf)?;
    listener.reuse_address(true)?;
    listener.bind(addr)?;
    let backlog = conf.backlog.unwrap_or(1024);
    let listener = listener.listen(backlog)?;
    TcpListener::from_listener(listener, addr, handle)
}

fn run_server_event_loop<S, A>(
    listen_addr: SocketAddr,
    state: Arc<Mutex<ServerState>>,
    tls: ServerTlsOption<A>,
    exec: CpuPoolOption,
    shutdown_future: ShutdownFuture,
    conf: ServerConf,
    service: S,
    send_to_back: mpsc::Sender<LoopToServer>,
    _alive_tx: mpsc::Sender<()>)
        where S : Service, A : TlsAcceptor,
{
    let service = Arc::new(service);

    let mut lp = reactor::Core::new().expect("http2server");

    let listen = listener(&listen_addr, &lp.handle(), &conf).unwrap();

    let stuff = stream::repeat((lp.handle(), service, state, tls, conf));

    let local_addr = listen.local_addr().unwrap();
    send_to_back
        .send(LoopToServer { local_addr: local_addr })
        .expect("send back");

    let loop_run = listen.incoming().map_err(Error::from).zip(stuff)
        .for_each(move |((socket, peer_addr), (loop_handle, service, state, tls, conf))| {
            info!("accepted connection from {}", peer_addr);

            let no_delay = conf.no_delay.unwrap_or(true);
            socket.set_nodelay(no_delay).expect("failed to set TCP_NODELAY");

            let (conn, future) = ServerConnection::new(
                &loop_handle, socket, tls, exec.clone(), conf, service);

            let conn_id = {
                let mut g = state.lock().expect("lock");
                g.last_conn_id += 1;
                let conn_id = g.last_conn_id;
                let prev = g.conns.insert(conn_id, conn);
                assert!(prev.is_none());
                conn_id
            };

            loop_handle.spawn(future
                .then(move |r| {
                    let mut g = state.lock().expect("lock");
                    let removed = g.conns.remove(&conn_id);
                    assert!(removed.is_some());
                    r
                })
                .map_err(|e| { warn!("connection end: {:?}", e); () }));
            Ok(())
        });

    let shutdown_future = shutdown_future
        .then(move |_| {
            // Must complete with error,
            // so `join` with this future cancels another future.
            future::failed::<(), _>(Error::Shutdown)
        });

    // Wait for either completion of connection (i. e. error)
    // or shutdown signal.
    let done = loop_run.join(shutdown_future);

    // TODO: do not ignore error
    lp.run(done).ok();
}

impl Server {
    pub fn local_addr(&self) -> &SocketAddr {
        &self.loop_to_server.local_addr
    }

    pub fn is_alive(&self) -> bool {
        self.alive_rx.try_recv() != Err(mpsc::TryRecvError::Disconnected)
    }

    // for tests
    pub fn dump_state(&self) -> HttpFutureSend<ServerStateSnapshot> {
        let g = self.state.lock().expect("lock");
        g.snapshot()
    }
}

// We shutdown the server in the destructor.
impl Drop for Server {
    fn drop(&mut self) {
        self.shutdown.shutdown();

        // do not ignore errors of take
        // ignore errors of join, it means that server event loop crashed
        drop(self.thread_join_handle.take().unwrap().join());
    }
}

<commit_msg>Create listening socket in `build`<commit_after>use std::thread;
use std::net::SocketAddr;
use std::net::ToSocketAddrs;
use std::collections::HashMap;
use std::sync::mpsc;
use std::sync::Arc;
use std::sync::Mutex;
use std::io;

use tls_api;

use tokio_core::reactor;
use tokio_core::net::TcpListener;

use futures::future;
use futures::future::Future;
use futures::future::join_all;
use futures::stream;
use futures::stream::Stream;

use futures_cpupool;

use exec::CpuPoolOption;

use error::Error;
use result::Result;

use solicit_async::*;

use futures_misc::*;

use net2;

use tls_api::TlsAcceptor;
use tls_api_stub;

use super::server_conn::*;
use super::common::*;

use service::Service;
use service_paths::ServicePaths;

use server_conf::*;

pub use server_tls::ServerTlsOption;

pub struct ServerBuilder<A : tls_api::TlsAcceptor = tls_api_stub::TlsAcceptor> {
    pub conf: ServerConf,
    pub cpu_pool: CpuPoolOption,
    pub tls: ServerTlsOption<A>,
    pub addr: Option<SocketAddr>,
    pub service: ServicePaths,
}

impl ServerBuilder<tls_api_stub::TlsAcceptor> {
    /// New server builder with defaults.
    ///
    /// Port must be set, other properties are optional.
    pub fn new_plain() -> ServerBuilder<tls_api_stub::TlsAcceptor> {
        ServerBuilder::new()
    }
}

impl<A : tls_api::TlsAcceptor> ServerBuilder<A> {
    /// New server builder with defaults.
    ///
    /// To call this function `ServerBuilder` must be parameterized with TLS acceptor.
    /// If TLS is not needed, `ServerBuilder::new_plain` function can be used.
    ///
    /// Port must be set, other properties are optional.
    pub fn new() -> ServerBuilder<A> {
        ServerBuilder {
            conf: ServerConf::new(),
            cpu_pool: CpuPoolOption::SingleThread,
            tls: ServerTlsOption::Plain,
            addr: None,
            service: ServicePaths::new(),
        }
    }

    /// Create a CPU pool, and use it in HTTP server
    pub fn set_cpu_pool_threads(&mut self, threads: usize) {
        let cpu_pool = futures_cpupool::Builder::new()
            .pool_size(threads)
            .name_prefix("httpbis-server-")
            .create();
        self.cpu_pool = CpuPoolOption::CpuPool(cpu_pool);
    }

    pub fn set_tls(&mut self, acceptor: A) {
        self.tls = ServerTlsOption::Tls(Arc::new(acceptor));
    }

    /// Set port server listens on.
    /// Can be zero to bind on any available port,
    /// which can be later obtained by `Server::local_addr`.
    pub fn set_port(&mut self, port: u16) {
        self.set_addr(("::", port)).expect("set_addr");
    }

    /// Set port server listens on.
    pub fn set_addr<S : ToSocketAddrs>(&mut self, addr: S) -> Result<()> {
        let addrs: Vec<_> = addr.to_socket_addrs()?.collect();
        if addrs.is_empty() {
            return Err(Error::Other("addr is resolved to empty list"));
        } else if addrs.len() > 1 {
            return Err(Error::Other("addr is resolved to more than one addr"));
        }
        self.addr = Some(addrs.into_iter().next().unwrap());
        Ok(())
    }

    pub fn build(self) -> Result<Server> {
        let addr = self.addr.expect("listen addr is unset");

        let listen_addr = addr.to_socket_addrs()?.next().unwrap();

        let (alive_tx, alive_rx) = mpsc::channel();

        let state: Arc<Mutex<ServerState>> = Default::default();

        let state_copy = state.clone();

        let (shutdown_signal, shutdown_future) = shutdown_signal();

        let listen = listener(&listen_addr, &self.conf)?;

        let local_addr = listen.local_addr().unwrap();

        let join_handle = thread::Builder::new()
            .name(self.conf.thread_name.clone().unwrap_or_else(|| "http2-server-loop".to_owned()).to_string())
            .spawn(move || {
                run_server_event_loop(
                    listen_addr,
                    state_copy,
                    self.tls,
                    listen,
                    self.cpu_pool,
                    shutdown_future,
                    self.conf,
                    self.service,
                    alive_tx);
            })?;

        Ok(Server {
            state: state,
            shutdown: shutdown_signal,
            local_addr: local_addr,
            thread_join_handle: Some(join_handle),
            alive_rx: alive_rx,
        })
    }
}

pub struct Server {
    state: Arc<Mutex<ServerState>>,
    local_addr: SocketAddr,
    shutdown: ShutdownSignal,
    alive_rx: mpsc::Receiver<()>,
    thread_join_handle: Option<thread::JoinHandle<()>>,
}

#[derive(Default)]
struct ServerState {
    last_conn_id: u64,
    conns: HashMap<u64, ServerConnection>,
}

impl ServerState {
    fn snapshot(&self) -> HttpFutureSend<ServerStateSnapshot> {
        let futures: Vec<_> = self.conns.iter()
            .map(|(&id, conn)| conn.dump_state().map(move |state| (id, state)))
            .collect();

        Box::new(join_all(futures)
            .map(|states| ServerStateSnapshot {
                conns: states.into_iter().collect(),
            }))
    }
}

pub struct ServerStateSnapshot {
    pub conns: HashMap<u64, ConnectionStateSnapshot>,
}

impl ServerStateSnapshot {
    pub fn single_conn(&self) -> (u64, &ConnectionStateSnapshot) {
        let mut iter = self.conns.iter();
        let (&id, conn) = iter.next().expect("no conns");
        assert!(iter.next().is_none(), "more than one conn");
        (id, conn)
    }
}

#[cfg(unix)]
fn configure_tcp(tcp: &net2::TcpBuilder, conf: &ServerConf) -> io::Result<()> {
    use net2::unix::UnixTcpBuilderExt;
    if let Some(reuse_port) = conf.reuse_port {
        tcp.reuse_port(reuse_port)?;
    }
    Ok(())
}

#[cfg(windows)]
fn configure_tcp(_tcp: &net2::TcpBuilder, conf: &ServerConf) -> io::Result<()> {
    Ok(())
}

fn listener(
    addr: &SocketAddr,
    conf: &ServerConf)
        -> io::Result<::std::net::TcpListener>
{
    let listener = match *addr {
        SocketAddr::V4(_) => net2::TcpBuilder::new_v4()?,
        SocketAddr::V6(_) => net2::TcpBuilder::new_v6()?,
    };
    configure_tcp(&listener, conf)?;
    listener.reuse_address(true)?;
    listener.bind(addr)?;
    let backlog = conf.backlog.unwrap_or(1024);
    listener.listen(backlog)
}

fn run_server_event_loop<S, A>(
    listen_addr: SocketAddr,
    state: Arc<Mutex<ServerState>>,
    tls: ServerTlsOption<A>,
    listen: ::std::net::TcpListener,
    exec: CpuPoolOption,
    shutdown_future: ShutdownFuture,
    conf: ServerConf,
    service: S,
    _alive_tx: mpsc::Sender<()>)
        where S : Service, A : TlsAcceptor,
{
    let service = Arc::new(service);

    let mut lp = reactor::Core::new().expect("http2server");

    let listen = TcpListener::from_listener(listen, &listen_addr, &lp.handle()).unwrap();

    let stuff = stream::repeat((lp.handle(), service, state, tls, conf));

    let loop_run = listen.incoming().map_err(Error::from).zip(stuff)
        .for_each(move |((socket, peer_addr), (loop_handle, service, state, tls, conf))| {
            info!("accepted connection from {}", peer_addr);

            let no_delay = conf.no_delay.unwrap_or(true);
            socket.set_nodelay(no_delay).expect("failed to set TCP_NODELAY");

            let (conn, future) = ServerConnection::new(
                &loop_handle, socket, tls, exec.clone(), conf, service);

            let conn_id = {
                let mut g = state.lock().expect("lock");
                g.last_conn_id += 1;
                let conn_id = g.last_conn_id;
                let prev = g.conns.insert(conn_id, conn);
                assert!(prev.is_none());
                conn_id
            };

            loop_handle.spawn(future
                .then(move |r| {
                    let mut g = state.lock().expect("lock");
                    let removed = g.conns.remove(&conn_id);
                    assert!(removed.is_some());
                    r
                })
                .map_err(|e| { warn!("connection end: {:?}", e); () }));
            Ok(())
        });

    let shutdown_future = shutdown_future
        .then(move |_| {
            // Must complete with error,
            // so `join` with this future cancels another future.
            future::failed::<(), _>(Error::Shutdown)
        });

    // Wait for either completion of connection (i. e. error)
    // or shutdown signal.
    let done = loop_run.join(shutdown_future);

    // TODO: do not ignore error
    lp.run(done).ok();
}

impl Server {
    pub fn local_addr(&self) -> &SocketAddr {
        &self.local_addr
    }

    pub fn is_alive(&self) -> bool {
        self.alive_rx.try_recv() != Err(mpsc::TryRecvError::Disconnected)
    }

    // for tests
    pub fn dump_state(&self) -> HttpFutureSend<ServerStateSnapshot> {
        let g = self.state.lock().expect("lock");
        g.snapshot()
    }
}

// We shutdown the server in the destructor.
impl Drop for Server {
    fn drop(&mut self) {
        self.shutdown.shutdown();

        // do not ignore errors of take
        // ignore errors of join, it means that server event loop crashed
        drop(self.thread_join_handle.take().unwrap().join());
    }
}

<|endoftext|>


<commit_before>use std::sync::Arc;
use std::collections::HashMap;
use std::net::ToSocketAddrs;

use mime_guess::guess_mime_type;

use hyper::Server;
use hyper::server::{Listening, Request, Response};
use hyper::uri::RequestUri;
use hyper::header::ContentType;
use hyper::status::StatusCode;

pub type StaticMap = HashMap<String, Vec<u8>>;

pub trait StaicProvider: Sync + Send + 'static {
	fn get_content(&self, path: &str) -> Option<&Vec<u8>>;
}

impl StaicProvider for StaticMap {
	fn get_content(&self, path: &str) -> Option<&Vec<u8>> {
		self.get(path)
	}
}

pub struct StaticWorker {
	listening: Listening,
}

impl Drop for StaticWorker {
	fn drop(&mut self) {
		let _ = self.listening.close();
	}
}

// TODO Add trait StaticMapCreater with fn(path) and update/read method
pub struct StaticServer {
	map: Arc<StaicProvider>,
}

impl StaticServer {

	pub fn new<T: StaicProvider>(map: T) -> Self {
		StaticServer { map: Arc::new(map) }
	}

	pub fn share<To: ToSocketAddrs>(&self, addr: To) -> Result<StaticWorker, ()> {
		let server = match Server::http(addr) {
			Ok(server) => server,
			Err(_) => return Err(()),
		};
		let map = self.map.clone();
		let handler = move |req: Request, mut res: Response| {
	    	match req.uri {
	    		RequestUri::AbsolutePath(mut apath) => {
	    			debug!("Request for static resource {}", apath);
	    			if apath.ends_with("/") {
	    				apath.push_str("index.html")
	    			}
    				if let Some(spath) = apath.splitn(2, '?').next() {
		    			let mime = guess_mime_type(spath.as_ref());
						res.headers_mut().set(ContentType(mime));
						match map.get_content(&spath) {
							Some(item) => {
								*res.status_mut() = StatusCode::Ok;
								&res.send(item).unwrap();
							},
							None => *res.status_mut() = StatusCode::NotFound,
						}
    				} else {
    					*res.status_mut() = StatusCode::BadRequest;
    				}
				},
				_ => *res.status_mut() = StatusCode::BadRequest,
			}
			//res.end();
		};
		// IMPORTANT! Browser blocks when there isn't enough threads!!!
		// That's because workers can't accept incomming connections in keep-alive state.
		match server.handle_threads(handler, 20) {
			Ok(listening) => {
				let worker = StaticWorker{ listening: listening};
				Ok(worker)
			},
			Err(_) => return Err(()),
		}
	}
}
<commit_msg>Fix indent in server.rs<commit_after>use std::sync::Arc;
use std::collections::HashMap;
use std::net::ToSocketAddrs;

use mime_guess::guess_mime_type;

use hyper::Server;
use hyper::server::{Listening, Request, Response};
use hyper::uri::RequestUri;
use hyper::header::ContentType;
use hyper::status::StatusCode;

pub type StaticMap = HashMap<String, Vec<u8>>;

pub trait StaicProvider: Sync + Send + 'static {
	fn get_content(&self, path: &str) -> Option<&Vec<u8>>;
}

impl StaicProvider for StaticMap {
	fn get_content(&self, path: &str) -> Option<&Vec<u8>> {
		self.get(path)
	}
}

pub struct StaticWorker {
	listening: Listening,
}

impl Drop for StaticWorker {
	fn drop(&mut self) {
		let _ = self.listening.close();
	}
}

// TODO Add trait StaticMapCreater with fn(path) and update/read method
pub struct StaticServer {
	map: Arc<StaicProvider>,
}

impl StaticServer {

	pub fn new<T: StaicProvider>(map: T) -> Self {
		StaticServer { map: Arc::new(map) }
	}

	pub fn share<To: ToSocketAddrs>(&self, addr: To) -> Result<StaticWorker, ()> {
		let server = match Server::http(addr) {
			Ok(server) => server,
			Err(_) => return Err(()),
		};
		let map = self.map.clone();
		let handler = move |req: Request, mut res: Response| {
			match req.uri {
				RequestUri::AbsolutePath(mut apath) => {
					debug!("Request for static resource {}", apath);
					if apath.ends_with("/") {
						apath.push_str("index.html")
					}
					if let Some(spath) = apath.splitn(2, '?').next() {
						let mime = guess_mime_type(spath.as_ref());
						res.headers_mut().set(ContentType(mime));
						match map.get_content(&spath) {
							Some(item) => {
								*res.status_mut() = StatusCode::Ok;
								&res.send(item).unwrap();
							},
							None => *res.status_mut() = StatusCode::NotFound,
						}
					} else {
						*res.status_mut() = StatusCode::BadRequest;
					}
				},
				_ => *res.status_mut() = StatusCode::BadRequest,
			}
			//res.end();
		};
		// IMPORTANT! Browser blocks when there isn't enough threads!!!
		// That's because workers can't accept incomming connections in keep-alive state.
		match server.handle_threads(handler, 20) {
			Ok(listening) => {
				let worker = StaticWorker{ listening: listening};
				Ok(worker)
			},
			Err(_) => return Err(()),
		}
	}
}
<|endoftext|>


<commit_before>use std::collections::HashMap;

use logic::{Logic,Expect,LogicFn};
use eval::{Eval,Evaluator};
use var::{Var,Mut};
use parse::{Parser,Map,IR};
use def::Def;
use fun::MutFn;

/// Source block statement types
#[derive(Debug,PartialEq)]
pub enum Src {
    /// Standard logic, eg: has_sword_item i
    Logic(String, Logic),

    /// References logic in env and emits varkinds
    ///
    /// Logic must resolve to true
    /// eg: if item_logic give_quest
    /// Can optionally end execution and begin next node
    If(String, Vec<Var>, Option<Next>),

    /// Or must follow an previous If
    ///
    /// Or only fires when previous If logic fails
    Or(Vec<Var>,Option<Next>),

    /// Just emits variables
    Emit(Vec<Var>),

    /// A composite logic type to group logic statements together
    Composite(String,Expect,Vec<String>),

    /// Ends execution and begins next node
    Next(Next),

    /// Mutate type, var being mutated, argument vars
    Mut(Mut, String, Vec<Var>),

    /// Match-like behavior for Mutations
    ///
    /// Map format should have Logic-Tested for the key
    /// and Mutation Function Signature for the value
    When(WhenMap),
}

/// Internal type to hold a specialized When-Mutate Map
pub type WhenMap = HashMap<String,(Mut,String,Vec<Var>)>;

/// Next-node action types
#[derive(Debug,PartialEq,Clone)]
pub enum Next {
    /// Instantly advances
    Now(String),

    /// Restarts current node, optionally another node -- heads immediately to this node on next evaluation
    Restart(Option<String>),

    /// Heads back to previous node visited
    Back,

    /// Clears out Node stack, pushes current node for further evaluation
    Clear,

    /// Awaits for manual advancement, failure to advance continues current node
    Await(String),

    /// Select from a group, based on decision
    Select(Map),

    /// Exits evaluation completely
    Exit
}
impl Next {
    pub fn parse(exp: &mut Vec<IR>) -> Result<Next,&'static str> {
        let mut select_idx = None;
        for (i,n) in exp.iter().enumerate() {
            match n {
                &IR::Sym(ref s) => {
                    if s == &"next:select" {
                        select_idx = Some(i);
                        break
                    }
                },
                _ => {},
            }
        }

        // handle nested selects as a special case
        if let Some(idx) = select_idx {
            let map_ir = exp.remove(idx+1);
            let _ = exp.remove(idx); // next:select statement
            if let Ok(map) = Parser::parse_map(map_ir) {
                return Ok(Next::Select(map))
            }
            else { return Err("Cannot parse map") }
        }

        let next;
        if let Some(node) = exp.pop() {
            if let Some(tag) = exp.pop() {
                match tag {
                    IR::Sym(tag) => {
                        let mut next_tag = tag.split_terminator(':');
                        let is_next = next_tag.next() == Some("next");

                        if is_next {
                            let next_tag = next_tag.next();
                            match next_tag {
                                Some("now") => { next = Next::Now(node.into()) },
                                Some("await") => { next = Next::Await(node.into()) },
                                Some("restart") => { next = Next::Restart(Some(node.into())) },
                                _ => { return Err("Invalid Next Type Found") },
                            }
                        }
                        else if next_tag.next().is_some() {
                            return Err("Unknown Tag encountered")
                        }
                        else {
                            exp.push(IR::Sym(tag.to_owned()));
                            exp.push(node);
                            return Err("Invalid Tag type")
                        }
                    },
                    _ => {
                        exp.push(tag);
                        exp.push(node);
                        return Err("Invalid Tag type")
                    }
                }
            }
            else {
                match node {
                    IR::Sym(ref tag) => {
                        let tag: &str = &tag;
                        match tag {
                            "next:back" => { next = Next::Back },
                            "next:restart" => { next = Next::Restart(None) },
                            "next:exit" => { next = Next::Exit },
                            "next:clear" => { next = Next::Clear },
                            _ => {
                                exp.push(IR::Sym(tag.to_owned()));
                                return Err("Invalid Tag type")
                            },
                        }
                    },
                    _ => {
                        exp.push(node);
                        return Err("Missing Tag type")
                    }
                }
            }
        }
        else { return Err("No Next type found") }

        Ok(next)
    }
}

impl Src {
    pub fn eval (&self,
                 logic: &mut HashMap<String,LogicFn>,
                 def: &mut Def,
                 fun: &mut HashMap<String,MutFn>)
                 -> (Vec<Var>,Option<Next>)
    {
        match self {
            &Src::Mut(ref m, ref v, ref a) => {
                match m {
                    &Mut::Add | &Mut::Sub | &Mut::Mul | &Mut::Div => {
                        let mut num = None;

                        let var_name = Var::Sym(v.to_owned());
                        let v1 = Var::get_num(&var_name, def);

                        if let Ok(v1) = v1 {
                            let var_name = &a[0];
                            let v2 = Var::get_num(&var_name, def);

                            if let Ok(v2) = v2 {
                                match m {
                                    &Mut::Add => {
                                        num = Some(v1+v2);
                                    },
                                    &Mut::Sub => {
                                        num = Some(v1-v2);
                                    },
                                    &Mut::Mul => {
                                        num = Some(v1*v2);
                                    },
                                    &Mut::Div => {
                                        num = Some(v1/v2);
                                    },
                                    _ => {},
                                }
                            }
                        }

                        if let Some(num) = num {
                            def.set_path(&v, Var::Num(num));
                        }
                    },
                    &Mut::Swap => {
                        let val = a[0].clone();
                        def.set_path(v,val); // NOTE: this will also build a var from scratch
                    },
                    &Mut::Fn(ref fun_name) => {
                        // NOTE: currently we skip non-resolved symbols!
                        let mut args = vec![]; //collect symbols' value
                        for n in a {
                            match n {
                                &Var::Sym(ref n) => {
                                    if let Some(v) = Evaluator::resolve(n, &logic, &def) {
                                        args.push(v)
                                    }
                                },
                                _ => { args.push(n.clone()) }
                            }
                        }

                        if let Some(mut mfn) = fun.get_mut(fun_name) {
                            if let Some(r) = mfn.run(&args, def) {
                                def.set_path(&v, r);
                            }
                        }
                    },
                }

                return (vec![],None)
            }
            &Src::Next(ref next) => {
                return (vec![],Some(next.clone()))
            },
            &Src::Or(ref vars, ref next) => {
                return (vars.clone(), next.clone())
            },
            &Src::Emit(ref vars) => {
                return (vars.clone(),None)
            },
            &Src::Logic(ref name, ref logic_src)=> {
                // NOTE: we only add logicfn if not compiled yet!
                if !logic.contains_key(name) {
                    let lfn = logic_src.eval();
                    logic.insert(name.clone(),lfn);
                }

                return (vec![],None) // logic does not return anything
            },
            &Src::Composite(ref _name, ref _x, ref _lookups) => {
                // TODO: reimplement as some sort of LogicFn closure
                unimplemented!();
            },
            &Src::If(ref lookup, ref v, ref next) => {
                let mut is_true = false;

                if let Some(val) = Evaluator::resolve(lookup, logic, def) {
                    match val {
                        Var::Bool(v) => { is_true = v; },
                        _ => { is_true = lookup != &val.to_string(); }
                    }
                }

                if is_true { return ((*v).clone(), next.clone()) }
                else { return (vec![],None) }
            },
            &Src::When(ref map) => {
                for (k, &(ref m, ref v, ref a)) in map.iter() {
                    let mut is_true = false;
                    if let Some(val) = Evaluator::resolve(k, logic, def) {
                        match val {
                            Var::Bool(v) => { is_true = v; },
                            _ => { is_true = k != &val.to_string(); }
                        }
                    }

                    if is_true {
                        Src::eval(&Src::Mut(m.clone(), v.clone(), a.clone()),
                                  logic,
                                  def,
                                  fun);
                    }
                }

                return (vec![],None)
            },
        }
    }

    pub fn parse(mut exp: Vec<IR>) -> Result<Src,&'static str> {
        let ir = exp.remove(0);
        match ir {
            IR::Sym(ref sym) => {
                if sym.chars().next() == Some('@') { //mutating statement
                    exp.insert(0,IR::Sym(sym.to_owned()));
                    let (m, v, a) = try!(Mut::parse(&mut exp));
                    return Ok(Src::Mut(m,v,a))
                }
                else if sym == "when" {
                    if exp.len() != 1 { return Err("Invalid WHEN Logic") }
                    if let Ok(mut map) = Parser::parse_map(exp.pop().unwrap()) {
                        let mut when_map: WhenMap = HashMap::new();
                        for (k,mut v) in map.drain() {
                            let v_ir = v.drain(..).map(|n| n.into()).collect();
                            let m = try!(Src::parse(v_ir));
                            match m {
                                Src::Mut(m,v,a) => {
                                    when_map.insert(k, (m,v,a));
                                },
                                _ => { return Err("Invalid WHEN Logic"); }
                            }
                        }

                        if when_map.is_empty() { return Err("Unable to parse WHEN Map into Mut") }
                        Ok(Src::When(when_map))
                    }
                    else { Err(" Invalid WHEN Logic") }
                }
                else if sym == "if" {
                    if exp.len() < 2 { return Err("Invalid IF Logic") }

                    let x = exp.remove(0);
                    let next = Next::parse(&mut exp);

                    let mut v = vec![];
                    for n in exp.drain(..) {
                        let r = try!(Var::parse(n));
                        v.push(r);
                    }

                    Ok(Src::If(x.into(), // NOTE: x.into() might cause errors, not all IR is acceptable
                               v, next.ok()))
                }
                else if sym == "or" {
                    if exp.len() < 1 { return Err("Invalid OR Logic") }

                    let next = Next::parse(&mut exp);

                    let mut v = vec![];
                    for n in exp.drain(..) {
                        let r = try!(Var::parse(n));
                        v.push(r);
                    }

                    Ok(Src::Or(v,next.ok()))
                }
                else if &sym.split_terminator(':').next() == &Some("next") {
                    exp.insert(0, IR::Sym(sym.to_owned()));
                    let next = Next::parse(&mut exp);
                    if let Ok(next) = next {
                        Ok(Src::Next(next))
                    }
                    else { Err("Invalid NEXT Logic") }
                }
                else if sym == "emit" {
                    if exp.len() > 0 {
                        let mut v = vec![];
                        for e in exp.drain(..) {
                            let r = try!(Var::parse(e));
                            v.push(r);
                        }

                        Ok(Src::Emit(v))
                    }
                    else { Err("Missing EMIT Logic") }
                }
                else {
                    let mut keys: Vec<&str> = sym.split_terminator(':').collect();
                    if keys.len() < 2 { // regular logic
                        let r = try!(Logic::parse(exp));
                        Ok(Src::Logic(sym.to_owned(),
                                      r))
                    }
                    else { // composite type
                        let name = keys.remove(0).to_owned();
                        let r = try!(Logic::parse_comp(keys, exp));
                        Ok(Src::Logic(name,
                                      r))
                    }
                }
            },
            _ => { Err("Encountered Non-Symbol Token") },
        }
    }
}
<commit_msg>remove unused<commit_after>use std::collections::HashMap;

use logic::{Logic,LogicFn};
use eval::{Eval,Evaluator};
use var::{Var,Mut};
use parse::{Parser,Map,IR};
use def::Def;
use fun::MutFn;

/// Source block statement types
#[derive(Debug,PartialEq)]
pub enum Src {
    /// Standard logic, eg: has_sword_item i
    Logic(String, Logic),

    /// References logic in env and emits varkinds
    ///
    /// Logic must resolve to true
    /// eg: if item_logic give_quest
    /// Can optionally end execution and begin next node
    If(String, Vec<Var>, Option<Next>),

    /// Or must follow an previous If
    ///
    /// Or only fires when previous If logic fails
    Or(Vec<Var>,Option<Next>),

    /// Just emits variables
    Emit(Vec<Var>),

    /// Ends execution and begins next node
    Next(Next),

    /// Mutate type, var being mutated, argument vars
    Mut(Mut, String, Vec<Var>),

    /// Match-like behavior for Mutations
    ///
    /// Map format should have Logic-Tested for the key
    /// and Mutation Function Signature for the value
    When(WhenMap),
}

/// Internal type to hold a specialized When-Mutate Map
pub type WhenMap = HashMap<String,(Mut,String,Vec<Var>)>;

/// Next-node action types
#[derive(Debug,PartialEq,Clone)]
pub enum Next {
    /// Instantly advances
    Now(String),

    /// Restarts current node, optionally another node -- heads immediately to this node on next evaluation
    Restart(Option<String>),

    /// Heads back to previous node visited
    Back,

    /// Clears out Node stack, pushes current node for further evaluation
    Clear,

    /// Awaits for manual advancement, failure to advance continues current node
    Await(String),

    /// Select from a group, based on decision
    Select(Map),

    /// Exits evaluation completely
    Exit
}
impl Next {
    pub fn parse(exp: &mut Vec<IR>) -> Result<Next,&'static str> {
        let mut select_idx = None;
        for (i,n) in exp.iter().enumerate() {
            match n {
                &IR::Sym(ref s) => {
                    if s == &"next:select" {
                        select_idx = Some(i);
                        break
                    }
                },
                _ => {},
            }
        }

        // handle nested selects as a special case
        if let Some(idx) = select_idx {
            let map_ir = exp.remove(idx+1);
            let _ = exp.remove(idx); // next:select statement
            if let Ok(map) = Parser::parse_map(map_ir) {
                return Ok(Next::Select(map))
            }
            else { return Err("Cannot parse map") }
        }

        let next;
        if let Some(node) = exp.pop() {
            if let Some(tag) = exp.pop() {
                match tag {
                    IR::Sym(tag) => {
                        let mut next_tag = tag.split_terminator(':');
                        let is_next = next_tag.next() == Some("next");

                        if is_next {
                            let next_tag = next_tag.next();
                            match next_tag {
                                Some("now") => { next = Next::Now(node.into()) },
                                Some("await") => { next = Next::Await(node.into()) },
                                Some("restart") => { next = Next::Restart(Some(node.into())) },
                                _ => { return Err("Invalid Next Type Found") },
                            }
                        }
                        else if next_tag.next().is_some() {
                            return Err("Unknown Tag encountered")
                        }
                        else {
                            exp.push(IR::Sym(tag.to_owned()));
                            exp.push(node);
                            return Err("Invalid Tag type")
                        }
                    },
                    _ => {
                        exp.push(tag);
                        exp.push(node);
                        return Err("Invalid Tag type")
                    }
                }
            }
            else {
                match node {
                    IR::Sym(ref tag) => {
                        let tag: &str = &tag;
                        match tag {
                            "next:back" => { next = Next::Back },
                            "next:restart" => { next = Next::Restart(None) },
                            "next:exit" => { next = Next::Exit },
                            "next:clear" => { next = Next::Clear },
                            _ => {
                                exp.push(IR::Sym(tag.to_owned()));
                                return Err("Invalid Tag type")
                            },
                        }
                    },
                    _ => {
                        exp.push(node);
                        return Err("Missing Tag type")
                    }
                }
            }
        }
        else { return Err("No Next type found") }

        Ok(next)
    }
}

impl Src {
    pub fn eval (&self,
                 logic: &mut HashMap<String,LogicFn>,
                 def: &mut Def,
                 fun: &mut HashMap<String,MutFn>)
                 -> (Vec<Var>,Option<Next>)
    {
        match self {
            &Src::Mut(ref m, ref v, ref a) => {
                match m {
                    &Mut::Add | &Mut::Sub | &Mut::Mul | &Mut::Div => {
                        let mut num = None;

                        let var_name = Var::Sym(v.to_owned());
                        let v1 = Var::get_num(&var_name, def);

                        if let Ok(v1) = v1 {
                            let var_name = &a[0];
                            let v2 = Var::get_num(&var_name, def);

                            if let Ok(v2) = v2 {
                                match m {
                                    &Mut::Add => {
                                        num = Some(v1+v2);
                                    },
                                    &Mut::Sub => {
                                        num = Some(v1-v2);
                                    },
                                    &Mut::Mul => {
                                        num = Some(v1*v2);
                                    },
                                    &Mut::Div => {
                                        num = Some(v1/v2);
                                    },
                                    _ => {},
                                }
                            }
                        }

                        if let Some(num) = num {
                            def.set_path(&v, Var::Num(num));
                        }
                    },
                    &Mut::Swap => {
                        let val = a[0].clone();
                        def.set_path(v,val); // NOTE: this will also build a var from scratch
                    },
                    &Mut::Fn(ref fun_name) => {
                        // NOTE: currently we skip non-resolved symbols!
                        let mut args = vec![]; //collect symbols' value
                        for n in a {
                            match n {
                                &Var::Sym(ref n) => {
                                    if let Some(v) = Evaluator::resolve(n, &logic, &def) {
                                        args.push(v)
                                    }
                                },
                                _ => { args.push(n.clone()) }
                            }
                        }

                        if let Some(mut mfn) = fun.get_mut(fun_name) {
                            if let Some(r) = mfn.run(&args, def) {
                                def.set_path(&v, r);
                            }
                        }
                    },
                }

                return (vec![],None)
            }
            &Src::Next(ref next) => {
                return (vec![],Some(next.clone()))
            },
            &Src::Or(ref vars, ref next) => {
                return (vars.clone(), next.clone())
            },
            &Src::Emit(ref vars) => {
                return (vars.clone(),None)
            },
            &Src::Logic(ref name, ref logic_src)=> {
                // NOTE: we only add logicfn if not compiled yet!
                if !logic.contains_key(name) {
                    let lfn = logic_src.eval();
                    logic.insert(name.clone(),lfn);
                }

                return (vec![],None) // logic does not return anything
            },
            &Src::If(ref lookup, ref v, ref next) => {
                let mut is_true = false;

                if let Some(val) = Evaluator::resolve(lookup, logic, def) {
                    match val {
                        Var::Bool(v) => { is_true = v; },
                        _ => { is_true = lookup != &val.to_string(); }
                    }
                }

                if is_true { return ((*v).clone(), next.clone()) }
                else { return (vec![],None) }
            },
            &Src::When(ref map) => {
                for (k, &(ref m, ref v, ref a)) in map.iter() {
                    let mut is_true = false;
                    if let Some(val) = Evaluator::resolve(k, logic, def) {
                        match val {
                            Var::Bool(v) => { is_true = v; },
                            _ => { is_true = k != &val.to_string(); }
                        }
                    }

                    if is_true {
                        Src::eval(&Src::Mut(m.clone(), v.clone(), a.clone()),
                                  logic,
                                  def,
                                  fun);
                    }
                }

                return (vec![],None)
            },
        }
    }

    pub fn parse(mut exp: Vec<IR>) -> Result<Src,&'static str> {
        let ir = exp.remove(0);
        match ir {
            IR::Sym(ref sym) => {
                if sym.chars().next() == Some('@') { //mutating statement
                    exp.insert(0,IR::Sym(sym.to_owned()));
                    let (m, v, a) = try!(Mut::parse(&mut exp));
                    return Ok(Src::Mut(m,v,a))
                }
                else if sym == "when" {
                    if exp.len() != 1 { return Err("Invalid WHEN Logic") }
                    if let Ok(mut map) = Parser::parse_map(exp.pop().unwrap()) {
                        let mut when_map: WhenMap = HashMap::new();
                        for (k,mut v) in map.drain() {
                            let v_ir = v.drain(..).map(|n| n.into()).collect();
                            let m = try!(Src::parse(v_ir));
                            match m {
                                Src::Mut(m,v,a) => {
                                    when_map.insert(k, (m,v,a));
                                },
                                _ => { return Err("Invalid WHEN Logic"); }
                            }
                        }

                        if when_map.is_empty() { return Err("Unable to parse WHEN Map into Mut") }
                        Ok(Src::When(when_map))
                    }
                    else { Err(" Invalid WHEN Logic") }
                }
                else if sym == "if" {
                    if exp.len() < 2 { return Err("Invalid IF Logic") }

                    let x = exp.remove(0);
                    let next = Next::parse(&mut exp);

                    let mut v = vec![];
                    for n in exp.drain(..) {
                        let r = try!(Var::parse(n));
                        v.push(r);
                    }

                    Ok(Src::If(x.into(), // NOTE: x.into() might cause errors, not all IR is acceptable
                               v, next.ok()))
                }
                else if sym == "or" {
                    if exp.len() < 1 { return Err("Invalid OR Logic") }

                    let next = Next::parse(&mut exp);

                    let mut v = vec![];
                    for n in exp.drain(..) {
                        let r = try!(Var::parse(n));
                        v.push(r);
                    }

                    Ok(Src::Or(v,next.ok()))
                }
                else if &sym.split_terminator(':').next() == &Some("next") {
                    exp.insert(0, IR::Sym(sym.to_owned()));
                    let next = Next::parse(&mut exp);
                    if let Ok(next) = next {
                        Ok(Src::Next(next))
                    }
                    else { Err("Invalid NEXT Logic") }
                }
                else if sym == "emit" {
                    if exp.len() > 0 {
                        let mut v = vec![];
                        for e in exp.drain(..) {
                            let r = try!(Var::parse(e));
                            v.push(r);
                        }

                        Ok(Src::Emit(v))
                    }
                    else { Err("Missing EMIT Logic") }
                }
                else {
                    let mut keys: Vec<&str> = sym.split_terminator(':').collect();
                    if keys.len() < 2 { // regular logic
                        let r = try!(Logic::parse(exp));
                        Ok(Src::Logic(sym.to_owned(),
                                      r))
                    }
                    else { // composite type
                        let name = keys.remove(0).to_owned();
                        let r = try!(Logic::parse_comp(keys, exp));
                        Ok(Src::Logic(name,
                                      r))
                    }
                }
            },
            _ => { Err("Encountered Non-Symbol Token") },
        }
    }
}
<|endoftext|>