<commit_before>use std::collections::HashMap;
use std::rc::Rc;
use std::str::SplitWhitespace;
use std::slice::Iter;
use std::cell::RefCell;

pub struct Command<'a> {
    command: Vec<&'a str>,
    exec: Box<RefCell<FnMut(Vec<&str>) + 'a>>,
    complete: Option<Box<FnMut(Vec<&str>) + 'a>>
}

impl<'a> Command<'a> {
    fn new<T: FnMut(Vec<&str>) + 'a, U: FnMut(Vec<&str>) + 'a>(cmd: Vec<&'a str>, exec_handler: T, complete_handler: Option<U>) -> Command<'a> {
        let mut obj = Command {
            command: cmd,
            exec: Box::new(RefCell::new(exec_handler)),
            complete: None
        };

        if let Some(cb) = complete_handler {
            obj.complete = Some(Box::new(cb));
        }

        obj
    }
}

pub struct Cli<'a> {
    commands: HashMap<&'a str, Cli<'a>>,
    handler: Option<Rc<Command<'a>>>
}

impl<'a> Cli<'a>{

    fn new() -> Cli<'a> {
        Cli {
            commands: HashMap::new(),
            handler: None
        }
    }

    fn register<T: FnMut(Vec<&str>) + 'a>(&mut self, cmd: Vec<&'a str>, exec: T) -> Result<(), ()> {
        let tmp = Rc::new(Command::new(cmd.clone(), exec, None::<T>));

        match self._register(cmd.iter(), tmp.clone()) {
            Ok(_) => Ok(()),
            Err(_) => {
                //TODO: this can only happen if we register "Vec::new()" ... probably disallow that at all
                self.handler = Some(tmp.clone());
                Err(())
            }
        }
    }

    fn _register(&mut self, mut it: Iter<&'a str>, command: Rc<Command<'a>>) -> Result<(), ()> {
        if let Some(portion) = it.next() {
            if !self.commands.contains_key(portion) {
                let mut cli = Cli::new();
                if let Err(_) = cli._register(it, command.clone()) {
                    cli.handler = Some(command.clone())
                }
                self.commands.insert(portion, cli);
            } else {
                if let Some(cmd) = self.commands.get_mut(portion) {
                    if let Err(_) = cmd._register(it, command.clone()) {
                        cmd.handler = Some(command.clone())
                    }
                }
            };
            Ok(())
        } else {
            Err(())
        }
    }

    fn complete(&self, argv: &str) -> Vec<&str> {
        println!("complete for '{}'", argv.trim());
        let portions = argv.trim().split_whitespace();

        match self._complete(portions) {
            Ok(ret) => ret,
            Err(_) => Vec::new()
        }
    }

    fn _complete(&self, mut portions: SplitWhitespace) -> Result<Vec<&str>, ()> {
        if let Some(ref portion) = portions.next() {
            if let Some(ref cmd) = self.commands.get(portion) {
                cmd._complete(portions)
            } else {
                Ok(self.commands.keys()
                    .filter(|cmd| cmd.starts_with(portion))
                    .cloned()
                    .collect())
            }
        } else {
            Ok(self.commands.keys()
                .cloned()
                .collect())
        }
    }

    fn exec(&mut self, cmd: &str) {
        let argv:Vec<&str> = cmd.clone().split_whitespace().collect();
        let portions = cmd.trim().split_whitespace();
        self._exec(portions, argv);
    }

    fn _exec(&mut self, mut portions: SplitWhitespace, argv: Vec<&str>) {
        if let Some(portion) = portions.next() {
            if let Some(cmd) = self.commands.get_mut(portion) {
                cmd._exec(portions, argv);
            } else {
                if let Some(ref mut cb) = self.handler {
                    println!("handler for {:?}", cb.command);
                    (&mut *cb.exec.borrow_mut())(argv);
                }
            }
        } else {
            if let Some(ref mut cb) = self.handler {
                println!("handler for {:?}", cb.command);
                (&mut *cb.exec.borrow_mut())(argv);
            }
        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_register_and_execute() {
        let mut called = false;
        {
            let mut cli = Cli::new();
            cli.register(vec!["foo", "bar"], | _ | { called=true } ).ok();
            cli.exec("foo bar");
        }
        assert!(called == true)
    }

    #[test]
    fn test_register_and_execute_multiple_times() {
        let mut called = 0u8;
        {
            let mut cli = Cli::new();
            cli.register(vec!["foo", "bar"], | _ | { called = called + 1} ).ok();
            cli.exec("foo bar");
            cli.exec("foo bar");
        }
        assert!(called == 2)
    }

    #[test]
    fn test_complete_empty_single_cmd() {
        let mut cli = Cli::new();
        cli.register(vec!["foo"], | _ | { } ).ok();
        assert!(vec!["foo"] == cli.complete(""));
        assert!(vec!["foo"] == cli.complete("f"));
        assert!(vec!["foo"] == cli.complete("  f"));
        //assert!(vec![""] == cli.complete("f   "));  //FIXME: this test should pass
        assert!(cli.complete("foo").is_empty());
    }

    #[test]
    fn test_complete_multi_cmd() {
        let mut cli = Cli::new();
        cli.register(vec!["foo", "bar"], | _| { } ).ok();
        assert!(vec!["foo"] == cli.complete("f"));
        assert!(vec!["bar"] == cli.complete("foo"));
        assert!(vec!["bar"] == cli.complete("foo b"));
    }

    #[test]
    fn test_register_and_execute_with_arguments() {
        let mut called = false;
        {
            let mut cli = Cli::new();
            cli.register(vec!["foo"], | args | {
                called=true;
                assert!(vec!["foo", "bar", "baz"] == args);
            } ).ok();
            cli.exec("foo bar baz");
        }
        assert!(called == true);
    }
}

fn foo(argv: Vec<&str>) {
    println!("--> {:?}", argv);
}

fn main() {
    let mut cli = Cli::new();

    cli.register(vec!["show", "stuff"], foo).ok();
    //cli.register(vec!["show", "other"], foo).ok();
    //cli.register(vec!["some", "other"], foo).ok();
    //cli.register(vec!["list", "other", "cool"], foo).ok();
    //cli.register(vec!["list", "other", "uncool"], foo).ok();

    loop {
        let mut line = String::new();
        std::io::stdin().read_line(&mut line).unwrap();

        //println!("got: {:?}", cli.complete(&line));
        cli.exec(&line);
    }
}
<commit_msg>got something 'hacky' to compile, doesn't work yet<commit_after>use std::collections::HashMap;
use std::rc::Rc;
use std::str::SplitWhitespace;
use std::slice::Iter;
use std::cell::RefCell;

pub struct Command<'a> {
    command: Vec<&'a str>,
    exec: Box<RefCell<FnMut(Vec<&str>) + 'a>>,
    complete: Option<Box<RefCell<FnMut(Vec<&str>) -> Vec<&str> + 'a>>>
}

impl<'a> Command<'a> {
    fn new<T: FnMut(Vec<&str>) + 'a, U: FnMut(Vec<&str>) -> Vec<&str> + 'a>(cmd: Vec<&'a str>, exec_handler: T, complete_handler: Option<U>) -> Command<'a> {
        let mut complete_cb:Option<Box<RefCell<FnMut(Vec<&str>) -> Vec<&str>>>> = None;
        if let Some(cb) = complete_handler {
            complete_cb = Some(Box::new(RefCell::new(cb)));
        }

        Command {
            command: cmd,
            exec: Box::new(RefCell::new(exec_handler)),
            complete: complete_cb
        }
    }
}

pub struct Cli<'a> {
    commands: HashMap<&'a str, Cli<'a>>,
    handler: Option<Rc<Command<'a>>>
}

impl<'a> Cli<'a>{

    fn new() -> Cli<'a> {
        Cli {
            commands: HashMap::new(),
            handler: None
        }
    }

    fn register<T: FnMut(Vec<&str>) + 'a, U: FnMut(Vec<&str>) -> Vec<&str> + 'a>(&mut self, cmd: Vec<&'a str>, exec: T) -> Result<(), ()> {
        let tmp = Rc::new(Command::new(cmd.clone(), exec, None::<U>));

        match self._register(cmd.iter(), tmp.clone()) {
            Ok(_) => Ok(()),
            Err(_) => {
                //TODO: this can only happen if we register "Vec::new()" ... probably disallow that at all
                self.handler = Some(tmp.clone());
                Err(())
            }
        }
    }

    fn register_dyn_complete<T: FnMut(Vec<&str>) + 'a, U: FnMut(Vec<&str>) -> Vec<&str> + 'a>(&mut self, cmd: Vec<&'a str>, exec: T, complete: U) -> Result<(), ()> {
        let tmp = Rc::new(Command::new(cmd.clone(), exec, Some(complete)));

        match self._register(cmd.iter(), tmp.clone()) {
            Ok(_) => Ok(()),
            Err(_) => {
                //TODO: this can only happen if we register "Vec::new()" ... probably disallow that at all
                self.handler = Some(tmp.clone());
                Err(())
            }
        }
    }

    fn _register(&mut self, mut it: Iter<&'a str>, command: Rc<Command<'a>>) -> Result<(), ()> {
        if let Some(portion) = it.next() {
            if !self.commands.contains_key(portion) {
                let mut cli = Cli::new();
                if let Err(_) = cli._register(it, command.clone()) {
                    cli.handler = Some(command.clone())
                }
                self.commands.insert(portion, cli);
            } else {
                if let Some(cmd) = self.commands.get_mut(portion) {
                    if let Err(_) = cmd._register(it, command.clone()) {
                        cmd.handler = Some(command.clone())
                    }
                }
            };
            Ok(())
        } else {
            Err(())
        }
    }

    fn complete(&mut self, argv: &'a str) -> Vec<&str> {
        println!("complete for '{}'", argv.trim());
        let portions = argv.trim().split_whitespace();

        match self._complete(portions) {
            Ok(ret) => ret,
            Err(_) => Vec::new()
        }
    }

    fn _complete(&mut self, mut portions: SplitWhitespace<'a>) -> Result<Vec<&str>, ()> {
        if let Some(ref portion) = portions.next() {
            if let Some(cmd) = self.commands.get_mut(portion) {
                cmd._complete(portions)
            } else {
                if let Some(ref mut handler) = self.handler {
                    if let Some(ref cb) = handler.complete {
                        return Ok((&mut *cb.borrow_mut())(vec![""]))
                    }
                }
                //Ok(self.commands.keys()
                    //.filter(|cmd| cmd.starts_with(portion))
                    //.cloned()
                    //.collect())
                    Ok(vec![""])
            }
        } else {
            if let Some(ref mut handler) = self.handler {
                if let Some(ref cb) = handler.complete {
                    return Ok((&mut *cb.borrow_mut())(vec![""]))
                }
            }
            //Ok(self.commands.keys()
                //.cloned()
                //.collect())
            Ok(vec![""])
        }
    }

    fn exec(&mut self, cmd: &'a str) {
        let argv:Vec<&'a str> = cmd.clone().split_whitespace().collect();
        let portions = cmd.trim().split_whitespace();
        self._exec(portions, argv);
    }

    fn _exec(&mut self, mut portions: SplitWhitespace, argv: Vec<&str>) {
        if let Some(portion) = portions.next() {
            if let Some(cmd) = self.commands.get_mut(portion) {
                cmd._exec(portions, argv);
            } else {
                if let Some(ref mut cb) = self.handler {
                    println!("handler for {:?}", cb.command);
                    (&mut *cb.exec.borrow_mut())(argv);
                }
            }
        } else {
            if let Some(ref mut cb) = self.handler {
                println!("handler for {:?}", cb.command);
                (&mut *cb.exec.borrow_mut())(argv);
            }
        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    //#[test]
    //fn test_register_and_execute() {
        //let mut called = false;
        //{
            //let mut cli = Cli::new();
            //cli.register(vec!["foo", "bar"], | _ | { called=true }).ok();
            //cli.exec("foo bar");
        //}
        //assert!(called == true)
    //}

    //#[test]
    //fn test_register_and_execute_multiple_times() {
        //let mut called = 0u8;
        //{
            //let mut cli = Cli::new();
            //cli.register(vec!["foo", "bar"], | _ | { called = called + 1} ).ok();
            //cli.exec("foo bar");
            //cli.exec("foo bar");
        //}
        //assert!(called == 2)
    //}

    //#[test]
    //fn test_complete_empty_single_cmd() {
        //let mut cli = Cli::new();
        //cli.register(vec!["foo"], | _ | { } ).ok();
        //assert!(vec!["foo"] == cli.complete(""));
        //assert!(vec!["foo"] == cli.complete("f"));
        //assert!(vec!["foo"] == cli.complete("  f"));
        ////assert!(vec![""] == cli.complete("f   "));  //FIXME: this test should pass
        //assert!(cli.complete("foo").is_empty());
    //}

    #[test]
    fn test_complete_with_dynamic() {
        let mut cli = Cli::new();
        cli.register_dyn_complete(vec!["foo"], | _ | { }, | _ | {
            println!("called");
            vec!["bar", "baz"]
        }).ok();
        assert!(vec!["foo"] == cli.complete("f"));
        assert!(vec!["bar", "baz"] == cli.complete("foo"));
    }

    //#[test]
    //fn test_complete_multi_cmd() {
        //let mut cli = Cli::new();
        //cli.register(vec!["foo", "bar"], | _| { } ).ok();
        //assert!(vec!["foo"] == cli.complete("f"));
        //assert!(vec!["bar"] == cli.complete("foo"));
        //assert!(vec!["bar"] == cli.complete("foo b"));
    //}

    //#[test]
    //fn test_register_and_execute_with_arguments() {
        //let mut called = false;
        //{
            //let mut cli = Cli::new();
            //cli.register(vec!["foo"], | args | {
                //called=true;
                //assert!(vec!["foo", "bar", "baz"] == args);
            //} ).ok();
            //cli.exec("foo bar baz");
        //}
        //assert!(called == true);
    //}
}

fn foo(argv: Vec<&str>) {
    println!("--> {:?}", argv);
}

fn main() {
    let mut cli = Cli::new();

    //cli.register(vec!["show", "stuff"], foo).ok();
    //cli.register(vec!["show", "other"], foo).ok();
    //cli.register(vec!["some", "other"], foo).ok();
    //cli.register(vec!["list", "other", "cool"], foo).ok();
    //cli.register(vec!["list", "other", "uncool"], foo).ok();

    //loop {
        //let mut line = String::new();
        //std::io::stdin().read_line(&mut line).unwrap();

        ////println!("got: {:?}", cli.complete(&line));
        //cli.exec(&line);
    //}
}
<|endoftext|>


<commit_before>use std::io::{self, BufReader};
use std::io::BufRead;
use std::fs::File;
extern crate time;
use time::Tm;
use time::strptime;
use time::Duration;

mod http_status;
use http_status::HttpStatus;

#[derive(Eq, PartialEq, Clone)]
#[derive(Debug)]
pub struct Request {
    id: i32,
    time: Tm,
    url: String,
}

impl Request {
    fn get_matching_response<'a>(&'a self, responses: &'a Vec<Response>) -> Option<&Response> {
        for response in responses {
            if self.id == response.id {
                return Some(response)
            }
        }

        None
    }
}

#[derive(Eq, PartialEq, Clone)]
#[derive(Debug)]
pub struct Response {
    id: i32,
    time: Tm,
    mime_type: String,
    response_time: Duration,
    http_status: HttpStatus,
}

pub fn open_logfile(path: &str) -> Result<(Vec<Request>,Vec<Response>), io::Error> {
    let f = try!(File::open(path));

    let f = BufReader::new(f);

    let mut requests: Vec<Request> = Vec::new();
    let mut responses: Vec<Response> = Vec::new();

    for line in f.lines() {
        let line_value = &line.unwrap();

        if line_value.contains("->") {
            let r = try!(parse_request_line(&line_value));
            println!("{:#?}", r);
            requests.push(r)
        }

        if line_value.contains("<-") {
            let r = try!(parse_response_line(&line_value));
            println!("{:#?}", r);
            responses.push(r)
        }

    }

    Ok((requests, responses))
}

pub fn parse_request_line(log_line: &String) -> Result<Request, io::Error> {
    let parts: Vec<&str> = log_line.split(" ").collect();

    let id = parts[2];
    let url = parts[5];

    Ok(Request {
        id: id[1..id.len()-1].parse().unwrap(),
        time: strptime(parts[0], "%d/%b/%Y:%H:%M:%S").unwrap(),
        url: url.to_string()
    })
}

pub fn parse_response_line(log_line: &String) -> Result<Response, io::Error> {
    let parts: Vec<&str> = log_line.split(" ").collect();

    let id = parts[2];
    let response_time = parts[parts.len()-1];
    let mime_type = parts[5];
    let status_code = parts[4];

    Ok(Response {
        id: id[1..id.len()-1].parse().unwrap(),
        time: strptime(parts[0], "%d/%b/%Y:%H:%M:%S").unwrap(),
        response_time: Duration::milliseconds(response_time[0..response_time.len()-2].parse().unwrap()),
        mime_type: mime_type.to_string(),
        http_status: HttpStatus::from_code(status_code.parse().unwrap()),
    })
}

pub struct RequestResponsePair {
    request: Request,
    response: Response
}

pub fn pair_requests_responses(requests:Vec<Request>, responses: Vec<Response>) -> Vec<RequestResponsePair> {
    let mut request_response_pairs: Vec<RequestResponsePair> = Vec::new();

    for request in requests  {
        match request.get_matching_response(&responses) {
            Some(response) => request_response_pairs.push(RequestResponsePair{
                request: request.clone(),
                response: response.clone()
            }),
            None => println!("none"),
        }
    }

    request_response_pairs
}

fn main() {
    let lines = open_logfile("src/test/simple-1.log");
    let (requests, responses) = lines.unwrap();
    println!("So many requests: {}", requests.len());
    println!("So many responses: {}", responses.len());

    let pairs: Vec<RequestResponsePair> = pair_requests_responses(requests, responses);

    let times: Vec<i64> = pairs.iter().map(|rr| rr.response.response_time.num_milliseconds()).collect();
    let sum: i64 = times.iter().sum();
    println!("{}", sum);
}

#[cfg(test)]
mod tests {
	use super::*;
    extern crate time;
    use time::strptime;
    use::time::Duration;
    use http_status::HttpStatus;

    #[test]
    fn test_parse_request_line() {
        let line = "08/Apr/2016:09:58:47 +0200 [02] -> GET /content/some/other.html HTTP/1.1".to_string();

        let expected = Request {
            id: 2,
            time: strptime("08/Apr/2016:09:58:47 +0200", "%d/%b/%Y:%H:%M:%S").unwrap(),
            url: "/content/some/other.html".to_string()
        };

        let result = parse_request_line(&line);

        assert_eq!(result.unwrap(), expected)
    }

    #[test]
    fn test_parse_response_line() {
        let line = "08/Apr/2016:09:58:48 +0200 [02] <- 200 text/html 10ms".to_string();

        let expected = Response {
            id: 2,
            time: strptime("08/Apr/2016:09:58:48 +0200", "%d/%b/%Y:%H:%M:%S").unwrap(),
            mime_type: "text/html".to_string(),
            response_time: Duration::milliseconds(10),
            http_status: HttpStatus::OK,
        };

        let result = parse_response_line(&line);

        assert_eq!(result.unwrap(), expected)
    }

    #[test]
    fn test_open_logfile() {
        let lines = open_logfile("src/test/simple-1.log");
        let (requests, responses) = lines.unwrap();

        assert_eq!(requests.len(), 2);
        assert_eq!(responses.len(), 2);
    }

    #[test]
    fn test_get_matching_response() {
        let lines = open_logfile("src/test/simple-1.log");
        let (requests, responses) = lines.unwrap();

        let result = requests[0].get_matching_response(&responses);

        let expected = Response {
            id: 1,
            time: strptime("08/Apr/2016:09:57:47 +0200", "%d/%b/%Y:%H:%M:%S").unwrap(),
            mime_type: "text/html".to_string(),
            response_time: Duration::milliseconds(7),
            http_status: HttpStatus::OK,
        };

        assert_eq!(*result.unwrap(), expected);
    }

    #[test]
    fn test_get_matching_response_none_found() {
        let lines = open_logfile("src/test/simple-1.log");
        let (_, responses) = lines.unwrap();

        let request_without_matching = Request {
            id: 999,
            time: strptime("08/Apr/2016:09:58:47 +0200", "%d/%b/%Y:%H:%M:%S").unwrap(),
            url: "/content/some/other.html".to_string()
        };

        let result = request_without_matching.get_matching_response(&responses);

        assert!(result.is_none());
    }

    #[test]
    fn test_pair_requests_resonses() {
        let lines = open_logfile("src/test/simple-1.log");
        let (requests, responses) = lines.unwrap();

        let result = pair_requests_responses(requests, responses);

        assert_eq!(result.len(), 2);

        assert_eq!(result[0].request.id, result[0].response.id);
        assert_eq!(result[1].request.id, result[1].response.id);
    }
}
<commit_msg>Factory functions should be part of structs<commit_after>use std::io::{self, BufReader};
use std::io::BufRead;
use std::fs::File;
extern crate time;
use time::Tm;
use time::strptime;
use time::Duration;

mod http_status;
use http_status::HttpStatus;

#[derive(Eq, PartialEq, Clone)]
#[derive(Debug)]
pub struct Request {
    id: i32,
    time: Tm,
    url: String,
}

impl Request {
    fn new_from_log_line(log_line: &String) -> Result<Request, io::Error> {
        let parts: Vec<&str> = log_line.split(" ").collect();

        let id = parts[2];
        let url = parts[5];

        Ok(Request {
            id: id[1..id.len()-1].parse().unwrap(),
            time: strptime(parts[0], "%d/%b/%Y:%H:%M:%S").unwrap(),
            url: url.to_string()
        })
    }

    fn get_matching_response<'a>(&'a self, responses: &'a Vec<Response>) -> Option<&Response> {
        for response in responses {
            if self.id == response.id {
                return Some(response)
            }
        }

        None
    }
}

#[derive(Eq, PartialEq, Clone)]
#[derive(Debug)]
pub struct Response {
    id: i32,
    time: Tm,
    mime_type: String,
    response_time: Duration,
    http_status: HttpStatus,
}

impl Response {
    fn new_from_log_line(log_line: &String) -> Result<Response, io::Error> {
        let parts: Vec<&str> = log_line.split(" ").collect();

        let id = parts[2];
        let response_time = parts[parts.len()-1];
        let mime_type = parts[5];
        let status_code = parts[4];

        Ok(Response {
            id: id[1..id.len()-1].parse().unwrap(),
            time: strptime(parts[0], "%d/%b/%Y:%H:%M:%S").unwrap(),
            response_time: Duration::milliseconds(response_time[0..response_time.len()-2].parse().unwrap()),
            mime_type: mime_type.to_string(),
            http_status: HttpStatus::from_code(status_code.parse().unwrap()),
        })
    }
}

pub fn open_logfile(path: &str) -> Result<(Vec<Request>,Vec<Response>), io::Error> {
    let f = try!(File::open(path));

    let f = BufReader::new(f);

    let mut requests: Vec<Request> = Vec::new();
    let mut responses: Vec<Response> = Vec::new();

    for line in f.lines() {
        let line_value = &line.unwrap();

        if line_value.contains("->") {
            let r = try!(Request::new_from_log_line(&line_value));
            println!("{:#?}", r);
            requests.push(r)
        }

        if line_value.contains("<-") {
            let r = try!(Response::new_from_log_line(&line_value));
            println!("{:#?}", r);
            responses.push(r)
        }

    }

    Ok((requests, responses))
}

pub struct RequestResponsePair {
    request: Request,
    response: Response
}

pub fn pair_requests_responses(requests:Vec<Request>, responses: Vec<Response>) -> Vec<RequestResponsePair> {
    let mut request_response_pairs: Vec<RequestResponsePair> = Vec::new();

    for request in requests  {
        match request.get_matching_response(&responses) {
            Some(response) => request_response_pairs.push(RequestResponsePair{
                request: request.clone(),
                response: response.clone()
            }),
            None => println!("none"),
        }
    }

    request_response_pairs
}

fn main() {
    let lines = open_logfile("src/test/simple-1.log");
    let (requests, responses) = lines.unwrap();
    println!("So many requests: {}", requests.len());
    println!("So many responses: {}", responses.len());

    let pairs: Vec<RequestResponsePair> = pair_requests_responses(requests, responses);

    let times: Vec<i64> = pairs.iter().map(|rr| rr.response.response_time.num_milliseconds()).collect();
    let sum: i64 = times.iter().sum();
    println!("{}", sum);
}

#[cfg(test)]
mod tests {
	use super::*;
    extern crate time;
    use time::strptime;
    use::time::Duration;
    use http_status::HttpStatus;

    #[test]
    fn test_parse_request_line() {
        let line = "08/Apr/2016:09:58:47 +0200 [02] -> GET /content/some/other.html HTTP/1.1".to_string();

        let expected = Request {
            id: 2,
            time: strptime("08/Apr/2016:09:58:47 +0200", "%d/%b/%Y:%H:%M:%S").unwrap(),
            url: "/content/some/other.html".to_string()
        };

        let result = Request::new_from_log_line(&line);

        assert_eq!(result.unwrap(), expected)
    }

    #[test]
    fn test_parse_response_line() {
        let line = "08/Apr/2016:09:58:48 +0200 [02] <- 200 text/html 10ms".to_string();

        let expected = Response {
            id: 2,
            time: strptime("08/Apr/2016:09:58:48 +0200", "%d/%b/%Y:%H:%M:%S").unwrap(),
            mime_type: "text/html".to_string(),
            response_time: Duration::milliseconds(10),
            http_status: HttpStatus::OK,
        };

        let result = Response::new_from_log_line(&line);

        assert_eq!(result.unwrap(), expected)
    }

    #[test]
    fn test_open_logfile() {
        let lines = open_logfile("src/test/simple-1.log");
        let (requests, responses) = lines.unwrap();

        assert_eq!(requests.len(), 2);
        assert_eq!(responses.len(), 2);
    }

    #[test]
    fn test_get_matching_response() {
        let lines = open_logfile("src/test/simple-1.log");
        let (requests, responses) = lines.unwrap();

        let result = requests[0].get_matching_response(&responses);

        let expected = Response {
            id: 1,
            time: strptime("08/Apr/2016:09:57:47 +0200", "%d/%b/%Y:%H:%M:%S").unwrap(),
            mime_type: "text/html".to_string(),
            response_time: Duration::milliseconds(7),
            http_status: HttpStatus::OK,
        };

        assert_eq!(*result.unwrap(), expected);
    }

    #[test]
    fn test_get_matching_response_none_found() {
        let lines = open_logfile("src/test/simple-1.log");
        let (_, responses) = lines.unwrap();

        let request_without_matching = Request {
            id: 999,
            time: strptime("08/Apr/2016:09:58:47 +0200", "%d/%b/%Y:%H:%M:%S").unwrap(),
            url: "/content/some/other.html".to_string()
        };

        let result = request_without_matching.get_matching_response(&responses);

        assert!(result.is_none());
    }

    #[test]
    fn test_pair_requests_resonses() {
        let lines = open_logfile("src/test/simple-1.log");
        let (requests, responses) = lines.unwrap();

        let result = pair_requests_responses(requests, responses);

        assert_eq!(result.len(), 2);

        assert_eq!(result[0].request.id, result[0].response.id);
        assert_eq!(result[1].request.id, result[1].response.id);
    }
}
<|endoftext|>


<commit_before>use std::net::*;
use std::io::prelude::*;
use std::mem::*;

#[repr(C)]
enum E {
    Int(i32),
    Double(f64),
    Str(String),
    None,
}

const PUT: i32 = 0;
/*
const GET: i32 = 1;
const READ: i32 = 2;
const GET_NB: i32 = 3;
const READ_NB: i32 = 4;
const DUMP: i32 = 5;
const COUNT: i32 = 6;
const LOG: i32 = 7;
const REPLACE: i32 = 8;
*/

const asciiS: i32 = 115;
const asciiI: i32 = 105;
const asciiD: i32 = 100;
const asciiQ: i32 = 63;
const asciiT: i32 = 116;

fn ti(i: i32) -> [u8; 4] {
	let buff: [u8; 4];
	unsafe {
		buff = transmute(i);
	}
	return buff;
}

fn ctoi(arr: &mut [u8; 24], mut val: i32, offset: isize)
{
	unsafe {
		std::ptr::copy_nonoverlapping(&mut val as *mut _ as *mut u8, arr.as_ptr().offset(offset) as *mut u8, std::mem::size_of::<i32>());
	}
}

fn ctod(arr: &mut [u8; 24], mut val: f64, offset: isize)
{
	unsafe {
		std::ptr::copy_nonoverlapping(&mut val as *mut _ as *mut u8, arr.as_ptr().offset(offset) as *mut u8, std::mem::size_of::<f64>());
	}
}

fn send_tuple(tuple: &[E], stream: &mut TcpStream) {

    stream.write_all(& (ti(tuple.len() as i32)));

    let mut string_length:i32 = 0;

    for elem in tuple {
    	match elem {
    		&E::Str(ref s) => string_length += s.len() as i32,
    		_ => {}
    	}
    }

    stream.write_all(&ti(string_length));

    string_length = 0;

    let mut buff: [u8; 24] = [0; 24];

    for elem in tuple {
    	match elem {
    		&E::Int(ref i) => {
				//tag
   	 			ctoi(&mut buff, asciiI, 0);
   	 			//union
   	 			ctoi(&mut buff, *i, 8);

   	 			stream.write_all(&buff);
    		},
    		&E::Double(ref d) => {
    			//tag
   	 			ctoi(&mut buff, asciiD, 0);
   	 			//union
   	 			ctod(&mut buff, *d, 8);
   	 			stream.write_all(&buff);

    		},
    		&E::Str(ref s) => {
    			//tag
   	 			ctoi(&mut buff, asciiS, 0);

   	 			//union
   	 			ctoi(&mut buff, string_length, 8);
   	 			ctoi(&mut buff, s.len() as i32, 16);

   	 			//tuple pointer
   	 			stream.write_all(&buff);

   	 			string_length += s.len() as i32;
    		}
    		&E::None => {
    		}
    	}
    }

    for elem in tuple {
    	match elem {
    		&E::Str(ref s) => {
    			stream.write_all(s.as_bytes());
    		}
    		_ => {}
    	}
    }
}

fn put_tuple(tuple: &[E], connection: &SocketAddr) {
    let mut stream = TcpStream::connect(connection).unwrap();

	stream.write_all(&ti(PUT));

	send_tuple(tuple, &mut stream);

	//stream.shutdown(Shutdown::Write);
}

fn main() {
    let connection = ("127.0.0.1:5000").parse().unwrap();
    //let tuple = [E::Int(10), E::Double(10.1)];
    put_tuple(&[E::Str("LOLOLOLO".to_string()), E::Int(10), E::Double(10.2), E::Str("123".to_string())], &connection);
}
<commit_msg>PUT, GET, READ work<commit_after>use std::net::*;
use std::io::prelude::*;
use std::mem::*;
use std::vec::Vec;

#[repr(C)]
enum E {
    Int(i32),
    Double(f64),
    Str(String),
    None,
}

impl E {
	fn println(&self) {
		match self {
			&E::Int(ref i) => println!("Int: {}", i),
			&E::Double(ref d) => println!("Double: {}", d),
			&E::Str(ref s) => println!("String: {}", s),
			&E::None => println!("Wildcard"),
		}
	}
}

const PUT: i32 = 0;
const GET: i32 = 1;
const READ: i32 = 2;
/*
const GET_NB: i32 = 3;
const READ_NB: i32 = 4;
const DUMP: i32 = 5;
const COUNT: i32 = 6;
const LOG: i32 = 7;
const REPLACE: i32 = 8;
*/

const asciiS: i32 = 115;
const asciiI: i32 = 105;
const asciiD: i32 = 100;
const asciiQ: i32 = 63;
const asciiT: i32 = 116;

fn ti(i: i32) -> [u8; 4] {
	let buff: [u8; 4];
	unsafe {
		buff = transmute(i);
	}
	return buff;
}

fn ctoi(arr: &mut [u8; 24], mut val: i32, offset: isize) {
	unsafe {
		std::ptr::copy_nonoverlapping(&mut val as *mut _ as *mut u8, arr.as_ptr().offset(offset) as *mut u8, std::mem::size_of::<i32>());
	}
}

fn ciot(arr:&[u8; 24], offset:isize) -> i32 {
	let mut val: i32 = 0;

	unsafe {
		std::ptr::copy_nonoverlapping(arr.as_ptr().offset(offset) as *mut u8, &mut val as *mut _ as *mut u8, std::mem::size_of::<i32>());
	}

	return val;
}

fn cdot(arr:&[u8; 24], offset:isize) -> f64 {
	let mut val: f64 = 0.;
	unsafe {
		std::ptr::copy_nonoverlapping(arr.as_ptr().offset(offset) as *mut u8, &mut val as *mut _ as *mut u8, std::mem::size_of::<f64>());
	}
	return val;
}

fn ctod(arr: &mut [u8; 24], mut val: f64, offset: isize) {
	unsafe {
		std::ptr::copy_nonoverlapping(&mut val as *mut _ as *mut u8, arr.as_ptr().offset(offset) as *mut u8, std::mem::size_of::<f64>());
	}
}

fn send_tuple(tuple: &Vec<E>, stream: &mut TcpStream) {

    stream.write_all(& (ti(tuple.len() as i32)));

    let mut string_length:i32 = 0;

    for elem in tuple {
    	match elem {
    		&E::Str(ref s) => string_length += s.len() as i32,
    		_ => {}
    	}
    }

    stream.write_all(&ti(string_length));

    string_length = 0;

    let mut buff: [u8; 24] = [0; 24];

    for elem in tuple {
    	match elem {
    		&E::Int(ref i) => {
				//tag
   	 			ctoi(&mut buff, asciiI, 0);
   	 			//union
   	 			ctoi(&mut buff, *i, 8);

   	 			stream.write_all(&buff);
    		},
    		&E::Double(ref d) => {
    			//tag
   	 			ctoi(&mut buff, asciiD, 0);
   	 			//union
   	 			ctod(&mut buff, *d, 8);
   	 			stream.write_all(&buff);

    		},
    		&E::Str(ref s) => {
    			//tag
   	 			ctoi(&mut buff, asciiS, 0);

   	 			//union
   	 			ctoi(&mut buff, string_length, 8);
   	 			ctoi(&mut buff, s.len() as i32, 16);

   	 			//tuple pointer
   	 			stream.write_all(&buff);

   	 			string_length += s.len() as i32;
    		}
    		&E::None => {
    			ctoi(&mut buff, asciiQ, 0);

    			stream.write_all(&buff);
    		}
    	}
    }

    for elem in tuple {
    	match elem {
    		&E::Str(ref s) => {
    			stream.write_all(s.as_bytes());
    		}
    		_ => {}
    	}
    }
}

fn recv_tuple(stream: &mut TcpStream) -> Vec<E> {

	struct str_desc {
		used: bool,
		offset: i32,
		len: i32,
	}

	let mut tuple: Vec<E> = Vec::<E>::new();
	let mut str_descs: Vec<str_desc> = Vec::<str_desc>::new();

	let mut buff_4:[u8; 4] = [0; 4];
	let mut buff_8:[u8; 8] = [0; 8];
	let mut buff:[u8; 24] = [0; 24];

	stream.read_exact(&mut buff_4);
	let num_elements:i32 = unsafe { transmute(buff_4) };

	//non-blocking reads/writes
	if num_elements == -1 {
		return tuple;
	}

	stream.read_exact(&mut buff_4);
	let string_length:i32 = unsafe { transmute(buff_4) };

	for i in 0..num_elements {

		stream.read_exact(&mut buff);

		let tag: i32 = ciot(&buff, 0);

		match tag {
			asciiI => {
				tuple.push(E::Int(ciot(&buff, 8)));
				str_descs.push(str_desc { used: false, offset: 0, len: 0} );
			},
			asciiD => {
				tuple.push(E::Double(cdot(&buff, 8)));
				str_descs.push(str_desc { used: false, offset: 0, len: 0} );
			},
			asciiS => {
				str_descs.push(str_desc {
						used: true,
						offset: ciot(&buff, 8),
						len: ciot(&buff, 16),
					});
				tuple.push(E::Str("".to_string()));
			},
			asciiQ => {
				str_descs.push(str_desc { used: false, offset: 0, len: 0} );
			},
			_ => {

			}
		}
	}

	if string_length != 0 {
		let mut string_space:Vec<u8> = vec![0; string_length as usize];
		stream.read_exact(&mut string_space);

		let mut str_slice = string_space.as_slice();
		for i in 0..num_elements {
			if str_descs[i as usize].used == true {
				tuple[i as usize] = E::Str(String::from_utf8(
					string_space[
						(str_descs[i as usize].offset as usize)..
						(str_descs[i as usize].offset + str_descs[i as usize].len) as usize].to_vec()).unwrap());
			}
		}

	}

	return tuple;
}

fn put_tuple(tuple: &Vec<E>, connection: &SocketAddr) {
    let mut stream_err = TcpStream::connect(connection);
    match stream_err {
    	Ok(mut stream) => {
    		stream.write_all(&ti(PUT));
			send_tuple(tuple, &mut stream);
			stream.shutdown(Shutdown::Write);
    	}
    	Err(why) => {
    		println!("{}", why);
    	}
    }
}

fn get_tuple(tuple: &Vec<E>, connection: &SocketAddr) -> Vec<E>
{
	let mut stream_err = TcpStream::connect(connection);
	match stream_err {
		Ok(mut stream) => {
			stream.write_all(&ti(GET));

			send_tuple(tuple, &mut stream);

			stream.shutdown(Shutdown::Write);

			return recv_tuple(&mut stream);
		}
		Err(why) => {
			println!("{}", why);
			return Vec::<E>::new();
		}
	}
}

fn read_tuple(tuple: &Vec<E>, connection: &SocketAddr) -> Vec<E>
{
	let mut stream_err = TcpStream::connect(connection);
	match stream_err {
		Ok(mut stream) => {
			stream.write_all(&ti(READ));

			send_tuple(tuple, &mut stream);

			stream.shutdown(Shutdown::Write);

			return recv_tuple(&mut stream);
		}
		Err(why) => {
			println!("{}", why);
			return Vec::<E>::new();
		}
	}
}

fn main() {
    let connection: SocketAddr = ("127.0.0.1:5000").parse().unwrap();
    let tuple = vec![E::Int(10), E::Double(10.1), E::Str("123".to_string())];
    let tuple2 = vec![E::Str("12789".to_string()), E::Int(10), E::Double(5.), E::Str("1234".to_string())];
    let tuple3 = vec![E::Str("12abv".to_string()), E::Int(11), E::Double(5.), E::Str("123".to_string())];

    put_tuple(&tuple, &connection);
    put_tuple(&tuple2, &connection);
    put_tuple(&tuple3, &connection);

    let tuple4 = read_tuple(&vec![E::None, E::Double(10.1), E::None], &connection);

    for val in tuple4 {
    	val.println();
    }
}
<|endoftext|>


<commit_before>#![allow(dead_code)]
#[macro_use]

extern crate glium;
extern crate nalgebra as na;

mod model_data;
mod static_object;
mod global_render_params;
mod lights;

use global_render_params::GlobalRenderParams;

use glium::DisplayBuild;
use glium::Surface;
use std::error::Error;
use std::io::prelude::*;

const VERTS: [model_data::Vertex; 6] = [
    model_data::Vertex{ position: ( 1.0,  0.0,  0.0) },
    model_data::Vertex{ position: ( 0.0,  1.0,  0.0) },
    model_data::Vertex{ position: ( 0.0,  0.0,  1.0) },
    model_data::Vertex{ position: (-1.0,  0.0,  0.0) },
    model_data::Vertex{ position: ( 0.0, -1.0,  0.0) },
    model_data::Vertex{ position: ( 0.0,  0.0, -1.0) },
];
const NORMALS: [model_data::Normal; 6] = [
    model_data::Normal{ normal: ( 1.0,  0.0,  0.0) },
    model_data::Normal{ normal: ( 0.0,  1.0,  0.0) },
    model_data::Normal{ normal: ( 0.0,  0.0,  1.0) },
    model_data::Normal{ normal: (-1.0,  0.0,  0.0) },
    model_data::Normal{ normal: ( 0.0, -1.0,  0.0) },
    model_data::Normal{ normal: ( 0.0,  0.0, -1.0) },
];

const INDICES: [u16; 24] = [
    0,1,2,
    0,2,4,
    0,4,5,
    0,5,1,
    3,1,2,
    3,2,4,
    3,4,5,
    3,5,1,
];

fn get_view_matrix(position: &[f32; 3], direction: &[f32; 3]) -> [[f32; 4]; 4]
{
    //Make y axis up
    let up = [0.0, 1.0, 0.0];

    let f = {
        let f = direction;
        let len = f[0] * f[0] + f[1] * f[1] + f[2] * f[2];
        let len = len.sqrt();

        //Final value
        [f[0] / len, f[1] / len, f[2] / len]
    };

    let s = [up[1] * f[2] - up[2] * f[1],
             up[2] * f[0] - up[0] * f[2],
             up[0] * f[1] - up[1] * f[0]];

    let s_norm = {
        let len = s[0] * s[0] + s[1] * s[1] + s[2] * s[2];
        let len = len.sqrt();

        //final value
        [s[0] / len, s[1] / len, s[2] / len]
    };

    let u = [f[1] * s_norm[2] - f[2] * s_norm[1],
             f[2] * s_norm[0] - f[0] * s_norm[2],
             f[0] * s_norm[1] - f[1] * s_norm[0]];

    let p = [-position[0] * s_norm[0] - position[1] * s_norm[1] - position[2] * s_norm[2],
             -position[0] * u[0] - position[1] * u[1] - position[2] * u[2],
             -position[0] * f[0] - position[1] * f[1] - position[2] * f[2]];

    [
        [s[0], u[0], f[0], 0.0],
        [s[1], u[1], f[1], 0.0],
        [s[2], u[2], f[2], 0.0],
        [p[0], p[1], p[2], 1.0],
    ]
}

fn get_basic_shader(display: &glium::backend::glutin_backend::GlutinFacade) -> glium::Program
{
    let vertex_shader_src = r#"
        #version 140

        in vec3 position;
        in vec3 normal;

        uniform mat4 modelMatrix;

        uniform worldData
        {
            mat4 view_matrix;
            mat4 projection_matrix;
        };

        out vec3 vertex_color;

        vec4 pos;

        void main()
        {
            mat4 modelViewMatrix = view_matrix * modelMatrix;
            pos = projection_matrix * modelViewMatrix * (vec4(position, 1.0));

            vertex_color = (position.xyz + vec3(1, 1, 1)) / 2;

            gl_Position = pos;
        }
    "#;
    let fragment_shader_src = r#"
        #version 140

        in vec3 position;

        in vec3 vertex_color;

        out vec4 color;

        void main()
        {
            color = vec4(vertex_color, 1.0);
        }
    "#;

    //Set up the shader
    glium::Program::from_source(display, vertex_shader_src, fragment_shader_src, None).unwrap()
}

fn load_whole_file(path: &String) -> String
{
    let file_path = std::path::Path::new(&path);

    let mut file = match std::fs::File::open(&file_path){
        Err(why) => panic!("Failed to open file {}, {}", &path, Error::description(&why)),

        Ok(open_file) => open_file
    };

    let mut result = String::new();
    match file.read_to_string(&mut result) {
        Err(why) => panic!("Failed to read content of file {}, {}", &path, Error::description(&why)),
        Ok(a) => a
    };

    result
}
fn load_shader(display: &glium::Display, vert_path: &String, frag_path: &String)
    -> glium::Program
{
    let vertex_shader_src = load_whole_file(vert_path);
    let fragment_shader_src = load_whole_file(frag_path);

    //Set up the shader
    glium::Program::from_source(display, vertex_shader_src.as_str(), fragment_shader_src.as_str(), None).unwrap()
}

fn get_perspective_matrix(target: &glium::Frame) -> [[f32; 4]; 4]
{
    let (width, height) = target.get_dimensions();
    let aspect_ratio = height as f32 / width as f32;

    let fov :f32 = 3.14 / 2.0;
    let zfar :f32 = 4096.0;
    let znear :f32 = 0.1;

    let f = 1.0 / (fov / 2.0).tan();

    [
        [f * aspect_ratio, 0.0, 0.0, 0.0],
        [0.0, f, 0.0, 0.0],
        [0.0, 0.0, (zfar + znear) / (zfar - znear), 1.0],
        [0.0, 0.0, -(2.0 * zfar * znear) / (zfar - znear), 0.0]
    ]
}

fn main()
{
    let mut t: f32 = 0.0;

    let display = glium::glutin::WindowBuilder::new()
                            .with_depth_buffer(24)
                            .build_glium()
                            .unwrap();

    let test_verts = vec!{
            model_data::Vertex{position: ( 1.0,  0.0,  0.0)},
            model_data::Vertex{position: ( 0.0,  1.0,  0.0)},
            model_data::Vertex{position: ( 0.0,  0.0,  1.0)},
            model_data::Vertex{position: (-1.0,  0.0,  0.0)},
            model_data::Vertex{position: ( 0.0, -1.0,  0.0)},
            model_data::Vertex{position: ( 0.0,  0.0, -1.0)}
        };
    let test_normals = vec!{
            model_data::Normal{normal: ( 1.0,  0.0,  0.0)},
            model_data::Normal{normal: ( 0.0,  1.0,  0.0)},
            model_data::Normal{normal: ( 0.0,  0.0,  1.0)},
            model_data::Normal{normal: ( 0.0,  0.0,  0.0)},
            model_data::Normal{normal: (-1.0,  0.0,  0.0)},
            model_data::Normal{normal: ( 0.0, -1.0,  0.0)},
            model_data::Normal{normal: ( 0.0,  0.0, -1.0)}
        };

    let test_indices = vec!{
        0,1,2,
        0,2,4,
        0,4,5,
        0,5,1,
        3,1,2,
        3,2,4,
        3,4,5,
        3,5,1,
    };
    let mut test_object = static_object::StaticObject::new(&display, &test_verts, &test_normals, &test_indices);

    let mut model_matrix = [
        [1.0, 0.0, 0.0, 0.0],
        [0.0, 1.0, 0.0, 0.0],
        [0.0, 0.0, 1.0, 0.0],
        [-2.0, 0.0, 0.0, 1.0f32],
    ];

    //let shader_program = get_basic_shader(&display);
    let shader_program = load_shader(&display, &"data/shaders/basic.vert".to_string(), &"data/shaders/basic.frag".to_string());

    let params = glium::DrawParameters {
        depth: glium::Depth {
            test: glium::draw_parameters::DepthTest::IfLess,
            write: true,
            .. Default::default()
        },
        .. Default::default()
    };

    let light = lights::LightUniform::new();

    loop
    {
        t += 0.01;

        //Rotate the model
        model_matrix[0][0] = t.cos();
        model_matrix[1][1] = t.cos();
        model_matrix[0][1] = t.sin();
        model_matrix[1][0] = -t.sin();

        let mut target = display.draw();
        target.clear_color_and_depth((0.0, 0.0 ,0.0 ,1.0), 1.0);

        //Creating the perspective matrix
        let perspective = get_perspective_matrix(&target);

        let view_matrix = get_view_matrix(&[0.0, 0.0, 4.0], &[0.0, 0.0, -1.0]);

        let vertex_buffer = glium::VertexBuffer::new(&display, &VERTS).unwrap();
        let normal_buffer = glium::VertexBuffer::new(&display, &NORMALS).unwrap();
        //let indices = glium::index::NoIndices(glium::index::PrimitiveType::TrianglesList);
        let indices = glium::IndexBuffer::new(&display, glium::index::PrimitiveType::TrianglesList, &INDICES).unwrap();

        let render_params = GlobalRenderParams{ view_matrix: view_matrix, projection_matrix: perspective };
        let light_buffer = glium::uniforms::UniformBuffer::new(&display, light).unwrap();
        let sphere_buffer = glium::uniforms::UniformBuffer::new(&display, lights::SphericalLight::new());

        let world_buffer = glium::uniforms::UniformBuffer::new(&display, render_params).unwrap();

        let uniforms = uniform!{
                modelMatrix: model_matrix,
                perspective: perspective,
                viewMatrix: view_matrix,

                worldData: &world_buffer,
                lights: light_buffer,
                sphere: &sphere_buffer,
            };

        target.draw((&vertex_buffer, &normal_buffer), &indices, &shader_program, &uniforms, &params).unwrap();

        test_object.set_position(&na::Vec4::new(t.cos(), 0.0, 0.0, 1.0));
        //test_object.draw(&mut target, &shader_program, &world_buffer, &light_buffer, &params);

        //Finish drawing and send the result off to the window
        target.finish().unwrap();

        for ev in display.poll_events()
        {
            match ev
            {
                glium::glutin::Event::Closed => return,
                _ => ()
            }
        }
    }
}
<commit_msg>Light experiments<commit_after>#![allow(dead_code)]
#[macro_use]

extern crate glium;
extern crate nalgebra as na;

mod model_data;
mod static_object;
mod global_render_params;
mod lights;

use global_render_params::GlobalRenderParams;

use glium::DisplayBuild;
use glium::Surface;
use std::error::Error;
use std::io::prelude::*;

const VERTS: [model_data::Vertex; 6] = [
    model_data::Vertex{ position: ( 1.0,  0.0,  0.0) },
    model_data::Vertex{ position: ( 0.0,  1.0,  0.0) },
    model_data::Vertex{ position: ( 0.0,  0.0,  1.0) },
    model_data::Vertex{ position: (-1.0,  0.0,  0.0) },
    model_data::Vertex{ position: ( 0.0, -1.0,  0.0) },
    model_data::Vertex{ position: ( 0.0,  0.0, -1.0) },
];
const NORMALS: [model_data::Normal; 6] = [
    model_data::Normal{ normal: ( 1.0,  0.0,  0.0) },
    model_data::Normal{ normal: ( 0.0,  1.0,  0.0) },
    model_data::Normal{ normal: ( 0.0,  0.0,  1.0) },
    model_data::Normal{ normal: (-1.0,  0.0,  0.0) },
    model_data::Normal{ normal: ( 0.0, -1.0,  0.0) },
    model_data::Normal{ normal: ( 0.0,  0.0, -1.0) },
];

const INDICES: [u16; 24] = [
    0,1,2,
    0,2,4,
    0,4,5,
    0,5,1,
    3,1,2,
    3,2,4,
    3,4,5,
    3,5,1,
];

fn get_view_matrix(position: &[f32; 3], direction: &[f32; 3]) -> [[f32; 4]; 4]
{
    //Make y axis up
    let up = [0.0, 1.0, 0.0];

    let f = {
        let f = direction;
        let len = f[0] * f[0] + f[1] * f[1] + f[2] * f[2];
        let len = len.sqrt();

        //Final value
        [f[0] / len, f[1] / len, f[2] / len]
    };

    let s = [up[1] * f[2] - up[2] * f[1],
             up[2] * f[0] - up[0] * f[2],
             up[0] * f[1] - up[1] * f[0]];

    let s_norm = {
        let len = s[0] * s[0] + s[1] * s[1] + s[2] * s[2];
        let len = len.sqrt();

        //final value
        [s[0] / len, s[1] / len, s[2] / len]
    };

    let u = [f[1] * s_norm[2] - f[2] * s_norm[1],
             f[2] * s_norm[0] - f[0] * s_norm[2],
             f[0] * s_norm[1] - f[1] * s_norm[0]];

    let p = [-position[0] * s_norm[0] - position[1] * s_norm[1] - position[2] * s_norm[2],
             -position[0] * u[0] - position[1] * u[1] - position[2] * u[2],
             -position[0] * f[0] - position[1] * f[1] - position[2] * f[2]];

    [
        [s[0], u[0], f[0], 0.0],
        [s[1], u[1], f[1], 0.0],
        [s[2], u[2], f[2], 0.0],
        [p[0], p[1], p[2], 1.0],
    ]
}

fn get_basic_shader(display: &glium::backend::glutin_backend::GlutinFacade) -> glium::Program
{
    let vertex_shader_src = r#"
        #version 140

        in vec3 position;
        in vec3 normal;

        uniform mat4 modelMatrix;

        uniform worldData
        {
            mat4 view_matrix;
            mat4 projection_matrix;
        };

        out vec3 vertex_color;

        vec4 pos;

        void main()
        {
            mat4 modelViewMatrix = view_matrix * modelMatrix;
            pos = projection_matrix * modelViewMatrix * (vec4(position, 1.0));

            vertex_color = (position.xyz + vec3(1, 1, 1)) / 2;

            gl_Position = pos;
        }
    "#;
    let fragment_shader_src = r#"
        #version 140

        in vec3 position;

        in vec3 vertex_color;

        out vec4 color;

        void main()
        {
            color = vec4(vertex_color, 1.0);
        }
    "#;

    //Set up the shader
    glium::Program::from_source(display, vertex_shader_src, fragment_shader_src, None).unwrap()
}

fn load_whole_file(path: &String) -> String
{
    let file_path = std::path::Path::new(&path);

    let mut file = match std::fs::File::open(&file_path){
        Err(why) => panic!("Failed to open file {}, {}", &path, Error::description(&why)),

        Ok(open_file) => open_file
    };

    let mut result = String::new();
    match file.read_to_string(&mut result) {
        Err(why) => panic!("Failed to read content of file {}, {}", &path, Error::description(&why)),
        Ok(a) => a
    };

    result
}
fn load_shader(display: &glium::Display, vert_path: &String, frag_path: &String)
    -> glium::Program
{
    let vertex_shader_src = load_whole_file(vert_path);
    let fragment_shader_src = load_whole_file(frag_path);

    //Set up the shader
    glium::Program::from_source(display, vertex_shader_src.as_str(), fragment_shader_src.as_str(), None).unwrap()
}

fn get_perspective_matrix(target: &glium::Frame) -> [[f32; 4]; 4]
{
    let (width, height) = target.get_dimensions();
    let aspect_ratio = height as f32 / width as f32;

    let fov :f32 = 3.14 / 2.0;
    let zfar :f32 = 4096.0;
    let znear :f32 = 0.1;

    let f = 1.0 / (fov / 2.0).tan();

    [
        [f * aspect_ratio, 0.0, 0.0, 0.0],
        [0.0, f, 0.0, 0.0],
        [0.0, 0.0, (zfar + znear) / (zfar - znear), 1.0],
        [0.0, 0.0, -(2.0 * zfar * znear) / (zfar - znear), 0.0]
    ]
}

fn main()
{
    let mut t: f32 = 0.0;

    let display = glium::glutin::WindowBuilder::new()
                            .with_depth_buffer(24)
                            .build_glium()
                            .unwrap();

    let test_verts = vec!{
            model_data::Vertex{position: ( 1.0,  0.0,  0.0)},
            model_data::Vertex{position: ( 0.0,  1.0,  0.0)},
            model_data::Vertex{position: ( 0.0,  0.0,  1.0)},
            model_data::Vertex{position: (-1.0,  0.0,  0.0)},
            model_data::Vertex{position: ( 0.0, -1.0,  0.0)},
            model_data::Vertex{position: ( 0.0,  0.0, -1.0)}
        };
    let test_normals = vec!{
            model_data::Normal{normal: ( 1.0,  0.0,  0.0)},
            model_data::Normal{normal: ( 0.0,  1.0,  0.0)},
            model_data::Normal{normal: ( 0.0,  0.0,  1.0)},
            model_data::Normal{normal: ( 0.0,  0.0,  0.0)},
            model_data::Normal{normal: (-1.0,  0.0,  0.0)},
            model_data::Normal{normal: ( 0.0, -1.0,  0.0)},
            model_data::Normal{normal: ( 0.0,  0.0, -1.0)}
        };

    let test_indices = vec!{
        0,1,2,
        0,2,4,
        0,4,5,
        0,5,1,
        3,1,2,
        3,2,4,
        3,4,5,
        3,5,1,
    };
    let mut test_object = static_object::StaticObject::new(&display, &test_verts, &test_normals, &test_indices);

    let mut model_matrix = [
        [1.0, 0.0, 0.0, 0.0],
        [0.0, 1.0, 0.0, 0.0],
        [0.0, 0.0, 1.0, 0.0],
        [-2.0, 0.0, 0.0, 1.0f32],
    ];

    //let shader_program = get_basic_shader(&display);
    let shader_program = load_shader(&display, &"data/shaders/basic.vert".to_string(), &"data/shaders/basic.frag".to_string());

    let params = glium::DrawParameters {
        depth: glium::Depth {
            test: glium::draw_parameters::DepthTest::IfLess,
            write: true,
            .. Default::default()
        },
        .. Default::default()
    };

    let light = lights::LightUniform::new();

    loop
    {
        t += 0.01;

        //Rotate the model
        model_matrix[0][0] = t.cos();
        model_matrix[1][1] = t.cos();
        model_matrix[0][1] = t.sin();
        model_matrix[1][0] = -t.sin();

        let mut target = display.draw();
        target.clear_color_and_depth((0.0, 0.0 ,0.0 ,1.0), 1.0);

        //Creating the perspective matrix
        let perspective = get_perspective_matrix(&target);

        let view_matrix = get_view_matrix(&[0.0, 0.0, 4.0], &[0.0, 0.0, -1.0]);

        let vertex_buffer = glium::VertexBuffer::new(&display, &VERTS).unwrap();
        let normal_buffer = glium::VertexBuffer::new(&display, &NORMALS).unwrap();
        //let indices = glium::index::NoIndices(glium::index::PrimitiveType::TrianglesList);
        let indices = glium::IndexBuffer::new(&display, glium::index::PrimitiveType::TrianglesList, &INDICES).unwrap();

        let render_params = GlobalRenderParams{ view_matrix: view_matrix, projection_matrix: perspective };
        let light_buffer = glium::uniforms::UniformBuffer::new(&display, light).unwrap();
        //let sphere_buffer = glium::uniforms::UniformBuffer::new(&display, lights::SphericalLight::new());

        let world_buffer = glium::uniforms::UniformBuffer::new(&display, render_params).unwrap();

        let uniforms = uniform!{
                modelMatrix: model_matrix,
                perspective: perspective,
                viewMatrix: view_matrix,

                worldData: &world_buffer,
                lights: light_buffer,
                //sphere: &sphere_buffer,
            };

        target.draw((&vertex_buffer, &normal_buffer), &indices, &shader_program, &uniforms, &params).unwrap();

        test_object.set_position(&na::Vec4::new(t.cos(), 0.0, 0.0, 1.0));
        //test_object.draw(&mut target, &shader_program, &world_buffer, &light_buffer, &params);

        //Finish drawing and send the result off to the window
        target.finish().unwrap();

        for ev in display.poll_events()
        {
            match ev
            {
                glium::glutin::Event::Closed => return,
                _ => ()
            }
        }
    }
}
<|endoftext|>


<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */

extern crate "rust-md2" as md2;

use md2::{S, S2, md2_compress};
use std::collections::HashMap;
use std::collections::hash_map::{Occupied, Vacant};
use std::slice::bytes::copy_memory;

type Collision = Vec<Vec<u8>>;
type Collisions = Vec<Collision>;

fn find_collisions(rows: uint) -> Collisions {
    let mut values = create_initial_state(rows);
    let mut bytes = Vec::from_elem(16 - rows, 0u8);
    let mut collisions: HashMap<Vec<u8>,Collision> = HashMap::new();

    loop {
        copy_memory(values[rows].slice_mut(17, 17 + 16 - rows), bytes.as_slice());
        copy_memory(values[rows].slice_mut(17 + 16, 17 + 16 - rows + 16), bytes.as_slice());

        for row in range(rows + 1, 18) {
            // Fill row.
            for i in range(1, 49) {
                values[row][i] = S[values[row][i - 1] as uint] ^ values[row - 1][i];
            }

            // Next t value.
            values[row + 1][0] = values[row][48] + (row as u8) - 1;
        }

        let key = Vec::from_fn(17 - rows, |row| values[rows + 2 + row][0]);

        match collisions.entry(key) {
            Vacant(entry) => { entry.set(vec!(bytes.clone())); },
            Occupied(mut entry) => { entry.get_mut().push(bytes.clone()); }
        };

        if !increase(bytes.as_mut_slice()) {
            break;
        }
    }

    // Compute original messages for each collision.
    collisions.values().filter(|x| x.len() > 1).map(|collision| {
        collision.iter().map(|bytes| {
            copy_memory(values[rows].slice_mut(17, 17 + 16 - rows), bytes.as_slice());
            copy_memory(values[rows].slice_mut(17 + 16, 17 + 16 - rows + 16), bytes.as_slice());

            // Fill upper rectangles.
            for row in range(1, rows + 1).rev() {
                for col in range(17, 32 - row + 2) {
                    values[row - 1][col] = S[values[row][col - 1] as uint] ^ values[row][col];
                }
            }

            values[0].slice(17, 33).to_vec()
        }).collect()
    }).collect()
}

fn create_initial_state(rows: uint) -> [[u8, ..49], ..19] {
    let mut values = [[0u8, ..49], ..19];

    for row in range(1, rows + 1) {
        // Fill row of T1.
        for i in range(1, 17) {
            values[row][i] = S[values[row][i - 1] as uint] ^ values[row - 1][i];
        }

        // Last bytes are equal.
        values[row][32] = values[row][16];
        values[row][48] = values[row][16];

        // Next t value.
        values[row + 1][0] = values[row][48] + (row as u8) - 1;
    }

    // Compute triangles.
    for col in range(0, rows) {
        for row in range(2 + col, rows + 1).rev() {
            values[row][32 - col - 1] = S2[(values[row][32 - col] ^ values[row - 1][32 - col]) as uint];
            values[row][48 - col - 1] = S2[(values[row][48 - col] ^ values[row - 1][48 - col]) as uint];
        }
    }

    values
}

fn increase(num: &mut [u8]) -> bool {
    let len = num.len();

    for i in range(0, len).rev() {
        if num[i] == 255 {
            continue;
        }

        num[i] += 1;

        for i in range(i + 1, len) {
            num[i] = 0;
        }

        return true;
    }

    false
}

fn check_collisions(collisions: &Collisions) -> bool {
    let empty = [0u8, ..16];

    for collision in collisions.iter() {
        let mut first_hash: Option<[u8, ..16]> = None;

        for msg in collision.iter() {
            let md2 = md2_compress(&empty, msg.as_slice());

            match first_hash {
                Some(hash) => {
                    if hash != md2 {
                        return false;
                    }
                }
                None => first_hash = Some(md2)
            };
        }
    }

    true
}

fn main() {
    let collisions = find_collisions(14);
    if !check_collisions(&collisions) {
        panic!("invalid collision found :(");
    }

    println!("Found {} collisions.", collisions.iter().count());
}
<commit_msg>use k values<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */

extern crate "rust-md2" as md2;

use md2::{S, S2, md2_compress};
use std::collections::HashMap;
use std::collections::hash_map::{Occupied, Vacant};
use std::slice::bytes::copy_memory;

type Collision = Vec<Vec<u8>>;
type Collisions = Vec<Collision>;

fn find_collisions(k: uint) -> Collisions {
    let mut values = create_initial_state(k);
    let mut bytes = Vec::from_elem(k, 0u8);
    let mut collisions: HashMap<Vec<u8>,Collision> = HashMap::new();

    let rows = 16 - k;

    loop {
        copy_memory(values[rows].slice_mut(17, 17 + k), bytes.as_slice());
        copy_memory(values[rows].slice_mut(17 + 16, 17 + k + 16), bytes.as_slice());

        for row in range(rows + 1, 18) {
            // Fill row.
            for i in range(1, 49) {
                values[row][i] = S[values[row][i - 1] as uint] ^ values[row - 1][i];
            }

            // Next t value.
            values[row + 1][0] = values[row][48] + (row as u8) - 1;
        }

        let key = Vec::from_fn(17 - rows, |row| values[rows + 2 + row][0]);

        match collisions.entry(key) {
            Vacant(entry) => { entry.set(vec!(bytes.clone())); },
            Occupied(mut entry) => { entry.get_mut().push(bytes.clone()); }
        };

        if !increase(bytes.as_mut_slice()) {
            break;
        }
    }

    // Compute original messages for each collision.
    collisions.values().filter(|x| x.len() > 1).map(|collision| {
        collision.iter().map(|bytes| {
            copy_memory(values[rows].slice_mut(17, 17 + k), bytes.as_slice());
            copy_memory(values[rows].slice_mut(17 + 16, 17 + k + 16), bytes.as_slice());

            // Fill upper rectangles.
            for row in range(1, rows + 1).rev() {
                for col in range(17, 32 - row + 2) {
                    values[row - 1][col] = S[values[row][col - 1] as uint] ^ values[row][col];
                }
            }

            values[0].slice(17, 33).to_vec()
        }).collect()
    }).collect()
}

fn create_initial_state(k: uint) -> [[u8, ..49], ..19] {
    let rows = 16 - k;
    let mut values = [[0u8, ..49], ..19];

    for row in range(1, rows + 1) {
        // Fill row of T1.
        for i in range(1, 17) {
            values[row][i] = S[values[row][i - 1] as uint] ^ values[row - 1][i];
        }

        // Last bytes are equal.
        values[row][32] = values[row][16];
        values[row][48] = values[row][16];

        // Next t value.
        values[row + 1][0] = values[row][48] + (row as u8) - 1;
    }

    // Compute triangles.
    for col in range(0, rows) {
        for row in range(2 + col, rows + 1).rev() {
            values[row][32 - col - 1] = S2[(values[row][32 - col] ^ values[row - 1][32 - col]) as uint];
            values[row][48 - col - 1] = S2[(values[row][48 - col] ^ values[row - 1][48 - col]) as uint];
        }
    }

    values
}

fn increase(num: &mut [u8]) -> bool {
    let len = num.len();

    for i in range(0, len).rev() {
        if num[i] == 255 {
            continue;
        }

        num[i] += 1;

        for i in range(i + 1, len) {
            num[i] = 0;
        }

        return true;
    }

    false
}

fn check_collisions(collisions: &Collisions) -> bool {
    let empty = [0u8, ..16];

    for collision in collisions.iter() {
        let mut first_hash: Option<[u8, ..16]> = None;

        for msg in collision.iter() {
            let md2 = md2_compress(&empty, msg.as_slice());

            match first_hash {
                Some(hash) => {
                    if hash != md2 {
                        return false;
                    }
                }
                None => first_hash = Some(md2)
            };
        }
    }

    true
}

fn main() {
    let collisions = find_collisions(2);
    if !check_collisions(&collisions) {
        panic!("invalid collision found :(");
    }

    println!("Found {} collisions.", collisions.iter().count());
}
<|endoftext|>


<commit_before>use std::env;
use std::fs::File;
use std::io::{BufRead, BufReader};
use std::process;

fn print_help() {
    println!("-h : help");
    println!("-p : package (first column)");
    println!("-f : file to read");
    println!("-s : start value for keys");
}

fn main() {
    let mut package = None;
    let mut start = 0;
    let mut file = None;
    for arg in env::args() {
        let arg = arg.split('=').collect::<Vec<&str>>();
        match arg[0] {
            "-h" => { // Help
                print_help();
                process::exit(0);
            },
            "-p" => { // Package
                package = Some(arg[1].to_string());
            },
            "-f" => { // File
                file = Some(File::open(arg[1]).unwrap());
            },
            "-s" => { // Start value
                start = arg[1].parse().unwrap();
            },
            _ => {
            }
        }
    }
    if let None = file {
        print_help();
        process::exit(0);
    }
    if let None = package {
        print_help();
        process::exit(0);
    }
    let package = package.unwrap();
    let file = BufReader::new(file.unwrap());
    let mut count = 0;
    for line in file.lines().filter_map(|result| result.ok()) {
        match line.chars().nth(0) {
            Some('#') | Some('\n') | Some('\r') | None => {
                continue;
            },
            _ => {
            }
        }
        count += 1;
        let mut parts = line.splitn(4, " ");
        let _ = parts.next().unwrap(); // 'set'
        let path = parts.next().unwrap();
        let key = parts.next().unwrap();
        let val = parts.next().unwrap();
        print!(",\"{},{},{},,{}\"", package, path, key, val);
    }
    println!("");
    println!("");
    for i in 0..count {
        print!(",\"SparkOnDemandPatchEntry{}\"", i + start);
    }
    println!("");
}
<commit_msg>Multi-file version<commit_after>use std::env;
use std::fs::File;
use std::path::{Path, PathBuf};
use std::io::{BufRead, BufReader};

fn print_help() {
    println!("-h : help");
    println!("-f : files to read, comma separated list");
}

enum HotfixType {
    OnDemand(Option<String>),
    Level(Option<String>),
    Patch
}

fn main() {
    let mut files = None;
    for arg in env::args() {
        let arg = arg.split('=').collect::<Vec<&str>>();
        match arg[0] {
            "-h" => { // Help
                print_help();
                return;
            },
            "-f" => { // Files
                files = Some(arg[1].split(',').map(|x| (Path::new(x).to_path_buf(), File::open(x).unwrap())).collect::<Vec<(PathBuf, File)>>());
            },
            _ => {
            }
        }
    }
    if let None = files {
        print_help();
        return;
    }
    let files = files.unwrap();
    if files.len() == 0 {
        print_help();
        return;
    }

    let mut keys = Vec::new();
    let mut values = Vec::new();

    let mut on_demand_index = 1;
    let mut level_index = 1;
    let mut patch_index = 1;

    let mut current_type = HotfixType::Patch;

    for file in files {
        let prefix = file.0.file_name().unwrap().to_str().unwrap().splitn(2, ".").next().unwrap();
        let file = BufReader::new(file.1);

        for line in file.lines().filter_map(|result| result.ok()) {
            match line.chars().nth(0) {
                Some('#') | Some('\n') | Some('\r') | None => {
                    continue;
                },
                _ => {
                }
            }
            let mut parts = line.splitn(2, " ");
            let command = parts.next().unwrap().to_lowercase();
            let data = parts.next().unwrap();
            match command.as_str() {
                "set" => {
                    let mut parts = data.splitn(3, " ");
                    match &current_type {
                        &HotfixType::Level(ref x) => {
                            keys.push(format!("SparkLevelPatchEntry-{}{}", prefix, level_index));
                            values.push(format!("{},{},{},,{}", x.clone().unwrap_or("".to_string()), parts.next().unwrap(), parts.next().unwrap(), parts.next().unwrap()));
                            level_index += 1;
                        },
                        &HotfixType::OnDemand(ref x) => {
                            keys.push(format!("SparkOnDemandPatchEntry-{}{}", prefix, on_demand_index));
                            values.push(format!("{},{},{},,{}", x.clone().unwrap_or("".to_string()), parts.next().unwrap(), parts.next().unwrap(), parts.next().unwrap()));
                            on_demand_index += 1;
                        },
                        &HotfixType::Patch => {
                            keys.push(format!("SparkPatchEntry-{}{}", prefix, patch_index));
                            values.push(format!("{},{},,{}", parts.next().unwrap(), parts.next().unwrap(), parts.next().unwrap()));
                            patch_index += 1;
                        }
                    }
                },
                "set_cmp" => {
                    let mut parts = data.splitn(4, " ");
                    match &current_type {
                        &HotfixType::Level(ref x) => {
                            keys.push(format!("SparkLevelPatchEntry-{}{}", prefix, level_index));
                            values.push(format!("{},{},{},{},{}", x.clone().unwrap_or("".to_string()), parts.next().unwrap(), parts.next().unwrap(), parts.next().unwrap(), parts.next().unwrap()));
                            level_index += 1;
                        },
                        &HotfixType::OnDemand(ref x) => {
                            keys.push(format!("SparkOnDemandPatchEntry-{}{}", prefix, on_demand_index));
                            values.push(format!("{},{},{},{},{}", x.clone().unwrap_or("".to_string()), parts.next().unwrap(), parts.next().unwrap(), parts.next().unwrap(), parts.next().unwrap()));
                            on_demand_index += 1;
                        },
                        &HotfixType::Patch => {
                            keys.push(format!("SparkPatchEntry-{}{}", prefix, patch_index));
                            values.push(format!("{},{},{},{}", parts.next().unwrap(), parts.next().unwrap(), parts.next().unwrap(), parts.next().unwrap()));
                            patch_index += 1;
                        }
                    }
                },
                "start" => {
                    // Level, OnDemand, and Patch
                    let mut parts = data.splitn(2, " ");
                    let command = parts.next().unwrap().to_lowercase();
                    match command.as_str() {
                        "ondemand" => {
                            let package = parts.next().unwrap();
                            current_type = HotfixType::OnDemand(if package.to_lowercase() == "none" {
                                None
                            } else {
                                Some(package.to_string())
                            });
                        },
                        "level" => {
                            let package = parts.next().unwrap();
                            current_type = HotfixType::Level(if package.to_lowercase() == "none" {
                                None
                            } else {
                                Some(package.to_string())
                            });
                        },
                        "patch" => {
                            current_type = HotfixType::Patch;
                        },
                        _ => {
                        }
                    }
                },
                _ => {
                }
            }
        }
    }
    print!("set Transient.SparkServiceConfiguration_6 Keys (");
    for i in 0..keys.len() {
        if i != 0 {
            print!(",");
        }
        print!("\"{}\"", keys[i]);
    }
    println!(")\r");
    println!("\r");
    println!("\r");
    print!("set Transient.SparkServiceConfiguration_6 Values (");
    for i in 0..values.len() {
        if i != 0 {
            print!(",");
        }
        print!("\"{}\"", values[i]);
    }
    println!(")\r");
}
<|endoftext|>


<commit_before>extern crate time;
extern crate toml;
extern crate rustc_serialize;
extern crate kernel32;
extern crate kernel32x;
extern crate winapi;
#[macro_use]
extern crate log;
extern crate simplelog;
extern crate clap;

use std::process::exit;
use simplelog::{TermLogger, LogLevelFilter};
use clap::{App, AppSettings, SubCommand};
use std::ffi::OsStr;
use std::os::windows::ffi::OsStrExt;
use std::path::Path;

mod config;
mod cygpath;
mod vss;
mod backup;

fn to_wstring(str: &str) -> Vec<u16> {
  let v: Vec<u16> = OsStr::new(str).encode_wide().chain(Some(0).into_iter()).collect();
  v
}

#[cfg(debug_assertions)]
pub fn get_exe_dir() -> String {
  return "vendor".to_owned();
}

#[cfg(not(debug_assertions))]
pub fn get_exe_dir() -> String {
  let mut path: Vec<u16> = vec![0; winapi::MAX_PATH];
  unsafe {
    kernel32x::GetModuleFileNameW(0 as winapi::HMODULE,
                                  path.as_mut_ptr(),
                                  winapi::MAX_PATH as u32);
  }
  let path = String::from_utf16(path.as_slice()).unwrap();
  let path = Path::new(&path);
  let parent = path.parent().unwrap();
  parent.to_str().unwrap().to_owned()
}

fn cmd_auto() {
  let mut cfg = match config::Config::parse("config.toml") {
    Ok(c) => c,
    Err(e) => {
      error!("{}", e);
      exit(1);
    }
  };

  let mut v = vss::Vss::new();
  v.create(&cfg).unwrap(); // destroyed on drop
  let mapped_drives = v.get_mapped_drives();

  // Fix up the config.
  cfg.create.sources = cfg.create
    .sources
    .iter()
    .map(|source| {
      if !mapped_drives.is_empty() {
        if let Some(l) = mapped_drives.get(&source.chars().nth(0).unwrap()) {
          let mut s = String::new();
          s.push(*l);
          s.push_str(&source[1..]);
          return cygpath::from_win(s);
        }
      }

      cygpath::from_win(source)
    })
    .collect();

  backup::init(&cfg);
  backup::create(&cfg);
  backup::purge(&cfg);
  backup::check(&cfg);
}

fn main() {
  TermLogger::init(LogLevelFilter::Info).unwrap();

  let app = App::new("ckbackup")
    .setting(AppSettings::SubcommandRequiredElseHelp)
    .version("0.0.1")
    .author("Kevin Darlington <kevin@outroot.com>")
    .about("A VSS enabled wrapper around Borg to be used in automated scripts.")
    .subcommand(SubCommand::with_name("auto").about("Does automatic backup based on config.toml."));
  let matches = app.get_matches();

  match matches.subcommand() {
    ("auto", Some(_)) => cmd_auto(),
    _ => {}
  };
}
<commit_msg>Import fix.<commit_after>extern crate time;
extern crate toml;
extern crate rustc_serialize;
extern crate kernel32;
extern crate kernel32x;
extern crate winapi;
#[macro_use]
extern crate log;
extern crate simplelog;
extern crate clap;

use std::process::exit;
use simplelog::{TermLogger, LogLevelFilter};
use clap::{App, AppSettings, SubCommand};
use std::ffi::OsStr;
use std::os::windows::ffi::OsStrExt;

#[cfg(not(debug_assertions))]
use std::path::Path;

mod config;
mod cygpath;
mod vss;
mod backup;

fn to_wstring(str: &str) -> Vec<u16> {
  let v: Vec<u16> = OsStr::new(str).encode_wide().chain(Some(0).into_iter()).collect();
  v
}

#[cfg(debug_assertions)]
pub fn get_exe_dir() -> String {
  return "vendor".to_owned();
}

#[cfg(not(debug_assertions))]
pub fn get_exe_dir() -> String {
  let mut path: Vec<u16> = vec![0; winapi::MAX_PATH];
  unsafe {
    kernel32x::GetModuleFileNameW(0 as winapi::HMODULE,
                                  path.as_mut_ptr(),
                                  winapi::MAX_PATH as u32);
  }
  let path = String::from_utf16(path.as_slice()).unwrap();
  let path = Path::new(&path);
  let parent = path.parent().unwrap();
  parent.to_str().unwrap().to_owned()
}

fn cmd_auto() {
  let mut cfg = match config::Config::parse("config.toml") {
    Ok(c) => c,
    Err(e) => {
      error!("{}", e);
      exit(1);
    }
  };

  let mut v = vss::Vss::new();
  v.create(&cfg).unwrap(); // destroyed on drop
  let mapped_drives = v.get_mapped_drives();

  // Fix up the config.
  cfg.create.sources = cfg.create
    .sources
    .iter()
    .map(|source| {
      if !mapped_drives.is_empty() {
        if let Some(l) = mapped_drives.get(&source.chars().nth(0).unwrap()) {
          let mut s = String::new();
          s.push(*l);
          s.push_str(&source[1..]);
          return cygpath::from_win(s);
        }
      }

      cygpath::from_win(source)
    })
    .collect();

  backup::init(&cfg);
  backup::create(&cfg);
  backup::purge(&cfg);
  backup::check(&cfg);
}

fn main() {
  TermLogger::init(LogLevelFilter::Info).unwrap();

  let app = App::new("ckbackup")
    .setting(AppSettings::SubcommandRequiredElseHelp)
    .version("0.0.1")
    .author("Kevin Darlington <kevin@outroot.com>")
    .about("A VSS enabled wrapper around Borg to be used in automated scripts.")
    .subcommand(SubCommand::with_name("auto").about("Does automatic backup based on config.toml."));
  let matches = app.get_matches();

  match matches.subcommand() {
    ("auto", Some(_)) => cmd_auto(),
    _ => {}
  };
}
<|endoftext|>


<commit_before>#![recursion_limit = "1024" ]
#[macro_use] extern crate clap;
#[macro_use] extern crate error_chain;
extern crate migrant_lib;

#[cfg(feature="update")]
extern crate self_update;

use std::io;
use std::fs;
use std::env;
use std::path::PathBuf;
use migrant_lib::{Config, Direction, Migrator, DbKind};
use migrant_lib::config::{SqliteSettingsBuilder, PostgresSettingsBuilder};

mod cli;
mod errors {
    use super::*;
    error_chain! {
        foreign_links {
            MigrantLib(migrant_lib::Error);
            SelfUpdate(self_update::errors::Error) #[cfg(feature="update")];
            Io(io::Error);
        }
    }
}
use errors::*;

static APP_VERSION: &'static str = crate_version!();
static APP_NAME: &'static str = "Migrant";

quick_main!(my_main);

fn my_main() -> Result<()> {
    let matches = cli::build_cli().get_matches();
    let dir = env::current_dir()?;

    run(&dir, &matches)
}

fn run(dir: &PathBuf, matches: &clap::ArgMatches) -> Result<()> {
    if let Some(self_matches) = matches.subcommand_matches("self") {
        if let Some(update_matches) = self_matches.subcommand_matches("update") {
            update(update_matches)?;
            return Ok(())
        }

        if let Some(compl_matches) = self_matches.subcommand_matches("bash-completions") {
            let mut out: Box<io::Write> = {
                if let Some(install_matches) = compl_matches.subcommand_matches("install") {
                    let install_path = install_matches.value_of("path").unwrap();
                    let prompt = format!("** Completion file will be installed at: `{}`\n** Is this Ok? [Y/n] ", install_path);
                    confirm(&prompt)?;
                    let file = fs::File::create(install_path)?;
                    Box::new(file)
                } else {
                    Box::new(io::stdout())
                }
            };
            cli::build_cli().gen_completions_to(APP_NAME.to_lowercase(), clap::Shell::Bash, &mut out);
            println!("** Success!");
            return Ok(())
        }
        println!("migrant: see `--help`");
        return Ok(())
    }

    let config_path = migrant_lib::search_for_settings_file(dir);

    if matches.is_present("init") || config_path.is_none() {
        let config = match matches.subcommand_matches("init") {
            None => Config::init_in(&dir),
            Some(init_matches) => {
                let dir = init_matches.value_of("location").map(PathBuf::from).unwrap_or_else(|| dir.to_owned());
                let mut config = Config::init_in(&dir);
                let interactive = !init_matches.is_present("no-confirm");
                config.interactive(interactive);
                if let Some(db_kind) = init_matches.value_of("type") {
                    match db_kind.parse::<DbKind>()? {
                        DbKind::Sqlite => {
                            config.with_sqlite_options(&SqliteSettingsBuilder::empty());
                        }
                        DbKind::Postgres => {
                            config.with_postgres_options(&PostgresSettingsBuilder::empty());
                        }
                    }
                }
                config
            }
        };
        config.initialize()?;
        return Ok(())
    }

    let config_path = config_path.unwrap();    // absolute path of `.migrant` file
    let config = Config::from_settings_file(&config_path)?;

    if matches.is_present("setup") {
        config.setup()?;
        return Ok(())
    }

    if matches.is_present("connect-string") {
        if config.database_type() == DbKind::Sqlite {
            let path = config.database_path()?;
            let path = path.to_str().ok_or_else(|| format!("PathError: Invalid utf8: {:?}", path))?;
            println!("{}", path);
        } else {
            println!("{}", config.connect_string()?);
        }
        return Ok(())
    }

    match matches.subcommand() {
        ("list", _) => {
            // load applied migrations from the database
            let config = config.reload()?;

            migrant_lib::list(&config)?;
        }
        ("new", Some(matches)) => {
            // load applied migrations from the database
            let config = config.reload()?;

            let tag = matches.value_of("tag").unwrap();
            migrant_lib::new(&config, tag)?;
            migrant_lib::list(&config)?;
        }
        ("apply", Some(matches)) => {
            // load applied migrations from the database
            let config = config.reload()?;

            let force = matches.is_present("force");
            let fake = matches.is_present("fake");
            let all = matches.is_present("all");
            let direction = if matches.is_present("down") { Direction::Down } else { Direction::Up };

            Migrator::with_config(&config)
                .direction(direction)
                .force(force)
                .fake(fake)
                .all(all)
                .apply()?;

            let config = config.reload()?;
            migrant_lib::list(&config)?;
        }
        ("redo", Some(matches)) => {
            // load applied migrations from the database
            let config = config.reload()?;

            let force = matches.is_present("force");
            let fake = matches.is_present("fake");
            let all = matches.is_present("all");

            Migrator::with_config(&config)
                .direction(Direction::Down)
                .force(force)
                .fake(fake)
                .all(all)
                .apply()?;
            let config = config.reload()?;
            migrant_lib::list(&config)?;

            Migrator::with_config(&config)
                .direction(Direction::Up)
                .force(force)
                .fake(fake)
                .all(all)
                .apply()?;
            let config = config.reload()?;
            migrant_lib::list(&config)?;
        }
        ("shell", _) => {
            migrant_lib::shell(&config)?;
        }
        ("edit", Some(matches)) => {
            let tag = matches.value_of("tag").unwrap();
            let up_down = if matches.is_present("down") { Direction::Down } else { Direction::Up };
            migrant_lib::edit(&config, &tag, &up_down)?;
        }
        ("which-config", _) => {
            println!("{}", config_path.to_str().unwrap());
        }
        _ => {
            println!("migrant: see `--help`");
        }
    };
    Ok(())
}

#[cfg(feature="update")]
fn update(matches: &clap::ArgMatches) -> Result<()> {
    let mut builder = self_update::backends::github::Update::configure()?;

    builder.repo_owner("jaemk")
        .repo_name("migrant")
        .target(&self_update::get_target()?)
        .bin_name("migrant")
        .show_download_progress(true)
        .no_confirm(matches.is_present("no_confirm"))
        .current_version(APP_VERSION);

    if matches.is_present("quiet") {
        builder.show_output(false)
            .show_download_progress(false);
    }

    let status = builder.build()?.update()?;
    match status {
        self_update::Status::UpToDate(v) => {
            println!("Already up to date [v{}]!", v);
        }
        self_update::Status::Updated(v) => {
            println!("Updated to {}!", v);
        }
    }
    return Ok(());
}

#[cfg(not(feature="update"))]
fn update(_: &clap::ArgMatches) -> Result<()> {
    bail!("This executable was not compiled with `self_update` features enabled via `--features update`")
}

/// Get confirmation on a prompt
/// Returns `Ok` for 'yes' and `Err` for anything else
fn confirm(s: &str) -> Result<()> {
    use io::Write;
    print!("{}", s);
    io::stdout().flush()?;
    let mut s = String::new();
    io::stdin().read_line(&mut s)?;
    let s = s.trim().to_lowercase();
    if !s.is_empty() && s != "y" { bail!("Unable to confirm...") }
    Ok(())
}

<commit_msg>bash completions<commit_after>#![recursion_limit = "1024" ]
#[macro_use] extern crate clap;
#[macro_use] extern crate error_chain;
extern crate migrant_lib;

#[cfg(feature="update")]
extern crate self_update;

use std::io;
use std::fs;
use std::env;
use std::path::PathBuf;
use migrant_lib::{Config, Direction, Migrator, DbKind};
use migrant_lib::config::{SqliteSettingsBuilder, PostgresSettingsBuilder};

mod cli;
mod errors {
    use super::*;
    error_chain! {
        foreign_links {
            MigrantLib(migrant_lib::Error);
            SelfUpdate(self_update::errors::Error) #[cfg(feature="update")];
            Io(io::Error);
        }
    }
}
use errors::*;

static APP_VERSION: &'static str = crate_version!();
static APP_NAME: &'static str = "Migrant";

quick_main!(my_main);

fn my_main() -> Result<()> {
    let matches = cli::build_cli().get_matches();
    let dir = env::current_dir()?;

    run(&dir, &matches)
}

fn run(dir: &PathBuf, matches: &clap::ArgMatches) -> Result<()> {
    if let Some(self_matches) = matches.subcommand_matches("self") {
        if let Some(update_matches) = self_matches.subcommand_matches("update") {
            update(update_matches)?;
            return Ok(())
        }

        if let Some(compl_matches) = self_matches.subcommand_matches("bash-completions") {
            let mut out: Box<io::Write> = {
                if let Some(install_matches) = compl_matches.subcommand_matches("install") {
                    let install_path = install_matches.value_of("path").unwrap();
                    let prompt = format!("** Completion file will be installed at: `{}`\n** Is this Ok? [Y/n] ", install_path);
                    confirm(&prompt)?;
                    let file = fs::File::create(install_path)?;
                    Box::new(file)
                } else {
                    Box::new(io::stdout())
                }
            };
            cli::build_cli().gen_completions_to(APP_NAME.to_lowercase(), clap::Shell::Bash, &mut out);
            eprintln!("** Success!");
            return Ok(())
        }
        println!("migrant: see `--help`");
        return Ok(())
    }

    let config_path = migrant_lib::search_for_settings_file(dir);

    if matches.is_present("init") || config_path.is_none() {
        let config = match matches.subcommand_matches("init") {
            None => Config::init_in(&dir),
            Some(init_matches) => {
                let dir = init_matches.value_of("location").map(PathBuf::from).unwrap_or_else(|| dir.to_owned());
                let mut config = Config::init_in(&dir);
                let interactive = !init_matches.is_present("no-confirm");
                config.interactive(interactive);
                if let Some(db_kind) = init_matches.value_of("type") {
                    match db_kind.parse::<DbKind>()? {
                        DbKind::Sqlite => {
                            config.with_sqlite_options(&SqliteSettingsBuilder::empty());
                        }
                        DbKind::Postgres => {
                            config.with_postgres_options(&PostgresSettingsBuilder::empty());
                        }
                    }
                }
                config
            }
        };
        config.initialize()?;
        return Ok(())
    }

    let config_path = config_path.unwrap();    // absolute path of `.migrant` file
    let config = Config::from_settings_file(&config_path)?;

    if matches.is_present("setup") {
        config.setup()?;
        return Ok(())
    }

    if matches.is_present("connect-string") {
        if config.database_type() == DbKind::Sqlite {
            let path = config.database_path()?;
            let path = path.to_str().ok_or_else(|| format!("PathError: Invalid utf8: {:?}", path))?;
            println!("{}", path);
        } else {
            println!("{}", config.connect_string()?);
        }
        return Ok(())
    }

    match matches.subcommand() {
        ("list", _) => {
            // load applied migrations from the database
            let config = config.reload()?;

            migrant_lib::list(&config)?;
        }
        ("new", Some(matches)) => {
            // load applied migrations from the database
            let config = config.reload()?;

            let tag = matches.value_of("tag").unwrap();
            migrant_lib::new(&config, tag)?;
            migrant_lib::list(&config)?;
        }
        ("apply", Some(matches)) => {
            // load applied migrations from the database
            let config = config.reload()?;

            let force = matches.is_present("force");
            let fake = matches.is_present("fake");
            let all = matches.is_present("all");
            let direction = if matches.is_present("down") { Direction::Down } else { Direction::Up };

            Migrator::with_config(&config)
                .direction(direction)
                .force(force)
                .fake(fake)
                .all(all)
                .apply()?;

            let config = config.reload()?;
            migrant_lib::list(&config)?;
        }
        ("redo", Some(matches)) => {
            // load applied migrations from the database
            let config = config.reload()?;

            let force = matches.is_present("force");
            let fake = matches.is_present("fake");
            let all = matches.is_present("all");

            Migrator::with_config(&config)
                .direction(Direction::Down)
                .force(force)
                .fake(fake)
                .all(all)
                .apply()?;
            let config = config.reload()?;
            migrant_lib::list(&config)?;

            Migrator::with_config(&config)
                .direction(Direction::Up)
                .force(force)
                .fake(fake)
                .all(all)
                .apply()?;
            let config = config.reload()?;
            migrant_lib::list(&config)?;
        }
        ("shell", _) => {
            migrant_lib::shell(&config)?;
        }
        ("edit", Some(matches)) => {
            let tag = matches.value_of("tag").unwrap();
            let up_down = if matches.is_present("down") { Direction::Down } else { Direction::Up };
            migrant_lib::edit(&config, &tag, &up_down)?;
        }
        ("which-config", _) => {
            println!("{}", config_path.to_str().unwrap());
        }
        _ => {
            println!("migrant: see `--help`");
        }
    };
    Ok(())
}

#[cfg(feature="update")]
fn update(matches: &clap::ArgMatches) -> Result<()> {
    let mut builder = self_update::backends::github::Update::configure()?;

    builder.repo_owner("jaemk")
        .repo_name("migrant")
        .target(&self_update::get_target()?)
        .bin_name("migrant")
        .show_download_progress(true)
        .no_confirm(matches.is_present("no_confirm"))
        .current_version(APP_VERSION);

    if matches.is_present("quiet") {
        builder.show_output(false)
            .show_download_progress(false);
    }

    let status = builder.build()?.update()?;
    match status {
        self_update::Status::UpToDate(v) => {
            println!("Already up to date [v{}]!", v);
        }
        self_update::Status::Updated(v) => {
            println!("Updated to {}!", v);
        }
    }
    return Ok(());
}

#[cfg(not(feature="update"))]
fn update(_: &clap::ArgMatches) -> Result<()> {
    bail!("This executable was not compiled with `self_update` features enabled via `--features update`")
}

/// Get confirmation on a prompt
/// Returns `Ok` for 'yes' and `Err` for anything else
fn confirm(s: &str) -> Result<()> {
    use io::Write;
    print!("{}", s);
    io::stdout().flush()?;
    let mut s = String::new();
    io::stdin().read_line(&mut s)?;
    let s = s.trim().to_lowercase();
    if !s.is_empty() && s != "y" { bail!("Unable to confirm...") }
    Ok(())
}

<|endoftext|>


<commit_before>extern crate yaml_rust;
extern crate csv;
extern crate tina;
extern crate log4rs;
#[macro_use] extern crate log;

mod config;

use std::env;
use std::sync::Arc;

use tina::*;
use config::*;

fn main()
{
	let args: Vec<String> = env::args().collect();

	let conf_path = args.get(1).map(|s| s.as_str()).unwrap_or("config/tina.yaml");

	let conf = match Config::load_config(conf_path) {
		Err(err) => {
			println!("Error while loading config ({:?})", err);
			return;
		},
		Ok(c) => c
	};

	if let Some(log4rs_conf_path) = conf.log4rs_conf_path {
		if let Err(err) = log4rs::init_file(log4rs_conf_path, Default::default()) {
			println!("Error while initializing logging config ({:?})", err);
			return;
		}
		println!("Enabled: Logger");
	}

	let tw_fn = |eews: &[Arc<EEW>], latest: Arc<EEW>,
		state: &mut (TwitterClient, LimitedQueue<(String, u64)>, bool)| {

		let (ref tw, ref mut q, reply_enabled) = *state;

		let out = match ja_format_eew_short(&latest, eews.iter().rev().nth(1).map(|e| e.as_ref())) {
			Some(out) => out,
			None => return
		};

		let prev_tw_id_opt = match reply_enabled {
			true => q.iter().find(|x| x.0 == latest.id).map(|x| x.1),
			false => None
		};

		match tw.update_status(&out, prev_tw_id_opt) {

			Ok(tw_id) => {

				if prev_tw_id_opt == None {
					q.push((latest.id.clone(), tw_id));
				} else {
					q.iter_mut().find(|x| x.0 == latest.id).unwrap().1 = tw_id;
				}
			},

			Err(e) => {
				error!("TwitterError: {:?}", e);
			}
		}
	};

	let log_fn = |_: &[Arc<EEW>], latest: Arc<EEW>, lw: &mut LoggingWrapper| {

		let out = format_eew_full(&latest);
		lw.output(&out);
	};

	let wni_client = WNIClient::new(conf.wni_id.clone(), conf.wni_password.clone());
	let mut cons: Vec<Connector> = Vec::new();

	cons.push(Connector::new(log_fn, LoggingWrapper::new()));
	info!("Enabled: EEW Logging");

	if conf.twitter.is_some() {
		let t = &conf.twitter.unwrap();
		let tc = TwitterClient::new(
			t.consumer_token.clone(), t.consumer_secret.clone(),
			t.access_token.clone(), t.access_secret.clone());
		let q = LimitedQueue::with_allocation(16);
		cons.push(Connector::new(tw_fn, (tc, q, t.in_reply_to_enabled)));
		info!("Enabled: Twitter");
	}

	loop {

		let mut connection = match wni_client.connect() {
			Ok(v) => v,
			Err(e) => {
				error!("ConnectionError: {:?}", e);
				continue;
			}
		};

		loop {

			let eew = match connection.wait_for_telegram(&conf.epicenter_dict, &conf.area_dict) {
				Err(e) => {
					error!("StreamingError: {:?}", e);
					break;
				},
				Ok(eew) => Arc::new(eew)
			};

			for e in cons.iter() {
				e.emit(eew.clone());
			}
		}
	}
}
<commit_msg>Config: Accept config path setting via environment variable<commit_after>extern crate yaml_rust;
extern crate csv;
extern crate tina;
extern crate log4rs;
#[macro_use] extern crate log;

mod config;

use std::env;
use std::sync::Arc;

use tina::*;
use config::*;

const ENV_VAR_NAME: &'static str = "TINA_CONF_PATH";
const DEFAULT_CONFIG_PATH: &'static str = "config/tina.yaml";

fn main()
{
	let cmd_args: Vec<String> = env::args().collect();
	let env_arg_string = env::var(ENV_VAR_NAME).ok();

	let cmd_arg = cmd_args.get(1).map(|s| s.as_str());
	let env_arg = env_arg_string.as_ref().map(|s| s.as_str());
	let conf_path = cmd_arg.or(env_arg).unwrap_or(DEFAULT_CONFIG_PATH);

	let conf = match Config::load_config(conf_path) {
		Err(err) => {
			println!("Error while loading config ({:?})", err);
			return;
		},
		Ok(c) => c
	};

	if let Some(log4rs_conf_path) = conf.log4rs_conf_path {
		if let Err(err) = log4rs::init_file(log4rs_conf_path, Default::default()) {
			println!("Error while initializing logging config ({:?})", err);
			return;
		}
		println!("Enabled: Logger");
	}

	let tw_fn = |eews: &[Arc<EEW>], latest: Arc<EEW>,
		state: &mut (TwitterClient, LimitedQueue<(String, u64)>, bool)| {

		let (ref tw, ref mut q, reply_enabled) = *state;

		let out = match ja_format_eew_short(&latest, eews.iter().rev().nth(1).map(|e| e.as_ref())) {
			Some(out) => out,
			None => return
		};

		let prev_tw_id_opt = match reply_enabled {
			true => q.iter().find(|x| x.0 == latest.id).map(|x| x.1),
			false => None
		};

		match tw.update_status(&out, prev_tw_id_opt) {

			Ok(tw_id) => {

				if prev_tw_id_opt == None {
					q.push((latest.id.clone(), tw_id));
				} else {
					q.iter_mut().find(|x| x.0 == latest.id).unwrap().1 = tw_id;
				}
			},

			Err(e) => {
				error!("TwitterError: {:?}", e);
			}
		}
	};

	let log_fn = |_: &[Arc<EEW>], latest: Arc<EEW>, lw: &mut LoggingWrapper| {

		let out = format_eew_full(&latest);
		lw.output(&out);
	};

	let wni_client = WNIClient::new(conf.wni_id.clone(), conf.wni_password.clone());
	let mut cons: Vec<Connector> = Vec::new();

	cons.push(Connector::new(log_fn, LoggingWrapper::new()));
	info!("Enabled: EEW Logging");

	if conf.twitter.is_some() {
		let t = &conf.twitter.unwrap();
		let tc = TwitterClient::new(
			t.consumer_token.clone(), t.consumer_secret.clone(),
			t.access_token.clone(), t.access_secret.clone());
		let q = LimitedQueue::with_allocation(16);
		cons.push(Connector::new(tw_fn, (tc, q, t.in_reply_to_enabled)));
		info!("Enabled: Twitter");
	}

	loop {

		let mut connection = match wni_client.connect() {
			Ok(v) => v,
			Err(e) => {
				error!("ConnectionError: {:?}", e);
				continue;
			}
		};

		loop {

			let eew = match connection.wait_for_telegram(&conf.epicenter_dict, &conf.area_dict) {
				Err(e) => {
					error!("StreamingError: {:?}", e);
					break;
				},
				Ok(eew) => Arc::new(eew)
			};

			for e in cons.iter() {
				e.emit(eew.clone());
			}
		}
	}
}
<|endoftext|>