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

// extern crate base64;
// extern crate blake2_rfc;
#[macro_use]
extern crate clap;
extern crate humansize;
extern crate linear_map;
extern crate rusqlite;
extern crate twox_hash;
extern crate walkdir;
extern crate indicatif;

// use blake2_rfc::blake2b::Blake2b;
use humansize::{FileSize, file_size_opts as options};
use clap::{App, Arg};
use linear_map::LinearMap;
use std::io;
use std::io::Read;
use std::fs::File;
use std::hash::Hasher;
use std::collections::BTreeMap;
use std::path::PathBuf;
use walkdir::WalkDir;

fn copy<R: io::Read, W: Hasher>(reader: &mut R, writer: &mut W) -> io::Result<u64> {
    let mut buf = [0; 64 * 1024];
    let mut written = 0;
    loop {
        let len = match reader.read(&mut buf) {
            Ok(0) => return Ok(written),
            Ok(len) => len,
            Err(ref e) if e.kind() == io::ErrorKind::Interrupted => continue,
            Err(e) => return Err(e),
        };
        writer.write(&buf[..len]);
        written += len as u64;
    }
}

fn to_hash(path: &PathBuf) -> u64 {
    let mut file = File::open(path).unwrap();
    let mut hasher = twox_hash::XxHash::default();
    copy(&mut file, &mut hasher).unwrap();
    hasher.finish()
}

fn read_file(path: &PathBuf) -> Vec<u8> {
    let mut file = File::open(path).unwrap();
    let mut vec = Vec::new();
    file.read_to_end(&mut vec).unwrap();
    vec
}

fn partition_by<I, F, R>(paths: I, f: F) -> LinearMap<R, Vec<PathBuf>>
    where I: Iterator<Item=PathBuf>, F: Fn(&PathBuf) -> R, R: Eq
{
    let mut map = LinearMap::with_capacity(paths.size_hint().0);
    for path in paths {
        let key = f(&path);
        map.entry(key).or_insert_with(Vec::new).push(path);
    }
    map
}

const DB_TABLE_SCHEMA: &'static str = r#"
CREATE TABLE files (
    hash BIGINT NOT NULL,
    path TEXT NOT NULL,
    size BIGINT NOT NULL
);
"#;

fn main() {
    let matches = App::new(crate_name!())
        .version(crate_version!())
        .author(crate_authors!("\n"))
        .arg(Arg::with_name("media_directory")
            .help("The location of the media store")
            .index(1)
            .required(true))
        .get_matches();

    let path = matches.value_of("media_directory").unwrap();

    println!("Creating DB...");

    let db = rusqlite::Connection::open_in_memory().expect("failed to open sqlite db");
    db.execute_batch(DB_TABLE_SCHEMA).expect("failed to create db schema");

    let mut paths_by_size = BTreeMap::new();
    let mut total_files = 0;

    println!("Walking fs...");

    let pb = indicatif::ProgressBar::new_spinner();

    for entry in WalkDir::new(path) {
        let entry = entry.unwrap();
        if !entry.file_type().is_file() {
            continue
        }

        let file_size = entry.metadata().unwrap().len() as usize;
        paths_by_size.entry(file_size).or_insert_with(Vec::new).push(entry.path().to_owned());

        total_files += 1;

        pb.inc(1);
        if total_files % 100 == 0 {
            // println!("Handled {} files", total_files);
            // pb.set_message(&format!("Handled {} files", total_files));
        }
        pb.set_message(&format!("Handled {} files", total_files));
    }

    pb.finish_and_clear();

    println!("Handled {} files", total_files);
    println!();

     let pb = indicatif::ProgressBar::new(total_files);

    let mut total_wasted_size = 0;

    for (file_size, paths) in paths_by_size {
        if paths.len() == 1 {
            pb.inc(file_size as u64);
            continue
        }

        let by_hash = partition_by(paths.into_iter(), to_hash);

        for (hash, paths) in by_hash {
            if paths.len() == 1 {
                pb.inc(file_size as u64);
                continue
            }

            let by_contents = partition_by(paths.into_iter(), read_file);

            for (_, paths) in by_contents {
                if paths.len() == 1 {
                    pb.inc(file_size as u64);
                    continue
                }

                // print!("Duplicate {} paths (hash: {})\n", paths.len(), hash);
                for path in &paths {
                    db.execute("INSERT INTO files (hash, path, size) VALUES (?, ?, ?)", &[&(hash as i64), &path.to_str().unwrap(), &(file_size as i64)]).expect("failed to write to db");
                    // print!("  {}\n", path.display());
                }

                let wasted = file_size * (paths.len() - 1);
                // print!(
                //     " Size: {}. Wasting {}.\n",
                //     file_size.file_size(options::CONVENTIONAL).unwrap(),
                //     wasted.file_size(options::CONVENTIONAL).unwrap(),
                // );

                total_wasted_size += wasted;

                pb.inc((file_size * paths.len()) as u64);
            }
        }
    }

    pb.finish();

    println!();
    println!("Total wasted size: {}", total_wasted_size.file_size(options::CONVENTIONAL).unwrap());

    let mut disk_db = rusqlite::Connection::open("media_store_sizes.db").expect("failed to open sqlite db");
    let backup = rusqlite::backup::Backup::new(&db, &mut disk_db).expect("failed to create backup");
    backup.run_to_completion(5, std::time::Duration::from_millis(0), None).expect("failed to write to disk");
}
<commit_msg>Fix up<commit_after>//    Copyright 2017 Vector Creations Limited
//
//    Licensed under the Apache License, Version 2.0 (the "License");
//    you may not use this file except in compliance with the License.
//    You may obtain a copy of the License at
//
//        http://www.apache.org/licenses/LICENSE-2.0
//
//    Unless required by applicable law or agreed to in writing, software
//    distributed under the License is distributed on an "AS IS" BASIS,
//    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//    See the License for the specific language governing permissions and
//    limitations under the License.

// extern crate base64;
// extern crate blake2_rfc;
#[macro_use]
extern crate clap;
extern crate humansize;
extern crate linear_map;
extern crate rusqlite;
extern crate twox_hash;
extern crate walkdir;
extern crate indicatif;

// use blake2_rfc::blake2b::Blake2b;
use humansize::{FileSize, file_size_opts as options};
use clap::{App, Arg};
use linear_map::LinearMap;
use std::io;
use std::io::Read;
use std::fs::File;
use std::hash::Hasher;
use std::collections::BTreeMap;
use std::path::PathBuf;
use walkdir::WalkDir;

fn copy<R: io::Read, W: Hasher>(reader: &mut R, writer: &mut W) -> io::Result<u64> {
    let mut buf = [0; 64 * 1024];
    let mut written = 0;
    loop {
        let len = match reader.read(&mut buf) {
            Ok(0) => return Ok(written),
            Ok(len) => len,
            Err(ref e) if e.kind() == io::ErrorKind::Interrupted => continue,
            Err(e) => return Err(e),
        };
        writer.write(&buf[..len]);
        written += len as u64;
    }
}

fn to_hash(path: &PathBuf) -> u64 {
    let mut file = File::open(path).unwrap();
    let mut hasher = twox_hash::XxHash::default();
    copy(&mut file, &mut hasher).unwrap();
    hasher.finish()
}

fn read_file(path: &PathBuf) -> Vec<u8> {
    let mut file = File::open(path).unwrap();
    let mut vec = Vec::new();
    file.read_to_end(&mut vec).unwrap();
    vec
}

fn partition_by<I, F, R>(paths: I, f: F) -> LinearMap<R, Vec<PathBuf>>
    where I: Iterator<Item=PathBuf>, F: Fn(&PathBuf) -> R, R: Eq
{
    let mut map = LinearMap::with_capacity(paths.size_hint().0);
    for path in paths {
        let key = f(&path);
        map.entry(key).or_insert_with(Vec::new).push(path);
    }
    map
}

const DB_TABLE_SCHEMA: &'static str = r#"
CREATE TABLE files (
    hash BIGINT NOT NULL,
    path TEXT NOT NULL,
    size BIGINT NOT NULL
);
"#;

fn main() {
    let matches = App::new(crate_name!())
        .version(crate_version!())
        .author(crate_authors!("\n"))
        .arg(Arg::with_name("media_directory")
            .help("The location of the media store")
            .index(1)
            .required(true))
        .get_matches();

    let path = matches.value_of("media_directory").unwrap();

    println!("Creating DB...");

    let db = rusqlite::Connection::open_in_memory().expect("failed to open sqlite db");
    db.execute_batch(DB_TABLE_SCHEMA).expect("failed to create db schema");

    let mut paths_by_size = BTreeMap::new();
    let mut total_files = 0;
    let mut total_size = 0;

    println!("Walking fs...");

    let pb = indicatif::ProgressBar::new_spinner();

    for entry in WalkDir::new(path) {
        let entry = entry.unwrap();
        if !entry.file_type().is_file() {
            continue
        }

        let file_size = entry.metadata().unwrap().len() as usize;
        paths_by_size.entry(file_size).or_insert_with(Vec::new).push(entry.path().to_owned());

        total_files += 1;
        total_size += file_size;

        pb.inc(1);
        if total_files % 100 == 0 {
            // println!("Handled {} files", total_files);
            // pb.set_message(&format!("Handled {} files", total_files));
        }
        pb.set_message(&format!("Handled {} files", total_files));
    }

    pb.finish_and_clear();

    println!("Handled {} files", total_files);
    println!();

     let pb = indicatif::ProgressBar::new(total_size as u64);

    let mut total_wasted_size = 0;

    for (file_size, paths) in paths_by_size {
        if paths.len() == 1 {
            pb.inc(file_size as u64);
            continue
        }

        let by_hash = partition_by(paths.into_iter(), to_hash);

        for (hash, paths) in by_hash {
            if paths.len() == 1 {
                pb.inc(file_size as u64);
                continue
            }

            let by_contents = partition_by(paths.into_iter(), read_file);

            for (_, paths) in by_contents {
                if paths.len() == 1 {
                    pb.inc(file_size as u64);
                    continue
                }

                // print!("Duplicate {} paths (hash: {})\n", paths.len(), hash);
                for path in &paths {
                    db.execute("INSERT INTO files (hash, path, size) VALUES (?, ?, ?)", &[&(hash as i64), &path.to_str().unwrap(), &(file_size as i64)]).expect("failed to write to db");
                    // print!("  {}\n", path.display());
                }

                let wasted = file_size * (paths.len() - 1);
                // print!(
                //     " Size: {}. Wasting {}.\n",
                //     file_size.file_size(options::CONVENTIONAL).unwrap(),
                //     wasted.file_size(options::CONVENTIONAL).unwrap(),
                // );

                total_wasted_size += wasted;

                pb.inc((file_size * paths.len()) as u64);
            }
        }
    }

    pb.finish();

    println!();
    println!("Total wasted size: {}", total_wasted_size.file_size(options::CONVENTIONAL).unwrap());

    let mut disk_db = rusqlite::Connection::open("media_store_sizes.db").expect("failed to open sqlite db");
    let backup = rusqlite::backup::Backup::new(&db, &mut disk_db).expect("failed to create backup");
    backup.run_to_completion(5, std::time::Duration::from_millis(0), None).expect("failed to write to disk");
}
<|endoftext|>


<commit_before>extern crate clap;
extern crate pcap;
extern crate pnet;
extern crate serde_json;

use clap::{Arg, App};
use pcap::Capture;
use pnet::packet::{Packet, ethernet, ip, ipv4, tcp, udp};
use serde_json::{Value, Map, Number};

fn parse_ethernet(p: &ethernet::EthernetPacket) -> Map<String, Value> {
	let source = p.get_source();
	let destination = p.get_destination();
	let ethertype = p.get_ethertype();

	let mut header = Map::new();
	header.insert("source".to_string(), Value::String(source.to_string()));
	header.insert("destination".to_string(), Value::String(destination.to_string()));
	header.insert("type".to_string(), Value::String(ethertype.to_string()));

	header
}

fn parse_ipv4(p: &ipv4::Ipv4Packet) -> Map<String, Value> {
	let version = p.get_version();
	let ihl = p.get_header_length();
	let dscp = p.get_dscp();
	let ecn = p.get_ecn();
	let total_length = p.get_total_length();
	let identification = p.get_identification();
	let flags = p.get_flags();
	let fragment_offset = p.get_fragment_offset();
	let ttl = p.get_ttl();
	let next_level_protocol = p.get_next_level_protocol();
	let checksum = p.get_checksum();
	let source = p.get_source();
	let destination = p.get_destination();

	let mut header = Map::new();
    header.insert("version".to_string(), Value::Number(Number::from(version)));
    header.insert("ihl".to_string(), Value::Number(Number::from(ihl)));
    header.insert("dscp".to_string(), Value::Number(Number::from(dscp)));
    header.insert("ecn".to_string(), Value::Number(Number::from(ecn)));
    header.insert("total_length".to_string(), Value::Number(Number::from(total_length)));
    header.insert("identification".to_string(), Value::Number(Number::from(identification)));
    header.insert("flags.".to_string(), Value::Number(Number::from(flags)));
    header.insert("fragment_offset".to_string(), Value::Number(Number::from(fragment_offset)));
    header.insert("ttl".to_string(), Value::Number(Number::from(ttl)));
    header.insert("protocol".to_string(), Value::String(next_level_protocol.to_string().to_lowercase()));
    header.insert("checksum".to_string(), Value::Number(Number::from(checksum)));
    header.insert("source_address".to_string(), Value::String(source.to_string()));
    header.insert("destination_address".to_string(), Value::String(destination.to_string()));

	header
}

fn parse_tcp(p: &tcp::TcpPacket) -> Map<String, Value> {
	let source_port = p.get_source();
	let destination_port = p.get_destination();
	let sequence_number = p.get_sequence();
	let ack_number = p.get_acknowledgement();
	let data_offset = p.get_data_offset();
	let flags = p.get_flags();
	let window_size = p.get_window();
	let checksum = p.get_checksum();
	let urgent_pointer = p.get_urgent_ptr();

	let mut header = Map::new();
	header.insert("source_port".to_string(), Value::String(source_port.to_string()));
	header.insert("destination_port".to_string(), Value::String(destination_port.to_string()));
	header.insert("sequence_number".to_string(), Value::Number(Number::from(sequence_number)));
	header.insert("ack_number".to_string(), Value::Number(Number::from(ack_number)));
	header.insert("data_offset".to_string(), Value::Number(Number::from(data_offset)));
	header.insert("flags".to_string(), Value::Number(Number::from(flags)));
	header.insert("window_size".to_string(), Value::Number(Number::from(window_size)));
	header.insert("checksum".to_string(), Value::Number(Number::from(checksum)));
	header.insert("urgent_pointer".to_string(), Value::Number(Number::from(urgent_pointer)));

	header
}

fn parse_udp(p: &udp::UdpPacket) -> Map<String, Value> {
	let source_port = p.get_source();
	let destination_port = p.get_destination();
	let length = p.get_length();
	let checksum = p.get_checksum();

	let mut header = Map::new();
	header.insert("source_port".to_string(), Value::String(source_port.to_string()));
	header.insert("destination_port".to_string(), Value::String(destination_port.to_string()));
	header.insert("length".to_string(), Value::Number(Number::from(length)));
	header.insert("checksum".to_string(), Value::Number(Number::from(checksum)));

	header
}

fn parse_headers(p: pcap::Packet) -> Map<String, Value> {
	let mut headers = Map::new();

	let timestamp = p.header.ts.tv_sec;

	let ethernet_packet = ethernet::EthernetPacket::new(p.data).unwrap();
	        let ethernet_header = parse_ethernet(&ethernet_packet);

	        match ethernet_packet.get_ethertype() {
	        	ethernet::EtherTypes::Ipv4 => {
	        		let ipv4_packet = ipv4::Ipv4Packet::new(ethernet_packet.payload()).unwrap();
	        		let ipv4_header = parse_ipv4(&ipv4_packet);

	        		match ipv4_packet.get_next_level_protocol() {
	        			ip::IpNextHeaderProtocols::Tcp => {
	        				let tcp_packet = tcp::TcpPacket::new(ipv4_packet.payload()).unwrap();
	        				let tcp_header = parse_tcp(&tcp_packet);
	        				headers.insert("tcp".to_string(), Value::Object(tcp_header));
	        			},
	        			ip::IpNextHeaderProtocols::Udp => {
	        				let udp_packet = udp::UdpPacket::new(ipv4_packet.payload()).unwrap();
	        				let udp_header = parse_udp(&udp_packet);
	        				headers.insert("udp".to_string(), Value::Object(udp_header));
	        			},
	        			_ => (),
	        		}
	        		headers.insert("ipv4".to_string(), Value::Object(ipv4_header));
	        	},
	        	_ => (),
	        }
	        headers.insert("ethernet".to_string(), Value::Object(ethernet_header));
	        headers.insert("timestamp".to_string(), Value::Number(Number::from(timestamp)));

	headers
}

fn sniff(interface: &str, promiscuous: bool, snaplen: i32, timeout: i32) {
    let mut capture = Capture::from_device(interface).unwrap()
                      	.promisc(promiscuous)
                        .snaplen(snaplen)
                        .timeout(timeout)
                        .open()
                        .unwrap();

    while let Ok(packet) = capture.next() {
    	let packet_headers = parse_headers(packet);
		println!("{}", serde_json::to_string(&packet_headers).unwrap());
    }
    println!();
}

fn main() {
	const VERSION: &str = "0.1.0";
	const AUTHOR: &str = "Kevin Brebanov <kevin.brebanov@gmail.com>";
	const ABOUT: &str = "DNS packet sniffer that outputs to JSON";

    let arguments = App::new("snout")
                            .version(VERSION)
                            .author(AUTHOR)
                            .about(ABOUT)
                            .arg(Arg::with_name("interface")
                                .short("i")
                                .long("interface")
                                .value_name("INTERFACE")
                                .required(true)
                                .help("Network interface to sniff packets on")
                                .takes_value(true))
                            .arg(Arg::with_name("promiscuous")
                                .short("p")
                                .long("promiscuous")
                                .required(false)
                                .help("Enable promiscuous mode"))
                            .arg(Arg::with_name("snaplen")
                                .short("s")
                                .long("snaplen")
                                .value_name("SNAPLEN")
                                .required(false)
                                .help("Snapshot length")
                                .takes_value(true))
                            .arg(Arg::with_name("timeout")
                                .short("t")
                                .long("timeout")
                                .value_name("TIMEOUT")
                                .required(false)
                                .help("Read timeout in milliseconds")
                                .takes_value(true))
                            .get_matches();

    let interface = arguments.value_of("interface").unwrap();
    let mut promiscuous = false;
    if arguments.is_present("promiscuous") {
        promiscuous = true;
    }
    let snaplen: i32 = arguments.value_of("snaplen").unwrap_or("65535").parse().unwrap();
    let timeout: i32 = arguments.value_of("timeout").unwrap_or("0").parse().unwrap();

    sniff(interface, promiscuous, snaplen, timeout);
}
<commit_msg>Start adding DNS parsing and add BPF option<commit_after>extern crate clap;
extern crate pcap;
extern crate pnet;
extern crate serde_json;
extern crate dns_parser;

use clap::{Arg, App};
use pcap::Capture;
use pnet::packet::{Packet, ethernet, ip, ipv4, tcp, udp};
use serde_json::{Value, Map, Number};
use dns_parser::Packet as DnsPacket;

fn parse_ethernet(p: &ethernet::EthernetPacket) -> Map<String, Value> {
	let source = p.get_source();
	let destination = p.get_destination();
	let ethertype = p.get_ethertype();

	let mut header = Map::new();
	header.insert("source".to_string(), Value::String(source.to_string()));
	header.insert("destination".to_string(), Value::String(destination.to_string()));
	header.insert("type".to_string(), Value::String(ethertype.to_string().to_lowercase()));

	header
}

fn parse_ipv4(p: &ipv4::Ipv4Packet) -> Map<String, Value> {
	let version = p.get_version();
	let ihl = p.get_header_length();
	let dscp = p.get_dscp();
	let ecn = p.get_ecn();
	let total_length = p.get_total_length();
	let identification = p.get_identification();
	let flags = p.get_flags();
	let fragment_offset = p.get_fragment_offset();
	let ttl = p.get_ttl();
	let next_level_protocol = p.get_next_level_protocol();
	let checksum = p.get_checksum();
	let source = p.get_source();
	let destination = p.get_destination();

	let mut header = Map::new();
    header.insert("version".to_string(), Value::Number(Number::from(version)));
    header.insert("ihl".to_string(), Value::Number(Number::from(ihl)));
    header.insert("dscp".to_string(), Value::Number(Number::from(dscp)));
    header.insert("ecn".to_string(), Value::Number(Number::from(ecn)));
    header.insert("total_length".to_string(), Value::Number(Number::from(total_length)));
    header.insert("identification".to_string(), Value::Number(Number::from(identification)));
    header.insert("flags.".to_string(), Value::Number(Number::from(flags)));
    header.insert("fragment_offset".to_string(), Value::Number(Number::from(fragment_offset)));
    header.insert("ttl".to_string(), Value::Number(Number::from(ttl)));
    header.insert("protocol".to_string(), Value::String(next_level_protocol.to_string().to_lowercase()));
    header.insert("checksum".to_string(), Value::Number(Number::from(checksum)));
    header.insert("source_address".to_string(), Value::String(source.to_string()));
    header.insert("destination_address".to_string(), Value::String(destination.to_string()));

	header
}

fn parse_tcp(p: &tcp::TcpPacket) -> Map<String, Value> {
	let source_port = p.get_source();
	let destination_port = p.get_destination();
	let sequence_number = p.get_sequence();
	let ack_number = p.get_acknowledgement();
	let data_offset = p.get_data_offset();
	let flags = p.get_flags();
	let window_size = p.get_window();
	let checksum = p.get_checksum();
	let urgent_pointer = p.get_urgent_ptr();

	let mut header = Map::new();
	header.insert("source_port".to_string(), Value::String(source_port.to_string()));
	header.insert("destination_port".to_string(), Value::String(destination_port.to_string()));
	header.insert("sequence_number".to_string(), Value::Number(Number::from(sequence_number)));
	header.insert("ack_number".to_string(), Value::Number(Number::from(ack_number)));
	header.insert("data_offset".to_string(), Value::Number(Number::from(data_offset)));
	header.insert("flags".to_string(), Value::Number(Number::from(flags)));
	header.insert("window_size".to_string(), Value::Number(Number::from(window_size)));
	header.insert("checksum".to_string(), Value::Number(Number::from(checksum)));
	header.insert("urgent_pointer".to_string(), Value::Number(Number::from(urgent_pointer)));

	header
}

fn parse_udp(p: &udp::UdpPacket) -> Map<String, Value> {
	let source_port = p.get_source();
	let destination_port = p.get_destination();
	let length = p.get_length();
	let checksum = p.get_checksum();

	let mut header = Map::new();
	header.insert("source_port".to_string(), Value::String(source_port.to_string()));
	header.insert("destination_port".to_string(), Value::String(destination_port.to_string()));
	header.insert("length".to_string(), Value::Number(Number::from(length)));
	header.insert("checksum".to_string(), Value::Number(Number::from(checksum)));

	header
}

fn parse_dns(p: &DnsPacket) -> Map<String, Value> {
	let id = p.header.id;
	let total_questions = p.header.questions;
	let total_answer_rrs = p.header.answers;
	let total_authority_rrs = p.header.nameservers;
	let total_additional_rrs = p.header.additional;

	let mut header = Map::new();
	header.insert("id".to_string(), Value::Number(Number::from(id)));
	header.insert("total_questions".to_string(), Value::Number(Number::from(total_questions)));
	header.insert("total_answer_rrs".to_string(), Value::Number(Number::from(total_answer_rrs)));
	header.insert("total_authority_rrs".to_string(), Value::Number(Number::from(total_authority_rrs)));
	header.insert("total_additional_rrs".to_string(), Value::Number(Number::from(total_additional_rrs)));

	header
}

fn parse_headers(p: pcap::Packet) -> Map<String, Value> {
	let mut headers = Map::new();

	let timestamp = p.header.ts.tv_sec;

	let ethernet_packet = ethernet::EthernetPacket::new(p.data).unwrap();
	        let ethernet_header = parse_ethernet(&ethernet_packet);

	        match ethernet_packet.get_ethertype() {
	        	ethernet::EtherTypes::Ipv4 => {
	        		let ipv4_packet = ipv4::Ipv4Packet::new(ethernet_packet.payload()).unwrap();
	        		let ipv4_header = parse_ipv4(&ipv4_packet);

	        		match ipv4_packet.get_next_level_protocol() {
	        			ip::IpNextHeaderProtocols::Tcp => {
	        				let tcp_packet = tcp::TcpPacket::new(ipv4_packet.payload()).unwrap();
	        				let tcp_header = parse_tcp(&tcp_packet);
	        				headers.insert("tcp".to_string(), Value::Object(tcp_header));

	        				match DnsPacket::parse(tcp_packet.payload()) {
	        					Ok(dns_packet) => {
	        						let dns_header = parse_dns(&dns_packet);
	        					    headers.insert("dns".to_string(), Value::Object(dns_header));
	        					},
	        					Err(_) => (),
	        				}
	        			},
	        			ip::IpNextHeaderProtocols::Udp => {
	        				let udp_packet = udp::UdpPacket::new(ipv4_packet.payload()).unwrap();
	        				let udp_header = parse_udp(&udp_packet);
	        				headers.insert("udp".to_string(), Value::Object(udp_header));

	        				match DnsPacket::parse(udp_packet.payload()) {
	        					Ok(dns_packet) => {
	        						let dns_header = parse_dns(&dns_packet);
	        						headers.insert("dns".to_string(), Value::Object(dns_header));
	        					},
	        					Err(_) => (),
	        				}
	        			},
	        			_ => (),
	        		}
	        		headers.insert("ipv4".to_string(), Value::Object(ipv4_header));
	        	},
	        	_ => (),
	        }
	        headers.insert("ethernet".to_string(), Value::Object(ethernet_header));
	        headers.insert("timestamp".to_string(), Value::Number(Number::from(timestamp)));

	headers
}

fn sniff(interface: &str, promiscuous: bool, snaplen: i32, timeout: i32, filter: &str) {
    let mut capture = Capture::from_device(interface).unwrap()
                      	.promisc(promiscuous)
                        .snaplen(snaplen)
                        .timeout(timeout)
                        .open()
                        .unwrap();

    if !filter.is_empty() {
    	capture.filter(filter).unwrap();
    }

    while let Ok(packet) = capture.next() {
    	let packet_headers = parse_headers(packet);
		println!("{}", serde_json::to_string(&packet_headers).unwrap());
    }
    println!();
}

fn main() {
	const VERSION: &str = "0.1.0";
	const AUTHOR: &str = "Kevin Brebanov <kevin.brebanov@gmail.com>";
	const ABOUT: &str = "DNS packet sniffer that outputs to JSON";

    let arguments = App::new("snout")
                            .version(VERSION)
                            .author(AUTHOR)
                            .about(ABOUT)
                            .arg(Arg::with_name("interface")
                                .short("i")
                                .long("interface")
                                .value_name("INTERFACE")
                                .required(true)
                                .help("Network interface to sniff packets on")
                                .takes_value(true))
                            .arg(Arg::with_name("promiscuous")
                                .short("p")
                                .long("promiscuous")
                                .required(false)
                                .help("Enable promiscuous mode"))
                            .arg(Arg::with_name("snaplen")
                                .short("s")
                                .long("snaplen")
                                .value_name("SNAPLEN")
                                .required(false)
                                .help("Snapshot length")
                                .takes_value(true))
                            .arg(Arg::with_name("timeout")
                                .short("t")
                                .long("timeout")
                                .value_name("TIMEOUT")
                                .required(false)
                                .help("Read timeout in milliseconds")
                                .takes_value(true))
                            .arg(Arg::with_name("filter")
                                 .short("f")
                                 .long("filter")
                                 .value_name("FILTER")
                                 .required(false)
                                 .help("Berkeley Packet Filter (BPF)")
                                 .takes_value(true))
                            .get_matches();

    let interface = arguments.value_of("interface").unwrap();
    let mut promiscuous = false;
    if arguments.is_present("promiscuous") {
        promiscuous = true;
    }
    let snaplen: i32 = arguments.value_of("snaplen").unwrap_or("65535").parse().unwrap();
    let timeout: i32 = arguments.value_of("timeout").unwrap_or("0").parse().unwrap();
    let filter: &str = arguments.value_of("filter").unwrap_or("");

    sniff(interface, promiscuous, snaplen, timeout, filter);
}
<|endoftext|>


<commit_before>#[macro_use]
extern crate log;
extern crate getopts;
#[macro_use]
extern crate shoop;

use std::str;
use std::env;
use std::path::Path;
use getopts::Options;
use shoop::{ShoopLogger, ShoopMode, Server, download};
use shoop::connection::PortRange;

const VERSION: &'static str = env!("CARGO_PKG_VERSION");
const DEFAULT_PORT_RANGE: &'static str = "55000-55050";

fn print_usage(program: &str, opts: Options) {
    let brief = format!("Shoop is a ultrafast, (hopefully) secure file transfer tool, that is
(hopefully) ideal for transferring large files.

Usage: {0} [options] SOURCE DEST
...where HOST is an SSH host
...where PATH is the path on the *remote* machine of the file you want
...where DEST is either an existing folder or a location for the new
                 file (\".\" by default)

Example: {0} seedbox.facebook.com:/home/zuck/internalized_sadness.zip .",
                        program);
    print!("{}", opts.usage(&brief));
}

enum Target {
    Local(String),
    Remote(String, String),
}

impl Target {
    fn from(s: String) -> Target {
        match s.find(':') {
            None => Target::Local(s),
            Some(i) => {
                let owned = s.to_owned();
                let (first, second) = owned.split_at(i);
                if first.contains('/') {
                    Target::Local(s)
                } else {
                    Target::Remote(String::from(first), String::from(second))
                }
            }
        }
    }
}

fn main() {
    let args: Vec<String> = env::args().collect();
    let program = args[0].clone();
    let mut opts = Options::new();
    // TODO
    // opts.optopt("o", "output", "set output file name", "NAME");
    // opts.optopt("a", "ssh-args", "arguments to pass to ssh directly (at your own risk)", ARGS);
    opts.optopt("p",
                "port-range",
                "server listening port range",
                DEFAULT_PORT_RANGE);
    opts.optflag("s", "server", "server mode (advanced usage only)");
    opts.optflag("h", "help", "print this help menu");
    opts.optflag("v", "version", "print the version");

    let matches = match opts.parse(&args[1..]) {
        Ok(m) => m,
        Err(f) => panic!(f.to_string()),
    };

    if matches.opt_present("h") {
        print_usage(&program, opts);
        return;
    }

    if matches.opt_present("v") {
        println!("shoop {}", VERSION);
        return;
    }

    let source = if !matches.free.is_empty() {
        matches.free[0].clone()
    } else {
        print_usage(&program, opts);
        return;
    };

    let mode = if matches.opt_present("s") {
        ShoopMode::Server
    } else {
        ShoopMode::Client
    };

    let port_range = {
        let range_opt = &matches.opt_str("p").unwrap_or_else(|| String::from(DEFAULT_PORT_RANGE));
        PortRange::from(range_opt).unwrap()
    };

    ShoopLogger::init(mode).expect("Error starting shoop logger.");

    match mode {
        ShoopMode::Server => {
            if let Ok(server) = Server::new(port_range, &source) {
                server.start();
                info!("exiting.");
            }
        }
        ShoopMode::Client => {
            let dest = if matches.free.len() > 1 {
                matches.free[1].clone()
            } else {
                String::from(".")
            };

            match Target::from(source) {
                Target::Local(_) => error!("Sorry, you can only copy *from* a remote host currently."),
                Target::Remote(source_addr, source_path_str) => {
                    match Target::from(dest) {
                        Target::Remote(_,_) => error!("Sorry, you can only copy to a local path currently."),
                        Target::Local(dest_path_str) => {
                            let source_path = Path::new(&source_path_str);
                            let source_file_name = match source_path.file_name() {
                                Some(s) => s,
                                None => {
                                    error!("The remote path specified doesn't look like a path to a file.");
                                    std::process::exit(1);
                                }
                            };
                            let dest_path = Path::new(&dest_path_str);
                            let final_dest_path = if dest_path.is_dir() {
                                dest_path.join(source_file_name)
                            } else {
                                dest_path.to_path_buf()
                            };

                            download(&source_addr, port_range, &dest_path_str, final_dest_path);
                        }
                    }
                }
            }

        }
    }
}
<commit_msg>i am dumb<commit_after>#[macro_use]
extern crate log;
extern crate getopts;
#[macro_use]
extern crate shoop;

use std::str;
use std::env;
use std::path::Path;
use getopts::Options;
use shoop::{ShoopLogger, ShoopMode, Server, download};
use shoop::connection::PortRange;

const VERSION: &'static str = env!("CARGO_PKG_VERSION");
const DEFAULT_PORT_RANGE: &'static str = "55000-55050";

fn print_usage(program: &str, opts: Options) {
    let brief = format!("Shoop is a ultrafast, (hopefully) secure file transfer tool, that is
(hopefully) ideal for transferring large files.

Usage: {0} [options] SOURCE DEST
...where HOST is an SSH host
...where PATH is the path on the *remote* machine of the file you want
...where DEST is either an existing folder or a location for the new
                 file (\".\" by default)

Example: {0} seedbox.facebook.com:/home/zuck/internalized_sadness.zip .",
                        program);
    print!("{}", opts.usage(&brief));
}

enum Target {
    Local(String),
    Remote(String, String),
}

impl Target {
    fn from(s: String) -> Target {
        match s.find(':') {
            None => Target::Local(s),
            Some(i) => {
                let owned = s.to_owned();
                let (first, second) = owned.split_at(i);
                if first.contains('/') {
                    Target::Local(s)
                } else {
                    Target::Remote(String::from(first), String::from(second))
                }
            }
        }
    }
}

fn main() {
    let args: Vec<String> = env::args().collect();
    let program = args[0].clone();
    let mut opts = Options::new();
    // TODO
    // opts.optopt("o", "output", "set output file name", "NAME");
    // opts.optopt("a", "ssh-args", "arguments to pass to ssh directly (at your own risk)", ARGS);
    opts.optopt("p",
                "port-range",
                "server listening port range",
                DEFAULT_PORT_RANGE);
    opts.optflag("s", "server", "server mode (advanced usage only)");
    opts.optflag("h", "help", "print this help menu");
    opts.optflag("v", "version", "print the version");

    let matches = match opts.parse(&args[1..]) {
        Ok(m) => m,
        Err(f) => panic!(f.to_string()),
    };

    if matches.opt_present("h") {
        print_usage(&program, opts);
        return;
    }

    if matches.opt_present("v") {
        println!("shoop {}", VERSION);
        return;
    }

    let source = if !matches.free.is_empty() {
        matches.free[0].clone()
    } else {
        print_usage(&program, opts);
        return;
    };

    let mode = if matches.opt_present("s") {
        ShoopMode::Server
    } else {
        ShoopMode::Client
    };

    let port_range = {
        let range_opt = &matches.opt_str("p").unwrap_or_else(|| String::from(DEFAULT_PORT_RANGE));
        PortRange::from(range_opt).unwrap()
    };

    ShoopLogger::init(mode).expect("Error starting shoop logger.");

    match mode {
        ShoopMode::Server => {
            if let Ok(server) = Server::new(port_range, &source) {
                server.start();
                info!("exiting.");
            }
        }
        ShoopMode::Client => {
            let dest = if matches.free.len() > 1 {
                matches.free[1].clone()
            } else {
                String::from(".")
            };

            match Target::from(source) {
                Target::Local(_) => error!("Sorry, you can only copy *from* a remote host currently."),
                Target::Remote(source_addr, source_path_str) => {
                    match Target::from(dest) {
                        Target::Remote(_,_) => error!("Sorry, you can only copy to a local path currently."),
                        Target::Local(dest_path_str) => {
                            let source_path = Path::new(&source_path_str);
                            let source_file_name = match source_path.file_name() {
                                Some(s) => s,
                                None => {
                                    error!("The remote path specified doesn't look like a path to a file.");
                                    std::process::exit(1);
                                }
                            };
                            let dest_path = Path::new(&dest_path_str);
                            let final_dest_path = if dest_path.is_dir() {
                                dest_path.join(source_file_name)
                            } else {
                                dest_path.to_path_buf()
                            };

                            download(&source_addr, port_range, &source_path_str, final_dest_path);
                        }
                    }
                }
            }

        }
    }
}
<|endoftext|>


<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

#![feature(box_syntax)]
#![feature(link_args)]

#[macro_use]
extern crate log;

#[cfg(all(not(feature = "force-glutin"), target_os = "macos"))]
extern crate libc;
#[cfg(all(not(feature = "force-glutin"), target_os = "macos"))]
extern crate cocoa;
#[cfg(all(not(feature = "force-glutin"), target_os = "macos"))]
extern crate objc_foundation;
#[cfg(all(not(feature = "force-glutin"), target_os = "macos"))]
#[macro_use]
extern crate objc;

#[cfg(any(feature = "force-glutin", not(target_os = "macos")))]
extern crate glutin;
#[cfg(any(feature = "force-glutin", not(target_os = "macos")))]
extern crate winit;
#[cfg(any(feature = "force-glutin", not(target_os = "macos")))]
extern crate tinyfiledialogs;

extern crate gleam;
extern crate open;

mod app;
mod window;
mod view;
mod servo;
mod platform;
mod state;

use app::{App, AppEvent, AppCommand};
use window::{Window, WindowEvent, WindowCommand};
use view::ViewEvent;
use servo::ServoEvent;
use std::cell::RefCell;
use std::rc::Rc;
use std::env::args;
use servo::{Servo, ServoUrl, WebRenderDebugOption};

fn main() {

    let logs = platform::Logger::init();

    info!("starting");

    let app = App::new().unwrap();
    let window = app.create_window().unwrap();

    let view = Rc::new(window.create_view().unwrap());

    Servo::configure(App::get_resources_path().unwrap());

    let servo = {
        let geometry = view.get_geometry();
        let waker = window.create_event_loop_waker();
        Servo::new(geometry, view.clone(), waker)
    };

    let home_url = App::get_resources_path().unwrap().parent().unwrap().join("shell_resources").join("home.html");
    let home_url = ServoUrl::from_file_path(&home_url).unwrap().into_string();

    // Skip first argument (executable), and find the first
    // argument that doesn't start with `-`
    let url = args().skip(1).find(|arg| {
        !arg.starts_with("-")
    }).unwrap_or(home_url);

    let browser = servo.create_browser(&url);
    servo.select_browser(browser.id);

    let mut state = App::get_init_state();
    state.current_window_index = Some(0);
    state.windows.push(Window::get_init_state());
    state.windows[0].current_browser_index = Some(0);
    state.windows[0].browsers.push(browser);
    app.render(&state);
    // FIXME: no mut!
    window.render(&mut state.windows[0]);

    info!("Servo version: {}", servo.version());

    // Use a RefCell, otherwise the handle_events callback needs to be a FnMut, making things a bit hard
    // FIXME: do not use a RefCell
    let state = RefCell::new(state);

    let handle_events = || {

        let mut state = state.borrow_mut();

        // Loop until no events are available anymore.
        loop {

            let app_events = app.get_events();
            let win_events = window.get_events();
            let view_events = view.get_events();
            let servo_events = servo.get_events();

            if app_events.is_empty() &&
               win_events.is_empty() &&
               view_events.is_empty() &&
               servo_events.is_empty() {
                   break
            }

            // FIXME: it's really annoying we need this
            let mut force_sync = false;
            let mut ui_invalidated = false;

            for event in app_events {
                match event {
                    AppEvent::DidFinishLaunching => {
                        // FIXME: does this work?
                    }
                    AppEvent::WillTerminate => {
                        // FIXME: does this work?
                    }
                    AppEvent::DidChangeScreenParameters => {
                        // FIXME: does this work?
                        servo.update_geometry(view.get_geometry());
                        view.update_drawable();
                    }
                    AppEvent::DoCommand(cmd) => {
                        match cmd {
                            AppCommand::ClearHistory => {
                                // FIXME
                            }
                            AppCommand::ToggleOptionDarkTheme => {
                                state.dark_theme = !state.dark_theme;
                                ui_invalidated = true;
                            }
                        }
                    }
                }
            }

            for event in win_events {
                match event {
                    WindowEvent::EventLoopAwaken => {
                        force_sync = true;
                    }
                    WindowEvent::GeometryDidChange => {
                        servo.update_geometry(view.get_geometry());
                        view.update_drawable();
                    }
                    WindowEvent::DidEnterFullScreen => {
                        // FIXME
                    }
                    WindowEvent::DidExitFullScreen => {
                        // FIXME
                    }
                    WindowEvent::WillClose => {
                        // FIXME
                    }
                    WindowEvent::OptionsClosed => {
                        state.windows[0].options_open = false;
                    }
                    WindowEvent::UrlbarFocusChanged(focused) => {
                        state.windows[0].urlbar_focused = focused;
                    }
                    WindowEvent::DoCommand(cmd) => {
                        let idx = state.windows[0].current_browser_index.unwrap();
                        let bid = state.windows[0].browsers[idx].id;
                        match cmd {
                            WindowCommand::Stop => {
                                // FIXME
                            }
                            WindowCommand::Reload => {
                                servo.reload(bid);
                            }
                            WindowCommand::NavigateBack => {
                                servo.go_back(bid);
                            }
                            WindowCommand::NavigateForward => {
                                servo.go_forward(bid);
                            }
                            WindowCommand::OpenLocation => {
                                state.windows[0].urlbar_focused = true;
                                ui_invalidated = true;
                            }
                            WindowCommand::OpenInDefaultBrowser => {
                                if let Some(ref url) = state.windows[0].browsers[idx].url {
                                    open::that(url.clone()).ok();
                                }
                            }
                            WindowCommand::ZoomIn => {
                                ui_invalidated = true;
                                state.windows[0].browsers[idx].zoom *= 1.1;
                                servo.zoom(state.windows[0].browsers[idx].zoom);
                            }
                            WindowCommand::ZoomOut => {
                                ui_invalidated = true;
                                state.windows[0].browsers[idx].zoom /= 1.1;
                                servo.zoom(state.windows[0].browsers[idx].zoom);
                            }
                            WindowCommand::ZoomToActualSize => {
                                ui_invalidated = true;
                                state.windows[0].browsers[idx].zoom = 1.0;
                                servo.reset_zoom();
                            }

                            WindowCommand::ToggleSidebar => {
                                state.windows[0].sidebar_is_open = !state.windows[0].sidebar_is_open;
                                ui_invalidated = true;
                            }

                            WindowCommand::ShowOptions => {
                                state.windows[0].options_open = !state.windows[0].options_open;
                                ui_invalidated = true;
                            }

                            WindowCommand::Load(request) => {
                                state.windows[0].browsers[idx].user_input = Some(request.clone());
                                state.windows[0].urlbar_focused = false;
                                let url = ServoUrl::parse(&request).or_else(|error| {
                                    // FIXME: weak
                                    if request.ends_with(".com") || request.ends_with(".org") || request.ends_with(".net") {
                                        ServoUrl::parse(&format!("http://{}", request))
                                    } else {
                                        Err(error)
                                    }
                                }).or_else(|_| {
                                    ServoUrl::parse(&format!("https://duckduckgo.com/html/?q={}", request))
                                });
                                match url {
                                    Ok(url) => {
                                        servo.load_url(bid, url)
                                    },
                                    Err(err) => warn!("Can't parse url: {}", err),
                                }
                            }
                            WindowCommand::ToggleOptionShowLogs => {
                                state.windows[0].logs_visible = !state.windows[0].logs_visible;
                                ui_invalidated = true;
                            },
                            WindowCommand::NewTab => {
                                let browser = servo.create_browser("about:blank");
                                servo.select_browser(browser.id);
                                servo.update_geometry(view.get_geometry());
                                state.windows[0].current_browser_index = Some(idx + 1);
                                state.windows[0].browsers.push(browser);
                                ui_invalidated = true;
                            },
                            WindowCommand::CloseTab => {
                                if state.windows[0].browsers.len() > 1 {
                                    let id = state.windows[0].browsers[idx].id;
                                    let new_id = if idx == state.windows[0].browsers.len() - 1 {
                                        state.windows[0].current_browser_index = Some(idx - 1);
                                        state.windows[0].browsers[idx - 1].id
                                    } else {
                                        state.windows[0].browsers[idx + 1].id
                                    };
                                    servo.select_browser(new_id);
                                    servo.close_browser(id);
                                    state.windows[0].browsers.remove(idx);
                                    ui_invalidated = true;
                                }
                            },
                            WindowCommand::PrevTab => {
                                let new_idx = if idx == 0 {
                                    state.windows[0].browsers.len() - 1
                                } else {
                                    idx - 1
                                };
                                state.windows[0].current_browser_index = Some(new_idx);
                                let id = state.windows[0].browsers[new_idx].id;
                                servo.select_browser(id);
                                ui_invalidated = true;
                            },
                            WindowCommand::NextTab => {
                                let new_idx = if idx == state.windows[0].browsers.len() - 1 {
                                    0
                                } else {
                                    idx + 1
                                };
                                state.windows[0].current_browser_index = Some(new_idx);
                                let id = state.windows[0].browsers[new_idx].id;
                                servo.select_browser(id);
                                ui_invalidated = true;
                            },
                            WindowCommand::SelectTab(idx) => {
                                if state.windows[0].current_browser_index != Some(idx) {
                                    state.windows[0].current_browser_index = Some(idx);
                                    let id = state.windows[0].browsers[idx].id;
                                    servo.select_browser(id);
                                    ui_invalidated = true;
                                }
                            },
                            WindowCommand::ToggleOptionFragmentBorders => { },
                            WindowCommand::ToggleOptionParallelDisplayListBuidling => { },
                            WindowCommand::ToggleOptionShowParallelLayout => { },
                            WindowCommand::ToggleOptionConvertMouseToTouch => { },
                            WindowCommand::ToggleOptionTileBorders => { },

                            WindowCommand::ToggleOptionWRProfiler => {
                                state.windows[0].debug_options.wr_profiler = !state.windows[0].debug_options.wr_profiler;
                                servo.toggle_webrender_debug_option(WebRenderDebugOption::Profiler);
                            },

                            WindowCommand::ToggleOptionWRTextureCacheDebug => {
                                state.windows[0].debug_options.wr_texture_cache_debug = !state.windows[0].debug_options.wr_texture_cache_debug;
                                servo.toggle_webrender_debug_option(WebRenderDebugOption::TextureCacheDebug);
                            },

                            WindowCommand::ToggleOptionWRTargetDebug => {
                                state.windows[0].debug_options.wr_render_target_debug = !state.windows[0].debug_options.wr_render_target_debug;
                                servo.toggle_webrender_debug_option(WebRenderDebugOption::RenderTargetDebug);
                            },
                        }
                    }
                }
            }

            for event in view_events {
                let idx = state.windows[0].current_browser_index.unwrap();
                let state = &mut state.windows[0].browsers[idx];
                match event {
                    ViewEvent::GeometryDidChange => {
                        servo.update_geometry(view.get_geometry());
                        view.update_drawable();
                    }
                    ViewEvent::MouseWheel(delta, phase) => {
                        let (mut x, mut y) = match delta {
                            view::MouseScrollDelta::PixelDelta(x, y) => (x, y),
                            _ => (0.0, 0.0),
                        };
                        if y.abs() >= x.abs() { x = 0.0; } else { y = 0.0; }
                        servo.perform_scroll(0, 0, x, y, phase);
                    }
                    ViewEvent::MouseMoved(x, y) => {
                        state.last_mouse_point = (x, y);
                        servo.perform_mouse_move(x, y);
                    }
                    ViewEvent::MouseInput(element_state, button) => {
                        let (x, y) = state.last_mouse_point;
                        let (org_x, org_y) = state.last_mouse_down_point;
                        let last_mouse_down_button = state.last_mouse_down_button;
                        servo.perform_click(x, y, org_x, org_y, element_state, button, last_mouse_down_button);
                        state.last_mouse_down_point = (x, y);
                        if element_state == view::ElementState::Pressed {
                            state.last_mouse_down_button = Some(button);
                        }
                    }
                    ViewEvent::KeyEvent(c, key, keystate, modifiers) => {
                        servo.send_key(state.id, c, key, keystate, modifiers);
                    }
                }
            }

            for event in servo_events {
                match event {
                    ServoEvent::SetWindowInnerSize(..) => {
                        // ignore
                    }
                    ServoEvent::SetWindowPosition(..) => {
                        // ignore
                    }
                    ServoEvent::SetFullScreenState(fullscreen) => {
                        if fullscreen {
                            view.enter_fullscreen();
                        } else {
                            view.exit_fullscreen();
                        }
                    }
                    ServoEvent::TitleChanged(id, title) => {
                        match state.windows[0].browsers.iter_mut().find(|b| b.id == id) {
                            Some(browser) => {
                                browser.title = title;
                                ui_invalidated = true;
                            }
                            None => { /*FIXME*/ }
                        }
                    }
                    ServoEvent::StatusChanged(status) => {
                        state.windows[0].status = status;
                        ui_invalidated = true;
                    }
                    ServoEvent::LoadStart(id) => {
                        match state.windows[0].browsers.iter_mut().find(|b| b.id == id) {
                            Some(browser) => {
                                browser.is_loading = true;
                                ui_invalidated = true;
                            }
                            None => { /*FIXME*/ }
                        }
                    }
                    ServoEvent::LoadEnd(id) => {
                        match state.windows[0].browsers.iter_mut().find(|b| b.id == id) {
                            Some(browser) => {
                                browser.is_loading = false;
                                ui_invalidated = true;
                            }
                            None => { /*FIXME*/ }
                        }
                    }
                    ServoEvent::HeadParsed(..) => {
                        // FIXME
                    }
                    ServoEvent::HistoryChanged(id, entries, current) => {
                        match state.windows[0].browsers.iter_mut().find(|b| b.id == id) {
                            Some(browser) => {
                                let url = entries[current].url.to_string();
                                browser.url = Some(url);
                                browser.can_go_back = current > 0;
                                browser.can_go_forward = current < entries.len() - 1;
                                ui_invalidated = true;
                            }
                            None => { /*FIXME*/ }
                        }
                    }
                    ServoEvent::CursorChanged(cursor) => {
                        state.cursor = cursor;
                        ui_invalidated = true;
                    }
                    ServoEvent::FaviconChanged(..) => {
                        // FIXME
                    }
                    ServoEvent::Key(..) => {
                        // FIXME
                    }
                    ServoEvent::OpenInDefaultBrowser(url) => {
                        open::that(url).ok();
                    }
                }
            }

            if ui_invalidated {
                app.render(&state);
                window.render(&state.windows[0]);
            }

            servo.sync(force_sync);
        }

        // Here, only stuff that we know for sure won't trigger any
        // new events

        // FIXME: logs will grow until pulled
        if state.windows[0].logs_visible {
            window.append_logs(&logs.get_logs());
        }
    };

    view.set_live_resize_callback(&handle_events);

    app.run(handle_events);

}
<commit_msg>focus urlbar on new tab<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

#![feature(box_syntax)]
#![feature(link_args)]

#[macro_use]
extern crate log;

#[cfg(all(not(feature = "force-glutin"), target_os = "macos"))]
extern crate libc;
#[cfg(all(not(feature = "force-glutin"), target_os = "macos"))]
extern crate cocoa;
#[cfg(all(not(feature = "force-glutin"), target_os = "macos"))]
extern crate objc_foundation;
#[cfg(all(not(feature = "force-glutin"), target_os = "macos"))]
#[macro_use]
extern crate objc;

#[cfg(any(feature = "force-glutin", not(target_os = "macos")))]
extern crate glutin;
#[cfg(any(feature = "force-glutin", not(target_os = "macos")))]
extern crate winit;
#[cfg(any(feature = "force-glutin", not(target_os = "macos")))]
extern crate tinyfiledialogs;

extern crate gleam;
extern crate open;

mod app;
mod window;
mod view;
mod servo;
mod platform;
mod state;

use app::{App, AppEvent, AppCommand};
use window::{Window, WindowEvent, WindowCommand};
use view::ViewEvent;
use servo::ServoEvent;
use std::cell::RefCell;
use std::rc::Rc;
use std::env::args;
use servo::{Servo, ServoUrl, WebRenderDebugOption};

fn main() {

    let logs = platform::Logger::init();

    info!("starting");

    let app = App::new().unwrap();
    let window = app.create_window().unwrap();

    let view = Rc::new(window.create_view().unwrap());

    Servo::configure(App::get_resources_path().unwrap());

    let servo = {
        let geometry = view.get_geometry();
        let waker = window.create_event_loop_waker();
        Servo::new(geometry, view.clone(), waker)
    };

    let home_url = App::get_resources_path().unwrap().parent().unwrap().join("shell_resources").join("home.html");
    let home_url = ServoUrl::from_file_path(&home_url).unwrap().into_string();

    // Skip first argument (executable), and find the first
    // argument that doesn't start with `-`
    let url = args().skip(1).find(|arg| {
        !arg.starts_with("-")
    }).unwrap_or(home_url);

    let browser = servo.create_browser(&url);
    servo.select_browser(browser.id);

    let mut state = App::get_init_state();
    state.current_window_index = Some(0);
    state.windows.push(Window::get_init_state());
    state.windows[0].current_browser_index = Some(0);
    state.windows[0].browsers.push(browser);
    app.render(&state);
    // FIXME: no mut!
    window.render(&mut state.windows[0]);

    info!("Servo version: {}", servo.version());

    // Use a RefCell, otherwise the handle_events callback needs to be a FnMut, making things a bit hard
    // FIXME: do not use a RefCell
    let state = RefCell::new(state);

    let handle_events = || {

        let mut state = state.borrow_mut();

        // Loop until no events are available anymore.
        loop {

            let app_events = app.get_events();
            let win_events = window.get_events();
            let view_events = view.get_events();
            let servo_events = servo.get_events();

            if app_events.is_empty() &&
               win_events.is_empty() &&
               view_events.is_empty() &&
               servo_events.is_empty() {
                   break
            }

            // FIXME: it's really annoying we need this
            let mut force_sync = false;
            let mut ui_invalidated = false;

            for event in app_events {
                match event {
                    AppEvent::DidFinishLaunching => {
                        // FIXME: does this work?
                    }
                    AppEvent::WillTerminate => {
                        // FIXME: does this work?
                    }
                    AppEvent::DidChangeScreenParameters => {
                        // FIXME: does this work?
                        servo.update_geometry(view.get_geometry());
                        view.update_drawable();
                    }
                    AppEvent::DoCommand(cmd) => {
                        match cmd {
                            AppCommand::ClearHistory => {
                                // FIXME
                            }
                            AppCommand::ToggleOptionDarkTheme => {
                                state.dark_theme = !state.dark_theme;
                                ui_invalidated = true;
                            }
                        }
                    }
                }
            }

            for event in win_events {
                match event {
                    WindowEvent::EventLoopAwaken => {
                        force_sync = true;
                    }
                    WindowEvent::GeometryDidChange => {
                        servo.update_geometry(view.get_geometry());
                        view.update_drawable();
                    }
                    WindowEvent::DidEnterFullScreen => {
                        // FIXME
                    }
                    WindowEvent::DidExitFullScreen => {
                        // FIXME
                    }
                    WindowEvent::WillClose => {
                        // FIXME
                    }
                    WindowEvent::OptionsClosed => {
                        state.windows[0].options_open = false;
                    }
                    WindowEvent::UrlbarFocusChanged(focused) => {
                        state.windows[0].urlbar_focused = focused;
                    }
                    WindowEvent::DoCommand(cmd) => {
                        let idx = state.windows[0].current_browser_index.unwrap();
                        let bid = state.windows[0].browsers[idx].id;
                        match cmd {
                            WindowCommand::Stop => {
                                // FIXME
                            }
                            WindowCommand::Reload => {
                                servo.reload(bid);
                            }
                            WindowCommand::NavigateBack => {
                                servo.go_back(bid);
                            }
                            WindowCommand::NavigateForward => {
                                servo.go_forward(bid);
                            }
                            WindowCommand::OpenLocation => {
                                state.windows[0].urlbar_focused = true;
                                ui_invalidated = true;
                            }
                            WindowCommand::OpenInDefaultBrowser => {
                                if let Some(ref url) = state.windows[0].browsers[idx].url {
                                    open::that(url.clone()).ok();
                                }
                            }
                            WindowCommand::ZoomIn => {
                                ui_invalidated = true;
                                state.windows[0].browsers[idx].zoom *= 1.1;
                                servo.zoom(state.windows[0].browsers[idx].zoom);
                            }
                            WindowCommand::ZoomOut => {
                                ui_invalidated = true;
                                state.windows[0].browsers[idx].zoom /= 1.1;
                                servo.zoom(state.windows[0].browsers[idx].zoom);
                            }
                            WindowCommand::ZoomToActualSize => {
                                ui_invalidated = true;
                                state.windows[0].browsers[idx].zoom = 1.0;
                                servo.reset_zoom();
                            }

                            WindowCommand::ToggleSidebar => {
                                state.windows[0].sidebar_is_open = !state.windows[0].sidebar_is_open;
                                ui_invalidated = true;
                            }

                            WindowCommand::ShowOptions => {
                                state.windows[0].options_open = !state.windows[0].options_open;
                                ui_invalidated = true;
                            }

                            WindowCommand::Load(request) => {
                                state.windows[0].browsers[idx].user_input = Some(request.clone());
                                state.windows[0].urlbar_focused = false;
                                let url = ServoUrl::parse(&request).or_else(|error| {
                                    // FIXME: weak
                                    if request.ends_with(".com") || request.ends_with(".org") || request.ends_with(".net") {
                                        ServoUrl::parse(&format!("http://{}", request))
                                    } else {
                                        Err(error)
                                    }
                                }).or_else(|_| {
                                    ServoUrl::parse(&format!("https://duckduckgo.com/html/?q={}", request))
                                });
                                match url {
                                    Ok(url) => {
                                        servo.load_url(bid, url)
                                    },
                                    Err(err) => warn!("Can't parse url: {}", err),
                                }
                            }
                            WindowCommand::ToggleOptionShowLogs => {
                                state.windows[0].logs_visible = !state.windows[0].logs_visible;
                                ui_invalidated = true;
                            },
                            WindowCommand::NewTab => {
                                let browser = servo.create_browser("about:blank");
                                servo.select_browser(browser.id);
                                servo.update_geometry(view.get_geometry());
                                state.windows[0].current_browser_index = Some(idx + 1);
                                state.windows[0].browsers.push(browser);
                                state.windows[0].urlbar_focused = true;
                                ui_invalidated = true;
                            },
                            WindowCommand::CloseTab => {
                                if state.windows[0].browsers.len() > 1 {
                                    let id = state.windows[0].browsers[idx].id;
                                    let new_id = if idx == state.windows[0].browsers.len() - 1 {
                                        state.windows[0].current_browser_index = Some(idx - 1);
                                        state.windows[0].browsers[idx - 1].id
                                    } else {
                                        state.windows[0].browsers[idx + 1].id
                                    };
                                    servo.select_browser(new_id);
                                    servo.close_browser(id);
                                    state.windows[0].browsers.remove(idx);
                                    ui_invalidated = true;
                                }
                            },
                            WindowCommand::PrevTab => {
                                let new_idx = if idx == 0 {
                                    state.windows[0].browsers.len() - 1
                                } else {
                                    idx - 1
                                };
                                state.windows[0].current_browser_index = Some(new_idx);
                                let id = state.windows[0].browsers[new_idx].id;
                                servo.select_browser(id);
                                ui_invalidated = true;
                            },
                            WindowCommand::NextTab => {
                                let new_idx = if idx == state.windows[0].browsers.len() - 1 {
                                    0
                                } else {
                                    idx + 1
                                };
                                state.windows[0].current_browser_index = Some(new_idx);
                                let id = state.windows[0].browsers[new_idx].id;
                                servo.select_browser(id);
                                ui_invalidated = true;
                            },
                            WindowCommand::SelectTab(idx) => {
                                if state.windows[0].current_browser_index != Some(idx) {
                                    state.windows[0].current_browser_index = Some(idx);
                                    let id = state.windows[0].browsers[idx].id;
                                    servo.select_browser(id);
                                    ui_invalidated = true;
                                }
                            },
                            WindowCommand::ToggleOptionFragmentBorders => { },
                            WindowCommand::ToggleOptionParallelDisplayListBuidling => { },
                            WindowCommand::ToggleOptionShowParallelLayout => { },
                            WindowCommand::ToggleOptionConvertMouseToTouch => { },
                            WindowCommand::ToggleOptionTileBorders => { },

                            WindowCommand::ToggleOptionWRProfiler => {
                                state.windows[0].debug_options.wr_profiler = !state.windows[0].debug_options.wr_profiler;
                                servo.toggle_webrender_debug_option(WebRenderDebugOption::Profiler);
                            },

                            WindowCommand::ToggleOptionWRTextureCacheDebug => {
                                state.windows[0].debug_options.wr_texture_cache_debug = !state.windows[0].debug_options.wr_texture_cache_debug;
                                servo.toggle_webrender_debug_option(WebRenderDebugOption::TextureCacheDebug);
                            },

                            WindowCommand::ToggleOptionWRTargetDebug => {
                                state.windows[0].debug_options.wr_render_target_debug = !state.windows[0].debug_options.wr_render_target_debug;
                                servo.toggle_webrender_debug_option(WebRenderDebugOption::RenderTargetDebug);
                            },
                        }
                    }
                }
            }

            for event in view_events {
                let idx = state.windows[0].current_browser_index.unwrap();
                let state = &mut state.windows[0].browsers[idx];
                match event {
                    ViewEvent::GeometryDidChange => {
                        servo.update_geometry(view.get_geometry());
                        view.update_drawable();
                    }
                    ViewEvent::MouseWheel(delta, phase) => {
                        let (mut x, mut y) = match delta {
                            view::MouseScrollDelta::PixelDelta(x, y) => (x, y),
                            _ => (0.0, 0.0),
                        };
                        if y.abs() >= x.abs() { x = 0.0; } else { y = 0.0; }
                        servo.perform_scroll(0, 0, x, y, phase);
                    }
                    ViewEvent::MouseMoved(x, y) => {
                        state.last_mouse_point = (x, y);
                        servo.perform_mouse_move(x, y);
                    }
                    ViewEvent::MouseInput(element_state, button) => {
                        let (x, y) = state.last_mouse_point;
                        let (org_x, org_y) = state.last_mouse_down_point;
                        let last_mouse_down_button = state.last_mouse_down_button;
                        servo.perform_click(x, y, org_x, org_y, element_state, button, last_mouse_down_button);
                        state.last_mouse_down_point = (x, y);
                        if element_state == view::ElementState::Pressed {
                            state.last_mouse_down_button = Some(button);
                        }
                    }
                    ViewEvent::KeyEvent(c, key, keystate, modifiers) => {
                        servo.send_key(state.id, c, key, keystate, modifiers);
                    }
                }
            }

            for event in servo_events {
                match event {
                    ServoEvent::SetWindowInnerSize(..) => {
                        // ignore
                    }
                    ServoEvent::SetWindowPosition(..) => {
                        // ignore
                    }
                    ServoEvent::SetFullScreenState(fullscreen) => {
                        if fullscreen {
                            view.enter_fullscreen();
                        } else {
                            view.exit_fullscreen();
                        }
                    }
                    ServoEvent::TitleChanged(id, title) => {
                        match state.windows[0].browsers.iter_mut().find(|b| b.id == id) {
                            Some(browser) => {
                                browser.title = title;
                                ui_invalidated = true;
                            }
                            None => { /*FIXME*/ }
                        }
                    }
                    ServoEvent::StatusChanged(status) => {
                        state.windows[0].status = status;
                        ui_invalidated = true;
                    }
                    ServoEvent::LoadStart(id) => {
                        match state.windows[0].browsers.iter_mut().find(|b| b.id == id) {
                            Some(browser) => {
                                browser.is_loading = true;
                                ui_invalidated = true;
                            }
                            None => { /*FIXME*/ }
                        }
                    }
                    ServoEvent::LoadEnd(id) => {
                        match state.windows[0].browsers.iter_mut().find(|b| b.id == id) {
                            Some(browser) => {
                                browser.is_loading = false;
                                ui_invalidated = true;
                            }
                            None => { /*FIXME*/ }
                        }
                    }
                    ServoEvent::HeadParsed(..) => {
                        // FIXME
                    }
                    ServoEvent::HistoryChanged(id, entries, current) => {
                        match state.windows[0].browsers.iter_mut().find(|b| b.id == id) {
                            Some(browser) => {
                                let url = entries[current].url.to_string();
                                browser.url = Some(url);
                                browser.can_go_back = current > 0;
                                browser.can_go_forward = current < entries.len() - 1;
                                ui_invalidated = true;
                            }
                            None => { /*FIXME*/ }
                        }
                    }
                    ServoEvent::CursorChanged(cursor) => {
                        state.cursor = cursor;
                        ui_invalidated = true;
                    }
                    ServoEvent::FaviconChanged(..) => {
                        // FIXME
                    }
                    ServoEvent::Key(..) => {
                        // FIXME
                    }
                    ServoEvent::OpenInDefaultBrowser(url) => {
                        open::that(url).ok();
                    }
                }
            }

            if ui_invalidated {
                app.render(&state);
                window.render(&state.windows[0]);
            }

            servo.sync(force_sync);
        }

        // Here, only stuff that we know for sure won't trigger any
        // new events

        // FIXME: logs will grow until pulled
        if state.windows[0].logs_visible {
            window.append_logs(&logs.get_logs());
        }
    };

    view.set_live_resize_callback(&handle_events);

    app.run(handle_events);

}
<|endoftext|>


<commit_before>extern crate evospinn;

use evospinn::*;
use std::ops::Range;

// From Optimierung-1/stimuli.txt

const SPIKES_INPUT_0: [float; 49] = [
    0.38, 3.38, 6.38, 9.38, 12.38, 15.38, 18.38,
    21.38, 24.38, 27.38, 30.38, 33.38, 36.38, 39.38,
    42.38, 45.38, 48.38, 52.98, 55.98, 58.98,
    61.98, 64.98, 67.98, 70.98, 73.98, 76.98, 79.98,
    82.98, 85.98, 88.98, 91.98, 94.98, 97.98,
    103.59, 106.59, 109.59, 112.59, 115.59, 118.59,
    121.59, 124.59, 127.59, 130.59, 133.59, 136.59, 139.59,
    142.59, 145.59, 148.59
];

const SPIKES_INPUT_1: [float; 49] = [
    1.0, 4.0, 7.0, 10.0, 13.0, 16.0, 19.0,
    22.0, 25.0, 28.0, 31.0, 34.0, 37.0,
    40.0, 43.0, 46.0, 49.0, 53.0, 56.0, 59.0,
    62.0, 65.0, 68.0, 71.0, 74.0, 77.0,
    80.0, 83.0, 86.0, 89.0, 92.0, 95.0, 98.0,
    103.0, 106.0, 109.0, 112.0, 115.0, 118.0,
    121.0, 124.0, 127.0, 130.0, 133.0, 136.0, 139.0,
    142.0, 145.0, 148.0
];

#[derive(Debug)]
struct FitnessRecorder {
    total_fires:    usize,
    correct_fires:  usize,
    correct_ranges: Vec<(NeuronId, Range<time>)>
}

impl FitnessRecorder {
    fn new() -> FitnessRecorder {
        FitnessRecorder {
            total_fires: 0,
            correct_fires: 0,
            correct_ranges: vec!(),
        }
    }

    fn add_correct_range(&mut self, neuron_id: NeuronId, range: Range<time>) {
        self.correct_ranges.push((neuron_id, range));
    }
}

impl Recorder for FitnessRecorder {
    fn record_fire(&mut self, timestamp: time, neuron_id: NeuronId) {
        for &(nid, ref range) in self.correct_ranges.iter() {
            if nid == neuron_id {
                self.total_fires += 1;
                if timestamp >= range.start && timestamp < range.end {
                    self.correct_fires += 1;
                }
            }
        }
    }
}

fn main() {
    let mut net = Net::new();

    let input_neuron_template = NeuronConfig {
        arp: ms(0),
        tau_m: ms(0),
        tau_r: 0.0,
        weight_r: 0.0,
        threshold: 0.0,
        record: Some("input"),
    };
    let output_neuron_template = NeuronConfig {
        arp: ms(0),
        tau_m: ms(0),
        tau_r: 0.0,
        weight_r: 0.0,
        threshold: 0.609375,
        record: Some("output"),
    };

    let cfg_input0 = net.create_neuron_config(NeuronConfig {
        record: Some("input0"),
        ..input_neuron_template
    });
    let cfg_input1 = net.create_neuron_config(NeuronConfig {
        record: Some("input1"),
        ..input_neuron_template
    });
    let cfg_output0 = net.create_neuron_config(NeuronConfig {
        record: Some("output0"),
        ..output_neuron_template
    });
    let cfg_output1 = net.create_neuron_config(NeuronConfig {
        record: Some("output1"),
        ..output_neuron_template
    });
    let cfg_output2 = net.create_neuron_config(NeuronConfig {
        record: Some("output2"),
        ..output_neuron_template
    });
    let cfg_innerinp = net.create_neuron_config(NeuronConfig {
        arp: ms(1),
        tau_m: ms(0),
        tau_r: 0.0,
        weight_r: 0.0,
        threshold: 0.59375,
        record: None,
    });
    // Koinzidenz neurons
    let cfg_k = net.create_neuron_config(NeuronConfig {
        arp: us(500), // 0.5 ms = 500 us
        tau_m: ns(46_875),
        tau_r: 0.0,
        weight_r: 0.0,
        threshold: 1.09375,
        record: None,
    });

    let n_input0 = net.create_neuron(cfg_input0);
    let n_input1 = net.create_neuron(cfg_input1);
    let n_output0 = net.create_neuron(cfg_output0);
    let n_output1 = net.create_neuron(cfg_output1);
    let n_output2 = net.create_neuron(cfg_output2);
    let n_innerinp0 = net.create_neuron(cfg_innerinp);
    let n_innerinp1 = net.create_neuron(cfg_innerinp);
    let n_k0 = net.create_neuron(cfg_k);
    let n_k1 = net.create_neuron(cfg_k);
    let n_k2 = net.create_neuron(cfg_k);

    let mut fitness = Box::new(FitnessRecorder::new());
    fitness.add_correct_range(n_output0, ms(0) .. ms(47));
    fitness.add_correct_range(n_output1, ms(47) .. ms(100));
    fitness.add_correct_range(n_output2, ms(100) .. ms(170));

    net.set_recorder(Some(fitness));

    net.create_synapse(n_input0, Synapse {delay: us(0), weight: 1.0, post_neuron: n_innerinp0});
    net.create_synapse(n_input1, Synapse {delay: us(0), weight: 1.0, post_neuron: n_innerinp1});
    net.create_synapse(n_k0, Synapse {delay: us(0), weight: 1.0, post_neuron: n_output0});
    net.create_synapse(n_k1, Synapse {delay: us(0), weight: 1.0, post_neuron: n_output1});
    net.create_synapse(n_k2, Synapse {delay: us(0), weight: 1.0, post_neuron: n_output2});

    net.create_synapse(n_innerinp0, Synapse {delay: us(625), weight: 1.0, post_neuron: n_k0});
    net.create_synapse(n_innerinp0, Synapse {delay: ns(15_625), weight: 1.0, post_neuron: n_k1});
    net.create_synapse(n_innerinp0, Synapse {delay: us(0), weight: 1.0, post_neuron: n_k2});

    net.create_synapse(n_innerinp1, Synapse {delay: us(0), weight: 1.0, post_neuron: n_k0});
    net.create_synapse(n_innerinp1, Synapse {delay: us(0), weight: 1.0, post_neuron: n_k1});
    net.create_synapse(n_innerinp1, Synapse {delay: ns(593_750), weight: 1.0, post_neuron: n_k2});

    net.add_spike_train_float_ms(n_input0, 1.0, &SPIKES_INPUT_0);
    net.add_spike_train_float_ms(n_input1, 1.0, &SPIKES_INPUT_1);

    net.simulate();

    println!("{:?}", net.get_recorder());
}
<commit_msg>Print out classification rate<commit_after>extern crate evospinn;

use evospinn::*;
use std::ops::Range;

// From Optimierung-1/stimuli.txt

const SPIKES_INPUT_0: [float; 49] = [
    0.38, 3.38, 6.38, 9.38, 12.38, 15.38, 18.38,
    21.38, 24.38, 27.38, 30.38, 33.38, 36.38, 39.38,
    42.38, 45.38, 48.38, 52.98, 55.98, 58.98,
    61.98, 64.98, 67.98, 70.98, 73.98, 76.98, 79.98,
    82.98, 85.98, 88.98, 91.98, 94.98, 97.98,
    103.59, 106.59, 109.59, 112.59, 115.59, 118.59,
    121.59, 124.59, 127.59, 130.59, 133.59, 136.59, 139.59,
    142.59, 145.59, 148.59
];

const SPIKES_INPUT_1: [float; 49] = [
    1.0, 4.0, 7.0, 10.0, 13.0, 16.0, 19.0,
    22.0, 25.0, 28.0, 31.0, 34.0, 37.0,
    40.0, 43.0, 46.0, 49.0, 53.0, 56.0, 59.0,
    62.0, 65.0, 68.0, 71.0, 74.0, 77.0,
    80.0, 83.0, 86.0, 89.0, 92.0, 95.0, 98.0,
    103.0, 106.0, 109.0, 112.0, 115.0, 118.0,
    121.0, 124.0, 127.0, 130.0, 133.0, 136.0, 139.0,
    142.0, 145.0, 148.0
];

#[derive(Debug)]
struct FitnessRecorder {
    total_fires:    usize,
    correct_fires:  usize,
    correct_ranges: Vec<(NeuronId, Range<time>)>
}

impl FitnessRecorder {
    fn new() -> FitnessRecorder {
        FitnessRecorder {
            total_fires: 0,
            correct_fires: 0,
            correct_ranges: vec!(),
        }
    }

    fn add_correct_range(&mut self, neuron_id: NeuronId, range: Range<time>) {
        self.correct_ranges.push((neuron_id, range));
    }

    fn classification_rate(&self) -> f64 {
        (self.correct_fires as f64) / (self.total_fires as f64)
    }
}

impl Recorder for FitnessRecorder {
    fn record_fire(&mut self, timestamp: time, neuron_id: NeuronId) {
        for &(nid, ref range) in self.correct_ranges.iter() {
            if nid == neuron_id {
                self.total_fires += 1;
                if timestamp >= range.start && timestamp < range.end {
                    self.correct_fires += 1;
                }
            }
        }
    }
}

fn main() {
    let mut net = Net::new();

    let input_neuron_template = NeuronConfig {
        arp: ms(0),
        tau_m: ms(0),
        tau_r: 0.0,
        weight_r: 0.0,
        threshold: 0.0,
        record: Some("input"),
    };
    let output_neuron_template = NeuronConfig {
        arp: ms(0),
        tau_m: ms(0),
        tau_r: 0.0,
        weight_r: 0.0,
        threshold: 0.609375,
        record: Some("output"),
    };

    let cfg_input0 = net.create_neuron_config(NeuronConfig {
        record: Some("input0"),
        ..input_neuron_template
    });
    let cfg_input1 = net.create_neuron_config(NeuronConfig {
        record: Some("input1"),
        ..input_neuron_template
    });
    let cfg_output0 = net.create_neuron_config(NeuronConfig {
        record: Some("output0"),
        ..output_neuron_template
    });
    let cfg_output1 = net.create_neuron_config(NeuronConfig {
        record: Some("output1"),
        ..output_neuron_template
    });
    let cfg_output2 = net.create_neuron_config(NeuronConfig {
        record: Some("output2"),
        ..output_neuron_template
    });
    let cfg_innerinp = net.create_neuron_config(NeuronConfig {
        arp: ms(1),
        tau_m: ms(0),
        tau_r: 0.0,
        weight_r: 0.0,
        threshold: 0.59375,
        record: None,
    });
    // Koinzidenz neurons
    let cfg_k = net.create_neuron_config(NeuronConfig {
        arp: us(500), // 0.5 ms = 500 us
        tau_m: ns(46_875),
        tau_r: 0.0,
        weight_r: 0.0,
        threshold: 1.09375,
        record: None,
    });

    let n_input0 = net.create_neuron(cfg_input0);
    let n_input1 = net.create_neuron(cfg_input1);
    let n_output0 = net.create_neuron(cfg_output0);
    let n_output1 = net.create_neuron(cfg_output1);
    let n_output2 = net.create_neuron(cfg_output2);
    let n_innerinp0 = net.create_neuron(cfg_innerinp);
    let n_innerinp1 = net.create_neuron(cfg_innerinp);
    let n_k0 = net.create_neuron(cfg_k);
    let n_k1 = net.create_neuron(cfg_k);
    let n_k2 = net.create_neuron(cfg_k);

    let mut fitness = Box::new(FitnessRecorder::new());
    fitness.add_correct_range(n_output0, ms(0) .. ms(47));
    fitness.add_correct_range(n_output1, ms(47) .. ms(100));
    fitness.add_correct_range(n_output2, ms(100) .. ms(170));

    net.set_recorder(Some(fitness));

    net.create_synapse(n_input0, Synapse {delay: us(0), weight: 1.0, post_neuron: n_innerinp0});
    net.create_synapse(n_input1, Synapse {delay: us(0), weight: 1.0, post_neuron: n_innerinp1});
    net.create_synapse(n_k0, Synapse {delay: us(0), weight: 1.0, post_neuron: n_output0});
    net.create_synapse(n_k1, Synapse {delay: us(0), weight: 1.0, post_neuron: n_output1});
    net.create_synapse(n_k2, Synapse {delay: us(0), weight: 1.0, post_neuron: n_output2});

    net.create_synapse(n_innerinp0, Synapse {delay: us(625), weight: 1.0, post_neuron: n_k0});
    net.create_synapse(n_innerinp0, Synapse {delay: ns(15_625), weight: 1.0, post_neuron: n_k1});
    net.create_synapse(n_innerinp0, Synapse {delay: us(0), weight: 1.0, post_neuron: n_k2});

    net.create_synapse(n_innerinp1, Synapse {delay: us(0), weight: 1.0, post_neuron: n_k0});
    net.create_synapse(n_innerinp1, Synapse {delay: us(0), weight: 1.0, post_neuron: n_k1});
    net.create_synapse(n_innerinp1, Synapse {delay: ns(593_750), weight: 1.0, post_neuron: n_k2});

    net.add_spike_train_float_ms(n_input0, 1.0, &SPIKES_INPUT_0);
    net.add_spike_train_float_ms(n_input1, 1.0, &SPIKES_INPUT_1);

    net.simulate();

    println!("Classification: {}", net.get_recorder().map(|r| r.classification_rate()).unwrap());
}
<|endoftext|>