<commit_before>// Unseemly is a "core" typed language with (typed!) macros.
// You shouldn't write code in Unseemly.
// Instead, you should implement your programming language as Unseemly macros.

#![allow(dead_code, unused_macros, non_snake_case, non_upper_case_globals, deprecated)]
// dead_code and unused_macros are hopefully temporary allowances
// non_snake_case is stylistic, so we can write `non__snake_case`.
// non_upper_case_globals is stylistic ... but maybe thread_locals really ought to be upper case.
// deprecated is temporary, until `Sky` replaces `EnvMBE` (and the deprecated calls are cleaned up)
#![recursion_limit = "128"] // Yikes.

// for testing; requires `cargo +nightly`
// #![feature(log_syntax, trace_macros)]
// trace_macros!(true);

// TODO: turn these into `use` statements in the appropriate places
#[macro_use]
extern crate custom_derive;

pub mod macros;

pub mod name; // should maybe be moved to `util`; `mbe` needs it

pub mod util;

pub mod alpha;
pub mod ast;
pub mod beta;
pub mod read;

pub mod earley;
pub mod grammar;
pub mod unparse;

pub mod form;

pub mod ast_walk;
pub mod expand;
pub mod ty;
pub mod ty_compare;
pub mod walk_mode;

pub mod runtime;

pub mod core_extra_forms;
pub mod core_forms;
pub mod core_macro_forms;
pub mod core_qq_forms;
pub mod core_type_forms;

pub mod highlighter_generation;

mod end_to_end__tests;

use crate::{
    ast::Ast,
    name::Name,
    runtime::eval::{eval, Value},
    util::assoc::Assoc,
};

use wasm_bindgen::prelude::*;

/// Everything you need to turn text into behavior.
#[derive(Clone)]
pub struct Language {
    pub pc: crate::earley::ParseContext,
    // TODO: how do these differ from the corresponding elements of `ParseContext`?
    //  Should we get rid of `Language` in favor of it???
    pub type_env: Assoc<Name, Ast>,
    pub type_env__phaseless: Assoc<Name, Ast>,
    pub value_env: Assoc<Name, Value>,
}

/// Generate Unseemly.
/// (This is the core language.)
pub fn unseemly() -> Language {
    Language {
        pc: crate::core_forms::outermost__parse_context(),
        type_env: crate::runtime::core_values::core_types(),
        type_env__phaseless: crate::runtime::core_values::core_types(),
        value_env: crate::runtime::core_values::core_values(),
    }
}

/// Run the file (which hopefully evaluates to `capture_language`), and get the language it defines.
/// Returns the parse context, the type environment, the phaseless version of the type environment,
///  and the value environment.
/// This doesn't take a language 4-tuple -- it assumes that the language is in Unseemly
///  (but of course it may do `include /[some_language.unseemly]/` itself).
/// TODO: we only need the phaselessness for macros, and maybe we can get rid of it there?
pub fn language_from_file(path: &std::path::Path) -> Language {
    let mut raw_lib = String::new();

    use std::io::Read;
    let orig_dir = std::env::current_dir().unwrap();
    std::fs::File::open(path)
        .expect("Error opening file")
        .read_to_string(&mut raw_lib)
        .expect("Error reading file");
    // Evaluate the file in its own directory:
    if let Some(dir) = path.parent() {
        // Might be empty:
        if dir.is_dir() {
            std::env::set_current_dir(dir).unwrap();
        }
    }

    let lang = get_language(&raw_lib, unseemly());

    // Go back to the original directory:
    std::env::set_current_dir(orig_dir).unwrap();

    return lang;
}

pub fn get_language(program: &str, lang: Language) -> Language {
    // TODO: I guess syntax extensions ought to return `Result`, too...
    let lib_ast = crate::grammar::parse(&core_forms::outermost_form(), lang.pc, &program).unwrap();
    let lib_typed = ast_walk::walk::<ty::SynthTy>(
        &lib_ast,
        &ast_walk::LazyWalkReses::new(lang.type_env, lang.type_env__phaseless, lib_ast.clone()),
    )
    .unwrap();
    let lib_expanded = crate::expand::expand(&lib_ast).unwrap();
    let lib_evaled = crate::runtime::eval::eval(&lib_expanded, lang.value_env).unwrap();
    let (new_pc, new__value_env) = if let Value::Sequence(mut lang_and_env) = lib_evaled {
        let env_value = lang_and_env.pop().unwrap();
        let lang_value = lang_and_env.pop().unwrap();
        let new_pc = match &*lang_value {
            Value::ParseContext(boxed_pc) => (**boxed_pc).clone(),
            _ => icp!("[type error] not a language"),
        };
        let new__value_env = if let Value::Struct(ref env) = *env_value {
            let mut new__value_env = Assoc::new();
            // We need to un-freshen the names that we're importing
            //  so they can actually be referred to.
            for (k, v) in env.iter_pairs() {
                new__value_env = new__value_env.set(k.unhygienic_orig(), v.clone())
            }
            new__value_env
        } else {
            icp!("[type error] Unexpected lib syntax structure: {:#?}", env_value)
        };
        (new_pc, new__value_env)
    } else {
        icp!("[type error] Unexpected lib syntax strucutre: {:#?}", lib_evaled);
    };

    node_let!(lib_typed => {Type tuple}
        lang_and_types *= component);
    node_let!(lang_and_types[1] => {Type struct}
        keys *= component_name, values *= component);

    let mut new__type_env = Assoc::<Name, Ast>::new();
    for (k, v) in keys.into_iter().zip(values.into_iter()) {
        // As above, unfreshen:
        new__type_env = new__type_env.set(k.to_name().unhygienic_orig(), v.clone());
    }

    // Do it again, to unpack the phaseless type environment:
    node_let!(lang_and_types[2] => {Type struct}
        pl_keys *= component_name, pl_values *= component);

    let mut new___type_env__phaseless = Assoc::<Name, Ast>::new();
    for (k, v) in pl_keys.into_iter().zip(pl_values.into_iter()) {
        // As above, unfreshen:
        new___type_env__phaseless =
            new___type_env__phaseless.set(k.to_name().unhygienic_orig(), v.clone());
    }

    Language {
        pc: new_pc,
        type_env: new__type_env,
        type_env__phaseless: new___type_env__phaseless,
        value_env: new__value_env,
    }
}

/// Evaluate a program written in some language.
/// The last four arguments match the values returned by `language_from_file`.
pub fn eval_program(program: &str, lang: Language) -> Result<Value, String> {
    // TODO: looks like `outermost_form` ought to be a property of `ParseContext`
    let ast: Ast = crate::grammar::parse(&core_forms::outermost_form(), lang.pc, program)
        .map_err(|e| e.msg)?;

    let _type = ast_walk::walk::<ty::SynthTy>(
        &ast,
        &ast_walk::LazyWalkReses::new(lang.type_env, lang.type_env__phaseless, ast.clone()),
    )
    .map_err(|e| format!("{}", e))?;

    let core_ast = crate::expand::expand(&ast).map_err(|_| "???".to_string())?;

    eval(&core_ast, lang.value_env).map_err(|_| "???".to_string())
}

/// Evaluate a program written in Unseemly.
/// Of course, it may immediately do `include /[something]/` to switch languages.
pub fn eval_unseemly_program_top(program: &str) -> Result<Value, String> {
    eval_program(program, unseemly())
}

/// Type program written in Unseemly.
/// Of course, it may immediately do `include /[something]/` to switch languages.
pub fn type_unseemly_program_top(program: &str) -> Result<Ast, String> {
    let unseemly = unseemly();
    let ast: Ast = crate::grammar::parse(&core_forms::outermost_form(), unseemly.pc, program)
        .map_err(|e| e.msg)?;

    ast_walk::walk::<ty::SynthTy>(
        &ast,
        &ast_walk::LazyWalkReses::new(unseemly.type_env, unseemly.type_env__phaseless, ast.clone()),
    )
    .map_err(|e| format!("{}", e))
}

/// Displays `res` on a color terminal.
pub fn terminal_display(res: Result<Value, String>) {
    match res {
        Ok(v) => println!("\x1b[1;32m≉\x1b[0m {}", v),
        Err(s) => println!("\x1b[1;31m✘\x1b[0m {}", s),
    }
}

fn html_render(res: Result<Value, String>) -> String {
    match res {
        Ok(v) => format!("{}", v),
        // HACK: codespan_reporting uses terminal escapes
        Err(s) => format!("
{}
", ansi_to_html::convert_escaped(&s).unwrap()),
    }
}

#[wasm_bindgen]
pub fn wasm_init() {
    #[cfg(target_arch = "wasm32")]
    std::panic::set_hook(Box::new(console_error_panic_hook::hook));
}

use std::iter::FromIterator;

thread_local! {
    static language_stash: std::cell::RefCell<std::collections::HashMap<String, Language>>
        = std::cell::RefCell::new(std::collections::HashMap::from_iter(
            vec![("unseemly".to_string(), unseemly())].into_iter()));
}

#[wasm_bindgen]
pub fn html__eval_program(program: &str, stashed_lang: &str) -> String {
    let lang: Language =
        language_stash.with(|ls| (*ls.borrow()).get(stashed_lang).unwrap().clone());
    html_render(eval_program(program, lang))
}

#[wasm_bindgen]
pub fn stash_lang(result_name: &str, program: &str, orig_stashed: &str) {
    let orig_lang = language_stash.with(|ls| (*ls.borrow()).get(orig_stashed).unwrap().clone());
    let new_lang = get_language(program, orig_lang);
    language_stash.with(|ls| ls.borrow_mut().insert(result_name.to_string(), new_lang));
}

#[wasm_bindgen]
pub fn generate__ace_rules(stashed_lang: &str) -> String {
    let rules = language_stash.with(|ls| {
        highlighter_generation::ace_rules(&(*ls.borrow()).get(stashed_lang).unwrap().pc.grammar)
    });
    format!(
        "start: [ {} // HACK: comments aren't part of the base language:
        {{ token: 'comment', regex: '#[^\\\\n|][^\\\\n]*|#\\\\|.*?\\\\|#' }}]",
        rules
    )
}

#[wasm_bindgen]
pub fn generate__ace_rules__for(program: &str, stashed_lang: &str) -> String {
    let lang = language_stash.with(|ls| (*ls.borrow()).get(stashed_lang).unwrap().clone());

    highlighter_generation::dynamic__ace_rules(program, &lang)
}
<commit_msg>Minor readability edits.<commit_after>// Unseemly is a "core" typed language with (typed!) macros.
// You shouldn't write code in Unseemly.
// Instead, you should implement your programming language as Unseemly macros.

#![allow(dead_code, unused_macros, non_snake_case, non_upper_case_globals, deprecated)]
// dead_code and unused_macros are hopefully temporary allowances
// non_snake_case is stylistic, so we can write `non__snake_case`.
// non_upper_case_globals is stylistic ... but maybe thread_locals really ought to be upper case.
// deprecated is temporary, until `Sky` replaces `EnvMBE` (and the deprecated calls are cleaned up)
#![recursion_limit = "128"] // Yikes.

// for testing; requires `cargo +nightly`
// #![feature(log_syntax, trace_macros)]
// trace_macros!(true);

// TODO: turn these into `use` statements in the appropriate places
#[macro_use]
extern crate custom_derive;

pub mod macros;

pub mod name; // should maybe be moved to `util`; `mbe` needs it

pub mod util;

pub mod alpha;
pub mod ast;
pub mod beta;
pub mod read;

pub mod earley;
pub mod grammar;
pub mod unparse;

pub mod form;

pub mod ast_walk;
pub mod expand;
pub mod ty;
pub mod ty_compare;
pub mod walk_mode;

pub mod runtime;

pub mod core_extra_forms;
pub mod core_forms;
pub mod core_macro_forms;
pub mod core_qq_forms;
pub mod core_type_forms;

pub mod highlighter_generation;

mod end_to_end__tests;

use crate::{
    ast::Ast,
    name::Name,
    runtime::eval::{eval, Value},
    util::assoc::Assoc,
};

use wasm_bindgen::prelude::*;

/// Everything you need to turn text into behavior.
#[derive(Clone)]
pub struct Language {
    pub pc: crate::earley::ParseContext,
    // TODO: how do these differ from the corresponding elements of `ParseContext`?
    //  Should we get rid of `Language` in favor of it???
    pub type_env: Assoc<Name, Ast>,
    pub type_env__phaseless: Assoc<Name, Ast>,
    pub value_env: Assoc<Name, Value>,
}

/// Generate Unseemly.
/// (This is the core language.)
pub fn unseemly() -> Language {
    Language {
        pc: crate::core_forms::outermost__parse_context(),
        type_env: crate::runtime::core_values::core_types(),
        type_env__phaseless: crate::runtime::core_values::core_types(),
        value_env: crate::runtime::core_values::core_values(),
    }
}

/// Run the file (which hopefully evaluates to `capture_language`), and get the language it defines.
/// Returns the parse context, the type environment, the phaseless version of the type environment,
///  and the value environment.
/// This doesn't take a language 4-tuple -- it assumes that the language is in Unseemly
///  (but of course it may do `include /[some_language.unseemly]/` itself).
/// TODO: we only need the phaselessness for macros, and maybe we can get rid of it there?
pub fn language_from_file(path: &std::path::Path) -> Language {
    let mut raw_lib = String::new();

    use std::io::Read;
    let orig_dir = std::env::current_dir().unwrap();
    std::fs::File::open(path)
        .expect("Error opening file")
        .read_to_string(&mut raw_lib)
        .expect("Error reading file");
    // Evaluate the file in its own directory:
    if let Some(dir) = path.parent() {
        // Might be empty:
        if dir.is_dir() {
            std::env::set_current_dir(dir).unwrap();
        }
    }

    let lang = get_language(&raw_lib, unseemly());

    // Go back to the original directory:
    std::env::set_current_dir(orig_dir).unwrap();

    return lang;
}

pub fn get_language(program: &str, lang: Language) -> Language {
    // TODO: I guess syntax extensions ought to return `Result`, too...
    let lib_ast = crate::grammar::parse(&core_forms::outermost_form(), lang.pc, &program).unwrap();
    let lib_typed = ast_walk::walk::<ty::SynthTy>(
        &lib_ast,
        &ast_walk::LazyWalkReses::new(lang.type_env, lang.type_env__phaseless, lib_ast.clone()),
    )
    .unwrap();
    let lib_expanded = crate::expand::expand(&lib_ast).unwrap();
    let lib_evaled = crate::runtime::eval::eval(&lib_expanded, lang.value_env).unwrap();
    let (new_pc, new__value_env) = if let Value::Sequence(mut lang_and_env) = lib_evaled {
        let env_value = lang_and_env.pop().unwrap();
        let lang_value = lang_and_env.pop().unwrap();
        let new_pc = match &*lang_value {
            Value::ParseContext(boxed_pc) => (**boxed_pc).clone(),
            _ => icp!("[type error] not a language"),
        };
        let new__value_env = if let Value::Struct(ref env) = *env_value {
            let mut new__value_env = Assoc::new();
            // We need to un-freshen the names that we're importing
            //  so they can actually be referred to.
            for (k, v) in env.iter_pairs() {
                new__value_env = new__value_env.set(k.unhygienic_orig(), v.clone())
            }
            new__value_env
        } else {
            icp!("[type error] Unexpected lib syntax structure: {:#?}", env_value)
        };
        (new_pc, new__value_env)
    } else {
        icp!("[type error] Unexpected lib syntax strucutre: {:#?}", lib_evaled);
    };

    node_let!(lib_typed => {Type tuple}
        lang_and_types *= component);
    node_let!(lang_and_types[1] => {Type struct}
        keys *= component_name, values *= component);

    let mut new__type_env = Assoc::<Name, Ast>::new();
    for (k, v) in keys.into_iter().zip(values.into_iter()) {
        // As above, unfreshen:
        new__type_env = new__type_env.set(k.to_name().unhygienic_orig(), v.clone());
    }

    // Do it again, to unpack the phaseless type environment:
    node_let!(lang_and_types[2] => {Type struct}
        pl_keys *= component_name, pl_values *= component);

    let mut new___type_env__phaseless = Assoc::<Name, Ast>::new();
    for (k, v) in pl_keys.into_iter().zip(pl_values.into_iter()) {
        // As above, unfreshen:
        new___type_env__phaseless =
            new___type_env__phaseless.set(k.to_name().unhygienic_orig(), v.clone());
    }

    Language {
        pc: new_pc,
        type_env: new__type_env,
        type_env__phaseless: new___type_env__phaseless,
        value_env: new__value_env,
    }
}

/// Evaluate a program written in some language.
pub fn eval_program(program: &str, lang: Language) -> Result<Value, String> {
    // TODO: looks like `outermost_form` ought to be a property of `ParseContext`
    let ast: Ast = crate::grammar::parse(&core_forms::outermost_form(), lang.pc, program)
        .map_err(|e| e.msg)?;

    let _type = ast_walk::walk::<ty::SynthTy>(
        &ast,
        &ast_walk::LazyWalkReses::new(lang.type_env, lang.type_env__phaseless, ast.clone()),
    )
    .map_err(|e| format!("{}", e))?;

    let core_ast = crate::expand::expand(&ast).map_err(|_| "???".to_string())?;

    eval(&core_ast, lang.value_env).map_err(|_| "???".to_string())
}

/// Evaluate a program written in Unseemly.
/// Of course, it may immediately do `include /[something]/` to switch languages.
pub fn eval_unseemly_program_top(program: &str) -> Result<Value, String> {
    eval_program(program, unseemly())
}

/// Type program written in Unseemly.
/// Of course, it may immediately do `include /[something]/` to switch languages.
pub fn type_unseemly_program_top(program: &str) -> Result<Ast, String> {
    let unseemly = unseemly();
    let ast: Ast = crate::grammar::parse(&core_forms::outermost_form(), unseemly.pc, program)
        .map_err(|e| e.msg)?;

    ast_walk::walk::<ty::SynthTy>(
        &ast,
        &ast_walk::LazyWalkReses::new(unseemly.type_env, unseemly.type_env__phaseless, ast.clone()),
    )
    .map_err(|e| format!("{}", e))
}

/// Displays `res` on a color terminal.
pub fn terminal_display(res: Result<Value, String>) {
    match res {
        Ok(v) => println!("\x1b[1;32m≉\x1b[0m {}", v),
        Err(s) => println!("\x1b[1;31m✘\x1b[0m {}", s),
    }
}

fn html_render(res: Result<Value, String>) -> String {
    match res {
        Ok(v) => format!("{}", v),
        // HACK: codespan_reporting uses terminal escapes
        Err(s) => format!("
{}
", ansi_to_html::convert_escaped(&s).unwrap()),
    }
}

#[wasm_bindgen]
pub fn wasm_init() {
    #[cfg(target_arch = "wasm32")]
    std::panic::set_hook(Box::new(console_error_panic_hook::hook));
}

use std::iter::FromIterator;

thread_local! {
    static language_stash: std::cell::RefCell<std::collections::HashMap<String, Language>>
        = std::cell::RefCell::new(std::collections::HashMap::from_iter(
            vec![("unseemly".to_string(), unseemly())].into_iter()));
}

#[wasm_bindgen]
pub fn html__eval_program(program: &str, stashed_lang: &str) -> String {
    let lang: Language =
        language_stash.with(|ls| (*ls.borrow()).get(stashed_lang).unwrap().clone());
    html_render(eval_program(program, lang))
}

#[wasm_bindgen]
pub fn stash_lang(result_name: &str, program: &str, lang_of_progam: &str) {
    let orig_lang = language_stash.with(|ls| (*ls.borrow()).get(lang_of_progam).unwrap().clone());
    let new_lang = get_language(program, orig_lang);
    language_stash.with(|ls| ls.borrow_mut().insert(result_name.to_string(), new_lang));
}

#[wasm_bindgen]
pub fn generate__ace_rules(stashed_lang: &str) -> String {
    let rules = language_stash.with(|ls| {
        highlighter_generation::ace_rules(&(*ls.borrow()).get(stashed_lang).unwrap().pc.grammar)
    });
    format!(
        "start: [ {} // HACK: comments aren't part of the base language:
        {{ token: 'comment', regex: '#[^\\\\n|][^\\\\n]*|#\\\\|.*?\\\\|#' }}]",
        rules
    )
}

#[wasm_bindgen]
pub fn generate__ace_rules__for(program: &str, stashed_lang: &str) -> String {
    let lang = language_stash.with(|ls| (*ls.borrow()).get(stashed_lang).unwrap().clone());

    highlighter_generation::dynamic__ace_rules(program, &lang)
}
<|endoftext|>


<commit_before>// Copyright 2015-2017 Intecture Developers. See the COPYRIGHT file at the
// top-level directory of this distribution and at
// https://intecture.io/COPYRIGHT.
//
// Licensed under the Mozilla Public License 2.0 <LICENSE or
// https://www.tldrlegal.com/l/mpl-2.0>. This file may not be copied,
// modified, or distributed except according to those terms.

extern crate chan;
extern crate chan_signal;
extern crate czmq;
extern crate docopt;
extern crate inapi;
extern crate inauth_client;
extern crate rustc_serialize;
extern crate serde;
#[macro_use]
extern crate serde_derive;
#[macro_use]
extern crate serde_json;
#[cfg(test)]
extern crate tempdir;
extern crate zdaemon;
extern crate zfilexfer;

mod api;
mod config;
mod error;

use chan_signal::Signal;
use config::Config;
use czmq::{ZCert, ZSock, SocketType, ZSys};
use docopt::Docopt;
use error::Result;
use inauth_client::{CertType, ZapHandler};
use std::{env, fs};
use std::io::Read;
use std::path::Path;
use std::process::exit;
use std::thread::spawn;
use zdaemon::Service;
use zfilexfer::Server as FileServer;

static USAGE: &'static str = "
Intecture Agent.

Usage:
  inagent [(-c <path> | --config <path>)]
  inagent (-h | --help)
  inagent --version

Options:
  -c --config <path>    Path to agent.json, e.g. \"/usr/local/etc\"
  -h --help             Show this screen.
  --version             Print this script's version.
";

#[derive(Debug, RustcDecodable)]
#[allow(non_snake_case)]
struct Args {
    flag_c: Option<String>,
    flag_config: Option<String>,
    flag_h: bool,
    flag_help: bool,
    flag_version: bool,
}

fn main() {
    let args: Args = Docopt::new(USAGE)
        .and_then(|d| d.decode())
        .unwrap_or_else(|e| e.exit());

    if args.flag_version {
        println!(env!("CARGO_PKG_VERSION"));
        exit(0);
    } else {
        let config_path = if args.flag_c.is_some() { args.flag_c.as_ref() } else { args.flag_config.as_ref() };
        if let Err(e) = start(config_path) {
            println!("{}", e);
            exit(1);
        }
    }
}

fn start<P: AsRef<Path>>(path: Option<P>) -> Result<()> {
    let signal = chan_signal::notify(&[Signal::INT, Signal::TERM]);
    let (parent, child) = try!(ZSys::create_pipe());
    parent.set_linger(0);
    parent.set_sndtimeo(Some(100));

    let config = read_conf(path)?;
    let server_cert = try!(ZCert::load(&config.server_cert));
    let auth_cert = try!(ZCert::load(&config.auth_cert));

    let _auth = ZapHandler::new(
        Some(CertType::User),
        &server_cert,
        &auth_cert,
        &config.auth_server,
        config.auth_update_port,
        false);

    let mut file_sock = ZSock::new(SocketType::ROUTER);
    server_cert.apply(&mut file_sock);
    file_sock.set_zap_domain("agent.intecture");
    file_sock.set_curve_server(true);
    file_sock.set_linger(1000);
    try!(file_sock.bind(&format!("tcp://*:{}", config.filexfer_port)));

    let thread = spawn(move || {
        let mut service = Service::new(child).unwrap();

        let api_endpoint = api::endpoint(config.api_port, &server_cert).unwrap();
        service.add_endpoint(api_endpoint).unwrap();

        let file_endpoint = FileServer::new(file_sock, config.filexfer_threads).unwrap();
        service.add_endpoint(file_endpoint).unwrap();

        service.start(None).unwrap();
    });

    // Wait for interrupt from system
    signal.recv().unwrap();

    // Terminate loop
    try!(parent.signal(1));
    thread.join().unwrap();

    Ok(())
}

fn read_conf<P: AsRef<Path>>(path: Option<P>) -> Result<Config> {
    if let Some(p) = path {
        do_read_conf(p)
    }
    else if let Ok(p) = env::var("INAGENT_CONFIG_DIR") {
        do_read_conf(p)
    }
    else if let Ok(c) = do_read_conf("/usr/local/etc/intecture") {
        Ok(c)
    } else {
        do_read_conf("/etc/intecture")
    }
}

fn do_read_conf<P: AsRef<Path>>(path: P) -> Result<Config> {
    let mut path = path.as_ref().to_owned();
    path.push("agent.json");

    let mut fh = fs::File::open(&path)?;
    let mut json = String::new();
    fh.read_to_string(&mut json)?;
    Ok(serde_json::from_str(&json)?)
}

#[cfg(test)]
mod tests {
    use std::{env, fs};
    use std::io::Write;
    use std::path::PathBuf;
    use super::read_conf;
    use tempdir::TempDir;

    #[test]
    fn test_read_conf() {
        let tmpdir = TempDir::new("test_read_conf").unwrap();
        let mut path = tmpdir.path().to_owned();

        path.push("agent.json");
        let mut fh = fs::File::create(&path).unwrap();
        fh.write_all(b"{
            \"api_port\": 123,
            \"server_cert\": \"\",
            \"filexfer_port\": 123,
            \"filexfer_threads\": 123,
            \"auth_server\": \"\",
            \"auth_update_port\": 123,
            \"auth_cert\": \"\"
        }").unwrap();
        path.pop();

        assert!(read_conf(Some(&path)).is_ok());
        env::set_var("INAGENT_CONFIG_DIR", path.to_str().unwrap());
        let none: Option<PathBuf> = None;
        assert!(read_conf(none).is_ok());
    }
}
<commit_msg>Remove superfluous macro_use attribute<commit_after>// Copyright 2015-2017 Intecture Developers. See the COPYRIGHT file at the
// top-level directory of this distribution and at
// https://intecture.io/COPYRIGHT.
//
// Licensed under the Mozilla Public License 2.0 <LICENSE or
// https://www.tldrlegal.com/l/mpl-2.0>. This file may not be copied,
// modified, or distributed except according to those terms.

extern crate chan;
extern crate chan_signal;
extern crate czmq;
extern crate docopt;
extern crate inapi;
extern crate inauth_client;
extern crate rustc_serialize;
extern crate serde;
#[macro_use]
extern crate serde_derive;
extern crate serde_json;
#[cfg(test)]
extern crate tempdir;
extern crate zdaemon;
extern crate zfilexfer;

mod api;
mod config;
mod error;

use chan_signal::Signal;
use config::Config;
use czmq::{ZCert, ZSock, SocketType, ZSys};
use docopt::Docopt;
use error::Result;
use inauth_client::{CertType, ZapHandler};
use std::{env, fs};
use std::io::Read;
use std::path::Path;
use std::process::exit;
use std::thread::spawn;
use zdaemon::Service;
use zfilexfer::Server as FileServer;

static USAGE: &'static str = "
Intecture Agent.

Usage:
  inagent [(-c <path> | --config <path>)]
  inagent (-h | --help)
  inagent --version

Options:
  -c --config <path>    Path to agent.json, e.g. \"/usr/local/etc\"
  -h --help             Show this screen.
  --version             Print this script's version.
";

#[derive(Debug, RustcDecodable)]
#[allow(non_snake_case)]
struct Args {
    flag_c: Option<String>,
    flag_config: Option<String>,
    flag_h: bool,
    flag_help: bool,
    flag_version: bool,
}

fn main() {
    let args: Args = Docopt::new(USAGE)
        .and_then(|d| d.decode())
        .unwrap_or_else(|e| e.exit());

    if args.flag_version {
        println!(env!("CARGO_PKG_VERSION"));
        exit(0);
    } else {
        let config_path = if args.flag_c.is_some() { args.flag_c.as_ref() } else { args.flag_config.as_ref() };
        if let Err(e) = start(config_path) {
            println!("{}", e);
            exit(1);
        }
    }
}

fn start<P: AsRef<Path>>(path: Option<P>) -> Result<()> {
    let signal = chan_signal::notify(&[Signal::INT, Signal::TERM]);
    let (parent, child) = try!(ZSys::create_pipe());
    parent.set_linger(0);
    parent.set_sndtimeo(Some(100));

    let config = read_conf(path)?;
    let server_cert = try!(ZCert::load(&config.server_cert));
    let auth_cert = try!(ZCert::load(&config.auth_cert));

    let _auth = ZapHandler::new(
        Some(CertType::User),
        &server_cert,
        &auth_cert,
        &config.auth_server,
        config.auth_update_port,
        false);

    let mut file_sock = ZSock::new(SocketType::ROUTER);
    server_cert.apply(&mut file_sock);
    file_sock.set_zap_domain("agent.intecture");
    file_sock.set_curve_server(true);
    file_sock.set_linger(1000);
    try!(file_sock.bind(&format!("tcp://*:{}", config.filexfer_port)));

    let thread = spawn(move || {
        let mut service = Service::new(child).unwrap();

        let api_endpoint = api::endpoint(config.api_port, &server_cert).unwrap();
        service.add_endpoint(api_endpoint).unwrap();

        let file_endpoint = FileServer::new(file_sock, config.filexfer_threads).unwrap();
        service.add_endpoint(file_endpoint).unwrap();

        service.start(None).unwrap();
    });

    // Wait for interrupt from system
    signal.recv().unwrap();

    // Terminate loop
    try!(parent.signal(1));
    thread.join().unwrap();

    Ok(())
}

fn read_conf<P: AsRef<Path>>(path: Option<P>) -> Result<Config> {
    if let Some(p) = path {
        do_read_conf(p)
    }
    else if let Ok(p) = env::var("INAGENT_CONFIG_DIR") {
        do_read_conf(p)
    }
    else if let Ok(c) = do_read_conf("/usr/local/etc/intecture") {
        Ok(c)
    } else {
        do_read_conf("/etc/intecture")
    }
}

fn do_read_conf<P: AsRef<Path>>(path: P) -> Result<Config> {
    let mut path = path.as_ref().to_owned();
    path.push("agent.json");

    let mut fh = fs::File::open(&path)?;
    let mut json = String::new();
    fh.read_to_string(&mut json)?;
    Ok(serde_json::from_str(&json)?)
}

#[cfg(test)]
mod tests {
    use std::{env, fs};
    use std::io::Write;
    use std::path::PathBuf;
    use super::read_conf;
    use tempdir::TempDir;

    #[test]
    fn test_read_conf() {
        let tmpdir = TempDir::new("test_read_conf").unwrap();
        let mut path = tmpdir.path().to_owned();

        path.push("agent.json");
        let mut fh = fs::File::create(&path).unwrap();
        fh.write_all(b"{
            \"api_port\": 123,
            \"server_cert\": \"\",
            \"filexfer_port\": 123,
            \"filexfer_threads\": 123,
            \"auth_server\": \"\",
            \"auth_update_port\": 123,
            \"auth_cert\": \"\"
        }").unwrap();
        path.pop();

        assert!(read_conf(Some(&path)).is_ok());
        env::set_var("INAGENT_CONFIG_DIR", path.to_str().unwrap());
        let none: Option<PathBuf> = None;
        assert!(read_conf(none).is_ok());
    }
}
<|endoftext|>


<commit_before>mod l0;

use l0::ast::{Atom, Program, Term, TopLevel, Var};
use l0::codegen::{compile_fact, compile_query};
use l0::machine::{MachineState};

use std::io::{self, Write};

fn print_instructions(program : &Program) {
    for instruction in program {
        println!("{:}", instruction);
    }
}

fn l0_repl<'a>() {
    let mut ms = MachineState::new();

    loop {
        print!("l0> ");
        io::stdout().flush();

        let mut buffer = String::new();
        io::stdin().read_line(&mut buffer).unwrap();

        let result = l0::l0_parser::parse_TopLevel(&*buffer);

        if &*buffer == "quit\n" {
            break;
        } else if &*buffer == "clear\n" {
            ms = MachineState::new();
        }

        match result {
            Ok(TopLevel::Fact(fact)) => {
                let program = compile_fact(&fact);

                ms = MachineState::new();
                ms.program = Some(program);

                println!("Program stored.");
            },
            Ok(TopLevel::Query(query)) => {
                if let Some(program) = ms.program.take() {
                    let query = compile_query(&query);

                    for instruction in &query {
                        ms.execute(instruction);
                    }

                    for instruction in &program {
                        ms.execute(instruction);

                        if ms.fail {
                            break;
                        }
                    }

                    if ms.fail {
                        println!("no");
                    } else {
                        println!("yes");
                    }

                    ms.reset_heap();
                    ms.program = Some(program);
                } else {
                    println!("No program to speak of.");
                }
            },
            Err(_) => println!("Grammatical error of some kind!"),
        };
    }
}

fn main() {
    l0_repl();
}
<commit_msg>remove unnecessary lifetime.<commit_after>mod l0;

use l0::ast::{Atom, Program, Term, TopLevel, Var};
use l0::codegen::{compile_fact, compile_query};
use l0::machine::{MachineState};

use std::io::{self, Write};

fn print_instructions(program : &Program) {
    for instruction in program {
        println!("{:}", instruction);
    }
}

fn l0_repl() {
    let mut ms = MachineState::new();

    loop {
        print!("l0> ");
        io::stdout().flush();

        let mut buffer = String::new();
        io::stdin().read_line(&mut buffer).unwrap();

        let result = l0::l0_parser::parse_TopLevel(&*buffer);

        if &*buffer == "quit\n" {
            break;
        } else if &*buffer == "clear\n" {
            ms = MachineState::new();
        }

        match result {
            Ok(TopLevel::Fact(fact)) => {
                let program = compile_fact(&fact);

                ms = MachineState::new();
                ms.program = Some(program);

                println!("Program stored.");
            },
            Ok(TopLevel::Query(query)) => {
                if let Some(program) = ms.program.take() {
                    let query = compile_query(&query);

                    for instruction in &query {
                        ms.execute(instruction);
                    }

                    for instruction in &program {
                        ms.execute(instruction);

                        if ms.fail {
                            break;
                        }
                    }

                    if ms.fail {
                        println!("no");
                    } else {
                        println!("yes");
                    }

                    ms.reset_heap();
                    ms.program = Some(program);
                } else {
                    println!("No program to speak of.");
                }
            },
            Err(_) => println!("Grammatical error of some kind!"),
        };
    }
}

fn main() {
    l0_repl();
}
<|endoftext|>


<commit_before>extern crate argparse;
extern crate walkdir;
#[macro_use] extern crate lazy_static;

use argparse::{ArgumentParser, Store, StoreOption, Print};
use std::io::BufReader;
use std::io::BufRead;
use std::fs::File;
use std::io::Write;
use walkdir::{DirEntry, WalkDir};

pub mod alt;

macro_rules! printerr(
    ($($arg:tt)*) => { {
        let r = writeln!(&mut ::std::io::stderr(), $($arg)*);
        r.expect("failed printing to stderr");
    } }
);

struct Options {
    path: String,
    file: Option<String>
}

fn is_hidden(entry: &DirEntry) -> bool {
    entry.file_name()
         .to_str()
         .map(|s| entry.depth() > 0 && s.starts_with("."))
         .unwrap_or(false)
}

fn get_possible_files() -> Vec<std::path::PathBuf> {
    WalkDir::new(".")
        .follow_links(true)
        .into_iter()
        .filter_entry(|e| !is_hidden(e))
        .filter_map(|direntry| {
            let entry = direntry.ok()?;
            if entry.file_type().is_file() {
                Some(entry.path().to_owned())
            }
            else {
                None
            }
        })
        .collect()
}

fn get_filename_minus_extension(path_str: &String) -> String {
    std::path::Path::new(path_str).file_stem().unwrap().to_str().unwrap().to_string()
}

fn cleanse_path(path: &str) -> String {
    let s = path.to_string();
    if s.len() > 1 && s[0..2].to_string() == "./" {
        s[2..].to_string()
    } else {
        s
    }
}

fn find_longest_common_substring_length(s1: &String, s2: &String) -> i32 {
    // Currently this is implemented using a dynamic programming solution similar
    // to http://www.geeksforgeeks.org/longest-common-substring/. This is O(N*M)
    // where N is the length of one string and M is the length of the other
    // string.
    //
    // Another option would of course be to explore using something like a
    // suffix tree to solve this problem, something like, the following.
    // http://www.geeksforgeeks.org/suffix-tree-application-5-longest-common-substring-2/
    // This is O(M+N) to build a Generalized Suffix Tree and O(M+N) to find the
    // the longest common substring via depth first search.
    //
    // Beyond that we would have to explore not caring about longest substring
    // and moving to a similarity ranking algorithm that maybe cares about
    // subsequences rather that substrings, etc.
    if s1.is_empty() || s2.is_empty() {
        return 0
    }

    let mut m: Vec<Vec<i32>> = Vec::with_capacity(s1.len());
    for _ in 0..s1.len() {
        let v: Vec<i32> = vec![0; s2.len()];
        m.push(v);
    }

    let mut longest_length = 0;

    let s1_bytes = s1.as_bytes();
    let s2_bytes = s2.as_bytes();

    for i in 0..s1.len() {
        for j in 0..s2.len() {
            if s1_bytes[i] == s2_bytes[j] {
                m[i][j] = 1;
                if i > 0 && j > 0 {
                    m[i][j] += m[i-1][j-1];
                }
                if m[i][j] > longest_length {
                    longest_length = m[i][j];
                }
            }
        }
    }

    longest_length
}

fn score(s1: &String, s2: &String) -> f32 {
    let longest_match_length: f32 = find_longest_common_substring_length(s1, s2) as f32;
    (longest_match_length/s2.len() as f32) * (longest_match_length/s1.len() as f32)
}

fn find_alt(filename: &String, cleansed_path: &String, paths: Vec<String>, test_file: bool) -> String {
    let (_, alternate) = paths.iter()
        .map(|path| cleanse_path(&path))
        .filter(|path| path.contains(filename.as_str()))  // filter to paths that contain the filename
        .filter(|path| alt::path::classification::is_test_file(&path) != test_file)
        .fold((0 as f32, "".to_string()), |result, path| {
            let (highest_score, best_match) = result;
            let s = score(&path, &cleansed_path);
            if s > highest_score {
                (s, path)
            } else {
                (highest_score, best_match)
            }
        });
    alternate
}

fn main() {
    let mut options = Options {
        path: "".to_string(),
        file: None
    };

    { // block limits of borrows by refer() method calls
        let mut ap = ArgumentParser::new();
        ap.add_option(&["-v", "--version"], Print(env!("CARGO_PKG_VERSION").to_string()), "show version");
        ap.refer(&mut options.file).add_option(&["-f", "--file"], StoreOption, "possible alternates file, - for stdin");
        ap.refer(&mut options.path).add_argument("PATH", Store, "path to find alternate for").required();
        ap.parse_args_or_exit();
    }

    let cleansed_path = cleanse_path(&options.path);
    let mut filename = get_filename_minus_extension(&options.path);
    if alt::path::classification::is_test_file(&cleansed_path) {
        filename = alt::path::alteration::strip_test_words(&filename);
    }

    let best_match = if let Some(unwrapped_file) = options.file {
        if unwrapped_file == "-" {
            let stdin = std::io::stdin();
            let paths: Vec<String> = stdin.lock().lines().map(|path| path.unwrap()).collect();
            find_alt(&filename, &cleansed_path, paths, alt::path::classification::is_test_file(&cleansed_path))
        } else {
            let f = match File::open(&unwrapped_file) {
                Ok(file) => file,
                Err(e) => {
                    printerr!("Failure occurred opening file {}, {}", &unwrapped_file, e);
                    std::process::exit(1)
                }
            };
            let file = BufReader::new(&f);
            let paths: Vec<String> = file.lines().map(|path| path.unwrap()).collect();
            find_alt(&filename, &cleansed_path, paths, alt::path::classification::is_test_file(&cleansed_path))
        }
    } else {
        let unwrapped_paths: Vec<String> = get_possible_files().iter().map(|path| { path.to_str().unwrap().to_string() }).collect();
        find_alt(&filename, &cleansed_path, unwrapped_paths, alt::path::classification::is_test_file(&cleansed_path))
    };
    print!("{}", best_match);
}

#[cfg(test)]
mod tests {
    use super::cleanse_path;
    use super::get_filename_minus_extension;

    #[test]
    fn cleanse_path_returns_path_with_dot_slash_prefix_stripped() {
        assert_eq!("hoopty/doopty.thing",cleanse_path("./hoopty/doopty.thing"));
    }

    #[test]
    fn cleanse_path_does_not_effect_non_dot_slash_prefixes() {
        assert_eq!("foo/hoopty/doopty.thing",cleanse_path("foo/hoopty/doopty.thing"));
    }

    #[test]
    fn get_filename_minus_extension_returns_the_filename_without_the_extension() {
        let s = String::from("foo/hoopty/doopty.thing");
        assert_eq!("doopty", get_filename_minus_extension(&s));
    }
}
<commit_msg>Rename Options.path to possible_alternates_path<commit_after>extern crate argparse;
extern crate walkdir;
#[macro_use] extern crate lazy_static;

use argparse::{ArgumentParser, Store, StoreOption, Print};
use std::io::BufReader;
use std::io::BufRead;
use std::fs::File;
use std::io::Write;
use walkdir::{DirEntry, WalkDir};

pub mod alt;

macro_rules! printerr(
    ($($arg:tt)*) => { {
        let r = writeln!(&mut ::std::io::stderr(), $($arg)*);
        r.expect("failed printing to stderr");
    } }
);

struct Options {
    path: String,
    possible_alternates_path: Option<String>
}

fn is_hidden(entry: &DirEntry) -> bool {
    entry.file_name()
         .to_str()
         .map(|s| entry.depth() > 0 && s.starts_with("."))
         .unwrap_or(false)
}

fn get_possible_files() -> Vec<std::path::PathBuf> {
    WalkDir::new(".")
        .follow_links(true)
        .into_iter()
        .filter_entry(|e| !is_hidden(e))
        .filter_map(|direntry| {
            let entry = direntry.ok()?;
            if entry.file_type().is_file() {
                Some(entry.path().to_owned())
            }
            else {
                None
            }
        })
        .collect()
}

fn get_filename_minus_extension(path_str: &String) -> String {
    std::path::Path::new(path_str).file_stem().unwrap().to_str().unwrap().to_string()
}

fn cleanse_path(path: &str) -> String {
    let s = path.to_string();
    if s.len() > 1 && s[0..2].to_string() == "./" {
        s[2..].to_string()
    } else {
        s
    }
}

fn find_longest_common_substring_length(s1: &String, s2: &String) -> i32 {
    // Currently this is implemented using a dynamic programming solution similar
    // to http://www.geeksforgeeks.org/longest-common-substring/. This is O(N*M)
    // where N is the length of one string and M is the length of the other
    // string.
    //
    // Another option would of course be to explore using something like a
    // suffix tree to solve this problem, something like, the following.
    // http://www.geeksforgeeks.org/suffix-tree-application-5-longest-common-substring-2/
    // This is O(M+N) to build a Generalized Suffix Tree and O(M+N) to find the
    // the longest common substring via depth first search.
    //
    // Beyond that we would have to explore not caring about longest substring
    // and moving to a similarity ranking algorithm that maybe cares about
    // subsequences rather that substrings, etc.
    if s1.is_empty() || s2.is_empty() {
        return 0
    }

    let mut m: Vec<Vec<i32>> = Vec::with_capacity(s1.len());
    for _ in 0..s1.len() {
        let v: Vec<i32> = vec![0; s2.len()];
        m.push(v);
    }

    let mut longest_length = 0;

    let s1_bytes = s1.as_bytes();
    let s2_bytes = s2.as_bytes();

    for i in 0..s1.len() {
        for j in 0..s2.len() {
            if s1_bytes[i] == s2_bytes[j] {
                m[i][j] = 1;
                if i > 0 && j > 0 {
                    m[i][j] += m[i-1][j-1];
                }
                if m[i][j] > longest_length {
                    longest_length = m[i][j];
                }
            }
        }
    }

    longest_length
}

fn score(s1: &String, s2: &String) -> f32 {
    let longest_match_length: f32 = find_longest_common_substring_length(s1, s2) as f32;
    (longest_match_length/s2.len() as f32) * (longest_match_length/s1.len() as f32)
}

fn find_alt(filename: &String, cleansed_path: &String, paths: Vec<String>, test_file: bool) -> String {
    let (_, alternate) = paths.iter()
        .map(|path| cleanse_path(&path))
        .filter(|path| path.contains(filename.as_str()))  // filter to paths that contain the filename
        .filter(|path| alt::path::classification::is_test_file(&path) != test_file)
        .fold((0 as f32, "".to_string()), |result, path| {
            let (highest_score, best_match) = result;
            let s = score(&path, &cleansed_path);
            if s > highest_score {
                (s, path)
            } else {
                (highest_score, best_match)
            }
        });
    alternate
}

fn main() {
    let mut options = Options {
        path: "".to_string(),
        possible_alternates_path: None
    };

    { // block limits of borrows by refer() method calls
        let mut ap = ArgumentParser::new();
        ap.add_option(&["-v", "--version"], Print(env!("CARGO_PKG_VERSION").to_string()), "show version");
        ap.refer(&mut options.possible_alternates_path).add_option(&["-f", "--file"], StoreOption, "possible alternates file, - for stdin");
        ap.refer(&mut options.path).add_argument("PATH", Store, "path to find alternate for").required();
        ap.parse_args_or_exit();
    }

    let cleansed_path = cleanse_path(&options.path);
    let mut filename = get_filename_minus_extension(&options.path);
    if alt::path::classification::is_test_file(&cleansed_path) {
        filename = alt::path::alteration::strip_test_words(&filename);
    }

    let best_match = if let Some(unwrapped_file) = options.possible_alternates_path {
        if unwrapped_file == "-" {
            let stdin = std::io::stdin();
            let paths: Vec<String> = stdin.lock().lines().map(|path| path.unwrap()).collect();
            find_alt(&filename, &cleansed_path, paths, alt::path::classification::is_test_file(&cleansed_path))
        } else {
            let f = match File::open(&unwrapped_file) {
                Ok(file) => file,
                Err(e) => {
                    printerr!("Failure occurred opening file {}, {}", &unwrapped_file, e);
                    std::process::exit(1)
                }
            };
            let file = BufReader::new(&f);
            let paths: Vec<String> = file.lines().map(|path| path.unwrap()).collect();
            find_alt(&filename, &cleansed_path, paths, alt::path::classification::is_test_file(&cleansed_path))
        }
    } else {
        let unwrapped_paths: Vec<String> = get_possible_files().iter().map(|path| { path.to_str().unwrap().to_string() }).collect();
        find_alt(&filename, &cleansed_path, unwrapped_paths, alt::path::classification::is_test_file(&cleansed_path))
    };
    print!("{}", best_match);
}

#[cfg(test)]
mod tests {
    use super::cleanse_path;
    use super::get_filename_minus_extension;

    #[test]
    fn cleanse_path_returns_path_with_dot_slash_prefix_stripped() {
        assert_eq!("hoopty/doopty.thing",cleanse_path("./hoopty/doopty.thing"));
    }

    #[test]
    fn cleanse_path_does_not_effect_non_dot_slash_prefixes() {
        assert_eq!("foo/hoopty/doopty.thing",cleanse_path("foo/hoopty/doopty.thing"));
    }

    #[test]
    fn get_filename_minus_extension_returns_the_filename_without_the_extension() {
        let s = String::from("foo/hoopty/doopty.thing");
        assert_eq!("doopty", get_filename_minus_extension(&s));
    }
}
<|endoftext|>


<commit_before>extern crate piston_window;
extern crate find_folder;
extern crate gfx_device_gl;
extern crate gfx_graphics;
extern crate gfx;
extern crate vecmath;
extern crate image as im;
extern crate time;

use piston_window::*;
use time::{Duration, PreciseTime};

mod creature;
mod player;
mod io;
mod level;
mod inventory;
mod item;
mod actor;
mod field;
mod interactable;
mod coord;
mod enums;
mod camera;

use camera::{Cam};
use player::{Player, LastKey};
use io::{ render_tile};
use io::tileset::{TILE_HEIGHT, TILE_WIDTH, Tileset};
use level::Level;

//EINGABEN
const TWO_PLAYER: bool = true;
const SPRITE_P_1: &'static str = "warrior2.png";
const SPRITE_P_2: &'static str = "paladin.png";
const CAMERA_BUF_X: u64 = 4;
const CAMERA_BUF_Y: u64 = 4;

const WIDTH: i64 = 1600;
const HEIGHT: i64 = 900;

const RED: [f32; 4] = [1.0, 0.0, 0.0, 1.0];
const BLACK: [f32; 4] = [0.0, 0.0, 0.0, 1.0];

pub struct App {
    player_one: Player,
    player_two: Option<Player>,
    cam: Cam,
}

impl App {
    fn new(two_player: bool) -> Self {
        App {
            // 0,0 Dummy-Value
            player_one: Player::new(0, 0),
            player_two: if two_player {
                // 0,0 Dummy-Value
                Some(Player::new(0, 0))
            } else {
                None
            },
            cam: Cam::new(CAMERA_BUF_X, CAMERA_BUF_Y),
        }
    }

    fn on_draw(&mut self,
               mut w: &mut PistonWindow,
               e: &Event,
               tileset: &Tileset,
               level: &mut Level) {
        let player_one = &self.player_one.creature;
        let player_two = &self.player_two;

        let range = self.cam.get_range();
        w.draw_2d(e, |c, gl| {
            // Clear the screen.
            clear(BLACK, gl);

            let center_lv = c.transform.trans(0.0, 0.0);

            //render_level(&tileset, gl, center_lv, &mut level);
            for (h, j) in (range.x_min..range.x_max).enumerate() {
                for (w, i) in (range.y_min..range.y_max).enumerate() {
                    let tile = match tileset.get_texture(level.get_data()[i as usize][j as usize].get_id()) {
                    Some(x) => x,
                    None => panic!("No texture found."),
                    };
                    // DEBUG
                    //println!("{} {}", i, j);
                    render_tile(&tile, gl, center_lv,  h as u32 * TILE_HEIGHT,
                            w as u32 * TILE_WIDTH,
                            w as u32,
                            h as u32);
                }
            }
            let center_p1 = c.transform.trans(((self.player_one.coord.get_x() - range.x_min )* 65) as f64,
                                              ((self.player_one.coord.get_y() - range.y_min)* 65) as f64);
            player_one.render(gl, center_p1);
            if let Some(ref p2) = *player_two {
                let center_p2 = c.transform.trans(((p2.coord.get_x() - range.x_min) * 65) as f64,

                                              ((p2.coord.get_y() - range.y_min )* 65) as f64);
                 p2.creature.render(gl, center_p2);

            }
        });
    }

    fn on_update(&mut self,
                 args: &UpdateArgs,) {
                let coord1 = self.player_one.coord.clone();
        let mut coord2 = coord1.clone();
        if let Some(ref p2) = self.player_two {
            coord2 = p2.coord.clone();
        }

                let range = self.cam.get_range_update();

        self.player_one.on_update(args, range);
        if let Some(ref mut x) = self.player_two {

            x.on_update(args, range);
        }
                self.cam.calc_coordinates(coord1, coord2);

    }

    fn on_input(&mut self, inp: Button, pressed: bool) {

        match inp {
            Button::Keyboard(Key::Up) => {
                if pressed {
                    self.player_one.last = LastKey::Up;
                }
                self.player_one.pressed = pressed;
            }
            Button::Keyboard(Key::Down) => {
                if pressed {
                    self.player_one.last = LastKey::Down;
                }
                self.player_one.pressed = pressed;
            }
            Button::Keyboard(Key::Left) => {
                if pressed {
                    self.player_one.last = LastKey::Left;
                }
                self.player_one.pressed = pressed;
            }
            Button::Keyboard(Key::Right) => {
                if pressed {
                    self.player_one.last = LastKey::Right;
                }
                self.player_one.pressed = pressed;
            }
            Button::Keyboard(Key::W) => {
                if let Some(ref mut x) = self.player_two {
                    if pressed {
                        x.last = LastKey::Up;
                    }
                    x.pressed = pressed;
                }
            }
            Button::Keyboard(Key::S) => {
                if let Some(ref mut x) = self.player_two {
                    if pressed {
                        x.last = LastKey::Down;
                    }
                    x.pressed = pressed;
                }
            }
            Button::Keyboard(Key::A) => {
                if let Some(ref mut x) = self.player_two {
                    if pressed {
                        x.last = LastKey::Left;
                    }
                    x.pressed = pressed;
                }
            }
            Button::Keyboard(Key::D) => {
                if let Some(ref mut x) = self.player_two {
                    if pressed {
                        x.last = LastKey::Right;
                    }
                    x.pressed = pressed;
                }
            }
            _ => {}

        }
    }
    fn on_load(&mut self, mut w: &mut PistonWindow) {
        let mut player_one = &mut self.player_one;
        App::load_sprite(w, &mut player_one, SPRITE_P_1);
        if let Some(ref mut x) = self.player_two {
            App::load_sprite(w, x, SPRITE_P_2);
        }

    }
    fn load_sprite(mut w: &mut PistonWindow, player: &mut Player, file: &str) {
        let assets = find_folder::Search::ParentsThenKids(3, 3).for_folder("assets").unwrap();
        let tank_sprite = assets.join(file);
        let tank_sprite2 = Texture::from_path(&mut w.factory,
                                              &tank_sprite,
                                              Flip::None,
                                              &TextureSettings::new());
        match tank_sprite2 {
            Err(_) => {
                println!("Empty");
            }
            Ok(x) => {
                player.creature.set_sprite(x);
            }
        }

    }
}

fn main() {
    // Create an Glutin window.
    let mut window: PistonWindow = WindowSettings::new("chicken_fight_3000_ultimate_tournament",
                                                       [WIDTH as u32, HEIGHT as u32])
        .exit_on_esc(true)
        //.fullscreen(true)
        .build()
        .unwrap();

    // Create a new game and run it.

    let mut app = App::new(TWO_PLAYER);
    app.on_load(&mut window);

    let mut events = window.events();

    let folder = match find_folder::Search::Kids(1).for_folder("tiles") {
        Ok(res) => res.join("tileset-pokemon_dawn.png"),
        Err(_) => panic!("Folder 'tiles' not found!"),
    };

    let file_path = match folder.to_str() {
        Some(res) => res,
        None => panic!("Tileset not found!"),
    };

    let folder_level = match find_folder::Search::Kids(0).for_folder("src") {
        Ok(res) => res.join("level1.lvl"),
        Err(_) => panic!("Folder 'src' not found!"),
    };

    let level_path = match folder_level.to_str() {
        Some(res) => res,
        None => panic!("Level not found!"),
    };

    let tileset = io::read_tileset(file_path, &mut window);

    let mut level = io::read_level(level_path);

    let mut start = PreciseTime::now();
    app.cam.set_borders((level.get_x() as u64, level.get_y()as u64));
    app.player_one.set_borders((level.get_x() as u64, level.get_y()as u64));
    if let Some(ref mut p2) = app.player_two {
        p2.set_borders((level.get_x() as u64, level.get_y()as u64));
    }

    while let Some(e) = events.next(&mut window) {
        let now = start.to(PreciseTime::now()).num_milliseconds();
        //println!("{}", now);

        if let Some(_) = e.render_args() {
            app.on_draw(&mut window, &e, &tileset, &mut level);
        }
        if let Some(i) = e.release_args() {
            app.on_input(i, false);
        }
        if let Some(i) = e.press_args() {
            app.on_input(i, true);
        }

            if let Some(u) = e.update_args() {
                app.on_update(&u);
                start = PreciseTime::now();
            }

    }

}

//UTIL//////////////////////////////

fn border_add(add1: f64, add2: f64, width: bool) -> f64 {
    let border = (if width { WIDTH } else { HEIGHT }) as f64;
    let sum = add1 + add2;
    if sum < 0.0 {
        0.0
    } else if sum > border {
        border
    } else {
        sum
    }
}
<commit_msg>just a name change<commit_after>extern crate piston_window;
extern crate find_folder;
extern crate gfx_device_gl;
extern crate gfx_graphics;
extern crate gfx;
extern crate vecmath;
extern crate image as im;
extern crate time;

use piston_window::*;
use time::{Duration, PreciseTime};

mod creature;
mod player;
mod io;
mod level;
mod inventory;
mod item;
mod actor;
mod field;
mod interactable;
mod coord;
mod enums;
mod camera;

use camera::{Cam};
use player::{Player, LastKey};
use io::{ render_tile};
use io::tileset::{TILE_HEIGHT, TILE_WIDTH, Tileset};
use level::Level;

//EINGABEN
const TWO_PLAYER: bool = true;
const SPRITE_P_1: &'static str = "warrior2.png";
const SPRITE_P_2: &'static str = "paladin.png";
const CAMERA_BUF_X: u64 = 4;
const CAMERA_BUF_Y: u64 = 4;

const WIDTH: i64 = 1600;
const HEIGHT: i64 = 900;

const RED: [f32; 4] = [1.0, 0.0, 0.0, 1.0];
const BLACK: [f32; 4] = [0.0, 0.0, 0.0, 1.0];

pub struct App {
    player_one: Player,
    player_two: Option<Player>,
    cam: Cam,
}

impl App {
    fn new(two_player: bool) -> Self {
        App {
            // 0,0 Dummy-Value
            player_one: Player::new(0, 0),
            player_two: if two_player {
                // 0,0 Dummy-Value
                Some(Player::new(0, 0))
            } else {
                None
            },
            cam: Cam::new(CAMERA_BUF_X, CAMERA_BUF_Y),
        }
    }

    fn on_draw(&mut self,
               mut w: &mut PistonWindow,
               e: &Event,
               tileset: &Tileset,
               level: &mut Level) {
        let player_one = &self.player_one.creature;
        let player_two = &self.player_two;

        let range = self.cam.get_range();
        w.draw_2d(e, |c, gl| {
            // Clear the screen.
            clear(BLACK, gl);

            let center_lv = c.transform.trans(0.0, 0.0);

            //render_level(&tileset, gl, center_lv, &mut level);
            for (h, j) in (range.x_min..range.x_max).enumerate() {
                for (w, i) in (range.y_min..range.y_max).enumerate() {
                    let tile = match tileset.get_texture(level.get_data()[i as usize][j as usize].get_id()) {
                    Some(x) => x,
                    None => panic!("No texture found."),
                    };
                    // DEBUG
                    //println!("{} {}", i, j);
                    render_tile(&tile, gl, center_lv,  h as u32 * TILE_HEIGHT,
                            w as u32 * TILE_WIDTH,
                            w as u32,
                            h as u32);
                }
            }
            let center_p1 = c.transform.trans(((self.player_one.coord.get_x() - range.x_min )* 65) as f64,
                                              ((self.player_one.coord.get_y() - range.y_min)* 65) as f64);
            player_one.render(gl, center_p1);
            if let Some(ref p2) = *player_two {
                let center_p2 = c.transform.trans(((p2.coord.get_x() - range.x_min) * 65) as f64,

                                              ((p2.coord.get_y() - range.y_min )* 65) as f64);
                 p2.creature.render(gl, center_p2);

            }
        });
    }

    fn on_update(&mut self,
                 args: &UpdateArgs,) {
                let coord1 = self.player_one.coord.clone();
        let mut coord2 = coord1.clone();
        if let Some(ref p2) = self.player_two {
            coord2 = p2.coord.clone();
        }

                let range = self.cam.get_range_update();

        self.player_one.on_update(args, range);
        if let Some(ref mut x) = self.player_two {

            x.on_update(args, range);
        }
                self.cam.calc_coordinates(coord1, coord2);

    }

    fn on_input(&mut self, inp: Button, pressed: bool) {

        match inp {
            Button::Keyboard(Key::Up) => {
                if pressed {
                    self.player_one.last = LastKey::Up;
                }
                self.player_one.pressed = pressed;
            }
            Button::Keyboard(Key::Down) => {
                if pressed {
                    self.player_one.last = LastKey::Down;
                }
                self.player_one.pressed = pressed;
            }
            Button::Keyboard(Key::Left) => {
                if pressed {
                    self.player_one.last = LastKey::Left;
                }
                self.player_one.pressed = pressed;
            }
            Button::Keyboard(Key::Right) => {
                if pressed {
                    self.player_one.last = LastKey::Right;
                }
                self.player_one.pressed = pressed;
            }
            Button::Keyboard(Key::W) => {
                if let Some(ref mut x) = self.player_two {
                    if pressed {
                        x.last = LastKey::Up;
                    }
                    x.pressed = pressed;
                }
            }
            Button::Keyboard(Key::S) => {
                if let Some(ref mut x) = self.player_two {
                    if pressed {
                        x.last = LastKey::Down;
                    }
                    x.pressed = pressed;
                }
            }
            Button::Keyboard(Key::A) => {
                if let Some(ref mut x) = self.player_two {
                    if pressed {
                        x.last = LastKey::Left;
                    }
                    x.pressed = pressed;
                }
            }
            Button::Keyboard(Key::D) => {
                if let Some(ref mut x) = self.player_two {
                    if pressed {
                        x.last = LastKey::Right;
                    }
                    x.pressed = pressed;
                }
            }
            _ => {}

        }
    }
    fn on_load(&mut self, mut w: &mut PistonWindow) {
        let mut player_one = &mut self.player_one;
        App::load_sprite(w, &mut player_one, SPRITE_P_1);
        if let Some(ref mut x) = self.player_two {
            App::load_sprite(w, x, SPRITE_P_2);
        }

    }
    fn load_sprite(mut w: &mut PistonWindow, player: &mut Player, file: &str) {
        let assets = find_folder::Search::ParentsThenKids(3, 3).for_folder("assets").unwrap();
        let tank_sprite = assets.join(file);
        let tank_sprite2 = Texture::from_path(&mut w.factory,
                                              &tank_sprite,
                                              Flip::None,
                                              &TextureSettings::new());
        match tank_sprite2 {
            Err(_) => {
                println!("Empty");
            }
            Ok(x) => {
                player.creature.set_sprite(x);
            }
        }

    }
}

fn main() {
    // Create an Glutin window.
    let mut window: PistonWindow = WindowSettings::new("Chicken Fight 3000 Ultimate Tournament",
                                                       [WIDTH as u32, HEIGHT as u32])
        .exit_on_esc(true)
        //.fullscreen(true)
        .build()
        .unwrap();

    // Create a new game and run it.

    let mut app = App::new(TWO_PLAYER);
    app.on_load(&mut window);

    let mut events = window.events();

    let folder = match find_folder::Search::Kids(1).for_folder("tiles") {
        Ok(res) => res.join("tileset-pokemon_dawn.png"),
        Err(_) => panic!("Folder 'tiles' not found!"),
    };

    let file_path = match folder.to_str() {
        Some(res) => res,
        None => panic!("Tileset not found!"),
    };

    let folder_level = match find_folder::Search::Kids(0).for_folder("src") {
        Ok(res) => res.join("level1.lvl"),
        Err(_) => panic!("Folder 'src' not found!"),
    };

    let level_path = match folder_level.to_str() {
        Some(res) => res,
        None => panic!("Level not found!"),
    };

    let tileset = io::read_tileset(file_path, &mut window);

    let mut level = io::read_level(level_path);

    let mut start = PreciseTime::now();
    app.cam.set_borders((level.get_x() as u64, level.get_y()as u64));
    app.player_one.set_borders((level.get_x() as u64, level.get_y()as u64));
    if let Some(ref mut p2) = app.player_two {
        p2.set_borders((level.get_x() as u64, level.get_y()as u64));
    }

    while let Some(e) = events.next(&mut window) {
        let now = start.to(PreciseTime::now()).num_milliseconds();
        //println!("{}", now);

        if let Some(_) = e.render_args() {
            app.on_draw(&mut window, &e, &tileset, &mut level);
        }
        if let Some(i) = e.release_args() {
            app.on_input(i, false);
        }
        if let Some(i) = e.press_args() {
            app.on_input(i, true);
        }

            if let Some(u) = e.update_args() {
                app.on_update(&u);
                start = PreciseTime::now();
            }

    }

}

//UTIL//////////////////////////////

fn border_add(add1: f64, add2: f64, width: bool) -> f64 {
    let border = (if width { WIDTH } else { HEIGHT }) as f64;
    let sum = add1 + add2;
    if sum < 0.0 {
        0.0
    } else if sum > border {
        border
    } else {
        sum
    }
}
<|endoftext|>


<commit_before>#[macro_use]
extern crate log;
extern crate env_logger;
extern crate irc;
extern crate github;

use irc::client::prelude::*;

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

    // This could be in a JSON config, but then we need to figure out how
    // to find that JSON config
    let irc_config : Config = Config {
        owners: Some(vec![format!("dbaron")]),
        nickname: Some(format!("wgmeeting-github-bot")),
        alt_nicks: Some(vec![format!("wgmeeting-github-bot-"), format!("wgmeeting-github-bot--")]),
        username: Some(format!("dbaron-gh-bot")),
        realname: Some(format!("Bot to add meeting minutes to github issues.")),
        server: Some(format!("irc.w3.org")),
        port: Some(6667),
        use_ssl: Some(false),
        encoding: Some(format!("UTF-8")),
        channels: Some(vec![format!("#cssbottest")]),
        user_info: Some(format!("Bot to add meeting minutes to github issues.")),
        //source: Some(format!("https://github.com/dbaron/wgmeeting-github-ircbot")), // FIXME: why doesn't this work as documented?
        .. Default::default()
    };

    // FIXME: Eventually this should support multiple channels, plus
    // options to ask the bot which channels it's in, and which channels
    // it currently has buffers in.  (Then we can do things like ask the
    // bot to reboot itself, but it will only do so if it's not busy.)
    let mut channel_data = ChannelData::new();

    let server = IrcServer::from_config(irc_config).unwrap();
    server.identify().unwrap();
    for message in server.iter() {
        let message = message.unwrap(); // panic if there's an error

        match message.command {
            Command::PRIVMSG(ref target, ref msg) => {
                match message.source_nickname() {
                    None => {
                        warn!("PRIVMSG without a source! {}", message); // FIXME: trailing \n
                    },
                    Some(ref source) => {
                        let mynick = server.current_nickname();
                        if target == mynick {
                            handle_bot_command(&server, msg, source, None)
                        } else if target.starts_with('#') {
                            match check_command_in_channel(mynick, msg) {
                                Some(ref command) => {
                                    handle_bot_command(&server, command, target, Some(source))
                                },
                                None => {
                                    channel_data.add_line(msg);
                                }
                            }
                        } else {
                            warn!("UNEXPECTED TARGET {} in message {}", target, message); // FIXME: trailing \n
                        }
                    }
                }
            },
            _ => (),
        }
    }
}

// Take a message in the channel, and see if it was a message sent to
// this bot.
fn check_command_in_channel(mynick: &str, msg: &String) -> Option<String> {
    if !msg.starts_with(mynick)  {
        return None;
    }
    let after_nick = &msg[mynick.len()..];
    if !after_nick.starts_with(":") && !after_nick.starts_with(",") {
        return None;
    }
    let after_punct = &after_nick[1..];
    Some(String::from(after_punct.trim_left()))
}

fn handle_bot_command(server: &IrcServer, command: &str, response_target: &str, response_username: Option<&str>) {

    let send_line = |response_username: Option<&str>, line: &str| {
        let adjusted_line = match response_username {
            None => String::from(line),
            Some(username) => String::from(username) + ", " + line
        };
        server.send_privmsg(response_target, &adjusted_line).unwrap();
    };

    if command == "help" {
        send_line(response_username, "The commands I understand are:");
        send_line(None,              "  help     Send this message.");
        return;
    }

    send_line(response_username, "Sorry, I don't understand that command.  Try 'help'.");
}

struct TopicData {
    lines: Vec<String>,
}

struct ChannelData {
    current_topic: TopicData,
}

impl TopicData {
    fn new() -> TopicData {
        TopicData { lines: vec![] }
    }
}

impl ChannelData {
    fn new() -> ChannelData {
        ChannelData { current_topic: TopicData::new() }
    }

    fn add_line(&mut self, line: &String) {
        self.current_topic.lines.push(line.clone())
    }
}
<commit_msg>Run 'cargo fmt', and clean up the errors about overlong lines that it gives.<commit_after>#[macro_use]
extern crate log;
extern crate env_logger;
extern crate irc;
extern crate github;

use irc::client::prelude::*;

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

    // This could be in a JSON config, but then we need to figure out how
    // to find that JSON config
    let irc_config: Config = Config {
        owners: Some(vec![format!("dbaron")]),
        nickname: Some(format!("wgmeeting-github-bot")),
        alt_nicks: Some(vec![format!("wgmeeting-github-bot-"),
                             format!("wgmeeting-github-bot--")]),
        username: Some(format!("dbaron-gh-bot")),
        realname: Some(format!("Bot to add meeting minutes to github issues.")),
        server: Some(format!("irc.w3.org")),
        port: Some(6667),
        use_ssl: Some(false),
        encoding: Some(format!("UTF-8")),
        channels: Some(vec![format!("#cssbottest")]),
        user_info: Some(format!("Bot to add meeting minutes to github issues.")),
        // FIXME: why doesn't this work as documented?
        //source: Some(format!("https://github.com/dbaron/wgmeeting-github-ircbot")),
        ..Default::default()
    };

    // FIXME: Eventually this should support multiple channels, plus
    // options to ask the bot which channels it's in, and which channels
    // it currently has buffers in.  (Then we can do things like ask the
    // bot to reboot itself, but it will only do so if it's not busy.)
    let mut channel_data = ChannelData::new();

    let server = IrcServer::from_config(irc_config).unwrap();
    server.identify().unwrap();
    for message in server.iter() {
        let message = message.unwrap(); // panic if there's an error

        match message.command {
            Command::PRIVMSG(ref target, ref msg) => {
                match message.source_nickname() {
                    None => {
                        // FIXME: trailing \n
                        warn!("PRIVMSG without a source! {}", message);
                    }
                    Some(ref source) => {
                        let mynick = server.current_nickname();
                        if target == mynick {
                            handle_bot_command(&server, msg, source, None)
                        } else if target.starts_with('#') {
                            match check_command_in_channel(mynick, msg) {
                                Some(ref command) => {
                                    handle_bot_command(&server, command, target, Some(source))
                                }
                                None => {
                                    channel_data.add_line(msg);
                                }
                            }
                        } else {
                            // FIXME: trailing \n
                            warn!("UNEXPECTED TARGET {} in message {}", target, message);
                        }
                    }
                }
            }
            _ => (),
        }
    }
}

// Take a message in the channel, and see if it was a message sent to
// this bot.
fn check_command_in_channel(mynick: &str, msg: &String) -> Option<String> {
    if !msg.starts_with(mynick) {
        return None;
    }
    let after_nick = &msg[mynick.len()..];
    if !after_nick.starts_with(":") && !after_nick.starts_with(",") {
        return None;
    }
    let after_punct = &after_nick[1..];
    Some(String::from(after_punct.trim_left()))
}

fn handle_bot_command(server: &IrcServer,
                      command: &str,
                      response_target: &str,
                      response_username: Option<&str>) {

    let send_line = |response_username: Option<&str>, line: &str| {
        let adjusted_line = match response_username {
            None => String::from(line),
            Some(username) => String::from(username) + ", " + line,
        };
        server
            .send_privmsg(response_target, &adjusted_line)
            .unwrap();
    };

    if command == "help" {
        send_line(response_username, "The commands I understand are:");
        send_line(None, "  help     Send this message.");
        return;
    }

    send_line(response_username,
              "Sorry, I don't understand that command.  Try 'help'.");
}

struct TopicData {
    lines: Vec<String>,
}

struct ChannelData {
    current_topic: TopicData,
}

impl TopicData {
    fn new() -> TopicData {
        TopicData { lines: vec![] }
    }
}

impl ChannelData {
    fn new() -> ChannelData {
        ChannelData { current_topic: TopicData::new() }
    }

    fn add_line(&mut self, line: &String) {
        self.current_topic.lines.push(line.clone())
    }
}
<|endoftext|>


<commit_before>// Copyright 2015 Robert Helmer <rhelmer@rhelmer.org>. See the LICENSE
// file at the top-level directory of this distribution.

/**
  * Symbolapi - a microservice which accepts lists of symbol+addresses, and returns
  * a list of symbolicated functions.
  *
  * The goal is to take an HTTP JSON request such as:
  * {"stacks":[
  *   [
  *     [0,11723767],
  *     [1, 65802]
  *    ]
  *  ],
  *  "memoryMap":[
  *    ["xul.pdb","44E4EC8C2F41492B9369D6B9A059577C2"],
  *    ["wntdll.pdb","D74F79EB1F8D4A45ABCD2F476CCABACC2"]
  *  ],
  *  "version":4
  * }
  *
  * The symbolapi service then downloads the corresponding symbol files (e.g. from S3), and returns
  * the function names for the corresponding addresses (in the "stacks" array) and returns JSON
  * such as:
  * {"symbolicatedStacks": [
  *   [
  *     "XREMain::XRE_mainRun() (in xul.pdb)",
  *     "KiUserCallbackDispatcher (in wntdll.pdb)"]
  *   ],
  *   "knownModules": [true, true]
  * }
  */

extern crate breakpad_symbols;
extern crate hyper;
#[macro_use]
extern crate log;
extern crate log4rs;
extern crate rustc_serialize;
extern crate toml;

use std::collections::HashMap;
use std::fs::{File, create_dir_all};
use std::io::{Read, Write};
use std::path::{PathBuf};
use std::thread;

use breakpad_symbols::{Symbolizer, SimpleSymbolSupplier};
use hyper::Client;
use hyper::server::{Server, Request, Response};
use hyper::status::StatusCode;
use rustc_serialize::json;

/**
  * Incoming JSON request format.
  */
// required JSON keys are non-snakecase
#[allow(non_snake_case)]
#[derive(RustcDecodable)]
pub struct SymbolRequest {
    memoryMap: Vec<(String,String)>,
    // index, offset
    stacks: Vec<Vec<(i8,u64)>>,
    version: u8,
}

/**
  * Outgoing JSON response format.
  */
// required JSON keys are non-snakecase
#[allow(non_snake_case)]
#[derive(RustcEncodable)]
pub struct SymbolResponse {
    symbolicatedStacks: Vec<String>,
    knownModules: Vec<bool>,
}

fn main() {
    log4rs::init_file("config/log.toml", Default::default()).unwrap();

    let address = "0.0.0.0:5000";

    info!("Listening on {}", address);
    Server::http(address).unwrap().handle(server).unwrap();
}

/**
  * Receives single HTTP requests and demuxes to symbols file fetches from S3 bucket.
  */
fn server(mut req: Request, mut res: Response) {
    info!("incoming connection from {}", req.remote_addr);

    match req.method {
        hyper::Post => {
            let mut res = res.start().unwrap();

            let mut buffer = String::new();
            req.read_to_string(&mut buffer).unwrap();
            debug!("raw POST: {:?}", &buffer);

            let decoded: SymbolRequest = json::decode(&buffer).unwrap();

            debug!("decoded memoryMap: {:?}", decoded.memoryMap);
            debug!("decoded stacks: {:?}", decoded.stacks);
            debug!("decoded version: {}", decoded.version);

            let symbol_url = get_config("symbol_urls.public");

            // stacks come in as an array, turn into hashmap
            let mut stack_map: HashMap<i8, Vec<u64>> = HashMap::new();

            debug!("decoded.stacks: {:?}", decoded.stacks);

            let stacks = decoded.stacks[0].clone();
            for stack in &stacks {
                let (index, offset) = *stack;

                let mut offsets = vec!();
                if stack_map.contains_key(&index) {
                    offsets = stack_map.get(&index).unwrap().clone();
                }
                offsets.push(offset);
                stack_map.insert(index, offsets);
            }

            debug!("stack_map: {:?}", stack_map);

            // FIXME limit the number of possible threads
            // TODO maybe push these into a queue and have a thread pool service the queue?
            let symbol_response = client(symbol_url, decoded.memoryMap, stack_map.clone());
            res.write_all(symbol_response.as_bytes()).unwrap();

            res.end().unwrap();
        },
        hyper::Get => {
            let mut res = res.start().unwrap();
            res.write_all("symbolapi, see github.com/rhelmer/symbolapi".as_bytes()).unwrap();
        },
        _ => { *res.status_mut() = StatusCode::MethodNotAllowed },
    }

    debug!("finished serving request");
}

/**
  * Creates multiple client connections and aggregates result.
  */
fn client(url: String, memory_map: Vec<(String,String)>, stack_map: HashMap<i8, Vec<u64>>) -> String {
    let mut handles = vec![];
    let mut counter: i8 = 0;
    for (debug_file, debug_id) in memory_map {
        let debug_file_name = debug_file.clone();
        let pdb = debug_file.find(".pdb").unwrap();
        let (symbol_name, _) = debug_file.split_at(pdb);
        let symbol_file = format!("{}.sym", symbol_name);
        let this_url = format!("{}/{}/{}/{}", url, debug_file, debug_id, symbol_file);

        let mut symbol_path = PathBuf::new();
        // TODO get from config
        symbol_path.push("testdata/symbols");

        let mut full_symbol_path = symbol_path.clone();
        full_symbol_path.push(&debug_file);
        full_symbol_path.push(&debug_id);
        full_symbol_path.push(&symbol_file);

        let stack_map_copy = stack_map.clone();

        create_dir_all(&full_symbol_path.parent().unwrap()).unwrap();

        let supplier = SimpleSymbolSupplier::new(vec!(symbol_path.clone()));

        // TODO most of the time is probably spent waiting on I/O, maybe async would be more appropriate?
        // TODO decide min/max possible threads, possibly based on number of cores?
        handles.push(thread::spawn(move || {

            let symbolizer = Symbolizer::new(supplier);
            // FIXME use Arc<Mutex<File>> to prevent concurrent writes
            // TODO only write contents if server version newer
            if !&full_symbol_path.exists() {

                let mut body = String::new();
                let c = Client::new();
                let mut res = c.get(&this_url).send().unwrap();
                res.read_to_string(&mut body).unwrap();

                let mut f = File::create(&full_symbol_path).unwrap();
                f.write_all(body.as_bytes()).unwrap();
            }

            debug!("symbol_path: {:?}", &symbol_path);
            // FIXME this is having problems with CRLF

            let mut symbols = vec!();
            for stacks in stack_map_copy.get(&counter) {
                for address in stacks {
                    debug!("attempt to symbolicate: {} for: {:?}", *address, &symbol_path);
                    match symbolizer.get_symbol_at_address(&debug_file_name, &debug_id, *address) {
                        Some(x) => symbols.push(x),
                        // return the address rather than function name if symbol not found
                        None => symbols.push(format!("0x{:x}", address)),
                    }
                }
            }
            debug!("debug_file_name: {:?}, symbols: {:?}", debug_file_name, symbols);

            (debug_file_name, symbols)
        }));

        counter += 1;
    }

    let mut result = SymbolResponse {
        symbolicatedStacks: vec!(),
        knownModules: vec!(),
    };

    for handle in handles {
        let (debug_file_name, symbols) = handle.join().unwrap();

        for symbol in symbols {
            result.symbolicatedStacks.push(
                format!("{} (in {})", symbol, debug_file_name)
            );
        }
        result.knownModules.push(true);
    }

    json::encode(&result).unwrap()
}

/**
  * Returns individual values from the configuration file.
  */
fn get_config(value_name: &str) -> String {
    // TODO move to actual file, static str for the moment
    let toml: &'static str = r#"
        [symbol_urls]
        public = "https://s3-us-west-2.amazonaws.com/org.mozilla.crash-stats.symbols-public/v1"
    "#;
    // TODO support multiple URLs
    let value: toml::Value = toml.parse().unwrap();

    value.lookup(value_name).unwrap().as_str().unwrap().to_string()
}
<commit_msg>match ouput format<commit_after>// Copyright 2015 Robert Helmer <rhelmer@rhelmer.org>. See the LICENSE
// file at the top-level directory of this distribution.

/**
  * Symbolapi - a microservice which accepts lists of symbol+addresses, and returns
  * a list of symbolicated functions.
  *
  * The goal is to take an HTTP JSON request such as:
  * {"stacks":[
  *   [
  *     [0,11723767],
  *     [1, 65802]
  *    ]
  *  ],
  *  "memoryMap":[
  *    ["xul.pdb","44E4EC8C2F41492B9369D6B9A059577C2"],
  *    ["wntdll.pdb","D74F79EB1F8D4A45ABCD2F476CCABACC2"]
  *  ],
  *  "version":4
  * }
  *
  * The symbolapi service then downloads the corresponding symbol files (e.g. from S3), and returns
  * the function names for the corresponding addresses (in the "stacks" array) and returns JSON
  * such as:
  * {"symbolicatedStacks": [
  *   [
  *     "XREMain::XRE_mainRun() (in xul.pdb)",
  *     "KiUserCallbackDispatcher (in wntdll.pdb)"]
  *   ],
  *   "knownModules": [true, true]
  * }
  */

extern crate breakpad_symbols;
extern crate hyper;
#[macro_use]
extern crate log;
extern crate log4rs;
extern crate rustc_serialize;
extern crate toml;

use std::collections::HashMap;
use std::fs::{File, create_dir_all};
use std::io::{Read, Write};
use std::path::{PathBuf};
use std::thread;

use breakpad_symbols::{Symbolizer, SimpleSymbolSupplier};
use hyper::Client;
use hyper::server::{Server, Request, Response};
use hyper::status::StatusCode;
use rustc_serialize::json;

/**
  * Incoming JSON request format.
  */
// required JSON keys are non-snakecase
#[allow(non_snake_case)]
#[derive(RustcDecodable)]
pub struct SymbolRequest {
    memoryMap: Vec<(String,String)>,
    // index, offset
    stacks: Vec<Vec<(i8,u64)>>,
    version: u8,
}

/**
  * Outgoing JSON response format.
  */
// required JSON keys are non-snakecase
#[allow(non_snake_case)]
#[derive(RustcEncodable)]
pub struct SymbolResponse {
    symbolicatedStacks: Vec<Vec<String>>,
    knownModules: Vec<bool>,
}

fn main() {
    log4rs::init_file("config/log.toml", Default::default()).unwrap();

    let address = "0.0.0.0:5000";

    info!("Listening on {}", address);
    Server::http(address).unwrap().handle(server).unwrap();
}

/**
  * Receives single HTTP requests and demuxes to symbols file fetches from S3 bucket.
  */
fn server(mut req: Request, mut res: Response) {
    info!("incoming connection from {}", req.remote_addr);

    match req.method {
        hyper::Post => {
            let mut res = res.start().unwrap();

            let mut buffer = String::new();
            req.read_to_string(&mut buffer).unwrap();
            debug!("raw POST: {:?}", &buffer);

            let decoded: SymbolRequest = json::decode(&buffer).unwrap();

            debug!("decoded memoryMap: {:?}", decoded.memoryMap);
            debug!("decoded stacks: {:?}", decoded.stacks);
            debug!("decoded version: {}", decoded.version);

            let symbol_url = get_config("symbol_urls.public");

            // stacks come in as an array, turn into hashmap
            let mut stack_map: HashMap<i8, Vec<u64>> = HashMap::new();

            debug!("decoded.stacks: {:?}", decoded.stacks);

            let stacks = decoded.stacks[0].clone();
            for stack in &stacks {
                let (index, offset) = *stack;

                let mut offsets = vec!();
                if stack_map.contains_key(&index) {
                    offsets = stack_map.get(&index).unwrap().clone();
                }
                offsets.push(offset);
                stack_map.insert(index, offsets);
            }

            debug!("stack_map: {:?}", stack_map);

            // FIXME limit the number of possible threads
            // TODO maybe push these into a queue and have a thread pool service the queue?
            let symbol_response = client(symbol_url, decoded.memoryMap, stack_map.clone());
            res.write_all(symbol_response.as_bytes()).unwrap();

            res.end().unwrap();
        },
        hyper::Get => {
            let mut res = res.start().unwrap();
            res.write_all("symbolapi, see github.com/rhelmer/symbolapi".as_bytes()).unwrap();
        },
        _ => { *res.status_mut() = StatusCode::MethodNotAllowed },
    }

    debug!("finished serving request");
}

/**
  * Creates multiple client connections and aggregates result.
  */
fn client(url: String, memory_map: Vec<(String,String)>, stack_map: HashMap<i8, Vec<u64>>) -> String {
    let mut handles = vec![];
    let mut counter: i8 = 0;
    for (debug_file, debug_id) in memory_map {
        let debug_file_name = debug_file.clone();
        let pdb = debug_file.find(".pdb").unwrap();
        let (symbol_name, _) = debug_file.split_at(pdb);
        let symbol_file = format!("{}.sym", symbol_name);
        let this_url = format!("{}/{}/{}/{}", url, debug_file, debug_id, symbol_file);

        let mut symbol_path = PathBuf::new();
        // TODO get from config
        symbol_path.push("testdata/symbols");

        let mut full_symbol_path = symbol_path.clone();
        full_symbol_path.push(&debug_file);
        full_symbol_path.push(&debug_id);
        full_symbol_path.push(&symbol_file);

        let stack_map_copy = stack_map.clone();

        create_dir_all(&full_symbol_path.parent().unwrap()).unwrap();

        let supplier = SimpleSymbolSupplier::new(vec!(symbol_path.clone()));

        // TODO most of the time is probably spent waiting on I/O, maybe async would be more appropriate?
        // TODO decide min/max possible threads, possibly based on number of cores?
        handles.push(thread::spawn(move || {

            let symbolizer = Symbolizer::new(supplier);
            // FIXME use Arc<Mutex<File>> to prevent concurrent writes
            // TODO only write contents if server version newer
            if !&full_symbol_path.exists() {

                let mut body = String::new();
                let c = Client::new();
                let mut res = c.get(&this_url).send().unwrap();
                res.read_to_string(&mut body).unwrap();

                let mut f = File::create(&full_symbol_path).unwrap();
                f.write_all(body.as_bytes()).unwrap();
            }

            debug!("symbol_path: {:?}", &symbol_path);
            // FIXME this is having problems with CRLF

            let mut symbols = vec!();
            for stacks in stack_map_copy.get(&counter) {
                for address in stacks {
                    debug!("attempt to symbolicate: {} for: {:?}", *address, &symbol_path);
                    match symbolizer.get_symbol_at_address(&debug_file_name, &debug_id, *address) {
                        Some(x) => symbols.push(x),
                        // return the address rather than function name if symbol not found
                        None => symbols.push(format!("0x{:x}", address)),
                    }
                }
            }
            debug!("debug_file_name: {:?}, symbols: {:?}", debug_file_name, symbols);

            (debug_file_name, symbols)
        }));

        counter += 1;
    }

    let mut result = SymbolResponse {
        symbolicatedStacks: vec!(),
        knownModules: vec!(),
    };

    let mut symbolicated_stacks = vec!();

    for handle in handles {
        let (debug_file_name, symbols) = handle.join().unwrap();

        for symbol in symbols {
            symbolicated_stacks.push(
                format!("{} (in {})", symbol, debug_file_name)
            );
        }
        result.knownModules.push(true);
    }

    // the required result format requires this to be a vec-of-vecs
    result.symbolicatedStacks.push(symbolicated_stacks);

    json::encode(&result).unwrap()
}

/**
  * Returns individual values from the configuration file.
  */
fn get_config(value_name: &str) -> String {
    // TODO move to actual file, static str for the moment
    let toml: &'static str = r#"
        [symbol_urls]
        public = "https://s3-us-west-2.amazonaws.com/org.mozilla.crash-stats.symbols-public/v1"
    "#;
    // TODO support multiple URLs
    let value: toml::Value = toml.parse().unwrap();

    value.lookup(value_name).unwrap().as_str().unwrap().to_string()
}
<|endoftext|>