<commit_before>//#![feature(plugin)]
//
//#[plugin]
//extern crate clippy;

extern crate cli;
extern crate getopts;
extern crate hyper;

use std::os;
use std::{env, fs, io, path};
use std::io::Read;
use getopts::Options;

static FONT_EXTENSIONS : [&'static str; 4] = ["ttf", "otf", "pcf", "bdf"];

fn main() {
    let mut opts = Options::new();
    cli::helpopt(&mut opts);
    cli::versionopt(&mut opts);
    opts.optflag("l", "list", "List installed fonts");
    opts.optopt("s", "search", "Search font", "FONTNAME");
    opts.optmulti("i", "install", "Install font(s) require a --source", "FONTNAME");
    opts.optmulti("d", "delete", "Delete font(s)", "FONTNAME");
    opts.optmulti("s", "source", "Source file to use", "FILENAME");

    let matches = cli::parse_args(&opts);

    if matches.opt_present("help") {
        println!("{}", cli::usage_string(&opts));
        return;
    }
    if matches.opt_present("version") {
        println!("{}", cli::version_string("0.0.1"));
        return;
    }
    if matches.opt_present("list") {
        list_installed_fonts();
    }
    if matches.opt_present("search") {
        search_font(&*matches.opt_str("search").unwrap());
    }
    if matches.opt_present("install") && matches.opt_present("source") {
        install_font(&*matches.opt_str("source").unwrap(), &*matches.opt_str("install").unwrap());
    } else {
        println!("{}", opts.usage("ttoo"));
    }
    if matches.opt_present("delete") {
        delete_font(&*matches.opt_str("delete").unwrap());
    }
}

fn get_font_dir() -> path::PathBuf {
    match env::consts::OS {
        "linux" => {
            match env::home_dir() {
                Some(ref p) => p.join(".fonts"),
                None => panic!("Impossible to get your home dir!")
            }
        },
        "macos" => {
            match env::home_dir() {
                Some(ref p) => p.join("Library").join("Fonts"),
                None => panic!("Impossible to get your home dir!")
            }
        },
        "windows" => {
            match os::getenv("SystemRoot") {
                Some(ref val) => path::Path::new(val).join("Fonts"),
                None => panic!("Impossible to get your font dir!")
            }
        },
        _ => unreachable!(),
    }
}

fn get_font_path(font_name: &str) -> path::PathBuf {
    get_font_dir().join(font_name.as_slice())
}

//let dir_results: Vec<_> = std::fs::read_dir("foo").and_then(|dir| dir.collect());
//
//let dir_results: Vec<_> = std::fs::read_dir("foo").and_then(|dir| dir.collect()).unwrap() ;
//
//let dir_results: Result<Vec<_>, _> = std::fs::read_dir("foo").and_then(|dir| dir.collect());

fn list_installed_fonts() {
    let font_dir = get_font_dir();
    match fs::read_dir(&font_dir) {
        Ok(fonts) => {
            let mut it_fonts = fonts.filter(|ref f| {
                FONT_EXTENSIONS.iter().find(|&ext| {
                    //*f.unwrap().path().extension().unwrap()..into_string() == *ext.to_string()
                 true
                }).is_some()
            });
            for font in it_fonts {
                if let Some(font_name) = font.ok().unwrap().path().file_name().unwrap().to_str() {
                    println!("{}", font_name);
                }
            }
        }
        Err(msg) => println!("{}", msg)
    }
}

fn search_font(font_name: &str) {
    let mut client = hyper::Client::new();
    let url = format!("http://api.github.com/search/repositories?q={}+in:name&sort=stars&order=desc", font_name);
    let resp = client.get(&*url).send();
    match resp {
        Ok(mut data) => {
            let mut body = String::new();
            data.read_to_string(&mut body).ok();
            println!("body={}", body);
        },
        Err(err) => println!("{}", err)
    };
}

fn install_font(source: &str, font_name: &str) {
    let dest_font_path = get_font_path(font_name);
    match fs::copy(&Path::new(source), &dest_font_path) {
        Ok(_) => println!("Font {} installed successfully", font_name),
        Err(msg) => println!("{}", msg)
    }
}

fn delete_font(font_name: &str) {
    let font_path = get_font_path(font_name);
    match fs::remove_file(&font_path) {
        Ok(_) => println!("Font {} deleted successfully", font_name),
        Err(msg) => println!("{}", msg)
    }
}

<commit_msg>Silent feature warnings<commit_after>//#![feature(plugin)]
//
//#[plugin]
//extern crate clippy;

#![feature(io)]
#![feature(os)]
#![feature(fs)]
#![feature(path)]
#![feature(core)]

extern crate cli;
extern crate getopts;
extern crate hyper;

use std::os;
use std::{env, fs, io, path};
use std::io::Read;
use getopts::Options;

static FONT_EXTENSIONS : [&'static str; 4] = ["ttf", "otf", "pcf", "bdf"];

fn main() {
    let mut opts = Options::new();
    cli::helpopt(&mut opts);
    cli::versionopt(&mut opts);
    opts.optflag("l", "list", "List installed fonts");
    opts.optopt("s", "search", "Search font", "FONTNAME");
    opts.optmulti("i", "install", "Install font(s) require a --source", "FONTNAME");
    opts.optmulti("d", "delete", "Delete font(s)", "FONTNAME");
    opts.optmulti("s", "source", "Source file to use", "FILENAME");

    let matches = cli::parse_args(&opts);

    if matches.opt_present("help") {
        println!("{}", cli::usage_string(&opts));
        return;
    }
    if matches.opt_present("version") {
        println!("{}", cli::version_string("0.0.1"));
        return;
    }
    if matches.opt_present("list") {
        list_installed_fonts();
    }
    if matches.opt_present("search") {
        search_font(&*matches.opt_str("search").unwrap());
    }
    if matches.opt_present("install") && matches.opt_present("source") {
        install_font(&*matches.opt_str("source").unwrap(), &*matches.opt_str("install").unwrap());
    } else {
        println!("{}", opts.usage("ttoo"));
    }
    if matches.opt_present("delete") {
        delete_font(&*matches.opt_str("delete").unwrap());
    }
}

fn get_font_dir() -> path::PathBuf {
    match env::consts::OS {
        "linux" => {
            match env::home_dir() {
                Some(ref p) => p.join(".fonts"),
                None => panic!("Impossible to get your home dir!")
            }
        },
        "macos" => {
            match env::home_dir() {
                Some(ref p) => p.join("Library").join("Fonts"),
                None => panic!("Impossible to get your home dir!")
            }
        },
        "windows" => {
            match os::getenv("SystemRoot") {
                Some(ref val) => path::Path::new(val).join("Fonts"),
                None => panic!("Impossible to get your font dir!")
            }
        },
        _ => unreachable!(),
    }
}

fn get_font_path(font_name: &str) -> path::PathBuf {
    get_font_dir().join(font_name.as_slice())
}

//let dir_results: Vec<_> = std::fs::read_dir("foo").and_then(|dir| dir.collect());
//
//let dir_results: Vec<_> = std::fs::read_dir("foo").and_then(|dir| dir.collect()).unwrap() ;
//
//let dir_results: Result<Vec<_>, _> = std::fs::read_dir("foo").and_then(|dir| dir.collect());

fn list_installed_fonts() {
    let font_dir = get_font_dir();
    match fs::read_dir(&font_dir) {
        Ok(fonts) => {
            let mut it_fonts = fonts.filter(|ref f| {
                FONT_EXTENSIONS.iter().find(|&ext| {
                    //*f.unwrap().path().extension().unwrap()..into_string() == *ext.to_string()
                 true
                }).is_some()
            });
            for font in it_fonts {
                if let Some(font_name) = font.ok().unwrap().path().file_name().unwrap().to_str() {
                    println!("{}", font_name);
                }
            }
        }
        Err(msg) => println!("{}", msg)
    }
}

fn search_font(font_name: &str) {
    let mut client = hyper::Client::new();
    let url = format!("http://api.github.com/search/repositories?q={}+in:name&sort=stars&order=desc", font_name);
    let resp = client.get(&*url).send();
    match resp {
        Ok(mut data) => {
            let mut body = String::new();
            data.read_to_string(&mut body).ok();
            println!("body={}", body);
        },
        Err(err) => println!("{}", err)
    };
}

fn install_font(source: &str, font_name: &str) {
    let dest_font_path = get_font_path(font_name);
    match fs::copy(&path::Path::new(source), &dest_font_path) {
        Ok(_) => println!("Font {} installed successfully", font_name),
        Err(msg) => println!("{}", msg)
    }
}

fn delete_font(font_name: &str) {
    let font_path = get_font_path(font_name);
    match fs::remove_file(&font_path) {
        Ok(_) => println!("Font {} deleted successfully", font_name),
        Err(msg) => println!("{}", msg)
    }
}

<|endoftext|>


<commit_before>#[macro_use]
extern crate nom;

use crate::asm::Assembler;
use crate::compiler::Compiler;
use crate::repl::REPL;
use crate::vm::{is_valid_bytecode, VM};

use std::fs;
use std::fs::File;
use std::io::Write;
use structopt::StructOpt;

pub mod asm;
pub mod compiler;
pub mod repl;
pub mod vm;

#[derive(StructOpt)]
struct CLI {
    #[structopt(parse(from_os_str))]
    program: Option<std::path::PathBuf>,
    #[structopt(short, long, parse(from_os_str))]
    output: Option<std::path::PathBuf>,
    #[structopt(short, long)]
    threads: Option<u32>,
}

fn main() {
    let args = CLI::from_args();

    match args.program {
        Some(p) => {
            let bytecode = read_bytecode(&p);
            let bc = match bytecode {
                Some(bc) => bc,
                None => compile(&p, args.output),
            };
            run_bytecode(&bc);
        }
        None => run_repl(),
    }
}

fn read_bytecode(tmp: &std::path::PathBuf) -> Option<Vec<u8>> {
    let bytecode = fs::read(&tmp).unwrap();

    match is_valid_bytecode(&bytecode) {
        true => Some(bytecode),
        false => None,
    }
}

fn read_assembly(tmp: &std::path::PathBuf) -> String {
    let contents = fs::read_to_string(tmp);
    match contents {
        Ok(_) => contents.unwrap(),
        Err(e) => {
            println!("Error reading file {:?}: {:?}", tmp.to_str(), e);
            std::process::exit(1);
        }
    }
}

fn run_repl() {
    let mut repl = REPL::new();
    repl.run();
}

fn run_bytecode(bytecode: &[u8]) {
    let mut vm = VM::new();
    if let Err(e) = vm.set_bytecode(&bytecode) {
        println!("vmerror: {}", e);
    }

    println!("Listing readonly:");
    for data in vm.ro_data.chunks(4) {
        println!("  {:?}", data);
    }
    println!("EOF");

    println!("Listing instructions:");
    for instr in vm.program.chunks(4) {
        println!("  {:?}", instr);
    }
    println!("EOF");

    let result = vm.run();
    match result {
        Ok(_) => {
            println!("Listing integer registers:");
            for (i, reg) in vm.iregisters.chunks(4).enumerate() {
                println!(
                    "  [{}]\t{}\t{}\t{}\t{}",
                    i * 4,
                    reg[0],
                    reg[1],
                    reg[2],
                    reg[3]
                );
            }
            println!("EOF");

            println!("Listing real registers:");
            for (i, reg) in vm.rregisters.chunks(4).enumerate() {
                println!(
                    "  [{}]\t{:.03}\t{:.03}\t{:.03}\t{:.03}",
                    i * 4,
                    reg[0],
                    reg[1],
                    reg[2],
                    reg[3]
                );
            }
            println!("EOF");
            std::process::exit(0);
        }
        Err(e) => {
            println!("vmerror: {}", e);
            std::process::exit(1);
        }
    }
}

fn compile(assembly: &std::path::PathBuf, output: Option<std::path::PathBuf>) -> Vec<u8> {
    let mut compiler = Compiler::new();

    let source = read_assembly(&assembly);
    let assembly = compiler.compile(&source);

    println!("assembly\n{}\nEOF", assembly);
    let mut asm = Assembler::new();
    let bytecode = asm.assemble(&assembly);
    match bytecode {
        Ok(bc) => {
            if let Some(o) = output {
                let mut f = File::create(o).expect("Unable to create file");
                f.write_all(&bc).expect("Unable to write data");
            };
            bc
        }
        Err(e) => {
            println!("assembler error: {:?}", e);
            std::process::exit(1);
        }
    }
}
<commit_msg>slimmer output<commit_after>#[macro_use]
extern crate nom;

use crate::asm::Assembler;
use crate::compiler::Compiler;
use crate::repl::REPL;
use crate::vm::{is_valid_bytecode, VM};

use std::fs;
use std::fs::File;
use std::io::Write;
use structopt::StructOpt;

pub mod asm;
pub mod compiler;
pub mod repl;
pub mod vm;

#[derive(StructOpt)]
struct CLI {
    #[structopt(parse(from_os_str))]
    program: Option<std::path::PathBuf>,

    #[structopt(short, long, parse(from_os_str))]
    output: Option<std::path::PathBuf>,

    #[structopt(short("a"), long)]
    list_asm: bool,

    #[structopt(short("b"), long)]
    list_bc: bool,

    #[structopt(short("r"), long)]
    list_reg: bool,

    #[structopt(short, long)]
    threads: Option<u32>,
}

fn main() {
    let args = CLI::from_args();

    match args.program {
        Some(p) => {
            let bytecode = read_bytecode(&p);
            let bc = match bytecode {
                Some(bc) => bc,
                None => compile(&p, args.output, args.list_asm),
            };
            run_bytecode(&bc, args.list_bc, args.list_reg);
        }
        None => run_repl(),
    }
}

fn read_bytecode(tmp: &std::path::PathBuf) -> Option<Vec<u8>> {
    let bytecode = fs::read(&tmp).unwrap();

    match is_valid_bytecode(&bytecode) {
        true => Some(bytecode),
        false => None,
    }
}

fn read_assembly(tmp: &std::path::PathBuf) -> String {
    let contents = fs::read_to_string(tmp);
    match contents {
        Ok(_) => contents.unwrap(),
        Err(e) => {
            println!("Error reading file {:?}: {:?}", tmp.to_str(), e);
            std::process::exit(1);
        }
    }
}

fn run_repl() {
    let mut repl = REPL::new();
    repl.run();
}

fn run_bytecode(bytecode: &[u8], list_bc: bool, list_reg: bool) {
    let mut vm = VM::new();
    if let Err(e) = vm.set_bytecode(&bytecode) {
        println!("vmerror: {}", e);
    }

    if list_bc {
        println!("Listing readonly:");
        for data in vm.ro_data.chunks(4) {
            println!("  {:?}", data);
        }
        println!("EOF");

        println!("Listing instructions:");
        for instr in vm.program.chunks(4) {
            println!("  {:?}", instr);
        }
        println!("EOF");
    }

    let result = vm.run();
    match result {
        Ok(_) => {
            if list_reg {
                println!("Listing integer registers:");
                for (i, reg) in vm.iregisters.chunks(4).enumerate() {
                    println!(
                        "  [{}]\t{}\t{}\t{}\t{}",
                        i * 4,
                        reg[0],
                        reg[1],
                        reg[2],
                        reg[3]
                    );
                }
                println!("EOF");

                println!("Listing real registers:");
                for (i, reg) in vm.rregisters.chunks(4).enumerate() {
                    println!(
                        "  [{}]\t{:.03}\t{:.03}\t{:.03}\t{:.03}",
                        i * 4,
                        reg[0],
                        reg[1],
                        reg[2],
                        reg[3]
                    );
                }
                println!("EOF");
            }
            std::process::exit(0);
        }
        Err(e) => {
            println!("vmerror: {}", e);
            std::process::exit(1);
        }
    }
}

fn compile(
    assembly: &std::path::PathBuf,
    output: Option<std::path::PathBuf>,
    list_asm: bool,
) -> Vec<u8> {
    let mut compiler = Compiler::new();

    let source = read_assembly(&assembly);
    let assembly = compiler.compile(&source);

    if list_asm {
        println!("assembly\n{}\nEOF", assembly);
    }
    let mut asm = Assembler::new();
    let bytecode = asm.assemble(&assembly);
    match bytecode {
        Ok(bc) => {
            if let Some(o) = output {
                let mut f = File::create(o).expect("Unable to create file");
                f.write_all(&bc).expect("Unable to write data");
            };
            bc
        }
        Err(e) => {
            println!("assembler error: {:?}", e);
            std::process::exit(1);
        }
    }
}
<|endoftext|>


<commit_before>use std::io::{Write, BufWriter};
use std::fs::File;

extern crate rand;
use rand::Rng;

mod vector;
mod ray;
mod sphere;
mod hitable;
mod hitable_list;
mod camera;

use vector::{Vec3, dot, cross, unit_vector};
use ray::Ray;
use sphere::{Sphere};
use hitable::{Hitable, hit_record};
use hitable_list::Hitable_list;
use camera::Camera;

fn color<T: Hitable>(ray : Ray, world : &T) -> Vec3 {
  let mut rec = hit_record::new(0.0, Vec3::origin(), Vec3::origin());
  if world.hit(ray, 0.0, std::f64::MAX, &mut rec) {
    let target = rec.p + rec.normal + random_in_unit_sphere();
    return color(Ray::new(rec.p, target - rec.p), world) * 0.5
  }
  else {
    let unit_direction = unit_vector(ray.direction());
    let t = (unit_direction.y() + 1.0) * 0.5;
    return Vec3::new(1.0, 1.0, 1.0) * (1.0 - t) + Vec3::new(0.5, 0.7, 1.0) * t;
  }
}

fn random_in_unit_sphere() -> Vec3 {
  let mut p : Vec3;
  let mut rng = rand::thread_rng();
  loop {
    p = Vec3::new(rng.gen::<f64>(),rng.gen::<f64>(),rng.gen::<f64>()) * 2.0 - Vec3::all(1.0);
    if dot(p, p) < 1.0 { break; }
  }
  p
}

fn random<T: Hitable>(i : i32, j : i32, nx : i32, ny : i32, cam : Camera, world : &T, rng : &mut rand::ThreadRng) -> Vec3 {
  let sample_size = 100;
  let mut samples = 0;
  let mut col = Vec3::origin();
  loop {
    let u = (i as f64 + rng.gen::<f64>()) / nx as f64;
    let v = (j as f64 + rng.gen::<f64>()) / ny as f64;
    let r = cam.get_ray(u, v);

    col += color(r, world);
    samples += 1;
    if samples >= sample_size { break; }
  }

  col /= sample_size as f64;
  return col;
}

fn stratified<T: Hitable>(i : i32, j : i32, nx : i32, ny : i32, cam : Camera, world : &T, rng : &mut rand::ThreadRng) -> Vec3 {
  let mut col = Vec3::origin();
  let grid_size = 5;
  let step = 1.0 / grid_size as f64;
  let low_i = i as f64 - 0.5;
  let low_j = j as f64 - 0.5;

  for ii in 0..grid_size {
    for jj in 0..grid_size {
      let u = ((low_i + ii as f64 * step) + rng.gen_range(0.0, step)) / nx as f64;
      let v = ((low_j + jj as f64 * step) + rng.gen_range(0.0, step)) / ny as f64;
      let r = cam.get_ray(u, v);

      col += color(r, world);
    }
  }

  col /= (grid_size * grid_size) as f64;
  return col;
}

fn main() {
  let nx = 200;
  let ny = 100;
  let data = format!("{}\n{} {}\n{}\n", "P3", nx, ny, 255);
  let f = File::create("target/image.ppm").expect("Unable to create file");
  let mut f = BufWriter::new(f);
  f.write_all(data.as_bytes()).expect("Unable to write data");

  let lower_left_corner = Vec3::new(-2.0, -1.0, -1.0);
  let horizontal = Vec3::new(4.0, 0.0, 0.0);
  let vertical = Vec3::new(0.0, 2.0, 0.0);
  let origin = Vec3::new(0.0, 0.0, 0.0);

  let cam = Camera::new(lower_left_corner, vertical, horizontal, origin);

  let mut list : Vec<Box<Hitable>> = Vec::new();
  list.push(Box::new(Sphere::new(Vec3::new(0.0,0.0,-1.0), 0.5)));
  list.push(Box::new(Sphere::new(Vec3::new(0.0,-100.5,-1.0), 100.0)));
  let world = Hitable_list::new(list);

  let mut rng = rand::thread_rng();

  for j in (0..ny).rev() {
    for i in 0..nx {
      let mut col = stratified(i, j, nx, ny, cam, &world, &mut rng);
      col = Vec3::new(col[0].sqrt(), col[1].sqrt(), col[2].sqrt());

      let ir = (255.99*col.r()) as i32;
      let ig = (255.99*col.g()) as i32;
      let ib = (255.99*col.b()) as i32;
      f.write_all(format!("{} {} {}\n", ir, ig, ib).as_bytes()).expect("Unable to write data");
    }
  }
}<commit_msg>Update main to use new vector square root<commit_after>use std::io::{Write, BufWriter};
use std::fs::File;

extern crate rand;
use rand::Rng;

mod vector;
mod ray;
mod sphere;
mod hitable;
mod hitable_list;
mod camera;

use vector::{Vec3, dot, cross, unit_vector};
use ray::Ray;
use sphere::{Sphere};
use hitable::{Hitable, hit_record};
use hitable_list::Hitable_list;
use camera::Camera;

fn color<T: Hitable>(ray : Ray, world : &T) -> Vec3 {
  let mut rec = hit_record::new(0.0, Vec3::origin(), Vec3::origin());
  if world.hit(ray, 0.0, std::f64::MAX, &mut rec) {
    let target = rec.p + rec.normal + random_in_unit_sphere();
    return color(Ray::new(rec.p, target - rec.p), world) * 0.5
  }
  else {
    let unit_direction = unit_vector(ray.direction());
    let t = (unit_direction.y() + 1.0) * 0.5;
    return Vec3::new(1.0, 1.0, 1.0) * (1.0 - t) + Vec3::new(0.5, 0.7, 1.0) * t;
  }
}

fn random_in_unit_sphere() -> Vec3 {
  let mut p : Vec3;
  let mut rng = rand::thread_rng();
  loop {
    p = Vec3::new(rng.gen::<f64>(),rng.gen::<f64>(),rng.gen::<f64>()) * 2.0 - Vec3::all(1.0);
    if dot(p, p) < 1.0 { break; }
  }
  p
}

fn random<T: Hitable>(i : i32, j : i32, nx : i32, ny : i32, cam : Camera, world : &T, rng : &mut rand::ThreadRng) -> Vec3 {
  let sample_size = 100;
  let mut samples = 0;
  let mut col = Vec3::origin();
  loop {
    let u = (i as f64 + rng.gen::<f64>()) / nx as f64;
    let v = (j as f64 + rng.gen::<f64>()) / ny as f64;
    let r = cam.get_ray(u, v);

    col += color(r, world);
    samples += 1;
    if samples >= sample_size { break; }
  }

  col /= sample_size as f64;
  return col;
}

fn stratified<T: Hitable>(i : i32, j : i32, nx : i32, ny : i32, cam : Camera, world : &T, rng : &mut rand::ThreadRng) -> Vec3 {
  let mut col = Vec3::origin();
  let grid_size = 5;
  let step = 1.0 / grid_size as f64;
  let low_i = i as f64 - 0.5;
  let low_j = j as f64 - 0.5;

  for ii in 0..grid_size {
    for jj in 0..grid_size {
      let u = ((low_i + ii as f64 * step) + rng.gen_range(0.0, step)) / nx as f64;
      let v = ((low_j + jj as f64 * step) + rng.gen_range(0.0, step)) / ny as f64;
      let r = cam.get_ray(u, v);

      col += color(r, world);
    }
  }

  col /= (grid_size * grid_size) as f64;
  return col;
}

fn main() {
  let nx = 200;
  let ny = 100;
  let data = format!("{}\n{} {}\n{}\n", "P3", nx, ny, 255);
  let f = File::create("target/image.ppm").expect("Unable to create file");
  let mut f = BufWriter::new(f);
  f.write_all(data.as_bytes()).expect("Unable to write data");

  let lower_left_corner = Vec3::new(-2.0, -1.0, -1.0);
  let horizontal = Vec3::new(4.0, 0.0, 0.0);
  let vertical = Vec3::new(0.0, 2.0, 0.0);
  let origin = Vec3::new(0.0, 0.0, 0.0);

  let cam = Camera::new(lower_left_corner, vertical, horizontal, origin);

  let mut list : Vec<Box<Hitable>> = Vec::new();
  list.push(Box::new(Sphere::new(Vec3::new(0.0,0.0,-1.0), 0.5)));
  list.push(Box::new(Sphere::new(Vec3::new(0.0,-100.5,-1.0), 100.0)));
  let world = Hitable_list::new(list);

  let mut rng = rand::thread_rng();

  for j in (0..ny).rev() {
    for i in 0..nx {
      let mut col = stratified(i, j, nx, ny, cam, &world, &mut rng);
      col = col.sqrt();

      let ir = (255.99*col.r()) as i32;
      let ig = (255.99*col.g()) as i32;
      let ib = (255.99*col.b()) as i32;
      f.write_all(format!("{} {} {}\n", ir, ig, ib).as_bytes()).expect("Unable to write data");
    }
  }
}<|endoftext|>


<commit_before>use std::io;

fn main() {
    let mut w = String::new();
    let mut k = String::new();

    println!("Type in a message to write");
    io::stdin().read_line(&mut w).expect("Error!");

    println!("Type in a key");
    io::stdin().read_line(&mut k).expect("Error!");

    let k: i32 = match k.trim().parse() {
        Ok(x) => x,
        Err(_) => 0
    };

    println!("Your translated string is\n{:?}", encsr(w.trim(), k));

    // let try_al: Vec<String> = decsr(encsr("Hello World", 10), 10);
    // for s in try_al {
    //     println!("{:?}", s);
    // }
}

fn key_v(starting: &str, key: i32) -> Vec<char> {
    let k: i32 = key;
    let s = starting;

    let s_v: Vec<char> = s.chars().collect();
    let mut new_v: Vec<char> = Vec::new();

    let mut i: i32 = k-1;

    while i < (s_v.len() as i32) {
        new_v.push(s_v[(i as usize)]);
        i += 1;
    }

    let mut new_i = 0;
    while new_i <= k-2 {
        new_v.push(s_v[(new_i as usize)]);
        new_i += 1;
    }

    return new_v;
}

fn l_to_n(l: char) -> i16 {
    match l {
        'A' => 0,
        'B' => 1,
        'C' => 2,
        'D' => 3,
        'E' => 4,
        'F' => 5,
        'G' => 6,
        'H' => 7,
        'I' => 8,
        'J' => 9,
        'K' => 10,
        'L' => 11,
        'M' => 12,
        'N' => 13,
        'O' => 14,
        'P' => 15,
        'Q' => 16,
        'R' => 17,
        'S' => 18,
        'T' => 19,
        'U' => 20,
        'V' => 21,
        'W' => 22,
        'X' => 23,
        'Y' => 24,
        'Z' => 25,
        _ => 30
    }
}

fn encsr_w(word: &str, key: i32) -> String {
    let starting = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
    let key_v = key_v(starting, key);

    let mut index_v: Vec<i16> = Vec::new();

    for l in word.to_uppercase().chars() {
        index_v.push(l_to_n(l));
    }

    let mut new_w_v: Vec<char> = Vec::new();

    for i in index_v {
        new_w_v.push(key_v[(i as usize)]);
    }

    let s: String = new_w_v.into_iter().collect();

    return s;
}

fn decsr_w(word: &str, key: i32) -> String {

    let starting = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
    let key_v = key_v(starting, key);

    let mut pos_v: Vec<i16> = Vec::new();
    let mut cur_i: i16 = 0;

    for c in word.to_uppercase().chars() {
        while cur_i < (key_v.len() as i16) - 1 {
            if c == key_v[(cur_i as usize)] {
                pos_v.push(cur_i);
                cur_i = 0;
                break;
            }
            cur_i += 1
        }
    }

    let c_vec: Vec<char> = starting.chars().collect();
    let mut fin_v: Vec<char> = Vec::new();

    for p in pos_v {
        fin_v.push(c_vec[(p as usize)]);
    }

    let s: String = fin_v.into_iter().collect();
    return s;
}

fn encsr(word: &str, key: i32) -> Vec<String> {
    let sp_w: Vec<&str> = word.split(" ").collect();
    let mut w_v: Vec<String> = Vec::new();

    for cur_w in sp_w {
        w_v.push(encsr_w(cur_w, key));
    }

    return w_v
}

fn decsr(enc: Vec<String>, key: i32) -> Vec<String> {
    let mut fin_v: Vec<String> = Vec::new();

    for pt in enc {
        fin_v.push(decsr_w(pt.trim(), key));
    }

    return fin_v;
}
<commit_msg>Add descr algorithm<commit_after>use std::io;

fn main() {
    // let mut w = String::new();
    // let mut k = String::new();
    //
    // println!("Type in a message to write");
    // io::stdin().read_line(&mut w).expect("Error!");
    //
    // println!("Type in a key");
    // io::stdin().read_line(&mut k).expect("Error!");
    //
    // let k: i32 = match k.trim().parse() {
    //     Ok(x) => x,
    //     Err(_) => 0
    // };
    //
    // println!("Your translated string is\n{:?}", encsr(w.trim(), k));
    let haha = decsr("KHOOR ZRUOG", 4);
    println!("{}", haha);
}

fn key_v(starting: &str, key: i32) -> Vec<char> {
    let k: i32 = key;
    let s = starting;

    let s_v: Vec<char> = s.chars().collect();
    let mut new_v: Vec<char> = Vec::new();

    let mut i: i32 = k-1;

    while i < (s_v.len() as i32) {
        new_v.push(s_v[(i as usize)]);
        i += 1;
    }

    let mut new_i = 0;
    while new_i <= k-2 {
        new_v.push(s_v[(new_i as usize)]);
        new_i += 1;
    }

    return new_v;
}

fn l_to_n(l: char) -> i16 {
    match l {
        'A' => 0,
        'B' => 1,
        'C' => 2,
        'D' => 3,
        'E' => 4,
        'F' => 5,
        'G' => 6,
        'H' => 7,
        'I' => 8,
        'J' => 9,
        'K' => 10,
        'L' => 11,
        'M' => 12,
        'N' => 13,
        'O' => 14,
        'P' => 15,
        'Q' => 16,
        'R' => 17,
        'S' => 18,
        'T' => 19,
        'U' => 20,
        'V' => 21,
        'W' => 22,
        'X' => 23,
        'Y' => 24,
        'Z' => 25,
        _ => 30
    }
}

fn encsr_w(word: &str, key: i32) -> String {
    let starting = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
    let key_v = key_v(starting, key);

    let mut index_v: Vec<i16> = Vec::new();

    for l in word.to_uppercase().chars() {
        index_v.push(l_to_n(l));
    }

    let mut new_w_v: Vec<char> = Vec::new();

    for i in index_v {
        new_w_v.push(key_v[(i as usize)]);
    }

    let s: String = new_w_v.into_iter().collect();

    return s;
}

fn decsr_w(word: &str, key: i32) -> String {

    let starting = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
    let key_v = key_v(starting, key);

    let mut pos_v: Vec<i16> = Vec::new();
    let mut cur_i: i16 = 0;

    for c in word.to_uppercase().chars() {
        while cur_i < (key_v.len() as i16) - 1 {
            if c == key_v[(cur_i as usize)] {
                pos_v.push(cur_i);
                cur_i = 0;
                break;
            }
            cur_i += 1
        }
    }

    let c_vec: Vec<char> = starting.chars().collect();
    let mut fin_v: Vec<char> = Vec::new();

    for p in pos_v {
        fin_v.push(c_vec[(p as usize)]);
    }

    let s: String = fin_v.into_iter().collect();
    return s;
}

fn encsr(word: &str, key: i32) -> String {
    let sp_w: Vec<&str> = word.split(" ").collect();
    let mut w_v: Vec<String> = Vec::new();

    for cur_w in sp_w {
        w_v.push(encsr_w(cur_w, key));
    }

    return w_v.join(" ");
}

fn decsr(enc: &str, key: i32) -> String {
    let mut fin_v: Vec<String> = Vec::new();

    for pt in enc.split(" ") {
        fin_v.push(decsr_w(pt.trim(), key));
    }

    return fin_v.join(" ");
}
<|endoftext|>


<commit_before>#![feature(core, unboxed_closures, fn_traits)]
// MSPC == 'multiple sender, single receiver'
use std::sync::mpsc::{Sender, Receiver};
use std::sync::mpsc;
use std::thread;

type Payload = i32;

struct Message {
    payload: Payload,
    sender: Sender<Payload>,
}

struct Actor {
    inbox: Receiver<Message>
}

impl Actor {
    fn new(inbox: Receiver<Message>) -> Actor {
        Actor{inbox: inbox}
    }
}

impl FnOnce<()> for Actor {
    type Output = ();
    extern "rust-call" fn call_once(self, args: ()) -> () {
        // Forever...
        loop {
            // See if we have messages!
            match self.inbox.recv() {
                // If we're given a 'special' -1 value, exit.
                Ok(Message{payload: num, sender: _}) if num == -1 => {
                    println!("[Actor] Exiting!");
                    break;
                },
                // Otherwise, print and respond to the message!
                Ok(Message{payload: num, sender: sender}) => {
                    println!("[Actor] Got: {:?}", num);
                    sender.send(num + 1).unwrap();
                },
                // Exit on error
                Err(e) => {
                    println!("[Actor] Error: {:?}", e);
                    break;
                },
            }
        }
    }
}

struct ActorRef {
    outbox: Sender<Message>
}

impl ActorRef {
    fn new(outbox: Sender<Message>) -> ActorRef {
        ActorRef{outbox: outbox}
    }
}

fn main() {
    // Actor Mailbox
    let (outbox, inbox): (Sender<Message>, Receiver<Message>) = mpsc::channel();

    let actor = Actor::new(inbox);
    let r = ActorRef::new(outbox);

    // Create a new thread
    let handle = thread::Builder::new()
        .name("actor".into())
        .spawn(actor)
        .unwrap();

    // Communication channel with actor
    let (sender, receiver): (Sender<Payload>, Receiver<Payload>) = mpsc::channel();
    r.outbox.send(Message{payload: 0, sender: sender.clone()}).unwrap();
    let num = receiver.recv().unwrap();
    println!("[Main] Got: {:?}", num);

    // Send another number!
    r.outbox.send(Message{payload: num + 1, sender: sender.clone()}).unwrap();
    let num = receiver.recv().unwrap();
    println!("[Main] Got: {:?}", num);

    // Send exit code
    r.outbox.send(Message{payload: -1, sender: sender.clone()}).unwrap();

    // Wait for thread to exit
    let res = handle.join().unwrap();
    println!("[Main] Res: {:?}", res);
}
<commit_msg>Cleanup<commit_after>#![feature(unboxed_closures, fn_traits)]
// MSPC == 'multiple sender, single receiver'
use std::sync::mpsc::{Sender, Receiver};
use std::sync::mpsc;
use std::thread;

type Payload = i32;

struct Message {
    payload: Payload,
    sender: Sender<Payload>,
}

struct Actor {
    inbox: Receiver<Message>
}

impl Actor {
    fn new(inbox: Receiver<Message>) -> Actor {
        Actor{inbox: inbox}
    }
}

impl FnOnce<()> for Actor {
    type Output = ();
    extern "rust-call" fn call_once(self, _: ()) -> () {
        // Forever...
        loop {
            // See if we have messages!
            match self.inbox.recv() {
                // If we're given a 'special' -1 value, exit.
                Ok(Message{payload, sender: _}) if payload == -1 => {
                    println!("[Actor] Exiting!");
                    break;
                },
                // Otherwise, print and respond to the message!
                Ok(Message{payload, sender}) => {
                    println!("[Actor] Got: {:?}", payload);
                    sender.send(payload + 1).unwrap();
                },
                // Exit on error
                Err(e) => {
                    println!("[Actor] Error: {:?}", e);
                    break;
                },
            }
        }
    }
}

struct ActorRef {
    outbox: Sender<Message>
}

impl ActorRef {
    fn new(outbox: Sender<Message>) -> ActorRef {
        ActorRef{outbox: outbox}
    }
}

fn main() {
    // Actor Mailbox
    let (outbox, inbox): (Sender<Message>, Receiver<Message>) = mpsc::channel();

    let actor = Actor::new(inbox);
    let r = ActorRef::new(outbox);

    // Create a new thread
    let handle = thread::Builder::new()
        .name("actor".into())
        .spawn(actor)
        .unwrap();

    // Communication channel with actor
    let (sender, receiver): (Sender<Payload>, Receiver<Payload>) = mpsc::channel();
    r.outbox.send(Message{payload: 0, sender: sender.clone()}).unwrap();
    let num = receiver.recv().unwrap();
    println!("[Main] Got: {:?}", num);

    // Send another number!
    r.outbox.send(Message{payload: num + 1, sender: sender.clone()}).unwrap();
    let num = receiver.recv().unwrap();
    println!("[Main] Got: {:?}", num);

    // Send exit code
    r.outbox.send(Message{payload: -1, sender: sender.clone()}).unwrap();

    // Wait for thread to exit
    let res = handle.join().unwrap();
    println!("[Main] Res: {:?}", res);
}
<|endoftext|>


<commit_before>//! Command line utility for querying and working with Iridium SBD messages.

extern crate docopt;
extern crate rustc_serialize;
extern crate sbd;

use std::process;
use std::str;

use docopt::Docopt;

use sbd::directip::Server;
use sbd::filesystem::Storage;
use sbd::message::Message;

const USAGE: &'static str = "
Iridium Short Burst Data (SBD) message utility.

Usage:
    sbd list <directory>
    sbd read <file>
    sbd serve <addr> <directory>
    sbd (-h | --help)
    sbd --version

Options:
    -h --help   Show this information
    --version   Show version
";

#[derive(Debug, RustcDecodable)]
struct Args {
    cmd_list: bool,
    cmd_read: bool,
    cmd_serve: bool,
    arg_addr: String,
    arg_directory: String,
    arg_file: String,
}

#[cfg_attr(test, allow(dead_code))]
fn main() {
    let args: Args = Docopt::new(USAGE)
        .and_then(|d| Ok(d.version(Some(env!("CARGO_PKG_VERSION").to_string()))))
        .and_then(|d| d.decode())
        .unwrap_or_else(|e| e.exit());

    if args.cmd_list {
        for entry in &Storage::new(&args.arg_directory) {
            println!("{}", entry.path_buf.to_str().unwrap());
        }
    }
    if args.cmd_read {
        match Message::from_path(args.arg_file) {
            Ok(message) => {
                println!("{}", str::from_utf8(message.payload_ref()).unwrap());
            }
            Err(err) => println!("ERROR: {:?}", err),
        }
    }
    if args.cmd_serve {
        let mut server = Server::new(&args.arg_addr[..], &args.arg_directory);
        match server.bind() {
            Ok(()) => server.serve_forever(),
            Err(err) => {
                println!("Error recieved when trying to bind to socket: {:?}", err);
                process::exit(1);
            }
        }
    }
}
<commit_msg>Tweak text when tcp bind fails<commit_after>//! Command line utility for querying and working with Iridium SBD messages.

extern crate docopt;
extern crate rustc_serialize;
extern crate sbd;

use std::process;
use std::str;

use docopt::Docopt;

use sbd::directip::Server;
use sbd::filesystem::Storage;
use sbd::message::Message;

const USAGE: &'static str = "
Iridium Short Burst Data (SBD) message utility.

Usage:
    sbd list <directory>
    sbd read <file>
    sbd serve <addr> <directory>
    sbd (-h | --help)
    sbd --version

Options:
    -h --help   Show this information
    --version   Show version
";

#[derive(Debug, RustcDecodable)]
struct Args {
    cmd_list: bool,
    cmd_read: bool,
    cmd_serve: bool,
    arg_addr: String,
    arg_directory: String,
    arg_file: String,
}

#[cfg_attr(test, allow(dead_code))]
fn main() {
    let args: Args = Docopt::new(USAGE)
        .and_then(|d| Ok(d.version(Some(env!("CARGO_PKG_VERSION").to_string()))))
        .and_then(|d| d.decode())
        .unwrap_or_else(|e| e.exit());

    if args.cmd_list {
        for entry in &Storage::new(&args.arg_directory) {
            println!("{}", entry.path_buf.to_str().unwrap());
        }
    }
    if args.cmd_read {
        match Message::from_path(args.arg_file) {
            Ok(message) => {
                println!("{}", str::from_utf8(message.payload_ref()).unwrap());
            }
            Err(err) => println!("ERROR: {:?}", err),
        }
    }
    if args.cmd_serve {
        let mut server = Server::new(&args.arg_addr[..], &args.arg_directory);
        match server.bind() {
            Ok(()) => server.serve_forever(),
            Err(err) => {
                println!("Error when trying to bind to socket: {:?}", err);
                process::exit(1);
            }
        }
    }
}
<|endoftext|>


<commit_before>#![recursion_limit = "256"]
#![feature(proc_macro_hygiene, decl_macro)]
#![allow(proc_macro_derive_resolution_fallback)]

extern crate ape;
extern crate app_dirs;
extern crate base64;
extern crate core;
extern crate crypto;
#[macro_use]
extern crate diesel;
#[macro_use]
extern crate diesel_migrations;
#[macro_use]
extern crate error_chain;
extern crate getopts;
extern crate id3;
extern crate image;
extern crate lewton;
extern crate metaflac;
extern crate mp3_duration;
extern crate rand;
extern crate regex;
extern crate reqwest;
extern crate ring;
#[macro_use]
extern crate rocket;
extern crate rocket_contrib;
extern crate rustfm_scrobble;
extern crate serde;
#[macro_use]
extern crate serde_derive;
extern crate serde_json;
extern crate toml;
#[macro_use]
extern crate log;
extern crate simplelog;

#[cfg(windows)]
extern crate uuid;
#[cfg(windows)]
extern crate winapi;

#[cfg(unix)]
extern crate unix_daemonize;

#[cfg(unix)]
use std::fs::File;
#[cfg(unix)]
use std::io::prelude::*;
#[cfg(unix)]
use unix_daemonize::{daemonize_redirect, ChdirMode};

use core::ops::Deref;
use crate::errors::*;
use getopts::Options;
use simplelog::{Level, LevelFilter, SimpleLogger, TermLogger};
use std::path::Path;
use std::sync::Arc;

mod api;
#[cfg(test)]
mod api_tests;
mod config;
mod db;
mod ddns;
mod errors;
mod index;
mod lastfm;
mod metadata;
mod playlist;
mod serve;
mod server;
mod swagger;
#[cfg(test)]
mod test;
mod thumbnails;
mod ui;
mod user;
mod utils;
mod vfs;
mod web;

static LOG_CONFIG: simplelog::Config = simplelog::Config {
	time: Some(Level::Error),
	level: Some(Level::Error),
	target: Some(Level::Error),
	location: Some(Level::Error),
	time_format: None,
};

fn main() {
	if let Err(ref e) = run() {
		println!("Error: {}", e);

		for e in e.iter().skip(1) {
			println!("caused by: {}", e);
		}
		if let Some(backtrace) = e.backtrace() {
			println!("backtrace: {:?}", backtrace);
		}
		::std::process::exit(1);
	}
}

#[cfg(unix)]
fn daemonize(options: &getopts::Matches) -> Result<()> {
	if options.opt_present("f") {
		return Ok(());
	}
	let mut log_file = utils::get_data_root()?;
	log_file.push("polaris.log");
	let pid = match daemonize_redirect(Some(&log_file), Some(&log_file), ChdirMode::NoChdir) {
		Ok(p) => p,
		Err(_) => bail!(ErrorKind::DaemonError),
	};
	let mut pid_path = utils::get_data_root()?;
	pid_path.push("polaris.pid");
	let mut file = File::create(pid_path)?;
	file.write_all(pid.to_string().as_bytes())?;
	Ok(())
}

#[cfg(unix)]
fn init_log(log_level: LevelFilter, options: &getopts::Matches) -> Result<()> {
	if options.opt_present("f") {
		if let Err(_) = TermLogger::init(log_level, LOG_CONFIG) {
            if let Err(e) = SimpleLogger::init(log_level, LOG_CONFIG) {
                bail!("Error starting terminal logger: {}", e);
            };
		};
	} else {
		if let Err(e) = SimpleLogger::init(log_level, LOG_CONFIG) {
			bail!("Error starting simple logger: {}", e);
		}
	}
	Ok(())
}

#[cfg(windows)]
fn init_log(log_level: LevelFilter, _: &getopts::Matches) -> Result<()> {
	if TermLogger::init(log_level, LOG_CONFIG).is_err() {
		if let Err(e) = SimpleLogger::init(log_level, LOG_CONFIG) {
			bail!("Error starting simple logger: {}", e);
		}
	};
	Ok(())
}

fn run() -> Result<()> {
	// Parse CLI options
	let args: Vec<String> = std::env::args().collect();
	let mut options = Options::new();
	options.optopt("c", "config", "set the configuration file", "FILE");
	options.optopt("p", "port", "set polaris to run on a custom port", "PORT");
	options.optopt("d", "database", "set the path to index database", "FILE");
	options.optopt("w", "web", "set the path to web client files", "DIRECTORY");
	options.optopt("s", "swagger", "set the path to swagger files", "DIRECTORY");
	options.optopt(
		"l",
		"log",
		"set the log level to a value between 0 (off) and 3 (debug)",
		"LEVEL",
	);

	#[cfg(unix)]
	options.optflag(
		"f",
		"foreground",
		"run polaris in the foreground instead of daemonizing",
	);

	options.optflag("h", "help", "print this help menu");

	let matches = options.parse(&args[1..])?;

	if matches.opt_present("h") {
		let program = args[0].clone();
		let brief = format!("Usage: {} [options]", program);
		print!("{}", options.usage(&brief));
		return Ok(());
	}

	let log_level = match matches.opt_str("l").as_ref().map(String::as_ref) {
		Some("0") => LevelFilter::Off,
		Some("1") => LevelFilter::Error,
		Some("2") => LevelFilter::Info,
		Some("3") => LevelFilter::Debug,
		_ => LevelFilter::Info,
	};

	init_log(log_level, &matches)?;

	#[cfg(unix)]
	daemonize(&matches)?;

	// Init DB
	info!("Starting up database");
	let db_path = matches.opt_str("d");
	let mut default_db_path = utils::get_data_root()?;
	default_db_path.push("db.sqlite");
	let db_path = db_path
		.map(|n| Path::new(n.as_str()).to_path_buf())
		.unwrap_or(default_db_path);
	let db = Arc::new(db::DB::new(&db_path)?);

	// Parse config
	info!("Parsing configuration");
	let config_file_name = matches.opt_str("c");
	let config_file_path = config_file_name.map(|p| Path::new(p.as_str()).to_path_buf());
	if let Some(path) = config_file_path {
		let config = config::parse_toml_file(&path)?;
		config::overwrite(db.deref(), &config)?;
	}
	let config = config::read(db.deref())?;

	// Init index
	info!("Initializing index");
	let command_sender = index::init(db.clone());

	// Trigger auto-indexing
	let db_auto_index = db.clone();
	let command_sender_auto_index = command_sender.clone();
	std::thread::spawn(move || {
		index::self_trigger(db_auto_index.deref(), &command_sender_auto_index);
	});

	// API mount target
	let prefix_url = config.prefix_url.unwrap_or_else(|| "".to_string());
	let api_url = format!("/{}api", &prefix_url);
	info!("Mounting API on {}", api_url);

	// Web client mount target
	let web_dir_name = matches.opt_str("w");
	let mut default_web_dir = utils::get_data_root()?;
	default_web_dir.push("web");
	let web_dir_path = web_dir_name
		.map(|n| Path::new(n.as_str()).to_path_buf())
		.unwrap_or(default_web_dir);
	info!("Static files location is {}", web_dir_path.display());
	let web_url = format!("/{}", &prefix_url);
	info!("Mounting web client files on {}", web_url);

	// Swagger files mount target
	let swagger_dir_name = matches.opt_str("s");
	let mut default_swagger_dir = utils::get_data_root()?;
	default_swagger_dir.push("swagger");
	let swagger_dir_path = swagger_dir_name
		.map(|n| Path::new(n.as_str()).to_path_buf())
		.unwrap_or(default_swagger_dir);
	info!("Swagger files location is {}", swagger_dir_path.display());
	let swagger_url = format!("/{}swagger", &prefix_url);
	info!("Mounting swagger files on {}", swagger_url);

	// Start server
	info!("Starting up server");
	let port: u16 = matches
		.opt_str("p")
		.unwrap_or_else(|| "5050".to_owned())
		.parse()
		.or(Err("invalid port number"))?;

	let server = server::get_server(
		port,
		&api_url,
		&web_url,
		&web_dir_path,
		&swagger_url,
		&swagger_dir_path,
		db.clone(),
		command_sender,
	)?;
	std::thread::spawn(move || {
		server.launch();
	});

	// Start DDNS updates
	let db_ddns = db.clone();
	std::thread::spawn(move || {
		ddns::run(db_ddns.deref());
	});

	// Run UI
	ui::run();

	info!("Shutting down server");
	Ok(())
}
<commit_msg>Implement suggestions<commit_after>#![recursion_limit = "256"]
#![feature(proc_macro_hygiene, decl_macro)]
#![allow(proc_macro_derive_resolution_fallback)]

extern crate ape;
extern crate app_dirs;
extern crate base64;
extern crate core;
extern crate crypto;
#[macro_use]
extern crate diesel;
#[macro_use]
extern crate diesel_migrations;
#[macro_use]
extern crate error_chain;
extern crate getopts;
extern crate id3;
extern crate image;
extern crate lewton;
extern crate metaflac;
extern crate mp3_duration;
extern crate rand;
extern crate regex;
extern crate reqwest;
extern crate ring;
#[macro_use]
extern crate rocket;
extern crate rocket_contrib;
extern crate rustfm_scrobble;
extern crate serde;
#[macro_use]
extern crate serde_derive;
extern crate serde_json;
extern crate toml;
#[macro_use]
extern crate log;
extern crate simplelog;

#[cfg(windows)]
extern crate uuid;
#[cfg(windows)]
extern crate winapi;

#[cfg(unix)]
extern crate unix_daemonize;

#[cfg(unix)]
use std::fs::File;
#[cfg(unix)]
use std::io::prelude::*;
#[cfg(unix)]
use unix_daemonize::{daemonize_redirect, ChdirMode};

use core::ops::Deref;
use crate::errors::*;
use getopts::Options;
use simplelog::{Level, LevelFilter, SimpleLogger, TermLogger};
use std::path::Path;
use std::sync::Arc;

mod api;
#[cfg(test)]
mod api_tests;
mod config;
mod db;
mod ddns;
mod errors;
mod index;
mod lastfm;
mod metadata;
mod playlist;
mod serve;
mod server;
mod swagger;
#[cfg(test)]
mod test;
mod thumbnails;
mod ui;
mod user;
mod utils;
mod vfs;
mod web;

static LOG_CONFIG: simplelog::Config = simplelog::Config {
	time: Some(Level::Error),
	level: Some(Level::Error),
	target: Some(Level::Error),
	location: Some(Level::Error),
	time_format: None,
};

fn main() {
	if let Err(ref e) = run() {
		println!("Error: {}", e);

		for e in e.iter().skip(1) {
			println!("caused by: {}", e);
		}
		if let Some(backtrace) = e.backtrace() {
			println!("backtrace: {:?}", backtrace);
		}
		::std::process::exit(1);
	}
}

#[cfg(unix)]
fn daemonize(options: &getopts::Matches) -> Result<()> {
	if options.opt_present("f") {
		return Ok(());
	}
	let mut log_file = utils::get_data_root()?;
	log_file.push("polaris.log");
	let pid = match daemonize_redirect(Some(&log_file), Some(&log_file), ChdirMode::NoChdir) {
		Ok(p) => p,
		Err(_) => bail!(ErrorKind::DaemonError),
	};
	let mut pid_path = utils::get_data_root()?;
	pid_path.push("polaris.pid");
	let mut file = File::create(pid_path)?;
	file.write_all(pid.to_string().as_bytes())?;
	Ok(())
}

#[cfg(unix)]
fn init_log(log_level: LevelFilter, options: &getopts::Matches) -> Result<()> {
	if options.opt_present("f") {
		if let Err(e) = TermLogger::init(log_level, LOG_CONFIG) {
			println!("Error starting terminal logger: {}", e);
		} else {
			return Ok(());
		}
	}

	if let Err(e) = SimpleLogger::init(log_level, LOG_CONFIG) {
		bail!("Error starting simple logger: {}", e);
	}
	Ok(())
}

#[cfg(windows)]
fn init_log(log_level: LevelFilter, _: &getopts::Matches) -> Result<()> {
	if TermLogger::init(log_level, LOG_CONFIG).is_err() {
		if let Err(e) = SimpleLogger::init(log_level, LOG_CONFIG) {
			bail!("Error starting simple logger: {}", e);
		}
	};
	Ok(())
}

fn run() -> Result<()> {
	// Parse CLI options
	let args: Vec<String> = std::env::args().collect();
	let mut options = Options::new();
	options.optopt("c", "config", "set the configuration file", "FILE");
	options.optopt("p", "port", "set polaris to run on a custom port", "PORT");
	options.optopt("d", "database", "set the path to index database", "FILE");
	options.optopt("w", "web", "set the path to web client files", "DIRECTORY");
	options.optopt("s", "swagger", "set the path to swagger files", "DIRECTORY");
	options.optopt(
		"l",
		"log",
		"set the log level to a value between 0 (off) and 3 (debug)",
		"LEVEL",
	);

	#[cfg(unix)]
	options.optflag(
		"f",
		"foreground",
		"run polaris in the foreground instead of daemonizing",
	);

	options.optflag("h", "help", "print this help menu");

	let matches = options.parse(&args[1..])?;

	if matches.opt_present("h") {
		let program = args[0].clone();
		let brief = format!("Usage: {} [options]", program);
		print!("{}", options.usage(&brief));
		return Ok(());
	}

	let log_level = match matches.opt_str("l").as_ref().map(String::as_ref) {
		Some("0") => LevelFilter::Off,
		Some("1") => LevelFilter::Error,
		Some("2") => LevelFilter::Info,
		Some("3") => LevelFilter::Debug,
		_ => LevelFilter::Info,
	};

	init_log(log_level, &matches)?;

	#[cfg(unix)]
	daemonize(&matches)?;

	// Init DB
	info!("Starting up database");
	let db_path = matches.opt_str("d");
	let mut default_db_path = utils::get_data_root()?;
	default_db_path.push("db.sqlite");
	let db_path = db_path
		.map(|n| Path::new(n.as_str()).to_path_buf())
		.unwrap_or(default_db_path);
	let db = Arc::new(db::DB::new(&db_path)?);

	// Parse config
	info!("Parsing configuration");
	let config_file_name = matches.opt_str("c");
	let config_file_path = config_file_name.map(|p| Path::new(p.as_str()).to_path_buf());
	if let Some(path) = config_file_path {
		let config = config::parse_toml_file(&path)?;
		config::overwrite(db.deref(), &config)?;
	}
	let config = config::read(db.deref())?;

	// Init index
	info!("Initializing index");
	let command_sender = index::init(db.clone());

	// Trigger auto-indexing
	let db_auto_index = db.clone();
	let command_sender_auto_index = command_sender.clone();
	std::thread::spawn(move || {
		index::self_trigger(db_auto_index.deref(), &command_sender_auto_index);
	});

	// API mount target
	let prefix_url = config.prefix_url.unwrap_or_else(|| "".to_string());
	let api_url = format!("/{}api", &prefix_url);
	info!("Mounting API on {}", api_url);

	// Web client mount target
	let web_dir_name = matches.opt_str("w");
	let mut default_web_dir = utils::get_data_root()?;
	default_web_dir.push("web");
	let web_dir_path = web_dir_name
		.map(|n| Path::new(n.as_str()).to_path_buf())
		.unwrap_or(default_web_dir);
	info!("Static files location is {}", web_dir_path.display());
	let web_url = format!("/{}", &prefix_url);
	info!("Mounting web client files on {}", web_url);

	// Swagger files mount target
	let swagger_dir_name = matches.opt_str("s");
	let mut default_swagger_dir = utils::get_data_root()?;
	default_swagger_dir.push("swagger");
	let swagger_dir_path = swagger_dir_name
		.map(|n| Path::new(n.as_str()).to_path_buf())
		.unwrap_or(default_swagger_dir);
	info!("Swagger files location is {}", swagger_dir_path.display());
	let swagger_url = format!("/{}swagger", &prefix_url);
	info!("Mounting swagger files on {}", swagger_url);

	// Start server
	info!("Starting up server");
	let port: u16 = matches
		.opt_str("p")
		.unwrap_or_else(|| "5050".to_owned())
		.parse()
		.or(Err("invalid port number"))?;

	let server = server::get_server(
		port,
		&api_url,
		&web_url,
		&web_dir_path,
		&swagger_url,
		&swagger_dir_path,
		db.clone(),
		command_sender,
	)?;
	std::thread::spawn(move || {
		server.launch();
	});

	// Start DDNS updates
	let db_ddns = db.clone();
	std::thread::spawn(move || {
		ddns::run(db_ddns.deref());
	});

	// Run UI
	ui::run();

	info!("Shutting down server");
	Ok(())
}
<|endoftext|>


<commit_before>#[macro_use]
extern crate serde_derive;
extern crate toml;
extern crate getopts;
use std::env;
use std::fs;
use std::io;
use std::io::prelude::*;
use std::io::Write;
use std::path;
use std::process;
use getopts::Options;
use getopts::ParsingStyle;

const DEFAULT_CONF_PATH: &str = "~/.config/openby/config";

#[derive(Debug)]
enum AppError {
    Io(io::Error),
    Toml(toml::de::Error),
}

#[allow(dead_code)]
#[derive(Deserialize)]
struct Config {
    version: f64,
    tools: Vec<Tools>,
}

#[allow(dead_code)]
#[derive(Deserialize)]
struct Tools {
    command: String,
    extentions: Vec<String>,
}

fn main() {
    let exit_code = match run() {
        Ok(_) => 0,
        Err(e) => {
            writeln!(&mut io::stderr(), "{:?}", e).unwrap();
            1
        }
    };
    process::exit(exit_code);
}

fn run() -> Result<(), AppError> {
    let args: Vec<String> = env::args().collect();
    let args_str: Vec<&str> = args.iter().map(|s| s.as_str()).collect();
    let (file_name, conf_name) = parse_options(args_str)?;
    println!("Ok: {} {}", file_name, conf_name);

    let conf = load_config(&conf_name)?;

    open_by(&conf, &file_name)?;

    Ok(())
}

fn parse_options(args: Vec<&str>) -> Result<(String, String), AppError> {
    let ref program = &args[0];

    let mut opts = Options::new();
    opts.parsing_style(ParsingStyle::FloatingFrees);
    opts.optopt("c", "config", "specify configure file name", "CONFIG");
    opts.optflag("h", "help", "print this help menu");

    let matches = opts.parse(&args[1..]).unwrap();

    if matches.opt_present("h") {
        print_usage(&program, &opts);
        process::exit(0);
    }

    let file_name = if !matches.free.is_empty() {
        matches.free[0].clone()
    } else {
        print_usage(&program, &opts);
        return Result::Err(AppError::Io(
            io::Error::new(io::ErrorKind::NotFound, "FILE is not found"),
        ));
    };

    let conf_name = if let Some(c) = matches.opt_str("c") {
        c
    } else {
        DEFAULT_CONF_PATH.to_string()
    };

    Ok((file_name, conf_name))
}

fn print_usage(program: &str, opts: &Options) {
    let brief = format!("Usage: {} [options] FILE", program);
    println!("{}", opts.usage(&brief));
}

fn load_config(conf_name: &str) -> Result<Config, AppError> {
    let path = path::Path::new(conf_name);
    if path.exists() == false {
        return Result::Err(AppError::Io(io::Error::new(
            io::ErrorKind::NotFound,
            format!("{} is not exist", path.to_str().unwrap_or("")),
        )));
    }

    let mut reader = io::BufReader::new(fs::File::open(path).map_err(AppError::Io)?);
    let mut s = String::new();
    reader.read_to_string(&mut s).map_err(AppError::Io)?;

    let conf: Config = toml::from_str(s.as_str()).map_err(AppError::Toml)?;

    Ok(conf)
}

fn open_by(conf: &Config, file_name: &str) -> Result<(), AppError> {
    let file_path = path::Path::new(file_name);
    if file_path.exists() == false {
        return Result::Err(AppError::Io(io::Error::new(
            io::ErrorKind::NotFound,
            format!("{} is not exist", file_path.to_str().unwrap_or("")),
        )));
    }

    let ext = file_path.extension().ok_or(AppError::Io(io::Error::new(
        io::ErrorKind::NotFound,
        format!(
            "{} has not extension",
            file_path.to_str().unwrap_or("")
        ),
    )))?;

    match get_commnad_from_extension(conf, ext.to_str().unwrap()) {
        Some(cmd) => {
            println!("file = {:?}", file_path);
            process::Command::new(cmd).arg(file_path).status().expect(
                "failed to run",
            );
        }
        None => {
            println!("command = None");
            // TODO: register command about this extension.
        }
    }

    Ok(())
}

fn get_commnad_from_extension(conf: &Config, extension: &str) -> Option<String> {
    let ext_string = extension.to_string();
    for t in conf.tools.iter() {
        if t.extentions.contains(&ext_string) {
            return Some(t.command.clone());
        }
    }
    None
}

#[test]
fn test_parse_options() {
    let no_arguments = vec!["openby", "input.file", "-c", "configure.file"];

    assert!(parse_options(no_arguments[0..1].to_vec()).is_err());
    assert_eq!(
        ("input.file".to_string(), DEFAULT_CONF_PATH.to_string()),
        parse_options(no_arguments[0..2].to_vec()).unwrap_or(("".to_string(), "".to_string()))
    );
    assert_eq!(
        ("input.file".to_string(), "configure.file".to_string()),
        parse_options(no_arguments).unwrap_or(("".to_string(), "".to_string()))
    );
}

#[test]
fn test_decode_toml() {
    let toml_config_str = r#"
    version = 0.0

    [[tools]]
    command = "apvlv"
    extentions = [ "pdf" ]

    [[tools]]
    command = "mirage"
    extentions = [ "jpg", "png", "gif" ]

    [[tools]]
    command = "vlc"
    extentions = [ "mp4", "mov", "avi" ]

    [[tools]]
    command = "vim -R"
    extentions = [ "conf" ]
    "#;

    let config: Config = toml::from_str(toml_config_str).unwrap();
    assert_eq!(config.version, 0.0);

    assert_eq!(config.tools[0].command, "apvlv".to_string());
    assert_eq!(config.tools[0].extentions[0], "pdf".to_string());

    assert_eq!(config.tools[1].command, "mirage".to_string());
    assert_eq!(config.tools[1].extentions[0], "jpg".to_string());
    assert_eq!(config.tools[1].extentions[1], "png".to_string());
    assert_eq!(config.tools[1].extentions[2], "gif".to_string());

    assert_eq!(config.tools[2].command, "vlc".to_string());
    assert_eq!(config.tools[2].extentions[0], "mp4".to_string());
    assert_eq!(config.tools[2].extentions[1], "mov".to_string());
    assert_eq!(config.tools[2].extentions[2], "avi".to_string());

    assert_eq!(config.tools[3].command, "vim -R".to_string());
    assert_eq!(config.tools[3].extentions[0], "conf".to_string());
}
<commit_msg>support the command has default multiple arguments<commit_after>#[macro_use]
extern crate serde_derive;
extern crate toml;
extern crate getopts;
use std::env;
use std::fs;
use std::io;
use std::io::prelude::*;
use std::io::Write;
use std::path;
use std::process;
use getopts::Options;
use getopts::ParsingStyle;

const DEFAULT_CONF_PATH: &str = "~/.config/openby/config";

#[derive(Debug)]
enum AppError {
    Io(io::Error),
    Toml(toml::de::Error),
}

#[allow(dead_code)]
#[derive(Deserialize)]
struct Config {
    version: f64,
    tools: Vec<Tools>,
}

#[allow(dead_code)]
#[derive(Deserialize)]
struct Tools {
    command: String,
    extentions: Vec<String>,
}

fn main() {
    let exit_code = match run() {
        Ok(_) => 0,
        Err(e) => {
            writeln!(&mut io::stderr(), "{:?}", e).unwrap();
            1
        }
    };
    process::exit(exit_code);
}

fn run() -> Result<(), AppError> {
    let args: Vec<String> = env::args().collect();
    let args_str: Vec<&str> = args.iter().map(|s| s.as_str()).collect();
    let (file_name, conf_name) = parse_options(args_str)?;
    println!("Ok: {} {}", file_name, conf_name);

    let conf = load_config(&conf_name)?;

    open_by(&conf, &file_name)?;

    Ok(())
}

fn parse_options(args: Vec<&str>) -> Result<(String, String), AppError> {
    let ref program = &args[0];

    let mut opts = Options::new();
    opts.parsing_style(ParsingStyle::FloatingFrees);
    opts.optopt("c", "config", "specify configure file name", "CONFIG");
    opts.optflag("h", "help", "print this help menu");

    let matches = opts.parse(&args[1..]).unwrap();

    if matches.opt_present("h") {
        print_usage(&program, &opts);
        process::exit(0);
    }

    let file_name = if !matches.free.is_empty() {
        matches.free[0].clone()
    } else {
        print_usage(&program, &opts);
        return Result::Err(AppError::Io(
            io::Error::new(io::ErrorKind::NotFound, "FILE is not found"),
        ));
    };

    let conf_name = if let Some(c) = matches.opt_str("c") {
        c
    } else {
        DEFAULT_CONF_PATH.to_string()
    };

    Ok((file_name, conf_name))
}

fn print_usage(program: &str, opts: &Options) {
    let brief = format!("Usage: {} [options] FILE", program);
    println!("{}", opts.usage(&brief));
}

fn load_config(conf_name: &str) -> Result<Config, AppError> {
    let path = path::Path::new(conf_name);
    if path.exists() == false {
        return Result::Err(AppError::Io(io::Error::new(
            io::ErrorKind::NotFound,
            format!("{} is not exist", path.to_str().unwrap_or("")),
        )));
    }

    let mut reader = io::BufReader::new(fs::File::open(path).map_err(AppError::Io)?);
    let mut s = String::new();
    reader.read_to_string(&mut s).map_err(AppError::Io)?;

    let conf: Config = toml::from_str(s.as_str()).map_err(AppError::Toml)?;

    Ok(conf)
}

fn open_by(conf: &Config, file_name: &str) -> Result<(), AppError> {
    let file_path = path::Path::new(file_name);
    if file_path.exists() == false {
        return Result::Err(AppError::Io(io::Error::new(
            io::ErrorKind::NotFound,
            format!("{} is not exist", file_path.to_str().unwrap_or("")),
        )));
    }

    let ext = file_path.extension().ok_or(AppError::Io(io::Error::new(
        io::ErrorKind::NotFound,
        format!(
            "{} has not extension",
            file_path.to_str().unwrap_or("")
        ),
    )))?;

    match get_commnad_from_extension(conf, ext.to_str().unwrap()) {
        Some(cmdline) => {
            let cmd: Vec<&str> = cmdline.split_whitespace().collect();
            println!("exec {:?} {:?}", cmd, file_path);

            if cmd.len() > 1 {
                process::Command::new(cmd[0])
                    .args(cmd[1..].into_iter())
                    .arg(file_path)
                    .status()
                    .expect("failed to run");
            } else {
                process::Command::new(cmd[0])
                    .arg(file_path)
                    .status()
                    .expect("failed to run");
            }
        }
        None => {
            println!("command = None");
            // TODO: register command about this extension.
        }
    }

    Ok(())
}

fn get_commnad_from_extension(conf: &Config, extension: &str) -> Option<String> {
    let ext_string = extension.to_string();
    for t in conf.tools.iter() {
        if t.extentions.contains(&ext_string) {
            return Some(t.command.clone());
        }
    }
    None
}

#[test]
fn test_parse_options() {
    let no_arguments = vec!["openby", "input.file", "-c", "configure.file"];

    assert!(parse_options(no_arguments[0..1].to_vec()).is_err());
    assert_eq!(
        ("input.file".to_string(), DEFAULT_CONF_PATH.to_string()),
        parse_options(no_arguments[0..2].to_vec()).unwrap_or(("".to_string(), "".to_string()))
    );
    assert_eq!(
        ("input.file".to_string(), "configure.file".to_string()),
        parse_options(no_arguments).unwrap_or(("".to_string(), "".to_string()))
    );
}

#[test]
fn test_decode_toml() {
    let toml_config_str = r#"
    version = 0.0

    [[tools]]
    command = "apvlv"
    extentions = [ "pdf" ]

    [[tools]]
    command = "mirage"
    extentions = [ "jpg", "png", "gif" ]

    [[tools]]
    command = "vlc"
    extentions = [ "mp4", "mov", "avi" ]

    [[tools]]
    command = "vim -R"
    extentions = [ "conf" ]
    "#;

    let config: Config = toml::from_str(toml_config_str).unwrap();
    assert_eq!(config.version, 0.0);

    assert_eq!(config.tools[0].command, "apvlv".to_string());
    assert_eq!(config.tools[0].extentions[0], "pdf".to_string());

    assert_eq!(config.tools[1].command, "mirage".to_string());
    assert_eq!(config.tools[1].extentions[0], "jpg".to_string());
    assert_eq!(config.tools[1].extentions[1], "png".to_string());
    assert_eq!(config.tools[1].extentions[2], "gif".to_string());

    assert_eq!(config.tools[2].command, "vlc".to_string());
    assert_eq!(config.tools[2].extentions[0], "mp4".to_string());
    assert_eq!(config.tools[2].extentions[1], "mov".to_string());
    assert_eq!(config.tools[2].extentions[2], "avi".to_string());

    assert_eq!(config.tools[3].command, "vim -R".to_string());
    assert_eq!(config.tools[3].extentions[0], "conf".to_string());
}
<|endoftext|>


<commit_before>extern crate futures;
extern crate futures_cpupool;
extern crate time;
extern crate wikidata;

use std::sync::mpsc::channel;

use futures::Future;
use futures_cpupool::CpuPool;
use time::precise_time_ns;

use wikidata::parse::parse_item;
use wikidata::read::Streamer;
use wikidata::param::{Parameters,read_params};

fn main() {
    let t0 = precise_time_ns();

    let Parameters{input_file, languages} = read_params();
    println!("Input file: {}", input_file);
    println!("Languages: {:?}", languages);

    let (tx, rx) = channel();
    if let Ok(streamer) = Streamer::new(&input_file) {
        let t00 = precise_time_ns();
        let pool = CpuPool::new(4);
        let mut futs = Vec::new();
        for line in streamer {
            let l = line.clone();
            let langs = languages.clone();
            let tx = tx.clone();
            let t = pool.spawn_fn(move || {
                parse_item(&l, &langs)
                    .ok()
                    .and_then(|l| l)
                    .map(|e| {
                        let _ = tx.send(e);
                    });
                Ok::<(), ()>(())
            });
            futs.push(t);
        }
        for f in futs {
            let _ = f.wait();
        }
        let t10 = precise_time_ns();
        println!("Main loop: {} us", (t10 - t00) / 1000 );
    }

    let t000 = precise_time_ns();
    let mut same = 0;
    let mut different = 0;
    drop(tx); // Close the original sender, since we won't be sending anything from it
    for e in rx {
        if e[&languages[0]] == e[&languages[1]] {
            same += 1
        } else {
            different += 1
        }
    }
    let t100 = precise_time_ns();
    println!("Counting: {} us", (t100 - t000) / 1000 );

    let t1 = precise_time_ns();
    println!("Results - Same: {}, Different: {}", same, different);
    println!("Time: {} us", (t1 - t0) / 1000 )
}
<commit_msg>Can wait on the futures after we're done counting results<commit_after>extern crate futures;
extern crate futures_cpupool;
extern crate time;
extern crate wikidata;

use std::sync::mpsc::channel;

use futures::Future;
use futures_cpupool::CpuPool;
use time::precise_time_ns;

use wikidata::parse::parse_item;
use wikidata::read::Streamer;
use wikidata::param::{Parameters,read_params};

fn main() {
    let t0 = precise_time_ns();

    let Parameters{input_file, languages} = read_params();
    println!("Input file: {}", input_file);
    println!("Languages: {:?}", languages);

    let pool = CpuPool::new(4);
    let mut futs = Vec::new();
    let (tx, rx) = channel();
    if let Ok(streamer) = Streamer::new(&input_file) {
        let t00 = precise_time_ns();
        for line in streamer {
            let l = line.clone();
            let langs = languages.clone();
            let tx = tx.clone();
            let t = pool.spawn_fn(move || {
                parse_item(&l, &langs)
                    .ok()
                    .and_then(|l| l)
                    .map(|e| {
                        let _ = tx.send(e);
                    });
                Ok::<(), ()>(())
            });
            futs.push(t);
        }
        let t10 = precise_time_ns();
        println!("Main loop: {} us", (t10 - t00) / 1000 );
    }

    let t000 = precise_time_ns();
    let mut same = 0;
    let mut different = 0;
    drop(tx); // Close the original sender, since we won't be sending anything from it
    for e in rx {
        if e[&languages[0]] == e[&languages[1]] {
            same += 1
        } else {
            different += 1
        }
    }
    for f in futs {
        let _ = f.wait();
    }
    let t100 = precise_time_ns();
    println!("Counting: {} us", (t100 - t000) / 1000 );

    let t1 = precise_time_ns();
    println!("Results - Same: {}, Different: {}", same, different);
    println!("Time: {} us", (t1 - t0) / 1000 )
}
<|endoftext|>


<commit_before>extern crate emailaddress;
extern crate iron;
extern crate lettre;
extern crate openssl;
extern crate rand;
extern crate redis;
extern crate router;
extern crate rustc_serialize;
extern crate serde_json;
extern crate time;
extern crate url;
extern crate urlencoded;

use emailaddress::EmailAddress;
use iron::headers::ContentType;
use iron::middleware::Handler;
use iron::prelude::*;
use iron::status;
use lettre::email::EmailBuilder;
use lettre::transport::smtp::SmtpTransportBuilder;
use lettre::transport::EmailTransport;
use urlencoded::{UrlEncodedBody, UrlEncodedQuery};
use openssl::bn::BigNum;
use openssl::crypto::pkey::PKey;
use openssl::crypto::hash;
use serde_json::builder::ObjectBuilder;
use serde_json::de::from_reader;
use serde_json::value::Value;
use redis::{Client, Commands, RedisResult};
use router::Router;
use rustc_serialize::base64::{self, ToBase64};
use std::collections::{BTreeMap, HashMap};
use std::env;
use std::error::Error;
use std::fs::File;
use std::io::{self, BufReader, Write};
use std::iter::Iterator;
use time::now_utc;
use url::percent_encoding::{utf8_percent_encode, QUERY_ENCODE_SET};

fn json_response(obj: &Value) -> IronResult<Response> {
    let content = serde_json::to_string(&obj).unwrap();
    let mut rsp = Response::with((status::Ok, content));
    rsp.headers.set(ContentType::json());
    Ok(rsp)
}

struct WelcomeHandler { app: AppConfig }
impl Handler for WelcomeHandler {
    fn handle(&self, _: &mut Request) -> IronResult<Response> {
        json_response(&ObjectBuilder::new()
            .insert("ladaemon", "Welcome")
            .insert("version", &self.app.version)
            .unwrap())
    }
}

struct OIDConfigHandler { app: AppConfig }
impl Handler for OIDConfigHandler {
    fn handle(&self, _: &mut Request) -> IronResult<Response> {
        json_response(&ObjectBuilder::new()
            .insert("issuer", &self.app.base_url)
            .insert("authorization_endpoint",
                    format!("{}/auth", self.app.base_url))
            .insert("jwks_uri", format!("{}/keys.json", self.app.base_url))
            .insert("scopes_supported", vec!["openid", "email"])
            .insert("claims_supported",
                    vec!["aud", "email", "email_verified", "exp", "iat", "iss", "sub"])
            .insert("response_types_supported", vec!["id_token"])
            .insert("response_modes_supported", vec!["form_post"])
            .insert("grant_types_supported", vec!["implicit"])
            .insert("subject_types_supported", vec!["public"])
            .insert("id_token_signing_alg_values_supported", vec!["RS256"])
            .unwrap())
    }
}

#[derive(Clone)]
struct ProviderConfig {
    discovery: String,
    client_id: String,
    secret: String,
}

#[derive(Clone)]
struct AppConfig {
    version: String,
    base_url: String,
    priv_key: PKey,
    store: Client,
    expire_keys: usize,
    sender: String,
    token_validity: i64,
    providers: BTreeMap<String, ProviderConfig>,
}

fn json_big_num(n: &BigNum) -> String {
    n.to_vec().to_base64(base64::URL_SAFE)
}

struct KeysHandler { app: AppConfig }
impl Handler for KeysHandler {
    fn handle(&self, _: &mut Request) -> IronResult<Response> {
        let rsa = self.app.priv_key.get_rsa();
        json_response(&ObjectBuilder::new()
            .insert_array("keys", |builder| {
                builder.push_object(|builder| {
                    builder.insert("kty", "RSA")
                        .insert("alg", "RS256")
                        .insert("use", "sig")
                        .insert("kid", "base")
                        .insert("n", json_big_num(&rsa.n().unwrap()))
                        .insert("e", json_big_num(&rsa.e().unwrap()))
                })
            })
            .unwrap())
    }
}

const CODE_CHARS: &'static [char] = &[
    '2', '3', '4', '6', '7', '9', 'a', 'c', 'd', 'e', 'f', 'g', 'h', 'j', 'k',
    'm', 'n', 'p', 'q', 'r', 't', 'v', 'w', 'x', 'y', 'z',
];

struct AuthHandler { app: AppConfig }
impl Handler for AuthHandler {
    fn handle(&self, req: &mut Request) -> IronResult<Response> {

        let chars: String = (0..6).map(|_| CODE_CHARS[rand::random::<usize>() % CODE_CHARS.len()]).collect();
        let params = req.get_ref::<UrlEncodedBody>().unwrap();
        let email_addr = EmailAddress::new(&params.get("login_hint").unwrap()[0]);
        let client_id = &params.get("client_id").unwrap()[0];
        let key = format!("{}:{}", email_addr, client_id);
        let set_res: RedisResult<String> = self.app.store.hset_multiple(key.clone(), &[
            ("code", chars.clone()),
            ("redirect", params.get("redirect_uri").unwrap()[0].clone()),
        ]);
        let exp_res: RedisResult<bool> = self.app.store.expire(key.clone(), self.app.expire_keys);

        let href = format!("{}/confirm?email={}&origin={}&code={}",
                           self.app.base_url,
                           utf8_percent_encode(&email_addr.to_string(), QUERY_ENCODE_SET),
                           utf8_percent_encode(client_id, QUERY_ENCODE_SET),
                           utf8_percent_encode(&chars, QUERY_ENCODE_SET));
        let email = EmailBuilder::new()
            .to(email_addr.to_string().as_str())
            .from(self.app.sender.as_str())
            .body(&format!("Enter your login code:\n\n{}\n\nOr click this link:\n\n{}",
                           chars, href))
            .subject(&format!("Code: {} - Finish logging in to {}", chars, client_id))
            .build().unwrap();
        let mut mailer = SmtpTransportBuilder::localhost().unwrap().build();
        let result = mailer.send(email);
        mailer.close();

        let mut obj = ObjectBuilder::new()
            .insert("href", href);
        if !result.is_ok() {
            let error = result.unwrap_err();
            obj = obj.insert("error", error.to_string());
            obj = match error {
                lettre::transport::error::Error::IoError(inner) => {
                    obj.insert("cause", inner.description())
                }
                _ => obj,
            }
        }
        if !set_res.is_ok() {
            obj = obj.insert("hset_multiple", set_res.unwrap_err().to_string());
        }
        if !exp_res.is_ok() {
            obj = obj.insert("expire", exp_res.unwrap_err().to_string());
        }
        json_response(&obj.unwrap())

    }
}

fn create_jwt(key: &PKey, header: &str, payload: &str) -> String {
    let mut input = Vec::<u8>::new();
    input.extend(header.as_bytes().to_base64(base64::URL_SAFE).into_bytes());
    input.push(b'.');
    input.extend(payload.as_bytes().to_base64(base64::URL_SAFE).into_bytes());
    let sha256 = hash::hash(hash::Type::SHA256, &input);
    let sig = key.sign(&sha256);
    input.push(b'.');
    input.extend(sig.to_base64(base64::URL_SAFE).into_bytes());
    String::from_utf8(input).unwrap()
}

const FORWARD_TEMPLATE: &'static str = r#"<!DOCTYPE html>
<html>
  <head>
    <title>Let's Auth</title>
    <script>
      document.addEventListener('DOMContentLoaded', function() {
        document.getElementById('form').submit();
      });
    </script>
  </head>
  <body>
    <form id="form" action="{{ return_url }}" method="post">
      <input type="hidden" name="id_token" value="{{ jwt }}">
    </form>
  </body>
</html>"#;

struct ConfirmHandler { app: AppConfig }
impl Handler for ConfirmHandler {
    fn handle(&self, req: &mut Request) -> IronResult<Response> {

        let params = req.get_ref::<UrlEncodedQuery>().unwrap();
        let email = &params.get("email").unwrap()[0];
        let origin = &params.get("origin").unwrap()[0];
        let key = format!("{}:{}", email, origin);
        let stored: HashMap<String, String> = self.app.store.hgetall(key.clone()).unwrap();

        let req_code = &params.get("code").unwrap()[0];
        if stored.get("code").is_none() || req_code != stored.get("code").unwrap() {
            let mut obj = ObjectBuilder::new().insert("error", "code fail");
            obj = obj.insert("stored", stored);
            return json_response(&obj.unwrap());
        }

        let now = now_utc().to_timespec().sec;
        let payload = ObjectBuilder::new()
            .insert("aud", origin)
            .insert("email", email)
            .insert("email_verified", email)
            .insert("exp", now + self.app.token_validity)
            .insert("iat", now)
            .insert("iss", &self.app.base_url)
            .insert("sub", email)
            .unwrap();
        let headers = ObjectBuilder::new()
            .insert("kid", "base")
            .insert("alg", "RS256")
            .unwrap();
        let jwt = create_jwt(&self.app.priv_key,
                             &serde_json::to_string(&headers).unwrap(),
                             &serde_json::to_string(&payload).unwrap());

        let redirect = stored.get("redirect").unwrap();
        let html = FORWARD_TEMPLATE.replace("{{ return_url }}", redirect)
            .replace("{{ jwt }}", &jwt);

        let mut rsp = Response::with((status::Ok, html));
        rsp.headers.set(ContentType::html());
        Ok(rsp)

    }
}

fn main() {

    let args: Vec<String> = env::args().collect();
    if args.len() < 2 {
        io::stderr().write(b"no configuration file specified\n").unwrap();
        return;
    }

    let config_file = File::open(&args[1]).unwrap();
    let config_reader = BufReader::new(config_file);
    let config: Value = from_reader(config_reader).unwrap();

    let key_file_name = config.find("private_key_file").unwrap().as_string().unwrap();
    let priv_key_file = File::open(key_file_name).unwrap();
    let mut reader = BufReader::new(priv_key_file);
    let app = AppConfig {
        version: env!("CARGO_PKG_VERSION").to_string(),
        base_url: config.find("base_url").unwrap().as_string().unwrap().to_string(),
        priv_key: PKey::private_key_from_pem(&mut reader).unwrap(),
        store: Client::open(config.find("redis").unwrap().as_string().unwrap()).unwrap(),
        expire_keys: config.find("expire_keys").unwrap().as_u64().unwrap() as usize,
        sender: "Let's Auth <letsauth@xavamedia.nl>".to_string(),
        token_validity: config.find("token_validity").unwrap().as_i64().unwrap(),
        providers: config.find("providers").unwrap().as_object().unwrap().iter()
            .map(|(host, params)| {
                let pobj = params.as_object().unwrap();
                (host.clone(), ProviderConfig {
                    discovery: pobj["discovery"].as_string().unwrap().to_string(),
                    client_id: pobj["client_id"].as_string().unwrap().to_string(),
                    secret: pobj["secret"].as_string().unwrap().to_string(),
                })
            })
            .collect::<BTreeMap<String, ProviderConfig>>(),
    };

    let mut router = Router::new();
    router.get("/", WelcomeHandler { app: app.clone() });
    router.get("/.well-known/openid-configuration",
               OIDConfigHandler { app: app.clone() });
    router.get("/keys.json", KeysHandler { app: app.clone() });
    router.post("/auth", AuthHandler { app: app.clone() });
    router.get("/confirm", ConfirmHandler { app: app.clone() });
    Iron::new(router).http("0.0.0.0:3333").unwrap();

}
<commit_msg>Extract send_jwt_response() function for reuse<commit_after>extern crate emailaddress;
extern crate iron;
extern crate lettre;
extern crate openssl;
extern crate rand;
extern crate redis;
extern crate router;
extern crate rustc_serialize;
extern crate serde_json;
extern crate time;
extern crate url;
extern crate urlencoded;

use emailaddress::EmailAddress;
use iron::headers::ContentType;
use iron::middleware::Handler;
use iron::prelude::*;
use iron::status;
use lettre::email::EmailBuilder;
use lettre::transport::smtp::SmtpTransportBuilder;
use lettre::transport::EmailTransport;
use urlencoded::{UrlEncodedBody, UrlEncodedQuery};
use openssl::bn::BigNum;
use openssl::crypto::pkey::PKey;
use openssl::crypto::hash;
use serde_json::builder::ObjectBuilder;
use serde_json::de::from_reader;
use serde_json::value::Value;
use redis::{Client, Commands, RedisResult};
use router::Router;
use rustc_serialize::base64::{self, ToBase64};
use std::collections::{BTreeMap, HashMap};
use std::env;
use std::error::Error;
use std::fs::File;
use std::io::{self, BufReader, Write};
use std::iter::Iterator;
use time::now_utc;
use url::percent_encoding::{utf8_percent_encode, QUERY_ENCODE_SET};

fn json_response(obj: &Value) -> IronResult<Response> {
    let content = serde_json::to_string(&obj).unwrap();
    let mut rsp = Response::with((status::Ok, content));
    rsp.headers.set(ContentType::json());
    Ok(rsp)
}

struct WelcomeHandler { app: AppConfig }
impl Handler for WelcomeHandler {
    fn handle(&self, _: &mut Request) -> IronResult<Response> {
        json_response(&ObjectBuilder::new()
            .insert("ladaemon", "Welcome")
            .insert("version", &self.app.version)
            .unwrap())
    }
}

struct OIDConfigHandler { app: AppConfig }
impl Handler for OIDConfigHandler {
    fn handle(&self, _: &mut Request) -> IronResult<Response> {
        json_response(&ObjectBuilder::new()
            .insert("issuer", &self.app.base_url)
            .insert("authorization_endpoint",
                    format!("{}/auth", self.app.base_url))
            .insert("jwks_uri", format!("{}/keys.json", self.app.base_url))
            .insert("scopes_supported", vec!["openid", "email"])
            .insert("claims_supported",
                    vec!["aud", "email", "email_verified", "exp", "iat", "iss", "sub"])
            .insert("response_types_supported", vec!["id_token"])
            .insert("response_modes_supported", vec!["form_post"])
            .insert("grant_types_supported", vec!["implicit"])
            .insert("subject_types_supported", vec!["public"])
            .insert("id_token_signing_alg_values_supported", vec!["RS256"])
            .unwrap())
    }
}

#[derive(Clone)]
struct ProviderConfig {
    discovery: String,
    client_id: String,
    secret: String,
}

#[derive(Clone)]
struct AppConfig {
    version: String,
    base_url: String,
    priv_key: PKey,
    store: Client,
    expire_keys: usize,
    sender: String,
    token_validity: i64,
    providers: BTreeMap<String, ProviderConfig>,
}

fn json_big_num(n: &BigNum) -> String {
    n.to_vec().to_base64(base64::URL_SAFE)
}

struct KeysHandler { app: AppConfig }
impl Handler for KeysHandler {
    fn handle(&self, _: &mut Request) -> IronResult<Response> {
        let rsa = self.app.priv_key.get_rsa();
        json_response(&ObjectBuilder::new()
            .insert_array("keys", |builder| {
                builder.push_object(|builder| {
                    builder.insert("kty", "RSA")
                        .insert("alg", "RS256")
                        .insert("use", "sig")
                        .insert("kid", "base")
                        .insert("n", json_big_num(&rsa.n().unwrap()))
                        .insert("e", json_big_num(&rsa.e().unwrap()))
                })
            })
            .unwrap())
    }
}

const CODE_CHARS: &'static [char] = &[
    '2', '3', '4', '6', '7', '9', 'a', 'c', 'd', 'e', 'f', 'g', 'h', 'j', 'k',
    'm', 'n', 'p', 'q', 'r', 't', 'v', 'w', 'x', 'y', 'z',
];

struct AuthHandler { app: AppConfig }
impl Handler for AuthHandler {
    fn handle(&self, req: &mut Request) -> IronResult<Response> {

        let chars: String = (0..6).map(|_| CODE_CHARS[rand::random::<usize>() % CODE_CHARS.len()]).collect();
        let params = req.get_ref::<UrlEncodedBody>().unwrap();
        let email_addr = EmailAddress::new(&params.get("login_hint").unwrap()[0]);
        let client_id = &params.get("client_id").unwrap()[0];
        let key = format!("{}:{}", email_addr, client_id);
        let set_res: RedisResult<String> = self.app.store.hset_multiple(key.clone(), &[
            ("code", chars.clone()),
            ("redirect", params.get("redirect_uri").unwrap()[0].clone()),
        ]);
        let exp_res: RedisResult<bool> = self.app.store.expire(key.clone(), self.app.expire_keys);

        let href = format!("{}/confirm?email={}&origin={}&code={}",
                           self.app.base_url,
                           utf8_percent_encode(&email_addr.to_string(), QUERY_ENCODE_SET),
                           utf8_percent_encode(client_id, QUERY_ENCODE_SET),
                           utf8_percent_encode(&chars, QUERY_ENCODE_SET));
        let email = EmailBuilder::new()
            .to(email_addr.to_string().as_str())
            .from(self.app.sender.as_str())
            .body(&format!("Enter your login code:\n\n{}\n\nOr click this link:\n\n{}",
                           chars, href))
            .subject(&format!("Code: {} - Finish logging in to {}", chars, client_id))
            .build().unwrap();
        let mut mailer = SmtpTransportBuilder::localhost().unwrap().build();
        let result = mailer.send(email);
        mailer.close();

        let mut obj = ObjectBuilder::new()
            .insert("href", href);
        if !result.is_ok() {
            let error = result.unwrap_err();
            obj = obj.insert("error", error.to_string());
            obj = match error {
                lettre::transport::error::Error::IoError(inner) => {
                    obj.insert("cause", inner.description())
                }
                _ => obj,
            }
        }
        if !set_res.is_ok() {
            obj = obj.insert("hset_multiple", set_res.unwrap_err().to_string());
        }
        if !exp_res.is_ok() {
            obj = obj.insert("expire", exp_res.unwrap_err().to_string());
        }
        json_response(&obj.unwrap())

    }
}

fn create_jwt(key: &PKey, header: &str, payload: &str) -> String {
    let mut input = Vec::<u8>::new();
    input.extend(header.as_bytes().to_base64(base64::URL_SAFE).into_bytes());
    input.push(b'.');
    input.extend(payload.as_bytes().to_base64(base64::URL_SAFE).into_bytes());
    let sha256 = hash::hash(hash::Type::SHA256, &input);
    let sig = key.sign(&sha256);
    input.push(b'.');
    input.extend(sig.to_base64(base64::URL_SAFE).into_bytes());
    String::from_utf8(input).unwrap()
}

const FORWARD_TEMPLATE: &'static str = r#"<!DOCTYPE html>
<html>
  <head>
    <title>Let's Auth</title>
    <script>
      document.addEventListener('DOMContentLoaded', function() {
        document.getElementById('form').submit();
      });
    </script>
  </head>
  <body>
    <form id="form" action="{{ return_url }}" method="post">
      <input type="hidden" name="id_token" value="{{ jwt }}">
    </form>
  </body>
</html>"#;

fn send_jwt_response(email: &str, origin: &str, redirect: &str, app: &AppConfig) -> IronResult<Response> {

    let now = now_utc().to_timespec().sec;
    let payload = ObjectBuilder::new()
        .insert("aud", origin)
        .insert("email", email)
        .insert("email_verified", email)
        .insert("exp", now + app.token_validity)
        .insert("iat", now)
        .insert("iss", &app.base_url)
        .insert("sub", email)
        .unwrap();
    let headers = ObjectBuilder::new()
        .insert("kid", "base")
        .insert("alg", "RS256")
        .unwrap();
    let jwt = create_jwt(&app.priv_key,
                         &serde_json::to_string(&headers).unwrap(),
                         &serde_json::to_string(&payload).unwrap());

    let html = FORWARD_TEMPLATE.replace("{{ return_url }}", redirect)
        .replace("{{ jwt }}", &jwt);
    let mut rsp = Response::with((status::Ok, html));
    rsp.headers.set(ContentType::html());
    Ok(rsp)

}

struct ConfirmHandler { app: AppConfig }
impl Handler for ConfirmHandler {
    fn handle(&self, req: &mut Request) -> IronResult<Response> {

        let params = req.get_ref::<UrlEncodedQuery>().unwrap();
        let email = &params.get("email").unwrap()[0];
        let origin = &params.get("origin").unwrap()[0];
        let key = format!("{}:{}", email, origin);
        let stored: HashMap<String, String> = self.app.store.hgetall(key.clone()).unwrap();

        let req_code = &params.get("code").unwrap()[0];
        if stored.get("code").is_none() || req_code != stored.get("code").unwrap() {
            let mut obj = ObjectBuilder::new().insert("error", "code fail");
            obj = obj.insert("stored", stored);
            return json_response(&obj.unwrap());
        }

        let redirect = stored.get("redirect").unwrap();
        send_jwt_response(email, origin, redirect, &self.app)

    }
}

fn main() {

    let args: Vec<String> = env::args().collect();
    if args.len() < 2 {
        io::stderr().write(b"no configuration file specified\n").unwrap();
        return;
    }

    let config_file = File::open(&args[1]).unwrap();
    let config_reader = BufReader::new(config_file);
    let config: Value = from_reader(config_reader).unwrap();

    let key_file_name = config.find("private_key_file").unwrap().as_string().unwrap();
    let priv_key_file = File::open(key_file_name).unwrap();
    let mut reader = BufReader::new(priv_key_file);
    let app = AppConfig {
        version: env!("CARGO_PKG_VERSION").to_string(),
        base_url: config.find("base_url").unwrap().as_string().unwrap().to_string(),
        priv_key: PKey::private_key_from_pem(&mut reader).unwrap(),
        store: Client::open(config.find("redis").unwrap().as_string().unwrap()).unwrap(),
        expire_keys: config.find("expire_keys").unwrap().as_u64().unwrap() as usize,
        sender: "Let's Auth <letsauth@xavamedia.nl>".to_string(),
        token_validity: config.find("token_validity").unwrap().as_i64().unwrap(),
        providers: config.find("providers").unwrap().as_object().unwrap().iter()
            .map(|(host, params)| {
                let pobj = params.as_object().unwrap();
                (host.clone(), ProviderConfig {
                    discovery: pobj["discovery"].as_string().unwrap().to_string(),
                    client_id: pobj["client_id"].as_string().unwrap().to_string(),
                    secret: pobj["secret"].as_string().unwrap().to_string(),
                })
            })
            .collect::<BTreeMap<String, ProviderConfig>>(),
    };

    let mut router = Router::new();
    router.get("/", WelcomeHandler { app: app.clone() });
    router.get("/.well-known/openid-configuration",
               OIDConfigHandler { app: app.clone() });
    router.get("/keys.json", KeysHandler { app: app.clone() });
    router.post("/auth", AuthHandler { app: app.clone() });
    router.get("/confirm", ConfirmHandler { app: app.clone() });
    Iron::new(router).http("0.0.0.0:3333").unwrap();

}
<|endoftext|>