<commit_before>use std::fs;
use std::io::Result;
use std::fs::File;
use std::fs::Metadata;
use std::io::Read;
use std::io::BufReader;
use std::io::Seek;
use std::io::SeekFrom;
use std::option::Option;

extern crate crypto;
use crypto::digest::Digest;

fn main() {
    match fs::read_dir("/Users/alexeyakhunov/Library/Application Support/Bitcoin/blocks") {
        Err(why) => println!("{:?}", why),
        Ok(dir_entries) => {
            let mut block_number: u32 = 0;
            for dir_entry in dir_entries {
                block_number = parse_file(dir_entry, block_number);
            }
        }
    };
}

fn parse_file(dir_entry: Result<fs::DirEntry>, initial_block: u32) -> u32 {
    match dir_entry {
        Err(why) => {
            println!("{:?}", why);
            0
        },
        Ok(path) => {
            let filepath = path.path();
            let filename = filepath.file_name().unwrap().to_str().unwrap();
            if filename.starts_with("blk") && filename.ends_with(".dat") {
                let metadata = fs::metadata(&filepath).unwrap();
                let f = File::open(&filepath);
                match f {
                    Err(why) => {
                        println!("{:?}", why);
                        0
                    }
                    Ok(mut file) => {
                        println!("Opened {:?}", filename);
                        read_blocks(&mut file, metadata.len(), initial_block)
                    },
                }
            } else {
                0
            }
        }
    }
}

fn read_blocks(file: &mut File, filesize: u64, initial_block: u32) -> u32 {
    let mut reader = BufReader::new(file);
    let mut buf: [u8; 4] = [0u8; 4];
    let mut block: Vec<u8> = vec![];
    let mut block_number: u32 = initial_block;
    loop {
        match reader.read_exact(&mut buf) {
            Err(_) => break,
            Ok(_) => {
                let magic = (buf[0] as u32) | ((buf[1] as u32)<<8) | ((buf[2] as u32)<<16) | ((buf[3] as u32)<<24);
                assert_eq!(3652501241, magic);
            }
        }
        reader.read_exact(&mut buf);
        let size = (buf[0] as u32) | ((buf[1] as u32)<<8) | ((buf[2] as u32)<<16) | ((buf[3] as u32)<<24);
        //println!("Read size {:?}", size);
        println!("Block {:?}", block_number);
        read_block(&mut reader, size as u64, &mut block);
        block_number += 1;
    }
    block_number
}

fn read_block<R>(reader:R, size: u64, block: &mut Vec<u8>) where R: Read, {
    block.clear();
    let mut block_reader = reader.take(size);
    match block_reader.read_to_end(block) {
        Err(_) => println!("Error reading block"),
        Ok(len) => {
            let (tx_count, pos) = read_varint(&block, 80);
            println!("Number of transactions: {:?}", tx_count);
            let mut p = pos;
            for _ in 0..tx_count {
                let version_p = read_u32(&block, p);
                p = version_p.1;
                // Read number of inputs
                let num_inputs_p = read_varint(&block, p);
                let num_inputs = num_inputs_p.0;
                p = num_inputs_p.1;
                for _ in 0..num_inputs {
                    let is_coinbase = block[p..p+32] == [0u8;32];
                    p += 32; // Skip prevout_hash
                    p += 4; // Skip prevous_n
                    let script_sig_len_p = read_varint(&block, p);
                    let script_sig_len = script_sig_len_p.0;
                    p = script_sig_len_p.1;
                    if !is_coinbase {
                        let script_sig: &[u8] = &block[p..p+(script_sig_len as usize)];
                        let decoded_script_sig = decode_script(script_sig);
                        //public_key_from_script(decoded_script_sig);
                    }
                    p = script_sig_len_p.1;
                    p += script_sig_len as usize; // Skip script_sig for now
                    p += 4; // Skip sequence
                }
                let num_outputs_p = read_varint(&block, p);
                let num_outputs = num_outputs_p.0;
                p = num_outputs_p.1;
                for _ in 0..num_outputs {
                    let value_p = read_u64(&block, p);
                    p = value_p.1;
                    let script_pub_key_len_p = read_varint(&block, p);
                    let script_pub_key_len = script_pub_key_len_p.0;
                    p = script_pub_key_len_p.1;
                    p += script_pub_key_len as usize; // Skip script_pub_key for now
                }
                p += 4; // Skip locktime
            }
            assert_eq!(size as usize, p);
        },
    }
}

fn read_u16(slice: &[u8], pos: usize) -> (u16, usize) {
    ((slice[pos] as u16) | ((slice[pos+1] as u16)<<8), pos+2)
}
fn read_u32(slice: &[u8], pos: usize) -> (u32, usize) {
    ((slice[pos] as u32) | ((slice[pos+1] as u32)<<8) | ((slice[pos+2] as u32)<<16) | ((slice[pos+3] as u32)<<24), pos+4)
}

fn read_u64(slice: &[u8], pos: usize) -> (u64, usize) {
    ((slice[pos] as u64) | ((slice[pos+1] as u64)<<8) | ((slice[pos+2] as u64)<<16) | ((slice[pos+3] as u64)<<24) |
        ((slice[pos+4] as u64)<<32) | ((slice[pos+5] as u64)<<40) | ((slice[pos+6] as u64)<<48) | ((slice[pos+7] as u64)<<56), pos+8)
}

fn read_varint(slice: &[u8], pos: usize) -> (u64, usize) {
    match slice[pos] {
        0xFD => ((slice[pos+1] as u64) | ((slice[pos+2] as u64)<<8), pos+3),
        0xFE => ((slice[pos+1] as u64) | ((slice[pos+2] as u64)<<8) | ((slice[pos+3] as u64)<<16) | ((slice[pos+4] as u64)<<24), pos+5),
        0xFF => ((slice[pos+1] as u64) | ((slice[pos+2] as u64)<<8) | ((slice[pos+3] as u64)<<16) | ((slice[pos+4] as u64)<<24) |
                 ((slice[pos+5] as u64)<<32) | ((slice[pos+6] as u64)<<40) | ((slice[pos+7] as u64)<<48) | ((slice[pos+8] as u64)<<56), pos+9),
        _ => (slice[pos] as u64, pos+1),
    }
}

enum Opcode {
    Op0 = 0x00,
    OpPushdata1 = 0x4C, OpPushdata2, OpPushdata4,
    Op1Negate,
    OpReserved,
    Op1, Op2, Op3, Op4, Op5, Op6, Op7, Op8, Op9, Op10, Op11, Op12, Op13, Op14, Op15, Op16,
    OpNop, OpVer, OpIf, OpNotif, OpVerif, OpVerNotIf, OpElse, OpEndif, OpVerify,
    OpReturn, OpTotalStack, OpFromaltstack, Op2Drop, Op2Dup, Op3Dup, Op2Over, Op2Rot, Op2Swap,
    OpIfdup, OpDepth, OpDrop, OpDup, OpNip, OpOver, OpPick, OpRoll, OpRot,
    OpSwap, OpTuck, OpCat, OpSubstr, OpLeft, OpRight, OpSize, OpInvert, OpAnd,
    OpOr, OpXor, OpEqual, OpEqualverify, OpReserved1, OpReserved2, Op1Add, Op1Sub, Op2Mul,
    Op2Div, OpNegate, OpAbs, OpNot, Op0NotEqual, OpAdd, OpSub, OpMul, OpDiv,
    OpMod, OpLshift, OpRshift, OpBooland, OpBoolor,
    OpNumequal, OpNumequalverify, OpNumnotequal, OpLessthan,
    OpGreaterthan, OpLessthanorequal, OpGreaterthanorequal, OpMin, OpMax,
    OpWithin, OpRipemd160, OpSha1, OpSha256, OpHash160,
    OpHash256, OpCodeseparator, OpChecksig, OpChecksigverify, OpCheckmultisig,
    OpCheckmultisigverify,
    OpNop1, OpNop2, OpNop3, OpNop4, OpNop5, OpNop6, OpNop7, OpNop8, OpNop9, OpNop10,
    OpInvalidopcode = 0xFF,
}

fn decode_script(slice: &[u8]) -> Vec<(u8, Option<&[u8]>)> {
    let mut script: Vec<(u8, Option<&[u8]>)> = vec![];
    let mut pos: usize = 0;
    while pos < slice.len() {
        let opcode = slice[pos];
        pos += 1;
        if opcode <= Opcode::OpPushdata4 as u8 {
            let (n_size, new_pos) =
                if opcode == Opcode::OpPushdata1 as u8 {
                    (slice[pos] as usize, pos + 1)
                } else if opcode == Opcode::OpPushdata2 as u8 {
                    let r = read_u16(slice, pos);
                    (r.0 as usize, r.1)
                } else if opcode == Opcode::OpPushdata4 as u8 {
                    let r = read_u32(slice, pos);
                    (r.0 as usize, r.1)
                } else {
                    (opcode as usize, pos)
                };
            pos = new_pos;
            script.push((opcode, Some(&slice[pos..pos+n_size])));
            pos += n_size;
        } else {
            script.push((opcode, None));
        }
    }
    script
}

fn public_key_from_script(decoded_script: Vec<(u8, Option<&[u8]>)>) -> Option<[u8;20]>{
    if decoded_script.len() == 0 {
        None
    } else if decoded_script[0].0 == Opcode::Op0 as u8 {
        // Beginning of a multisignature spend ?
        match decoded_script[decoded_script.len()-1].1 {
            None => None,
            Some(sub_script) => {
                let decoded_sub_script = decode_script(sub_script);
                let mut sha256 = crypto::sha2::Sha256::new();
                sha256.input(sub_script);
                let mut buffer32b: [u8;32] = [0;32];
                sha256.result(&mut buffer32b);
                let mut ripemd160 = crypto::ripemd160::Ripemd160::new();
                ripemd160.input(&buffer32b);
                let mut buffer20b: [u8;20] = [0;20];
                ripemd160.result(&mut buffer20b);
                None
            }
        }
    } else if decoded_script[0].0 <= Opcode::OpPushdata4 as u8 {
        None
    } else {
        None
    }
}
<commit_msg>Gracefully terminate<commit_after>use std::fs;
use std::io::Result;
use std::fs::File;
use std::fs::Metadata;
use std::io::Read;
use std::io::BufReader;
use std::io::Seek;
use std::io::SeekFrom;
use std::option::Option;

extern crate crypto;
use crypto::digest::Digest;

fn main() {
    match fs::read_dir("/Users/alexeyakhunov/Library/Application Support/Bitcoin/blocks") {
        Err(why) => println!("{:?}", why),
        Ok(dir_entries) => {
            let mut block_number: u32 = 0;
            for dir_entry in dir_entries {
                block_number = parse_file(dir_entry, block_number);
            }
        }
    };
}

fn parse_file(dir_entry: Result<fs::DirEntry>, initial_block: u32) -> u32 {
    match dir_entry {
        Err(why) => {
            println!("{:?}", why);
            0
        },
        Ok(path) => {
            let filepath = path.path();
            let filename = filepath.file_name().unwrap().to_str().unwrap();
            if filename.starts_with("blk") && filename.ends_with(".dat") {
                let metadata = fs::metadata(&filepath).unwrap();
                let f = File::open(&filepath);
                match f {
                    Err(why) => {
                        println!("{:?}", why);
                        0
                    }
                    Ok(mut file) => {
                        println!("Opened {:?}", filename);
                        read_blocks(&mut file, metadata.len(), initial_block)
                    },
                }
            } else {
                0
            }
        }
    }
}

fn read_blocks(file: &mut File, filesize: u64, initial_block: u32) -> u32 {
    let mut reader = BufReader::new(file);
    let mut buf: [u8; 4] = [0u8; 4];
    let mut block: Vec<u8> = vec![];
    let mut block_number: u32 = initial_block;
    loop {
        match reader.read_exact(&mut buf) {
            Err(_) => break,
            Ok(_) => {
                let magic = (buf[0] as u32) | ((buf[1] as u32)<<8) | ((buf[2] as u32)<<16) | ((buf[3] as u32)<<24);
                if magic == 0 {
                    break;
                };
                assert_eq!(3652501241, magic);
            }
        }
        reader.read_exact(&mut buf);
        let size = (buf[0] as u32) | ((buf[1] as u32)<<8) | ((buf[2] as u32)<<16) | ((buf[3] as u32)<<24);
        //println!("Read size {:?}", size);
        println!("Block {:?}", block_number);
        read_block(&mut reader, size as u64, &mut block);
        block_number += 1;
    }
    block_number
}

fn read_block<R>(reader:R, size: u64, block: &mut Vec<u8>) where R: Read, {
    block.clear();
    let mut block_reader = reader.take(size);
    match block_reader.read_to_end(block) {
        Err(_) => println!("Error reading block"),
        Ok(len) => {
            let (tx_count, pos) = read_varint(&block, 80);
            println!("Number of transactions: {:?}", tx_count);
            let mut p = pos;
            for _ in 0..tx_count {
                let version_p = read_u32(&block, p);
                p = version_p.1;
                // Read number of inputs
                let num_inputs_p = read_varint(&block, p);
                let num_inputs = num_inputs_p.0;
                p = num_inputs_p.1;
                for _ in 0..num_inputs {
                    let is_coinbase = block[p..p+32] == [0u8;32];
                    p += 32; // Skip prevout_hash
                    p += 4; // Skip prevous_n
                    let script_sig_len_p = read_varint(&block, p);
                    let script_sig_len = script_sig_len_p.0;
                    p = script_sig_len_p.1;
                    if !is_coinbase {
                        let script_sig: &[u8] = &block[p..p+(script_sig_len as usize)];
                        let decoded_script_sig = decode_script(script_sig);
                        //public_key_from_script(decoded_script_sig);
                    }
                    p = script_sig_len_p.1;
                    p += script_sig_len as usize; // Skip script_sig for now
                    p += 4; // Skip sequence
                }
                let num_outputs_p = read_varint(&block, p);
                let num_outputs = num_outputs_p.0;
                p = num_outputs_p.1;
                for _ in 0..num_outputs {
                    let value_p = read_u64(&block, p);
                    p = value_p.1;
                    let script_pub_key_len_p = read_varint(&block, p);
                    let script_pub_key_len = script_pub_key_len_p.0;
                    p = script_pub_key_len_p.1;
                    p += script_pub_key_len as usize; // Skip script_pub_key for now
                }
                p += 4; // Skip locktime
            }
            assert_eq!(size as usize, p);
        },
    }
}

fn read_u16(slice: &[u8], pos: usize) -> (u16, usize) {
    ((slice[pos] as u16) | ((slice[pos+1] as u16)<<8), pos+2)
}
fn read_u32(slice: &[u8], pos: usize) -> (u32, usize) {
    ((slice[pos] as u32) | ((slice[pos+1] as u32)<<8) | ((slice[pos+2] as u32)<<16) | ((slice[pos+3] as u32)<<24), pos+4)
}

fn read_u64(slice: &[u8], pos: usize) -> (u64, usize) {
    ((slice[pos] as u64) | ((slice[pos+1] as u64)<<8) | ((slice[pos+2] as u64)<<16) | ((slice[pos+3] as u64)<<24) |
        ((slice[pos+4] as u64)<<32) | ((slice[pos+5] as u64)<<40) | ((slice[pos+6] as u64)<<48) | ((slice[pos+7] as u64)<<56), pos+8)
}

fn read_varint(slice: &[u8], pos: usize) -> (u64, usize) {
    match slice[pos] {
        0xFD => ((slice[pos+1] as u64) | ((slice[pos+2] as u64)<<8), pos+3),
        0xFE => ((slice[pos+1] as u64) | ((slice[pos+2] as u64)<<8) | ((slice[pos+3] as u64)<<16) | ((slice[pos+4] as u64)<<24), pos+5),
        0xFF => ((slice[pos+1] as u64) | ((slice[pos+2] as u64)<<8) | ((slice[pos+3] as u64)<<16) | ((slice[pos+4] as u64)<<24) |
                 ((slice[pos+5] as u64)<<32) | ((slice[pos+6] as u64)<<40) | ((slice[pos+7] as u64)<<48) | ((slice[pos+8] as u64)<<56), pos+9),
        _ => (slice[pos] as u64, pos+1),
    }
}

enum Opcode {
    Op0 = 0x00,
    OpPushdata1 = 0x4C, OpPushdata2, OpPushdata4,
    Op1Negate,
    OpReserved,
    Op1, Op2, Op3, Op4, Op5, Op6, Op7, Op8, Op9, Op10, Op11, Op12, Op13, Op14, Op15, Op16,
    OpNop, OpVer, OpIf, OpNotif, OpVerif, OpVerNotIf, OpElse, OpEndif, OpVerify,
    OpReturn, OpTotalStack, OpFromaltstack, Op2Drop, Op2Dup, Op3Dup, Op2Over, Op2Rot, Op2Swap,
    OpIfdup, OpDepth, OpDrop, OpDup, OpNip, OpOver, OpPick, OpRoll, OpRot,
    OpSwap, OpTuck, OpCat, OpSubstr, OpLeft, OpRight, OpSize, OpInvert, OpAnd,
    OpOr, OpXor, OpEqual, OpEqualverify, OpReserved1, OpReserved2, Op1Add, Op1Sub, Op2Mul,
    Op2Div, OpNegate, OpAbs, OpNot, Op0NotEqual, OpAdd, OpSub, OpMul, OpDiv,
    OpMod, OpLshift, OpRshift, OpBooland, OpBoolor,
    OpNumequal, OpNumequalverify, OpNumnotequal, OpLessthan,
    OpGreaterthan, OpLessthanorequal, OpGreaterthanorequal, OpMin, OpMax,
    OpWithin, OpRipemd160, OpSha1, OpSha256, OpHash160,
    OpHash256, OpCodeseparator, OpChecksig, OpChecksigverify, OpCheckmultisig,
    OpCheckmultisigverify,
    OpNop1, OpNop2, OpNop3, OpNop4, OpNop5, OpNop6, OpNop7, OpNop8, OpNop9, OpNop10,
    OpInvalidopcode = 0xFF,
}

fn decode_script(slice: &[u8]) -> Vec<(u8, Option<&[u8]>)> {
    let mut script: Vec<(u8, Option<&[u8]>)> = vec![];
    let mut pos: usize = 0;
    while pos < slice.len() {
        let opcode = slice[pos];
        pos += 1;
        if opcode <= Opcode::OpPushdata4 as u8 {
            let (n_size, new_pos) =
                if opcode == Opcode::OpPushdata1 as u8 {
                    (slice[pos] as usize, pos + 1)
                } else if opcode == Opcode::OpPushdata2 as u8 {
                    let r = read_u16(slice, pos);
                    (r.0 as usize, r.1)
                } else if opcode == Opcode::OpPushdata4 as u8 {
                    let r = read_u32(slice, pos);
                    (r.0 as usize, r.1)
                } else {
                    (opcode as usize, pos)
                };
            pos = new_pos;
            script.push((opcode, Some(&slice[pos..pos+n_size])));
            pos += n_size;
        } else {
            script.push((opcode, None));
        }
    }
    script
}

fn public_key_from_script(decoded_script: Vec<(u8, Option<&[u8]>)>) -> Option<[u8;20]>{
    if decoded_script.len() == 0 {
        None
    } else if decoded_script[0].0 == Opcode::Op0 as u8 {
        // Beginning of a multisignature spend ?
        match decoded_script[decoded_script.len()-1].1 {
            None => None,
            Some(sub_script) => {
                let decoded_sub_script = decode_script(sub_script);
                let mut sha256 = crypto::sha2::Sha256::new();
                sha256.input(sub_script);
                let mut buffer32b: [u8;32] = [0;32];
                sha256.result(&mut buffer32b);
                let mut ripemd160 = crypto::ripemd160::Ripemd160::new();
                ripemd160.input(&buffer32b);
                let mut buffer20b: [u8;20] = [0;20];
                ripemd160.result(&mut buffer20b);
                None
            }
        }
    } else if decoded_script[0].0 <= Opcode::OpPushdata4 as u8 {
        None
    } else {
        None
    }
}
<|endoftext|>


<commit_before>extern crate ansi_term;

use ansi_term::Colour;

use std::env;
use std::fs;
use std::path;

static IGNORE_PATHS: [&'static str; 1] = [
    ".git",
];

fn main() {
    let curdir = env::current_dir().unwrap();
    explore(&curdir);
}

trait IsDir {
    fn is_dir(&self) -> bool;
}

impl IsDir for fs::DirEntry {
    fn is_dir(&self) -> bool {
        self.metadata().unwrap().is_dir()
    }
}

impl IsDir for path::PathBuf {
    fn is_dir(&self) -> bool {
        fs::metadata(self).unwrap().is_dir()
    }
}

trait DisplayColour {
    fn display_colour(&self) -> String;
}

impl DisplayColour for path::PathBuf {
    fn display_colour(&self) -> String {
        match self.is_dir() {
            true => Colour::Yellow.bold().paint(self.to_str().unwrap()).to_string(),
            false => String::from(self.to_str().unwrap()),
        }
    }
}

fn explore(path: &path::PathBuf) -> () {
    if !path.is_dir() {
        println!("{}", path.display_colour());
        return;
    }

    if IGNORE_PATHS.contains(&path.file_name().unwrap().to_str().unwrap()) {
        return;
    }
    println!("{}:", path.display_colour());

    let mut q: Vec<path::PathBuf> = Vec::new();
    for item in fs::read_dir(path).unwrap() {
        let f = item.unwrap(); // f is a DirEntry
        match f.is_dir() {
            true => {
                q.push(f.path());
            },
            false => {
                explore(&f.path());
            },
        };
    }

    print!("\n");

    for d in q {
        explore(&d);
    }
}
<commit_msg>Improve colour output and directory traversal logic<commit_after>extern crate ansi_term;

use ansi_term::Colour;
use ansi_term::Style;

use std::env;
use std::fs;
use std::path;

static IGNORE_PATHS: [&'static str; 1] = [
    ".git",
];

fn main() {
    let curdir = env::current_dir().unwrap();
    explore(&curdir);
}

trait IsDir {
    fn is_dir(&self) -> bool;
}

impl IsDir for fs::DirEntry {
    fn is_dir(&self) -> bool {
        self.metadata().unwrap().is_dir()
    }
}

impl IsDir for path::PathBuf {
    fn is_dir(&self) -> bool {
        fs::metadata(self).unwrap().is_dir()
    }
}

trait DisplayColour {
    fn display_colour(&self, dstyle: Style, fstyle: Style, short: bool) -> String;
}

impl DisplayColour for path::PathBuf {
    fn display_colour(&self, dstyle: Style, fstyle: Style, short: bool) -> String {
        let style: Style;
        if self.is_dir() {
            style = dstyle;
        } else {
            style = fstyle;
        }

        if short {
            style.paint(self.file_name().unwrap().to_str().unwrap()).to_string()
        } else {
            style.paint(self.to_str().unwrap()).to_string()
        }
    }
}

fn explore(path: &path::PathBuf) -> () {
    if !path.is_dir() ||
       IGNORE_PATHS.contains(&path.file_name().unwrap().to_str().unwrap()) {
        return;
    }
    println!("{}:", path.display_colour(Colour::Yellow.bold(), Style::default(), false));

    let mut q: Vec<path::PathBuf> = Vec::new();
    for item in fs::read_dir(path).unwrap() {
        let f = item.unwrap(); // f is a DirEntry
        if f.is_dir() {
            q.push(f.path());
        };
        println!("{}", f.path().display_colour(Colour::Cyan.normal(), Style::default(), true));
    }

    print!("\n");

    for d in q {
        explore(&d);
    }
}
<|endoftext|>


<commit_before>extern crate sdl2;

mod phi;
mod views;

fn main() {
    self::phi::spawn("Arcade Shooter", |_|{
        Box::new(self::views::ViewA)
    });
}
<commit_msg>use the new ship view when game starts<commit_after>extern crate sdl2;

mod phi;
mod views;

fn main() {
    self::phi::spawn("Arcade Shooter", |ctx|{
        Box::new(self::views::ship::ShipView::new(ctx))
    });
}
<|endoftext|>


<commit_before>//! The main entry point for the SpaceAPi server.
//!
//! Running this code starts a HTTP server instance. The default port is 3000, but you can set your
//! own favorite port by exporting the `PORT` environment variable.

extern crate rustc_serialize;
extern crate hyper;
extern crate redis;

mod utils;
mod spaceapi;
mod datastore;
mod redis_store;

use std::io::Write;
use std::net::Ipv4Addr;

use rustc_serialize::json;
use hyper::Server;
use hyper::server::Request;
use hyper::server::Response;
use hyper::net::Fresh;
use hyper::header;

use datastore::DataStore;

fn build_response_json(people_present: Option<u32>, raspi_temperature: Option<f32>) -> String {
    let people_present_sensor = match people_present {
        Some(count) => vec![
            spaceapi::PeopleNowPresentSensor {
                value: count,
                location: Some("Hackerspace".to_string()),
                name: None,
                description: None,
            }
        ],
        None => Vec::new(),
    };

    let temperature_sensor = match raspi_temperature {
        Some(degrees) => vec![
            spaceapi::TemperatureSensor {
                value: degrees,
                unit: "°C".to_string(),
                location: "Hackerspace".to_string(),
                name: Some("Raspberry CPU".to_string()),
                description: None,
            }
        ],
        None => Vec::new(),
    };

    let status = spaceapi::Status {
        api: "0.13".to_string(),
        space: "coredump".to_string(),
        logo: "https://www.coredump.ch/logo.png".to_string(),
        url: "https://www.coredump.ch/".to_string(),
        location: spaceapi::Location {
            address: "Spinnereistrasse 2, 8640 Rapperswil, Switzerland".to_string(),
            lat: 47.22936,
            lon: 8.82949,
        },
        spacefed: spaceapi::SpaceFED {
            spacenet: false,
            spacesaml: false,
            spacephone: false,
        },
        cache: spaceapi::Cache {
            schedule: "m.02".to_string(),
        },
        state: spaceapi::State {
            open: false,
            message: "Open every Monday from 20:00".to_string(),
        },
        contact: spaceapi::Contact {
            irc: "irc://freenode.net/#coredump".to_string(),
            twitter: "@coredump_ch".to_string(),
            foursquare: "525c20e5498e875d8231b1e5".to_string(),
            email: "danilo@coredump.ch".to_string(),
        },
        issue_report_channels: vec![
            "email".to_string(),
            "twitter".to_string(),
        ],
        feeds: spaceapi::Feeds {
            blog: spaceapi::Feed {
                _type: "rss".to_string(),
                url: "https://www.coredump.ch/feed/".to_string(),
            },
        },
        projects: vec![
            "https://www.coredump.ch/projekte/".to_string(),
            "https://discourse.coredump.ch/c/projects".to_string(),
            "https://github.com/coredump-ch/".to_string(),
        ],
        sensors: spaceapi::Sensors {
            people_now_present: people_present_sensor,
            temperature: temperature_sensor,
        },
    };
    json::encode(&status).unwrap()
}

fn status_endpoint(_: Request, res: Response<Fresh>) {
    // Move response into mutable variable
    let mut res = res;

    // Fetch data from datastore
    let datastore = redis_store::RedisStore::new().unwrap();
    let people_present: Option<u32> = match datastore.retrieve("people_present") {
        Ok(v) => match v.parse::<u32>() {
            Ok(i) => Some(i),
            Err(_) => None,
        },
        Err(_) => None,
    };
    let raspi_temperature: Option<f32> = match datastore.retrieve("raspi_temperature") {
        Ok(v) => match v.parse::<f32>() {
            Ok(i) => Some(i),
            Err(_) => None,
        },
        Err(_) => None,
    };

    // Get response body
    let body = build_response_json(people_present, raspi_temperature);
    let body_bytes = body.as_bytes();

    // Set headers
    {
        let mut headers = res.headers_mut();
        headers.set(header::ContentLength(body_bytes.len() as u64));
        headers.set(header::ContentType("application/json; charset=utf-8".parse().unwrap()));
        headers.set(header::CacheControl(vec![header::CacheDirective::NoCache]));
        headers.set(header::AccessControlAllowOrigin::Any);
    }

    // Write response body
    let mut stream = res.start().unwrap();
    stream.write_all(body_bytes).unwrap();

    stream.end().unwrap();
}

fn main() {
    let ip = Ipv4Addr::new(127, 0, 0, 1);
    let port = utils::get_port();

    println!("Starting HTTP server on {}:{}...", ip, port);
    Server::http(status_endpoint).listen((ip, port)).unwrap();
}
<commit_msg>Pass in response parameter as mutable<commit_after>//! The main entry point for the SpaceAPi server.
//!
//! Running this code starts a HTTP server instance. The default port is 3000, but you can set your
//! own favorite port by exporting the `PORT` environment variable.

extern crate rustc_serialize;
extern crate hyper;
extern crate redis;

mod utils;
mod spaceapi;
mod datastore;
mod redis_store;

use std::io::Write;
use std::net::Ipv4Addr;

use rustc_serialize::json;
use hyper::Server;
use hyper::server::Request;
use hyper::server::Response;
use hyper::net::Fresh;
use hyper::header;

use datastore::DataStore;

fn build_response_json(people_present: Option<u32>, raspi_temperature: Option<f32>) -> String {
    let people_present_sensor = match people_present {
        Some(count) => vec![
            spaceapi::PeopleNowPresentSensor {
                value: count,
                location: Some("Hackerspace".to_string()),
                name: None,
                description: None,
            }
        ],
        None => Vec::new(),
    };

    let temperature_sensor = match raspi_temperature {
        Some(degrees) => vec![
            spaceapi::TemperatureSensor {
                value: degrees,
                unit: "°C".to_string(),
                location: "Hackerspace".to_string(),
                name: Some("Raspberry CPU".to_string()),
                description: None,
            }
        ],
        None => Vec::new(),
    };

    let status = spaceapi::Status {
        api: "0.13".to_string(),
        space: "coredump".to_string(),
        logo: "https://www.coredump.ch/logo.png".to_string(),
        url: "https://www.coredump.ch/".to_string(),
        location: spaceapi::Location {
            address: "Spinnereistrasse 2, 8640 Rapperswil, Switzerland".to_string(),
            lat: 47.22936,
            lon: 8.82949,
        },
        spacefed: spaceapi::SpaceFED {
            spacenet: false,
            spacesaml: false,
            spacephone: false,
        },
        cache: spaceapi::Cache {
            schedule: "m.02".to_string(),
        },
        state: spaceapi::State {
            open: false,
            message: "Open every Monday from 20:00".to_string(),
        },
        contact: spaceapi::Contact {
            irc: "irc://freenode.net/#coredump".to_string(),
            twitter: "@coredump_ch".to_string(),
            foursquare: "525c20e5498e875d8231b1e5".to_string(),
            email: "danilo@coredump.ch".to_string(),
        },
        issue_report_channels: vec![
            "email".to_string(),
            "twitter".to_string(),
        ],
        feeds: spaceapi::Feeds {
            blog: spaceapi::Feed {
                _type: "rss".to_string(),
                url: "https://www.coredump.ch/feed/".to_string(),
            },
        },
        projects: vec![
            "https://www.coredump.ch/projekte/".to_string(),
            "https://discourse.coredump.ch/c/projects".to_string(),
            "https://github.com/coredump-ch/".to_string(),
        ],
        sensors: spaceapi::Sensors {
            people_now_present: people_present_sensor,
            temperature: temperature_sensor,
        },
    };
    json::encode(&status).unwrap()
}

fn status_endpoint(_: Request, mut res: Response<Fresh>) {
    // Fetch data from datastore
    let datastore = redis_store::RedisStore::new().unwrap();
    let people_present: Option<u32> = match datastore.retrieve("people_present") {
        Ok(v) => match v.parse::<u32>() {
            Ok(i) => Some(i),
            Err(_) => None,
        },
        Err(_) => None,
    };
    let raspi_temperature: Option<f32> = match datastore.retrieve("raspi_temperature") {
        Ok(v) => match v.parse::<f32>() {
            Ok(i) => Some(i),
            Err(_) => None,
        },
        Err(_) => None,
    };

    // Get response body
    let body = build_response_json(people_present, raspi_temperature);
    let body_bytes = body.as_bytes();

    // Set headers
    {
        let mut headers = res.headers_mut();
        headers.set(header::ContentLength(body_bytes.len() as u64));
        headers.set(header::ContentType("application/json; charset=utf-8".parse().unwrap()));
        headers.set(header::CacheControl(vec![header::CacheDirective::NoCache]));
        headers.set(header::AccessControlAllowOrigin::Any);
    }

    // Write response body
    let mut stream = res.start().unwrap();
    stream.write_all(body_bytes).unwrap();

    stream.end().unwrap();
}

fn main() {
    let ip = Ipv4Addr::new(127, 0, 0, 1);
    let port = utils::get_port();

    println!("Starting HTTP server on {}:{}...", ip, port);
    Server::http(status_endpoint).listen((ip, port)).unwrap();
}
<|endoftext|>


<commit_before>#[macro_use]
extern crate clap;

#[macro_use]
extern crate log;
extern crate env_logger;

extern crate xmlrpc;
extern crate rustc_serialize;

extern crate regex;

use clap::{Arg, App};
use std::env;
use std::io;
use std::io::prelude::*;

use regex::Regex;

const GANDI_URL_PROD: &'static str = "https://rpc.gandi.net/xmlrpc/";

trait DNSProvider {
    fn init(&mut self, domain: &str);
    fn is_record_already_declared(&self, record_name: &str) -> Option<String>;
    fn update_record(&self, record_name: &str, ip_addr: &str) -> bool;
    fn create_record(&self, record_name: &str, ip_addr: &str);
}

struct GandiDNSProvider<'a> {
    zone_id: Option<u32>,
    zone_id_version: u16,
    gandi_rpc: GandiRPC<'a>,
}

impl<'a> GandiDNSProvider<'a> {

    fn new(gandi_url: &'a str, gandi_apikey: &'a str) -> GandiDNSProvider<'a> {

        let gandi_rpc = GandiRPC {
            xmlrpc_server: gandi_url,
            apikey: gandi_apikey,
        };

        GandiDNSProvider {
            zone_id: None,
            zone_id_version: 0,
            gandi_rpc: gandi_rpc,
        }
    }
}

impl<'a> DNSProvider for GandiDNSProvider<'a> {

    fn init(&mut self, domain: &str) {

        let (client, mut request) = self.gandi_rpc.get_gandi_client("domain.info");
        request = request.argument(&domain.to_string());
        request = request.finalize();

        let response = client.remote_call(&request).unwrap();

        // TODO: fix this ugly code
        // Handle errors
        let zone_id_pos = response.body.find("zone_id").unwrap();
        let (_, body_end) = response.body.split_at(zone_id_pos);
        let first_int_markup = body_end.find("<int>").unwrap();
        let (_, body_end) = body_end.split_at(first_int_markup + "<int>".len());
        let first_end_int_markup = body_end.find("</int>").unwrap();
        let (zone_id, _) = body_end.split_at(first_end_int_markup);
        self.zone_id = zone_id.parse::<u32>().ok();

        debug!("Zone id: {}", self.zone_id.unwrap());
    }

    fn is_record_already_declared(&self, record_name: &str) -> Option<String> {

        let response = &self.gandi_rpc.get_record_list(record_name, &self.zone_id.unwrap(), &self.zone_id_version);

        // Extract already configured IP address
        // We are looking for something like that: <value><string>55.32.210.10</string></value>
        let regex = Regex::new(r"<value><string>([0-9.]*)</string></value>").unwrap();

        let caps = regex.captures(&*response.body);

        caps
            .map_or(None, |caps| caps.at(1))
            .map(|val| val.to_string())
    }

    fn update_record(&self, record_name: &str, ip_addr: &str) -> bool {

        // Create a new zone and get return version

        let new_zone_version = &self.gandi_rpc.create_new_zone(&self.zone_id.unwrap());

        debug!("New zone version: {}", new_zone_version);

        // Extract new record id

        let new_record_id = &self.gandi_rpc.get_record_id(record_name, &self.zone_id.unwrap(), &new_zone_version);

        debug!("New record id: {}", new_record_id);

        // Update zone with the new record

        &self.gandi_rpc.update_zone_with_record(record_name, ip_addr, &self.zone_id.unwrap(), new_zone_version, new_record_id);

        // Activate the new zone
        debug!("Activate version '{}' of the zone '{}'", new_zone_version, &self.zone_id.unwrap());

        let (client, mut request) = self.gandi_rpc.get_gandi_client("domain.zone.version.set");
        request = request.argument(&self.zone_id.unwrap());
        request = request.argument(&new_zone_version);
        request = request.finalize();

        let response = client.remote_call(&request).unwrap();

        let regex = Regex::new(r"<boolean>([0-1]*)</boolean>").unwrap();

        let caps = regex.captures(&*response.body).unwrap();

        let result = caps.at(1).unwrap();

        debug!("Activate version result: {}", result);

        match result {
            "1" => true,
            "0" | _ => false,
        }
    }

    fn create_record(&self, record_name: &str, ip_addr: &str) {
        unimplemented!();
    }
}

struct GandiRPC<'a> {
    xmlrpc_server: &'a str,
    apikey: &'a str,
}

impl<'a> GandiRPC<'a> {

    fn get_gandi_client(&self, rpc_action: &str) -> (xmlrpc::Client, xmlrpc::Request) {
        let client = xmlrpc::Client::new(self.xmlrpc_server);
        let mut request = xmlrpc::Request::new(rpc_action);
        request = request.argument(&self.apikey.to_string());
        (client, request)
    }

    fn get_record_list(&self, record_name: &str, zone_id: &u32, zone_id_version: &u16) -> xmlrpc::Response {

        let (client, mut request) = self.get_gandi_client("domain.zone.record.list");
        request = request.argument(zone_id);
        request = request.argument(zone_id_version);

        #[derive(Debug,RustcEncodable,RustcDecodable)]
        struct Record {
            name: String,
            type_: String,
        }

        let record = Record { name: record_name.to_string(), type_: "A".to_string() };

        request = request.argument(&record);

        request = request.finalize();

        // Horrible hack, because 'type' is a reserved keyword ...
        request.body = request.body.replace("type_", "type");

        client.remote_call(&request).unwrap()
    }

    fn create_new_zone(&self, zone_id: &u32) -> u16 {
        let (client, mut request) = self.get_gandi_client("domain.zone.version.new");
        request = request.argument(zone_id);
        request = request.finalize();

        let response = client.remote_call(&request).unwrap();

        let regex = Regex::new(r"<int>([0-9]+)</int>").unwrap();

        let caps = regex.captures(&*response.body).unwrap();

        caps.at(1).unwrap().parse::<u16>().ok().unwrap()
    }

    fn get_record_id(&self, record_name: &str, zone_id: &u32, new_zone_version: &u16) -> u32 {
        let response = &self.get_record_list(record_name, zone_id, new_zone_version);

        let regex = Regex::new(r"<int>([0-9]+)</int>").unwrap();

        let caps = regex.captures(&*response.body).unwrap();

        caps.at(1).unwrap().parse::<u32>().ok().unwrap()
    }

    fn update_zone_with_record(&self, record_name: &str, ip_addr: &str, zone_id: &u32, new_zone_version: &u16, new_record_id: &u32) {
        let (client, mut request) = self.get_gandi_client("domain.zone.record.update");
        request = request.argument(zone_id);
        request = request.argument(new_zone_version);

        #[derive(Debug,RustcEncodable,RustcDecodable)]
        struct NewRecordId { id: u32 };
        request = request.argument(&NewRecordId{ id: *new_record_id });

        #[derive(Debug,RustcEncodable,RustcDecodable)]
        struct Record {
            name: String,
            type_: String,
            value: String,
        }

        let record = Record {
            name: record_name.to_string(),
            type_: "A".to_string(),
            value: ip_addr.to_string(),
        };

        request = request.argument(&record);

        request = request.finalize();

        // Horrible hack, because 'type' is a reserved keyword ...
        request.body = request.body.replace("type_", "type");

        client.remote_call(&request); // ignore response
    }
}

fn main() {
    let matches = App::new("gdu")
        .version(&crate_version!()[..])
        .author("Damien Lecan <dev@dlecan.com>")
        .about("Gandi DNS updater, useful to reflect your dynamic IP address to your Gandi DNS zone file.\nIP address is read from stdin.")
        .args_from_usage(
            "-a --apikey=[apikey] 'Your API key provided by Gandi'
            -d --domain=[domain] 'The domain name whose active zonefile will be updated, e.g. \"domain.com\"'
            -n --dry-run 'Dry run, don't really update Gandi zone file'
            -f --force 'Force new zonefile creation even if IP address isn\'t modified'
            [verbose]... -v 'Verbose mode'")
        .arg(Arg::with_name("record_name")
            .help("Name of the A record to update or create (without domain)")
            .index(1)
            .required(true)
            .multiple(false))
        .get_matches();

    // Init logging to DEBUG only if user requires it
    match matches.occurrences_of("verbose") {
        0 => (),
        1 => {
                println!("Verbose mode");
                env::set_var("RUST_LOG", "DEBUG");
            },
        2 | _=> {
                println!("More verbose mode");
                env::set_var("RUST_LOG", "TRACE");
            }
    }
    env_logger::init().unwrap();

    let apikey = matches.value_of("apikey").unwrap();
    debug!("Using apikey: {}", apikey);

    let domain = matches.value_of("domain").unwrap();
    debug!("Using domain: {}", domain);

    let record_name = matches.value_of("record_name").unwrap();
    debug!("Using record name: {}", record_name);

    let dry_run = matches.is_present("dry-run");
    debug!("Dry run: {}", dry_run);

    let force = matches.is_present("force");
    debug!("Force: {}", force);

    let mut input = String::new();
    match io::stdin().read_line(&mut input) {
        Ok(_) => {
            println!("Input: {}", input);
        }
        Err(error) => println!("error: {}", error),
    }

    let expected_ip_addr = input.trim();

    let mut dns_provider = GandiDNSProvider::new(GANDI_URL_PROD, apikey);

    dns_provider.init(domain);

    let maybe_checked = dns_provider.is_record_already_declared(record_name);

    match maybe_checked {
        Some(ip_addr) => {
            debug!("Record already declared, with IP address: {}", &ip_addr);

            if !force && (&ip_addr == expected_ip_addr) {
                debug!("IP address not modified, no record to update");
            } else {
                debug!("Update record '{}' with IP address '{}'", record_name, &expected_ip_addr);
                let result = dns_provider.update_record(record_name, &expected_ip_addr);
                debug!("End of update process with result: {}", result);
            }
        }
        None => dns_provider.create_record(record_name, expected_ip_addr)
    }

}
<commit_msg>More separation between GandiDNSProvider and GandiRPC<commit_after>#[macro_use]
extern crate clap;

#[macro_use]
extern crate log;
extern crate env_logger;

extern crate xmlrpc;
extern crate rustc_serialize;

extern crate regex;

use clap::{Arg, App};
use std::env;
use std::io;
use std::io::prelude::*;

use regex::Regex;

const GANDI_URL_PROD: &'static str = "https://rpc.gandi.net/xmlrpc/";

trait DNSProvider {
    fn init(&mut self, domain: &str);
    fn is_record_already_declared(&self, record_name: &str) -> Option<String>;
    fn update_record(&self, record_name: &str, ip_addr: &str) -> bool;
    fn create_record(&self, record_name: &str, ip_addr: &str);
}

struct GandiDNSProvider<'a> {
    zone_id: Option<u32>,
    zone_id_version: u16,
    gandi_rpc: GandiRPC<'a>,
}

impl<'a> GandiDNSProvider<'a> {

    fn new(gandi_url: &'a str, gandi_apikey: &'a str) -> GandiDNSProvider<'a> {

        let gandi_rpc = GandiRPC {
            xmlrpc_server: gandi_url,
            apikey: gandi_apikey,
        };

        GandiDNSProvider {
            zone_id: None,
            zone_id_version: 0,
            gandi_rpc: gandi_rpc,
        }
    }
}

impl<'a> DNSProvider for GandiDNSProvider<'a> {

    fn init(&mut self, domain: &str) {

        let response = &self.gandi_rpc.get_domain_info(domain);

        // TODO: fix this ugly code
        // Handle errors
        let zone_id_pos = response.body.find("zone_id").unwrap();
        let (_, body_end) = response.body.split_at(zone_id_pos);
        let first_int_markup = body_end.find("<int>").unwrap();
        let (_, body_end) = body_end.split_at(first_int_markup + "<int>".len());
        let first_end_int_markup = body_end.find("</int>").unwrap();
        let (zone_id, _) = body_end.split_at(first_end_int_markup);
        self.zone_id = zone_id.parse::<u32>().ok();

        debug!("Zone id: {}", self.zone_id.unwrap());
    }

    fn is_record_already_declared(&self, record_name: &str) -> Option<String> {

        let response = &self.gandi_rpc.get_record_list(record_name, &self.zone_id.unwrap(), &self.zone_id_version);

        // Extract already configured IP address
        // We are looking for something like that: <value><string>55.32.210.10</string></value>
        let regex = Regex::new(r"<value><string>([0-9.]*)</string></value>").unwrap();

        let caps = regex.captures(&*response.body);

        caps
            .map_or(None, |caps| caps.at(1))
            .map(|val| val.to_string())
    }

    fn update_record(&self, record_name: &str, ip_addr: &str) -> bool {

        // Create a new zone and get return version

        let new_zone_version = &self.gandi_rpc.create_new_zone(&self.zone_id.unwrap());

        debug!("New zone version: {}", new_zone_version);

        // Extract new record id

        let new_record_id = &self.gandi_rpc.get_record_id(record_name, &self.zone_id.unwrap(), &new_zone_version);

        debug!("New record id: {}", new_record_id);

        // Update zone with the new record

        &self.gandi_rpc.update_zone_with_record(record_name, ip_addr, &self.zone_id.unwrap(), new_zone_version, new_record_id);

        // Activate the new zone
        debug!("Activate version '{}' of the zone '{}'", new_zone_version, &self.zone_id.unwrap());

        self.gandi_rpc.update_zone_version(&self.zone_id.unwrap(), &new_zone_version)
    }

    fn create_record(&self, record_name: &str, ip_addr: &str) {
        unimplemented!();
    }
}

struct GandiRPC<'a> {
    xmlrpc_server: &'a str,
    apikey: &'a str,
}

impl<'a> GandiRPC<'a> {

    fn get_gandi_client(&self, rpc_action: &str) -> (xmlrpc::Client, xmlrpc::Request) {
        let client = xmlrpc::Client::new(self.xmlrpc_server);
        let mut request = xmlrpc::Request::new(rpc_action);
        request = request.argument(&self.apikey.to_string());
        (client, request)
    }

    fn get_domain_info(&self, domain: &'a str) -> xmlrpc::Response {
        let (client, mut request) = self.get_gandi_client("domain.info");
        request = request.argument(&domain.to_string());
        request = request.finalize();

        client.remote_call(&request).unwrap()
    }

    fn get_record_list(&self, record_name: &str, zone_id: &u32, zone_id_version: &u16) -> xmlrpc::Response {

        let (client, mut request) = self.get_gandi_client("domain.zone.record.list");
        request = request.argument(zone_id);
        request = request.argument(zone_id_version);

        #[derive(Debug,RustcEncodable,RustcDecodable)]
        struct Record {
            name: String,
            type_: String,
        }

        let record = Record { name: record_name.to_string(), type_: "A".to_string() };

        request = request.argument(&record);

        request = request.finalize();

        // Horrible hack, because 'type' is a reserved keyword ...
        request.body = request.body.replace("type_", "type");

        client.remote_call(&request).unwrap()
    }

    fn create_new_zone(&self, zone_id: &u32) -> u16 {
        let (client, mut request) = self.get_gandi_client("domain.zone.version.new");
        request = request.argument(zone_id);
        request = request.finalize();

        let response = client.remote_call(&request).unwrap();

        let regex = Regex::new(r"<int>([0-9]+)</int>").unwrap();

        let caps = regex.captures(&*response.body).unwrap();

        caps.at(1).unwrap().parse::<u16>().ok().unwrap()
    }

    fn get_record_id(&self, record_name: &str, zone_id: &u32, new_zone_version: &u16) -> u32 {
        let response = &self.get_record_list(record_name, zone_id, new_zone_version);

        let regex = Regex::new(r"<int>([0-9]+)</int>").unwrap();

        let caps = regex.captures(&*response.body).unwrap();

        caps.at(1).unwrap().parse::<u32>().ok().unwrap()
    }

    fn update_zone_with_record(&self, record_name: &str, ip_addr: &str, zone_id: &u32, new_zone_version: &u16, new_record_id: &u32) {
        let (client, mut request) = self.get_gandi_client("domain.zone.record.update");
        request = request.argument(zone_id);
        request = request.argument(new_zone_version);

        #[derive(Debug,RustcEncodable,RustcDecodable)]
        struct NewRecordId { id: u32 };
        request = request.argument(&NewRecordId{ id: *new_record_id });

        #[derive(Debug,RustcEncodable,RustcDecodable)]
        struct Record {
            name: String,
            type_: String,
            value: String,
        }

        let record = Record {
            name: record_name.to_string(),
            type_: "A".to_string(),
            value: ip_addr.to_string(),
        };

        request = request.argument(&record);

        request = request.finalize();

        // Horrible hack, because 'type' is a reserved keyword ...
        request.body = request.body.replace("type_", "type");

        client.remote_call(&request); // ignore response
    }

    fn update_zone_version(&self, zone_id: &u32, zone_version: &u16) -> bool {

        let (client, mut request) = self.get_gandi_client("domain.zone.version.set");
        request = request.argument(zone_id);
        request = request.argument(zone_version);
        request = request.finalize();

        let response = client.remote_call(&request).unwrap();

        let regex = Regex::new(r"<boolean>([0-1]*)</boolean>").unwrap();

        let caps = regex.captures(&*response.body).unwrap();

        let result = caps.at(1).unwrap();

        debug!("Activate version result: {}", result);

        match result {
            "1" => true,
            "0" | _ => false,
        }

    }
}

fn main() {
    let matches = App::new("gdu")
        .version(&crate_version!()[..])
        .author("Damien Lecan <dev@dlecan.com>")
        .about("Gandi DNS updater, useful to reflect your dynamic IP address to your Gandi DNS zone file.\nIP address is read from stdin.")
        .args_from_usage(
            "-a --apikey=[apikey] 'Your API key provided by Gandi'
            -d --domain=[domain] 'The domain name whose active zonefile will be updated, e.g. \"domain.com\"'
            -n --dry-run 'Dry run, don't really update Gandi zone file'
            -f --force 'Force new zonefile creation even if IP address isn\'t modified'
            [verbose]... -v 'Verbose mode'")
        .arg(Arg::with_name("record_name")
            .help("Name of the A record to update or create (without domain)")
            .index(1)
            .required(true)
            .multiple(false))
        .get_matches();

    // Init logging to DEBUG only if user requires it
    match matches.occurrences_of("verbose") {
        0 => (),
        1 => {
                println!("Verbose mode");
                env::set_var("RUST_LOG", "DEBUG");
            },
        2 | _=> {
                println!("More verbose mode");
                env::set_var("RUST_LOG", "TRACE");
            }
    }
    env_logger::init().unwrap();

    let apikey = matches.value_of("apikey").unwrap();
    debug!("Using apikey: {}", apikey);

    let domain = matches.value_of("domain").unwrap();
    debug!("Using domain: {}", domain);

    let record_name = matches.value_of("record_name").unwrap();
    debug!("Using record name: {}", record_name);

    let dry_run = matches.is_present("dry-run");
    debug!("Dry run: {}", dry_run);

    let force = matches.is_present("force");
    debug!("Force: {}", force);

    let mut input = String::new();
    match io::stdin().read_line(&mut input) {
        Ok(_) => {
            println!("Input: {}", input);
        }
        Err(error) => println!("error: {}", error),
    }

    let expected_ip_addr = input.trim();

    let mut dns_provider = GandiDNSProvider::new(GANDI_URL_PROD, apikey);

    dns_provider.init(domain);

    let maybe_checked = dns_provider.is_record_already_declared(record_name);

    match maybe_checked {
        Some(ip_addr) => {
            debug!("Record already declared, with IP address: {}", &ip_addr);

            if !force && (&ip_addr == expected_ip_addr) {
                debug!("IP address not modified, no record to update");
            } else {
                debug!("Update record '{}' with IP address '{}'", record_name, &expected_ip_addr);
                let result = dns_provider.update_record(record_name, &expected_ip_addr);
                debug!("End of update process with result: {}", result);
            }
        }
        None => dns_provider.create_record(record_name, expected_ip_addr)
    }

}
<|endoftext|>


<commit_before>pub mod rsh;

use std::env;

fn main() {
    let mut argv = env::args();

    let path = argv.
        next().
        unwrap_or(".".to_string());

    let s = rsh::State::new(path);
    rsh::run(s)
}
<commit_msg>don't export rsh<commit_after>mod rsh;

use std::env;

fn main() {
    let mut argv = env::args();

    let path = argv.
        next().
        unwrap_or(".".to_string());

    let s = rsh::State::new(path);
    rsh::run(s)
}
<|endoftext|>


<commit_before>extern crate rand;

const N: usize = 3;

struct MetricHolder {
    // TODO: make N a part of the metric holder and use a vector
    // also improve by persisting the sum instead of doing avg every time
    history: [u32; N],
    counter: usize
}

impl MetricHolder {
    fn moving_average(&mut self, new_val: u32) -> f64 {
        self.history[self.counter] = new_val;
        self.counter = (self.counter + 1) % N;
        let mut sum: u32 = 0;
        let mut count: u32 = 0;
        for &el in self.history.iter() {
            sum += el;
            if el != 0 {
                count += 1;
            }
        }
        sum as f64 / count as f64
    }
}

fn main() {

    // TODO: implement default
    let mut metric_holder = MetricHolder {
        history: [0; N],
        counter: 0
    };

    println!("{}", metric_holder.moving_average(1));
    println!("{}", metric_holder.moving_average(1));
    println!("{}", metric_holder.moving_average(1));
    println!("{}", metric_holder.moving_average(2));
    println!("{}", metric_holder.moving_average(3));
}
<commit_msg>Add MetricHolder::new() and use LinkedList<commit_after>use std::collections::LinkedList;

struct MetricHolder {
    n: usize,
    sum: u32,
    history: LinkedList<u32>
}

impl MetricHolder {
    fn moving_average(&mut self, new_val: u32) -> f64 {
        self.history.push_back(new_val);
        self.sum += new_val;
        if self.history.len() > self.n {
            let old_val = match self.history.pop_front() {
                Some(val) => val,
                None => 0,
            };
            self.sum -= old_val;
        }

        self.sum as f64 / self.history.len() as f64
    }

    fn new(n: usize) -> MetricHolder {
        MetricHolder {
            n: n,
            sum: 0,
            history: LinkedList::new()
        }
    }
}

fn main() {
    let mut metric_holder = MetricHolder::new(2);
    println!("{}", metric_holder.moving_average(1));
    println!("{}", metric_holder.moving_average(1));
    println!("{}", metric_holder.moving_average(1));
    println!("{}", metric_holder.moving_average(2));
    println!("{}", metric_holder.moving_average(3));
}
<|endoftext|>


<commit_before>use std::env;

fn main() {
    let args: Vec<_> = env::args().collect();
    let mut size:i32 = 20;
    let padding = vec!["  ", " ", "", " ", "  ", "   ", "    ", "   "];

    if args.len() > 1 {
        size = args[1].parse()
                .ok()
                .expect("Wanted a number");
    }
    if size >= 0 {
        let mut i:usize = 0;

        println!("    ╚⊙ ⊙╝");
        while i < size as usize {
            println!("{}╚═(███)═╝", padding[i % 8]);
            i = i + 1;
        }
    } else {
        let mut i:usize = size.abs() as usize;

        while i > 0 {
            println!("{}╔═(███)═╗", padding[i%8]);
            i = i - 1;
        }
        println!("   ╔⊙ ⊙╗");
    }
}
<commit_msg>rustfmt<commit_after>use std::env;

fn main() {
    let args: Vec<_> = env::args().collect();
    let mut size: i32 = 20;
    let padding = vec!["  ", " ", "", " ", "  ", "   ", "    ", "   "];

    if args.len() > 1 {
        size = args[1]
                   .parse()
                   .ok()
                   .expect("Wanted a number");
    }
    if size >= 0 {
        let mut i: usize = 0;

        println!("    ╚⊙ ⊙╝");
        while i < size as usize {
            println!("{}╚═(███)═╝", padding[i % 8]);
            i = i + 1;
        }
    } else {
        let mut i: usize = size.abs() as usize;

        while i > 0 {
            println!("{}╔═(███)═╗", padding[i % 8]);
            i = i - 1;
        }
        println!("   ╔⊙ ⊙╗");
    }
}
<|endoftext|>


<commit_before>extern crate "dbus-rs" as dbus;

use std::os::args;
use dbus::{Connection, BusType, Message, MessageItem};

static DEST: &'static str = "org.kde.kdeconnect";
static PATH: &'static str = "/modules/kdeconnect";

fn get_ids(c: &Connection) -> Result<Vec<String>, &'static str> {
    let mut m = Message::new_method_call(DEST
                                         , PATH
                                         , &*[DEST, "daemon"].connect(".")
                                         , "devices").unwrap();
    m.append_items(&[MessageItem::Bool(true)]); // onlyReachable
    m = c.send_with_reply_and_block(m, 1000).unwrap();
    match m.get_items()[0] {
        MessageItem::Array(_, 0) => Err("No reachable devices."),
        MessageItem::Array(ref a, _) => Ok(a.iter().map(|&ref e| match *e {
            MessageItem::Str(ref s) => s.clone(),
            _ => unreachable!(),
        }).collect()),
        _ => unreachable!(),
    }
}

fn share_url(c: &Connection, id: &String, url: &String) {
    let mut m = Message::new_method_call(DEST
                                         , &*[PATH, "devices", &id[], "share"].connect("/")
                                         , &*[DEST, "device.share"].connect(".")
                                         , "shareUrl").unwrap();
    m.append_items(&[MessageItem::Str(url.clone())]);
    c.send_with_reply_and_block(m, 1000).unwrap();
}

fn main() {
    let urls = &args()[1..];
    if urls.is_empty() {
        return println!("Usage: {} url [url ...]", &args()[0])
    }

    let ref c = Connection::get_private(BusType::Session).unwrap();
    match get_ids(c) {
        Err(e) => return println!("{}", e),
        Ok(ids) =>
            for url in urls.iter() {
                for id in (*ids).iter() {
                    share_url(c, id, url);
                }
            }
    }
}
<commit_msg>less indirection<commit_after>extern crate "dbus-rs" as dbus;

use std::os::args;
use dbus::{Connection, BusType, Message, MessageItem};

static DEST: &'static str = "org.kde.kdeconnect";
static PATH: &'static str = "/modules/kdeconnect";

fn get_ids(c: &Connection) -> Result<Vec<String>, &'static str> {
    let mut m = Message::new_method_call(DEST
                                         , PATH
                                         , &*[DEST, "daemon"].connect(".")
                                         , "devices").unwrap();
    m.append_items(&[MessageItem::Bool(true)]); // onlyReachable
    m = c.send_with_reply_and_block(m, 1000).unwrap();
    match m.get_items()[0] {
        MessageItem::Array(_, 0) => Err("No reachable devices."),
        MessageItem::Array(ref a, _) => Ok(a.iter().map(|e| match e {
            &MessageItem::Str(ref s) => s.clone(),
            _ => unreachable!(),
        }).collect()),
        _ => unreachable!(),
    }
}

fn share_url(c: &Connection, id: &String, url: &String) {
    let mut m = Message::new_method_call(DEST
                                         , &*[PATH, "devices", &id[], "share"].connect("/")
                                         , &*[DEST, "device.share"].connect(".")
                                         , "shareUrl").unwrap();
    m.append_items(&[MessageItem::Str(url.clone())]);
    c.send_with_reply_and_block(m, 1000).unwrap();
}

fn main() {
    let urls = &args()[1..];
    if urls.is_empty() {
        return println!("Usage: {} url [url ...]", &args()[0])
    }

    let ref c = Connection::get_private(BusType::Session).unwrap();
    match get_ids(c) {
        Err(e) => return println!("{}", e),
        Ok(ids) =>
            for url in urls.iter() {
                for id in (*ids).iter() {
                    share_url(c, id, url);
                }
            }
    }
}
<|endoftext|>


<commit_before>mod token;
mod lexer;

fn main() {}
<commit_msg>Using repl (buggy).<commit_after>extern crate users;

mod token;
mod lexer;
mod repl;

use std::io::stdin;
use std::io::stdout;

use users::get_user_by_uid;
use users::get_current_uid;

use repl::start;

fn main() {
    let user = get_user_by_uid(get_current_uid()).unwrap();
    println!("Hello {}! This is the Monkey programming language!", user.name());
    println!("Feel free to type in commands");

    start(stdin(), stdout());
}
<|endoftext|>


<commit_before>
extern crate mprovision;
extern crate clap;

use std::fs;
use clap::{Arg, App, AppSettings, SubCommand};

fn main() {
    let count_subcommand = SubCommand::with_name("count")
                               .about("Counts provisioning profiles in a directory.")
                               .arg(Arg::with_name("DIRECTORY")
                                        .help("Directory where to count provisioning profiles.")
                                        .required(false));

    let matches = App::new("mprovision")
                      .setting(AppSettings::SubcommandRequired)
                      .version("0.1.0")
                      .about("A tool that helps iOS developers to manage mobileprovision files.")
                      .subcommand(count_subcommand)
                      .get_matches();

    if let Some(matches) = matches.subcommand_matches("count") {
        handle_count_subcommand(matches)
    }
}

fn handle_count_subcommand(matches: &clap::ArgMatches) {

    fn show(result: mprovision::Result<Box<Iterator<Item = fs::DirEntry>>>) {
        match result {
            Ok(files) => println!("Found {} files.", files.count()),
            Err(err) => println!("Error: {}", err),
        }
    }

    if let Some(directory) = matches.value_of("DIRECTORY") {
        show(mprovision::files(directory));
    } else {
        match mprovision::directory() {
            Ok(directory) => show(mprovision::files(directory)),
            Err(err) => println!("Error: {}", err),
        }
    }
}
<commit_msg>Use vec of subcommands for future.<commit_after>
extern crate mprovision;
extern crate clap;

use std::fs;
use clap::{Arg, App, AppSettings, SubCommand};

fn main() {
    let subcommands = vec![
        SubCommand::with_name("count")
            .about("Counts provisioning profiles in a directory.")
            .arg(Arg::with_name("DIRECTORY")
                .help("Directory where to count provisioning profiles.")
                .required(false)),
    ];

    let matches = App::new("mprovision")
                      .setting(AppSettings::SubcommandRequired)
                      .version("0.1.0")
                      .about("A tool that helps iOS developers to manage mobileprovision files.")
                      .subcommands(subcommands)
                      .get_matches();

    if let Some(matches) = matches.subcommand_matches("count") {
        handle_count_subcommand(matches)
    }
}

fn handle_count_subcommand(matches: &clap::ArgMatches) {

    fn show(result: mprovision::Result<Box<Iterator<Item = fs::DirEntry>>>) {
        match result {
            Ok(files) => println!("Found {} files.", files.count()),
            Err(err) => println!("Error: {}", err),
        }
    }

    if let Some(directory) = matches.value_of("DIRECTORY") {
        show(mprovision::files(directory));
    } else {
        match mprovision::directory() {
            Ok(directory) => show(mprovision::files(directory)),
            Err(err) => println!("Error: {}", err),
        }
    }
}
<|endoftext|>


<commit_before>#![feature(slice_bytes)]

extern crate libc;
extern crate errno;
extern crate rustc_serialize; //debug hex dump

use std::io::Write;
use rustc_serialize::hex::ToHex;

const ETH_P_ALL: u16 = 0x0003;
const ETH_P_ARP: u16 = 0x0806;
const IFNAMSIZ: usize = 16; // net/if.h
const SIOCGIFINDEX: libc::c_int = 0x8933;
const RECV_BUF_LEN: usize = 1542;
const SO_ATTACH_FILTER: libc::c_int = 26;

#[repr(C)]
#[allow(non_camel_case_types)]
struct sock_filter {	/* Filter block */
	code: u16,   /* Actual filter code */
	jt: u8,	/* Jump true */
	jf: u8,	/* Jump false */
	k: u32      /* Generic multiuse field */
}

#[repr(C)]
#[allow(non_camel_case_types)]
#[derive(Debug)]
struct sock_fprog {     /* Required for SO_ATTACH_FILTER. */
        len: u16,    /* Number of filter blocks */
        filter: *const sock_filter
}

#[repr(C)]
#[allow(non_camel_case_types)]
struct ifreq {
    ifr_name: [u8; IFNAMSIZ],
    ifr_ifindex: libc::c_int
}

fn ifindex_from_ifname(ifname: &str, sock: libc::c_int) -> libc::c_int {
    let mut ifr = ifreq {
        ifr_name: [0; IFNAMSIZ],
        ifr_ifindex: 0
    };
    std::slice::bytes::copy_memory(ifname.as_bytes(), &mut ifr.ifr_name);
    if unsafe { libc::funcs::bsd44::ioctl(sock, SIOCGIFINDEX, &ifr) } == -1 {
        let err = errno::errno();
        panic!("Error getting ifindex: {} ({})", err, err.0);
    }
    return ifr.ifr_ifindex;

}

fn main() {
    // tcpdump -dd arp and incoming
    let bpf_filter_arp_incoming: [sock_filter; 6] = [
        sock_filter { code: 0x28, jt: 0, jf: 0, k: 0x0000000c },
        sock_filter { code: 0x15, jt: 0, jf: 3, k: 0x00000806 },
        sock_filter { code: 0x28, jt: 0, jf: 0, k: 0xfffff004 },
        sock_filter { code: 0x15, jt: 1, jf: 0, k: 0x00000004 },
        sock_filter { code: 0x06, jt: 0, jf: 0, k: 0x00040000 },
        sock_filter { code: 0x06, jt: 0, jf: 0, k: 0x00000000 },
    ];
    let bpf_filter_arp_incoming_prog: sock_fprog = sock_fprog {
        len: 6,
        filter: bpf_filter_arp_incoming.as_ptr()
    };

    let mut args = std::env::args();
    if args.len() != 3 {
        std::io::stderr().write("Usage: arpmasqd LISTEN_IFACE SEND_ADDR\n".as_ref()).unwrap();
        panic!("number of arguments");
    }
    args.next();
    //unwrap is ok because arg count has been checked
    let listen_iface = args.next().unwrap();
    let send_addr = args.next().unwrap();
    let listen_socket = unsafe { libc::socket(libc::AF_PACKET, libc::SOCK_RAW, ETH_P_ALL.to_be() as i32) };
    if listen_socket == -1 {
        let err = errno::errno();
        println!("maybe try: sudo setcap CAP_NET_RAW+eip arpmasqd");
        panic!("Error opening socket: {} ({})", err, err.0);
    }
    let attach_filter_res = unsafe { libc::setsockopt(listen_socket, libc::SOL_SOCKET, SO_ATTACH_FILTER, std::mem::transmute(&bpf_filter_arp_incoming_prog), std::mem::size_of_val(&bpf_filter_arp_incoming_prog) as u32) };
    if attach_filter_res == -1 {
        let err = errno::errno();
        panic!("Error attaching filter: {} ({})", err, err.0);
    }
    let listen_sockaddr = libc::sockaddr_ll {
        sll_family: libc::AF_PACKET as u16,
        sll_protocol: ETH_P_ALL.to_be(),
        sll_ifindex: ifindex_from_ifname(&listen_iface, listen_socket),
        sll_hatype: 0,
        sll_pkttype: 0,
        sll_halen: 0,
        sll_addr: [0; 8]
    };
    let bind_result = unsafe { libc::bind(listen_socket, std::mem::transmute(&listen_sockaddr), std::mem::size_of_val(&listen_sockaddr) as u32) };
    if bind_result == -1 {
        let err = errno::errno();
        panic!("Error binding socket: {} ({})", err, err.0);
    }

    let buf = [0u8; RECV_BUF_LEN];
    let mut recv_sockaddr = unsafe { std::mem::zeroed::<libc::sockaddr_ll>() };
    let mut recv_sockaddr_len: u32 = std::mem::size_of_val(&recv_sockaddr) as u32;
    let recv_result = unsafe { libc::recvfrom(listen_socket, std::mem::transmute(&buf), RECV_BUF_LEN as u64, 0, std::mem::transmute(&recv_sockaddr), &mut recv_sockaddr_len) };
    if recv_result == -1 {
        let err = errno::errno();
        panic!("Error in recvfrom: {} ({})", err, err.0);
    }
    println!("From: {}", recv_sockaddr.sll_addr[0..6].to_hex());
    println!("Data: {}", buf[0..(recv_result as usize)].to_hex());
}
<commit_msg>reorganized code<commit_after>#![feature(slice_bytes)]

extern crate libc;
extern crate errno;
extern crate rustc_serialize; //debug hex dump

use std::io::Write;
use rustc_serialize::hex::ToHex;

const ETH_P_ALL: u16 = 0x0003;
const ETH_P_ARP: u16 = 0x0806;
const IFNAMSIZ: usize = 16; // net/if.h
const SIOCGIFINDEX: libc::c_int = 0x8933;
const RECV_BUF_LEN: usize = 1542;
const SO_ATTACH_FILTER: libc::c_int = 26;

#[repr(C)]
#[allow(non_camel_case_types)]
struct sock_filter {	/* Filter block */
	code: u16,   /* Actual filter code */
	jt: u8,	/* Jump true */
	jf: u8,	/* Jump false */
	k: u32      /* Generic multiuse field */
}

#[repr(C)]
#[allow(non_camel_case_types)]
#[derive(Debug)]
struct sock_fprog {     /* Required for SO_ATTACH_FILTER. */
        len: u16,    /* Number of filter blocks */
        filter: *const sock_filter
}

#[repr(C)]
#[allow(non_camel_case_types)]
struct ifreq {
    ifr_name: [u8; IFNAMSIZ],
    ifr_ifindex: libc::c_int
}

fn ifindex_from_ifname(ifname: &str, sock: libc::c_int) -> libc::c_int {
    let mut ifr = ifreq {
        ifr_name: [0; IFNAMSIZ],
        ifr_ifindex: 0
    };
    std::slice::bytes::copy_memory(ifname.as_bytes(), &mut ifr.ifr_name);
    if unsafe { libc::funcs::bsd44::ioctl(sock, SIOCGIFINDEX, &ifr) } == -1 {
        let err = errno::errno();
        panic!("Error getting ifindex: {} ({})", err, err.0);
    }
    return ifr.ifr_ifindex;

}

struct SocketError {
    action: &'static str,
    err: errno::Errno
}

macro_rules! sockerr {
    ($action:expr) => {
        return Err(SocketError{ action: $action, err: errno::errno() });
    };
}

fn create_listen_socket(iface: &str) -> Result<libc::c_int, SocketError> {
    // tcpdump -dd arp and incoming
    let bpf_filter_arp_incoming: [sock_filter; 6] = [
        sock_filter { code: 0x28, jt: 0, jf: 0, k: 0x0000000c },
        sock_filter { code: 0x15, jt: 0, jf: 3, k: 0x00000806 },
        sock_filter { code: 0x28, jt: 0, jf: 0, k: 0xfffff004 },
        sock_filter { code: 0x15, jt: 1, jf: 0, k: 0x00000004 },
        sock_filter { code: 0x06, jt: 0, jf: 0, k: 0x00040000 },
        sock_filter { code: 0x06, jt: 0, jf: 0, k: 0x00000000 },
    ];
    let bpf_filter_arp_incoming_prog: sock_fprog = sock_fprog {
        len: 6,
        filter: bpf_filter_arp_incoming.as_ptr()
    };

    let listen_socket = unsafe { libc::socket(libc::AF_PACKET, libc::SOCK_RAW, ETH_P_ALL.to_be() as i32) };
    if listen_socket == -1 {
        println!("try: sudo setcap CAP_NET_RAW+eip arpmasqd");
        sockerr!("opening socket");
    }
    let attach_filter_res = unsafe { libc::setsockopt(listen_socket, libc::SOL_SOCKET, SO_ATTACH_FILTER, std::mem::transmute(&bpf_filter_arp_incoming_prog), std::mem::size_of_val(&bpf_filter_arp_incoming_prog) as u32) };
    if attach_filter_res == -1 {
        sockerr!("attaching filter");
    }
    let listen_sockaddr = libc::sockaddr_ll {
        sll_family: libc::AF_PACKET as u16,
        sll_protocol: ETH_P_ALL.to_be(),
        sll_ifindex: ifindex_from_ifname(&iface, listen_socket),
        sll_hatype: 0,
        sll_pkttype: 0,
        sll_halen: 0,
        sll_addr: [0; 8]
    };
    let bind_result = unsafe { libc::bind(listen_socket, std::mem::transmute(&listen_sockaddr), std::mem::size_of_val(&listen_sockaddr) as u32) };
    if bind_result == -1 {
        sockerr!("binding socket");
    }
    return Ok(listen_socket);
}

fn do_recv(listen_socket: libc::c_int) -> ! {
    let buf = [0u8; RECV_BUF_LEN];
    let mut recv_sockaddr = unsafe { std::mem::zeroed::<libc::sockaddr_ll>() };
    let mut recv_sockaddr_len: u32 = std::mem::size_of_val(&recv_sockaddr) as u32;
    loop {
        let recv_result = unsafe { libc::recvfrom(listen_socket, std::mem::transmute(&buf), RECV_BUF_LEN as u64, 0, std::mem::transmute(&recv_sockaddr), &mut recv_sockaddr_len) };
        if recv_result == -1 {
            let err = errno::errno();
            panic!("Error in recvfrom: {} ({})", err, err.0);
        }
        // rust has no offsetof yet so we hardcode 12 here instead
        println!("From: {}", recv_sockaddr.sll_addr[0..(recv_sockaddr_len as usize -12)].to_hex());
        println!("Data: {}", buf[0..(recv_result as usize)].to_hex());
    }
}

fn main() {
    let mut args = std::env::args();
    if args.len() != 2 {
        std::io::stderr().write("Usage: arpmasqd LISTEN_IFACE\n".as_ref()).unwrap();
        panic!("number of arguments");
    }
    args.next();
    //unwrap is ok because arg count has been checked
    let listen_iface = args.next().unwrap();
    let listen_socket = create_listen_socket(&listen_iface).unwrap_or_else(|err| panic!("Error {}: {} ({})", err.action, err.err, err.err.0));

    do_recv(listen_socket);
}
<|endoftext|>


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

extern crate time;
use time::Duration;

extern crate stats;
use stats::median;

extern crate clap;
use clap::{Arg, App};

mod percentile;
use percentile::percentile;

mod http_status;

mod request_response;
use request_response::*;

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

    let f = BufReader::new(f);

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

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

        if line_value.contains("->") {
            let r = try!(Request::new_from_log_line(&line_value));

            if time_filter.is_none() ||
              (time_filter.is_some() && r.is_between_times(time::now() - time_filter.unwrap(), time::now())) {
                requests.push(r);
            }
        }

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

    }

    responses.sort_by_key(|r| r.id);

    Ok((requests, responses))
}

#[derive(Eq, PartialEq)]
#[derive(Debug)]
pub struct RequestLogAnalyzerResult {
    count: usize,
    max: usize,
    min: usize,
    avg: usize,
    median: usize,
    percentile90: usize,
}

pub fn analyze(request_response_pairs: &Vec<RequestResponsePair>) -> RequestLogAnalyzerResult {
    let times: Vec<i64> = request_response_pairs.iter()
        .map(|rr: &RequestResponsePair| -> i64 {rr.response.response_time.num_milliseconds() })
        .collect();

    let sum: usize = times.iter().sum::<i64>() as usize;
    let avg: usize = sum / times.len();

    let max: usize = *times.iter().max().unwrap() as usize;
    let min: usize = *times.iter().min().unwrap() as usize;

    let percentile90: usize = percentile(&times, 0.9) as usize;

    let median = median(times.into_iter()).unwrap() as usize;

    RequestLogAnalyzerResult {
        count: request_response_pairs.len().into(),
        max: max,
        min: min,
        avg: avg,
        median: median,
        percentile90: percentile90,
    }
}

fn render_terminal(result: RequestLogAnalyzerResult) {
    println!("count:\t{}", result.count);
    println!("time.avg:\t{}", result.avg);
    println!("time.min:\t{}", result.min);
    println!("time.median:\t{}", result.median);
    println!("time.90percent:\t{}", result.percentile90);
    println!("time.max:\t{}", result.max);
}

fn main() {
    let matches = App::new("Request.log Analyzer")
        .arg(Arg::with_name("filename")
            .index(1)
            .value_name("FILE")
            .help("Log file to analyze")
            .takes_value(true))
            .get_matches();

    let filename = matches.value_of("filename").unwrap();

    let lines = open_logfile(filename, None);
    let (requests, responses) = lines.unwrap();

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

    let result: RequestLogAnalyzerResult = analyze(&pairs);

    render_terminal(result);
}

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

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

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

    #[test]
    fn test_open_logfile_time_filter() {
        let time_filter: Duration = Duration::minutes(1);
        let lines = open_logfile("src/test/simple-1.log", Some(time_filter));
        let (requests, responses) = lines.unwrap();

        assert_eq!(requests.len(), 0);

        let time_filter: Duration = Duration::minutes(52560000); // 100 years
        let lines = open_logfile("src/test/simple-1.log", Some(time_filter));
        let (requests, responses) = lines.unwrap();

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

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

        let result = pair_requests_responses(requests, responses);

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

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

    #[test]
    fn test_request_log_analyzer_result() {
        let lines = open_logfile("src/test/response-time-calculations.log", None);
        let (requests, responses) = lines.unwrap();

        let request_response_pairs = pair_requests_responses(requests, responses);

        let result: RequestLogAnalyzerResult = analyze(&request_response_pairs);

        let expected = RequestLogAnalyzerResult {
            count: 3,
            max: 100,
            min: 1,
            avg: 37,
            median: 10,
            percentile90: 100,
        };

        assert_eq!(result, expected);
    }

    #[test]
    fn test_90_percentile_calculation() {
        let lines = open_logfile("src/test/percentile.log", None);
        let (requests, responses) = lines.unwrap();

        let request_response_pairs = pair_requests_responses(requests, responses);

        let result: RequestLogAnalyzerResult = analyze(&request_response_pairs);

        assert_eq!(result.percentile90, 9);
    }
}
<commit_msg>Expose time filter as command line argument<commit_after>use std::io::{self, BufReader};
use std::io::BufRead;
use std::fs::File;

extern crate time;
use time::Duration;

extern crate stats;
use stats::median;

extern crate clap;
use clap::{Arg, App};

mod percentile;
use percentile::percentile;

mod http_status;

mod request_response;
use request_response::*;

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

    let f = BufReader::new(f);

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

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

        if line_value.contains("->") {
            let r = try!(Request::new_from_log_line(&line_value));

            if time_filter.is_none() ||
              (time_filter.is_some() && r.is_between_times(time::now() - time_filter.unwrap(), time::now())) {
                requests.push(r);
            }
        }

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

    }

    responses.sort_by_key(|r| r.id);

    Ok((requests, responses))
}

#[derive(Eq, PartialEq)]
#[derive(Debug)]
pub struct RequestLogAnalyzerResult {
    count: usize,
    max: usize,
    min: usize,
    avg: usize,
    median: usize,
    percentile90: usize,
}

pub fn analyze(request_response_pairs: &Vec<RequestResponsePair>) -> RequestLogAnalyzerResult {
    let times: Vec<i64> = request_response_pairs.iter()
        .map(|rr: &RequestResponsePair| -> i64 {rr.response.response_time.num_milliseconds() })
        .collect();

    let sum: usize = times.iter().sum::<i64>() as usize;
    let avg: usize = sum / times.len();

    let max: usize = *times.iter().max().unwrap() as usize;
    let min: usize = *times.iter().min().unwrap() as usize;

    let percentile90: usize = percentile(&times, 0.9) as usize;

    let median = median(times.into_iter()).unwrap() as usize;

    RequestLogAnalyzerResult {
        count: request_response_pairs.len().into(),
        max: max,
        min: min,
        avg: avg,
        median: median,
        percentile90: percentile90,
    }
}

fn render_terminal(result: RequestLogAnalyzerResult) {
    println!("count:\t{}", result.count);
    println!("time.avg:\t{}", result.avg);
    println!("time.min:\t{}", result.min);
    println!("time.median:\t{}", result.median);
    println!("time.90percent:\t{}", result.percentile90);
    println!("time.max:\t{}", result.max);
}

fn main() {
    let matches = App::new("Request.log Analyzer")
        .arg(Arg::with_name("filename")
            .index(1)
            .value_name("FILE")
            .help("Log file to analyze")
            .takes_value(true))
        .arg(Arg::with_name("time_filter_minutes")
                .value_name("MINUTES")
                .short("t")
                .help("Limit to the last n minutes")
                .takes_value(true))
                .get_matches();

    let filename = matches.value_of("filename").unwrap();

    let time_filter = match matches.value_of("time_filter_minutes") {
        Some(minutes) => Some(Duration::minutes(minutes.parse().unwrap())),
        None => None
    };

    let lines = open_logfile(filename, time_filter);
    let (requests, responses) = lines.unwrap();

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

    let result: RequestLogAnalyzerResult = analyze(&pairs);

    render_terminal(result);
}

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

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

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

    #[test]
    fn test_open_logfile_time_filter() {
        let time_filter: Duration = Duration::minutes(1);
        let lines = open_logfile("src/test/simple-1.log", Some(time_filter));
        let (requests, responses) = lines.unwrap();

        assert_eq!(requests.len(), 0);

        let time_filter: Duration = Duration::minutes(52560000); // 100 years
        let lines = open_logfile("src/test/simple-1.log", Some(time_filter));
        let (requests, responses) = lines.unwrap();

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

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

        let result = pair_requests_responses(requests, responses);

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

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

    #[test]
    fn test_request_log_analyzer_result() {
        let lines = open_logfile("src/test/response-time-calculations.log", None);
        let (requests, responses) = lines.unwrap();

        let request_response_pairs = pair_requests_responses(requests, responses);

        let result: RequestLogAnalyzerResult = analyze(&request_response_pairs);

        let expected = RequestLogAnalyzerResult {
            count: 3,
            max: 100,
            min: 1,
            avg: 37,
            median: 10,
            percentile90: 100,
        };

        assert_eq!(result, expected);
    }

    #[test]
    fn test_90_percentile_calculation() {
        let lines = open_logfile("src/test/percentile.log", None);
        let (requests, responses) = lines.unwrap();

        let request_response_pairs = pair_requests_responses(requests, responses);

        let result: RequestLogAnalyzerResult = analyze(&request_response_pairs);

        assert_eq!(result.percentile90, 9);
    }
}
<|endoftext|>


<commit_before>use std::io;
use std::io::Write; // need it to flush stdout
use std::env;
use std::path::PathBuf;
use std::process;
use std::process::{Stdio, Command};

static BUILTINS: [&'static str; 3] = ["exit", "cd", "pwd"];

struct CommandLine {
    // command name
    cmd: String,
    // arguments, starting directly with the first actual argument
    args: Vec<String>,
    // whether to execute as background process
    bg: bool
}

// probaby doesn't need to be a macro
macro_rules! print_err {
    ($msg:expr) => (println!("relish: {}", $msg));
}

/*
 * get_pwd - returns String containing pwd or "???" if there was an error
 */
fn get_pwd() -> String {
    match env::current_dir() {
        Ok(pwd) => {
            pwd.to_string_lossy().to_string()
        }
        Err(_) => {
            "???".to_string()
        }
    }
}

/*
 * execute - execute shell command line based on input CommandLine
 */
fn execute(cmdline: &CommandLine) {
    let mut _cmd = Command::new(&cmdline.cmd);
    let cmd = _cmd.args(&cmdline.args);

    if cmdline.bg {
        if let Err(why) = cmd.spawn() {
            print_err!(why);
        }
    } else {
        if let Err(why) = cmd.stdout(Stdio::inherit())
                             .stderr(Stdio::inherit())
                             .output() {
            print_err!(why);
        }
    }
}

fn builtin(cmdline: &CommandLine) {
    match &cmdline.cmd[..] {
        "exit" => {
            println!("So long, and thanks for all the fish!");
            process::exit(0);
        }
        "cd" => {
            // get dir to change to based on the length of cmdline.args
            let dir = if cmdline.args.len() == 0 {
                env::home_dir().unwrap_or(PathBuf::from("."))
            } else {
                // if they say `cd -`
                if cmdline.args[0] == "-" {
                    // return $OLDPWD, or "." if it's not available
                    PathBuf::from(&env::var("OLDPWD")
                                             .unwrap_or(".".to_string()))
                } else {
                    // create PathBuf from what they actually said
                    PathBuf::from(&cmdline.args[0])
                }
            };

            // set $OLDPWD
            env::set_var("OLDPWD", &env::current_dir()
                                        .unwrap_or(PathBuf::from(".".to_string())));
            // change directory
            if let Err(why) = env::set_current_dir(&dir) {
                print_err!(why);
            }
        }
        "pwd" => println!("{}", get_pwd()),
        _ => {}
    }
}

/*
 * get_prompt - generate and return shell prompt
 */
fn get_prompt() -> String {
    // get username
    let username = env::var("USER").unwrap_or("???".to_string());

    // get hostname
    let hostname = Command::new("/bin/hostname").output().unwrap();
    let hostname = String::from_utf8_lossy(&hostname.stdout);
    let hostname = hostname.trim();

    format!("{}@{} {} $ ", username, hostname, get_pwd())
}

/*
 * preprocess - main parsing routine responsible for populating CommandLine
 * struct
 */
fn preprocess(cmdline: &mut CommandLine) {
    let tmp = cmdline.cmd.clone();
    // TODO: this is awful, refactor to not use a loop
    for (i, each) in tmp.split(' ').enumerate() {
        if each.trim() == "" {
            // eat extra tabs/spaces
            continue;
        } else if each.trim().chars().nth(0).unwrap() == '#' {
            // stop parsing if there's a comment
            // ok to use unwrap because we've guaranteed input isn't empty
            break;
        } else if each.trim().chars().nth(0).unwrap() == '&' {
            // background process, ignoring rest of input
            // TODO: probably shouldn't just ignore rest of input. also,
            // the & has to have a space before it right now
            cmdline.bg = true;
            break;
        } else if i == 0 {
            cmdline.cmd = each.trim().to_string();
        } else {
            cmdline.args.push(each.trim().to_string());
        }
    }
}

fn main() {

    // main shell loop
    loop {

        let mut cmdline: CommandLine = CommandLine {
            cmd: String::new(),
            args: Vec::new(),
            bg: false
        };

        // print prompt
        print!("{}", get_prompt());
        if let Err(why) = io::stdout().flush() {
            print_err!(why);
            continue;
        }

        // read input into our String. if bytes_read is 0, we've hit EOF
        // and should exit. if there was an error, print the
        // error message and restart loop
        match io::stdin().read_line(&mut cmdline.cmd) {
            Ok(bytes_read) =>
                // Exit on EOF (Ctrl-d, end of script)
                if bytes_read == 0 {
                    println!("");
                    break;
                },
            Err(why) => {
                print_err!(why);
                continue;
            }
        }

        // check if blank/comment
        cmdline.cmd = cmdline.cmd.trim().to_string();
        match cmdline.cmd.chars().nth(0) {
            Some(first) =>
                if first == '#' {
                    continue
                },
            None => continue // empty string
        }

        // parse
        preprocess(&mut cmdline);

        // handle builtins
        if BUILTINS.contains(&&cmdline.cmd[..]) {
            builtin(&cmdline)
        } else {
            execute(&cmdline);
        }
    }
}
<commit_msg>Implement `exit` builtin within preprocess<commit_after>use std::io;
use std::io::Write; // need it to flush stdout
use std::env;
use std::path::PathBuf;
use std::process;
use std::process::{Stdio, Command};

static BUILTINS: [&'static str; 3] = ["exit", "cd", "pwd"];

struct CommandLine {
    // command name
    cmd: String,
    // arguments, starting directly with the first actual argument
    args: Vec<String>,
    // whether to execute as background process
    bg: bool
}

// probaby doesn't need to be a macro
macro_rules! print_err {
    ($msg:expr) => (println!("relish: {}", $msg));
}

/*
 * get_pwd - returns String containing pwd or "???" if there was an error
 */
fn get_pwd() -> String {
    match env::current_dir() {
        Ok(pwd) => {
            pwd.to_string_lossy().to_string()
        }
        Err(_) => {
            "???".to_string()
        }
    }
}

/*
 * execute - execute shell command line based on input CommandLine
 */
fn execute(cmdline: &CommandLine) {
    let mut _cmd = Command::new(&cmdline.cmd);
    let cmd = _cmd.args(&cmdline.args);

    if cmdline.bg {
        if let Err(why) = cmd.spawn() {
            print_err!(why);
        }
    } else {
        if let Err(why) = cmd.stdout(Stdio::inherit())
                             .stderr(Stdio::inherit())
                             .output() {
            print_err!(why);
        }
    }
}

/*
 * builtin - implement shell builtins
 *
 * NOTE: `exit` is implemented in preprocess() for efficiency
 */
fn builtin(cmdline: &CommandLine) {
    match &cmdline.cmd[..] {
        "cd" => {
            // get dir to change to based on the length of cmdline.args
            let dir = if cmdline.args.len() == 0 {
                env::home_dir().unwrap_or(PathBuf::from("."))
            } else {
                // if they say `cd -`
                if cmdline.args[0] == "-" {
                    // return $OLDPWD, or "." if it's not available
                    PathBuf::from(&env::var("OLDPWD")
                                             .unwrap_or(".".to_string()))
                } else {
                    // create PathBuf from what they actually said
                    PathBuf::from(&cmdline.args[0])
                }
            };

            // set $OLDPWD
            env::set_var("OLDPWD", &env::current_dir()
                                        .unwrap_or(PathBuf::from(".".to_string())));
            // change directory
            if let Err(why) = env::set_current_dir(&dir) {
                print_err!(why);
            }
        }
        "pwd" => println!("{}", get_pwd()),
        _ => {}
    }
}

/*
 * get_prompt - generate and return shell prompt
 */
fn get_prompt() -> String {
    // get username
    let username = env::var("USER").unwrap_or("???".to_string());

    // get hostname
    let hostname = Command::new("/bin/hostname").output().unwrap();
    let hostname = String::from_utf8_lossy(&hostname.stdout);
    let hostname = hostname.trim();

    format!("{}@{} {} $ ", username, hostname, get_pwd())
}

/*
 * preprocess - main parsing routine responsible for populating CommandLine
 * struct
 */
fn preprocess(cmdline: &mut CommandLine) {
    let tmp = cmdline.cmd.clone();
    // TODO: this is awful, refactor to not use a loop
    for (i, each) in tmp.split(' ').enumerate() {
        if each.trim() == "" {
            // eat extra tabs/spaces
            continue;
        } else if each.trim().chars().nth(0).unwrap() == '#' {
            // stop parsing if there's a comment
            // ok to use unwrap because we've guaranteed input isn't empty
            break;
        } else if each.trim().chars().nth(0).unwrap() == '&' {
            // background process, ignoring rest of input
            // TODO: probably shouldn't just ignore rest of input. also,
            // the & has to have a space before it right now
            cmdline.bg = true;
            break;
        } else if i == 0 {
            // implement `exit` builtin here for efficiency. as soon as we
            // know that the command name is exit, we can shut it down
            if each.trim() == "exit" {
                println!("So long, and thanks for all the fish!");
                process::exit(0);
            } else {
                cmdline.cmd = each.trim().to_string();
            }
        } else {
            cmdline.args.push(each.trim().to_string());
        }
    }
}

fn main() {

    // main shell loop
    loop {

        let mut cmdline: CommandLine = CommandLine {
            cmd: String::new(),
            args: Vec::new(),
            bg: false
        };

        // print prompt
        print!("{}", get_prompt());
        if let Err(why) = io::stdout().flush() {
            print_err!(why);
            continue;
        }

        // read input into our String. if bytes_read is 0, we've hit EOF
        // and should exit. if there was an error, print the
        // error message and restart loop
        match io::stdin().read_line(&mut cmdline.cmd) {
            Ok(bytes_read) =>
                // Exit on EOF (Ctrl-d, end of script)
                if bytes_read == 0 {
                    println!("");
                    break;
                },
            Err(why) => {
                print_err!(why);
                continue;
            }
        }

        // check if blank/comment
        cmdline.cmd = cmdline.cmd.trim().to_string();
        match cmdline.cmd.chars().nth(0) {
            Some(first) =>
                if first == '#' {
                    continue
                },
            None => continue // empty string
        }

        // parse
        preprocess(&mut cmdline);

        // handle builtins
        if BUILTINS.contains(&&cmdline.cmd[..]) {
            builtin(&cmdline)
        } else {
            execute(&cmdline);
        }
    }
}
<|endoftext|>