<commit_before>extern crate base64;
extern crate clap;
extern crate hyper;
extern crate hyper_rustls;
extern crate pem;
#[macro_use]
extern crate prettytable;
extern crate ring;
extern crate rustls;
extern crate serde_json;
extern crate tempfile;
#[macro_use]
extern crate tera;

extern crate ct_tools;

use ct_tools::{crtsh, letsencrypt};
use ct_tools::common::{Log, sha256_hex};
use ct_tools::ct::submit_cert_to_logs;
use ct_tools::google::fetch_trusted_ct_logs;
use std::env;
use std::fs::File;
use std::io::{Read, Write};
use std::process::Command;
use std::sync::Arc;
use std::time::Duration;

fn pems_to_chain(data: &str) -> Vec<Vec<u8>> {
    pem::parse_many(data)
        .into_iter()
        .filter(|p| p.tag == "CERTIFICATE")
        .map(|p| p.contents)
        .collect()
}

fn submit(paths: clap::Values, log_urls: Option<clap::Values>) {
    let mut http_client = hyper::Client::with_connector(
        hyper::net::HttpsConnector::new(hyper_rustls::TlsClient::new())
    );
    http_client.set_read_timeout(Some(Duration::from_secs(15)));

    let logs = match log_urls {
        Some(urls) => {
            urls.map(|url| {
                         Log {
                             url: url.to_string(),
                             description: url.to_string(),
                             is_google: false,
                         }
                     })
                .collect()
        }
        None => fetch_trusted_ct_logs(&http_client),
    };

    for path in paths {
        println!("Submitting {} ...", path);

        let mut contents = String::new();
        File::open(path)
            .unwrap()
            .read_to_string(&mut contents)
            .unwrap();

        let mut chain = pems_to_chain(&contents);
        if chain.len() == 1 {
            // TODO: There's got to be some way to do this ourselves, instead of using crt.sh as a
            // glorified AIA chaser.
            println!("Only one certificate in chain, using crt.sh to build a full chain ...");
            chain = match crtsh::build_chain_for_cert(&http_client, &chain[0]) {
                Some(c) => c,
                None => {
                    println!("Unable to build a chain");
                    continue;
                }
            }
        }
        let scts = submit_cert_to_logs(&http_client, &logs, &chain);

        if !scts.is_empty() {
            println!("Find the cert on crt.sh: {}",
                     crtsh::url_for_cert(&chain[0]));
        }
        let mut table = prettytable::Table::new();
        table.add_row(row!["Log", "SCT"]);
        for (log, sct) in scts {
            table.add_row(row![log.description, base64::encode(&sct.to_raw_bytes())]);
        }
        table.printstd();
        println!();
        println!();
    }
}

fn check(paths: clap::Values) {
    let http_client = hyper::Client::with_connector(
        hyper::net::HttpsConnector::new(hyper_rustls::TlsClient::new())
    );

    for path in paths {
        let mut contents = String::new();
        File::open(path)
            .unwrap()
            .read_to_string(&mut contents)
            .unwrap();

        let chain = pems_to_chain(&contents);

        let is_logged = crtsh::is_cert_logged(&http_client, &chain[0]);
        if is_logged {
            println!("{} was already logged", path);
        } else {
            println!("{} has not been logged", path);
        }
    }
}

struct HttpHandler {
    templates: tera::Tera,
    http_client: hyper::Client,
    logs: Vec<Log>,
}

impl hyper::server::Handler for HttpHandler {
    fn handle(&self, request: hyper::server::Request, response: hyper::server::Response) {
        let peer_certs = request
            .ssl::<hyper_rustls::WrappedStream>()
            .unwrap()
            .to_tls_stream()
            .get_session()
            .get_peer_certificates();

        let mut crtsh_url = None;
        if peer_certs.is_some() && request.method == hyper::method::Method::Post {
            if let Some(chain) = crtsh::build_chain_for_cert(&self.http_client,
                                                             &peer_certs.as_ref().unwrap()[0].0) {
                let scts = submit_cert_to_logs(&self.http_client, &self.logs, &chain);
                if !scts.is_empty() {
                    crtsh_url = Some(crtsh::url_for_cert(&chain[0]));
                    println!("Successfully submitted: {}", sha256_hex(&chain[0]));
                }
            }
        }

        let rendered_cert = peer_certs.map(|chain| {
            let mut tmp = tempfile::NamedTempFile::new().unwrap();
            tmp.write_all(&chain[0].0).unwrap();
            tmp.flush().unwrap();
            let stdout = Command::new("openssl")
                .arg("x509")
                .arg("-text")
                .arg("-noout")
                .arg("-inform")
                .arg("der")
                .arg("-in")
                .arg(tmp.path().as_os_str())
                .output()
                .unwrap()
                .stdout;
            String::from_utf8_lossy(&stdout).into_owned()
        });

        let mut context = tera::Context::new();
        context.add("cert", &rendered_cert);
        context.add("crtsh_url", &crtsh_url);
        response
            .send(self.templates
                      .render("home.html", &context)
                      .unwrap()
                      .as_bytes())
            .unwrap();
    }
}

struct NoVerificationCertificateVerifier;
impl rustls::ClientCertVerifier for NoVerificationCertificateVerifier {
    fn verify_client_cert(&self,
                          _: &rustls::RootCertStore,
                          _: &[rustls::Certificate])
                          -> Result<(), rustls::TLSError> {
        Ok(())
    }
}

fn server(local_dev: bool, domain: Option<&str>, letsencrypt_env: Option<&str>) {
    match (local_dev, domain, letsencrypt_env) {
        (true, Some(_), _) |
        (true, _, Some(_)) => {
            panic!("Can't use both --local-dev and --letsencrypt-env or --domain")
        }
        (_, Some(_), None) |
        (_, None, Some(_)) => {
            panic!("When using Let's Encrypt, must set both --letsencrypt-env and --domain")
        }
        (false, _, None) => panic!("Must set at least one of --local-dev or --letsencrypt-env"),
        _ => {}
    };

    let mut tls_config = rustls::ServerConfig::new();
    tls_config.client_auth_offer = true;
    if local_dev {
        // TODO: not all the details on the cert are perfect, but it's fine.
        let (cert, pkey) = letsencrypt::generate_temporary_cert("localhost");
        tls_config.set_single_cert(vec![letsencrypt::openssl_cert_to_rustls(&cert)],
                                   letsencrypt::openssl_pkey_to_rustls(&pkey));
    } else {
        let letsencrypt_url = match letsencrypt_env.unwrap() {
            "prod" => "https://acme-v01.api.letsencrypt.org/directory",
            "dev" => "https://acme-staging.api.letsencrypt.org/directory",
            _ => unreachable!(),
        };
        let cert_cache = letsencrypt::DiskCache::new(env::home_dir()
                                                         .unwrap()
                                                         .join(".ct-tools")
                                                         .join("certificates"));
        tls_config.cert_resolver =
            Box::new(letsencrypt::AutomaticCertResolver::new(letsencrypt_url,
                                                             vec![domain.unwrap().to_string()],
                                                             cert_cache));
    }
    tls_config.set_persistence(rustls::ServerSessionMemoryCache::new(1024));
    tls_config.ticketer = rustls::Ticketer::new();
    // Disable certificate verification. In any normal context, this would be horribly insecure!
    // However, all we're doing is taking the certs and then turning around and submitting them to
    // CT logs, so it doesn't matter if they're verified.
    tls_config
        .dangerous()
        .set_certificate_verifier(Box::new(NoVerificationCertificateVerifier));
    let tls_server = hyper_rustls::TlsServer { cfg: Arc::new(tls_config) };

    let mut http_client = hyper::Client::with_connector(
        hyper::net::HttpsConnector::new(hyper_rustls::TlsClient::new())
    );
    let logs = fetch_trusted_ct_logs(&http_client);
    http_client.set_write_timeout(Some(Duration::from_secs(5)));
    http_client.set_read_timeout(Some(Duration::from_secs(5)));
    let handler = HttpHandler {
        templates: compile_templates!("templates/*"),
        http_client: http_client,
        logs: logs,
    };

    let addr = if local_dev {
        "127.0.0.1:1337"
    } else {
        "0.0.0.0:443"
    };
    println!("Listening on https://{} ...", addr);
    hyper::Server::https(addr, tls_server)
        .unwrap()
        // If there aren't at least two threads, the Let's Encrypt integration will deadlock.
        .handle_threads(handler, 16)
        .unwrap();
}

fn main() {
    let matches = clap::App::new("ct-tools")
        .subcommand(clap::SubCommand::with_name("submit")
                        .about("Directly submits certificates to CT logs")
                        .arg(clap::Arg::with_name("path")
                                 .multiple(true)
                                 .required(true)
                                 .help("Path to certificate or chain"))
                        .arg(clap::Arg::with_name("log-url")
                                 .long("--log-url")
                                 .multiple(true)
                                 .help("Log URL to submit certificate to")))
        .subcommand(clap::SubCommand::with_name("check")
                        .about("Checks whether a certificate exists in CT logs")
                        .arg(clap::Arg::with_name("path")
                                 .multiple(true)
                                 .required(true)
                                 .help("Path to certificate or chain")))
        .subcommand(clap::SubCommand::with_name("server")
                        .about("Run an HTTPS server that submits client to CT logs")
                        .arg(clap::Arg::with_name("local-dev")
                                 .long("--local-dev")
                                 .help("Local development, do not obtain a certificate"))
                        .arg(clap::Arg::with_name("domain")
                                 .takes_value(true)
                                 .long("--domain")
                                 .help("Domain this is running as"))
                        .arg(clap::Arg::with_name("letsencrypt-env")
                                 .takes_value(true)
                                 .long("--letsencrypt-env")
                                 .possible_values(&["dev", "prod"])
                                 .help("Let's Encrypt environment to use")))
        .get_matches();

    if let Some(matches) = matches.subcommand_matches("submit") {
        submit(matches.values_of("path").unwrap(),
               matches.values_of("log-url"));
    } else if let Some(matches) = matches.subcommand_matches("check") {
        check(matches.values_of("path").unwrap());
    } else if let Some(matches) = matches.subcommand_matches("server") {
        server(matches.is_present("local-dev"),
               matches.value_of("domain"),
               matches.value_of("letsencrypt-env"));
    }
}
<commit_msg>Fixed submit's --log-url arg<commit_after>extern crate base64;
extern crate clap;
extern crate hyper;
extern crate hyper_rustls;
extern crate pem;
#[macro_use]
extern crate prettytable;
extern crate ring;
extern crate rustls;
extern crate serde_json;
extern crate tempfile;
#[macro_use]
extern crate tera;

extern crate ct_tools;

use ct_tools::{crtsh, letsencrypt};
use ct_tools::common::{Log, sha256_hex};
use ct_tools::ct::submit_cert_to_logs;
use ct_tools::google::fetch_trusted_ct_logs;
use std::env;
use std::fs::File;
use std::io::{Read, Write};
use std::process::Command;
use std::sync::Arc;
use std::time::Duration;

fn pems_to_chain(data: &str) -> Vec<Vec<u8>> {
    pem::parse_many(data)
        .into_iter()
        .filter(|p| p.tag == "CERTIFICATE")
        .map(|p| p.contents)
        .collect()
}

fn submit(paths: clap::Values, log_urls: Option<clap::Values>) {
    let mut http_client = hyper::Client::with_connector(
        hyper::net::HttpsConnector::new(hyper_rustls::TlsClient::new())
    );
    http_client.set_read_timeout(Some(Duration::from_secs(15)));

    let logs = match log_urls {
        Some(urls) => {
            urls.map(|url| {
                         Log {
                             url: url.to_string(),
                             description: url.to_string(),
                             is_google: false,
                         }
                     })
                .collect()
        }
        None => fetch_trusted_ct_logs(&http_client),
    };

    for path in paths {
        println!("Submitting {} ...", path);

        let mut contents = String::new();
        File::open(path)
            .unwrap()
            .read_to_string(&mut contents)
            .unwrap();

        let mut chain = pems_to_chain(&contents);
        if chain.len() == 1 {
            // TODO: There's got to be some way to do this ourselves, instead of using crt.sh as a
            // glorified AIA chaser.
            println!("Only one certificate in chain, using crt.sh to build a full chain ...");
            chain = match crtsh::build_chain_for_cert(&http_client, &chain[0]) {
                Some(c) => c,
                None => {
                    println!("Unable to build a chain");
                    continue;
                }
            }
        }
        let scts = submit_cert_to_logs(&http_client, &logs, &chain);

        if !scts.is_empty() {
            println!("Find the cert on crt.sh: {}",
                     crtsh::url_for_cert(&chain[0]));
        }
        let mut table = prettytable::Table::new();
        table.add_row(row!["Log", "SCT"]);
        for (log, sct) in scts {
            table.add_row(row![log.description, base64::encode(&sct.to_raw_bytes())]);
        }
        table.printstd();
        println!();
        println!();
    }
}

fn check(paths: clap::Values) {
    let http_client = hyper::Client::with_connector(
        hyper::net::HttpsConnector::new(hyper_rustls::TlsClient::new())
    );

    for path in paths {
        let mut contents = String::new();
        File::open(path)
            .unwrap()
            .read_to_string(&mut contents)
            .unwrap();

        let chain = pems_to_chain(&contents);

        let is_logged = crtsh::is_cert_logged(&http_client, &chain[0]);
        if is_logged {
            println!("{} was already logged", path);
        } else {
            println!("{} has not been logged", path);
        }
    }
}

struct HttpHandler {
    templates: tera::Tera,
    http_client: hyper::Client,
    logs: Vec<Log>,
}

impl hyper::server::Handler for HttpHandler {
    fn handle(&self, request: hyper::server::Request, response: hyper::server::Response) {
        let peer_certs = request
            .ssl::<hyper_rustls::WrappedStream>()
            .unwrap()
            .to_tls_stream()
            .get_session()
            .get_peer_certificates();

        let mut crtsh_url = None;
        if peer_certs.is_some() && request.method == hyper::method::Method::Post {
            if let Some(chain) = crtsh::build_chain_for_cert(&self.http_client,
                                                             &peer_certs.as_ref().unwrap()[0].0) {
                let scts = submit_cert_to_logs(&self.http_client, &self.logs, &chain);
                if !scts.is_empty() {
                    crtsh_url = Some(crtsh::url_for_cert(&chain[0]));
                    println!("Successfully submitted: {}", sha256_hex(&chain[0]));
                }
            }
        }

        let rendered_cert = peer_certs.map(|chain| {
            let mut tmp = tempfile::NamedTempFile::new().unwrap();
            tmp.write_all(&chain[0].0).unwrap();
            tmp.flush().unwrap();
            let stdout = Command::new("openssl")
                .arg("x509")
                .arg("-text")
                .arg("-noout")
                .arg("-inform")
                .arg("der")
                .arg("-in")
                .arg(tmp.path().as_os_str())
                .output()
                .unwrap()
                .stdout;
            String::from_utf8_lossy(&stdout).into_owned()
        });

        let mut context = tera::Context::new();
        context.add("cert", &rendered_cert);
        context.add("crtsh_url", &crtsh_url);
        response
            .send(self.templates
                      .render("home.html", &context)
                      .unwrap()
                      .as_bytes())
            .unwrap();
    }
}

struct NoVerificationCertificateVerifier;
impl rustls::ClientCertVerifier for NoVerificationCertificateVerifier {
    fn verify_client_cert(&self,
                          _: &rustls::RootCertStore,
                          _: &[rustls::Certificate])
                          -> Result<(), rustls::TLSError> {
        Ok(())
    }
}

fn server(local_dev: bool, domain: Option<&str>, letsencrypt_env: Option<&str>) {
    match (local_dev, domain, letsencrypt_env) {
        (true, Some(_), _) |
        (true, _, Some(_)) => {
            panic!("Can't use both --local-dev and --letsencrypt-env or --domain")
        }
        (_, Some(_), None) |
        (_, None, Some(_)) => {
            panic!("When using Let's Encrypt, must set both --letsencrypt-env and --domain")
        }
        (false, _, None) => panic!("Must set at least one of --local-dev or --letsencrypt-env"),
        _ => {}
    };

    let mut tls_config = rustls::ServerConfig::new();
    tls_config.client_auth_offer = true;
    if local_dev {
        // TODO: not all the details on the cert are perfect, but it's fine.
        let (cert, pkey) = letsencrypt::generate_temporary_cert("localhost");
        tls_config.set_single_cert(vec![letsencrypt::openssl_cert_to_rustls(&cert)],
                                   letsencrypt::openssl_pkey_to_rustls(&pkey));
    } else {
        let letsencrypt_url = match letsencrypt_env.unwrap() {
            "prod" => "https://acme-v01.api.letsencrypt.org/directory",
            "dev" => "https://acme-staging.api.letsencrypt.org/directory",
            _ => unreachable!(),
        };
        let cert_cache = letsencrypt::DiskCache::new(env::home_dir()
                                                         .unwrap()
                                                         .join(".ct-tools")
                                                         .join("certificates"));
        tls_config.cert_resolver =
            Box::new(letsencrypt::AutomaticCertResolver::new(letsencrypt_url,
                                                             vec![domain.unwrap().to_string()],
                                                             cert_cache));
    }
    tls_config.set_persistence(rustls::ServerSessionMemoryCache::new(1024));
    tls_config.ticketer = rustls::Ticketer::new();
    // Disable certificate verification. In any normal context, this would be horribly insecure!
    // However, all we're doing is taking the certs and then turning around and submitting them to
    // CT logs, so it doesn't matter if they're verified.
    tls_config
        .dangerous()
        .set_certificate_verifier(Box::new(NoVerificationCertificateVerifier));
    let tls_server = hyper_rustls::TlsServer { cfg: Arc::new(tls_config) };

    let mut http_client = hyper::Client::with_connector(
        hyper::net::HttpsConnector::new(hyper_rustls::TlsClient::new())
    );
    let logs = fetch_trusted_ct_logs(&http_client);
    http_client.set_write_timeout(Some(Duration::from_secs(5)));
    http_client.set_read_timeout(Some(Duration::from_secs(5)));
    let handler = HttpHandler {
        templates: compile_templates!("templates/*"),
        http_client: http_client,
        logs: logs,
    };

    let addr = if local_dev {
        "127.0.0.1:1337"
    } else {
        "0.0.0.0:443"
    };
    println!("Listening on https://{} ...", addr);
    hyper::Server::https(addr, tls_server)
        .unwrap()
        // If there aren't at least two threads, the Let's Encrypt integration will deadlock.
        .handle_threads(handler, 16)
        .unwrap();
}

fn main() {
    let matches = clap::App::new("ct-tools")
        .subcommand(clap::SubCommand::with_name("submit")
                        .about("Directly submits certificates to CT logs")
                        .arg(clap::Arg::with_name("path")
                                 .multiple(true)
                                 .required(true)
                                 .help("Path to certificate or chain"))
                        .arg(clap::Arg::with_name("log-url")
                                 .long("--log-url")
                                 .takes_value(true)
                                 .multiple(true)
                                 .help("Log URL to submit certificate to")))
        .subcommand(clap::SubCommand::with_name("check")
                        .about("Checks whether a certificate exists in CT logs")
                        .arg(clap::Arg::with_name("path")
                                 .multiple(true)
                                 .required(true)
                                 .help("Path to certificate or chain")))
        .subcommand(clap::SubCommand::with_name("server")
                        .about("Run an HTTPS server that submits client to CT logs")
                        .arg(clap::Arg::with_name("local-dev")
                                 .long("--local-dev")
                                 .help("Local development, do not obtain a certificate"))
                        .arg(clap::Arg::with_name("domain")
                                 .takes_value(true)
                                 .long("--domain")
                                 .help("Domain this is running as"))
                        .arg(clap::Arg::with_name("letsencrypt-env")
                                 .takes_value(true)
                                 .long("--letsencrypt-env")
                                 .possible_values(&["dev", "prod"])
                                 .help("Let's Encrypt environment to use")))
        .get_matches();

    if let Some(matches) = matches.subcommand_matches("submit") {
        submit(matches.values_of("path").unwrap(),
               matches.values_of("log-url"));
    } else if let Some(matches) = matches.subcommand_matches("check") {
        check(matches.values_of("path").unwrap());
    } else if let Some(matches) = matches.subcommand_matches("server") {
        server(matches.is_present("local-dev"),
               matches.value_of("domain"),
               matches.value_of("letsencrypt-env"));
    }
}
<|endoftext|>


<commit_before>extern crate macaroni_lang;
use macaroni_lang::*;

extern crate getopts;
use getopts::Options;

use std::io;
use std::io::prelude::*;
use std::env;
use std::fs::File;

fn main() {
    let mut mac = macaroni::Macaroni::new();
    let args: Vec<String> = env::args().collect();
    let program = args[0].clone();

    let mut opts = Options::new();
    opts.optflag("h", "help", "output this usage information");
    opts.optflag("v", "version", "output the current Macaroni version");
    opts.optflag("i", "interactive", "start an interactive REPL");
    opts.optopt("e", "evaluate", "takes one parameter, runs as Macaroni code",
        "[code]");
    let matches = match opts.parse(&args[1..]) {
        Ok(m) => m,
        Err(_) => {
            usage(&program, opts);
            return;
        }
    };

    if matches.opt_present("h") {
        usage(&program, opts);
    } else if matches.opt_present("v") {
        println!("version 0.0.0 (no official release)");
    } else if matches.opt_present("i") {
        loop {
            print!(">>> ");
            io::stdout().flush().unwrap();
            let mut line = String::new();
            if io::stdin().read_line(&mut line).unwrap() == 0 { break; }

            println!(" => {:?}", mac.run(line));
        }
    } else if matches.opt_present("e") {
        mac.run(matches.opt_str("e").unwrap());
    } else {
        match matches.free.len() {
            0 => {
                let mut code = String::new();
                io::stdin().read_to_string(&mut code).unwrap();
                mac.run(code);
            },
            1 => {
                let mut code = String::new();
                match File::open(matches.free[0].clone()) {
                    Ok(mut f) => {
                        match f.read_to_string(&mut code) {
                            Ok(_) => { mac.run(code); },
                            Err(_) => file_err(&matches.free[0])
                        }
                    },
                    Err(_) => file_err(&matches.free[0])
                }
            },
            _ => usage(&program, opts)
        }
    }
}

fn usage(program: &str, opts: Options) {
    print!("{}", opts.usage(&format!("Usage: {} [filename] [options...]",
        program)));
}

fn file_err(name: &str) {
    println!("could not read file {}", name);
}
<commit_msg>release 0.0.1<commit_after>extern crate macaroni_lang;
use macaroni_lang::*;

extern crate getopts;
use getopts::Options;

use std::io;
use std::io::prelude::*;
use std::env;
use std::fs::File;

fn main() {
    let mut mac = macaroni::Macaroni::new();
    let args: Vec<String> = env::args().collect();
    let program = args[0].clone();

    let mut opts = Options::new();
    opts.optflag("h", "help", "output this usage information");
    opts.optflag("v", "version", "output the current Macaroni version");
    opts.optflag("i", "interactive", "start an interactive REPL");
    opts.optopt("e", "evaluate", "takes one parameter, runs as Macaroni code",
        "[code]");
    let matches = match opts.parse(&args[1..]) {
        Ok(m) => m,
        Err(_) => {
            usage(&program, opts);
            return;
        }
    };

    if matches.opt_present("h") {
        usage(&program, opts);
    } else if matches.opt_present("v") {
        println!("version 0.0.1 (alpha)");
    } else if matches.opt_present("i") {
        loop {
            print!(">>> ");
            io::stdout().flush().unwrap();
            let mut line = String::new();
            if io::stdin().read_line(&mut line).unwrap() == 0 { break; }

            println!(" => {:?}", mac.run(line));
        }
    } else if matches.opt_present("e") {
        mac.run(matches.opt_str("e").unwrap());
    } else {
        match matches.free.len() {
            0 => {
                let mut code = String::new();
                io::stdin().read_to_string(&mut code).unwrap();
                mac.run(code);
            },
            1 => {
                let mut code = String::new();
                match File::open(matches.free[0].clone()) {
                    Ok(mut f) => {
                        match f.read_to_string(&mut code) {
                            Ok(_) => { mac.run(code); },
                            Err(_) => file_err(&matches.free[0])
                        }
                    },
                    Err(_) => file_err(&matches.free[0])
                }
            },
            _ => usage(&program, opts)
        }
    }
}

fn usage(program: &str, opts: Options) {
    print!("{}", opts.usage(&format!("Usage: {} [filename] [options...]",
        program)));
}

fn file_err(name: &str) {
    println!("could not read file {}", name);
}
<|endoftext|>


<commit_before>#![allow(dead_code, unused_features)]
#![feature(collections, os, io, std_misc, core, libc, path)]

extern crate libc;

mod args;
mod ansi;
mod matching;
mod screen;

use std::os;
use std::old_io;
use std::cmp::min;
use screen::Screen;
use screen::Key;
use screen::Key::*;
use self::SearchState::*;

fn main() {
    let args = match args::parse_args() {
        Some(args) => args,
        None => {
            os::set_exit_status(1);
            return;
        },
    };

    if args.help { return; }

    let choices = read_choices();
    let initial_search = args.initial_search.clone();
    if args.use_first {
        let matches = matching::compute_matches(&choices, initial_search.as_slice());
        println!("{}", matches.get(0).unwrap_or(&&"".to_string()));
        return;
    } else {
        event_loop(choices, initial_search.as_slice());
    }
}

fn event_loop(choices: Vec<String>, initial_search: &str) {
    let mut search = Search::new(&choices, initial_search.to_string());
    let mut screen = Screen::open_screen();

    loop {
        search.recompute_matches();

        match search.state {
            InProgress => draw_screen(&mut screen, &search),
            _ => break,
        }

        let keys = screen.get_buffered_keys();
        for key in keys.iter() {
            handle_key(&mut search, key, screen.visible_choices);
        }
    }

    screen.move_cursor_to_bottom();
    println!("{}", search.get_selection());
}

fn handle_key(search: &mut Search, key: &Key, visible_choices: u16) {
    match *key {
        Char(x) => search.append(x),
        Backspace => search.backspace(),
        Control('h') => search.backspace(),
        Control('w') => search.delete_word(),
        Control('u') => search.clear_query(),
        Control('c') => search.cancel(),
        Control('g') => search.cancel(),
        Control('n') => search.down(visible_choices),
        Control('p') => search.up(),
        Enter => search.done(),
        _ => {}
    }
}

struct Search<'a> {
    choices: &'a Vec<String>,
    query: String,
    matches: Vec<&'a String>,
    stale: bool,
    index: usize,
    state: SearchState,
}

#[derive(PartialEq, Eq)]
enum SearchState {
    InProgress,
    Done,
    Canceled,
}

impl<'a> Search<'a> {
    fn new(choices: &'a Vec<String>, initial_search: String) -> Search<'a> {
        Search {
            choices: choices,
            query: initial_search,
            matches: Vec::new(),
            stale: true,
            index: 0,
            state: InProgress,
        }
    }

    fn up(&mut self) {
        self.index = if self.index == 0 { 0 } else { self.index - 1 };
    }

    fn down(&mut self, visible_choices: u16) {
        let limit = min(visible_choices as usize - 1, self.matches.len() - 1);
        self.index = min(self.index + 1, limit);
    }

    fn backspace(&mut self) {
        self.query.pop();
        self.stale = true;
        self.index = 0;
    }

    fn delete_word(&mut self) {
        self.stale = true;
        delete_last_word(&mut self.query);
    }

    fn append(&mut self, c: char) {
        self.query.push(c);
        self.stale = true;
        self.index = 0;
    }

    fn clear_query(&mut self) {
        self.query.clear();
        self.stale = true;
    }

    fn recompute_matches(&mut self) {
        if self.stale {
            self.matches = matching::compute_matches(self.choices, self.query.as_slice());
            self.stale = false;
        }
    }

    fn get_selection(&mut self) -> String {
        if self.state == Canceled {
            "".to_string()
        } else {
            self.recompute_matches();
            self.matches.get(self.index).unwrap_or(&&"".to_string()).to_string()
        }
    }

    fn cancel(&mut self) {
        self.state = Canceled
    }

    fn done(&mut self) {
        self.state = Done
    }
}

fn draw_screen(screen: &mut Screen, search: &Search) {
    screen.hide_cursor();
    screen.blank_screen();
    screen.write(format!("> {} ({} choices)\n", search.query, search.choices.len()).as_slice());

    print_matches(screen, &search.matches, search.index);

    let start = screen.start_line;
    screen.move_cursor(start, 2 + search.query.len() as u16);
    screen.show_cursor();
}

fn print_matches(screen: &mut Screen, matches: &Vec<&String>, index: usize) {
    let mut i = 1;
    for choice in matches.iter() {
        if i == index + 1 {
            screen.write_inverted(choice.as_slice());
        } else {
            screen.write(choice.as_slice());
        }
        if i >= screen.visible_choices as usize {
            return;
        } else {
            screen.write("\n");
        }
        i += 1;
    }
}

fn read_choices() -> Vec<String> {
    let mut stdin = old_io::stdio::stdin();
    let mut lines = Vec::new();

    while let Ok(mut s) = stdin.read_line() {
        trim(&mut s);
        lines.push(s);
    }

    lines
}

pub fn trim(s: &mut String) {
    while let Some(x) = s.pop() {
        if x != '\n' {
            s.push(x);
            return;
        }
    }
}

fn delete_last_word(s: &mut String) {
    let mut deleted_something = false;
    while let Some(x) = s.pop() {
        if x == ' ' {
            if deleted_something {
                s.push(x);
                return;
            }
        } else {
            deleted_something = true;
        }
    }
}

#[test]
fn trim_test() {
    fn should_become(before: &str, after: &str) {
        let mut x = before.to_string();
        trim(&mut x);
        assert_eq!(after.to_string(), x);
    }
    should_become("", "");
    should_become("\n", "");
    should_become("\n\n", "");
    should_become("asdf", "asdf");
    should_become("asdf\n", "asdf");
    should_become("asdf\nasdf\n", "asdf\nasdf");
}

#[test]
fn delete_word_test() {
    fn should_become(before: &str, after: &str) {
        let mut x = before.to_string();
        delete_last_word(&mut x);
        assert_eq!(after.to_string(), x);
    }
    should_become("", "");
    should_become("a", "");
    should_become("asdf", "");
    should_become("asdf asdf asdf", "asdf asdf ");
    should_become("asdf asdf asdf ", "asdf asdf ");
    should_become("asdf asdf asdf  ", "asdf asdf ");
}
<commit_msg>Allow feature(path) on non-Windows builds<commit_after>#![allow(dead_code)]
#![feature(collections, os, io, std_misc, core, libc)]
#![cfg_attr(not(windows), feature(path))]

extern crate libc;

mod args;
mod ansi;
mod matching;
mod screen;

use std::os;
use std::old_io;
use std::cmp::min;
use screen::Screen;
use screen::Key;
use screen::Key::*;
use self::SearchState::*;

fn main() {
    let args = match args::parse_args() {
        Some(args) => args,
        None => {
            os::set_exit_status(1);
            return;
        },
    };

    if args.help { return; }

    let choices = read_choices();
    let initial_search = args.initial_search.clone();
    if args.use_first {
        let matches = matching::compute_matches(&choices, initial_search.as_slice());
        println!("{}", matches.get(0).unwrap_or(&&"".to_string()));
        return;
    } else {
        event_loop(choices, initial_search.as_slice());
    }
}

fn event_loop(choices: Vec<String>, initial_search: &str) {
    let mut search = Search::new(&choices, initial_search.to_string());
    let mut screen = Screen::open_screen();

    loop {
        search.recompute_matches();

        match search.state {
            InProgress => draw_screen(&mut screen, &search),
            _ => break,
        }

        let keys = screen.get_buffered_keys();
        for key in keys.iter() {
            handle_key(&mut search, key, screen.visible_choices);
        }
    }

    screen.move_cursor_to_bottom();
    println!("{}", search.get_selection());
}

fn handle_key(search: &mut Search, key: &Key, visible_choices: u16) {
    match *key {
        Char(x) => search.append(x),
        Backspace => search.backspace(),
        Control('h') => search.backspace(),
        Control('w') => search.delete_word(),
        Control('u') => search.clear_query(),
        Control('c') => search.cancel(),
        Control('g') => search.cancel(),
        Control('n') => search.down(visible_choices),
        Control('p') => search.up(),
        Enter => search.done(),
        _ => {}
    }
}

struct Search<'a> {
    choices: &'a Vec<String>,
    query: String,
    matches: Vec<&'a String>,
    stale: bool,
    index: usize,
    state: SearchState,
}

#[derive(PartialEq, Eq)]
enum SearchState {
    InProgress,
    Done,
    Canceled,
}

impl<'a> Search<'a> {
    fn new(choices: &'a Vec<String>, initial_search: String) -> Search<'a> {
        Search {
            choices: choices,
            query: initial_search,
            matches: Vec::new(),
            stale: true,
            index: 0,
            state: InProgress,
        }
    }

    fn up(&mut self) {
        self.index = if self.index == 0 { 0 } else { self.index - 1 };
    }

    fn down(&mut self, visible_choices: u16) {
        let limit = min(visible_choices as usize - 1, self.matches.len() - 1);
        self.index = min(self.index + 1, limit);
    }

    fn backspace(&mut self) {
        self.query.pop();
        self.stale = true;
        self.index = 0;
    }

    fn delete_word(&mut self) {
        self.stale = true;
        delete_last_word(&mut self.query);
    }

    fn append(&mut self, c: char) {
        self.query.push(c);
        self.stale = true;
        self.index = 0;
    }

    fn clear_query(&mut self) {
        self.query.clear();
        self.stale = true;
    }

    fn recompute_matches(&mut self) {
        if self.stale {
            self.matches = matching::compute_matches(self.choices, self.query.as_slice());
            self.stale = false;
        }
    }

    fn get_selection(&mut self) -> String {
        if self.state == Canceled {
            "".to_string()
        } else {
            self.recompute_matches();
            self.matches.get(self.index).unwrap_or(&&"".to_string()).to_string()
        }
    }

    fn cancel(&mut self) {
        self.state = Canceled
    }

    fn done(&mut self) {
        self.state = Done
    }
}

fn draw_screen(screen: &mut Screen, search: &Search) {
    screen.hide_cursor();
    screen.blank_screen();
    screen.write(format!("> {} ({} choices)\n", search.query, search.choices.len()).as_slice());

    print_matches(screen, &search.matches, search.index);

    let start = screen.start_line;
    screen.move_cursor(start, 2 + search.query.len() as u16);
    screen.show_cursor();
}

fn print_matches(screen: &mut Screen, matches: &Vec<&String>, index: usize) {
    let mut i = 1;
    for choice in matches.iter() {
        if i == index + 1 {
            screen.write_inverted(choice.as_slice());
        } else {
            screen.write(choice.as_slice());
        }
        if i >= screen.visible_choices as usize {
            return;
        } else {
            screen.write("\n");
        }
        i += 1;
    }
}

fn read_choices() -> Vec<String> {
    let mut stdin = old_io::stdio::stdin();
    let mut lines = Vec::new();

    while let Ok(mut s) = stdin.read_line() {
        trim(&mut s);
        lines.push(s);
    }

    lines
}

pub fn trim(s: &mut String) {
    while let Some(x) = s.pop() {
        if x != '\n' {
            s.push(x);
            return;
        }
    }
}

fn delete_last_word(s: &mut String) {
    let mut deleted_something = false;
    while let Some(x) = s.pop() {
        if x == ' ' {
            if deleted_something {
                s.push(x);
                return;
            }
        } else {
            deleted_something = true;
        }
    }
}

#[test]
fn trim_test() {
    fn should_become(before: &str, after: &str) {
        let mut x = before.to_string();
        trim(&mut x);
        assert_eq!(after.to_string(), x);
    }
    should_become("", "");
    should_become("\n", "");
    should_become("\n\n", "");
    should_become("asdf", "asdf");
    should_become("asdf\n", "asdf");
    should_become("asdf\nasdf\n", "asdf\nasdf");
}

#[test]
fn delete_word_test() {
    fn should_become(before: &str, after: &str) {
        let mut x = before.to_string();
        delete_last_word(&mut x);
        assert_eq!(after.to_string(), x);
    }
    should_become("", "");
    should_become("a", "");
    should_become("asdf", "");
    should_become("asdf asdf asdf", "asdf asdf ");
    should_become("asdf asdf asdf ", "asdf asdf ");
    should_become("asdf asdf asdf  ", "asdf asdf ");
}
<|endoftext|>


<commit_before>extern crate iron;
#[macro_use]
extern crate router;
extern crate staticfile;
extern crate mount;
extern crate urlencoded;
extern crate rustc_serialize;
extern crate html5ever;
extern crate regex;
extern crate uuid;
extern crate chrono;

use std::net::SocketAddrV4;
use std::net::Ipv4Addr;
use std::path::Path;
use iron::prelude::*;
use iron::status;
use iron::mime::Mime;
use staticfile::Static;
use mount::Mount;
use router::{Router};
use urlencoded::UrlEncodedQuery;
use urlencoded::UrlEncodedBody;
use std::str::FromStr;
use uuid::Uuid;

#[macro_use]
extern crate string_cache;
extern crate pink_spider;

use pink_spider::error::Error;
use pink_spider::scraper::extract;
use pink_spider::model::{Track, Playlist, Entry, Provider, PaginatedCollection};
use rustc_serialize::json::{ToJson, Json};
use pink_spider::youtube;
use pink_spider::soundcloud;

pub fn index_entries(req: &mut Request) -> IronResult<Response> {
    let (page, per_page) = pagination_params(req);
    let entries          = Entry::find(page, per_page);
    let json_obj: Json   = entries.to_json();
    let json_str: String = json_obj.to_string();
    Ok(Response::with((status::Ok, application_json(), json_str)))
}

pub fn index_tracks(req: &mut Request) -> IronResult<Response> {
    let (page, per_page) = pagination_params(req);
    let tracks  = Track::find(page, per_page);
    let json_obj: Json   = tracks.to_json();
    let json_str: String = json_obj.to_string();
    Ok(Response::with((status::Ok, application_json(), json_str)))
}

pub fn index_tracks_by_entry(req: &mut Request) -> IronResult<Response> {
    let ref entry_id = req.extensions.get::<Router>().unwrap().find("entry_id").unwrap();
    let uuid = try!(Uuid::parse_str(entry_id).map_err(|_| Error::Unprocessable));
    let items = Track::find_by_entry_id(uuid);
    let col = PaginatedCollection {
        page:     0,
        per_page: items.len() as i64,
        total:    items.len() as i64,
        items:    items,
    };
    let json_obj: Json   = col.to_json();
    let json_str: String = json_obj.to_string();
    Ok(Response::with((status::Ok, application_json(), json_str)))
}

pub fn index_playlists(req: &mut Request) -> IronResult<Response> {
    let (page, per_page) = pagination_params(req);
    let playlists  = Playlist::find(page, per_page);
    let json_obj: Json   = playlists.to_json();
    let json_str: String = json_obj.to_string();
    Ok(Response::with((status::Ok, application_json(), json_str)))
}

pub fn index_playlists_by_entry(req: &mut Request) -> IronResult<Response> {
    let ref entry_id = req.extensions.get::<Router>().unwrap().find("entry_id").unwrap();
    let uuid = try!(Uuid::parse_str(entry_id).map_err(|_| Error::Unprocessable));
    let items = Playlist::find_by_entry_id(uuid);
    let col = PaginatedCollection {
        page:     0,
        per_page: items.len() as i64,
        total:    items.len() as i64,
        items:    items,
    };
    let json_obj: Json   = col.to_json();
    let json_str: String = json_obj.to_string();
    Ok(Response::with((status::Ok, application_json(), json_str)))
}

pub fn playlistify(req: &mut Request) -> IronResult<Response> {
    pub fn playlistify2(req: &mut Request) -> Result<Response, Error> {
        let ref params  = try!(req.get_ref::<UrlEncodedQuery>());
        let url         = try!(params.get("url").ok_or(Error::BadRequest));
        let defaults    = &vec!("false".to_string());
        let force_param = params.get("force").unwrap_or(defaults);
        let force       = force_param.len() > 0 && &force_param[0] == "true";
        let entry       = try!(find_or_playlistify_entry(&url[0], force));
        let json_obj    = entry.to_json() as Json;
        let json_str    = json_obj.to_string() as String;
        Ok(Response::with((status::Ok, application_json(), json_str)))
    }
    playlistify2(req).map_err(|err| IronError::from(err))
}

pub fn find_or_playlistify_entry(url: &str, force: bool) -> Result<Entry, Error> {
    match Entry::find_by_url(url) {
        Ok(entry) => {
            println!("Get entry from database cache: {}", url);
            if force {
                println!("Update entry: {}", url);
                let entry = try!(playlistify_entry(entry));
                Ok(entry)
            } else {
                Ok(entry)
            }
        },
        Err(_) => {
            let entry = try!(Entry::create_by_url(url.to_string()));
            let entry = try!(playlistify_entry(entry));
            println!("Create new entry to database cache: {}", url);
            Ok(entry)
        },
    }
}

pub fn playlistify_entry(entry: Entry) -> Result<Entry, Error> {
    let mut e = entry.clone();
    let product = try!(extract(&entry.url));
    match product.og_obj {
        Some(og_obj) => {
            e.title       = Some(og_obj.title);
            e.description = og_obj.description;
            e.locale      = og_obj.locale;
            e.visual_url  = og_obj.images.first().map(|i| i.url.clone());
        },
        None => (),
    }
    for t in product.tracks {
        let new_track = try!(Track::find_or_create(t.provider, t.identifier.to_string()));
        let mut track = t.clone();
        track.id      = new_track.id;
        try!(track.fetch_detail().save());
        match entry.tracks.iter().find(|&t| t.id == track.id) {
            Some(_) => (),
            None    => e.add_track(track.clone())
        }
    }
    for p in product.playlists {
        let new_playlist = try!(Playlist::find_or_create(p.provider, p.identifier.to_string()));
        let mut playlist = p.clone();
        playlist.id      = new_playlist.id;
        try!(playlist.save());
        match entry.playlists.iter().find(|&p| p.id == playlist.id) {
            Some(_) => (),
            None    => e.add_playlist(playlist.clone())
        }
    }
    try!(e.save());
    Ok(e)
}

pub fn show_track_by_id(req: &mut Request) -> IronResult<Response> {
    let ref track_id = req.extensions.get::<Router>().unwrap()
                          .find("track_id").unwrap();
    match Track::find_by_id(track_id) {
        Ok(track) => {
            Ok(Response::with((status::Ok,
                               application_json(),
                               track.to_json().to_string())))
        },
        Err(e) => Ok(e.as_response())
    }
}

pub fn show_track(req: &mut Request) -> IronResult<Response> {
    let provider   = req.extensions.get::<Router>().unwrap().find("provider").unwrap();
    let identifier = req.extensions.get::<Router>().unwrap().find("id").unwrap();
    let p = &Provider::new(provider.to_string());
    match Track::find_by(p, identifier) {
        Ok(track) => {
            Ok(Response::with((status::Ok,
                               application_json(),
                               track.to_json().to_string())))
        },
        Err(e) => Ok(e.as_response())
    }
}

pub fn update_track(req: &mut Request) -> IronResult<Response> {
    let mut track = try!(Track::find_by_id(&query_as_string(req, "track_id")));
    match param_as_string(req, "title") {
        Some(title) => track.title = title,
        None        => (),
    }
    match param_as_string(req, "url") {
        Some(url) => track.url = url,
        None      => (),
    }
    let track = match track.provider {
        Provider::YouTube => match youtube::fetch_video(&track.identifier) {
            Ok(video) => track.update_with_yt_video(&video),
            Err(_)    => track.disable(),
        },
        Provider::SoundCloud => match soundcloud::fetch_track(&track.identifier) {
            Ok(sc_track) => track.update_with_sc_track(&sc_track),
            Err(_)       => track.disable(),
        },
        _ => &mut track,
    };
    try!(track.save());
    let res = track.to_json().to_string();
    Ok(Response::with((status::Ok, application_json(), res)))
}

pub fn show_playlist_by_id(req: &mut Request) -> IronResult<Response> {
    let ref playlist_id = req.extensions.get::<Router>().unwrap()
                          .find("playlist_id").unwrap();
    match Playlist::find_by_id(playlist_id) {
        Ok(playlist) => {
            Ok(Response::with((status::Ok,
                               application_json(),
                               playlist.to_json().to_string())))
        },
        Err(e) => Ok(e.as_response())
    }
}

pub fn show_playlist(req: &mut Request) -> IronResult<Response> {
    let provider   = req.extensions.get::<Router>().unwrap().find("provider").unwrap();
    let identifier = req.extensions.get::<Router>().unwrap().find("id").unwrap();
    let p = &Provider::new(provider.to_string());
    match Playlist::find_by(p, identifier) {
        Ok(playlist) => {
            Ok(Response::with((status::Ok,
                               application_json(),
                               playlist.to_json().to_string())))
        },
        Err(e) => Ok(e.as_response())
    }
}

fn param_as_string(req: &mut Request, key: &str) -> Option<String> {
    match req.get_ref::<UrlEncodedBody>() {
        Ok(ref params) => match params.get(key) {
            Some(val) => Some(val[0].clone()),
            None      => None
        },
        Err(_) => None
    }
}

fn query_as_string(req: &mut Request, key: &str) -> String {
    return req.extensions.get::<Router>().unwrap()
        .find(key).unwrap().to_string();
}

fn pagination_params(req: &mut Request) -> (i64, i64) {
    match req.get_ref::<UrlEncodedQuery>() {
        Ok(ref params) =>
            (params.get("page").unwrap()[0].to_string().parse::<i64>().unwrap(),
             params.get("per_page").unwrap()[0].to_string().parse::<i64>().unwrap()),
        Err(_) =>
            (0, 10)
    }
}

fn application_json() -> Mime {
    Mime::from_str("application/json").ok().unwrap()
}

pub fn main() {
    let path = Path::new("public");
    let mut mount = Mount::new();
    mount.mount("/web/", Static::new(Path::new(path)));
    let router = router!(
        playlistify:              get  "/playlistify"                 => playlistify,
        show_track_by_id:         get  "/tracks/:track_id"            => show_track_by_id,
        update_track:             post "/tracks/:track_id"            => update_track,
        show_track:               get  "/tracks/:provider/:id"        => show_track,
        show_playlist_by_id:      get  "/playlists/:playlist_id"      => show_playlist_by_id,
//        update_playlist:          post "/playlists/:playlist_id"      => update_playlist,
        show_playlist:            get  "/playlist/:provider/:id"      => show_playlist,
        index_entries:            get  "/entries"                     => index_entries,
        index_tracks:             get  "/tracks"                      => index_tracks,
        index_tracks_by_entry:    get  "/entries/:entry_id/tracks"    => index_tracks_by_entry,
        index_playlists:          get  "/playlists"                   => index_playlists,
        index_playlists_by_entry: get  "/entries/:entry_id/playlists" => index_playlists_by_entry,
        web:                   get  "/*"                        => mount,
    );
    let port_str = match std::env::var("PORT") {
        Ok(n)    => n,
        Err(_) => "8080".to_string()
    };
    let port: u16 = match port_str.trim().parse() {
        Ok(n) => n,
        Err(_) => {
            println!("Faild to parse port");
            return;
        }
    };
    println!("PORT {}", port_str);
    let ip = Ipv4Addr::new(0, 0, 0, 0);
    Iron::new(router).http(SocketAddrV4::new(ip, port)).unwrap();
}
<commit_msg>Add albums route and refactor with Model and Enclosure generics<commit_after>extern crate iron;
#[macro_use]
extern crate router;
extern crate staticfile;
extern crate mount;
extern crate urlencoded;
extern crate rustc_serialize;
extern crate html5ever;
extern crate regex;
extern crate uuid;
extern crate chrono;

use std::net::SocketAddrV4;
use std::net::Ipv4Addr;
use std::path::Path;
use iron::prelude::*;
use iron::status;
use iron::mime::Mime;
use staticfile::Static;
use mount::Mount;
use router::{Router};
use urlencoded::UrlEncodedQuery;
use urlencoded::UrlEncodedBody;
use std::str::FromStr;
use uuid::Uuid;

#[macro_use]
extern crate string_cache;
extern crate pink_spider;

use pink_spider::error::Error;
use pink_spider::scraper::extract;
use pink_spider::model::{Model, Track, Playlist, Album, Entry, Enclosure, Provider, PaginatedCollection};
use rustc_serialize::json::{ToJson, Json};
use pink_spider::youtube;
use pink_spider::soundcloud;

pub fn index_entries(req: &mut Request) -> IronResult<Response> {
    let (page, per_page) = pagination_params(req);
    let entries          = Entry::find(page, per_page);
    let json_obj: Json   = entries.to_json();
    let json_str: String = json_obj.to_string();
    Ok(Response::with((status::Ok, application_json(), json_str)))
}

pub fn index<T: Enclosure>(req: &mut Request) -> IronResult<Response> {
    let (page, per_page) = pagination_params(req);
    let enclosures       = T::find(page, per_page);
    let json_obj: Json   = enclosures.to_json();
    let json_str: String = json_obj.to_string();
    Ok(Response::with((status::Ok, application_json(), json_str)))
}

pub fn index_by_entry<T: Enclosure>(req: &mut Request) -> IronResult<Response> {
    let ref entry_id = req.extensions.get::<Router>().unwrap().find("entry_id").unwrap();
    let uuid = try!(Uuid::parse_str(entry_id).map_err(|_| Error::Unprocessable));
    let items = T::find_by_entry_id(uuid);
    let col = PaginatedCollection {
        page:     0,
        per_page: items.len() as i64,
        total:    items.len() as i64,
        items:    items,
    };
    let json_obj: Json   = col.to_json();
    let json_str: String = json_obj.to_string();
    Ok(Response::with((status::Ok, application_json(), json_str)))
}

pub fn playlistify(req: &mut Request) -> IronResult<Response> {
    pub fn playlistify2(req: &mut Request) -> Result<Response, Error> {
        let ref params  = try!(req.get_ref::<UrlEncodedQuery>());
        let url         = try!(params.get("url").ok_or(Error::BadRequest));
        let defaults    = &vec!("false".to_string());
        let force_param = params.get("force").unwrap_or(defaults);
        let force       = force_param.len() > 0 && &force_param[0] == "true";
        let entry       = try!(find_or_playlistify_entry(&url[0], force));
        let json_obj    = entry.to_json() as Json;
        let json_str    = json_obj.to_string() as String;
        Ok(Response::with((status::Ok, application_json(), json_str)))
    }
    playlistify2(req).map_err(|err| IronError::from(err))
}

pub fn find_or_playlistify_entry(url: &str, force: bool) -> Result<Entry, Error> {
    match Entry::find_by_url(url) {
        Ok(entry) => {
            println!("Get entry from database cache: {}", url);
            if force {
                println!("Update entry: {}", url);
                let entry = try!(playlistify_entry(entry));
                Ok(entry)
            } else {
                Ok(entry)
            }
        },
        Err(_) => {
            let entry = try!(Entry::create_by_url(url.to_string()));
            let entry = try!(playlistify_entry(entry));
            println!("Create new entry to database cache: {}", url);
            Ok(entry)
        },
    }
}

pub fn playlistify_entry(entry: Entry) -> Result<Entry, Error> {
    let mut e = entry.clone();
    let product = try!(extract(&entry.url));
    match product.og_obj {
        Some(og_obj) => {
            e.title       = Some(og_obj.title);
            e.description = og_obj.description;
            e.locale      = og_obj.locale;
            e.visual_url  = og_obj.images.first().map(|i| i.url.clone());
        },
        None => (),
    }
    for t in product.tracks {
        let new_track = try!(Track::find_or_create(t.provider, t.identifier.to_string()));
        let mut track = t.clone();
        track.id      = new_track.id;
        try!(track.fetch_detail().save());
        match entry.tracks.iter().find(|&t| t.id == track.id) {
            Some(_) => (),
            None    => try!(e.add_track(track.clone())),
        }
    }
    for p in product.playlists {
        let new_playlist = try!(Playlist::find_or_create(p.provider, p.identifier.to_string()));
        let mut playlist = p.clone();
        playlist.id      = new_playlist.id;
        try!(playlist.save());
        match entry.playlists.iter().find(|&p| p.id == playlist.id) {
            Some(_) => (),
            None    => try!(e.add_playlist(playlist.clone())),
        }
    }
    try!(e.save());
    Ok(e)
}

pub fn update_track(req: &mut Request) -> IronResult<Response> {
    let mut track = try!(Track::find_by_id(&query_as_string(req, "track_id")));
    match param_as_string(req, "title") {
        Some(title) => track.title = title,
        None        => (),
    }
    match param_as_string(req, "url") {
        Some(url) => track.url = url,
        None      => (),
    }
    let track = match track.provider {
        Provider::YouTube => match youtube::fetch_video(&track.identifier) {
            Ok(video) => track.update_with_yt_video(&video),
            Err(_)    => track.disable(),
        },
        Provider::SoundCloud => match soundcloud::fetch_track(&track.identifier) {
            Ok(sc_track) => track.update_with_sc_track(&sc_track),
            Err(_)       => track.disable(),
        },
        _ => &mut track,
    };
    try!(track.save());
    let res = track.to_json().to_string();
    Ok(Response::with((status::Ok, application_json(), res)))
}

pub fn show<T: Enclosure>(req: &mut Request) -> IronResult<Response> {
    let provider   = req.extensions.get::<Router>().unwrap().find("provider").unwrap();
    let identifier = req.extensions.get::<Router>().unwrap().find("id").unwrap();
    let p = &Provider::new(provider.to_string());
    match T::find_by(p, identifier) {
        Ok(enclosure) => {
            Ok(Response::with((status::Ok,
                               application_json(),
                               enclosure.to_json().to_string())))
        },
        Err(e) => Ok(e.as_response())
    }
}

pub fn show_by_id<T: Enclosure>(req: &mut Request) -> IronResult<Response> {
    let ref id = req.extensions.get::<Router>().unwrap().find("id").unwrap();
    match T::find_by_id(id) {
        Ok(enclosure) => {
            Ok(Response::with((status::Ok,
                               application_json(),
                               enclosure.to_json().to_string())))
        },
        Err(e) => Ok(e.as_response())
    }
}

fn param_as_string(req: &mut Request, key: &str) -> Option<String> {
    match req.get_ref::<UrlEncodedBody>() {
        Ok(ref params) => match params.get(key) {
            Some(val) => Some(val[0].clone()),
            None      => None
        },
        Err(_) => None
    }
}

fn query_as_string(req: &mut Request, key: &str) -> String {
    return req.extensions.get::<Router>().unwrap()
        .find(key).unwrap().to_string();
}

fn pagination_params(req: &mut Request) -> (i64, i64) {
    match req.get_ref::<UrlEncodedQuery>() {
        Ok(ref params) =>
            (params.get("page").unwrap()[0].to_string().parse::<i64>().unwrap(),
             params.get("per_page").unwrap()[0].to_string().parse::<i64>().unwrap()),
        Err(_) =>
            (0, 10)
    }
}

fn application_json() -> Mime {
    Mime::from_str("application/json").ok().unwrap()
}

pub fn main() {
    let path = Path::new("public");
    let mut mount = Mount::new();
    mount.mount("/web/", Static::new(Path::new(path)));
    let router = router!(
        playlistify:              get  "/playlistify"                 => playlistify,
        show_track_by_id:         get  "/tracks/:id"                  => show_by_id::<Track>,
        show_track:               get  "/tracks/:provider/:id"        => show::<Track>,
        update_track:             post "/tracks/:track_id"            => update_track,
        show_playlist_by_id:      get  "/playlists/:id"               => show_by_id::<Playlist>,
        show_playlist:            get  "/playlists/:provider/:id"      => show::<Playlist>,
        show_album_by_id:         get  "/albums/:id"                  => show_by_id::<Album>,
        show_album:               get  "/albums/:provider/:id"        => show::<Album>,
        index_entries:            get  "/entries"                     => index_entries,
        index_tracks:             get  "/tracks"                      => index::<Track>,
        index_tracks_by_entry:    get  "/entries/:entry_id/tracks"    => index_by_entry::<Track>,
        index_playlists:          get  "/playlists"                   => index::<Playlist>,
        index_playlists_by_entry: get  "/entries/:entry_id/playlists" => index_by_entry::<Playlist>,
        index_albums:             get  "/albums"                      => index::<Album>,
        index_albums_by_entry:    get  "/entries/:entry_id/albums"    => index_by_entry::<Album>,
        web:                   get  "/*"                        => mount,
    );
    let port_str = match std::env::var("PORT") {
        Ok(n)    => n,
        Err(_) => "8080".to_string()
    };
    let port: u16 = match port_str.trim().parse() {
        Ok(n) => n,
        Err(_) => {
            println!("Faild to parse port");
            return;
        }
    };
    println!("PORT {}", port_str);
    let ip = Ipv4Addr::new(0, 0, 0, 0);
    Iron::new(router).http(SocketAddrV4::new(ip, port)).unwrap();
}
<|endoftext|>


<commit_before>// Copyright 2015 The Athena Developers.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

extern crate jamkit;
extern crate rand;

use rand::{Rng};

fn main() {
    let mut graphics = jamkit::Graphics::init();

    let map = Map::new(&graphics, "assets/tiles.png");

    'main: loop {
        for event in graphics.poll_events() {
            match event {
                jamkit::Event::Closed => break 'main,
                _ => {}
            }
        }

        let mut frame = jamkit::Frame::start(&graphics);

        map.draw(&mut frame);

        frame.finish();
    }
}

struct Map {
    tileset: jamkit::Texture,
    data: Vec<u32>
}

impl Map {
    fn new(graphics: &jamkit::Graphics, tileset: &str) -> Map {
        let mut rng = rand::thread_rng();

        Map {
            tileset: jamkit::Texture::load(&graphics, tileset),
            data: [0u32; 256*256].iter().map(|_| rng.gen::<u32>() % 2).collect()
        }
    }

    fn draw(&self, frame: &mut jamkit::Frame) {
        for tile in 0..self.data.len() {
            let (x, y) = (tile as i32 / 256 * 64, tile as i32 % 256i32 * 64);

            let dest = [x, y, x + 64, y + 64];
            let src = if self.data[tile] == 0 {
                [0, 0, 32, 32]
            } else {
                [32, 0, 64, 32]
            };

            frame.draw(&self.tileset, Some(src), dest);
        }
    }
}
<commit_msg>Add support for batching draws with the same texture<commit_after>// Copyright 2015 The Athena Developers.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

extern crate jamkit;
extern crate rand;

use rand::{Rng};

fn main() {
    let mut graphics = jamkit::Graphics::init();

    let map = Map::new(&graphics, "assets/tiles.png");

    'main: loop {
        for event in graphics.poll_events() {
            match event {
                jamkit::Event::Closed => break 'main,
                _ => {}
            }
        }

        let mut frame = jamkit::Frame::start(&graphics);

        map.draw(&mut frame);

        frame.finish();
    }
}

struct Map {
    tileset: jamkit::Texture,
    size: (u32, u32),
    data: Vec<u32>
}

impl Map {
    fn new(graphics: &jamkit::Graphics, tileset: &str) -> Map {
        let width = 50; //256
        let height = 50;
        let mut rng = rand::thread_rng();

        Map {
            tileset: jamkit::Texture::load(&graphics, tileset),
            size: (width, height),
            data: (0u32..width*height).map(|_| rng.gen::<u32>() % 2).collect()
        }
    }

    fn draw(&self, frame: &mut jamkit::Frame) {
        for tile in 0..self.data.len() {
            let (x, y) = (
                tile as i32 / self.size.0 as i32 * 64,
                tile as i32 % self.size.1 as i32 * 64);

            let dest = [x, y, x + 64, y + 64];
            let src = if self.data[tile] == 0 {
                [0, 0, 32, 32]
            } else {
                [32, 0, 64, 32]
            };

            frame.draw(&self.tileset, Some(src), dest);
        }
    }
}
<|endoftext|>


<commit_before>extern crate sdl;
extern crate rand;

use rand::distributions::{IndependentSample, Range};
use sdl::video::{SurfaceFlag, VideoFlag, Color};
use sdl::event::{Event, Key, Mouse};

#[derive(Copy, Clone)]
struct Spot {
    hidden: bool,
    mine: bool,
    flag: bool,
    n: u8,
}

struct Field {
    width: usize,
    height: usize,
    field: Vec<Vec<Spot>>,
}

impl Field {
    fn new(r: f32, w: usize, h: usize) -> Field {
        let bt = Range::new(0.,1.);
        let mut rng = rand::thread_rng();
        let mut field = Vec::with_capacity(h);
        for i in 0..h {
            field.push(Vec::with_capacity(w));
            for _ in 0..w {
                field[i].push(
                    Spot{hidden: true,
                         mine: bt.ind_sample(&mut rng) < r,
                         flag: false,
                         n: 0}
                );
            }
        }
        let mut f = Field {width: w, height: h, field: field};
        f.count_field();
        f
    }

    fn swap_mine(&mut self, x: usize, y: usize) {
        let f = self.field[y][x];
        self.field[y][x].mine = !f.mine;
    }

    fn show_spot(&mut self, x: usize, y: usize) {
        if x > self.width {return;}
        if y > self.height {return;}
        let f = self.field[y][x];
        if !f.flag {
            self.field[y as usize][x as usize].hidden = false;
        }
    }

    fn flag_spot(&mut self, x: usize, y: usize) {
        let f = self.field[y][x];
        if f.hidden {
            self.field[y][x].flag = !f.flag;
        }
    }

    fn count_field(&mut self) {
        for i in 0..self.width {
            for j in 0..self.height {
                self.field[j][i].n = self.count_neighbors(i, j);
            }
        }
    }

    fn count_neighbors(&self, x: usize, y: usize) -> u8 {
        let mut n = 0;
        for i in 0..3 {
            if x+i == 0 || x+i > self.width {continue;}
            for j in 0..3 {
                if i == 1 && j == 1 {continue;}
                if y+j == 0 || y+j > self.height {continue;}
                if self.field[y+j-1][x+i-1].mine {n += 1}
            }
        }
        n
    }

    fn count_flags(&self, x: usize, y: usize) -> u8 {
        let mut n = 0;
        for i in 0..3 {
            if y+i == 0 || y+i == self.height+1 {continue;}
            for j in 0..3 {
                if i == 1 && j == 1 {continue;}
                if x+j == 0 || x+j == self.width+1 {continue;}
                if self.field[y+i-1][x+j-1].flag {n += 1}
            }
        }
        n
    }
}

struct Screen {
    width: isize,
    height: isize,
    spot_length: u16,
    surface: sdl::video::Surface,
}

impl Screen {
    fn new(w: isize, h: isize, l: u16) -> Screen {
        sdl::init(&[sdl::InitFlag::Video]);
        sdl::wm::set_caption("mines", "mines");

        let s = match sdl::video::set_video_mode(w, h, 32,
                                                 &[SurfaceFlag::HWSurface],
                                                 &[VideoFlag::DoubleBuf]) {
            Ok(s) => s,
            Err(err) => panic!("failed to set video mode: {}", err)
        };
        Screen {width: w, height: h, spot_length: l, surface: s}
    }

    fn draw_square(&self, x: u16, y: u16, w: u16, (r,g,b): (u8, u8, u8)) {
        self.surface.fill_rect(
            Some(sdl::Rect {x: x as i16, y: y as i16, w: w, h: w}),
            Color::RGB(r, g, b)
        );
    }

    fn draw_num(&self, n: u8, x: u16, y: u16) {
        self.draw_square(x, y, self.spot_length-1,
            (255, 255, 255)
        );
        let mut n = n;
        let sub = (self.spot_length-1)/3;
        let pack = (self.spot_length - sub*3)/2;
        let color = if n == 1 {
            (100,100,255)
        }else if n == 2 {
            (0,255,0)
        }else if n == 3 {
            (255,0,0)
        }else if n == 4 {
            (0,0,255)
        }else if n == 5 {
            (200,50,0)
        }else if n == 6 {
            (0,255,255)
        }else if n == 7 {
            (0,0,0)
        }else {
            (150,150,150)
        };

        loop {
            if n == 0 {break;}
            else if n == 1{
                self.draw_square(sub+x+pack, sub+y+pack, sub-1, color);
                break;
            }else if n == 2{
                self.draw_square(x+pack, y+pack, sub-1,  color);
                self.draw_square(sub*2+x+pack, sub*2+y+pack, sub-1, color);
                break;
            }else if n == 3{
                self.draw_square(sub+x+pack, sub+y+pack, sub-1, color);
                n = 2;
            }else if n == 4{
                self.draw_square(x+pack, sub*2+y+pack, sub-1, color);
                self.draw_square(sub*2+x+pack, y+pack, sub-1, color);
                n = 2;
            }else if n == 5{
                self.draw_square(sub+x+pack, sub+y+pack, sub-1, color);
                n = 4;
            }else if n == 6{
                self.draw_square(x+pack, sub+y+pack, sub-1, color);
                self.draw_square(sub*2+x+pack, sub+y+pack, sub-1, color);
                n = 4;
            }else if n == 7{
                self.draw_square(sub+x+pack, sub+y+pack, sub-1, color);
                n = 6;
            }else if n == 8{
                self.draw_square(sub+x+pack, y+pack, sub-1, color);
                self.draw_square(sub+x+pack, sub*2+y+pack, sub-1, color);
                n = 6;
            }
        }
    }

    fn draw_field(&self, ref field: &Field) {
        let length = self.spot_length;
        let mut n = 0;
        for ref i in field.field.iter() {
            let mut m = 0;
            for ref sq in i.iter() {
                if sq.hidden {
                    self.draw_square(m*length+1,
                        n*length+1,
                        length-1,
                        (180, 180, 180)
                    );
                    if sq.flag {
                        self.draw_square(m*length+4,
                            n*length+4,
                            length-7,
                            (255, 0, 0)
                        );
                    }
                }else{
                    if sq.mine {
                        self.draw_square(m*length+1,
                            n*length+1,
                            length-1,
                            (0, 0, 0)
                        );
                    }else{
                        self.draw_num(
                            sq.n,
                            m*length+1,
                            n*length+1
                        );
                    }
                }
                m += 1;
            }
            n += 1;
        }
    }
}

fn main() {
    const WIDTH: usize = 30;
    const HEIGHT: usize = 20;
    const SIZE: usize = 35;
    const R: f32 = 0.1;

    let mut field = Field::new(R, WIDTH, HEIGHT);

    let screen = Screen::new((SIZE*WIDTH) as isize + 1, (SIZE*HEIGHT) as isize + 1, SIZE as u16);

    loop {
        match sdl::event::poll_event() {
            Event::Quit => break,
            Event::MouseButton(b, down, mx, my) => {
                if down {
                    if b == Mouse::Left {
                        field.show_spot(mx as usize/SIZE, my as usize/SIZE);
                    }
                    else if b == Mouse::Right {
                        field.flag_spot(mx as usize/SIZE, my as usize/SIZE);
                    }
                }
            },
            Event::Key(k, down, _, _) => {
                if down {
                    if k == Key::Escape {
                        break;
                    }
                    if k == Key::R {
                        field = Field::new(R, WIDTH, HEIGHT);
                    }
                }
            },
            _ => {}
        }
        screen.draw_field(&field);
        screen.surface.flip();
    }

    sdl::quit();
}
<commit_msg>flag-show almost working<commit_after>extern crate sdl;
extern crate rand;

use rand::distributions::{IndependentSample, Range};
use sdl::video::{SurfaceFlag, VideoFlag, Color};
use sdl::event::{Event, Key, Mouse};

#[derive(Copy, Clone)]
struct Spot {
    hidden: bool,
    mine: bool,
    flag: bool,
    n: u8,
}

struct Field {
    width: usize,
    height: usize,
    field: Vec<Vec<Spot>>,
}

impl Field {
    fn new(r: f32, w: usize, h: usize) -> Field {
        let bt = Range::new(0.,1.);
        let mut rng = rand::thread_rng();
        let mut field = Vec::with_capacity(h);
        for i in 0..h {
            field.push(Vec::with_capacity(w));
            for _ in 0..w {
                field[i].push(
                    Spot{hidden: true,
                         mine: bt.ind_sample(&mut rng) < r,
                         flag: false,
                         n: 0}
                );
            }
        }
        let mut f = Field {width: w, height: h, field: field};
        f.count_field();
        f
    }

    fn swap_mine(&mut self, x: usize, y: usize) {
        let f = &mut self.field[y][x];
        f.mine = !f.mine;
    }

    fn show_spot(&mut self, x: usize, y: usize) {
        if x >= self.width {return;}
        if y >= self.height {return;}
        {
            let f = &mut self.field[y][x];
            if f.flag {return;}
            if f.hidden {
                f.hidden = false;
                return;
            }
        }
        if self.field[y][x].n != self.count_flags(x, y) {return;}
        for i in 0..3 {
            if x+i == 0 || x+i > self.width {continue;}
            for j in 0..3 {
                if y+j == 0 || y+j > self.height {continue;}
                if i ==1 && j == 1 {continue;}
                let f = self.field[y+j-1][x+i-1];
                if f.hidden {
                    self.show_spot(x+i-1, y+j-1);
                }
            }
        }
    }

    fn flag_spot(&mut self, x: usize, y: usize) {
        let f = &mut self.field[y][x];
        if f.hidden {
            f.flag = !f.flag;
        }
    }

    fn count_field(&mut self) {
        for i in 0..self.width {
            for j in 0..self.height {
                self.field[j][i].n = self.count_neighbors(i, j);
            }
        }
    }

    fn count_neighbors(&self, x: usize, y: usize) -> u8 {
        let mut n = 0;
        for i in 0..3 {
            if x+i == 0 || x+i > self.width {continue;}
            for j in 0..3 {
                if y+j == 0 || y+j > self.height {continue;}
                if i == 1 && j == 1 {continue;}
                if self.field[y+j-1][x+i-1].mine {n += 1}
            }
        }
        n
    }

    fn count_flags(&self, x: usize, y: usize) -> u8 {
        let mut n = 0;
        for i in 0..3 {
            if x+i == 0 || x+i > self.height {continue;}
            for j in 0..3 {
                if y+j == 0 || y+j > self.height {continue;}
                if i == 1 && j == 1 {continue;}
                if self.field[y+j-1][x+i-1].flag {n += 1}
            }
        }
        n
    }
}

struct Screen {
    width: isize,
    height: isize,
    spot_length: u16,
    surface: sdl::video::Surface,
}

impl Screen {
    fn new(w: isize, h: isize, l: u16) -> Screen {
        sdl::init(&[sdl::InitFlag::Video]);
        sdl::wm::set_caption("mines", "mines");

        let s = match sdl::video::set_video_mode(w, h, 32,
                                                 &[SurfaceFlag::HWSurface],
                                                 &[VideoFlag::DoubleBuf]) {
            Ok(s) => s,
            Err(err) => panic!("failed to set video mode: {}", err)
        };
        Screen {width: w, height: h, spot_length: l, surface: s}
    }

    fn draw_square(&self, x: u16, y: u16, w: u16, (r,g,b): (u8, u8, u8)) {
        self.surface.fill_rect(
            Some(sdl::Rect {x: x as i16, y: y as i16, w: w, h: w}),
            Color::RGB(r, g, b)
        );
    }

    fn draw_num(&self, n: u8, x: u16, y: u16) {
        self.draw_square(x, y, self.spot_length-1,
            (255, 255, 255)
        );
        let mut n = n;
        let sub = (self.spot_length-1)/3;
        let pack = (self.spot_length - sub*3)/2;
        let color = if n == 1 {
            (100,100,255)
        }else if n == 2 {
            (0,255,0)
        }else if n == 3 {
            (255,0,0)
        }else if n == 4 {
            (0,0,255)
        }else if n == 5 {
            (200,50,0)
        }else if n == 6 {
            (0,255,255)
        }else if n == 7 {
            (0,0,0)
        }else {
            (150,150,150)
        };

        loop {
            if n == 0 {break;}
            else if n == 1{
                self.draw_square(sub+x+pack, sub+y+pack, sub-1, color);
                break;
            }else if n == 2{
                self.draw_square(x+pack, y+pack, sub-1,  color);
                self.draw_square(sub*2+x+pack, sub*2+y+pack, sub-1, color);
                break;
            }else if n == 3{
                self.draw_square(sub+x+pack, sub+y+pack, sub-1, color);
                n = 2;
            }else if n == 4{
                self.draw_square(x+pack, sub*2+y+pack, sub-1, color);
                self.draw_square(sub*2+x+pack, y+pack, sub-1, color);
                n = 2;
            }else if n == 5{
                self.draw_square(sub+x+pack, sub+y+pack, sub-1, color);
                n = 4;
            }else if n == 6{
                self.draw_square(x+pack, sub+y+pack, sub-1, color);
                self.draw_square(sub*2+x+pack, sub+y+pack, sub-1, color);
                n = 4;
            }else if n == 7{
                self.draw_square(sub+x+pack, sub+y+pack, sub-1, color);
                n = 6;
            }else if n == 8{
                self.draw_square(sub+x+pack, y+pack, sub-1, color);
                self.draw_square(sub+x+pack, sub*2+y+pack, sub-1, color);
                n = 6;
            }
        }
    }

    fn draw_field(&self, ref field: &Field) {
        let length = self.spot_length;
        let mut n = 0;
        for ref i in field.field.iter() {
            let mut m = 0;
            for ref sq in i.iter() {
                if sq.hidden {
                    self.draw_square(m*length+1,
                        n*length+1,
                        length-1,
                        (180, 180, 180)
                    );
                    if sq.flag {
                        self.draw_square(m*length+4,
                            n*length+4,
                            length-7,
                            (255, 0, 0)
                        );
                    }
                }else{
                    if sq.mine {
                        self.draw_square(m*length+1,
                            n*length+1,
                            length-1,
                            (0, 0, 0)
                        );
                    }else{
                        self.draw_num(
                            sq.n,
                            m*length+1,
                            n*length+1
                        );
                    }
                }
                m += 1;
            }
            n += 1;
        }
    }
}

fn main() {
    const WIDTH: usize = 30;
    const HEIGHT: usize = 20;
    const SIZE: usize = 35;
    const R: f32 = 0.1;

    let mut field = Field::new(R, WIDTH, HEIGHT);

    let screen = Screen::new((SIZE*WIDTH) as isize + 1,
                             (SIZE*HEIGHT) as isize + 1, SIZE as u16);

    loop {
        match sdl::event::poll_event() {
            Event::Quit => break,
            Event::MouseButton(b, down, mx, my) => {
                if down {
                    if b == Mouse::Left {
                        field.show_spot(mx as usize/SIZE, my as usize/SIZE);
                    }
                    else if b == Mouse::Right {
                        field.flag_spot(mx as usize/SIZE, my as usize/SIZE);
                    }
                }
            },
            Event::Key(k, down, _, _) => {
                if down {
                    if k == Key::Escape {
                        break;
                    }
                    if k == Key::R {
                        field = Field::new(R, WIDTH, HEIGHT);
                    }
                }
            },
            _ => {}
        }
        screen.draw_field(&field);
        screen.surface.flip();
    }

    sdl::quit();
}
<|endoftext|>


<commit_before>extern crate piston_window;

mod entity;

use piston_window::*;
use entity::Entity;
use std::time::SystemTime;

#[derive(Debug, Clone)]
pub struct Point(f64, f64);

const MU: f64 = 1.0;
const WIDTH: u32 = 1024;
const HEIGHT: u32 = 800;
const WAIT_TIME: u32 = 300_000_000; //nanoseconds

fn main() {
    let title = "Goober";
    let mut inputs_submitted = false;
    let mut inputs = Vec::new();
    let mut timestamp = SystemTime::now();
    let mut i: usize = 0;
    let mut squares = vec![
        Entity::new(Point(0.0, 0.0), [0.3, 0.0, 0.7, 0.5], 25.0, 25.0),
        Entity::new(Point(100.0, 100.0), [0.7, 0.0, 0.3, 0.5], 25.0, 25.0)
    ];

    let mut window: PistonWindow = WindowSettings::new(title, [WIDTH, HEIGHT])
        .exit_on_esc(true)
        .build()
        .unwrap_or_else(|e| panic!("Failed to build PistonWindow: {}", e));

    let sprite_path = "./assets/green-blob-hi.png";
    let sprite = Texture::from_path(
            &mut window.factory,
            &sprite_path,
            Flip::None,
            &TextureSettings::new())
            .unwrap();

    let font = "assets/FiraSans-Regular.ttf";
    let factory = window.factory.clone();
    let mut glyphs = Glyphs::new(font, factory).unwrap();

    while let Some(e) = window.next() {

        if let Some(_) = e.render_args() {
            window.draw_2d(&e, |c, g| {
                clear([0.8, 0.0, 0.8, 1.0], g);
                for sq in &squares {
                    image(&sprite, c.transform.trans(sq.geometry()[0], sq.geometry()[1]), g);
                }

                text::Text::new_color([0.0, 1.0, 0.0, 1.0], 32).draw(
                    &format_inputs(&inputs),
                    &mut glyphs,
                    &c.draw_state,
                    c.transform.trans(40.0, 40.0), g
                );
            });
        }

        if let Some(button) = e.press_args() {
            if !inputs_submitted {
                match button {
                    Button::Keyboard(Key::Up)     => inputs.push(button),
                    Button::Keyboard(Key::Down)   => inputs.push(button),
                    Button::Keyboard(Key::Left)   => inputs.push(button),
                    Button::Keyboard(Key::Right)  => inputs.push(button),
                    Button::Keyboard(Key::Space)  => inputs.push(button),
                    Button::Keyboard(Key::A)      => squares.push(
                        Entity::new(
                            Point(0.0, 0.0),
                            [0.3, 0.0, 0.7, 0.5],
                            25.0, 25.0
                        )
                    ),
                    Button::Keyboard(Key::Return) => {inputs_submitted = true; inputs.reverse()},
                    _ => ()
                }
            }
        }

        if let Some(_) = e.update_args() {
            if inputs_submitted && wait_time_elapsed(timestamp) {
                timestamp = SystemTime::now();
                match inputs.pop() {
                    Some(button) => handle_input(button, &mut squares, &mut i),
                    None => ()
                }
            }
            for square in squares.iter_mut() {
                square.nudge();
            }
        }
    }

    fn handle_input(button: Button, squares: &mut [Entity], i: &mut usize) {
        match button {
            Button::Keyboard(Key::Up)     => squares[*i].adjust_dy(-1.0),
            Button::Keyboard(Key::Down)   => squares[*i].adjust_dy(1.0),
            Button::Keyboard(Key::Left)   => squares[*i].adjust_dx(-1.0),
            Button::Keyboard(Key::Right)  => squares[*i].adjust_dx(1.0),
            Button::Keyboard(Key::Space)  => if *i == squares.len() - 1 { *i = 0 } else { *i += 1 },
            _ => ()
        }
    }

    fn wait_time_elapsed(timestamp: SystemTime) -> bool {
        match timestamp.elapsed() {
            Ok(elapsed) => elapsed.subsec_nanos() >= WAIT_TIME,
            Err(e) => {println!("{:?}", e); false}
        }
    }

    fn format_inputs(inputs: &Vec<Button>) -> String {
        inputs.iter().map(|button|
            match *button {
                Button::Keyboard(Key::Up)    => "↑",
                Button::Keyboard(Key::Down)  => "↓",
                Button::Keyboard(Key::Left)  => "←",
                Button::Keyboard(Key::Right) => "→",
                Button::Keyboard(Key::Space) => "↔",
                _ => ""
            }
        ).collect::<Vec<_>>().concat()
    }
}
<commit_msg>Display symbol for adding goobs<commit_after>extern crate piston_window;

mod entity;

use piston_window::*;
use entity::Entity;
use std::time::SystemTime;

#[derive(Debug, Clone)]
pub struct Point(f64, f64);

const MU: f64 = 1.0;
const WIDTH: u32 = 1024;
const HEIGHT: u32 = 800;
const WAIT_TIME: u32 = 300_000_000; //nanoseconds

fn main() {
    let title = "Goober";
    let mut inputs_submitted = false;
    let mut inputs = Vec::new();
    let mut timestamp = SystemTime::now();
    let mut i: usize = 0;
    let mut goobs = vec![
        Entity::new(Point(0.0, 0.0), [0.3, 0.0, 0.7, 0.5], 25.0, 25.0)
    ];

    let mut window: PistonWindow = WindowSettings::new(title, [WIDTH, HEIGHT])
        .exit_on_esc(true)
        .build()
        .unwrap_or_else(|e| panic!("Failed to build PistonWindow: {}", e));

    let sprite_path = "./assets/green-blob-hi.png";
    let sprite = Texture::from_path(
            &mut window.factory,
            &sprite_path,
            Flip::None,
            &TextureSettings::new())
            .unwrap();

    let font = "assets/FiraSans-Regular.ttf";
    let factory = window.factory.clone();
    let mut glyphs = Glyphs::new(font, factory).unwrap();

    while let Some(e) = window.next() {

        if let Some(_) = e.render_args() {
            window.draw_2d(&e, |c, g| {
                clear([0.8, 0.0, 0.8, 1.0], g);
                for goob in &goobs {
                    image(&sprite, c.transform.trans(goob.geometry()[0], goob.geometry()[1]), g);
                }

                text::Text::new_color([0.0, 1.0, 0.0, 1.0], 16).draw(
                    &format_inputs(&inputs),
                    &mut glyphs,
                    &c.draw_state,
                    c.transform.trans(40.0, 40.0), g
                );
            });
        }

        if let Some(button) = e.press_args() {
            if !inputs_submitted {
                match button {
                    Button::Keyboard(Key::Up)     => inputs.push(button),
                    Button::Keyboard(Key::Down)   => inputs.push(button),
                    Button::Keyboard(Key::Left)   => inputs.push(button),
                    Button::Keyboard(Key::Right)  => inputs.push(button),
                    Button::Keyboard(Key::Space)  => inputs.push(button),
                    Button::Keyboard(Key::A)      => {
                        goobs.push(
                            Entity::new(
                            Point(0.0, 0.0),
                            [0.3, 0.0, 0.7, 0.5],
                            25.0, 25.0
                            )
                        );
                        inputs.push(button);
                    },
                    Button::Keyboard(Key::Return) => {inputs_submitted = true; inputs.reverse()},
                    _ => ()
                }
            }
        }

        if let Some(_) = e.update_args() {
            if inputs_submitted && wait_time_elapsed(timestamp) {
                timestamp = SystemTime::now();
                match inputs.pop() {
                    Some(button) => handle_input(button, &mut goobs, &mut i),
                    None => ()
                }
            }
            for goob in goobs.iter_mut() {
                goob.nudge();
            }
        }
    }

    fn handle_input(button: Button, goobs: &mut [Entity], i: &mut usize) {
        match button {
            Button::Keyboard(Key::Up)     => goobs[*i].adjust_dy(-1.0),
            Button::Keyboard(Key::Down)   => goobs[*i].adjust_dy(1.0),
            Button::Keyboard(Key::Left)   => goobs[*i].adjust_dx(-1.0),
            Button::Keyboard(Key::Right)  => goobs[*i].adjust_dx(1.0),
            Button::Keyboard(Key::Space)  => if *i == goobs.len() - 1 { *i = 0 } else { *i += 1 },
            _ => ()
        }
    }

    fn wait_time_elapsed(timestamp: SystemTime) -> bool {
        match timestamp.elapsed() {
            Ok(elapsed) => elapsed.subsec_nanos() >= WAIT_TIME,
            Err(e) => {println!("{:?}", e); false}
        }
    }

    fn format_inputs(inputs: &Vec<Button>) -> String {
        inputs.iter().map(|button|
            match *button {
                Button::Keyboard(Key::Up)    => "↑",
                Button::Keyboard(Key::Down)  => "↓",
                Button::Keyboard(Key::Left)  => "←",
                Button::Keyboard(Key::Right) => "→",
                Button::Keyboard(Key::Space) => "↔",
                Button::Keyboard(Key::A)     => "+",
                _ => ""
            }
        ).collect::<Vec<_>>().concat()
    }
}
<|endoftext|>


<commit_before>
mod curses;

use std::ffi::CString;

use curses::*;

enum DrawMe {
    //Circle { radius : i32, x : i32, y : i32 },
    Rec { width : i32, height : i32, x : i32, y : i32 },
    /*VHall { length : i32, x : i32, y : i32 },
    HHall { length : i32, x : i32, y : i32 },*/
    // TODO add color
    // TODO add background color
    // TODO add point case
    // TODO add overlap
    // TODO can probably have a struct represent common items (x,y, color, etc)
}

unsafe fn render_shape( s : &DrawMe ) {
    match s {
        &DrawMe::Rec { width, height, x, y } => render_rec( width, height, x, y ),
        _ => (),
    }
}

unsafe fn render_rec( w : i32, h : i32, x : i32, y : i32 ) {
    let c = CString::new( "." ).unwrap();

    let mut h2 = h;
    while h2 > 0 {
        let mut w2 = w;
        while w2 > 0 {
            mvprintw( y + h2, x + w2, c.as_ptr() );
            w2 -= 1;
        }
        h2 -= 1;
    }
}

fn main() {
    let mut x = 0;
    let mut y = 0;
    unsafe {
        initscr();
        cbreak();
        noecho();

        let mut c = getch();
        let mut shapes : Vec<DrawMe> = vec! [];

        while c as u8 as char != 'q' {
            let c2 = c as u8 as char;

            match c2 {
                /*'c' => {
                    shapes.push( DrawMe::Circle { radius: 5, x: x, y: y } );
                },*/
                'r' => {
                    shapes.push( DrawMe::Rec { width: 2, height: 2, x: x, y: y } );
                },
                'j' => {
                    y+=1;
                },
                'k' => {
                    y-=1;
                },
                'l' => {
                    x+=1;
                },
                'h' => {
                    x-=1;
                },
                _ => (),
            }

            for s in &shapes {
                render_shape( s );
            }

            cursor_move( y, x );
      //      clear();
            refresh();

            c = getch();
        }

        endwin();
    }
}

<commit_msg>render rectangle<commit_after>
mod curses;

use std::ffi::CString;

use curses::*;

enum DrawMe {
    //Circle { radius : i32, x : i32, y : i32 },
    Rec { width : i32, height : i32, x : i32, y : i32 },
    /*VHall { length : i32, x : i32, y : i32 },
    HHall { length : i32, x : i32, y : i32 },*/
    // TODO add color
    // TODO add background color
    // TODO add point case
    // TODO add overlap
    // TODO can probably have a struct represent common items (x,y, color, etc)
}

unsafe fn render_shape( s : &DrawMe ) {
    match s {
        &DrawMe::Rec { width, height, x, y } => render_rec( width, height, x, y ),
        _ => (),
    }
}

unsafe fn render_rec( w : i32, h : i32, x : i32, y : i32 ) {
    let dot = CString::new( "." ).unwrap();
    let h_line = CString::new( "-" ).unwrap();
    let v_line = CString::new( "|" ).unwrap();
    let plus = CString::new( "+" ).unwrap();

    let mut h2 = h + 2;
    while h2 > 0 {
        let d : &CString = if h2 == h + 2 {
            &h_line
        } else if h2 == 1 {
            &h_line
        } else {
            &dot
        };
        let mut w2 = w;

        let other_d : &CString = if h2 == h + 2 {
            &plus
        } else if h2 == 1 {
            &plus
        } else {
            &v_line
        };
        mvprintw( y + h2, x + w2 + 1, other_d.as_ptr() );
        while w2 > 0 {
            mvprintw( y + h2, x + w2, d.as_ptr() );
            w2 -= 1;
        }
        mvprintw( y + h2, x, other_d.as_ptr() );
        h2 -= 1;
    }
}

fn main() {
    let mut x = 0;
    let mut y = 0;
    unsafe {
        initscr();
        cbreak();
        noecho();

        let mut c = getch();
        let mut shapes : Vec<DrawMe> = vec! [];

        while c as u8 as char != 'q' {
            let c2 = c as u8 as char;

            match c2 {
                /*'c' => {
                    shapes.push( DrawMe::Circle { radius: 5, x: x, y: y } );
                },*/
                'r' => {
                    shapes.push( DrawMe::Rec { width: 5, height: 8, x: x, y: y } );
                },
                'j' => {
                    y+=1;
                },
                'k' => {
                    y-=1;
                },
                'l' => {
                    x+=1;
                },
                'h' => {
                    x-=1;
                },
                _ => (),
            }

            for s in &shapes {
                render_shape( s );
            }

            cursor_move( y, x );
      //      clear();
            refresh();

            c = getch();
        }

        endwin();
    }
}

<|endoftext|>