<commit_before>extern crate irc;
extern crate slack;
#[macro_use] extern crate lazy_static;
extern crate regex;
extern crate rustc_serialize;

use std::collections::HashMap;
use std::thread;
use std::sync::mpsc::{Sender, channel};
use std::default::Default;
use irc::client::prelude::*;
use regex::Regex;
use rustc_serialize::json;

#[derive(Debug)]
enum SlackToIrc {
    Message { to: String, msg: String },
    MeMessage { to: String, msg: String },
    Raw(String),
    Away(bool),
}

#[derive(Debug)]
enum IrcToSlack {
    Message { to: String, from: Option<String>, msg: String },
    Topic { chan: String, topic: Option<String> },
    Kick { by: Option<String>, chans: String, nicks: String, reason: Option<String> },
    Join { nick: String, chans: String },
    Part { nick: String, chans: String, reason: Option<String> },
    Quit { nick: String, reason: Option<String> },
    Nick { old_nick: String, new_nick: String },
    Mode { by: Option<String>, name: String, modes: String, params: Option<String> },
    Error(String),
}

struct SlackHandler<'a, T: 'a> {
    chan: &'a Sender<T>,
}

fn get_channel_with_id(id: &str, channels: Vec<slack::Channel>) -> Option<slack::Channel> {
    channels.into_iter().find(|channel| {
        channel.id == id
    })
}

fn get_user_with_id(id: &str, users: Vec<slack::User>) -> Option<slack::User> {
    users.into_iter().find(|user| {
        user.id == id
    })
}

fn parse_slack_text(text: &str, cli: &slack::RtmClient) -> String {
    lazy_static!{
        static ref REPLACEMENTS: Vec<(Regex, &'static str)> = vec![
            (Regex::new(r"\n|\r\n|\r").unwrap(), " "),
            (Regex::new(r"&").unwrap(), "&"),
            (Regex::new(r"<").unwrap(), "<"),
            (Regex::new(r">").unwrap(), ">"),
            (Regex::new(r"<!channel>").unwrap(), "@channel"),
            (Regex::new(r"<!group>").unwrap(), "@group"),
            (Regex::new(r"<!everyone>").unwrap(), "@everyone"),
        ];
        static ref EMOJIS: HashMap<&'static str, &'static str> = {
            let mut m = HashMap::new();
            m.insert("smile", ":)");
            m.insert("simple_smile", ":)");
            m.insert("smiley", ":-)");
            m.insert("grin", ":D");
            m.insert("wink", ";)");
            m.insert("smirk", ";)");
            m.insert("blush", ":$");
            m.insert("stuck_out_tongue", ":P");
            m.insert("stuck_out_tongue_winking_eye", ";P");
            m.insert("stuck_out_tongue_closed_eyes", "xP");
            m.insert("disappointed", ":(");
            m.insert("astonished", ":O");
            m.insert("open_mouth", ":O");
            m.insert("heart", "<3");
            m.insert("broken_heart", "</3");
            m.insert("confused", ":S");
            m.insert("angry", ">:(");
            m.insert("cry", ":,(");
            m.insert("frowning", ":(");
            m.insert("imp", "]:(");
            m.insert("innocent", "o:)");
            m.insert("joy", ":,)");
            m.insert("kissing", ":*");
            m.insert("laughing", "x)");
            m.insert("neutral_face", ":|");
            m.insert("no_mouth", ":-");
            m.insert("rage", ":@");
            m.insert("smiling_imp", "]:)");
            m.insert("sob", ":,'(");
            m.insert("sunglasses", "8)");
            m.insert("sweat", ",:(");
            m.insert("sweat_smile", ",:)");
            m.insert("unamused", ":$");
            m
        };
        static ref FUNCTIONS: Vec<(Regex, Box<Fn(&regex::Captures, &slack::RtmClient) -> String + Sync>)> = vec![
            (Regex::new(r"<#(C\w+)\|?(\w+)?>").unwrap(), Box::new(|captures: &regex::Captures, cli: &slack::RtmClient| {
                if let Some(id) = captures.at(1) {
                    if let Some(channel) = get_channel_with_id(id, cli.get_channels()) {
                        return format!("#{}", channel.name).to_owned()
                    }
                }
                captures.at(2).unwrap_or("").to_owned()
            })),
            (Regex::new(r"<@(U\w+)\|?(\w+)?>").unwrap(), Box::new(|captures: &regex::Captures, cli: &slack::RtmClient| {
                if let Some(id) = captures.at(1) {
                    if let Some(user) = get_user_with_id(id, cli.get_users()) {
                        return format!("@{}", user.name).to_owned()
                    }
                }
                captures.at(2).unwrap_or("").to_owned()
            })),
            (Regex::new(r"<(?!!)(\S+)>").unwrap(), Box::new(|captures: &regex::Captures, _| {
                captures.at(1).unwrap_or("").to_owned()
            })),
            (Regex::new(r"<!(\w+)\|?(\w+)?>").unwrap(), Box::new(|captures: &regex::Captures, _| {
                format!("<{}>", captures.at(2).or(captures.at(1)).unwrap_or("")).to_owned()
            })),
            (Regex::new(r"\:(\w+)\:").unwrap(), Box::new(|captures: &regex::Captures, _| {
                if let Some(&emoji) = EMOJIS.get(captures.at(1).unwrap()) {
                    emoji.to_owned()
                } else {
                    captures.at(0).unwrap().to_owned()
                }
            })),
        ];
    }

    let text = REPLACEMENTS.iter().fold(text.to_owned(), |text, &(ref re, replacement)| {
        re.replace_all(&text, replacement)
    });

    FUNCTIONS.iter().fold(text, |text, &(ref re, ref replacement)| {
        re.replace_all(&text, |captures: &regex::Captures| {
            replacement(captures, cli)
        })
    })
}

impl<'a> slack::EventHandler for SlackHandler<'a, SlackToIrc> {
    fn on_event(&mut self, cli: &mut slack::RtmClient, event: Result<&slack::Event, slack::Error>, _raw_json: &str) {
        let slack_user = &"TEMP_REPLACE_ME";
        let bot_channel = &"TEMP_REPLACE_ME";
        match event {
            Ok(&slack::Event::Message(ref message)) => match message {
                &slack::Message::Standard { channel: Some(ref channel), user: Some(ref user), text: Some(ref text), .. } if user == slack_user => {
                    lazy_static!{
                        static ref COMMAND_RE: Regex = Regex::new(r"^%[A-Z]{3,}\s\S").unwrap();
                        static ref PM_RE: Regex = Regex::new(r"^(\S+):\s+(.+)").unwrap();
                    }

                    let text = parse_slack_text(&text, cli);

                    if COMMAND_RE.is_match(&text) {
                        self.chan.send(SlackToIrc::Raw(text[1..].to_owned())).unwrap();
                        cli.send_message(channel, "_sent raw command_").unwrap();
                    } else if channel == bot_channel {
                        if let Some(captures) = PM_RE.captures(&text) {
                            self.chan.send(SlackToIrc::Message { to: captures.at(1).unwrap().to_owned(), msg: captures.at(2).unwrap().to_owned() }).unwrap();
                        } else {
                            cli.send_message(channel, "_no message sent, are you missing a `user: ` prefix?_").unwrap();
                        }
                    } else {
                        self.chan.send(SlackToIrc::Message { to: channel.clone(), msg: text.clone() }).unwrap();
                    }
                },
                &slack::Message::MeMessage { ref channel, ref user, ref text, .. } if user == slack_user => {
                    self.chan.send(SlackToIrc::MeMessage { to: channel.clone(), msg: text.clone() }).unwrap();
                },
                _ => (),
            },
            Ok(&slack::Event::PresenceChange { ref user, ref presence }) if user == slack_user => {
                self.chan.send(SlackToIrc::Away(presence == "active")).unwrap();
            },
            _ => (),
        }
    }

    fn on_ping(&mut self, _cli: &mut slack::RtmClient) {}

    fn on_close(&mut self, _cli: &mut slack::RtmClient) {
        println!("Disconnected from Slack");
    }

    fn on_connect(&mut self, _cli: &mut slack::RtmClient) {
        println!("Connected to Slack");
    }
}

fn make_slack_action(username: Option<String>, text: String) -> String {
    #[derive(RustcEncodable)]
    struct SlackAction {
        text: String,
        username: Option<String>,
        parse: String,
        icon_url: Option<String>,
    }

    json::encode(&SlackAction {
        text: text,
        username: username.clone(),
        parse: "full".to_owned(),
        icon_url: username.map(|username| { format!("http://api.adorable.io/avatars/48/{}.png", username) }),
    }).unwrap()
}

fn main() {
    let (slack_tx, slack_rx) = channel();
    let (irc_tx, irc_rx) = channel();

    let slack_thread = thread::Builder::new().name("slack".to_owned()).spawn(move || {
        let mut handler = SlackHandler { chan: &irc_tx };
        let mut cli = slack::RtmClient::new(&"SLACK_TOKEN_REPLACE_ME");

        cli.login_and_run(&mut handler).unwrap();

        let all_channels = ["ALL_CHANNELS_REPLACE_ME"];
        let dm_channel = "SLACK_DM_CHANNEL_TODO_REPLACE_ME";

        for msg in slack_rx {
            match msg {
                IrcToSlack::Message { to, from, msg } => {
                    let to: &str = if to.starts_with("#") {
                        dm_channel
                    } else {
                        &to
                    };

                    let msg = make_slack_action(from, msg);

                    cli.post_message(to, &msg, None).unwrap();
                },
                IrcToSlack::Topic { chan, topic } => {
                    cli.set_topic(&chan, &topic.unwrap_or("".to_owned())).unwrap();
                },
                IrcToSlack::Kick { by, chans, nicks, reason } => {
                    let by = &by.unwrap_or("server".to_owned());
                    let reason = &reason.unwrap_or("".to_owned());

                    for chan in chans.split(",") {
                        for nick in nicks.split(",") {
                            cli.send_message(&chan, &format!("*{}* has kicked *{}* (_{}_)", by, nick, reason)).unwrap();
                        }
                    }
                },
                IrcToSlack::Join { nick, chans } => {
                    for chan in chans.split(",") {
                        cli.send_message(&chan, &format!("*{}* has joined", nick)).unwrap();
                    }
                },
                IrcToSlack::Part { nick, chans, reason } => {
                    let reason = &reason.unwrap_or("".to_owned());

                    for chan in chans.split(",") {
                        cli.send_message(&chan, &format!("*{}* has left (_{}_)", nick, reason)).unwrap();
                    }
                },
                IrcToSlack::Quit { nick, reason } => {
                    let reason = &reason.unwrap_or("".to_owned());

                    for chan in &all_channels {
                        cli.send_message(&chan, &format!("*{}* has quit (_{}_)", nick, reason)).unwrap();
                    }
                },
                IrcToSlack::Nick { old_nick, new_nick } => {
                    for chan in &all_channels {
                        cli.send_message(&chan, &format!("*{}* is now known as *{}*", old_nick, new_nick)).unwrap();
                    }
                },
                IrcToSlack::Mode { by, name, modes, params } => {
                    if name.starts_with("#") {
                        cli.send_message(&name, &format!("*{}* sets mode *{}* on _{}_", by.unwrap_or("server".to_owned()), modes, params.unwrap_or(name.clone()))).unwrap();
                    }
                },
                IrcToSlack::Error(msg) => {
                    cli.send_message(dm_channel, &msg).unwrap();
                },
            }
        }
    }).unwrap();

    let irc_thread = thread::Builder::new().name("irc".to_owned()).spawn(move || {
        let config = Config {
            nickname: Some(format!("NICK_REPLACE_ME")),
            server: Some(format!("SERVER_REPLACE_ME")),
            channels: Some(vec![format!("CHANNELS_REPLACE_ME")]),
            port: Some(6697),
            use_ssl: Some(true),
            ..Default::default()
        };

        let server = IrcServer::from_config(config).unwrap();

        server.identify().unwrap();

        let server_thread = {
            let server = server.clone();
            thread::Builder::new().name("irc_server".to_owned()).spawn(move || {
                for message in server.iter() {
                    let message = message.unwrap();
                    match message.command {
                        Command::ERROR(msg) => {
                            slack_tx.send(IrcToSlack::Error(msg)).unwrap();
                        },
                        Command::PRIVMSG(to, text) | Command::NOTICE(to, text) => {
                            lazy_static!{
                                static ref ACTION_RE: Regex = Regex::new("^\x01ACTION (.+)\x01$").unwrap();
                            }

                            if ACTION_RE.is_match(&text) {
                                slack_tx.send(IrcToSlack::Message {
                                    to: to,
                                    from: message.prefix,
                                    msg: format!("_{}_", ACTION_RE.captures(&text).unwrap().at(1).unwrap())
                                }).unwrap();
                            } else {
                                slack_tx.send(IrcToSlack::Message { to: to, from: message.prefix, msg: text }).unwrap();
                            }
                        },
                        Command::TOPIC(channel, topic) => {
                            slack_tx.send(IrcToSlack::Topic { chan: channel, topic: topic }).unwrap();
                        },
                        Command::KICK(channels, users, reason) => {
                            slack_tx.send(IrcToSlack::Kick { by: message.prefix, chans: channels, nicks: users, reason: reason }).unwrap();
                        },
                        Command::JOIN(channels, _, _) => {
                            slack_tx.send(IrcToSlack::Join { nick: message.prefix.unwrap(), chans: channels }).unwrap();
                        },
                        Command::PART(channels, reason) => {
                            slack_tx.send(IrcToSlack::Part { nick: message.prefix.unwrap(), chans: channels, reason: reason }).unwrap();
                        },
                        Command::QUIT(reason) => {
                            slack_tx.send(IrcToSlack::Quit { nick: message.prefix.unwrap(), reason: reason }).unwrap();
                        },
                        Command::NICK(nick) => {
                            slack_tx.send(IrcToSlack::Nick { old_nick: message.prefix.unwrap(), new_nick: nick }).unwrap();
                        },
                        Command::MODE(name, modes, params) => {
                            slack_tx.send(IrcToSlack::Mode { by: message.prefix, name: name, modes: modes, params: params }).unwrap();
                        }
                        _ => (),
                    }
                }
            }).unwrap()
        };

        for msg in irc_rx {
            match msg {
                SlackToIrc::Message { to, msg } => {
                    server.send_privmsg(&to, &msg).unwrap();
                },
                SlackToIrc::MeMessage { to, msg } => {
                    server.send_privmsg(&to, &format!("\x01ACTION {}\x01", msg)).unwrap();
                },
                SlackToIrc::Raw(msg) => {
                    server.send(Command::Raw(msg, vec![], None)).unwrap();
                },
                SlackToIrc::Away(is_away) => {
                    server.send(Command::AWAY(Some(if is_away { " ".to_owned() } else { "".to_owned() }))).unwrap();
                },
            }
        }

        server_thread.join().unwrap();
    }).unwrap();

    slack_thread.join().unwrap();
    irc_thread.join().unwrap();
}
<commit_msg>replace some unused `format!` with `.to_owned()`<commit_after>extern crate irc;
extern crate slack;
#[macro_use] extern crate lazy_static;
extern crate regex;
extern crate rustc_serialize;

use std::collections::HashMap;
use std::thread;
use std::sync::mpsc::{Sender, channel};
use std::default::Default;
use irc::client::prelude::*;
use regex::Regex;
use rustc_serialize::json;

#[derive(Debug)]
enum SlackToIrc {
    Message { to: String, msg: String },
    MeMessage { to: String, msg: String },
    Raw(String),
    Away(bool),
}

#[derive(Debug)]
enum IrcToSlack {
    Message { to: String, from: Option<String>, msg: String },
    Topic { chan: String, topic: Option<String> },
    Kick { by: Option<String>, chans: String, nicks: String, reason: Option<String> },
    Join { nick: String, chans: String },
    Part { nick: String, chans: String, reason: Option<String> },
    Quit { nick: String, reason: Option<String> },
    Nick { old_nick: String, new_nick: String },
    Mode { by: Option<String>, name: String, modes: String, params: Option<String> },
    Error(String),
}

struct SlackHandler<'a, T: 'a> {
    chan: &'a Sender<T>,
}

fn get_channel_with_id(id: &str, channels: Vec<slack::Channel>) -> Option<slack::Channel> {
    channels.into_iter().find(|channel| {
        channel.id == id
    })
}

fn get_user_with_id(id: &str, users: Vec<slack::User>) -> Option<slack::User> {
    users.into_iter().find(|user| {
        user.id == id
    })
}

fn parse_slack_text(text: &str, cli: &slack::RtmClient) -> String {
    lazy_static!{
        static ref REPLACEMENTS: Vec<(Regex, &'static str)> = vec![
            (Regex::new(r"\n|\r\n|\r").unwrap(), " "),
            (Regex::new(r"&").unwrap(), "&"),
            (Regex::new(r"<").unwrap(), "<"),
            (Regex::new(r">").unwrap(), ">"),
            (Regex::new(r"<!channel>").unwrap(), "@channel"),
            (Regex::new(r"<!group>").unwrap(), "@group"),
            (Regex::new(r"<!everyone>").unwrap(), "@everyone"),
        ];
        static ref EMOJIS: HashMap<&'static str, &'static str> = {
            let mut m = HashMap::new();
            m.insert("smile", ":)");
            m.insert("simple_smile", ":)");
            m.insert("smiley", ":-)");
            m.insert("grin", ":D");
            m.insert("wink", ";)");
            m.insert("smirk", ";)");
            m.insert("blush", ":$");
            m.insert("stuck_out_tongue", ":P");
            m.insert("stuck_out_tongue_winking_eye", ";P");
            m.insert("stuck_out_tongue_closed_eyes", "xP");
            m.insert("disappointed", ":(");
            m.insert("astonished", ":O");
            m.insert("open_mouth", ":O");
            m.insert("heart", "<3");
            m.insert("broken_heart", "</3");
            m.insert("confused", ":S");
            m.insert("angry", ">:(");
            m.insert("cry", ":,(");
            m.insert("frowning", ":(");
            m.insert("imp", "]:(");
            m.insert("innocent", "o:)");
            m.insert("joy", ":,)");
            m.insert("kissing", ":*");
            m.insert("laughing", "x)");
            m.insert("neutral_face", ":|");
            m.insert("no_mouth", ":-");
            m.insert("rage", ":@");
            m.insert("smiling_imp", "]:)");
            m.insert("sob", ":,'(");
            m.insert("sunglasses", "8)");
            m.insert("sweat", ",:(");
            m.insert("sweat_smile", ",:)");
            m.insert("unamused", ":$");
            m
        };
        static ref FUNCTIONS: Vec<(Regex, Box<Fn(&regex::Captures, &slack::RtmClient) -> String + Sync>)> = vec![
            (Regex::new(r"<#(C\w+)\|?(\w+)?>").unwrap(), Box::new(|captures: &regex::Captures, cli: &slack::RtmClient| {
                if let Some(id) = captures.at(1) {
                    if let Some(channel) = get_channel_with_id(id, cli.get_channels()) {
                        return format!("#{}", channel.name).to_owned()
                    }
                }
                captures.at(2).unwrap_or("").to_owned()
            })),
            (Regex::new(r"<@(U\w+)\|?(\w+)?>").unwrap(), Box::new(|captures: &regex::Captures, cli: &slack::RtmClient| {
                if let Some(id) = captures.at(1) {
                    if let Some(user) = get_user_with_id(id, cli.get_users()) {
                        return format!("@{}", user.name).to_owned()
                    }
                }
                captures.at(2).unwrap_or("").to_owned()
            })),
            (Regex::new(r"<(?!!)(\S+)>").unwrap(), Box::new(|captures: &regex::Captures, _| {
                captures.at(1).unwrap_or("").to_owned()
            })),
            (Regex::new(r"<!(\w+)\|?(\w+)?>").unwrap(), Box::new(|captures: &regex::Captures, _| {
                format!("<{}>", captures.at(2).or(captures.at(1)).unwrap_or("")).to_owned()
            })),
            (Regex::new(r"\:(\w+)\:").unwrap(), Box::new(|captures: &regex::Captures, _| {
                if let Some(&emoji) = EMOJIS.get(captures.at(1).unwrap()) {
                    emoji.to_owned()
                } else {
                    captures.at(0).unwrap().to_owned()
                }
            })),
        ];
    }

    let text = REPLACEMENTS.iter().fold(text.to_owned(), |text, &(ref re, replacement)| {
        re.replace_all(&text, replacement)
    });

    FUNCTIONS.iter().fold(text, |text, &(ref re, ref replacement)| {
        re.replace_all(&text, |captures: &regex::Captures| {
            replacement(captures, cli)
        })
    })
}

impl<'a> slack::EventHandler for SlackHandler<'a, SlackToIrc> {
    fn on_event(&mut self, cli: &mut slack::RtmClient, event: Result<&slack::Event, slack::Error>, _raw_json: &str) {
        let slack_user = &"TEMP_REPLACE_ME";
        let bot_channel = &"TEMP_REPLACE_ME";
        match event {
            Ok(&slack::Event::Message(ref message)) => match message {
                &slack::Message::Standard { channel: Some(ref channel), user: Some(ref user), text: Some(ref text), .. } if user == slack_user => {
                    lazy_static!{
                        static ref COMMAND_RE: Regex = Regex::new(r"^%[A-Z]{3,}\s\S").unwrap();
                        static ref PM_RE: Regex = Regex::new(r"^(\S+):\s+(.+)").unwrap();
                    }

                    let text = parse_slack_text(&text, cli);

                    if COMMAND_RE.is_match(&text) {
                        self.chan.send(SlackToIrc::Raw(text[1..].to_owned())).unwrap();
                        cli.send_message(channel, "_sent raw command_").unwrap();
                    } else if channel == bot_channel {
                        if let Some(captures) = PM_RE.captures(&text) {
                            self.chan.send(SlackToIrc::Message { to: captures.at(1).unwrap().to_owned(), msg: captures.at(2).unwrap().to_owned() }).unwrap();
                        } else {
                            cli.send_message(channel, "_no message sent, are you missing a `user: ` prefix?_").unwrap();
                        }
                    } else {
                        self.chan.send(SlackToIrc::Message { to: channel.clone(), msg: text.clone() }).unwrap();
                    }
                },
                &slack::Message::MeMessage { ref channel, ref user, ref text, .. } if user == slack_user => {
                    self.chan.send(SlackToIrc::MeMessage { to: channel.clone(), msg: text.clone() }).unwrap();
                },
                _ => (),
            },
            Ok(&slack::Event::PresenceChange { ref user, ref presence }) if user == slack_user => {
                self.chan.send(SlackToIrc::Away(presence == "active")).unwrap();
            },
            _ => (),
        }
    }

    fn on_ping(&mut self, _cli: &mut slack::RtmClient) {}

    fn on_close(&mut self, _cli: &mut slack::RtmClient) {
        println!("Disconnected from Slack");
    }

    fn on_connect(&mut self, _cli: &mut slack::RtmClient) {
        println!("Connected to Slack");
    }
}

fn make_slack_action(username: Option<String>, text: String) -> String {
    #[derive(RustcEncodable)]
    struct SlackAction {
        text: String,
        username: Option<String>,
        parse: String,
        icon_url: Option<String>,
    }

    json::encode(&SlackAction {
        text: text,
        username: username.clone(),
        parse: "full".to_owned(),
        icon_url: username.map(|username| { format!("http://api.adorable.io/avatars/48/{}.png", username) }),
    }).unwrap()
}

fn main() {
    let (slack_tx, slack_rx) = channel();
    let (irc_tx, irc_rx) = channel();

    let slack_thread = thread::Builder::new().name("slack".to_owned()).spawn(move || {
        let mut handler = SlackHandler { chan: &irc_tx };
        let mut cli = slack::RtmClient::new(&"SLACK_TOKEN_REPLACE_ME");

        cli.login_and_run(&mut handler).unwrap();

        let all_channels = ["ALL_CHANNELS_REPLACE_ME"];
        let dm_channel = "SLACK_DM_CHANNEL_TODO_REPLACE_ME";

        for msg in slack_rx {
            match msg {
                IrcToSlack::Message { to, from, msg } => {
                    let to: &str = if to.starts_with("#") {
                        dm_channel
                    } else {
                        &to
                    };

                    let msg = make_slack_action(from, msg);

                    cli.post_message(to, &msg, None).unwrap();
                },
                IrcToSlack::Topic { chan, topic } => {
                    cli.set_topic(&chan, &topic.unwrap_or("".to_owned())).unwrap();
                },
                IrcToSlack::Kick { by, chans, nicks, reason } => {
                    let by = &by.unwrap_or("server".to_owned());
                    let reason = &reason.unwrap_or("".to_owned());

                    for chan in chans.split(",") {
                        for nick in nicks.split(",") {
                            cli.send_message(&chan, &format!("*{}* has kicked *{}* (_{}_)", by, nick, reason)).unwrap();
                        }
                    }
                },
                IrcToSlack::Join { nick, chans } => {
                    for chan in chans.split(",") {
                        cli.send_message(&chan, &format!("*{}* has joined", nick)).unwrap();
                    }
                },
                IrcToSlack::Part { nick, chans, reason } => {
                    let reason = &reason.unwrap_or("".to_owned());

                    for chan in chans.split(",") {
                        cli.send_message(&chan, &format!("*{}* has left (_{}_)", nick, reason)).unwrap();
                    }
                },
                IrcToSlack::Quit { nick, reason } => {
                    let reason = &reason.unwrap_or("".to_owned());

                    for chan in &all_channels {
                        cli.send_message(&chan, &format!("*{}* has quit (_{}_)", nick, reason)).unwrap();
                    }
                },
                IrcToSlack::Nick { old_nick, new_nick } => {
                    for chan in &all_channels {
                        cli.send_message(&chan, &format!("*{}* is now known as *{}*", old_nick, new_nick)).unwrap();
                    }
                },
                IrcToSlack::Mode { by, name, modes, params } => {
                    if name.starts_with("#") {
                        cli.send_message(&name, &format!("*{}* sets mode *{}* on _{}_", by.unwrap_or("server".to_owned()), modes, params.unwrap_or(name.clone()))).unwrap();
                    }
                },
                IrcToSlack::Error(msg) => {
                    cli.send_message(dm_channel, &msg).unwrap();
                },
            }
        }
    }).unwrap();

    let irc_thread = thread::Builder::new().name("irc".to_owned()).spawn(move || {
        let config = Config {
            nickname: Some("NICK_REPLACE_ME".to_owned()),
            server: Some("SERVER_REPLACE_ME".to_owned()),
            channels: Some(vec!["CHANNELS_REPLACE_ME".to_owned()]),
            port: Some(6697),
            use_ssl: Some(true),
            ..Default::default()
        };

        let server = IrcServer::from_config(config).unwrap();

        server.identify().unwrap();

        let server_thread = {
            let server = server.clone();
            thread::Builder::new().name("irc_server".to_owned()).spawn(move || {
                for message in server.iter() {
                    let message = message.unwrap();
                    match message.command {
                        Command::ERROR(msg) => {
                            slack_tx.send(IrcToSlack::Error(msg)).unwrap();
                        },
                        Command::PRIVMSG(to, text) | Command::NOTICE(to, text) => {
                            lazy_static!{
                                static ref ACTION_RE: Regex = Regex::new("^\x01ACTION (.+)\x01$").unwrap();
                            }

                            if ACTION_RE.is_match(&text) {
                                slack_tx.send(IrcToSlack::Message {
                                    to: to,
                                    from: message.prefix,
                                    msg: format!("_{}_", ACTION_RE.captures(&text).unwrap().at(1).unwrap())
                                }).unwrap();
                            } else {
                                slack_tx.send(IrcToSlack::Message { to: to, from: message.prefix, msg: text }).unwrap();
                            }
                        },
                        Command::TOPIC(channel, topic) => {
                            slack_tx.send(IrcToSlack::Topic { chan: channel, topic: topic }).unwrap();
                        },
                        Command::KICK(channels, users, reason) => {
                            slack_tx.send(IrcToSlack::Kick { by: message.prefix, chans: channels, nicks: users, reason: reason }).unwrap();
                        },
                        Command::JOIN(channels, _, _) => {
                            slack_tx.send(IrcToSlack::Join { nick: message.prefix.unwrap(), chans: channels }).unwrap();
                        },
                        Command::PART(channels, reason) => {
                            slack_tx.send(IrcToSlack::Part { nick: message.prefix.unwrap(), chans: channels, reason: reason }).unwrap();
                        },
                        Command::QUIT(reason) => {
                            slack_tx.send(IrcToSlack::Quit { nick: message.prefix.unwrap(), reason: reason }).unwrap();
                        },
                        Command::NICK(nick) => {
                            slack_tx.send(IrcToSlack::Nick { old_nick: message.prefix.unwrap(), new_nick: nick }).unwrap();
                        },
                        Command::MODE(name, modes, params) => {
                            slack_tx.send(IrcToSlack::Mode { by: message.prefix, name: name, modes: modes, params: params }).unwrap();
                        }
                        _ => (),
                    }
                }
            }).unwrap()
        };

        for msg in irc_rx {
            match msg {
                SlackToIrc::Message { to, msg } => {
                    server.send_privmsg(&to, &msg).unwrap();
                },
                SlackToIrc::MeMessage { to, msg } => {
                    server.send_privmsg(&to, &format!("\x01ACTION {}\x01", msg)).unwrap();
                },
                SlackToIrc::Raw(msg) => {
                    server.send(Command::Raw(msg, vec![], None)).unwrap();
                },
                SlackToIrc::Away(is_away) => {
                    server.send(Command::AWAY(Some(if is_away { " ".to_owned() } else { "".to_owned() }))).unwrap();
                },
            }
        }

        server_thread.join().unwrap();
    }).unwrap();

    slack_thread.join().unwrap();
    irc_thread.join().unwrap();
}
<|endoftext|>


<commit_before>#![feature(io, os, core, collections, rustc_private)]

extern crate getopts;
extern crate selecta;

use getopts::{optopt,getopts};
use selecta::configuration::Configuration;
use selecta::search::Search;
use selecta::tty::IO;
use selecta::screen::Screen;

#[allow(dead_code)]
fn main() {
    let initial_query = extract_initial_query();
    let lines = read_lines();

    let config = Configuration::from_inputs(lines, initial_query, Some(20));
    let mut search = Search::blank(&config);

    let mut screen = Screen::new();

    for _ in 0..(search.config.visible_limit) {
        screen.ansi.io.write("\n");
    }

    while !search.is_done() {
        screen.print(&search);
        let input = screen.ansi.io.read();
        match input {
            Some(n) => {
                search = screen.handle_keystroke(search, n.as_slice());
            },
            None => break,
        };
    }
    screen.move_cursor_to_end();
    screen.ansi.io.reset();
    println!("\n{}", search.selection().unwrap_or("None".to_string()));
}

fn extract_initial_query() -> Option<String> {
    let args = std::os::args();
    let opts = &[
        optopt("s", "search", "initial search query", ""),
    ];
    let matches = getopts(args.tail(), opts).unwrap();

    matches.opt_str("s")
}

fn read_lines() -> Vec<String> {
    std::old_io::stdio::stdin().lock().lines().map( |line| {
        line.unwrap().trim().to_string()
    }).collect()
}
<commit_msg>Use new env::args()<commit_after>#![feature(io, os, env, core, collections, rustc_private)]

extern crate getopts;
extern crate selecta;

use getopts::{optopt,getopts};

use selecta::configuration::Configuration;
use selecta::search::Search;
use selecta::tty::IO;
use selecta::screen::Screen;

#[allow(dead_code)]
fn main() {
    let initial_query = extract_initial_query();
    let lines = read_lines();

    let config = Configuration::from_inputs(lines, initial_query, Some(20));
    let mut search = Search::blank(&config);

    let mut screen = Screen::new();

    for _ in 0..(search.config.visible_limit) {
        screen.ansi.io.write("\n");
    }

    while !search.is_done() {
        screen.print(&search);
        let input = screen.ansi.io.read();
        match input {
            Some(n) => {
                search = screen.handle_keystroke(search, n.as_slice());
            },
            None => break,
        };
    }
    screen.move_cursor_to_end();
    screen.ansi.io.reset();
    println!("\n{}", search.selection().unwrap_or("".to_string()));
}

fn extract_initial_query() -> Option<String> {
    let args: Vec<String> = get_args();
    let opts = &[
        optopt("s", "search", "initial search query", ""),
    ];
    let matches = getopts(args.tail(), opts).unwrap();

    matches.opt_str("s")
}

fn get_args() -> Vec<String> {
    std::env::args().map( |os| os.into_string().ok().unwrap() ).collect()
}

fn read_lines() -> Vec<String> {
    std::old_io::stdio::stdin().lock().lines().map( |line| {
        line.unwrap().trim().to_string()
    }).collect()
}
<|endoftext|>


<commit_before>#![feature(collections)]

use std::io;
use std::io::prelude::*;
use std::iter::repeat;
use std::str::FromStr;
use std::collections::BitVec;

enum Hamming { Encode, Decode }

fn main() {
    let title = "RUSTYHAM: A HAMMING CODE GENERATOR IN RUST";
    let border: String = repeat('=').take(title.len()).collect::<>();
    println!("{}", border);
    println!("{}", title);
    println!("{}", border);

    loop {
        let mut linebuf = String::new();
        println!("(1) Encode ASCII");
        println!("(2) Encode binary");
        println!("(3) Decode to ASCII");
        println!("(4) Decode to binary");
        print!("Enter your choice: ");
        io::stdout().flush().unwrap();
        io::stdin().read_line(&mut linebuf).unwrap();

        let num = i32::from_str(linebuf.trim());
        match num.ok() {
            Some(n) => {
                let mut good = true;
                println!("{}", match n {
                    1 => hamming(Hamming::Encode),
                    3 => hamming(Hamming::Decode),
                    2 | 4 => "Sorry, not implemented yet.".to_string(),
                    _ => { good = false; "Invalid input.".to_string() }
                });
                if good { break; }
            }
            None => {
                println!("Invalid input.");
            }
        };
    }
}

fn hamming(action: Hamming) -> String {
    match action {
        Hamming::Encode => {
            // prompt for ASCII input
            let mut message = String::new();
            print!("Enter string to encode: ");
            io::stdout().flush().unwrap();
            io::stdin().read_line(&mut message).unwrap();

            // compute block and message length
            message = message.trim().to_string();
            let mlen = message.len() as u32 * 7;
            let lenpow = (2..).find(|&r| 2u32.pow(r) - r - 1 >= mlen).unwrap();
            let len = 2us.pow(lenpow) - 1;

            // the thing we're storing the hamming code in
            let mut bv = BitVec::from_elem(len, false);

            // convert ASCII string to binary
            // IMPORTANT NOTE: the following line takes ownership of the
            // `message' variable. We no longer have access to the original
            // string from this point onwards.
            let bytes = message.into_bytes();
            let bytes_str = bytes.iter().map(|&c| format!("{:0>1$b}", c, 7))
                .collect::<Vec<String>>().concat();

            // set data bits
            let mut bytes_iter = bytes_str.chars();
            for i in 1..len {
                if (i & (i - 1)) != 0 {  // if i is not a power of 2
                    bv.set(i-1, bytes_iter.next().unwrap_or('0') == '1');
                }
            }

            // set parity bits
            for i in 0..lenpow {
                let bi = 2us.pow(i) - 1;
                let (mut parity, mut ignore, mut counter) = (false, false, 0);
                for j in bi..len {
                    if !ignore && bv.get(j).unwrap() { parity = !parity; }
                    counter += 1;
                    if counter >= 2u32.pow(i) {
                        ignore = !ignore;
                        counter = 0;
                    }
                }
                bv.set(bi, parity);
            }

            format!("{:?}", bv)
        },
        Hamming::Decode => {
            "foo".to_string()
        }
    }
}
<commit_msg>implemented decode functionality (without error correction)<commit_after>#![feature(collections)]

use std::io;
use std::io::prelude::*;
use std::iter::repeat;
use std::str::FromStr;
use std::collections::BitVec;

enum Hamming { Encode, Decode }

fn main() {
    let title = "RUSTYHAM: A HAMMING CODE GENERATOR IN RUST";
    let border: String = repeat('=').take(title.len()).collect::<>();
    println!("{}", border);
    println!("{}", title);
    println!("{}", border);

    loop {
        let mut linebuf = String::new();
        println!("(1) Encode ASCII");
        println!("(2) Encode binary");
        println!("(3) Decode to ASCII");
        println!("(4) Decode to binary");
        print!("Enter your choice: ");
        io::stdout().flush().unwrap();
        io::stdin().read_line(&mut linebuf).unwrap();

        let num = i32::from_str(linebuf.trim());
        match num.ok() {
            Some(n) => {
                let mut good = true;
                println!("{}", match n {
                    1 => hamming(Hamming::Encode),
                    3 => hamming(Hamming::Decode),
                    2 | 4 => "Sorry, not implemented yet.".to_string(),
                    _ => { good = false; "Invalid input.".to_string() }
                });
                if good { break; }
            }
            None => {
                println!("Invalid input.");
            }
        };
    }
}

fn hamming(action: Hamming) -> String {
    match action {
        Hamming::Encode => {
            // prompt for ASCII input
            let mut message = String::new();
            print!("Enter string to encode: ");
            io::stdout().flush().unwrap();
            io::stdin().read_line(&mut message).unwrap();

            // compute block and message length
            message = message.trim().to_string();
            let mlen = message.len() as u32 * 7;
            let lenpow = (2..).find(|&r| 2u32.pow(r) - r - 1 >= mlen).unwrap();
            let len = 2us.pow(lenpow) - 1;

            // the thing we're storing the hamming code in
            let mut bv = BitVec::from_elem(len, false);

            // convert ASCII string to binary
            // IMPORTANT NOTE: the following line takes ownership of the
            // `message' variable. We no longer have access to the original
            // string from this point onwards.
            let bytes = message.into_bytes();
            let bytes_str = bytes.iter().map(|&c| format!("{:0>1$b}", c, 7))
                .collect::<Vec<String>>().concat();

            // set data bits
            let mut bytes_iter = bytes_str.chars();
            for i in 1..len {
                if (i & (i - 1)) != 0 {  // if i is not a power of 2
                    bv.set(i-1, bytes_iter.next().unwrap_or('0') == '1');
                }
            }

            // set parity bits
            for i in 0..lenpow {
                let bi = 2us.pow(i) - 1;
                let (mut parity, mut ignore, mut counter) = (false, false, 0);
                for j in bi..len {
                    if !ignore && bv.get(j).unwrap() { parity = !parity; }
                    counter += 1;
                    if counter >= 2u32.pow(i) {
                        ignore = !ignore;
                        counter = 0;
                    }
                }
                bv.set(bi, parity);
            }

            format!("{:?}", bv)
        },
        Hamming::Decode => {
            // TODO make this support error correction (which is basically the
            // whole point of a hamming code...)

            // prompt for binary input
            let mut code = String::new();
            print!("Enter Hamming code to decode: ");
            io::stdout().flush().unwrap();
            io::stdin().read_line(&mut code).unwrap();

            // collect all bits at non-powers-of-2
            let data = &code.trim().chars().enumerate()
                .filter(|x| ((x.0 + 1) & x.0) != 0).map(|x| x.1)
                .collect::<Vec<char>>()[..];
            let chars = data.chunks(7)
                .map(|x| u8::from_str_radix(&x.iter().cloned().collect::<String>()[..], 2).unwrap())
                .collect::<Vec<u8>>();

            String::from_utf8(chars).unwrap()
        }
    }
}
<|endoftext|>


<commit_before>// fs.rs
use std::env; // env::home_dir()
use std::fs; // fs::read_dir()
//use std::path::Path;
use std::path::PathBuf;

// allow ItemType to be cloned
#[derive(Clone)]
enum ItemType {
   Dir,
   File,
   Other,
}

// allow FoundItem to be cloned
// 'PathBuf' only allows cloning, not copying
#[derive(Clone)]
struct FoundItem {
   item_type: ItemType,
   item_path: PathBuf,
}

impl FoundItem {
   fn dump(self: FoundItem) {
      match self.item_type {
         // use .unwrap() to get the contents of the Option returned by
         // file_name()
         ItemType::Dir   => println!("d {:?}",
            self.item_path.file_name().unwrap()),
         ItemType::File  => println!("f {:?}",
            self.item_path.file_name().unwrap()),
         ItemType::Other => println!("o {:?}",
            self.item_path.file_name().unwrap()),
      }
   }
}

fn main() {
   //let mut idg_dir_path = PathBuf::from("~/Files/Doom/idgames");
   // create an empty PathBuf
   let mut idg_dir = PathBuf::new();
   // call `home_dir()` and act on what it returns
   match env::home_dir() {
      //Some(idg_dir) => println!("{}", idg_dir.display()),
      // home_dir() returned something
      Some(home_dir) => idg_dir = home_dir,
      // home_dir() returned nothing
      None => println!("Can't obtain home directory path!"),
   }

   // append more directories on to idg_dir
   idg_dir.push("Files");
   idg_dir.push("Doom");
   idg_dir.push("idgames");

   let mut items_v = Vec::new();
   let mut recurse_stack = Vec::new();
   // working example from:
   // https://doc.rust-lang.org/std/fs/struct.DirEntry.html#method.file_name
   // returns an array of DirEntry objects
   if let Ok(entries) = fs::read_dir(&idg_dir) {
      // for each DirEntry object...
      for dir_entry in entries {

         // the item being tested/checked
         let item;

         if let Ok(dir_entry) = dir_entry {
            //let path = dir_entry.path();
            // get the metadata object for this DirEntry
            if let Ok(metadata) = dir_entry.metadata() {
               // below, `dir_entry` is a `DirEntry`.
               if metadata.is_file() {
                  item = FoundItem {
                     item_type: ItemType::File,
                     item_path: dir_entry.path()
                  };
               }
               else if metadata.is_dir() {
                  item = FoundItem {
                     item_type: ItemType::Dir,
                     item_path: dir_entry.path()
                  };
                  recurse_stack.push(item.clone());
               }
               else {
                  item = FoundItem {
                     item_type: ItemType::Other,
                     item_path: dir_entry.path()
                  };

               }
               // push this items onto a Vec
               items_v.push(item);
            }
         }
      }
   }

   println!("Dumping items in {:?}", idg_dir);
   for item in items_v {
      // dump each item
      item.dump();
   }
/*
// doesn't work, try!() won't handle _Result_ objects
   for entry in try!(fs::read_dir(idg_dir)) {
       let dir = try!(entry);
       println!("{:?}", dir.path());
   }
*/

/*
   // try and read the contents of idg_dir/
   // - doesn't work, try!() won't handle _Result_ objects
   for entry in try!(fs::read_dir(idg_dir)) {
      let dir = try!(entry);
      // 'entry' is still a _Result_, so this is broken
      let metadata = try!(entry.metadata());
      // 'dir' is still a _DirEntry_
      if dir.is_dir() {
         println!("d {:?}", dir.path());
      } else {
         println!("! {:?}", dir.path());
      }
   }
*/

/*
   if let Ok(entries) = fs::read_dir(idg_dir) {
      for entry in entries {
         // 'item' is a Result, unwrap it to get access to Metadata
         if let Ok(entry) = entry {
               if let Ok(metadata) = entry.metadata() {};
               // entry.path() returns a _Result_
               if let Ok(path) = entry.path() {};
               // 'entry' is a _DirEntry_, and doesn't have an 'is_dir()'
               // method
               if entry.is_dir() {
                  println!("d {:?} {:?}",
                     // 'metadata' isn't available here
                     metadata.file_type(),
                     // the compiler doesn't know what 'path' is here
                     path);
            }
         }
      }
   }
*/

/*
   // working example
   println!("Updated іdgames/ path: {}", idg_dir.display());
   // read the contents of idg_dir/
   match fs::read_dir(idg_dir) {
      Err(why) => println!("! {:?}", why.kind()),
      Ok(paths) => for path in paths {
         println!("> {:?}", path.unwrap().path());
      }
   }
*/

}
<commit_msg>src/main.rs: added a TODO for cloning/referring to a directory<commit_after>// fs.rs
use std::env; // env::home_dir()
use std::fs; // fs::read_dir()
//use std::path::Path;
use std::path::PathBuf;

// allow ItemType to be cloned
#[derive(Clone)]
enum ItemType {
   Dir,
   File,
   Other,
}

// allow FoundItem to be cloned
// 'PathBuf' only allows cloning, not copying
#[derive(Clone)]
struct FoundItem {
   item_type: ItemType,
   item_path: PathBuf,
}

impl FoundItem {
   fn dump(self: FoundItem) {
      match self.item_type {
         // use .unwrap() to get the contents of the Option returned by
         // file_name()
         ItemType::Dir   => println!("d {:?}",
            self.item_path.file_name().unwrap()),
         ItemType::File  => println!("f {:?}",
            self.item_path.file_name().unwrap()),
         ItemType::Other => println!("o {:?}",
            self.item_path.file_name().unwrap()),
      }
   }
}

fn main() {
   //let mut idg_dir_path = PathBuf::from("~/Files/Doom/idgames");
   // create an empty PathBuf
   let mut idg_dir = PathBuf::new();
   // call `home_dir()` and act on what it returns
   match env::home_dir() {
      //Some(idg_dir) => println!("{}", idg_dir.display()),
      // home_dir() returned something
      Some(home_dir) => idg_dir = home_dir,
      // home_dir() returned nothing
      None => println!("Can't obtain home directory path!"),
   }

   // append more directories on to idg_dir
   idg_dir.push("Files");
   idg_dir.push("Doom");
   idg_dir.push("idgames");

   let mut items_v = Vec::new();
   let mut recurse_stack = Vec::new();
   // working example from:
   // https://doc.rust-lang.org/std/fs/struct.DirEntry.html#method.file_name
   // returns an array of DirEntry objects
   if let Ok(entries) = fs::read_dir(&idg_dir) {
      // for each DirEntry object...
      for dir_entry in entries {

         // the item being tested/checked
         let item;

         if let Ok(dir_entry) = dir_entry {
            //let path = dir_entry.path();
            // get the metadata object for this DirEntry
            if let Ok(metadata) = dir_entry.metadata() {
               // below, `dir_entry` is a `DirEntry`.
               if metadata.is_file() {
                  item = FoundItem {
                     item_type: ItemType::File,
                     item_path: dir_entry.path()
                  };
               }
               else if metadata.is_dir() {
                  item = FoundItem {
                     item_type: ItemType::Dir,
                     item_path: dir_entry.path()
                  };
                  // XXX clone this directory, or create a reference to it?
                  recurse_stack.push(item.clone());
               }
               else {
                  item = FoundItem {
                     item_type: ItemType::Other,
                     item_path: dir_entry.path()
                  };

               }
               // push this items onto a Vec
               items_v.push(item);
            }
         }
      }
   }

   println!("Dumping items in {:?}", idg_dir);
   for item in items_v {
      // dump each item
      item.dump();
   }
/*
// doesn't work, try!() won't handle _Result_ objects
   for entry in try!(fs::read_dir(idg_dir)) {
       let dir = try!(entry);
       println!("{:?}", dir.path());
   }
*/

/*
   // try and read the contents of idg_dir/
   // - doesn't work, try!() won't handle _Result_ objects
   for entry in try!(fs::read_dir(idg_dir)) {
      let dir = try!(entry);
      // 'entry' is still a _Result_, so this is broken
      let metadata = try!(entry.metadata());
      // 'dir' is still a _DirEntry_
      if dir.is_dir() {
         println!("d {:?}", dir.path());
      } else {
         println!("! {:?}", dir.path());
      }
   }
*/

/*
   if let Ok(entries) = fs::read_dir(idg_dir) {
      for entry in entries {
         // 'item' is a Result, unwrap it to get access to Metadata
         if let Ok(entry) = entry {
               if let Ok(metadata) = entry.metadata() {};
               // entry.path() returns a _Result_
               if let Ok(path) = entry.path() {};
               // 'entry' is a _DirEntry_, and doesn't have an 'is_dir()'
               // method
               if entry.is_dir() {
                  println!("d {:?} {:?}",
                     // 'metadata' isn't available here
                     metadata.file_type(),
                     // the compiler doesn't know what 'path' is here
                     path);
            }
         }
      }
   }
*/

/*
   // working example
   println!("Updated іdgames/ path: {}", idg_dir.display());
   // read the contents of idg_dir/
   match fs::read_dir(idg_dir) {
      Err(why) => println!("! {:?}", why.kind()),
      Ok(paths) => for path in paths {
         println!("> {:?}", path.unwrap().path());
      }
   }
*/

}
<|endoftext|>


<commit_before>use std::io::{TcpStream, BufferedStream};

fn main() {
    let mut stream = TcpStream::connect("hm.hacked.jp:4242");

    // Time to attempt a connection...

    // here is the handshake
    stream.write_be_u32(0x42b33f00).ok().expect("failed to send magic int"); // we absolutely do not support encryption or compression
    stream.write_be_u32(0x00000001).ok().expect("failed to send legacy protocol bit"); // we are only using the legacy protocol
    stream.write_be_u32(0x80000001).ok().expect("failed to send end-of-list bit"); // end of list

    println!("We are now going to sit on our asses and wait for the buf to come back");

    loop {
        let _ = match stream.read_be_u32() {
            Ok(data) => {
                println!("0x{:x}", data)
            },
            Err(err) => {
                panic!("error reading response: {}", err)
            }
        };
    }
    drop(stream);
    println!("Hopefully the core has shut the fuck up by now");
}

<commit_msg>Figured out how to do module imports<commit_after>use std::io::TcpStream;
use std::collections::HashMap;

use qt::qvariant::Type as qVariantType;
mod qt;

fn main() {
    let mut stream = TcpStream::connect("hm.hacked.jp:4242");

    // Time to attempt a connection...

    // here is the handshake
    stream.write_be_u32(0x42b33f00).ok().expect("failed to send magic int"); // we absolutely do not support encryption or compression
    stream.write_be_u32(0x00000001).ok().expect("failed to send legacy protocol bit"); // we are only using the legacy protocol
    stream.write_be_u32(0x80000001).ok().expect("failed to send end-of-list bit"); // end of list

    println!("We are now going to sit on our asses and wait for the buf to come back");

    let result = stream.read_be_u32().ok().expect("Did not receive data from stream");
    println!("0x{}", result);

    drop(stream);
    println!("Hopefully the core has shut the fuck up by now");
}

<|endoftext|>


<commit_before>// SPDX-FileCopyrightText: 2019 Tuomas Siipola
// SPDX-License-Identifier: GPL-3.0-or-later

use sdl2::surface::Surface;

mod direction;
mod font;
mod game;
mod map;
mod menu;
mod snake;
mod state;
mod tile;

use crate::font::Font;
use crate::menu::Menu;
use crate::state::{Action, State};

fn main() {
    let sdl_context = sdl2::init().unwrap();
    let video_subsystem = sdl_context.video().unwrap();

    let window = video_subsystem
        .window("Natrix", 320, 240)
        .position_centered()
        .build()
        .unwrap();

    let mut canvas = window.into_canvas().software().build().unwrap();
    let texture_creator = canvas.texture_creator();

    let tiles = texture_creator
        .create_texture_from_surface(Surface::load_bmp("data/images/tiles.bmp").unwrap())
        .unwrap();

    let logo = texture_creator
        .create_texture_from_surface(Surface::load_bmp("data/images/logo.bmp").unwrap())
        .unwrap();

    let mut font = Font::load_bmp(&texture_creator, "data/images/NeoSans.bmp");

    let mut event_pump = sdl_context.event_pump().unwrap();

    let mut current_state: Box<dyn State> = Box::new(Menu::new());

    loop {
        match current_state.update(
            event_pump.poll_iter(),
            &mut canvas,
            &mut font,
            &tiles,
            &logo,
        ) {
            Action::Quit => break,
            Action::Change(next_state) => current_state = next_state,
            Action::None => {}
        }
    }
}
<commit_msg>Render game in 2x scale<commit_after>// SPDX-FileCopyrightText: 2019 Tuomas Siipola
// SPDX-License-Identifier: GPL-3.0-or-later

use sdl2::surface::Surface;

mod direction;
mod font;
mod game;
mod map;
mod menu;
mod snake;
mod state;
mod tile;

use crate::font::Font;
use crate::menu::Menu;
use crate::state::{Action, State};

fn main() {
    let sdl_context = sdl2::init().unwrap();
    let video_subsystem = sdl_context.video().unwrap();

    let scale = 2;

    let window = video_subsystem
        .window("Natrix", scale * 320, scale * 240)
        .position_centered()
        .build()
        .unwrap();

    let mut canvas = window.into_canvas().software().build().unwrap();
    canvas.set_scale(scale as f32, scale as f32).unwrap();

    let texture_creator = canvas.texture_creator();

    let tiles = texture_creator
        .create_texture_from_surface(Surface::load_bmp("data/images/tiles.bmp").unwrap())
        .unwrap();

    let logo = texture_creator
        .create_texture_from_surface(Surface::load_bmp("data/images/logo.bmp").unwrap())
        .unwrap();

    let mut font = Font::load_bmp(&texture_creator, "data/images/NeoSans.bmp");

    let mut event_pump = sdl_context.event_pump().unwrap();

    let mut current_state: Box<dyn State> = Box::new(Menu::new());

    loop {
        match current_state.update(
            event_pump.poll_iter(),
            &mut canvas,
            &mut font,
            &tiles,
            &logo,
        ) {
            Action::Quit => break,
            Action::Change(next_state) => current_state = next_state,
            Action::None => {}
        }
    }
}
<|endoftext|>


<commit_before>#[macro_use]
extern crate serde_derive;
extern crate image;
extern crate rayon;
extern crate docopt;
extern crate sprack;

mod sprack_bin;

use sprack_bin::*;
use sprack::*;
use std::path::Path;
use rayon::prelude::*;
use image::{DynamicImage, GenericImage};
use docopt::Docopt;

const PNG_EXT: &str = "png";

const USAGE: &'static str = "
Usage:  sprack [options] ([-w SIDE] [-h SIDE] | [-s SIDE]) [--help | <files>...]

Options:
    -r, --recursive             Recursively descend into directories.
    -o, --out=DIR               Output dir for results, overwrites existing files [default: ./out].
    -w, --width=SIDE            Atlas width [default: 1024].
    -h, --height=SIDE           Atlas height [default: 1024].
    -s, --size=SIDE             Atlas width and height.
    -f, --flipping              Allow placement of sprites rotated by 90 degrees.
    -t, --trim                  Trim resulting images to minimal size.
    -i, --increments-count=NUM  Allows incremental atlas size growth. 0 means atlas starts at
                                specified size, without increments. If NUM is > 0 starts at
                                INC size and if sprite doesn't fit - grows by another INC, where
                                INC = min(1, SIDE/(NUM+1)). Allowed values are 0..255, the higher
                                the value - the more time packing will take [default: 0].
    -k, --keep-work-dir         Do not delete temporary files after work.
    -h, --help                  Show this help message.
";

#[derive(Deserialize, Debug)]
struct Args {
  arg_files: Vec<String>,
  flag_out: String,
  flag_increments_count: u8,
  flag_width: u32,
  flag_height: u32,
  flag_size: Option<u32>,
  flag_trim: bool,
  flag_flipping: bool,
  flag_keep_work_dir: bool,
  flag_recursive: bool,
  flag_help: bool,
}

impl<'a> From<&'a Args> for RunOptions<'a> {
  fn from(args: &'a Args) -> Self {
    let bin_size = if let Some(size) = args.flag_size {
      Dimension { w: size, h: size }
    } else {
      Dimension { w: args.flag_width, h: args.flag_height }
    };

    let pack_options = PackOptions {
      bin_size,
      flipping: args.flag_flipping,
      trim: args.flag_trim,
      atlas_compact_steps: args.flag_increments_count,
      ..Default::default()
    };

    RunOptions {
      keep_work_dir: args.flag_keep_work_dir,
      input_paths: args.arg_files.iter().map(|f| Path::new(f.as_str())).collect(),
      output_path: Path::new(args.flag_out.as_str()),
      recursive: args.flag_recursive,
      pack_options,
      ..Default::default()
    }
  }
}

fn main() {
  let args: Args = Docopt::new(USAGE)
    .and_then(|d| d.deserialize())
    .unwrap_or_else(|e| e.exit());

  println!("Args: {:?}", args);
  let work_dir = new_work_dir().expect("Failed to create work dir");
  println!("Work dir is {:?}", &work_dir);

  let options = RunOptions::from(&args);
  for path in &options.input_paths {
    println!("> {:?}", path)
  }

  let samples = options.input_paths.iter().map(|path| image::open(path).unwrap()).collect::<Vec<_>>();

  let input = samples.iter().map(|s| Dimension { w: s.width(), h: s.height() }).collect::<Vec<_>>();
  let solutions = pack(&input, &options.pack_options);

  let best: Option<&PackResult> = match solutions {
    Ok(ref solutions) => solutions.par_iter()
      .map(|pack_result| (pack_result, write_solution(pack_result, &samples, &options, &work_dir)))
      .min_by_key(|tuple| tuple.1)
      .map(|tuple| tuple.0),
    Err(e) => {
      eprintln!("Error: {:?}", e);
      None
    }
  };

  if let Some(best) = best {
    let best_result_dir = Path::new(&work_dir).join(&best.heuristics.name());
    match copy_result_to_out(&best_result_dir, &options) {
      Ok(size) => println!("Best results with {}, {} bytes", &best.heuristics.name(), size),
      Err(e) => eprintln!("Failed to copy results from {:?} to {:?} - {:?}", &best_result_dir, &options.output_path, e),
    }
  }

  if !&options.keep_work_dir { cleanup_work_dir(&work_dir); }
}

fn write_solution(solution: &PackResult, images: &[DynamicImage], options: &RunOptions, work_dir: &AsRef<Path>) -> u64 {
  let dir = Path::new(&work_dir.as_ref()).join(&solution.heuristics.name());
  std::fs::remove_dir_all(&dir).unwrap_or(());
  std::fs::create_dir_all(&dir).expect(format!("Failed to create dir {:?}", &dir).as_ref());
  let mut size = 0;
  for (i, bin) in solution.bins.iter().enumerate() {
    size += draw_bin(&dir.join(i.to_string()).with_extension(PNG_EXT), images, bin, options.pack_options.trim);
  }
  println!("Heuristic {}: {} bins used, total size: {}b", solution.heuristics.name(), solution.bins.len(), size);
  size
}
<commit_msg>input file filtration<commit_after>#[macro_use]
extern crate serde_derive;
extern crate image;
extern crate rayon;
extern crate docopt;
extern crate sprack;

mod sprack_bin;

use sprack_bin::*;
use sprack::*;
use std::path::Path;
use std::ffi::OsStr;
use rayon::prelude::*;
use image::{DynamicImage, GenericImage};
use docopt::Docopt;

const PNG_EXT: &str = "png";

const USAGE: &'static str = "
Usage:  sprack [options] ([-w SIDE] [-h SIDE] | [-s SIDE]) [--help | <files>...]

Options:
    -r, --recursive             Recursively descend into directories.
    -o, --out=DIR               Output dir for results, overwrites existing files [default: ./out].
    -w, --width=SIDE            Atlas width [default: 1024].
    -h, --height=SIDE           Atlas height [default: 1024].
    -s, --size=SIDE             Atlas width and height.
    -f, --flipping              Allow placement of sprites rotated by 90 degrees.
    -t, --trim                  Trim resulting images to minimal size.
    -i, --increments-count=NUM  Allows incremental atlas size growth. 0 means atlas starts at
                                specified size, without increments. If NUM is > 0 starts at
                                INC size and if sprite doesn't fit - grows by another INC, where
                                INC = min(1, SIDE/(NUM+1)). Allowed values are 0..255, the higher
                                the value - the more time packing will take [default: 0].
    -k, --keep-work-dir         Do not delete temporary files after work.
    -h, --help                  Show this help message.
";

#[derive(Deserialize, Debug)]
struct Args {
  arg_files: Vec<String>,
  flag_out: String,
  flag_increments_count: u8,
  flag_width: u32,
  flag_height: u32,
  flag_size: Option<u32>,
  flag_trim: bool,
  flag_flipping: bool,
  flag_keep_work_dir: bool,
  flag_recursive: bool,
  flag_help: bool,
}

impl<'a> From<&'a Args> for RunOptions<'a> {
  fn from(args: &'a Args) -> Self {
    let bin_size = if let Some(size) = args.flag_size {
      Dimension { w: size, h: size }
    } else {
      Dimension { w: args.flag_width, h: args.flag_height }
    };

    let pack_options = PackOptions {
      bin_size,
      flipping: args.flag_flipping,
      trim: args.flag_trim,
      atlas_compact_steps: args.flag_increments_count,
      ..Default::default()
    };

    RunOptions {
      keep_work_dir: args.flag_keep_work_dir,
      input_paths: args.arg_files.iter().map(|f| Path::new(f.as_str())).collect(),
      output_path: Path::new(args.flag_out.as_str()),
      recursive: args.flag_recursive,
      pack_options,
      ..Default::default()
    }
  }
}

fn main() {
  let args: Args = Docopt::new(USAGE)
    .and_then(|d| d.deserialize())
    .unwrap_or_else(|e| e.exit());

  println!("Args: {:?}", args);
  let work_dir = new_work_dir().expect("Failed to create work dir");
  println!("Work dir is {:?}", &work_dir);

  let options = RunOptions::from(&args);
  for path in &options.input_paths {
    println!("> {:?}", path)
  }

  let samples = options.input_paths.iter()
    .filter(|path| is_supported_format(path))
    .map(|path| image::open(path).unwrap())
    .collect::<Vec<_>>();

  let input = samples.iter().map(|s| Dimension { w: s.width(), h: s.height() }).collect::<Vec<_>>();
  let solutions = pack(&input, &options.pack_options);

  let best: Option<&PackResult> = match solutions {
    Ok(ref solutions) => solutions.par_iter()
      .map(|pack_result| (pack_result, write_solution(pack_result, &samples, &options, &work_dir)))
      .min_by_key(|tuple| tuple.1)
      .map(|tuple| tuple.0),
    Err(e) => {
      eprintln!("Error: {:?}", e);
      None
    }
  };

  if let Some(best) = best {
    let best_result_dir = Path::new(&work_dir).join(&best.heuristics.name());
    match copy_result_to_out(&best_result_dir, &options) {
      Ok(size) => println!("Best results with {}, {} bytes", &best.heuristics.name(), size),
      Err(e) => eprintln!("Failed to copy results from {:?} to {:?} - {:?}", &best_result_dir, &options.output_path, e),
    }
  }

  if !&options.keep_work_dir { cleanup_work_dir(&work_dir); }
}

fn is_supported_format(path: &Path) -> bool {
  if let Some(ext) = path.extension().map(OsStr::to_string_lossy).map(|e| e.to_lowercase()) {
    let ext = ext.as_str();
    match ext {
      "png" | "bmp" | "gif" | "jpg" | "jpeg" | "ico" | "tiff" | "webp" | "ppm" => true,
      _ => false
    }
  } else { false }
}

fn write_solution(solution: &PackResult, images: &[DynamicImage], options: &RunOptions, work_dir: &AsRef<Path>) -> u64 {
  let dir = Path::new(&work_dir.as_ref()).join(&solution.heuristics.name());
  std::fs::remove_dir_all(&dir).unwrap_or(());
  std::fs::create_dir_all(&dir).expect(format!("Failed to create dir {:?}", &dir).as_ref());
  let mut size = 0;
  for (i, bin) in solution.bins.iter().enumerate() {
    size += draw_bin(&dir.join(i.to_string()).with_extension(PNG_EXT), images, bin, options.pack_options.trim);
  }
  println!("Heuristic {}: {} bins used, total size: {}b", solution.heuristics.name(), solution.bins.len(), size);
  size
}
<|endoftext|>


<commit_before>use std::fs;
use std::env;
use std::fs::File;
use std::collections::HashMap;
use std::os::unix::fs::MetadataExt;
use std::hash::Hasher;
use std::collections::hash_map::DefaultHasher;
use std::io::Read;

#[derive(Debug)]
struct FileEntry {
    inode: u64,
    size: u64,
    dev:  u64,
    path : String,
}

fn collect_files(dir: &String, h: &mut HashMap<u64, Vec<FileEntry>>) {
    if let Ok(entries) = fs::read_dir(dir) {
        for entry in entries {
            if let Ok(entry) = entry {
                let path = entry.path();
                if let Some(path_str) = path.to_str() {
                    if let Ok(metadata) = path.symlink_metadata() {
                        let ft = metadata.file_type();
                        if !ft.is_symlink() {
                            if ft.is_file() {
                                let file_size = metadata.len();
                                if !h.contains_key(&file_size) {
                                    h.insert(file_size, Vec::new());
                                }
                                if let Some(vec) = h.get_mut(&file_size) {
                                    vec.push(
                                         FileEntry{ inode : metadata.ino(),
                                             size  : metadata.len(),
                                             dev   : metadata.dev(),
                                             path  : String::from(path_str),
                                         });
                                }
                            } else if ft.is_dir() {
                                collect_files(&(String::from(path_str)), h);
                            }
                        }
                    }
                }
            }
        }
    }
    else {
        println!("{}: invalid directory", dir);
    }
}

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

    // Print out usage if no directories are given.
    if args.len() == 1 {
        println!("Usage: {} <dir1> [dir2 [dir3 ...]]", args[0]);
        ::std::process::exit(0);
    }

    let mut hmap: HashMap<u64, Vec<FileEntry> > = HashMap::new();

    for dir in &args[1..] {
        collect_files(dir, &mut hmap);
    }

    // Get rid of all the single entries.
    hmap.retain(|_, v| v.len() >= 2);

    let mut cluster = 1;

    for (key, val) in hmap.iter() {
        if *key == 0 {
            continue;
        }
        let mut duplicates: HashMap<u64, Vec<FileEntry> > = HashMap::new();
        for file_entry in val {
            if let Ok(mut file) = File::open(&file_entry.path) {
                let mut buf: [u8; 1024] = [0; 1024];
                if let Ok(nbytes) = file.read(&mut buf) {
                    let mut hasher = DefaultHasher::new();
                    hasher.write(&buf[..nbytes as usize]);
                    let k = hasher.finish();
                    if !duplicates.contains_key(&k) {
                        duplicates.insert(k, Vec::new());
                    }
                    if let Some(vec) = duplicates.get_mut(&k) {
                        vec.push(
                            FileEntry{ inode : file_entry.inode,
                                size : file_entry.size,
                                dev  : file_entry.dev,
                                path : file_entry.path.to_string(),
                            });
                    }
                }
            }
        }
        for (hash, vec) in duplicates {
            if vec.len() >= 2 {
                println!("{} files in cluster {} (size: {}, digest: {})",
                         vec.len(), cluster, key, hash);
                for file_entry in vec {
                    println!("{}", file_entry.path);
                }
                cluster += 1;
            }
        }
    }
}
<commit_msg>Put the duplicate finding logic in a function<commit_after>use std::fs;
use std::env;
use std::fs::File;
use std::collections::HashMap;
use std::os::unix::fs::MetadataExt;
use std::hash::Hasher;
use std::collections::hash_map::DefaultHasher;
use std::io::Read;

#[derive(Debug)]
struct FileEntry {
    inode: u64,
    size: u64,
    dev:  u64,
    path : String,
}

fn collect_files(dir: &String, h: &mut HashMap<u64, Vec<FileEntry>>) {
    if let Ok(entries) = fs::read_dir(dir) {
        for entry in entries {
            if let Ok(entry) = entry {
                let path = entry.path();
                if let Some(path_str) = path.to_str() {
                    if let Ok(metadata) = path.symlink_metadata() {
                        let ft = metadata.file_type();
                        if !ft.is_symlink() {
                            if ft.is_file() {
                                let file_size = metadata.len();
                                if !h.contains_key(&file_size) {
                                    h.insert(file_size, Vec::new());
                                }
                                if let Some(vec) = h.get_mut(&file_size) {
                                    vec.push(
                                         FileEntry{ inode : metadata.ino(),
                                             size  : metadata.len(),
                                             dev   : metadata.dev(),
                                             path  : String::from(path_str),
                                         });
                                }
                            } else if ft.is_dir() {
                                collect_files(&(String::from(path_str)), h);
                            }
                        }
                    }
                }
            }
        }
    }
    else {
        println!("{}: invalid directory", dir);
    }
}

fn find_duplicates(duplicates: &mut HashMap<u64, Vec<FileEntry>>,
                   vec: &Vec<FileEntry> ) {
    for file_entry in vec {
        if let Ok(mut file) = File::open(&file_entry.path) {
            let mut buf: [u8; 1024] = [0; 1024];
            if let Ok(nbytes) = file.read(&mut buf) {
                let mut hasher = DefaultHasher::new();
                hasher.write(&buf[..nbytes as usize]);
                let k = hasher.finish();
                if !duplicates.contains_key(&k) {
                    duplicates.insert(k, Vec::new());
                }
                if let Some(vec) = duplicates.get_mut(&k) {
                    vec.push(
                        FileEntry{ inode : file_entry.inode,
                            size : file_entry.size,
                            dev  : file_entry.dev,
                            path : file_entry.path.to_string(),
                        });
                }
            }
        }
    }
}

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

    // Print out usage if no directories are given.
    if args.len() == 1 {
        println!("Usage: {} <dir1> [dir2 [dir3 ...]]", args[0]);
        ::std::process::exit(0);
    }

    let mut hmap: HashMap<u64, Vec<FileEntry> > = HashMap::new();

    for dir in &args[1..] {
        collect_files(dir, &mut hmap);
    }

    // Get rid of all the single entries.
    hmap.retain(|_, v| v.len() >= 2);

    let mut cluster = 1;

    for (key, val) in hmap.iter() {
        if *key == 0 {
            continue;
        }
        let mut duplicates: HashMap<u64, Vec<FileEntry> > = HashMap::new();
        find_duplicates(&mut duplicates, &val);
        for (hash, vec) in duplicates {
            if vec.len() >= 2 {
                println!("{} files in cluster {} (size: {}, digest: {})",
                         vec.len(), cluster, key, hash);
                for file_entry in vec {
                    println!("{}", file_entry.path);
                }
                cluster += 1;
            }
        }
    }
}
<|endoftext|>


<commit_before>#[macro_use]
extern crate serde_derive;
#[macro_use]
extern crate serde_json;
#[macro_use]
extern crate snafu;
#[macro_use]
extern crate slog;
#[macro_use]
extern crate rusqlite;
#[macro_use]
extern crate clap;

use clap::Arg;
use daemonize::Daemonize;
use futures_cpupool::CpuPool;
use hyper_tls::HttpsConnector;
use sloggers::Config;

use std::error::Error;
use std::fs::File;
use std::io::Read;
use std::net::SocketAddr;
use std::process::exit;
use std::sync::Arc;

mod db;
mod error;
mod github;
mod rest;
mod settings;

use rest::{register_servlets, AppConfig, AppState, AuthenticateUser, MiddlewareLogger};
use settings::Settings;

/// Short hand for our HTTPS enabled outbound HTTP client.
type HttpClient = hyper::Client<HttpsConnector<hyper::client::HttpConnector>>;

/// Attempts to load and build the handlebars template file.
macro_rules! load_template {
    ($logger:expr, $hb:expr, $root:expr, $name:expr) => {
        if let Err(e) = load_template_impl(&mut $hb, $root, $name) {
            crit!($logger, "Failed to load resources/{}.hbs: {}", $name, e);
            exit(1);
        }
    };
}

/// App Entry point.
fn main() {
    // Load settings, first by looking at command line options for config files
    // to look in.
    let matches = app_from_crate!()
        .arg(
            Arg::with_name("config")
                .short("c")
                .multiple(true)
                .long("config")
                .value_name("FILE")
                .help("Sets a custom config file")
                .takes_value(true)
                .required(false),
        )
        .get_matches();

    let mut c = config::Config::new();

    // We can have multiple config files which get merged together
    for file in matches.values_of("config").unwrap_or_default() {
        if let Err(err) = c.merge(config::File::with_name(file)) {
            // We don't have a logger yet, so print to stderr
            eprintln!("{}", err);
            exit(1)
        }
    }

    // Also load config from environment
    c.merge(config::Environment::with_prefix("SHAFT")).unwrap();

    let settings: Settings = match c.try_into() {
        Ok(s) => s,
        Err(err) => {
            // We don't have a logger yet, so print to stderr
            eprintln!("Config error: {}", err);
            exit(1);
        }
    };

    // Set up logging immediately.
    let logger = settings.log.build_logger().unwrap();

    let addr: SocketAddr = match settings.bind.parse() {
        Ok(a) => a,
        Err(err) => {
            crit!(
                logger,
                "Failed to parse bind addr {}: {}",
                settings.bind,
                err
            );
            exit(1)
        }
    };

    // Load and build the templates.
    let mut hb = handlebars::Handlebars::new();
    load_template!(logger, hb, &settings.resource_dir, "index");
    load_template!(logger, hb, &settings.resource_dir, "login");
    load_template!(logger, hb, &settings.resource_dir, "transactions");
    load_template!(logger, hb, &settings.resource_dir, "base");
    hb.register_helper(
        "pence-as-pounds",
        Box::new(rest::format_pence_as_pounds_helper),
    );

    // Set up the database
    let database = Arc::new(db::SqliteDatabase::with_path(settings.database_file));

    // Sanitize the webroot to not end in a trailing slash.
    let web_root = settings.web_root.trim_end_matches('/').to_string();

    // This is the read only config for the app.
    let app_config = AppConfig {
        github_client_id: settings.github.client_id.clone(),
        github_client_secret: settings.github.client_secret.clone(),
        github_state: settings.github.state.clone(),
        web_root,
        required_org: settings.github.required_org.clone(),
        resource_dir: settings.resource_dir.clone(),
    };

    // Thread pool to use mainly for DB
    let cpu_pool = CpuPool::new_num_cpus();

    // Set up HTTPS enabled HTTP client
    let https = HttpsConnector::new();
    let http_client = hyper::Client::builder().build::<_, hyper::Body>(https);

    // Holds the state for the shared state of the app. Gets cloned to each thread.
    let app_state = AppState {
        database,
        config: app_config,
        cpu_pool,
        handlebars: Arc::new(hb),
        http_client,
    };

    // Set up HTTP server
    let mut sys = actix_rt::System::new("shaft"); // Need to set up an actix system first.

    let logger_middleware = MiddlewareLogger::new(logger.clone());

    let http_server = actix_web::HttpServer::new(move || {
        // This gets called in each thread to set up the HTTP handlers

        let logger_middleware = logger_middleware.clone();

        actix_web::App::new()
            .data(app_state.clone())
            .wrap(AuthenticateUser::new(app_state.database.clone()))
            .wrap_fn(move |req, srv| logger_middleware.wrap(req, srv))
            .configure(|config| register_servlets(config, &app_state))
    })
    .bind(addr)
    .unwrap();

    // If we need to daemonize do so *just* before starting the event loop
    if let Some(daemonize_settings) = settings.daemonize {
        Daemonize::new()
            .pid_file(daemonize_settings.pid_file)
            .start()
            .expect("be able to daemonize");
    }

    // Start the event loop.
    info!(logger, "Started server on {}", settings.bind);
    let _ = sys.block_on(async move { http_server.run().await });
}

/// Attempts to load the template into handlebars instance.
fn load_template_impl(
    hb: &mut handlebars::Handlebars,
    root: &str,
    name: &str,
) -> Result<(), Box<dyn Error>> {
    let mut index_file = File::open(format!("{}/{}.hbs", root, name))?;
    let mut source = String::new();
    index_file.read_to_string(&mut source)?;
    hb.register_template_string(name, source)?;

    Ok(())
}
<commit_msg>Update 'Started...' log line<commit_after>#[macro_use]
extern crate serde_derive;
#[macro_use]
extern crate serde_json;
#[macro_use]
extern crate snafu;
#[macro_use]
extern crate slog;
#[macro_use]
extern crate rusqlite;
#[macro_use]
extern crate clap;

use clap::Arg;
use daemonize::Daemonize;
use futures_cpupool::CpuPool;
use hyper_tls::HttpsConnector;
use sloggers::Config;

use std::error::Error;
use std::fs::File;
use std::io::Read;
use std::net::SocketAddr;
use std::process::exit;
use std::sync::Arc;

mod db;
mod error;
mod github;
mod rest;
mod settings;

use rest::{register_servlets, AppConfig, AppState, AuthenticateUser, MiddlewareLogger};
use settings::Settings;

/// Short hand for our HTTPS enabled outbound HTTP client.
type HttpClient = hyper::Client<HttpsConnector<hyper::client::HttpConnector>>;

/// Attempts to load and build the handlebars template file.
macro_rules! load_template {
    ($logger:expr, $hb:expr, $root:expr, $name:expr) => {
        if let Err(e) = load_template_impl(&mut $hb, $root, $name) {
            crit!($logger, "Failed to load resources/{}.hbs: {}", $name, e);
            exit(1);
        }
    };
}

/// App Entry point.
fn main() {
    // Load settings, first by looking at command line options for config files
    // to look in.
    let matches = app_from_crate!()
        .arg(
            Arg::with_name("config")
                .short("c")
                .multiple(true)
                .long("config")
                .value_name("FILE")
                .help("Sets a custom config file")
                .takes_value(true)
                .required(false),
        )
        .get_matches();

    let mut c = config::Config::new();

    // We can have multiple config files which get merged together
    for file in matches.values_of("config").unwrap_or_default() {
        if let Err(err) = c.merge(config::File::with_name(file)) {
            // We don't have a logger yet, so print to stderr
            eprintln!("{}", err);
            exit(1)
        }
    }

    // Also load config from environment
    c.merge(config::Environment::with_prefix("SHAFT")).unwrap();

    let settings: Settings = match c.try_into() {
        Ok(s) => s,
        Err(err) => {
            // We don't have a logger yet, so print to stderr
            eprintln!("Config error: {}", err);
            exit(1);
        }
    };

    // Set up logging immediately.
    let logger = settings.log.build_logger().unwrap();

    let addr: SocketAddr = match settings.bind.parse() {
        Ok(a) => a,
        Err(err) => {
            crit!(
                logger,
                "Failed to parse bind addr {}: {}",
                settings.bind,
                err
            );
            exit(1)
        }
    };

    // Load and build the templates.
    let mut hb = handlebars::Handlebars::new();
    load_template!(logger, hb, &settings.resource_dir, "index");
    load_template!(logger, hb, &settings.resource_dir, "login");
    load_template!(logger, hb, &settings.resource_dir, "transactions");
    load_template!(logger, hb, &settings.resource_dir, "base");
    hb.register_helper(
        "pence-as-pounds",
        Box::new(rest::format_pence_as_pounds_helper),
    );

    // Set up the database
    let database = Arc::new(db::SqliteDatabase::with_path(settings.database_file));

    // Sanitize the webroot to not end in a trailing slash.
    let web_root = settings.web_root.trim_end_matches('/').to_string();

    // This is the read only config for the app.
    let app_config = AppConfig {
        github_client_id: settings.github.client_id.clone(),
        github_client_secret: settings.github.client_secret.clone(),
        github_state: settings.github.state.clone(),
        web_root,
        required_org: settings.github.required_org.clone(),
        resource_dir: settings.resource_dir.clone(),
    };

    // Thread pool to use mainly for DB
    let cpu_pool = CpuPool::new_num_cpus();

    // Set up HTTPS enabled HTTP client
    let https = HttpsConnector::new();
    let http_client = hyper::Client::builder().build::<_, hyper::Body>(https);

    // Holds the state for the shared state of the app. Gets cloned to each thread.
    let app_state = AppState {
        database,
        config: app_config,
        cpu_pool,
        handlebars: Arc::new(hb),
        http_client,
    };

    // Set up HTTP server
    let mut sys = actix_rt::System::new("shaft"); // Need to set up an actix system first.

    let logger_middleware = MiddlewareLogger::new(logger.clone());

    let http_server = actix_web::HttpServer::new(move || {
        // This gets called in each thread to set up the HTTP handlers

        let logger_middleware = logger_middleware.clone();

        actix_web::App::new()
            .data(app_state.clone())
            .wrap(AuthenticateUser::new(app_state.database.clone()))
            .wrap_fn(move |req, srv| logger_middleware.wrap(req, srv))
            .configure(|config| register_servlets(config, &app_state))
    })
    .bind(addr)
    .unwrap();

    // If we need to daemonize do so *just* before starting the event loop
    if let Some(daemonize_settings) = settings.daemonize {
        Daemonize::new()
            .pid_file(daemonize_settings.pid_file)
            .start()
            .expect("be able to daemonize");
    }

    // Start the event loop.
    info!(logger, "Started server on http://{}", settings.bind);
    let _ = sys.block_on(async move { http_server.run().await });
}

/// Attempts to load the template into handlebars instance.
fn load_template_impl(
    hb: &mut handlebars::Handlebars,
    root: &str,
    name: &str,
) -> Result<(), Box<dyn Error>> {
    let mut index_file = File::open(format!("{}/{}.hbs", root, name))?;
    let mut source = String::new();
    index_file.read_to_string(&mut source)?;
    hb.register_template_string(name, source)?;

    Ok(())
}
<|endoftext|>


<commit_before>#![feature(custom_derive)]
#![feature(fmt_flags)]

extern crate hyper;
extern crate rustc_serialize;

use std::fmt;
use std::io::Read;
use std::collections::HashSet;

use hyper::client::{Client, Response, RequestBuilder};
use hyper::header::{Accept, Connection, qitem};
use hyper::mime::{Mime, TopLevel, SubLevel};

use rustc_serialize::json;

struct MyClient {
    client : Client,
    app_id : String,
    app_key : String,
}

#[derive(Hash, Debug, RustcEncodeable, RustcDecodable)]
struct Line {
    id : String,
    name : String,
    modeName : String,
    routeSections : Vec<RouteSection>
}

#[derive(Hash, Debug, RustcEncodeable, RustcDecodable)]
struct RouteSection {
    name : String,
    direction : String,
    originator : String,
    destination : String,
}

impl fmt::Display for Line {
    fn fmt(&self, f : &mut fmt::Formatter) -> fmt::Result {
        write!(f, "({})", self.id)
    }
}

impl MyClient {
    fn new() -> MyClient {
        return MyClient{
            client : Client::new(),
            app_id : String::new(),
            app_key : String::new(),
        }
    }

    fn get(&mut self, endpoint : &str) -> Response {
        self.client.get("https://api.tfl.gov.uk/line/route?app_id=&app_key=")
            .header(Connection::close())
            .header(Accept(vec![
                qitem(Mime(TopLevel::Application,
                    SubLevel::Ext("json".to_owned()), vec![])),
            ]))
            .send().unwrap()
    }
}

fn main() {
    let mut line_names : HashSet<String> = HashSet::new();
    let mut route_section_names : HashSet<String> = HashSet::new();
    let mut client = MyClient::new();
    let mut resp = client.get("/line/route");
    let mut body = String::new();
    resp.read_to_string(&mut body).unwrap();
    let lines : Vec<Line> = json::decode(&body).unwrap();
    for line in lines {
        let line_known = line_names.contains(&line.name);
        println!("{}, Duplicate: {}:", line.name, line_known);
        line_names.insert(line.name.clone());
        for routeSection in line.routeSections {
            let route_section_known = route_section_names.contains(&routeSection.name);
            println!("\t{}, Duplicate: {}", routeSection.name, route_section_known);
            route_section_names.insert(routeSection.name.clone());
        }
    }
}
<commit_msg>Work torwards parsing and caching all needed data<commit_after>#![feature(custom_derive)]

extern crate hyper;
extern crate rustc_serialize;

use std::fs;
use std::path::Path;
use std::fs::File;
use std::io::{Read, Write};
use std::collections::{HashSet, HashMap};

use hyper::client::{Client, Response, RequestBuilder};
use hyper::header::{Accept, Connection, qitem};
use hyper::mime::{Mime, TopLevel, SubLevel};

use rustc_serialize::json;

struct MyClient {
    client : Client,
    app_id : String,
    app_key : String,
}

#[derive(Clone, Debug, RustcEncodeable, RustcDecodable)]
struct Line {
    id : String,
    name : String,
    modeName : String,
    routeSections : Vec<RouteSection>
}

#[derive(Clone, Debug, RustcEncodeable, RustcDecodable)]
struct RouteSection {
    name : String,
    direction : String,
    originator : String,
    destination : String,
    timetable : Option<TimeTable>,
}

#[derive(Clone, Debug, RustcEncodeable, RustcDecodable)]
struct Interval {
    stopId : String,
    timeToArrival: f64,
}

#[derive(Clone, Debug, RustcEncodeable, RustcDecodable)]
struct StationInterval {
    id : i64,
    intervals : Vec<Interval>
}

#[derive(Clone, Debug, RustcEncodeable, RustcDecodable)]
struct KnownJourney {
    intervalId : i64,
    hour : String,
    minute : String,
}

#[derive(Clone, Debug, RustcEncodeable, RustcDecodable)]
struct Schedule {
    name : String,
    knownJourneys : Vec<KnownJourney>,
}

#[derive(Clone, Debug, RustcEncodeable, RustcDecodable)]
struct TimeTable {
    stationIntervals : Vec<StationInterval>,
    schedules : Vec<Schedule>,
}

#[derive(Debug, RustcEncodeable, RustcDecodable)]
struct RoutesTimeTables {
    routes : Vec<TimeTable>,
}

#[derive(Debug, RustcEncodeable, RustcDecodable)]
struct TimeTableResponse {
    timetable : RoutesTimeTables,
}

impl MyClient {
    fn new() -> MyClient {
        let cachePath : Path = Path::new("./cache");
        fs::create_dir(cachePath).unwrap();
        return MyClient{
            client : Client::new(),
            app_id : String::new(),
            app_key : String::new(),
            cache_dir : String::from_str("./cache"),
        }
    }

    fn get(&mut self, endpoint : &str) -> String {
        match self.cache_get(endpoint) {
            Some(body) => body,
            None => self.remote_get(endpoint)
        }
    }

    fn remote_get(&mut self, endpoint : &str) -> String {
        let req_uri = format!("https://api.tfl.gov.uk{}?app_id={}&app_key={}", endpoint, self.app_id, self.app_key);
        let mut body = String::new();
        let mut resp = self.client.get(&req_uri)
            .header(Connection::close())
            .header(Accept(vec![
                qitem(Mime(TopLevel::Application,
                    SubLevel::Ext("json".to_owned()), vec![])),
            ]))
            .send().unwrap();
        resp.read_to_string(&mut body).unwrap();
        self.cache_put(endpoint, body)
    }

    fn cache_fname(&mut self, endpoint : &str) -> String {
        let fname = String::from_str(endpoint);
        self.cache_dir + "/".to_string() + fname.replace("/", "_")
    }

    fn cache_put(&mut self, endpoint : &str, body : String) -> String {
        let mut f = try!(File::create(self.cache_fname(endpoint)));
        f.write_string(body);
        body
    }

    fn cache_get(&mut self, endpoint : &str) -> Option<String> {
        let mut body = String::new();
        match File::open(self.cache_fname(endpoint)) {
            Ok(f) => {
                f.read_to_string(&mut body);
                Some(body)
            },
            Err(_) => None,
        }
    }
}

fn get_lines(client : &mut MyClient) -> Vec<Line> {
    let body = client.get("/line/route");
    json::decode(&body).unwrap()
}

fn get_timetable(client : &mut MyClient, line_id : &str, originator: &str, destination : &str) -> Option<TimeTable> {
    let req_uri = format!("/line/{}/timetable/{}/to/{}", line_id, originator, destination);
    let body = client.get(&req_uri);
    match json::decode::<TimeTableResponse>(&body) {
        Ok(ttresp) => Some(ttresp.timetable.routes[0].clone()),
        Err(_) => None,
    }
}

fn main() {
    let mut line_names : HashSet<String> = HashSet::new();
    let mut route_section_names : HashSet<String> = HashSet::new();
    let mut client = MyClient::new();
    let mut lines = get_lines(&mut client);
    for line in &mut lines {
        let line_known = line_names.contains(&line.name);
        println!("{}, Duplicate: {}:", line.name, line_known);
        line_names.insert(line.name.clone());
        for routeSection in &mut line.routeSections {
            let route_section_known = route_section_names.contains(&routeSection.name);
            println!("\t{}, Duplicate: {}", routeSection.name, route_section_known);
            route_section_names.insert(routeSection.name.clone());
            routeSection.timetable = get_timetable(&mut client, &line.id, &routeSection.originator, &routeSection.destination);
        }
    }
}
<|endoftext|>