<commit_before>extern crate axum;
extern crate handlebars;
extern crate http;
extern crate image;
extern crate num;
extern crate redis;
extern crate serde;
extern crate time;
extern crate tracing;
extern crate urlencoded;

use axum::{
    body::Bytes,
    error_handling::HandleErrorLayer,
    extract::{Extension, Path, Query},
    http::{header, HeaderValue, StatusCode},
    response::{Html, IntoResponse},
    routing::get,
    BoxError, Router,
};
use handlebars::Handlebars;
use image::ImageBuffer;
use serde::{Deserialize, Serialize};
use std::collections::BTreeMap;
use std::{collections::HashMap, net::SocketAddr, time::Duration};
use tower::ServiceBuilder;
use tower_http::{
    trace::{DefaultMakeSpan, DefaultOnResponse, TraceLayer},
    LatencyUnit, ServiceBuilderExt,
};

mod counter;
mod img;

// from: https://github.com/iron/iron/blob/master/examples/time.rs
// struct ResponseTime;

// impl typemap::Key for ResponseTime {
//     type Value = OffsetDateTime;
// }

// impl BeforeMiddleware for ResponseTime {
//     fn before(&self, req: &mut Request) -> IronResult<()> {
//         req.extensions
//             .insert::<ResponseTime>(OffsetDateTime::now_utc());
//         Ok(())
//     }
// }

// impl AfterMiddleware for ResponseTime {
//     fn after(&self, req: &mut Request, res: Response) -> IronResult<Response> {
//         let delta = OffsetDateTime::now_utc() - *req.extensions.get::<ResponseTime>().unwrap();
//         println!("Request took: {} ms", delta.subsec_milliseconds());
//         Ok(res)
//     }
// }

static BASE: &'static str = r#"
<!DOCTYPE html>

    <meta charset="utf-8">
    <title>{{title}}</title>
    <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-alpha.2/css/bootstrap.min.css" integrity="sha384-y3tfxAZXuh4HwSYylfB+J125MxIs6mR5FOHamPBG064zB+AFeWH94NdvaCBm8qnd" crossorigin="anonymous">

    {{> page}}

"#;

static INDEX: &'static str = r#"
{{#*inline "page"}}

Peekaboo server

I see you!

{{/inline}}
{{~> base title=Peekaboo~}}
"#;

static INFO: &'static str = r#"
{{#*inline "page"}}

Peekaboo server

{{name}} has had {{count}} visitors!

{{/inline}}
{{~> base title=Peekaboo~}}
"#;

#[derive(Serialize, Deserialize, Debug)]
struct Peek {
    name: String,
    count: i64,
}

async fn handle_errors(err: BoxError) -> impl IntoResponse {
    if err.is::<tower::timeout::error::Elapsed>() {
        (
            StatusCode::REQUEST_TIMEOUT,
            "Request took too long".to_string(),
        )
    } else {
        (
            StatusCode::INTERNAL_SERVER_ERROR,
            format!("Unhandled internal error: {}", err),
        )
    }
}

#[tokio::main]
async fn main() {
    async fn handler() -> Result<Html<String>, StatusCode> {
        let mut handlebars = Handlebars::new();
        match handlebars.register_template_string("base", BASE.to_string()) {
            Ok(_) => {}
            Err(err) => println!("error parsing header: {:?}", err),
        }
        match handlebars.register_template_string("index", INDEX.to_string()) {
            Ok(_) => {}
            Err(err) => println!("error parsing index: {:?}", err),
        }

        let data: BTreeMap<String, String> = BTreeMap::new();

        match handlebars.render("index", &data) {
            Ok(result) => Ok(Html(result)),
            Err(err) => {
                println!("error rendering index: {}", err);
                Err(StatusCode::BAD_REQUEST)
            }
        }
    }

    async fn peek_handler(
        Extension(state): Extension<counter::State>,
        Path(id): Path<String>,
        params: Query<HashMap<String, String>>,
    ) -> Result {
        {
            let _ = match state.inc(id) {
                Ok(v) => v,
                Err(e) => {
                    println!("error connecting to redis: {}", e);
                    0i64
                }
            };
        }

        let mut img = ImageBuffer::new(512, 512);
        // let content_type = "image/png".parse::<Mime>().unwrap();

        match params.get("t").map(|t| t.as_str()) {
            Some("mandelbrot") => img::apply_mandelbrot(&mut img, 500),
            Some("julia") => img::apply_julia(&mut img, 500),
            Some(_) => return Err(StatusCode::NOT_FOUND),
            None => {
                // turn the image white
                let mut img_sm = ImageBuffer::new(1, 1);
                img::apply_color(&mut img_sm, 255);
                return Ok(img::ImgWriter { img: img_sm });
            }
        };

        Ok(img::ImgWriter { img: img })
    }

    async fn peek_info_handler(
        Extension(state): Extension<counter::State>,
        Path(id): Path<String>,
    ) -> Result<Html<String>, StatusCode> {
        let mut handlebars = Handlebars::new();
        match handlebars.register_template_string("base", BASE.to_string()) {
            Ok(_) => {}
            Err(err) => println!("error parsing header: {:?}", err),
        }
        match handlebars.register_template_string("info", INFO.to_string()) {
            Ok(_) => {}
            Err(err) => println!("error parsing info: {:?}", err),
        }

        let data = Peek {
            name: id.clone(),
            count: state.get(id).unwrap_or(0i64),
        };

        match handlebars.render("info", &data) {
            Ok(result) => Ok(Html(result)),
            Err(err) => {
                println!("error rendering index: {}", err);
                Err(StatusCode::INTERNAL_SERVER_ERROR)
            }
        }
    }

    let state = counter::State::new("redis://127.0.0.1/");

    // Build our middleware stack
    // ref: https://github.com/tower-rs/tower-http/blob/master/examples/axum-key-value-store/src/main.rs
    let middleware = ServiceBuilder::new()
        // Add high level tracing/logging to all requests
        .layer(
            TraceLayer::new_for_http()
                .on_body_chunk(|chunk: &Bytes, latency: Duration, _: &tracing::Span| {
                    tracing::trace!(size_bytes = chunk.len(), latency = ?latency, "sending body chunk")
                })
                .make_span_with(DefaultMakeSpan::new().include_headers(true))
                .on_response(DefaultOnResponse::new().include_headers(true).latency_unit(LatencyUnit::Micros)),
        )
        // Handle errors
        .layer(HandleErrorLayer::new(handle_errors))
        // Set a timeout
        .timeout(Duration::from_secs(10))
        // Share the state with each handler via a request extension
        .add_extension(state)
        // Compress responses
        .compression()
        // Set a `Content-Type` if there isn't one already.
        .insert_response_header_if_not_present(
            header::CONTENT_TYPE,
            HeaderValue::from_static("application/octet-stream"),
        );

    // let mut peek_chain = Chain::new(peek_handler);
    // peek_chain.link_before(ResponseTime);
    // peek_chain.link_after(ResponseTime);

    let app = Router::new()
        .route("/", get(handler))
        .route("/peek/:id", get(peek_handler))
        .route("/peek/:id/info", get(peek_info_handler))
        .layer(middleware.into_inner());

    // run our app with hyper
    // `axum::Server` is a re-export of `hyper::Server`
    let addr = SocketAddr::from(([127, 0, 0, 1], 2829));
    tracing::debug!("listening on {}", addr);
    axum::Server::bind(&addr)
        .serve(app.into_make_service())
        .await
        .unwrap();
}
<commit_msg>src: properly setup tower_http logging<commit_after>extern crate axum;
extern crate handlebars;
extern crate http;
extern crate image;
extern crate num;
extern crate redis;
extern crate serde;
extern crate time;
extern crate tracing;
extern crate urlencoded;

use axum::{
    error_handling::HandleErrorLayer,
    extract::{Extension, Path, Query},
    http::{header, HeaderValue, StatusCode},
    response::{Html, IntoResponse},
    routing::get,
    BoxError, Router,
};
use handlebars::Handlebars;
use image::ImageBuffer;
use serde::{Deserialize, Serialize};
use std::collections::BTreeMap;
use std::{collections::HashMap, net::SocketAddr, time::Duration};
use tower::ServiceBuilder;
use tower_http::{trace::TraceLayer, ServiceBuilderExt};

mod counter;
mod img;

static BASE: &'static str = r#"
<!DOCTYPE html>

    <meta charset="utf-8">
    <title>{{title}}</title>
    <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-alpha.2/css/bootstrap.min.css" integrity="sha384-y3tfxAZXuh4HwSYylfB+J125MxIs6mR5FOHamPBG064zB+AFeWH94NdvaCBm8qnd" crossorigin="anonymous">

    {{> page}}

"#;

static INDEX: &'static str = r#"
{{#*inline "page"}}

Peekaboo server

I see you!

{{/inline}}
{{~> base title=Peekaboo~}}
"#;

static INFO: &'static str = r#"
{{#*inline "page"}}

Peekaboo server

{{name}} has had {{count}} visitors!

{{/inline}}
{{~> base title=Peekaboo~}}
"#;

#[derive(Serialize, Deserialize, Debug)]
struct Peek {
    name: String,
    count: i64,
}

async fn handle_errors(err: BoxError) -> impl IntoResponse {
    if err.is::<tower::timeout::error::Elapsed>() {
        (
            StatusCode::REQUEST_TIMEOUT,
            "Request took too long".to_string(),
        )
    } else {
        (
            StatusCode::INTERNAL_SERVER_ERROR,
            format!("Unhandled internal error: {}", err),
        )
    }
}

#[tokio::main]
async fn main() {
    async fn handler() -> Result<Html<String>, StatusCode> {
        let mut handlebars = Handlebars::new();
        match handlebars.register_template_string("base", BASE.to_string()) {
            Ok(_) => {}
            Err(err) => println!("error parsing header: {:?}", err),
        }
        match handlebars.register_template_string("index", INDEX.to_string()) {
            Ok(_) => {}
            Err(err) => println!("error parsing index: {:?}", err),
        }

        let data: BTreeMap<String, String> = BTreeMap::new();

        match handlebars.render("index", &data) {
            Ok(result) => Ok(Html(result)),
            Err(err) => {
                println!("error rendering index: {}", err);
                Err(StatusCode::BAD_REQUEST)
            }
        }
    }

    async fn peek_handler(
        Extension(state): Extension<counter::State>,
        Path(id): Path<String>,
        params: Query<HashMap<String, String>>,
    ) -> Result {
        {
            let _ = match state.inc(id) {
                Ok(v) => v,
                Err(e) => {
                    println!("error connecting to redis: {}", e);
                    0i64
                }
            };
        }

        let mut img = ImageBuffer::new(512, 512);
        // let content_type = "image/png".parse::<Mime>().unwrap();

        match params.get("t").map(|t| t.as_str()) {
            Some("mandelbrot") => img::apply_mandelbrot(&mut img, 500),
            Some("julia") => img::apply_julia(&mut img, 500),
            Some(_) => return Err(StatusCode::NOT_FOUND),
            None => {
                // turn the image white
                let mut img_sm = ImageBuffer::new(1, 1);
                img::apply_color(&mut img_sm, 255);
                return Ok(img::ImgWriter { img: img_sm });
            }
        };

        Ok(img::ImgWriter { img: img })
    }

    async fn peek_info_handler(
        Extension(state): Extension<counter::State>,
        Path(id): Path<String>,
    ) -> Result<Html<String>, StatusCode> {
        let mut handlebars = Handlebars::new();
        match handlebars.register_template_string("base", BASE.to_string()) {
            Ok(_) => {}
            Err(err) => println!("error parsing header: {:?}", err),
        }
        match handlebars.register_template_string("info", INFO.to_string()) {
            Ok(_) => {}
            Err(err) => println!("error parsing info: {:?}", err),
        }

        let data = Peek {
            name: id.clone(),
            count: state.get(id).unwrap_or(0i64),
        };

        match handlebars.render("info", &data) {
            Ok(result) => Ok(Html(result)),
            Err(err) => {
                println!("error rendering index: {}", err);
                Err(StatusCode::INTERNAL_SERVER_ERROR)
            }
        }
    }

    // Setup tracing
    tracing_subscriber::fmt::init();

    let state = counter::State::new("redis://127.0.0.1/");

    // Build our middleware stack
    // ref: https://github.com/tower-rs/tower-http/blob/master/examples/axum-key-value-store/src/main.rs
    let middleware = ServiceBuilder::new()
        // Add high level tracing/logging to all requests
        .layer(TraceLayer::new_for_http())
        // Handle errors
        .layer(HandleErrorLayer::new(handle_errors))
        // Set a timeout
        .timeout(Duration::from_secs(10))
        // Share the state with each handler via a request extension
        .add_extension(state)
        // Compress responses
        .compression()
        // Set a `Content-Type` if there isn't one already.
        .insert_response_header_if_not_present(
            header::CONTENT_TYPE,
            HeaderValue::from_static("application/octet-stream"),
        );

    let app = Router::new()
        .route("/", get(handler))
        .route("/peek/:id", get(peek_handler))
        .route("/peek/:id/info", get(peek_info_handler))
        .layer(middleware.into_inner());

    // run our app with hyper
    // `axum::Server` is a re-export of `hyper::Server`
    let addr = SocketAddr::from(([127, 0, 0, 1], 2829));
    tracing::debug!("listening on {}", addr);
    axum::Server::bind(&addr)
        .serve(app.into_make_service())
        .await
        .unwrap();
}
<|endoftext|>


<commit_before>extern crate mmap;

use std::ptr;
use std::fs::OpenOptions;
use mmap::{MemoryMap, MapOption};

#[path="pi.rs"]
mod Pi;

fn main() {
    let mut gpio = Pi::Bcm2835Peripheral {
                    addr_p: &Pi::GPIO_BASE,
                    mem_fd: OpenOptions::new().create(true).open("temp.txt").unwrap(),
                    map: MemoryMap::new(1024, &[]).unwrap(),
                    addr: ptr::null_mut()
    };
    gpio.map_peripheral();
    unsafe {
        gpio.in_gpio(4);
        gpio.out_gpio(4);

        loop {
          gpio.set_gpio(1u8 << 4);
          std::thread::sleep_ms(1000);

          gpio.clear_gpio(1u8 << 4);
          std::thread::sleep_ms(1000);
      }
  }
}
<commit_msg>silence warnings for sleep_ms<commit_after>#![feature(core_intrinsics)]
#![allow(deprecated)]
extern crate mmap;

use std::ptr;
use std::fs::OpenOptions;
use mmap::MemoryMap;

#[path="pi.rs"]
mod pi;

fn main() {
    let mut gpio = pi::Bcm2835Peripheral {
                    addr_p: &pi::GPIO_BASE,
                    mem_fd: OpenOptions::new().create(true).open("temp.txt").unwrap(),
                    map: MemoryMap::new(1024, &[]).unwrap(),
                    addr: ptr::null_mut()
    };
    gpio.map_peripheral();
    unsafe {
        gpio.in_gpio(4);
        gpio.out_gpio(4);

        loop {
          gpio.set_gpio(1u32 << 4);
          std::thread::sleep_ms(1000);

          gpio.clear_gpio(1u32 << 4);
          std::thread::sleep_ms(1000);
        }
    }
}
<|endoftext|>


<commit_before>mod cd;
mod launch_bin;
mod env;

fn command_parser(mut command_vector : Vec<&str>) {
    use cd::cd;
    use launch_bin::launch_bin;
    use env::{env, setenv, unsetenv};

    match command_vector[0].trim() {
        "cd"        => cd(&command_vector),
        "env"       => env(),
        "setenv"    => setenv(&mut command_vector),
        "unsetenv"  => unsetenv(&mut command_vector),
        ""          => {},
        _           => launch_bin(&mut command_vector)
    }
}

fn print_prompt() {
    use std::io;
    use std::io::Write;
    use std::env;

    if let Ok(dir) = env::current_dir() {
        print!("{} > ", dir.display());
        io::stdout().flush().unwrap();
    } else {
        print!("> ");
        io::stdout().flush().unwrap();
    }
}

fn clean_cmd(cmd: &mut String) -> String {
    if cmd.chars().last().unwrap() == '\n' {
        cmd.pop();
    }
    return cmd.trim().to_string();
}

fn get_command_vector(command: &mut String) {
    let all_commands = command.split(";").map(|x: &str| x.to_string()).collect::<Vec<String>>();
    for mut cmd in all_commands {
        {
            cmd = clean_cmd(&mut cmd);
            let cmd_vector = cmd.split(" ").collect::<Vec<&str>>();
            command_parser(cmd_vector);
        }
    }
    print_prompt();
}

fn main_loop() {
    let mut command = String::new();

    while std::io::stdin().read_line(&mut command).unwrap() > 0
    {
        get_command_vector(&mut command);
        command.clear();
    }
}

fn main() {
    print_prompt();
    main_loop();
    println!();
    return ;
}
<commit_msg>handling empty string command<commit_after>mod cd;
mod launch_bin;
mod env;

fn command_parser(mut command_vector : Vec<&str>) {
    use cd::cd;
    use launch_bin::launch_bin;
    use env::{env, setenv, unsetenv};

    match command_vector[0].trim() {
        "cd"        => cd(&command_vector),
        "env"       => env(),
        "setenv"    => setenv(&mut command_vector),
        "unsetenv"  => unsetenv(&mut command_vector),
        ""          => {},
        _           => launch_bin(&mut command_vector)
    }
}

fn print_prompt() {
    use std::io;
    use std::io::Write;
    use std::env;

    if let Ok(dir) = env::current_dir() {
        print!("{} > ", dir.display());
        io::stdout().flush().unwrap();
    } else {
        print!("> ");
        io::stdout().flush().unwrap();
    }
}

fn clean_cmd(cmd: &mut String) -> String {
    match cmd.chars().last() {
        Some(c) => {if c == '\n' { cmd.pop(); }},
        _ => {}
    }
    return cmd.trim().to_string();
}

fn get_command_vector(command: &mut String) {
    let all_commands = command.split(";").map(|x: &str| x.to_string()).collect::<Vec<String>>();
    for mut cmd in all_commands {
        {
            cmd = clean_cmd(&mut cmd);
            let cmd_vector = cmd.split(" ").collect::<Vec<&str>>();
            command_parser(cmd_vector);
        }
    }
    print_prompt();
}

fn main_loop() {
    let mut command = String::new();

    while std::io::stdin().read_line(&mut command).unwrap() > 0
        {
            get_command_vector(&mut command);
            command.clear();
        }
}

fn main() {
    print_prompt();
    main_loop();
    println!();
    return ;
}
<|endoftext|>


<commit_before>extern crate sdl2_window;
extern crate graphics;
extern crate itertools;
extern crate opengl_graphics;
extern crate piston;
extern crate rand;
extern crate find_folder;

mod models;
mod drawings;
mod game;

use sdl2_window::Sdl2Window;
use opengl_graphics::{GlGraphics, OpenGL};
use piston::event_loop::{Events, EventLoop};
use piston::input::{Button, Event, Input, RenderEvent};
use piston::window::WindowSettings;

use game::Game;

const OPEN_GL: OpenGL = OpenGL::V3_2;

// Returns a result containing a GlutinWindow or an error if the window
// settings are not supported
fn try_create_window(samples: u8) -> Result<Sdl2Window, String> {
    WindowSettings::new("Rust Rogue", [640, 640])
        .exit_on_esc(true)
        .opengl(OPEN_GL)
        .vsync(true)
        .samples(samples)
        .fullscreen(false)
        .build()
}

fn main() {
    // Create a window with a AA sampling of 8 or fall back to 0
    let mut window = try_create_window(8).or_else(|_| try_create_window(0)).unwrap();
    // window.sdl_context.mouse().set_relative_mouse_mode(true);

    let mut gl = GlGraphics::new(OPEN_GL);

    // Event handling
    let mut events = window.events().ups(60).max_fps(60);

    // Game state
    let mut game = Game::new();

    while let Some(e) = events.next(&mut window) {
        match e {
            Event::Input(Input::Press(Button::Keyboard(key))) => {
                game.key_press(key);
            }

            Event::Input(Input::Release(Button::Keyboard(key))) => {
                game.key_release(key);
            }

            Event::Render(args) => {
                gl.draw(args.viewport(), |c, g| game.render(c, g));
            }

            Event::Update(args) => {
                game.update(args);
            }

            _ => {}
        }
    }
}
<commit_msg>sprites management + jon skelington<commit_after>extern crate sdl2_window;
extern crate graphics;
extern crate itertools;
extern crate opengl_graphics;
extern crate piston;
extern crate rand;
extern crate find_folder;

mod models;
mod drawings;
mod game;

use sdl2_window::Sdl2Window;
use opengl_graphics::{GlGraphics, OpenGL};
use piston::event_loop::{Events, EventLoop};
use piston::input::{Button, Event, Input, RenderEvent};
use piston::window::WindowSettings;

use game::Game;

const OPEN_GL: OpenGL = OpenGL::V3_2;

// Returns a result containing a Sdl2Window or an error if the window
// settings are not supported
fn try_create_window(samples: u8) -> Result<Sdl2Window, String> {
    WindowSettings::new("Rust Rogue", [640, 640])
        .exit_on_esc(true)
        .opengl(OPEN_GL)
        .vsync(true)
        .samples(samples)
        .fullscreen(false)
        .build()
}

fn main() {
    // Create a window with a AA sampling of 8 or fall back to 0
    let mut window = try_create_window(8).or_else(|_| try_create_window(0)).unwrap();
    // window.sdl_context.mouse().set_relative_mouse_mode(true);

    let mut gl = GlGraphics::new(OPEN_GL);

    // Event handling
    let mut events = window.events().ups(60).max_fps(60);

    // Game state
    let mut game = Game::new();

    while let Some(e) = events.next(&mut window) {
        match e {
            Event::Input(Input::Press(Button::Keyboard(key))) => {
                game.key_press(key);
            }

            Event::Input(Input::Release(Button::Keyboard(key))) => {
                game.key_release(key);
            }

            Event::Render(args) => {
                gl.draw(args.viewport(), |c, g| game.render(c, g));
            }

            Event::Update(args) => {
                game.update(args);
            }

            _ => {}
        }
    }
}
<|endoftext|>


<commit_before>#![feature(custom_derive)]

extern crate hyper;
extern crate rustc_serialize;
extern crate scoped_threadpool;
extern crate csv;

use std::fs;
use std::sync::Arc;
use std::path::Path;
use std::fs::File;
use std::io::{Read, Write};
use std::collections::{HashSet, HashMap};

use hyper::client::{Client, Response, RequestBuilder};
use hyper::header::{Accept, Connection, qitem};
use hyper::mime::{Mime, TopLevel, SubLevel};

use rustc_serialize::json;

use scoped_threadpool::Pool;

#[derive(Clone)]
struct MyClient {
    client : Arc<Client>,
    app_id : String,
    app_key : String,
    cache_dir : String,
}

#[derive(Clone, Debug, RustcDecodable)]
struct Line {
    id : String,
    name : String,
    modeName : String,
    routeSections : Vec<RouteSection>,
    stops : Option<Vec<Stop>>,
}

#[derive(Clone, Debug, RustcDecodable)]
struct Stop {
    naptanId : String,
    commonName : String,
    lat : f64,
    lon : f64,
}

#[derive(Clone, Debug, RustcDecodable)]
struct RouteSection {
    name : String,
    direction : String,
    originator : String,
    destination : String,
    timetable : Option<TimeTable>,
}

#[derive(Clone, Debug, RustcDecodable)]
struct Interval {
    stopId : String,
    timeToArrival: f64,
}

#[derive(Clone, Debug, RustcDecodable)]
struct StationInterval {
    id : i64,
    intervals : Vec<Interval>
}

#[derive(Clone, Debug, RustcDecodable)]
struct KnownJourney {
    intervalId : i64,
    hour : String,
    minute : String,
}

#[derive(Clone, Debug, RustcDecodable)]
struct Schedule {
    name : String,
    knownJourneys : Vec<KnownJourney>,
}

#[derive(Clone, Debug, RustcDecodable)]
struct TimeTable {
    stationIntervals : Vec<StationInterval>,
    schedules : Vec<Schedule>,
}

#[derive(Clone, Debug, RustcDecodable)]
struct RoutesTimeTables {
    routes : Vec<TimeTable>,
}

#[derive(Debug, RustcDecodable)]
struct TimeTableResponse {
    timetable : RoutesTimeTables,
}

impl MyClient {
    fn new() -> MyClient {
        let cachePath : &Path = Path::new("./cache");
        fs::create_dir(cachePath);
        return MyClient{
            client : Arc::new(Client::new()),
            app_id : String::new(),
            app_key : String::new(),
            cache_dir : String::from("./cache"),
        }
    }

    fn get(&self, endpoint : &str) -> String {
        match self.cache_get(endpoint) {
            Some(body) => body,
            None => self.remote_get(endpoint)
        }
    }

    fn remote_get(&self, endpoint : &str) -> String {
        let req_uri = format!("https://api.tfl.gov.uk{}?app_id={}&app_key={}", endpoint, self.app_id, self.app_key);
        let mut body = String::new();
        let mut resp = self.client.get(&req_uri)
            .header(Accept(vec![
                qitem(Mime(TopLevel::Application,
                    SubLevel::Ext("json".to_owned()), vec![])),
            ]))
            .send().unwrap();
        resp.read_to_string(&mut body).unwrap();
        self.cache_put(endpoint, body)
    }

    fn cache_fname(&self, endpoint : &str) -> String {
        let fname = String::from(endpoint);
        let fname0 = fname.replace("/", "_");
        self.cache_dir.clone() + "/" + &fname0
    }

    fn cache_put(&self, endpoint : &str, body : String) -> String {
        let mut f = File::create(self.cache_fname(endpoint)).unwrap();
        f.write_all(body.as_bytes());
        body
    }

    fn cache_get(&self, endpoint : &str) -> Option<String> {
        let mut body = String::new();
        match File::open(self.cache_fname(endpoint)) {
            Ok(ref mut f) => {
                f.read_to_string(&mut body);
                Some(body)
            },
            Err(_) => None,
        }
    }
}

fn get_lines(client : &MyClient) -> Vec<Line> {
    let body = client.get("/line/route");
    json::decode(&body).unwrap()
}

fn get_timetable(client : &MyClient, line_id : &str, originator: &str, destination : &str) -> Option<TimeTable> {
    let req_uri = format!("/line/{}/timetable/{}/to/{}", line_id, originator, destination);
    let body = client.get(&req_uri);
    match json::decode::<TimeTableResponse>(&body) {
        Ok(ttresp) =>  Some(ttresp.timetable.routes[0].clone()),
        Err(err) => {
            println!("Error decoding timetable {}", err);
            None
        },
    }
}

fn get_stops(client : &MyClient, line_id : &str) -> Vec<Stop> {
    let req_uri = format!("/line/{}/stoppoints", line_id);
    let body = client.get(&req_uri);
    match json::decode::<Vec<Stop>>(&body) {
        Ok(stops) => stops,
        Err(err) => {
            println!("Error decoding stops: {}", err);
            Vec::<Stop>::new()
        }
    }
}

fn route_section_id(line : &Line, section : &RouteSection) -> String {
    return line.id.clone() + " " + &section.originator + " to " + &section.destination;
}

fn write_agency(gtfs_path : &str) {
    let fname = format!("{}/{}", gtfs_path, "/agency.txt");
    let fpath = Path::new(&fname);
    let mut wtr = csv::Writer::from_file(fpath).unwrap();
    let records = vec![
        ("agency_id","agency_name","agency_url","agency_timezone"),
        ("tfl","Transport For London","https://tfl.gov.uk","Europe/London")
    ];
    for record in records {
        wtr.encode(record);
    }
}

fn route_type(line : &Line) -> &'static str {
    match &line.modeName[..] {
        "dlr" | "tram" => "0",
        "tube" | "overground" => "1",
        "national-rail" | "tflrail" => "2",
        "bus" => "3",
        "river-tour" | "river-bus" => "4",
        "cable-car" => "5",
        _ => {
            println!("Missing line modeName match: {}", line.modeName);
            ""
        },
    }
}

fn write_routes(gtfs_path : &str, lines : &Vec<Line>) {
    let fname = format!("{}/{}", gtfs_path, "/routes.txt");
    let fpath = Path::new(&fname);
    let mut wtr = csv::Writer::from_file(fpath).unwrap();
    wtr.encode(("route_id", "agency_id", "route_short_name", "route_long_name", "route_type"));
    for line in lines {
        wtr.encode((&line.id, "tfl", &line.name, "", route_type(&line)));
    }
}

fn write_stops(gtfs_path : &str, lines : &Vec<Line>) {
    let fname = format!("{}/{}", gtfs_path, "/stops.txt");
    let fpath = Path::new(&fname);
    let mut wtr = csv::Writer::from_file(fpath).unwrap();
    let mut written_stops = HashSet::<String>::new();
    wtr.encode(("stop_id", "stop_name", "stop_lat", "stop_lon"));
    for line in lines {
        let stops = line.stops.as_ref().unwrap();
        for stop in stops {
            match written_stops.contains(&stop.naptanId) {
                true => (),
                false => {
                    wtr.encode((stop.naptanId.clone(), stop.commonName.clone(), stop.lat, stop.lon));
                    written_stops.insert(stop.naptanId.clone());
                },
            };
        }
    }
}

fn write_calendar(gtfs_path : &str) {
}

fn trip_id(line : &Line, section : &RouteSection, schedule : &Schedule, journey : &KnownJourney) -> String {
    return line.id.clone() + " " + &section.originator + " to " + &section.destination + " scheduled " + &schedule.name + " departing " + &journey.hour + ":" + &journey.minute;
}

fn write_route_section_trips(wtr : &mut csv::Writer<File>, line : &Line, section : &RouteSection) {
    match section.timetable.as_ref() {
        None => (),
        Some(timetable) => {
            for schedule in &timetable.schedules {
                for journey in &schedule.knownJourneys {
                    wtr.encode((&line.id, &schedule.name, trip_id(line, section, schedule, journey)));
                }
            }
        },
    }
}

fn write_trips(gtfs_path : &str, lines : &Vec<Line>) {
    let fname = format!("{}/{}", gtfs_path, "/trips.txt");
    let fpath = Path::new(&fname);
    let mut wtr = csv::Writer::from_file(fpath).unwrap();
    let mut written_stops = HashSet::<String>::new();
    wtr.encode(("route_id", "service_id", "trip_id"));
    for line in lines {
        let mut written_route_sections = HashSet::<String>::new();
        let route_sections = &line.routeSections;
        for route_section in route_sections {
            let id = route_section_id(line, route_section);
            match written_route_sections.contains(&id) {
                true => (),
                false => {
                    write_route_section_trips(&mut wtr, line, route_section);
                    written_route_sections.insert(id);
                },
            };
        }
    }
}

fn time_offset_fmt(journey : &KnownJourney, offset : f64) -> String {
    String::new()
}

fn write_journey_stop_times(wtr : &mut csv::Writer<File>, line : &Line, section : &RouteSection, schedule : &Schedule, journey : &KnownJourney, interval : &StationInterval) {
    let mut stop_seq = 1;
    let trip_id = trip_id(line, section, schedule, journey);
    wtr.encode((&trip_id, &section.originator, stop_seq, time_offset_fmt(journey, 0.0)));
    for stop in &interval.intervals {
        stop_seq += 1;
        wtr.encode((&trip_id, &stop.stopId, stop_seq, time_offset_fmt(journey, stop.timeToArrival)));
    }
}

fn write_route_section_stop_times(wtr : &mut csv::Writer<File>, line : &Line, section : &RouteSection) {
    match section.timetable.as_ref() {
        None => (),
        Some(timetable) => {
            let mut intervals : HashMap<i64, &StationInterval> = HashMap::new();
            for interval in &timetable.stationIntervals {
                intervals.insert(interval.id, interval);
            }
            for schedule in &timetable.schedules {
                for journey in &schedule.knownJourneys {
                    match intervals.get(&journey.intervalId) {
                        Some(interval) => write_journey_stop_times(wtr, line, section, schedule, journey, interval),
                        None => println!("Error, Could not find interval for schedule!!!!"),
                    };
                }
            };
        },
    }

}

fn write_stop_times(gtfs_path : &str, lines : &Vec<Line>) {
    let fname = format!("{}/{}", gtfs_path, "/stop_times.txt");
    let fpath = Path::new(&fname);
    let mut wtr = csv::Writer::from_file(fpath).unwrap();
    let mut written_stops = HashSet::<String>::new();
    wtr.encode(("trip_id", "stop_id", "stop_sequence", "arrival_time", "departure_time"));
    for line in lines {
        let mut written_route_sections = HashSet::<String>::new();
        let route_sections = &line.routeSections;
        for route_section in route_sections {
            let id = route_section_id(line, route_section);
            match written_route_sections.contains(&id) {
                true => (),
                false => {
                    write_route_section_stop_times(&mut wtr, line, route_section);
                    written_route_sections.insert(id);
                },
            };
        }
    }
}

fn write_gtfs(lines : &Vec<Line>) {
        let gtfs_path : &Path = Path::new("./gtfs");
        let gtfs_path_str = gtfs_path.to_str().unwrap();
        fs::create_dir(gtfs_path_str);
        write_agency(gtfs_path_str);
        write_routes(gtfs_path_str, lines);
        write_stops(gtfs_path_str, lines);
        write_calendar(gtfs_path_str);
        write_trips(gtfs_path_str, lines);
        write_stop_times(gtfs_path_str, lines);
}

fn main() {
    // Fetch data
    let client = Arc::new(MyClient::new());
    let mut lines = get_lines(&client);
    let mut pool = Pool::new(10);

    pool.scoped(|scope| {
        for line in &mut lines {
            let client = client.clone();
            scope.execute(move || {
                line.stops = Some(get_stops(&client, &line.id));
                for route_section in &mut line.routeSections {
                    println!("Getting Timetable for Line: {}, Route Section: {} ...", line.name, route_section.name);
                    route_section.timetable = get_timetable(&client, &line.id, &route_section.originator, &route_section.destination);
                }
            });
        }
    });

    // Generate a report
    let mut line_count = 0;
    let mut line_ids : HashSet<String> = HashSet::new();
    let mut route_section_count = 0;
    let mut route_section_ids: HashSet<String> = HashSet::new();
    let mut schedule_names: HashSet<String> = HashSet::new();
    for line in &lines {
        println!("{}, Duplicate: {}", line.id, line_ids.contains(&line.id));
        for route_section in &line.routeSections {
            let has_timetable = match route_section.timetable {
                Some(ref timetable) => {
                    for schedule in &timetable.schedules {
                        schedule_names.insert(schedule.name.clone());
                    }
                    true
                },
                None => false,
            };
            let id = route_section_id(&line, &route_section);
            println!("\t{}, Has Timetable: {}, Duplicate: {}", id, has_timetable, route_section_ids.contains(&id));
            route_section_ids.insert(id.clone());
            route_section_count += 1;
        }
        line_count += 1;
        line_ids.insert(line.id.clone());
    }
    println!("Duplicate Lines: {}, Duplicate Route Sections: {}", line_count-line_ids.len(), route_section_count-route_section_ids.len());

    println!("Schedule Names:");
    for schedule_name in &schedule_names {
        println!("\t{}", schedule_name);
    }

    // Generate CSV files from fetched data
    write_gtfs(&lines);
}
<commit_msg>Correctly output arrival/departure times<commit_after>#![feature(custom_derive)]

extern crate hyper;
extern crate rustc_serialize;
extern crate scoped_threadpool;
extern crate csv;

use std::fs;
use std::sync::Arc;
use std::path::Path;
use std::fs::File;
use std::io::{Read, Write};
use std::collections::{HashSet, HashMap};

use hyper::client::{Client, Response, RequestBuilder};
use hyper::header::{Accept, Connection, qitem};
use hyper::mime::{Mime, TopLevel, SubLevel};

use rustc_serialize::json;

use scoped_threadpool::Pool;

#[derive(Clone)]
struct MyClient {
    client : Arc<Client>,
    app_id : String,
    app_key : String,
    cache_dir : String,
}

#[derive(Clone, Debug, RustcDecodable)]
struct Line {
    id : String,
    name : String,
    modeName : String,
    routeSections : Vec<RouteSection>,
    stops : Option<Vec<Stop>>,
}

#[derive(Clone, Debug, RustcDecodable)]
struct Stop {
    naptanId : String,
    commonName : String,
    lat : f64,
    lon : f64,
}

#[derive(Clone, Debug, RustcDecodable)]
struct RouteSection {
    name : String,
    direction : String,
    originator : String,
    destination : String,
    timetable : Option<TimeTable>,
}

#[derive(Clone, Debug, RustcDecodable)]
struct Interval {
    stopId : String,
    timeToArrival: f64,
}

#[derive(Clone, Debug, RustcDecodable)]
struct StationInterval {
    id : i64,
    intervals : Vec<Interval>
}

#[derive(Clone, Debug, RustcDecodable)]
struct KnownJourney {
    intervalId : i64,
    hour : String,
    minute : String,
}

#[derive(Clone, Debug, RustcDecodable)]
struct Schedule {
    name : String,
    knownJourneys : Vec<KnownJourney>,
}

#[derive(Clone, Debug, RustcDecodable)]
struct TimeTable {
    stationIntervals : Vec<StationInterval>,
    schedules : Vec<Schedule>,
}

#[derive(Clone, Debug, RustcDecodable)]
struct RoutesTimeTables {
    routes : Vec<TimeTable>,
}

#[derive(Debug, RustcDecodable)]
struct TimeTableResponse {
    timetable : RoutesTimeTables,
}

impl MyClient {
    fn new() -> MyClient {
        let cachePath : &Path = Path::new("./cache");
        fs::create_dir(cachePath);
        return MyClient{
            client : Arc::new(Client::new()),
            app_id : String::new(),
            app_key : String::new(),
            cache_dir : String::from("./cache"),
        }
    }

    fn get(&self, endpoint : &str) -> String {
        match self.cache_get(endpoint) {
            Some(body) => body,
            None => self.remote_get(endpoint)
        }
    }

    fn remote_get(&self, endpoint : &str) -> String {
        let req_uri = format!("https://api.tfl.gov.uk{}?app_id={}&app_key={}", endpoint, self.app_id, self.app_key);
        let mut body = String::new();
        let mut resp = self.client.get(&req_uri)
            .header(Accept(vec![
                qitem(Mime(TopLevel::Application,
                    SubLevel::Ext("json".to_owned()), vec![])),
            ]))
            .send().unwrap();
        resp.read_to_string(&mut body).unwrap();
        self.cache_put(endpoint, body)
    }

    fn cache_fname(&self, endpoint : &str) -> String {
        let fname = String::from(endpoint);
        let fname0 = fname.replace("/", "_");
        self.cache_dir.clone() + "/" + &fname0
    }

    fn cache_put(&self, endpoint : &str, body : String) -> String {
        let mut f = File::create(self.cache_fname(endpoint)).unwrap();
        f.write_all(body.as_bytes());
        body
    }

    fn cache_get(&self, endpoint : &str) -> Option<String> {
        let mut body = String::new();
        match File::open(self.cache_fname(endpoint)) {
            Ok(ref mut f) => {
                f.read_to_string(&mut body);
                Some(body)
            },
            Err(_) => None,
        }
    }
}

fn get_lines(client : &MyClient) -> Vec<Line> {
    let body = client.get("/line/route");
    json::decode(&body).unwrap()
}

fn get_timetable(client : &MyClient, line_id : &str, originator: &str, destination : &str) -> Option<TimeTable> {
    let req_uri = format!("/line/{}/timetable/{}/to/{}", line_id, originator, destination);
    let body = client.get(&req_uri);
    match json::decode::<TimeTableResponse>(&body) {
        Ok(ttresp) =>  Some(ttresp.timetable.routes[0].clone()),
        Err(err) => {
            println!("Error decoding timetable {}", err);
            None
        },
    }
}

fn get_stops(client : &MyClient, line_id : &str) -> Vec<Stop> {
    let req_uri = format!("/line/{}/stoppoints", line_id);
    let body = client.get(&req_uri);
    match json::decode::<Vec<Stop>>(&body) {
        Ok(stops) => stops,
        Err(err) => {
            println!("Error decoding stops: {}", err);
            Vec::<Stop>::new()
        }
    }
}

fn route_section_id(line : &Line, section : &RouteSection) -> String {
    return line.id.clone() + " " + &section.originator + " to " + &section.destination;
}

fn write_agency(gtfs_path : &str) {
    let fname = format!("{}/{}", gtfs_path, "/agency.txt");
    let fpath = Path::new(&fname);
    let mut wtr = csv::Writer::from_file(fpath).unwrap();
    let records = vec![
        ("agency_id","agency_name","agency_url","agency_timezone"),
        ("tfl","Transport For London","https://tfl.gov.uk","Europe/London")
    ];
    for record in records {
        wtr.encode(record);
    }
}

fn route_type(line : &Line) -> &'static str {
    match &line.modeName[..] {
        "dlr" | "tram" => "0",
        "tube" | "overground" => "1",
        "national-rail" | "tflrail" => "2",
        "bus" => "3",
        "river-tour" | "river-bus" => "4",
        "cable-car" => "5",
        _ => {
            println!("Missing line modeName match: {}", line.modeName);
            ""
        },
    }
}

fn write_routes(gtfs_path : &str, lines : &Vec<Line>) {
    let fname = format!("{}/{}", gtfs_path, "/routes.txt");
    let fpath = Path::new(&fname);
    let mut wtr = csv::Writer::from_file(fpath).unwrap();
    wtr.encode(("route_id", "agency_id", "route_short_name", "route_long_name", "route_type"));
    for line in lines {
        wtr.encode((&line.id, "tfl", &line.name, "", route_type(&line)));
    }
}

fn write_stops(gtfs_path : &str, lines : &Vec<Line>) {
    let fname = format!("{}/{}", gtfs_path, "/stops.txt");
    let fpath = Path::new(&fname);
    let mut wtr = csv::Writer::from_file(fpath).unwrap();
    let mut written_stops = HashSet::<String>::new();
    wtr.encode(("stop_id", "stop_name", "stop_lat", "stop_lon"));
    for line in lines {
        let stops = line.stops.as_ref().unwrap();
        for stop in stops {
            match written_stops.contains(&stop.naptanId) {
                true => (),
                false => {
                    wtr.encode((stop.naptanId.clone(), stop.commonName.clone(), stop.lat, stop.lon));
                    written_stops.insert(stop.naptanId.clone());
                },
            };
        }
    }
}

fn write_calendar(gtfs_path : &str) {
}

fn trip_id(line : &Line, section : &RouteSection, schedule : &Schedule, journey : &KnownJourney) -> String {
    return line.id.clone() + " " + &section.originator + " to " + &section.destination + " scheduled " + &schedule.name + " departing " + &journey.hour + ":" + &journey.minute;
}

fn write_route_section_trips(wtr : &mut csv::Writer<File>, line : &Line, section : &RouteSection) {
    match section.timetable.as_ref() {
        None => (),
        Some(timetable) => {
            for schedule in &timetable.schedules {
                for journey in &schedule.knownJourneys {
                    wtr.encode((&line.id, &schedule.name, trip_id(line, section, schedule, journey)));
                }
            }
        },
    }
}

fn write_trips(gtfs_path : &str, lines : &Vec<Line>) {
    let fname = format!("{}/{}", gtfs_path, "/trips.txt");
    let fpath = Path::new(&fname);
    let mut wtr = csv::Writer::from_file(fpath).unwrap();
    let mut written_stops = HashSet::<String>::new();
    wtr.encode(("route_id", "service_id", "trip_id"));
    for line in lines {
        let mut written_route_sections = HashSet::<String>::new();
        let route_sections = &line.routeSections;
        for route_section in route_sections {
            let id = route_section_id(line, route_section);
            match written_route_sections.contains(&id) {
                true => (),
                false => {
                    write_route_section_trips(&mut wtr, line, route_section);
                    written_route_sections.insert(id);
                },
            };
        }
    }
}
fn time_offset_fmt(journey : &KnownJourney, offset : f64) -> String {
    let dep_hour : u64 = journey.hour.parse().unwrap();
    let dep_minute : u64 = journey.minute.parse().unwrap();
    let rounded_offset : u64 = offset.floor() as u64;
    let minute_offset : u64 = dep_minute + rounded_offset;
    let hour : u64 = dep_hour + minute_offset / 60;
    let minute : u64 = minute_offset % 60;
    format!("{:02}:{:02}", hour, minute)
}

fn write_journey_stop_times(wtr : &mut csv::Writer<File>, line : &Line, section : &RouteSection, schedule : &Schedule, journey : &KnownJourney, interval : &StationInterval) {
    let mut stop_seq = 1;
    let trip_id = trip_id(line, section, schedule, journey);
    let dep_time = time_offset_fmt(journey, 0.0);
    wtr.encode((&trip_id, &section.originator, stop_seq, &dep_time, &dep_time));
    for stop in &interval.intervals {
        stop_seq += 1;
        let dep_time = time_offset_fmt(journey, stop.timeToArrival);
        wtr.encode((&trip_id, &stop.stopId, stop_seq, &dep_time, &dep_time));
    }
}

fn write_route_section_stop_times(wtr : &mut csv::Writer<File>, line : &Line, section : &RouteSection) {
    match section.timetable.as_ref() {
        None => (),
        Some(timetable) => {
            let mut intervals : HashMap<i64, &StationInterval> = HashMap::new();
            for interval in &timetable.stationIntervals {
                intervals.insert(interval.id, interval);
            }
            for schedule in &timetable.schedules {
                for journey in &schedule.knownJourneys {
                    match intervals.get(&journey.intervalId) {
                        Some(interval) => write_journey_stop_times(wtr, line, section, schedule, journey, interval),
                        None => println!("Error, Could not find interval for schedule!!!!"),
                    };
                }
            };
        },
    }

}

fn write_stop_times(gtfs_path : &str, lines : &Vec<Line>) {
    let fname = format!("{}/{}", gtfs_path, "/stop_times.txt");
    let fpath = Path::new(&fname);
    let mut wtr = csv::Writer::from_file(fpath).unwrap();
    let mut written_stops = HashSet::<String>::new();
    wtr.encode(("trip_id", "stop_id", "stop_sequence", "arrival_time", "departure_time"));
    for line in lines {
        let mut written_route_sections = HashSet::<String>::new();
        let route_sections = &line.routeSections;
        for route_section in route_sections {
            let id = route_section_id(line, route_section);
            match written_route_sections.contains(&id) {
                true => (),
                false => {
                    write_route_section_stop_times(&mut wtr, line, route_section);
                    written_route_sections.insert(id);
                },
            };
        }
    }
}

fn write_gtfs(lines : &Vec<Line>) {
        let gtfs_path : &Path = Path::new("./gtfs");
        let gtfs_path_str = gtfs_path.to_str().unwrap();
        fs::create_dir(gtfs_path_str);
        write_agency(gtfs_path_str);
        write_routes(gtfs_path_str, lines);
        write_stops(gtfs_path_str, lines);
        write_calendar(gtfs_path_str);
        write_trips(gtfs_path_str, lines);
        write_stop_times(gtfs_path_str, lines);
}

fn main() {
    // Fetch data
    let client = Arc::new(MyClient::new());
    let mut lines = get_lines(&client);
    let mut pool = Pool::new(10);

    pool.scoped(|scope| {
        for line in &mut lines {
            let client = client.clone();
            scope.execute(move || {
                line.stops = Some(get_stops(&client, &line.id));
                for route_section in &mut line.routeSections {
                    println!("Getting Timetable for Line: {}, Route Section: {} ...", line.name, route_section.name);
                    route_section.timetable = get_timetable(&client, &line.id, &route_section.originator, &route_section.destination);
                }
            });
        }
    });

    // Generate a report
    let mut line_count = 0;
    let mut line_ids : HashSet<String> = HashSet::new();
    let mut route_section_count = 0;
    let mut route_section_ids: HashSet<String> = HashSet::new();
    let mut schedule_names: HashSet<String> = HashSet::new();
    for line in &lines {
        println!("{}, Duplicate: {}", line.id, line_ids.contains(&line.id));
        for route_section in &line.routeSections {
            let has_timetable = match route_section.timetable {
                Some(ref timetable) => {
                    for schedule in &timetable.schedules {
                        schedule_names.insert(schedule.name.clone());
                    }
                    true
                },
                None => false,
            };
            let id = route_section_id(&line, &route_section);
            println!("\t{}, Has Timetable: {}, Duplicate: {}", id, has_timetable, route_section_ids.contains(&id));
            route_section_ids.insert(id.clone());
            route_section_count += 1;
        }
        line_count += 1;
        line_ids.insert(line.id.clone());
    }
    println!("Duplicate Lines: {}, Duplicate Route Sections: {}", line_count-line_ids.len(), route_section_count-route_section_ids.len());

    println!("Schedule Names:");
    for schedule_name in &schedule_names {
        println!("\t{}", schedule_name);
    }

    // Generate CSV files from fetched data
    write_gtfs(&lines);
}
<|endoftext|>


<commit_before>//
// main.rs
// Copyright (C) 2017 Szymon Urbaś <szymon.urbas@aol.com>
// Distributed under terms of the BSD (2-clause) license.
//
// Created on: 13 Mar 2017 21:03:41 +0100 (CET)
//

extern crate rand;
extern crate cursive;

#[cfg(feature = "go-slow")]
use std::thread;
#[cfg(feature = "go-slow")]
use std::time;

mod process;
mod scheduler;
mod fcfs;
mod round_robin;
mod tui;

use scheduler::*;
use tui::*;

/// Length of a single system clock tick (frequency of actual, real time)
#[cfg(feature = "go-slow")]
const CLOCK_HZ: u64 = 1000;
/// Switch context every <value> clock ticks
const SYSTEM_HZ: usize = 8;

fn main() {
  let mut tui = tui::new();

  let scenarios = {
    (0..20).map(|_| (0..64).map(|_| rand::random::<usize>() % (SYSTEM_HZ * 4) + 1).collect::<Vec<usize>>()).collect::<Vec<Vec<usize>>>()
  };

  macro_rules! run_simulation_suite {
    ($scheduler:ident) => ({
      let mut average_waiting_time = 0f64;

      for (run, scenario) in scenarios.iter().enumerate() {
        let scheduler = $scheduler::new();
        let avg = run_simulation(&mut tui, scheduler, scenario.clone());
        tui.add_result(format!("{}: #{:02}: Average waiting time: {:02.2}", stringify!($scheduler), run, avg));

        average_waiting_time -= average_waiting_time / (run + 1) as f64;
        average_waiting_time += avg / (run + 1) as f64;
      }

      tui.add_result(format!("{}: Overall average: {:02.2}", stringify!($scheduler), average_waiting_time));
    })
  }

  run_simulation_suite!(fcfs);
  run_simulation_suite!(round_robin);

  tui.update();

  loop {}
}

fn run_simulation<S>(mut tui: &mut Tui, mut scheduler: S, mut process_list: Vec<usize>) -> f64
where S: Scheduler {
  let mut clock_tick = 0;
  let mut process_spawner = process::new_spawner();
  let mut average_waiting_time = 0f64;
  let mut num_of_spawned_procs = 1;

  tui.set_header(format!("Using algorithm: {}", scheduler.name()));
  tui.debug(format!("{:05}: Starting simulation using {}", clock_tick, scheduler.name()));

  // vectors only support the pop (from the back) operation so
  // reverse it (so we pop from the front)
  process_list.reverse();

  // Add the equivalent of the 'init' process
  scheduler.add_process(process_spawner.spawn(process_list.pop().unwrap()));

  loop {
    if cfg!(feature = "go-slow") || clock_tick % (SYSTEM_HZ * 2) == 0 {
      // update the process view
      scheduler.list_processes(&mut tui);
      // update all the views
      tui.update();
    }

    if !scheduler.has_processes() {
      // if there's no more processes - end the simulation
      // if a process can only be created by another process - there's
      // nothing else to do
      break;
    }

    // simulate executing the current process
    tui.debug(format!("{:05}: Executing {}", clock_tick, scheduler.current_proc().unwrap().name));
    scheduler.current_proc_mut().unwrap().record_execution();

    // Simulate other processes creating new processes
    // Assume that you can't create new processes, if there's none already
    if clock_tick % SYSTEM_HZ == 0 {
      if let Some(burst_time) = process_list.pop() {
        let new_proc = process_spawner.spawn(burst_time);
        tui.debug(format!("{:05}: Spawning {}", clock_tick, new_proc.name));
        scheduler.add_process(new_proc);
        num_of_spawned_procs += 1;
      }
    }

    if scheduler.current_proc().unwrap().done_executing() {
      tui.debug(format!("{:05}: Killing process {}", clock_tick, scheduler.current_proc().unwrap().name));
      scheduler.kill_current_proc();
    }

    if scheduler.has_processes() {
      if clock_tick % SYSTEM_HZ == SYSTEM_HZ - 1 {
        let prev_proc_name = scheduler.current_proc().unwrap().name.clone();
        scheduler.schedule();
        tui.debug(format!("{:05}: Switching context: {} -> {}", clock_tick, prev_proc_name, scheduler.current_proc().unwrap().name));
        tui.debug(format!("{:05}: {} was waiting {} clock ticks", clock_tick, scheduler.current_proc().unwrap().name, scheduler.current_proc().unwrap().waiting_time));

        average_waiting_time -= average_waiting_time / num_of_spawned_procs as f64;
        average_waiting_time += scheduler.current_proc().unwrap().waiting_time as f64 / num_of_spawned_procs as f64;
      }

      // increase the waiting time for every process
      scheduler.increase_waiting_times();
    }

    #[cfg(feature = "go-slow")]
    thread::sleep(time::Duration::from_millis(1000 / CLOCK_HZ));

    clock_tick += 1;
  }

  average_waiting_time
}

/*
 * vi: ts=2 sw=2 expandtab
 */

<commit_msg>Update the process list view on every clock tick<commit_after>//
// main.rs
// Copyright (C) 2017 Szymon Urbaś <szymon.urbas@aol.com>
// Distributed under terms of the BSD (2-clause) license.
//
// Created on: 13 Mar 2017 21:03:41 +0100 (CET)
//

extern crate rand;
extern crate cursive;

#[cfg(feature = "go-slow")]
use std::thread;
#[cfg(feature = "go-slow")]
use std::time;

mod process;
mod scheduler;
mod fcfs;
mod round_robin;
mod tui;

use scheduler::*;
use tui::*;

/// Length of a single system clock tick (frequency of actual, real time)
#[cfg(feature = "go-slow")]
const CLOCK_HZ: u64 = 1000;
/// Switch context every <value> clock ticks
const SYSTEM_HZ: usize = 8;

fn main() {
  let mut tui = tui::new();

  let scenarios = {
    (0..20).map(|_| (0..64).map(|_| rand::random::<usize>() % (SYSTEM_HZ * 4) + 1).collect::<Vec<usize>>()).collect::<Vec<Vec<usize>>>()
  };

  macro_rules! run_simulation_suite {
    ($scheduler:ident) => ({
      let mut average_waiting_time = 0f64;

      for (run, scenario) in scenarios.iter().enumerate() {
        let scheduler = $scheduler::new();
        let avg = run_simulation(&mut tui, scheduler, scenario.clone());
        tui.add_result(format!("{}: #{:02}: Average waiting time: {:02.2}", stringify!($scheduler), run, avg));

        average_waiting_time -= average_waiting_time / (run + 1) as f64;
        average_waiting_time += avg / (run + 1) as f64;
      }

      tui.add_result(format!("{}: Overall average: {:02.2}", stringify!($scheduler), average_waiting_time));
    })
  }

  run_simulation_suite!(fcfs);
  run_simulation_suite!(round_robin);

  tui.update();

  loop {}
}

fn run_simulation<S>(mut tui: &mut Tui, mut scheduler: S, mut process_list: Vec<usize>) -> f64
where S: Scheduler {
  let mut clock_tick = 0;
  let mut process_spawner = process::new_spawner();
  let mut average_waiting_time = 0f64;
  let mut num_of_spawned_procs = 1;

  tui.set_header(format!("Using algorithm: {}", scheduler.name()));
  tui.debug(format!("{:05}: Starting simulation using {}", clock_tick, scheduler.name()));

  // vectors only support the pop (from the back) operation so
  // reverse it (so we pop from the front)
  process_list.reverse();

  // Add the equivalent of the 'init' process
  scheduler.add_process(process_spawner.spawn(process_list.pop().unwrap()));

  loop {
    // update the process view
    scheduler.list_processes(&mut tui);

    if cfg!(feature = "go-slow") || clock_tick % (SYSTEM_HZ * 2) == 0 {
      // update all the views
      tui.update();
    }

    if !scheduler.has_processes() {
      // if there's no more processes - end the simulation
      // if a process can only be created by another process - there's
      // nothing else to do
      break;
    }

    // simulate executing the current process
    tui.debug(format!("{:05}: Executing {}", clock_tick, scheduler.current_proc().unwrap().name));
    scheduler.current_proc_mut().unwrap().record_execution();

    // Simulate other processes creating new processes
    // Assume that you can't create new processes, if there's none already
    if clock_tick % SYSTEM_HZ == 0 {
      if let Some(burst_time) = process_list.pop() {
        let new_proc = process_spawner.spawn(burst_time);
        tui.debug(format!("{:05}: Spawning {}", clock_tick, new_proc.name));
        scheduler.add_process(new_proc);
        num_of_spawned_procs += 1;
      }
    }

    if scheduler.current_proc().unwrap().done_executing() {
      tui.debug(format!("{:05}: Killing process {}", clock_tick, scheduler.current_proc().unwrap().name));
      scheduler.kill_current_proc();
    }

    if scheduler.has_processes() {
      if clock_tick % SYSTEM_HZ == SYSTEM_HZ - 1 {
        let prev_proc_name = scheduler.current_proc().unwrap().name.clone();
        scheduler.schedule();
        tui.debug(format!("{:05}: Switching context: {} -> {}", clock_tick, prev_proc_name, scheduler.current_proc().unwrap().name));
        tui.debug(format!("{:05}: {} was waiting {} clock ticks", clock_tick, scheduler.current_proc().unwrap().name, scheduler.current_proc().unwrap().waiting_time));

        average_waiting_time -= average_waiting_time / num_of_spawned_procs as f64;
        average_waiting_time += scheduler.current_proc().unwrap().waiting_time as f64 / num_of_spawned_procs as f64;
      }

      // increase the waiting time for every process
      scheduler.increase_waiting_times();
    }

    #[cfg(feature = "go-slow")]
    thread::sleep(time::Duration::from_millis(1000 / CLOCK_HZ));

    clock_tick += 1;
  }

  average_waiting_time
}

/*
 * vi: ts=2 sw=2 expandtab
 */

<|endoftext|>


<commit_before>use macroquad::prelude::*;

use colour::Colour;
use graph::{Graph, Position};
use grid::Grid;

mod colour;
mod graph;
mod grid;

fn macroquad_colour(colour: Colour) -> Color {
    match colour {
        Colour::Red => color_u8!(255, 0, 0, 255),
        Colour::Yellow => color_u8!(255, 255, 0, 255),
        Colour::Green => color_u8!(0, 176, 0, 255),
        Colour::LightBrown => color_u8!(255, 204, 102, 255),
        Colour::Purple => color_u8!(128, 0, 128, 255),
        Colour::Cyan => color_u8!(0, 255, 255, 255),
        Colour::Blue => color_u8!(0, 0, 255, 255),
        Colour::Fuchsia => color_u8!(255, 0, 255, 255),
    }
}

fn draw_cell(grid_x: f32, grid_y: f32, cell_size: f32, position: &Position, colour: Colour) {
    let color = macroquad_colour(colour);
    draw_rectangle(
        grid_x + cell_size * position.column as f32,
        grid_y + cell_size * position.row as f32,
        cell_size,
        cell_size,
        color,
    );
}

struct Ui {
    /// Size of the grid in cells.
    size: usize,

    /// Size of the grid in pixels.  Assumes the grid is always square.
    grid_size: f32,

    /// Offset of the grid relative to the whole window along the horizontal axis.
    grid_x: f32,

    /// Offset of the grid relative to the whole window along the vertical axis.
    grid_y: f32,
}

impl Ui {
    fn create(size: usize) -> Ui {
        let mut ui = Ui {
            size,
            grid_size: 0.0,
            grid_x: 0.0,
            grid_y: 0.0,
        };

        ui.resize();

        ui
    }

    fn resize(&mut self) {
        let screen_height = screen_height();
        let screen_width = screen_width();

        let grid_size = screen_height.min(screen_width);
        self.grid_size = grid_size;
        self.grid_x = (screen_width - grid_size) / 2.0;
        self.grid_y = (screen_height - grid_size) / 2.0;
    }

    fn render(&self, graph: &Graph) {
        clear_background(BLACK);

        let grid_x = self.grid_x;
        let grid_y = self.grid_y;
        let cell_size = self.cell_size();

        for component in graph.neighbours.keys() {
            for position in &graph.components[component].cells {
                draw_cell(grid_x, grid_y, cell_size, position, graph.components[component].colour);
            }
        }
    }

    fn cell_size(&self) -> f32 {
        self.grid_size / self.size as f32
    }

    fn cell_position(&self, raw_position: (f32, f32)) -> Option<Position> {
        let (raw_x, raw_y) = raw_position;

        let cell_size = self.cell_size();
        let x = (raw_x - self.grid_x) / cell_size;
        let y = (raw_y - self.grid_y) / cell_size;

        let size = self.size as f32;
        if x < 0.0 || y < 0.0 || x > size || y > size {
            // Out of bounds, nothing to do
            None
        } else {
            Some(Position{column: x.floor() as usize, row: y.floor() as usize})
        }
    }

    fn handle_click(&self, graph: &mut Graph) {
        if !is_mouse_button_pressed(MouseButton::Left) {
            return;
        }

        if let Some(position) = self.cell_position(mouse_position()) {
            let clicked_component = graph.find_component(&position);
            let colour = clicked_component.colour;

            println!("Detected click at cell ({}, {}) with colour {:#?}", position.column, position.row, colour);

            graph.change_colour_of_component_at(&Position{column: 0_usize, row: 0_usize}, colour);
        }
    }
}

#[macroquad::main("Flood-It")]
async fn main() {
    let size = 8;
    let grid = Grid::generate(size);
    let mut graph = Graph::create(&grid);
    println!("{:#?}", graph);

    let mut ui = Ui::create(size);

    loop {
        if let Some(KeyCode::Q) = get_last_key_pressed() {
            break;
        }

        ui.handle_click(&mut graph);

        ui.resize();
        ui.render(&graph);

        next_frame().await
    }
}
<commit_msg>Detect when the game has been solved<commit_after>use macroquad::prelude::*;

use colour::Colour;
use graph::{Graph, Position};
use grid::Grid;

mod colour;
mod graph;
mod grid;

fn macroquad_colour(colour: Colour) -> Color {
    match colour {
        Colour::Red => color_u8!(255, 0, 0, 255),
        Colour::Yellow => color_u8!(255, 255, 0, 255),
        Colour::Green => color_u8!(0, 176, 0, 255),
        Colour::LightBrown => color_u8!(255, 204, 102, 255),
        Colour::Purple => color_u8!(128, 0, 128, 255),
        Colour::Cyan => color_u8!(0, 255, 255, 255),
        Colour::Blue => color_u8!(0, 0, 255, 255),
        Colour::Fuchsia => color_u8!(255, 0, 255, 255),
    }
}

fn draw_cell(grid_x: f32, grid_y: f32, cell_size: f32, position: &Position, colour: Colour) {
    let color = macroquad_colour(colour);
    draw_rectangle(
        grid_x + cell_size * position.column as f32,
        grid_y + cell_size * position.row as f32,
        cell_size,
        cell_size,
        color,
    );
}

struct Ui {
    /// Size of the grid in cells.
    size: usize,

    /// Size of the grid in pixels.  Assumes the grid is always square.
    grid_size: f32,

    /// Offset of the grid relative to the whole window along the horizontal axis.
    grid_x: f32,

    /// Offset of the grid relative to the whole window along the vertical axis.
    grid_y: f32,
}

impl Ui {
    fn create(size: usize) -> Ui {
        let mut ui = Ui {
            size,
            grid_size: 0.0,
            grid_x: 0.0,
            grid_y: 0.0,
        };

        ui.resize();

        ui
    }

    fn resize(&mut self) {
        let screen_height = screen_height();
        let screen_width = screen_width();

        let grid_size = screen_height.min(screen_width);
        self.grid_size = grid_size;
        self.grid_x = (screen_width - grid_size) / 2.0;
        self.grid_y = (screen_height - grid_size) / 2.0;
    }

    fn render(&self, graph: &Graph) {
        clear_background(BLACK);

        let grid_x = self.grid_x;
        let grid_y = self.grid_y;
        let cell_size = self.cell_size();

        for component in graph.neighbours.keys() {
            for position in &graph.components[component].cells {
                draw_cell(grid_x, grid_y, cell_size, position, graph.components[component].colour);
            }
        }
    }

    fn cell_size(&self) -> f32 {
        self.grid_size / self.size as f32
    }

    fn cell_position(&self, raw_position: (f32, f32)) -> Option<Position> {
        let (raw_x, raw_y) = raw_position;

        let cell_size = self.cell_size();
        let x = (raw_x - self.grid_x) / cell_size;
        let y = (raw_y - self.grid_y) / cell_size;

        let size = self.size as f32;
        if x < 0.0 || y < 0.0 || x > size || y > size {
            // Out of bounds, nothing to do
            None
        } else {
            Some(Position{column: x.floor() as usize, row: y.floor() as usize})
        }
    }

    fn handle_click(&self, graph: &mut Graph) {
        if !is_mouse_button_pressed(MouseButton::Left) {
            return;
        }

        if let Some(position) = self.cell_position(mouse_position()) {
            let clicked_component = graph.find_component(&position);
            let colour = clicked_component.colour;

            println!("Detected click at cell ({}, {}) with colour {:#?}", position.column, position.row, colour);

            graph.change_colour_of_component_at(&Position{column: 0_usize, row: 0_usize}, colour);
        }
    }
}

enum GameState {
    Solving,
    Solved,
}

#[macroquad::main("Flood-It")]
async fn main() {
    let size = 8;
    let grid = Grid::generate(size);
    let mut graph = Graph::create(&grid);
    println!("{:#?}", graph);

    let mut ui = Ui::create(size);

    let mut state = GameState::Solving;

    loop {
        if let Some(KeyCode::Q) = get_last_key_pressed() {
            break;
        }

        ui.handle_click(&mut graph);

        ui.resize();
        ui.render(&graph);

        match state {
            GameState::Solving =>
            if graph.components.len() == 1 {
                state = GameState::Solved;
                println!("Done");
            }
            GameState::Solved => (),
        }

        next_frame().await
    }
}
<|endoftext|>


<commit_before>extern crate serde;
extern crate serde_json;
#[macro_use] extern crate serde_derive;
#[macro_use] extern crate exonum;
extern crate router;
extern crate bodyparser;
extern crate iron;

use exonum::blockchain::{Blockchain, Service, GenesisConfig, Transaction, ApiContext};
use exonum::messages::{RawTransaction, FromRaw, Message};
use exonum::node::{Node, NodeConfig, NodeApiConfig, TransactionSend};
use exonum::storage::{Fork, MemoryDB, MapIndex};
use exonum::crypto::{PublicKey, Hash};
use exonum::encoding::{self, Field};
use exonum::api::{Api, ApiError};
use iron::prelude::*;
use iron::Handler;
use router::Router;

// // // // // // // // // // PERSISTENT DATA // // // // // // // // // //

encoding_struct! {
    struct Wallet {
        const SIZE = 48;

        field pub_key:            &PublicKey  [00 => 32]
        field name:               &str        [32 => 40]
        field balance:            u64         [40 => 48]
    }
}

impl Wallet {
    pub fn increase(&mut self, amount: u64) {
        let balance = self.balance() + amount;
        Field::write(&balance, &mut self.raw, 40, 48);
    }

    pub fn decrease(&mut self, amount: u64) {
        let balance = self.balance() - amount;
        Field::write(&balance, &mut self.raw, 40, 48);
    }
}

// // // // // // // // // // TRANSACTIONS // // // // // // // // // //

pub const TX_WALLET_ID: u16 = 1;

message! {
    struct TxCreateWallet {
        const TYPE = SERVICE_ID;
        const ID = TX_WALLET_ID;
        const SIZE = 40;

        field pub_key:     &PublicKey  [00 => 32]
        field name:        &str        [32 => 40]
    }
}

pub const TX_ISSUE_ID: u16 = 2;

message! {
    struct TxIssue {
        const TYPE = SERVICE_ID;
        const ID = TX_ISSUE_ID;
        const SIZE = 48;

        field pub_key:     &PublicKey  [00 => 32]
        field amount:      u64         [32 => 40]
        field seed:        u64         [40 => 48]
    }
}

pub const TX_TRANSFER_ID: u16 = 3;

message! {
    struct TxTransfer {
        const TYPE = SERVICE_ID;
        const ID = TX_TRANSFER_ID;
        const SIZE = 80;

        field from:        &PublicKey  [00 => 32]
        field to:          &PublicKey  [32 => 64]
        field amount:      u64         [64 => 72]
        field seed:        u64         [72 => 80]
    }
}

// // // // // // // // // // CONTRACTS // // // // // // // // // //

impl Transaction for TxCreateWallet {
    fn verify(&self) -> bool {
        self.verify_signature(self.pub_key())
    }

    fn execute(&self, view: &mut Fork) {
        let mut schema = CurrencySchema { view };
        if let None = schema.wallet(self.pub_key()) {
            let wallet = Wallet::new(self.pub_key(), self.name(), 0);
            println!("Create the wallet: {:?}", wallet);
            schema.wallets().put(self.pub_key(), wallet)
        }
    }
}

impl Transaction for TxIssue {
    fn verify(&self) -> bool {
        self.verify_signature(self.pub_key())
    }

    fn execute(&self, view: &mut Fork) {
        let mut schema = CurrencySchema { view };
        if let Some(mut wallet) = schema.wallet(self.pub_key()) {
            wallet.increase(self.amount());
            println!("Add funds to wallet: {:?}", wallet);
            schema.wallets().put(self.pub_key(), wallet)
        }
    }
}

impl Transaction for TxTransfer {
    fn verify(&self) -> bool {
        (*self.from() != *self.to()) && self.verify_signature(self.from())
    }

    fn execute(&self, view: &mut Fork) {
        let mut schema = CurrencySchema { view };
        let sender = schema.wallet(self.from());
        let receiver = schema.wallet(self.to());
        if let (Some(mut sender), Some(mut receiver)) = (sender, receiver) {
            let amount = self.amount();
            if sender.balance() >= amount {
                sender.decrease(amount);
                receiver.increase(amount);
                println!("Transfer between wallets: {:?} => {:?}", sender, receiver);
                let mut wallets = schema.wallets();
                wallets.put(self.from(), sender);
                wallets.put(self.to(), receiver);
            }
        }
    }
}

// // // // // // // // // // REST API // // // // // // // // // //

#[derive(Clone)]
struct CryptocurrencyApi<T> {
    channel: T,
}

impl<T: TransactionSend + Clone + 'static> Api for CryptocurrencyApi<T> {
    fn wire(&self, router: &mut Router) {

        #[serde(untagged)]
        #[derive(Clone, Serialize, Deserialize)]
        enum TransactionRequest {
            CreateWallet(TxCreateWallet),
            Issue(TxIssue),
            Transfer(TxTransfer),
        }

        impl Into<Box<Transaction>> for TransactionRequest {
            fn into(self) -> Box<Transaction> {
                match self {
                    TransactionRequest::CreateWallet(trans) => Box::new(trans),
                    TransactionRequest::Issue(trans) => Box::new(trans),
                    TransactionRequest::Transfer(trans) => Box::new(trans),
                }
            }
        }

        #[derive(Serialize, Deserialize)]
        struct TransactionResponse {
            tx_hash: Hash,
        }

        let self_ = self.clone();
        let transaction = move |req: &mut Request| -> IronResult<Response> {
            match req.get::<bodyparser::Struct<TransactionRequest>>() {
                Ok(Some(transaction)) => {
                    let transaction: Box<Transaction> = transaction.into();
                    let tx_hash = transaction.hash();
                    self_.channel.send(transaction).map_err(|e| ApiError::Events(e))?;
                    let json = TransactionResponse { tx_hash };
                    self_.ok_response(&serde_json::to_value(&json).unwrap())
                }
                Ok(None) => Err(ApiError::IncorrectRequest("Empty request body".into()))?,
                Err(e) => Err(ApiError::IncorrectRequest(Box::new(e)))?,
            }
        };
        let route_post = "/v1/wallets/transaction";
        router.post(&route_post, transaction, "transaction");
    }
}

// // // // // // // // // // STORAGE DATA LAYOUT // // // // // // // // // //

pub struct CurrencySchema<'a> {
    view: &'a mut Fork,
}

impl<'a> CurrencySchema<'a> {
    pub fn wallets(&mut self) -> MapIndex<&mut Fork, PublicKey, Wallet> {
        MapIndex::new(vec![20], self.view)
    }

    pub fn wallet(&mut self, pub_key: &PublicKey) -> Option<Wallet> {
        self.wallets().get(pub_key)
    }
}

// // // // // // // // // // SERVICE DECLARATION // // // // // // // // // //

pub const SERVICE_ID: u16 = 1;

struct CurrencyService;

impl Service for CurrencyService {
    fn service_name(&self) -> &'static str { "cryptocurrency" }

    fn service_id(&self) -> u16 { SERVICE_ID }

    fn tx_from_raw(&self, raw: RawTransaction) -> Result<Box<Transaction>, encoding::Error> {
        let trans: Box<Transaction> = match raw.message_type() {
            TX_TRANSFER_ID => Box::new(TxTransfer::from_raw(raw)?),
            TX_ISSUE_ID => Box::new(TxIssue::from_raw(raw)?),
            TX_WALLET_ID => Box::new(TxCreateWallet::from_raw(raw)?),
            _ => {
                return Err(encoding::Error::IncorrectMessageType { message_type: raw.message_type() });
            },
        };
        Ok(trans)
    }

    fn public_api_handler(&self, ctx: &ApiContext) -> Option<Box<Handler>> {
        let mut router = Router::new();
        let api = CryptocurrencyApi {
            channel: ctx.node_channel().clone(),
        };
        api.wire(&mut router);
        Some(Box::new(router))
    }
}

// // // // // // // // // // ENTRY POINT // // // // // // // // // //

fn main() {
    exonum::crypto::init();
    exonum::helpers::init_logger().unwrap();

    let db = MemoryDB::new();
    let services: Vec<Box<Service>> = vec![
        Box::new(CurrencyService),
    ];
    let blockchain = Blockchain::new(Box::new(db), services);

    let (public_key, secret_key) = exonum::crypto::gen_keypair();

    let peer_address = "0.0.0.0:2000".parse().unwrap();
    let api_address = "0.0.0.0:8000".parse().unwrap();

    let genesis = GenesisConfig::new(vec![public_key].into_iter());

    let api_cfg = NodeApiConfig {
        enable_blockchain_explorer: true,
        public_api_address: Some(api_address),
        private_api_address: None,
    };

    let node_cfg = NodeConfig {
        listen_address: peer_address,
        peers: vec![],
        public_key,
        secret_key,
        genesis,
        network: Default::default(),
        whitelist: Default::default(),
        api: api_cfg,
        mempool: Default::default(),
    };

    let mut node = Node::new(blockchain, node_cfg);
    node.run().unwrap();
}
<commit_msg>Add logging about starting<commit_after>extern crate serde;
extern crate serde_json;
#[macro_use] extern crate serde_derive;
#[macro_use] extern crate exonum;
extern crate router;
extern crate bodyparser;
extern crate iron;

use exonum::blockchain::{Blockchain, Service, GenesisConfig, Transaction, ApiContext};
use exonum::messages::{RawTransaction, FromRaw, Message};
use exonum::node::{Node, NodeConfig, NodeApiConfig, TransactionSend};
use exonum::storage::{Fork, MemoryDB, MapIndex};
use exonum::crypto::{PublicKey, Hash};
use exonum::encoding::{self, Field};
use exonum::api::{Api, ApiError};
use iron::prelude::*;
use iron::Handler;
use router::Router;

// // // // // // // // // // PERSISTENT DATA // // // // // // // // // //

encoding_struct! {
    struct Wallet {
        const SIZE = 48;

        field pub_key:            &PublicKey  [00 => 32]
        field name:               &str        [32 => 40]
        field balance:            u64         [40 => 48]
    }
}

impl Wallet {
    pub fn increase(&mut self, amount: u64) {
        let balance = self.balance() + amount;
        Field::write(&balance, &mut self.raw, 40, 48);
    }

    pub fn decrease(&mut self, amount: u64) {
        let balance = self.balance() - amount;
        Field::write(&balance, &mut self.raw, 40, 48);
    }
}

// // // // // // // // // // TRANSACTIONS // // // // // // // // // //

pub const TX_WALLET_ID: u16 = 1;

message! {
    struct TxCreateWallet {
        const TYPE = SERVICE_ID;
        const ID = TX_WALLET_ID;
        const SIZE = 40;

        field pub_key:     &PublicKey  [00 => 32]
        field name:        &str        [32 => 40]
    }
}

pub const TX_ISSUE_ID: u16 = 2;

message! {
    struct TxIssue {
        const TYPE = SERVICE_ID;
        const ID = TX_ISSUE_ID;
        const SIZE = 48;

        field pub_key:     &PublicKey  [00 => 32]
        field amount:      u64         [32 => 40]
        field seed:        u64         [40 => 48]
    }
}

pub const TX_TRANSFER_ID: u16 = 3;

message! {
    struct TxTransfer {
        const TYPE = SERVICE_ID;
        const ID = TX_TRANSFER_ID;
        const SIZE = 80;

        field from:        &PublicKey  [00 => 32]
        field to:          &PublicKey  [32 => 64]
        field amount:      u64         [64 => 72]
        field seed:        u64         [72 => 80]
    }
}

// // // // // // // // // // CONTRACTS // // // // // // // // // //

impl Transaction for TxCreateWallet {
    fn verify(&self) -> bool {
        self.verify_signature(self.pub_key())
    }

    fn execute(&self, view: &mut Fork) {
        let mut schema = CurrencySchema { view };
        if let None = schema.wallet(self.pub_key()) {
            let wallet = Wallet::new(self.pub_key(), self.name(), 0);
            println!("Create the wallet: {:?}", wallet);
            schema.wallets().put(self.pub_key(), wallet)
        }
    }
}

impl Transaction for TxIssue {
    fn verify(&self) -> bool {
        self.verify_signature(self.pub_key())
    }

    fn execute(&self, view: &mut Fork) {
        let mut schema = CurrencySchema { view };
        if let Some(mut wallet) = schema.wallet(self.pub_key()) {
            wallet.increase(self.amount());
            println!("Add funds to wallet: {:?}", wallet);
            schema.wallets().put(self.pub_key(), wallet)
        }
    }
}

impl Transaction for TxTransfer {
    fn verify(&self) -> bool {
        (*self.from() != *self.to()) && self.verify_signature(self.from())
    }

    fn execute(&self, view: &mut Fork) {
        let mut schema = CurrencySchema { view };
        let sender = schema.wallet(self.from());
        let receiver = schema.wallet(self.to());
        if let (Some(mut sender), Some(mut receiver)) = (sender, receiver) {
            let amount = self.amount();
            if sender.balance() >= amount {
                sender.decrease(amount);
                receiver.increase(amount);
                println!("Transfer between wallets: {:?} => {:?}", sender, receiver);
                let mut wallets = schema.wallets();
                wallets.put(self.from(), sender);
                wallets.put(self.to(), receiver);
            }
        }
    }
}

// // // // // // // // // // REST API // // // // // // // // // //

#[derive(Clone)]
struct CryptocurrencyApi<T> {
    channel: T,
}

impl<T: TransactionSend + Clone + 'static> Api for CryptocurrencyApi<T> {
    fn wire(&self, router: &mut Router) {

        #[serde(untagged)]
        #[derive(Clone, Serialize, Deserialize)]
        enum TransactionRequest {
            CreateWallet(TxCreateWallet),
            Issue(TxIssue),
            Transfer(TxTransfer),
        }

        impl Into<Box<Transaction>> for TransactionRequest {
            fn into(self) -> Box<Transaction> {
                match self {
                    TransactionRequest::CreateWallet(trans) => Box::new(trans),
                    TransactionRequest::Issue(trans) => Box::new(trans),
                    TransactionRequest::Transfer(trans) => Box::new(trans),
                }
            }
        }

        #[derive(Serialize, Deserialize)]
        struct TransactionResponse {
            tx_hash: Hash,
        }

        let self_ = self.clone();
        let transaction = move |req: &mut Request| -> IronResult<Response> {
            match req.get::<bodyparser::Struct<TransactionRequest>>() {
                Ok(Some(transaction)) => {
                    let transaction: Box<Transaction> = transaction.into();
                    let tx_hash = transaction.hash();
                    self_.channel.send(transaction).map_err(|e| ApiError::Events(e))?;
                    let json = TransactionResponse { tx_hash };
                    self_.ok_response(&serde_json::to_value(&json).unwrap())
                }
                Ok(None) => Err(ApiError::IncorrectRequest("Empty request body".into()))?,
                Err(e) => Err(ApiError::IncorrectRequest(Box::new(e)))?,
            }
        };
        let route_post = "/v1/wallets/transaction";
        router.post(&route_post, transaction, "transaction");
    }
}

// // // // // // // // // // STORAGE DATA LAYOUT // // // // // // // // // //

pub struct CurrencySchema<'a> {
    view: &'a mut Fork,
}

impl<'a> CurrencySchema<'a> {
    pub fn wallets(&mut self) -> MapIndex<&mut Fork, PublicKey, Wallet> {
        MapIndex::new(vec![20], self.view)
    }

    pub fn wallet(&mut self, pub_key: &PublicKey) -> Option<Wallet> {
        self.wallets().get(pub_key)
    }
}

// // // // // // // // // // SERVICE DECLARATION // // // // // // // // // //

pub const SERVICE_ID: u16 = 1;

struct CurrencyService;

impl Service for CurrencyService {
    fn service_name(&self) -> &'static str { "cryptocurrency" }

    fn service_id(&self) -> u16 { SERVICE_ID }

    fn tx_from_raw(&self, raw: RawTransaction) -> Result<Box<Transaction>, encoding::Error> {
        let trans: Box<Transaction> = match raw.message_type() {
            TX_TRANSFER_ID => Box::new(TxTransfer::from_raw(raw)?),
            TX_ISSUE_ID => Box::new(TxIssue::from_raw(raw)?),
            TX_WALLET_ID => Box::new(TxCreateWallet::from_raw(raw)?),
            _ => {
                return Err(encoding::Error::IncorrectMessageType { message_type: raw.message_type() });
            },
        };
        Ok(trans)
    }

    fn public_api_handler(&self, ctx: &ApiContext) -> Option<Box<Handler>> {
        let mut router = Router::new();
        let api = CryptocurrencyApi {
            channel: ctx.node_channel().clone(),
        };
        api.wire(&mut router);
        Some(Box::new(router))
    }
}

// // // // // // // // // // ENTRY POINT // // // // // // // // // //

fn main() {
    exonum::crypto::init();
    exonum::helpers::init_logger().unwrap();

    println!("Creating in-memory database...");
    let db = MemoryDB::new();
    let services: Vec<Box<Service>> = vec![
        Box::new(CurrencyService),
    ];
    let blockchain = Blockchain::new(Box::new(db), services);

    let (public_key, secret_key) = exonum::crypto::gen_keypair();

    let peer_address = "0.0.0.0:2000".parse().unwrap();
    let api_address = "0.0.0.0:8000".parse().unwrap();

    let genesis = GenesisConfig::new(vec![public_key].into_iter());

    let api_cfg = NodeApiConfig {
        enable_blockchain_explorer: true,
        public_api_address: Some(api_address),
        private_api_address: None,
    };

    let node_cfg = NodeConfig {
        listen_address: peer_address,
        peers: vec![],
        public_key,
        secret_key,
        genesis,
        network: Default::default(),
        whitelist: Default::default(),
        api: api_cfg,
        mempool: Default::default(),
    };

    println!("Starting a single node...");
    let mut node = Node::new(blockchain, node_cfg);

    println!("Blockchain in ready for transactions!");
    node.run().unwrap();
}
<|endoftext|>