<commit_before>#![allow(unused_imports)]
#![allow(dead_code)]
#[allow(unused)]
#[allow(unused_variables)]

mod api;
mod server;
mod config;
mod consul;

#[cfg(test)]
mod config_test;

#[macro_use]
extern crate log;
extern crate env_logger;
#[macro_use]
extern crate clap;
extern crate grpcio;
extern crate futures;
extern crate protobuf;
#[macro_use]
extern crate serde_derive;
#[macro_use]
extern crate serde_json;
extern crate toml;
#[macro_use]
extern crate error_chain;
#[macro_use]
extern crate reqwest;
extern crate serde;
extern crate url;
extern crate md5;

use clap::{Arg, App, SubCommand};
use std::process::exit;
use std::sync::Arc;
use consul::Client as ConsulClient;
use consul::catalog::Catalog;
use std::borrow::Borrow;
use grpcio::{Environment, ChannelBuilder, UnarySink};
use config::Config;
use api::eds_grpc::EndpointDiscoveryServiceClient;
use api::discovery::DiscoveryRequest;

fn main() {
    env_logger::init();

    let app = App::new("diplomat")
        .version(crate_version!())
        .about(
            "Provides the Envoy v2 API as a gRPC service and CLI application.",
        )
        .author("Timothy Perrett")
        .arg(
            Arg::with_name("config")
                .long("config")
                .value_name("config")
                .help("Path to the configuration for diplomat")
                .required(false)
                .takes_value(true),
        )
        .subcommand(
            SubCommand::with_name("client")
                .about("Interact with diplomat using the cli")
                .subcommand(
                    SubCommand::with_name("eds")
                        .about(
                            "given a service name, resolve the IPs providing that service",
                        )
                        .arg(
                            Arg::with_name("service-name")
                                .long("service-name")
                                .value_name("service-name")
                                .required(true)
                                .takes_value(true),
                        ),
                )
                .subcommand(
                    SubCommand::with_name("cds").about("cds").arg(
                        Arg::with_name("service-name")
                            .long("service-name")
                            .value_name("service-name")
                            .required(true)
                            .takes_value(true),
                    ),
                ),
        )
        .subcommand(SubCommand::with_name("serve").about(
            "Starts the diplomat server",
        ));

    // TIM: Not sure if cloning here is going to cause problems,
    // but given this is once at the edge of the world it probally isn't
    // too much of a big deal.
    let matches = app.clone().get_matches();

    let config_path: &str = matches.value_of("config").unwrap_or("diplomat.toml");
    info!(
        "==>> attempting to load configuration from '{}'",
        config_path
    );

    let config = config::load(config_path.to_string());
    if config.is_err() {
        error!("==>> failed loading the specified configuration file... exiting.");
        exit(1);
    }

    let ccc = consul::Config::new().unwrap();
    let xxx = ConsulClient::new(ccc);

    match matches.subcommand() {
        ("client", Some(sub_m)) => {
            match sub_m.subcommand_name() {
                Some("eds") => {
                    let unwrapped = config.unwrap();

                    info!("==>> attempting to call {}", unwrapped.client.address);

                    let env = Arc::new(Environment::new(1));
                    let channel = ChannelBuilder::new(env).connect(unwrapped.client.address.as_str());
                    let client = EndpointDiscoveryServiceClient::new(channel);

                    let mut node = api::base::Node::new();
                    node.set_id("10.0.10.100".to_string());
                    node.set_cluster("foo--1-2-3--sdfiqsq".to_string());

                    let mut dr = DiscoveryRequest::new();
                    dr.set_node(node);
                    dr.set_type_url(server::MessageType::DiscoveryRequest.to_string());

                    let res = client.fetch_endpoints(dr);
                    println!("eds {:?}", res);
                }
                Some("cds") => println!("cds is currently not implemented"),
                _ => {
                    let _ = app.clone().print_help();
                    println!("");
                }
            }
        }
        ("serve", Some(_)) => {
            let unwrapped = config.unwrap();
            info!("==>> booting diplomat server on {}:{}...", unwrapped.server.host, unwrapped.server.port);
            ::server::start(unwrapped, xxx);
        }
        _ => {
            let _ = app.clone().print_help();
            println!("");
        }
    }
}
<commit_msg>Update some params<commit_after>#![allow(unused_imports)]
#![allow(dead_code)]
#[allow(unused)]
#[allow(unused_variables)]

mod api;
mod server;
mod config;
mod consul;

#[cfg(test)]
mod config_test;

#[macro_use]
extern crate log;
extern crate env_logger;
#[macro_use]
extern crate clap;
extern crate grpcio;
extern crate futures;
extern crate protobuf;
#[macro_use]
extern crate serde_derive;
#[macro_use]
extern crate serde_json;
extern crate toml;
#[macro_use]
extern crate error_chain;
#[macro_use]
extern crate reqwest;
extern crate serde;
extern crate url;
extern crate md5;

use clap::{Arg, App, SubCommand};
use std::process::exit;
use std::sync::Arc;
use consul::Client as ConsulClient;
use consul::catalog::Catalog;
use std::borrow::Borrow;
use grpcio::{Environment, ChannelBuilder, UnarySink};
use config::Config;
use api::eds_grpc::EndpointDiscoveryServiceClient;
use api::discovery::DiscoveryRequest;

fn main() {
    env_logger::init();

    let app = App::new("diplomat")
        .version(crate_version!())
        .about(
            "Provides the Envoy v2 API as a gRPC service and CLI application.",
        )
        .author("Timothy Perrett")
        .arg(
            Arg::with_name("config")
                .long("config")
                .value_name("config")
                .help("Path to the configuration for diplomat")
                .required(false)
                .takes_value(true),
        )
        .subcommand(
            SubCommand::with_name("client")
                .about("Interact with diplomat using the cli")
                .subcommand(
                    SubCommand::with_name("eds")
                        .about(
                            "given a service name, resolve the IPs providing that service",
                        )
                        .arg(
                            Arg::with_name("cluster")
                                .long("cluster")
                                .value_name("cluster")
                                .required(true)
                                .takes_value(true),
                        )
                        .arg(
                            Arg::with_name("node")
                                .long("node")
                                .value_name("node")
                                .required(true)
                                .takes_value(true),
                        ),
                )
                .subcommand(
                    SubCommand::with_name("cds").about("cds").arg(
                        Arg::with_name("cluster")
                            .long("cluster")
                            .value_name("cluster")
                            .required(true)
                            .takes_value(true),
                    ),
                ),
        )
        .subcommand(SubCommand::with_name("serve").about(
            "Starts the diplomat server",
        ));

    // TIM: Not sure if cloning here is going to cause problems,
    // but given this is once at the edge of the world it probally isn't
    // too much of a big deal.
    let matches = app.clone().get_matches();

    let config_path: &str = matches.value_of("config").unwrap_or("diplomat.toml");
    info!(
        "==>> attempting to load configuration from '{}'",
        config_path
    );

    let configr = config::load(config_path.to_string());
    if configr.is_err() {
        error!("==>> failed loading the specified configuration file... exiting.");
        exit(1);
    }
    let config = configr.unwrap();
    let consul_config = consul::Config::new().unwrap();
    let consu_client = ConsulClient::new(consul_config);

    match matches.subcommand() {
        ("client", Some(sub_m)) => {
            match sub_m.subcommand_name() {
                Some("eds") => {
                    info!("==>> attempting to call {}", config.client.address);

                    let env = Arc::new(Environment::new(1));
                    let channel = ChannelBuilder::new(env).connect(config.client.address.as_str());
                    let client = EndpointDiscoveryServiceClient::new(channel);

                    let mut node = api::base::Node::new();
                    node.set_id(matches.value_of("node").unwrap().to_string());
                    node.set_cluster(matches.value_of("service-cluster").unwrap().to_string());

                    let mut dr = DiscoveryRequest::new();
                    dr.set_node(node);
                    dr.set_type_url(server::MessageType::DiscoveryRequest.to_string());

                    let res = client.fetch_endpoints(dr);
                    println!("eds {:?}", res);
                }
                Some("cds") => println!("cds is currently not implemented"),
                _ => {
                    let _ = app.clone().print_help();
                    println!("");
                }
            }
        }
        ("serve", Some(_)) => {
            info!("==>> booting diplomat server on {}:{}...", config.server.host, config.server.port);
            ::server::start(config, consu_client);
        }
        _ => {
            let _ = app.clone().print_help();
            println!("");
        }
    }
}
<|endoftext|>


<commit_before>extern crate clap;
extern crate git2;
extern crate yaml_rust;

use backend::Backend;
use cli::cli;
use conf::{RemoteBranch};
use conf::{Conf,get_configuration,create_default_config,Value};
use constants::*;

use std::collections::HashMap;

use git2::Repository;

// util mod def needs to be first b/c of macro definitions and usage in other modules
#[macro_use]
mod util;
mod backend;
mod cli;
mod conf;
mod constants;

fn format_value(value: Value, data: &str) -> String {
    format!("{}{}{}{}", value.pre_format, value.label, data, value.post_format)
}

fn substiute_special_values(s: String, values: &HashMap<String, String>) -> String {
    let mut r:String = s;
    for (k, v) in values {
        r = r.replace(k, &v);
    }
    r
}

// struct for displaying all the data -- the actual program
struct Program {
    out: Vec<String>,
    backend: Backend,
    conf: Conf,
    debug: bool
}

impl Program {
    pub fn new(backend: Backend, conf: Conf, debug: bool) -> Program {
        let out: Vec<String> = Vec::new();
        Program { out: out, backend: backend, conf: conf, debug: debug }
    }

    // add repository state to output buffer
    fn add_repository_state(&mut self) {
        let repo_state = self.backend.get_repository_state();
        if !repo_state.is_empty() {
            self.out.push(repo_state);
        }
    }

    fn add_monitored_branches_state(&mut self) {
        let mr = match self.conf.get_remotes_monitoring() {
            Some(x) => x,
            None => return (),
        };
        for monitored_remote in mr {
            let rb: Option<RemoteBranch> = monitored_remote.remote_branch;
            let a_b = match self.backend.get_branch_ahead_behind(rb.clone()) {
                Some(x) => x,
                None => {
                    log!(self, "no ahead behind stats found for = {:?}", rb);
                    continue
                },
            };
            let local_branch_name = match a_b.local_branch_name {
                Some(l) => l,
                None => {
                    log!(self, "No local branch name.");
                    "".to_string()
                }
            };
            if monitored_remote.display_if_uptodate || a_b.ahead > 0 || a_b.behind > 0 {
                if let (Some(a_v), Some(b_v)) = (
                    self.conf.get_difference_ahead_value(),
                    self.conf.get_difference_behind_value()
                ) {
                    let mut special_values: HashMap<String, String> = HashMap::new();
                    special_values.insert("<LOCAL_BRANCH>".to_string(), local_branch_name);
                    match a_b.remote_branch_name {
                        Some(v) => special_values.insert("<REMOTE_BRANCH>".to_string(), v),
                        None => special_values.insert("<REMOTE_BRANCH>".to_string(), "".to_string()),
                    };
                    match a_b.remote_name {
                        Some(v) => special_values.insert("<REMOTE>".to_string(), v),
                        None => special_values.insert("<REMOTE>".to_string(), "".to_string()),
                    };
                    let mut local: String = format!(
                        "{}{}",
                        substiute_special_values(monitored_remote.pre_format, &special_values),
                        substiute_special_values(monitored_remote.post_format, &special_values),
                    );
                    if a_b.ahead > 0 {
                        local += &format_value(a_v, &a_b.ahead.to_string());
                    }
                    if a_b.behind > 0 {
                        local += &format_value(b_v, &a_b.behind.to_string());
                    }
                    self.out.push(local);
                }
            }
        }
    }

    fn add_file_status(&mut self) {
        if let Some(s) = self.backend.get_file_status() {
            if !s.is_empty() {
                let mut o = String::from("");

                if let Some(x) = s.get(NEW_KEY) {
                    if let Some(y) = self.conf.get_new_value() {
                        o += &format!("{}{}{}{}", y.pre_format, y.label, x, y.post_format);
                    };
                }
                if let Some(x) = s.get(CHANGED_KEY) {
                    if let Some(y) = self.conf.get_changed_value() {
                        o += &format!("{}{}{}{}", y.pre_format, y.label, x, y.post_format);
                    };
                }
                if let Some(x) = s.get(STAGED_KEY) {
                    if let Some(y) = self.conf.get_staged_value() {
                        o += &format!("{}{}{}{}", y.pre_format, y.label, x, y.post_format);
                    };
                }
                if let Some(x) = s.get(CONFLICTS_KEY) {
                    if let Some(y) = self.conf.get_conflicts_value() {
                        o += &format!("{}{}{}{}", y.pre_format, y.label, x, y.post_format);
                    };
                }
                self.out.push(o);
            }
        }
    }

    fn populate(&mut self) {
        self.add_repository_state();
        self.add_monitored_branches_state();
        self.add_file_status();
    }

    // print output buffer
    fn output(&self) {
        log!(self, "# of blocks = {}", self.out.len());
        let output = self.out.join("|");
        if self.debug {
            println!("'{}'", output);
        } else {
            println!("{}", output);
        }
    }
}

fn main() {
    let app = cli();
    let matches = app.get_matches();

    let debug_enabled = matches.is_present("debug");
    if debug_enabled { println!("Debug messages are enabled."); }

    let repo = match Repository::discover(".") {
        Ok(repo) => repo,
        // not a git repository, ignore
        Err(e) => {
            if debug_enabled { println!("This is not a git repository: {:?}", e); }
            return ();
        }
    };

    let mut conf_path: Option<String> = None;
    if matches.is_present("config") {
        conf_path = Some(String::from(matches.value_of("config").unwrap()));
    }

    let conf = get_configuration(conf_path);

    if matches.is_present(CLI_DEFAULT_CONFIG_SUBC_NAME) {
        let p = get_default_config_path();
        match create_default_config(p.clone()) {
            Ok(path) => {
                println!("Configuration file created at \"{}\"", path);
                return ();
            }
            Err(e) => {
                println!("Failed to create configuration file \"{}\": {}", p.to_str().unwrap(), e);
                return ();
            }
        };
    }

    let backend = Backend::new(repo, debug_enabled);
    let mut output = Program::new(backend, conf, debug_enabled);

    output.populate();
    output.output();
}
<commit_msg>clippy: let _ = if {} else {}<commit_after>extern crate clap;
extern crate git2;
extern crate yaml_rust;

use backend::Backend;
use cli::cli;
use conf::{RemoteBranch};
use conf::{Conf,get_configuration,create_default_config,Value};
use constants::*;

use std::collections::HashMap;

use git2::Repository;

// util mod def needs to be first b/c of macro definitions and usage in other modules
#[macro_use]
mod util;
mod backend;
mod cli;
mod conf;
mod constants;

fn format_value(value: Value, data: &str) -> String {
    format!("{}{}{}{}", value.pre_format, value.label, data, value.post_format)
}

fn substiute_special_values(s: String, values: &HashMap<String, String>) -> String {
    let mut r:String = s;
    for (k, v) in values {
        r = r.replace(k, &v);
    }
    r
}

// struct for displaying all the data -- the actual program
struct Program {
    out: Vec<String>,
    backend: Backend,
    conf: Conf,
    debug: bool
}

impl Program {
    pub fn new(backend: Backend, conf: Conf, debug: bool) -> Program {
        let out: Vec<String> = Vec::new();
        Program { out: out, backend: backend, conf: conf, debug: debug }
    }

    // add repository state to output buffer
    fn add_repository_state(&mut self) {
        let repo_state = self.backend.get_repository_state();
        if !repo_state.is_empty() {
            self.out.push(repo_state);
        }
    }

    fn add_monitored_branches_state(&mut self) {
        let mr = match self.conf.get_remotes_monitoring() {
            Some(x) => x,
            None => return (),
        };
        for monitored_remote in mr {
            let rb: Option<RemoteBranch> = monitored_remote.remote_branch;
            let a_b = match self.backend.get_branch_ahead_behind(rb.clone()) {
                Some(x) => x,
                None => {
                    log!(self, "no ahead behind stats found for = {:?}", rb);
                    continue
                },
            };
            let local_branch_name = match a_b.local_branch_name {
                Some(l) => l,
                None => {
                    log!(self, "No local branch name.");
                    "".to_string()
                }
            };
            if monitored_remote.display_if_uptodate || a_b.ahead > 0 || a_b.behind > 0 {
                if let (Some(a_v), Some(b_v)) = (
                    self.conf.get_difference_ahead_value(),
                    self.conf.get_difference_behind_value()
                ) {
                    let mut special_values: HashMap<String, String> = HashMap::new();
                    special_values.insert("<LOCAL_BRANCH>".to_string(), local_branch_name);
                    match a_b.remote_branch_name {
                        Some(v) => special_values.insert("<REMOTE_BRANCH>".to_string(), v),
                        None => special_values.insert("<REMOTE_BRANCH>".to_string(), "".to_string()),
                    };
                    match a_b.remote_name {
                        Some(v) => special_values.insert("<REMOTE>".to_string(), v),
                        None => special_values.insert("<REMOTE>".to_string(), "".to_string()),
                    };
                    let mut local: String = format!(
                        "{}{}",
                        substiute_special_values(monitored_remote.pre_format, &special_values),
                        substiute_special_values(monitored_remote.post_format, &special_values),
                    );
                    if a_b.ahead > 0 {
                        local += &format_value(a_v, &a_b.ahead.to_string());
                    }
                    if a_b.behind > 0 {
                        local += &format_value(b_v, &a_b.behind.to_string());
                    }
                    self.out.push(local);
                }
            }
        }
    }

    fn add_file_status(&mut self) {
        if let Some(s) = self.backend.get_file_status() {
            if !s.is_empty() {
                let mut o = String::from("");

                if let Some(x) = s.get(NEW_KEY) {
                    if let Some(y) = self.conf.get_new_value() {
                        o += &format!("{}{}{}{}", y.pre_format, y.label, x, y.post_format);
                    };
                }
                if let Some(x) = s.get(CHANGED_KEY) {
                    if let Some(y) = self.conf.get_changed_value() {
                        o += &format!("{}{}{}{}", y.pre_format, y.label, x, y.post_format);
                    };
                }
                if let Some(x) = s.get(STAGED_KEY) {
                    if let Some(y) = self.conf.get_staged_value() {
                        o += &format!("{}{}{}{}", y.pre_format, y.label, x, y.post_format);
                    };
                }
                if let Some(x) = s.get(CONFLICTS_KEY) {
                    if let Some(y) = self.conf.get_conflicts_value() {
                        o += &format!("{}{}{}{}", y.pre_format, y.label, x, y.post_format);
                    };
                }
                self.out.push(o);
            }
        }
    }

    fn populate(&mut self) {
        self.add_repository_state();
        self.add_monitored_branches_state();
        self.add_file_status();
    }

    // print output buffer
    fn output(&self) {
        log!(self, "# of blocks = {}", self.out.len());
        let output = self.out.join("|");
        if self.debug {
            println!("'{}'", output);
        } else {
            println!("{}", output);
        }
    }
}

fn main() {
    let app = cli();
    let matches = app.get_matches();

    let debug_enabled = matches.is_present("debug");
    if debug_enabled { println!("Debug messages are enabled."); }

    let repo = match Repository::discover(".") {
        Ok(repo) => repo,
        // not a git repository, ignore
        Err(e) => {
            if debug_enabled { println!("This is not a git repository: {:?}", e); }
            return ();
        }
    };

    let conf_path: Option<String> = if matches.is_present("config") {
        Some(String::from(matches.value_of("config").unwrap()))
    } else {
        None
    };

    let conf = get_configuration(conf_path);

    if matches.is_present(CLI_DEFAULT_CONFIG_SUBC_NAME) {
        let p = get_default_config_path();
        match create_default_config(p.clone()) {
            Ok(path) => {
                println!("Configuration file created at \"{}\"", path);
                return ();
            }
            Err(e) => {
                println!("Failed to create configuration file \"{}\": {}", p.to_str().unwrap(), e);
                return ();
            }
        };
    }

    let backend = Backend::new(repo, debug_enabled);
    let mut output = Program::new(backend, conf, debug_enabled);

    output.populate();
    output.output();
}
<|endoftext|>


<commit_before>macro_rules! opt {
    ($opt:expr) => {
        match $opt {
            Some(item) => item,
            None => {
                return None;
            }
        }
    }
}

extern crate image;
extern crate imageproc;
extern crate rusttype;

use image::{DynamicImage, GenericImage, ImageFormat, Rgba};
use imageproc::drawing;
use rusttype::Scale;

#[cfg(windows)]
const DEFAULT_FONT: Option<&str> = Some("C:/Windows/Fonts/Impact.ttf");

#[cfg(macos)]
const DEFAULT_FONT: Option<&str> = Some("/Library/Fonts/Impact.ttf");

#[cfg(not(any(windows, macos)))]
const DEFAULT_FONT: Option<&str> = None;

fn main() {
    // I don't know what the last value in this array is.
    let white_pixel = Rgba([255, 255, 255, 0]);
    let black_pixel = Rgba([0, 255, 0, 0]);

    let (image_path, text) = match read_command() {
        Some(command) => command,
        None => {
            println!("Try `annatar <image path> <text>");
            std::process::exit(1);
        }
    };

    let mut pixels = match image::open(image_path) {
        Ok(pixels) => pixels,
        _ => {
            println!("Unable to open image file");
            std::process::exit(2);
        }
    };

    // Not sure what the &[u8] thing is for, but that was in the example on PistonDevelopers.
    // I'm guessing that's to prevent the font from blowing the stack frame if it's too large.
    // Furthermore, I'm stealing this font from the Mac Sierra shared font folder, so there is
    // exactly zero chance of this compiling on Windows right now.
    let font = read_font(DEFAULT_FONT);
    let height = pixels.height() as f32 / 10.0;

    // This scales the font size itself. Using the same multiplier for both just makes it bigger
    // as the multiplier increases. Making X larger makes the font wider, while making Y larger
    // makes the font taller.
    //
    // let scale = Scale { x: height, y: height };
    //
    // The above form is equivalent to what I'm currently using:
    let scale = Scale::uniform(height);

    // Apparently, `Scale` is copy.
    let (text_width, text_height) = text_size(&text, &font, scale);

    // Seems like the coordinates x and y designate the top left corner of the region being drawn.
    // In order to center this, I'm going to have to figure out how to determine the size of the
    // region being drawn.
    let (width, height) = pixels.dimensions();

    // What follows is a little fourth grade math that attempts to stick the text at the center
    // of the bottom fifth of the image.
    let x = (width / 2) - (text_width / 2);
    let y = height - ((height / 5) - (text_height / 2));

    let mut scratch = image::ImageBuffer::from_pixel(text_width, text_height, black_pixel);

    drawing::draw_text_mut(&mut scratch, white_pixel, 0, 0, scale, &font, &text);
    drawing::draw_text_mut(&mut pixels, white_pixel, x, y, scale, &font, &text);

    save("scratch.png", &DynamicImage::ImageRgba8(scratch));
    save("output.png", &pixels);
}

/// Calculate the dimensions of the bounding box for a given string, font, and scale.
///
/// This works by summing the "advance width" of each glyph in the text, entirely ignoring
/// kerning as each character is considered in isolation. Because this is used primarily to
/// center text in the image, it's close enough for government work.
fn text_size(s: &str, font: &[u8], scale: Scale) -> (u32, u32) {
    use rusttype::{FontCollection, VMetrics};

    // Font collections apparently consist of a collection of fonts. That is, more than one will
    // be defined in any given bag of bytes. Life's imperfect. The common case, however, is that
    // a given bag of bytes will contain a single font, in which case this will not explode.
    let font = FontCollection::from_bytes(font).into_font().expect("Font collection contains multiple fonts.");

    let text_width = font.glyphs_for(s.chars())
        .map(|glyph| glyph.scaled(scale).h_metrics().advance_width)
        .sum::<f32>();

    // The "v-metrics" for any given letter in a font are the same for a given scale, so we don't
    // need to check this for each glyph.
    let text_height = {
        let VMetrics { ascent, descent, ..} = font.v_metrics(scale);
        (ascent - descent) as u32
    };

    // I know I'm truncating the length and this is probably wrong, but it's not wrong by enough
    // to be noticeable when you print it to an image.
    (text_width as u32, text_height)
}

fn save(path: &str, pixels: &DynamicImage) {
    use std::fs::OpenOptions;

    let mut out = OpenOptions::new()
        .write(true)
        .create(true)
        .truncate(true)
        .open(path).unwrap();

    pixels.save(&mut out, ImageFormat::PNG).unwrap();
}

fn read_font(path: Option<&'static str>) -> Vec<u8> {
    use std::fs::File;
    use std::io::Read;

    let path = path.expect("Unsupported platform--please annoy the maintainer until this is fixed");
    let mut file = File::open(path).expect("Default font not found");
    let mut buf = Vec::new();

    file.read_to_end(&mut buf).expect("Unable to read file");
    buf
}

fn read_command() -> Option<(String, String)> {
    let mut args = std::env::args().skip(1);
    Some((
        opt!(args.next()),
        opt!(args.next()),
    ))
}
<commit_msg>Detect edges for border<commit_after>macro_rules! opt {
    ($opt:expr) => {
        match $opt {
            Some(item) => item,
            None => {
                return None;
            }
        }
    }
}

extern crate image;
extern crate imageproc;
extern crate rusttype;

use image::{DynamicImage, GenericImage, ImageFormat, Rgba};
use imageproc::drawing;
use rusttype::Scale;

#[cfg(windows)]
const DEFAULT_FONT: Option<&str> = Some("C:/Windows/Fonts/Impact.ttf");

#[cfg(macos)]
const DEFAULT_FONT: Option<&str> = Some("/Library/Fonts/Impact.ttf");

#[cfg(not(any(windows, macos)))]
const DEFAULT_FONT: Option<&str> = None;

fn main() {
    // The final value in the array here is the *opacity* of the pixel. Not the transparency.
    // Apparently, this is not CSS...
    let white_pixel = Rgba([255, 255, 255, 255]);
    let black_pixel = Rgba([0, 0, 0, 255]);

    let (image_path, text) = match read_command() {
        Some(command) => command,
        None => {
            println!("Try `annatar <image path> <text>");
            std::process::exit(1);
        }
    };

    let mut pixels = match image::open(image_path) {
        Ok(pixels) => pixels,
        _ => {
            println!("Unable to open image file");
            std::process::exit(2);
        }
    };

    // Not sure what the &[u8] thing is for, but that was in the example on PistonDevelopers.
    // I'm guessing that's to prevent the font from blowing the stack frame if it's too large.
    // Furthermore, I'm stealing this font from the Mac Sierra shared font folder, so there is
    // exactly zero chance of this compiling on Windows right now.
    let font = read_font(DEFAULT_FONT);
    let height = pixels.height() as f32 / 10.0;

    // This scales the font size itself. Using the same multiplier for both just makes it bigger
    // as the multiplier increases. Making X larger makes the font wider, while making Y larger
    // makes the font taller.
    //
    // let scale = Scale { x: height, y: height };
    //
    // The above form is equivalent to what I'm currently using:
    let scale = Scale::uniform(height);

    // Apparently, `Scale` is copy.
    let (text_width, text_height) = text_size(&text, &font, scale);

    // Seems like the coordinates x and y designate the top left corner of the region being drawn.
    // In order to center this, I'm going to have to figure out how to determine the size of the
    // region being drawn.
    let (width, height) = pixels.dimensions();

    // What follows is a little fourth grade math that attempts to stick the text at the center
    // of the bottom fifth of the image. This, by the way, is the closest I have ever come to
    // using anything I learned in Mrs. Vye's 9th grade keyboarding class. Thank God for the
    // IBM Selectric III, huh?
    let x = (width / 2) - (text_width / 2);
    let y = height - ((height / 5) - (text_height / 2));

    let mut scratch = image::ImageBuffer::from_fn(text_width, text_height, |_, _| black_pixel);

    drawing::draw_text_mut(&mut scratch, white_pixel, 0, 0, scale, &font, &text);
    drawing::draw_text_mut(&mut pixels, white_pixel, x, y, scale, &font, &text);

    // Here I set the "low threshold" and the "high threshold" for edge detection to 0.5 I have
    // not the first fucking clue what either of these thresholds is for or what sort of values
    // they might accept. I can only assume that even a drunk wallaby could detect these edges.
    let gray = imageproc::edges::canny(&image::imageops::grayscale(&scratch), 255.0, 255.0);

    save("edges.png", &DynamicImage::ImageLuma8(gray));
    save("scratch.png", &DynamicImage::ImageRgba8(scratch));
    save("output.png", &pixels);
}

/// Calculate the dimensions of the bounding box for a given string, font, and scale.
///
/// This works by summing the "advance width" of each glyph in the text, entirely ignoring
/// kerning as each character is considered in isolation. Because this is used primarily to
/// center text in the image, it's close enough for government work.
fn text_size(s: &str, font: &[u8], scale: Scale) -> (u32, u32) {
    use rusttype::{FontCollection, VMetrics};

    // Font collections apparently consist of a collection of fonts. That is, more than one will
    // be defined in any given bag of bytes. Life's imperfect. The common case, however, is that
    // a given bag of bytes will contain a single font, in which case this will not explode.
    let font = FontCollection::from_bytes(font).into_font().expect("Font collection contains multiple fonts.");

    let text_width = font.glyphs_for(s.chars())
        .map(|glyph| glyph.scaled(scale).h_metrics().advance_width)
        .sum::<f32>();

    // The "v-metrics" for any given letter in a font are the same for a given scale, so we don't
    // need to check this for each glyph.
    let text_height = {
        let VMetrics { ascent, descent, ..} = font.v_metrics(scale);
        (ascent - descent) as u32
    };

    // I know I'm truncating the length and this is probably wrong, but it's not wrong by enough
    // to be noticeable when you print it to an image.
    (text_width as u32, text_height)
}

fn save(path: &str, pixels: &DynamicImage) {
    use std::fs::OpenOptions;

    let mut out = OpenOptions::new()
        .write(true)
        .create(true)
        .truncate(true)
        .open(path).unwrap();

    pixels.save(&mut out, ImageFormat::PNG).unwrap();
}

fn read_font(path: Option<&'static str>) -> Vec<u8> {
    use std::fs::File;
    use std::io::Read;

    let path = path.expect("Unsupported platform--please annoy the maintainer until this is fixed");
    let mut file = File::open(path).expect("Default font not found");
    let mut buf = Vec::new();

    file.read_to_end(&mut buf).expect("Unable to read file");
    buf
}

fn read_command() -> Option<(String, String)> {
    let mut args = std::env::args().skip(1);
    Some((
        opt!(args.next()),
        opt!(args.next()),
    ))
}
<|endoftext|>


<commit_before>extern crate env_logger;
extern crate git2;
#[macro_use]
extern crate log;
extern crate tempdir;
extern crate url;
extern crate walkdir;

extern crate rig;

use std::env;
use std::ffi::OsStr;
use std::fs;

use git2::{Config as Git2Config, FetchOptions};
use git2::build::RepoBuilder;
use rig::fsutils;
use tempdir::TempDir;
use url::Url;
use walkdir::{DirEntry, WalkDir, WalkDirIterator};

fn find_proxy_url() -> Option<Url> {

    // environment variables are first priority
    if let Some(env_val) = env::var_os("http_proxy") {
        Url::parse(&env_val.to_string_lossy()).ok()
    } else {
        // if no env vars set, look for git global config
        if let Ok(global_conf) = Git2Config::find_global() {

            if let Ok(config) = Git2Config::open(global_conf.as_path()) {
                config.get_string("http.proxy").map(|v| Url::parse(&v).unwrap()).ok()
            } else {
                warn!("Cannot locate or open git global configuration");
                None
            }

        } else {
            None
        }
    }
}

fn is_git_metadata(entry: &DirEntry) -> bool {
    let is_git = entry.file_name().to_str().map(|s| s == ".git").unwrap_or(false);
    fsutils::is_directory(entry.path()) && is_git
}

fn main() {

    env_logger::init().unwrap();
    let dry_run = true;

    let clone_root = TempDir::new("__rig_template").expect("Failed to create temporal directory!");

    let mut output_dir = clone_root.path()
        .parent()
        .map(|p| p.to_path_buf())
        .expect("Failed to locate current directory!");
    output_dir.push("_test_out");

    if fsutils::exists(&output_dir) {
        fs::remove_dir_all(&output_dir).expect("Cannot overwrite existing output directory!");
    }
    fs::create_dir_all(&output_dir).unwrap();

    let url = Url::parse("https://github.com/n8han/giter8.g8").unwrap();
    let mut _in = String::new();

    let mut repo = RepoBuilder::new();
    if let Some(proxy_url) = find_proxy_url() {

        let mut proxy = git2::ProxyOptions::new();
        proxy.url(proxy_url.as_ref());

        let mut fetch = FetchOptions::new();
        fetch.proxy_options(proxy);

        repo.fetch_options(fetch);
    }

    info!("Cloning remote git repository: {:?} into {:?}",
          url,
          clone_root.path());
    let _ = repo.clone(url.as_ref(), &clone_root.path()).unwrap();

    let walker = WalkDir::new(&clone_root.path()).into_iter();
    for entry in walker.filter_entry(|e| !is_git_metadata(e)) {

        let entry = entry.unwrap();

        if entry.file_name() == clone_root.path().file_name().unwrap() {
            debug!("skipping {:?}", entry.file_name());
            continue;
        }

        let mut segment: Vec<&OsStr> = Vec::new();
        let mut rel_path_up = entry.path().parent();
        let mut upwards = 1;
        while let Some(parent) = rel_path_up {
            if upwards >= entry.depth() {
                break;
            } else {
                segment.push(parent.file_name().unwrap_or("".as_ref()));
            }
            upwards += 1;
            rel_path_up = parent.parent();
        }

        let mut dest = output_dir.clone();
        if !segment.is_empty() {
            segment.reverse();
            for part in segment {
                dest.push(part);
            }
        }
        dest.push(entry.file_name());
        debug!("{:?}", dest);

        if !dry_run {
            if entry.file_type().is_file() {
                fs::copy(&entry.path(), dest.as_path()).expect("Failed to copy file");
            } else if entry.file_type().is_dir() {
                fs::create_dir(dest.as_path()).expect("Failed to copy directory");
            }
        }
    }

    info!("done.");
}
<commit_msg>more logging<commit_after>extern crate env_logger;
extern crate git2;
#[macro_use]
extern crate log;
extern crate tempdir;
extern crate url;
extern crate walkdir;

extern crate rig;

use std::env;
use std::ffi::OsStr;
use std::fs;

use git2::{Config as Git2Config, FetchOptions};
use git2::build::RepoBuilder;
use rig::fsutils;
use tempdir::TempDir;
use url::Url;
use walkdir::{DirEntry, WalkDir, WalkDirIterator};

fn find_proxy_url() -> Option<Url> {

    // environment variables are first priority
    if let Some(env_val) = env::var_os("http_proxy") {
        debug!("Setting proxy configuration from environment key: `http_proxy`.");
        Url::parse(&env_val.to_string_lossy()).ok()
    } else {
        // if no env vars set, look for git global config
        if let Ok(global_conf) = Git2Config::find_global() {

            if let Ok(config) = Git2Config::open(global_conf.as_path()) {
                config.get_string("http.proxy").map(|v| Url::parse(&v).unwrap()).ok()
            } else {
                warn!("Cannot locate or open git global configuration");
                None
            }

        } else {
            None
        }
    }
}

fn is_git_metadata(entry: &DirEntry) -> bool {
    let is_git = entry.file_name().to_str().map(|s| s == ".git").unwrap_or(false);
    fsutils::is_directory(entry.path()) && is_git
}

fn main() {

    env_logger::init().unwrap();
    let dry_run = true;

    let clone_root = TempDir::new("rig__template").expect("Failed to create temporal directory!");

    let mut output_dir = clone_root.path()
        .parent()
        .map(|p| p.to_path_buf())
        .expect("Failed to locate current directory!");
    output_dir.push("_test_out");

    if fsutils::exists(&output_dir) {
        fs::remove_dir_all(&output_dir).expect("Cannot overwrite existing output directory!");
    }
    fs::create_dir_all(&output_dir).unwrap();

    let url = Url::parse("https://github.com/n8han/giter8.g8").unwrap();
    let mut _in = String::new();

    let mut repo = RepoBuilder::new();
    if let Some(proxy_url) = find_proxy_url() {

        debug!("Proxy settings found, initializing fetch options.");

        let mut proxy = git2::ProxyOptions::new();
        proxy.url(proxy_url.as_ref());

        let mut fetch = FetchOptions::new();
        fetch.proxy_options(proxy);

        repo.fetch_options(fetch);
    } else {
        debug!("No proxy settings found.")
    }

    info!("Cloning remote git repository: {:?} into {:?}",
          url,
          clone_root.path());
    let _ = repo.clone(url.as_ref(), &clone_root.path()).unwrap();

    let walker = WalkDir::new(&clone_root.path()).into_iter();
    for entry in walker.filter_entry(|e| !is_git_metadata(e)) {

        let entry = entry.unwrap();

        if entry.file_name() == clone_root.path().file_name().unwrap() {
            debug!("skipping {:?}", entry.file_name());
            continue;
        }

        let mut segment: Vec<&OsStr> = Vec::new();
        let mut rel_path_up = entry.path().parent();
        let mut upwards = 1;
        while let Some(parent) = rel_path_up {
            if upwards >= entry.depth() {
                break;
            } else {
                segment.push(parent.file_name().unwrap_or("".as_ref()));
            }
            upwards += 1;
            rel_path_up = parent.parent();
        }

        let mut dest = output_dir.clone();
        if !segment.is_empty() {
            segment.reverse();
            for part in segment {
                dest.push(part);
            }
        }
        dest.push(entry.file_name());
        debug!("{:?}", dest);

        if !dry_run {
            if entry.file_type().is_file() {
                fs::copy(&entry.path(), dest.as_path()).expect("Failed to copy file");
            } else if entry.file_type().is_dir() {
                fs::create_dir(dest.as_path()).expect("Failed to copy directory");
            }
        }
    }

    info!("done.");
}
<|endoftext|>


<commit_before>extern crate ansi_term;
extern crate argparse;
extern crate hyper;
extern crate libsnatch;

use ansi_term::Colour::{Green, Yellow, Red};
use argparse::{ArgumentParser, Store, StoreTrue};
use hyper::client::Client;
use libsnatch::Chunks;
use libsnatch::client::GetResponse;
use libsnatch::contentlength::GetContentLength;
use libsnatch::download::download_chunks;
use libsnatch::http_version::ValidateHttpVersion;
use libsnatch::write::write_file;
use std::fs::File;
use std::io;
use std::sync::{Arc, Mutex};
use std::path::Path;
use std::process::exit;

fn main() {

    let mut file = String::from("");
    let mut threads: usize = 4;
    let mut url = String::from("");
    let mut verbose = false;

    {
        let mut argparse = ArgumentParser::new();
        argparse.set_description("Snatch, a simple, fast and interruptable download accelerator, \
                                  written in Rust.");
        argparse.refer(&mut file)
            .add_option(&["-f", "--file"],
                        Store,
                        "The local file to save the remote content file")
            .required();
        argparse.refer(&mut threads)
            .add_option(&["-t", "--threads"],
                        Store,
                        "Number of threads available to download");
        argparse.refer(&mut url)
            .add_option(&["-u", "--url"], Store, "Remote content URL to download")
            .required();
        argparse.refer(&mut verbose)
            .add_option(&["-v", "--verbose"], StoreTrue, "Verbose mode");
        argparse.parse_args_or_exit();
    }

    let hyper_client = Client::new();

    // Get the first response from the server
    let client_response = hyper_client.get_http_response(&url).unwrap();

    print!("# Waiting a response from the remote server... ");

    if !client_response.version.greater_than_http_11() {
        println!("{}",
                 Yellow.bold()
                     .paint("OK (HTTP version <= 1.0 detected)"));
    } else {
        println!("{}", Green.bold().paint("OK !"));
    }

    let local_path = Path::new(&file);

    if local_path.exists() {
        if local_path.is_dir() {
            panic!(Red.bold()
                .paint("[ERROR] The local path to store the remote content is already exists, \
                        and is a directory!"));
        }
        println!("{}",
                 Red.bold()
                     .paint("[WARNING] The path to store the file already exists! Do you want \
                             to override it? [y/N]"));
        {
            let mut user_input = String::new();
            io::stdin()
                .read_line(&mut user_input)
                .ok()
                .expect("[ERROR] Couldn't read line!");
            user_input = String::from(user_input.trim());
            if !(user_input == "y" || user_input == "Y") {
                exit(0);
            }
        }
    }

    let remote_content_length = match client_response.headers.get_content_length() {
        Some(remote_content_length) => remote_content_length,
        None => {
            println!("{}",
                     Red.bold()
                         .paint("[ERROR] Canno't get the content length of the remote content, \
                                 from the server."));
            exit(1);
        }
    };

    println!("# Remote content length: {:?} bytes", remote_content_length);

    let mut core_chunks = Chunks::with_capacity(threads);

    for _ in 0..threads {
        core_chunks.push(Vec::new());
    }

    let mut shared_chunks = Arc::new(Mutex::new(core_chunks));

    download_chunks(remote_content_length,
                    &mut shared_chunks,
                    threads as u64,
                    &url);

    let mut local_file = File::create(local_path).expect("[ERROR] Canno't create a file !");

    match write_file(&mut local_file, &shared_chunks) {
        Ok(()) => println!("{}", Green.bold().paint("Chunks have been successfuly saved!")),
        Err(error) => println!("[ERROR] {}", error),
    }

}
<commit_msg>Change the way to get header informations<commit_after>extern crate ansi_term;
extern crate argparse;
extern crate hyper;
extern crate libsnatch;

use ansi_term::Colour::{Green, Yellow, Red};
use argparse::{ArgumentParser, Store, StoreTrue};
use hyper::client::Client;
use libsnatch::Chunks;
use libsnatch::client::GetResponse;
use libsnatch::contentlength::GetContentLength;
use libsnatch::download::download_chunks;
use libsnatch::http_version::ValidateHttpVersion;
use libsnatch::write::write_file;
use std::fs::File;
use std::io;
use std::sync::{Arc, Mutex};
use std::path::Path;
use std::process::exit;

fn main() {

    let mut file = String::from("");
    let mut threads: usize = 4;
    let mut url = String::from("");
    let mut verbose = false;

    {
        let mut argparse = ArgumentParser::new();
        argparse.set_description("Snatch, a simple, fast and interruptable download accelerator, \
                                  written in Rust.");
        argparse.refer(&mut file)
            .add_option(&["-f", "--file"],
                        Store,
                        "The local file to save the remote content file")
            .required();
        argparse.refer(&mut threads)
            .add_option(&["-t", "--threads"],
                        Store,
                        "Number of threads available to download");
        argparse.refer(&mut url)
            .add_option(&["-u", "--url"], Store, "Remote content URL to download")
            .required();
        argparse.refer(&mut verbose)
            .add_option(&["-v", "--verbose"], StoreTrue, "Verbose mode");
        argparse.parse_args_or_exit();
    }

    let hyper_client = Client::new();

    // Get the first response from the server
    let client_response = hyper_client.get_head_response(&url).unwrap();

    print!("# Waiting a response from the remote server... ");

    if !client_response.version.greater_than_http_11() {
        println!("{}",
                 Yellow.bold()
                     .paint("OK (HTTP version <= 1.0 detected)"));
    } else {
        println!("{}", Green.bold().paint("OK !"));
    }

    let local_path = Path::new(&file);

    if local_path.exists() {
        if local_path.is_dir() {
            panic!(Red.bold()
                .paint("[ERROR] The local path to store the remote content is already exists, \
                        and is a directory!"));
        }
        println!("{}",
                 Red.bold()
                     .paint("[WARNING] The path to store the file already exists! Do you want \
                             to override it? [y/N]"));
        {
            let mut user_input = String::new();
            io::stdin()
                .read_line(&mut user_input)
                .ok()
                .expect("[ERROR] Couldn't read line!");
            user_input = String::from(user_input.trim());
            if !(user_input == "y" || user_input == "Y") {
                exit(0);
            }
        }
    }

    let remote_content_length = match client_response.headers.get_content_length() {
        Some(remote_content_length) => remote_content_length,
        None => {
            println!("{}",
                     Red.bold()
                         .paint("[ERROR] Canno't get the content length of the remote content, \
                                 from the server."));
            exit(1);
        }
    };

    println!("# Remote content length: {:?} bytes", remote_content_length);

    let mut core_chunks = Chunks::with_capacity(threads);

    for _ in 0..threads {
        core_chunks.push(Vec::new());
    }

    let mut shared_chunks = Arc::new(Mutex::new(core_chunks));

    download_chunks(remote_content_length,
                    &mut shared_chunks,
                    threads as u64,
                    &url);

    let mut local_file = File::create(local_path).expect("[ERROR] Canno't create a file !");

    match write_file(&mut local_file, &shared_chunks) {
        Ok(()) => println!("{}", Green.bold().paint("Chunks have been successfuly saved!")),
        Err(error) => println!("[ERROR] {}", error),
    }

}
<|endoftext|>


<commit_before>extern crate curl;

fn main() {
    // let data = 2;
    let mut easy = curl::easy::Easy::new();
    // easy.debug_function(&mut |_, _| {});
    let _ = easy.perform();
}
<commit_msg>Remove erroneous src/main.rs<commit_after><|endoftext|>


<commit_before>extern crate hkg;
extern crate termion;
extern crate rustc_serialize;
extern crate kuchiki;
extern crate chrono;
extern crate hyper;
extern crate cancellation;
extern crate time;
extern crate url;

use std::path::Path;
use std::fs::File;
use std::fs;
use std::io::{stdout, stdin, Read, Write};
use std::thread;
use std::sync::mpsc::channel;
use std::sync::mpsc::Sender;
use cancellation::{CancellationToken, CancellationTokenSource, OperationCanceled};
use kuchiki::traits::*;
use rustc_serialize::json;
use termion::input::TermRead;
use termion::raw::IntoRawMode;
use termion::event::Key;
use hkg::status::*;
use hkg::model::IconItem;
use hkg::model::ListTopicItem;
use hkg::utility::client::*;
use hkg::state_manager::*;
use hkg::screen_manager::*;
use hkg::resources::common::*;
use hkg::caches::common::*;
use hkg::caches::file_cache::*;

fn main() {

    // Initialize
    let stdout = stdout();
    let mut stdout = stdout.lock().into_raw_mode().unwrap();

    // Clear the screen.
    hkg::screen::common::clear_screen();

    let mut builder = hkg::builder::Builder::new();

    let mut state_manager = StateManager::new();
    let mut screen_manager = ScreenManager::new();

    let icon_manifest_string = hkg::utility::readfile(String::from("data/icon.manifest.json"));
    let icon_collection: Box<Vec<IconItem>> = Box::new(json::decode(&icon_manifest_string).unwrap());

    // initialize empty page
    let mut list_topic_items: Vec<ListTopicItem> = vec![];
    let mut show_item = builder.default_show_item();

    let mut status_bar = hkg::screen::status_bar::StatusBar::new();
    let mut index = hkg::screen::index::Index::new();
    let mut show = hkg::screen::show::Show::new(icon_collection);

    let (tx_req, rx_req) = channel::<ChannelItem>();
    let (tx_res, rx_res) = channel::<ChannelItem>();

    // web client
    thread::spawn(move || {
        let mut wr = WebResource::new();
        let ct = CancellationTokenSource::new();
        ct.cancel_after(std::time::Duration::new(10, 0));
        let mut fc = Box::new(FileCache::new());
        let mut index_resource = hkg::resources::index_resource::IndexResource::new(&mut wr, &ct, &mut fc);
        loop {
            match rx_req.recv() {
                Ok(item) => {

                    let th = thread::current();
                    ct.run(|| {
                               th.unpark();
                           },
                           || {
                                tx_res.send(index_resource.fetch(&item)).unwrap();
                            //    tx_res.send(page_request(&item, &mut wr, &ct)).unwrap();
                           });

                    if ct.is_canceled() {
                        thread::park_timeout(std::time::Duration::new(0, 250));
                        // Err(OperationCanceled)
                    } else {
                        // Ok(())
                    }
                }
                Err(_) => {}
            }
        }
    });

    // topics request
    let status_message = list_page(&mut state_manager, &tx_req);
    status_bar.append(&screen_manager, &status_message);

    loop {

        match rx_res.try_recv() {
            Ok(item) => {
                match item.extra {
                    ChannelItemType::Show(extra) => {
                        let document = kuchiki::parse_html().from_utf8().one(item.result.as_bytes());

                        let posturl = get_posturl(&extra.postid, extra.page);
                        show_item = builder.show_item(&document, &posturl);

                        status_bar.append(&screen_manager, &format!("[{}-{}:ROK][{}]",
                                 show_item.url_query.message,
                                 show_item.page,
                                 state_manager.isWebRequest()));

                        show.resetY();
                        hkg::screen::common::clear_screen();
                        state_manager.updateState(Status::Show); //state = Status::Show;
                        state_manager.setWebRequest(false); // is_web_requesting = false;
                    },
                    ChannelItemType::Index(_) => {
                        let document = kuchiki::parse_html().from_utf8().one(item.result.as_bytes());

                        list_topic_items = builder.list_topic_items(&document);

                        status_bar.append(&screen_manager,
                                               &format!("[TOPICS:ROK]"));

                        hkg::screen::common::clear_screen();

                        state_manager.updateState(Status::List); // state = Status::List;
                        state_manager.setWebRequest(false); // is_web_requesting = false;

                    }
                }
            }
            Err(_) => {}
        }

        match state_manager.getState() {
            Status::Startup => {

            },
            Status::List => {
                index.print(&mut stdout, &list_topic_items);
            }
            Status::Show => {
                show.print(&mut stdout, &show_item);
            }
        }

        status_bar.print(&screen_manager);

        stdout.flush().unwrap();

        if !state_manager.isWebRequest() {

            let stdin = stdin();

            for c in stdin.keys() {

                if screen_manager.isWidthChanged() {
                    hkg::screen::common::clear_screen();
                }

                match state_manager.getState() {
                    Status::Startup => {},
                    Status::List => {
                        match c.unwrap() {
                            Key::Char('q') => {
                                hkg::screen::common::reset_screen();
                                return
                            },
                            Key::Char('\n') => {
                                status_bar.append(&screen_manager, "ENTER");
                                let i = index.get_selected_topic();
                                if i > 0 {
                                    let topic_item = &list_topic_items[i - 1];
                                    let postid = &topic_item.title.url_query.message;
                                    let page = 1;
                                    let status_message = show_page(&postid, page, &mut state_manager, &tx_req);

                                    status_bar.append(&screen_manager,
                                                           &get_show_page_status_message(postid, page, &status_message));
                                }
                                break
                            },
                            Key::PageUp => {
                                status_bar.append(&screen_manager, "↑");
                                let tmp = index.get_selected_topic();
                                status_bar.append(&screen_manager, &format!("{}", tmp));

                                if tmp > 1 {
                                    index.select_topic(tmp - 1);
                                }
                                break
                            },
                            Key::Up => {
                                status_bar.append(&screen_manager, "↑");
                                let tmp = index.get_selected_topic();
                                status_bar.append(&screen_manager, &format!("{}", tmp));

                                if tmp > 1 {
                                    index.select_topic(tmp - 1);
                                }
                                break
                            },
                            Key::Down => {
                                status_bar.append(&screen_manager, "↓");
                                let tmp = index.get_selected_topic();
                                status_bar.append(&screen_manager, &format!("{}", tmp));

                                if tmp < index.body_height() {
                                    index.select_topic(tmp + 1);
                                }
                                break
                            },
                            _ => {},
                        }
                    },
                    Status::Show => {
                            match c.unwrap() {
                                Key::Char('q') => {
                                    hkg::screen::common::reset_screen(); // print!("{}{}{}", termion::clear::All, style::Reset, termion::cursor::Show);
                                    return
                                },
                                Key::Left => {
                                    status_bar.append(&screen_manager, &format!("←"));
                                    if show_item.page > 1 {
                                        let postid = &show_item.url_query.message;
                                        let page = &show_item.page - 1;
                                        let status_message = show_page(&postid, page, &mut state_manager, &tx_req);

                                        status_bar.append(&screen_manager,
                                                               &get_show_page_status_message(postid, page, &status_message));
                                    }
                                    break
                                }
                                Key::Right => {
                                    status_bar.append(&screen_manager, &format!("→"));
                                    if show_item.max_page > show_item.page {
                                        let postid = &show_item.url_query.message;
                                        let page = &show_item.page + 1;
                                        let status_message = show_page(&postid, page, &mut state_manager, &tx_req);

                                        status_bar.append(&screen_manager,
                                                               &get_show_page_status_message(postid, page, &status_message));
                                    }
                                    break
                                },
                                Key::PageUp => {
                                    status_bar.append(&screen_manager, "↑");
                                    let bh = show.body_height();
                                    if show.scrollUp(bh) {
                                    hkg::screen::common::clear_screen();
                                    }
                                    break
                                },
                                Key::PageDown => {
                                    status_bar.append(&screen_manager, "↓");
                                    let bh = show.body_height();
                                    if show.scrollDown(bh) {
                                        hkg::screen::common::clear_screen();
                                    }
                                    break
                                },
                                Key::Up => {
                                    status_bar.append(&screen_manager, "↑");
                                    if show.scrollUp(2) {
                                        hkg::screen::common::clear_screen();
                                    }
                                    break
                                },
                                Key::Down => {
                                    status_bar.append(&screen_manager, "↓");
                                    if show.scrollDown(2) {
                                        hkg::screen::common::clear_screen();
                                    }
                                    break
                                },
                                Key::Backspace => {
                                    status_bar.append(&screen_manager, "B");
                                    state_manager.updateState(Status::List); // state = Status::List;
                                    hkg::screen::common::clear_screen();
                                    break
                                },
                                _ => {},
                            }
                        }
                }

            }
        }

    }
}

fn read_cache<P: AsRef<Path>, S: AsRef<Path>>(cache_path: P,
                                              file_name: S)
                                              -> Result<String, String> {
    let file_path = cache_path.as_ref().join(file_name);
    let mut file = try!(File::open(file_path).map_err(|e| e.to_string()));
    let mut contents = String::new();
    try!(file.read_to_string(&mut contents).map_err(|e| e.to_string()));
    Ok(contents)
}

fn write_cache<P: AsRef<Path>, S: AsRef<Path>>(cache_path: P,
                                               file_name: S,
                                               s: String)
                                               -> Result<(), String> {
    let file_path = cache_path.as_ref().join(file_name);
    try!(fs::create_dir_all(&cache_path).map_err(|e| e.to_string()));
    let mut file = try!(File::create(file_path).map_err(|e| e.to_string()));
    try!(file.write_all(&s.into_bytes()).map_err(|e| e.to_string()));
    Ok(())
}

fn get_posturl(postid: &String, page: usize) -> String {
    let base_url = "http://forum1.hkgolden.com/view.aspx";
    let posturl = format!("{base_url}?type=BW&message={postid}&page={page}",
                          base_url = base_url,
                          postid = postid,
                          page = page);
    posturl
}

fn get_topic_bw_url() -> String {
    let base_url = "http://forum1.hkgolden.com";
    let url = format!("{base_url}/topics_bw.htm", base_url = base_url);
    url
}

fn page_request(item: &ChannelItem,
                wr: &mut WebResource,
                ct: &CancellationTokenSource)
                -> ChannelItem {

    match item.extra.clone() {
        ChannelItemType::Show(extra) => {
            let html_path = format!("data/html/{postid}/", postid = extra.postid);
            let show_file_name = format!("show_{page}.html", page = extra.page);

            let postid = extra.postid.clone();

            let (from_cache, result) = match read_cache(&html_path, &show_file_name) {
                Ok(result) => (true, result),
                Err(_) => {
                    let posturl = get_posturl(&extra.postid, extra.page);
                    let result = wr.get(&posturl);
                    (false, result)
                }
            };

            if !from_cache {
                let result2 = result.clone();
                write_cache(&html_path, &show_file_name, result2);
            }

            let result_item = ChannelItem {
                extra: ChannelItemType::Show(ChannelShowItem { postid: postid, page: extra.page }),
                result: result,
            };
            result_item
        },
        ChannelItemType::Index(_) => {

            let time_format = |t: time::Tm| {
                match t.strftime("%Y%m%d%H%M") {
                    Ok(s) => s.to_string(),
                    Err(e) => panic!(e)
                }
            };

            let time = time_format(time::now());

            let html_path = format!("data/html/topics/");
            let file_name = format!("{time}.html", time = time);

            let (from_cache, result) = match read_cache(&html_path, &file_name) {
                Ok(result) => (true, result),
                Err(_) => {
                    let url = get_topic_bw_url();
                    let result = wr.get(&url);
                    (false, result)
                }
            };

            if !from_cache {
                let result2 = result.clone();
                write_cache(&html_path, &file_name, result2);
            }

            let result_item = ChannelItem {
                extra: ChannelItemType::Index(ChannelIndexItem { }),
                result: result,
            };
            result_item
        }
    }

}

fn list_page(state_manager: &mut StateManager, tx_req: &Sender<ChannelItem>) -> String {

    let ci = ChannelItem {
        extra: ChannelItemType::Index(ChannelIndexItem { }),
        result: String::from(""),
    };

    let status_message = match tx_req.send(ci) {
        Ok(()) => {
            state_manager.setWebRequest(true);    // *is_web_requesting = true;
            "SOK".to_string()
        }
        Err(e) => format!("{}:{}", "SFAIL", e).to_string(),
    };

    status_message
}

fn show_page(postid: &String, page: usize, state_manager: &mut StateManager, tx_req: &Sender<ChannelItem>) -> String {

    let ci = ChannelItem {
        extra: ChannelItemType::Show(ChannelShowItem { postid: postid.clone(), page: page }),
        result: String::from(""),
    };

    let status_message = match tx_req.send(ci) {
        Ok(()) => {
            state_manager.setWebRequest(true); // *is_web_requesting = true;
            "SOK".to_string()
        }
        Err(e) => format!("{}:{}", "SFAIL", e).to_string(),
    };

    status_message
}

fn get_show_page_status_message(postid: &String, page: usize, status_message: &String) -> String {
    format!("[{}-{}:{}]", postid, page, status_message)
}
<commit_msg>wclient - conditionally call index/show resource#fetch<commit_after>extern crate hkg;
extern crate termion;
extern crate rustc_serialize;
extern crate kuchiki;
extern crate chrono;
extern crate hyper;
extern crate cancellation;
extern crate time;
extern crate url;

use std::path::Path;
use std::fs::File;
use std::fs;
use std::io::{stdout, stdin, Read, Write};
use std::thread;
use std::sync::mpsc::channel;
use std::sync::mpsc::Sender;
use cancellation::{CancellationToken, CancellationTokenSource, OperationCanceled};
use kuchiki::traits::*;
use rustc_serialize::json;
use termion::input::TermRead;
use termion::raw::IntoRawMode;
use termion::event::Key;
use hkg::status::*;
use hkg::model::IconItem;
use hkg::model::ListTopicItem;
use hkg::utility::client::*;
use hkg::state_manager::*;
use hkg::screen_manager::*;
use hkg::resources::common::*;
use hkg::caches::common::*;
use hkg::caches::file_cache::*;

fn main() {

    // Initialize
    let stdout = stdout();
    let mut stdout = stdout.lock().into_raw_mode().unwrap();

    // Clear the screen.
    hkg::screen::common::clear_screen();

    let mut builder = hkg::builder::Builder::new();

    let mut state_manager = StateManager::new();
    let mut screen_manager = ScreenManager::new();

    let icon_manifest_string = hkg::utility::readfile(String::from("data/icon.manifest.json"));
    let icon_collection: Box<Vec<IconItem>> = Box::new(json::decode(&icon_manifest_string).unwrap());

    // initialize empty page
    let mut list_topic_items: Vec<ListTopicItem> = vec![];
    let mut show_item = builder.default_show_item();

    let mut status_bar = hkg::screen::status_bar::StatusBar::new();
    let mut index = hkg::screen::index::Index::new();
    let mut show = hkg::screen::show::Show::new(icon_collection);

    let (tx_req, rx_req) = channel::<ChannelItem>();
    let (tx_res, rx_res) = channel::<ChannelItem>();

    // web client
    thread::spawn(move || {
        let mut wr = WebResource::new();
        let ct = CancellationTokenSource::new();
        ct.cancel_after(std::time::Duration::new(10, 0));
        let mut fc = Box::new(FileCache::new());

        loop {
            match rx_req.recv() {
                Ok(item) => {

                    let th = thread::current();
                    ct.run(|| {
                               th.unpark();
                           },
                           || {
                                match item.extra.clone() {
                                    ChannelItemType::Index(_) => {
                                        let mut index_resource = hkg::resources::index_resource::IndexResource::new(&mut wr, &ct, &mut fc);
                                        tx_res.send(index_resource.fetch(&item)).unwrap();
                                    },
                                    ChannelItemType::Show(_) => {
                                        let mut show_resource = hkg::resources::show_resource::ShowResource::new(&mut wr, &ct, &mut fc);
                                        tx_res.send(show_resource.fetch(&item)).unwrap();
                                    }
                                }
                           });

                    if ct.is_canceled() {
                        thread::park_timeout(std::time::Duration::new(0, 250));
                        // Err(OperationCanceled)
                    } else {
                        // Ok(())
                    }
                }
                Err(_) => {}
            }
        }
    });

    // topics request
    let status_message = list_page(&mut state_manager, &tx_req);
    status_bar.append(&screen_manager, &status_message);

    loop {

        match rx_res.try_recv() {
            Ok(item) => {
                match item.extra {
                    ChannelItemType::Show(extra) => {
                        let document = kuchiki::parse_html().from_utf8().one(item.result.as_bytes());

                        let posturl = get_posturl(&extra.postid, extra.page);
                        show_item = builder.show_item(&document, &posturl);

                        status_bar.append(&screen_manager, &format!("[{}-{}:ROK][{}]",
                                 show_item.url_query.message,
                                 show_item.page,
                                 state_manager.isWebRequest()));

                        show.resetY();
                        hkg::screen::common::clear_screen();
                        state_manager.updateState(Status::Show); //state = Status::Show;
                        state_manager.setWebRequest(false); // is_web_requesting = false;
                    },
                    ChannelItemType::Index(_) => {
                        let document = kuchiki::parse_html().from_utf8().one(item.result.as_bytes());

                        list_topic_items = builder.list_topic_items(&document);

                        status_bar.append(&screen_manager,
                                               &format!("[TOPICS:ROK]"));

                        hkg::screen::common::clear_screen();

                        state_manager.updateState(Status::List); // state = Status::List;
                        state_manager.setWebRequest(false); // is_web_requesting = false;

                    }
                }
            }
            Err(_) => {}
        }

        match state_manager.getState() {
            Status::Startup => {

            },
            Status::List => {
                index.print(&mut stdout, &list_topic_items);
            }
            Status::Show => {
                show.print(&mut stdout, &show_item);
            }
        }

        status_bar.print(&screen_manager);

        stdout.flush().unwrap();

        if !state_manager.isWebRequest() {

            let stdin = stdin();

            for c in stdin.keys() {

                if screen_manager.isWidthChanged() {
                    hkg::screen::common::clear_screen();
                }

                match state_manager.getState() {
                    Status::Startup => {},
                    Status::List => {
                        match c.unwrap() {
                            Key::Char('q') => {
                                hkg::screen::common::reset_screen();
                                return
                            },
                            Key::Char('\n') => {
                                status_bar.append(&screen_manager, "ENTER");
                                let i = index.get_selected_topic();
                                if i > 0 {
                                    let topic_item = &list_topic_items[i - 1];
                                    let postid = &topic_item.title.url_query.message;
                                    let page = 1;
                                    let status_message = show_page(&postid, page, &mut state_manager, &tx_req);

                                    status_bar.append(&screen_manager,
                                                           &get_show_page_status_message(postid, page, &status_message));
                                }
                                break
                            },
                            Key::PageUp => {
                                status_bar.append(&screen_manager, "↑");
                                let tmp = index.get_selected_topic();
                                status_bar.append(&screen_manager, &format!("{}", tmp));

                                if tmp > 1 {
                                    index.select_topic(tmp - 1);
                                }
                                break
                            },
                            Key::Up => {
                                status_bar.append(&screen_manager, "↑");
                                let tmp = index.get_selected_topic();
                                status_bar.append(&screen_manager, &format!("{}", tmp));

                                if tmp > 1 {
                                    index.select_topic(tmp - 1);
                                }
                                break
                            },
                            Key::Down => {
                                status_bar.append(&screen_manager, "↓");
                                let tmp = index.get_selected_topic();
                                status_bar.append(&screen_manager, &format!("{}", tmp));

                                if tmp < index.body_height() {
                                    index.select_topic(tmp + 1);
                                }
                                break
                            },
                            _ => {},
                        }
                    },
                    Status::Show => {
                            match c.unwrap() {
                                Key::Char('q') => {
                                    hkg::screen::common::reset_screen(); // print!("{}{}{}", termion::clear::All, style::Reset, termion::cursor::Show);
                                    return
                                },
                                Key::Left => {
                                    status_bar.append(&screen_manager, &format!("←"));
                                    if show_item.page > 1 {
                                        let postid = &show_item.url_query.message;
                                        let page = &show_item.page - 1;
                                        let status_message = show_page(&postid, page, &mut state_manager, &tx_req);

                                        status_bar.append(&screen_manager,
                                                               &get_show_page_status_message(postid, page, &status_message));
                                    }
                                    break
                                }
                                Key::Right => {
                                    status_bar.append(&screen_manager, &format!("→"));
                                    if show_item.max_page > show_item.page {
                                        let postid = &show_item.url_query.message;
                                        let page = &show_item.page + 1;
                                        let status_message = show_page(&postid, page, &mut state_manager, &tx_req);

                                        status_bar.append(&screen_manager,
                                                               &get_show_page_status_message(postid, page, &status_message));
                                    }
                                    break
                                },
                                Key::PageUp => {
                                    status_bar.append(&screen_manager, "↑");
                                    let bh = show.body_height();
                                    if show.scrollUp(bh) {
                                    hkg::screen::common::clear_screen();
                                    }
                                    break
                                },
                                Key::PageDown => {
                                    status_bar.append(&screen_manager, "↓");
                                    let bh = show.body_height();
                                    if show.scrollDown(bh) {
                                        hkg::screen::common::clear_screen();
                                    }
                                    break
                                },
                                Key::Up => {
                                    status_bar.append(&screen_manager, "↑");
                                    if show.scrollUp(2) {
                                        hkg::screen::common::clear_screen();
                                    }
                                    break
                                },
                                Key::Down => {
                                    status_bar.append(&screen_manager, "↓");
                                    if show.scrollDown(2) {
                                        hkg::screen::common::clear_screen();
                                    }
                                    break
                                },
                                Key::Backspace => {
                                    status_bar.append(&screen_manager, "B");
                                    state_manager.updateState(Status::List); // state = Status::List;
                                    hkg::screen::common::clear_screen();
                                    break
                                },
                                _ => {},
                            }
                        }
                }

            }
        }

    }
}

fn read_cache<P: AsRef<Path>, S: AsRef<Path>>(cache_path: P,
                                              file_name: S)
                                              -> Result<String, String> {
    let file_path = cache_path.as_ref().join(file_name);
    let mut file = try!(File::open(file_path).map_err(|e| e.to_string()));
    let mut contents = String::new();
    try!(file.read_to_string(&mut contents).map_err(|e| e.to_string()));
    Ok(contents)
}

fn write_cache<P: AsRef<Path>, S: AsRef<Path>>(cache_path: P,
                                               file_name: S,
                                               s: String)
                                               -> Result<(), String> {
    let file_path = cache_path.as_ref().join(file_name);
    try!(fs::create_dir_all(&cache_path).map_err(|e| e.to_string()));
    let mut file = try!(File::create(file_path).map_err(|e| e.to_string()));
    try!(file.write_all(&s.into_bytes()).map_err(|e| e.to_string()));
    Ok(())
}

fn get_posturl(postid: &String, page: usize) -> String {
    let base_url = "http://forum1.hkgolden.com/view.aspx";
    let posturl = format!("{base_url}?type=BW&message={postid}&page={page}",
                          base_url = base_url,
                          postid = postid,
                          page = page);
    posturl
}

fn get_topic_bw_url() -> String {
    let base_url = "http://forum1.hkgolden.com";
    let url = format!("{base_url}/topics_bw.htm", base_url = base_url);
    url
}

fn page_request(item: &ChannelItem,
                wr: &mut WebResource,
                ct: &CancellationTokenSource)
                -> ChannelItem {

    match item.extra.clone() {
        ChannelItemType::Show(extra) => {
            let html_path = format!("data/html/{postid}/", postid = extra.postid);
            let show_file_name = format!("show_{page}.html", page = extra.page);

            let postid = extra.postid.clone();

            let (from_cache, result) = match read_cache(&html_path, &show_file_name) {
                Ok(result) => (true, result),
                Err(_) => {
                    let posturl = get_posturl(&extra.postid, extra.page);
                    let result = wr.get(&posturl);
                    (false, result)
                }
            };

            if !from_cache {
                let result2 = result.clone();
                write_cache(&html_path, &show_file_name, result2);
            }

            let result_item = ChannelItem {
                extra: ChannelItemType::Show(ChannelShowItem { postid: postid, page: extra.page }),
                result: result,
            };
            result_item
        },
        ChannelItemType::Index(_) => {

            let time_format = |t: time::Tm| {
                match t.strftime("%Y%m%d%H%M") {
                    Ok(s) => s.to_string(),
                    Err(e) => panic!(e)
                }
            };

            let time = time_format(time::now());

            let html_path = format!("data/html/topics/");
            let file_name = format!("{time}.html", time = time);

            let (from_cache, result) = match read_cache(&html_path, &file_name) {
                Ok(result) => (true, result),
                Err(_) => {
                    let url = get_topic_bw_url();
                    let result = wr.get(&url);
                    (false, result)
                }
            };

            if !from_cache {
                let result2 = result.clone();
                write_cache(&html_path, &file_name, result2);
            }

            let result_item = ChannelItem {
                extra: ChannelItemType::Index(ChannelIndexItem { }),
                result: result,
            };
            result_item
        }
    }

}

fn list_page(state_manager: &mut StateManager, tx_req: &Sender<ChannelItem>) -> String {

    let ci = ChannelItem {
        extra: ChannelItemType::Index(ChannelIndexItem { }),
        result: String::from(""),
    };

    let status_message = match tx_req.send(ci) {
        Ok(()) => {
            state_manager.setWebRequest(true);    // *is_web_requesting = true;
            "SOK".to_string()
        }
        Err(e) => format!("{}:{}", "SFAIL", e).to_string(),
    };

    status_message
}

fn show_page(postid: &String, page: usize, state_manager: &mut StateManager, tx_req: &Sender<ChannelItem>) -> String {

    let ci = ChannelItem {
        extra: ChannelItemType::Show(ChannelShowItem { postid: postid.clone(), page: page }),
        result: String::from(""),
    };

    let status_message = match tx_req.send(ci) {
        Ok(()) => {
            state_manager.setWebRequest(true); // *is_web_requesting = true;
            "SOK".to_string()
        }
        Err(e) => format!("{}:{}", "SFAIL", e).to_string(),
    };

    status_message
}

fn get_show_page_status_message(postid: &String, page: usize, status_message: &String) -> String {
    format!("[{}-{}:{}]", postid, page, status_message)
}
<|endoftext|>


<commit_before>
#![feature(macro_rules)]

use std::collections::HashMap;
use std::comm::{Receiver, Sender};
use std::io::{Acceptor, BufferedReader, BufWriter, Listener, MemReader, MemWriter, TcpListener, TcpStream};
use std::io::stdin;
use std::rand::random;

type Id = u32;
type NullResult<T> = Result<T, ()>;
type Packet = Vec<u8>;

enum Message {
    RemovePlayer(Id),
    HandlePacket(Id, Packet),
    AddPlayer(TcpStream),
}

struct Player {
    id: Id,
    tcp: TcpStream,
    name: String,
    send: Sender<Packet>,
}

struct Server {
    players: HashMap<Id, Player>,
    send: Sender<Message>,
    recv: Receiver<Message>,
}

fn main() {
    println!("NoLifePony Server");
    let mut server = Server::new();
    server.run();
    println!("Shutting down");
}

fn new_packet() -> MemWriter {
    let mut buf = MemWriter::new();
    buf.write([0, 0, 0, 0]).unwrap();
    buf
}

fn packet_sender(recv: Receiver<Packet>, mut tcp: TcpStream) {
    for mut msg in recv.iter() {
        println!("Got packet to send!");
        let len = msg.len() as u32 - 4;
        {
            let mut buf = BufWriter::new(msg.mut_slice_to(4));
            buf.write_be_u32(len).unwrap();
        }
        let msg = msg;
        tcp.write(msg.as_slice()).unwrap();
    }
}

fn packet_receiver(send: Sender<Message>, tcp: TcpStream, id: Id) {
    struct Packets {
        buf: BufferedReader<TcpStream>,
    }
    impl Iterator<Packet> for Packets {
        fn next(&mut self) -> Option<Packet> {
            self.buf.read_be_u32().and_then(|len| self.buf.read_exact(len as uint)).ok()
        }
    }
    let mut packets = Packets {
        buf: BufferedReader::new(tcp),
    };
    for packet in packets {
        send.send(HandlePacket(id, packet));
    }
    send.send(RemovePlayer(id));
}

fn listener(send: Sender<Message>) {
    let listen = TcpListener::bind("0.0.0.0", 273);
    let mut accept = listen.listen();
    for stream in accept.incoming() {
        match stream {
            Ok(stream) => send.send(AddPlayer(stream)),
            Err(_) => return,
        }
    }
}

fn commands(_: Sender<Message>) {
    let mut cin = stdin();
    for line in cin.lines() {
        let line = line.unwrap();
        let line: String = line.as_slice().chars().map(|c| c.to_lowercase())
            .filter(|c| *c != '\n' && *c != '\r').collect();
        match line.as_slice() {
            _ => println!("Unknown command"),
        }
    }
}

impl Player {
    fn default_name(id: Id) -> String {
        format!("Pony{:08X}", id)
    }
    fn new(id: Id, mut tcp: TcpStream, send: Sender<Message>) -> Player {
        let tcp2 = tcp.clone();
        spawn(proc() packet_receiver(send, tcp2, id));
        let (send, recv) = channel::<Packet>();
        let tcp2 = tcp.clone();
        spawn(proc() packet_sender(recv, tcp2));
        let name = Player::default_name(id);
        match tcp.peer_name() {
            Ok(ip) => println!("{} connected from {}", name, ip),
            Err(_) => println!("{} connected from unknown", name),
        }
        Player {
            id: id,
            tcp: tcp,
            name: name,
            send: send,
        }
    }
}

impl Server {
    fn new() -> Server {
        let (send, recv) = channel::<Message>();
        let send2 = send.clone();
        spawn(proc() listener(send2));
        let send2 = send.clone();
        spawn(proc() commands(send2));
        Server {
            players: HashMap::new(),
            send: send,
            recv: recv,
        }
    }
    fn gen_id(&self) -> Id {
        loop {
            let id = random();
            if self.players.find(&id).is_none() { return id }
        }
    }
    fn add_player(&mut self, tcp: TcpStream) {
        let id = self.gen_id();
        let player = Player::new(id, tcp, self.send.clone());
        self.players.insert(player.id, player);
    }
    fn remove_player(&mut self, id: Id) {
        let mut player = match self.players.pop(&id) {
            Some(player) => player,
            None => return,
        };
        println!("{} disconnected", player.name);
        player.tcp.close_read().unwrap();
        player.tcp.close_write().unwrap();
    }
    fn handle_packet(&mut self, id: Id, packet: Packet) {
        let player = match self.players.find_mut(&id) {
            Some(player) => player,
            None => { println!("Packet from non-existant player: {}", id); return },
        };
        let mut packet = MemReader::new(packet);
        let opcode = match packet.read_be_u16() {
            Ok(opcode) => opcode,
            Err(_) => { println!("Failed to read opcode from player: {}", id); return },
        };
        match opcode {
            _ => println!("Unknown opcode {} from {}", opcode, player.name),
        }
    }
    fn run(&mut self) {
        loop {
            let message = self.recv.recv();
            match message {
                AddPlayer(tcp) => self.add_player(tcp),
                RemovePlayer(id) => self.remove_player(id),
                HandlePacket(id, packet) => self.handle_packet(id, packet),
            }
        }
    }
}
<commit_msg>send_id and send_players<commit_after>
#![feature(macro_rules)]

use std::collections::HashMap;
use std::comm::{Receiver, Sender};
use std::io::{Acceptor, BufferedReader, BufWriter, Listener, MemReader, MemWriter, TcpListener, TcpStream};
use std::io::stdin;
use std::rand::random;

type Id = u32;
type NullResult<T> = Result<T, ()>;
type Packet = Vec<u8>;

enum Message {
    RemovePlayer(Id),
    HandlePacket(Id, Packet),
    AddPlayer(TcpStream),
}

struct Player {
    id: Id,
    tcp: TcpStream,
    name: String,
    send: Sender<Packet>,
}

struct Server {
    players: HashMap<Id, Player>,
    send: Sender<Message>,
    recv: Receiver<Message>,
}

fn main() {
    println!("NoLifePony Server");
    let mut server = Server::new();
    server.run();
    println!("Shutting down");
}

fn new_packet() -> MemWriter {
    let mut buf = MemWriter::new();
    buf.write([0, 0, 0, 0]).unwrap();
    buf
}

fn packet_sender(recv: Receiver<Packet>, mut tcp: TcpStream) {
    for mut msg in recv.iter() {
        println!("Got packet to send!");
        let len = msg.len() as u32 - 4;
        {
            let mut buf = BufWriter::new(msg.mut_slice_to(4));
            buf.write_be_u32(len).unwrap();
        }
        let msg = msg;
        tcp.write(msg.as_slice()).unwrap();
    }
}

fn packet_receiver(send: Sender<Message>, tcp: TcpStream, id: Id) {
    struct Packets {
        buf: BufferedReader<TcpStream>,
    }
    impl Iterator<Packet> for Packets {
        fn next(&mut self) -> Option<Packet> {
            self.buf.read_be_u32().and_then(|len| self.buf.read_exact(len as uint)).ok()
        }
    }
    let mut packets = Packets {
        buf: BufferedReader::new(tcp),
    };
    for packet in packets {
        send.send(HandlePacket(id, packet));
    }
    send.send(RemovePlayer(id));
}

fn listener(send: Sender<Message>) {
    let listen = TcpListener::bind("0.0.0.0", 273);
    let mut accept = listen.listen();
    for stream in accept.incoming() {
        match stream {
            Ok(stream) => send.send(AddPlayer(stream)),
            Err(_) => return,
        }
    }
}

fn commands(_: Sender<Message>) {
    let mut cin = stdin();
    for line in cin.lines() {
        let line = line.unwrap();
        let line: String = line.as_slice().chars().map(|c| c.to_lowercase())
            .filter(|c| *c != '\n' && *c != '\r').collect();
        match line.as_slice() {
            _ => println!("Unknown command"),
        }
    }
}

impl Player {
    fn default_name(id: Id) -> String {
        format!("Pony{:08X}", id)
    }
    fn new(id: Id, mut tcp: TcpStream, send: Sender<Message>) -> Player {
        let tcp2 = tcp.clone();
        spawn(proc() packet_receiver(send, tcp2, id));
        let (send, recv) = channel::<Packet>();
        let tcp2 = tcp.clone();
        spawn(proc() packet_sender(recv, tcp2));
        let name = Player::default_name(id);
        match tcp.peer_name() {
            Ok(ip) => println!("{} connected from {}", name, ip),
            Err(_) => println!("{} connected from unknown", name),
        }
        Player {
            id: id,
            tcp: tcp,
            name: name,
            send: send,
        }
    }
    fn send_id(&self) {
        let mut p = new_packet();
        p.write_be_u16(0x4).unwrap();
        p.write_be_u32(self.id).unwrap();
        self.send.send(p.unwrap());
    }
    fn send_players(&self, server: &Server) {
        let mut p = new_packet();
        p.write_be_u16(0xB).unwrap();
        p.write_be_u32(server.players.len() as u32).unwrap();
        for (_, player) in server.players.iter() {
            p.write_be_u32(player.id).unwrap();
            p.write_be_u32(player.name.len() as u32).unwrap();
            p.write_str(player.name.as_slice()).unwrap();
        }
        self.send.send(p.unwrap());
    }
}

impl Server {
    fn new() -> Server {
        let (send, recv) = channel::<Message>();
        let send2 = send.clone();
        spawn(proc() listener(send2));
        let send2 = send.clone();
        spawn(proc() commands(send2));
        Server {
            players: HashMap::new(),
            send: send,
            recv: recv,
        }
    }
    fn gen_id(&self) -> Id {
        loop {
            let id = random();
            if self.players.find(&id).is_none() { return id }
        }
    }
    fn add_player(&mut self, tcp: TcpStream) {
        let id = self.gen_id();
        let player = Player::new(id, tcp, self.send.clone());
        self.players.insert(player.id, player);
        let player = self.players.get(&id);
        player.send_id();
        player.send_players(self);
    }
    fn remove_player(&mut self, id: Id) {
        let mut player = match self.players.pop(&id) {
            Some(player) => player,
            None => return,
        };
        println!("{} disconnected", player.name);
        player.tcp.close_read().unwrap();
        player.tcp.close_write().unwrap();
    }
    fn handle_packet(&mut self, id: Id, packet: Packet) {
        let player = match self.players.find_mut(&id) {
            Some(player) => player,
            None => { println!("Packet from non-existant player: {}", id); return },
        };
        let mut packet = MemReader::new(packet);
        let opcode = match packet.read_be_u16() {
            Ok(opcode) => opcode,
            Err(_) => { println!("Failed to read opcode from player: {}", id); return },
        };
        match opcode {
            _ => println!("Unknown opcode {} from {}", opcode, player.name),
        }
    }
    fn run(&mut self) {
        loop {
            let message = self.recv.recv();
            match message {
                AddPlayer(tcp) => self.add_player(tcp),
                RemovePlayer(id) => self.remove_player(id),
                HandlePacket(id, packet) => self.handle_packet(id, packet),
            }
        }
    }
}
<|endoftext|>


<commit_before>fn main() {
    println!("Hello, world!");
}
<commit_msg>(WIP) more<commit_after>extern crate card_engine;

fn main() {
    println!("Hello, world!");
}
<|endoftext|>