<commit_before>#![cfg_attr(feature = "clippy", plugin(clippy))]
#![feature(plugin)]

#[macro_use]
extern crate serde_derive;
extern crate serde_json;
extern crate notify;
extern crate aho_corasick;
extern crate rusoto_core;
extern crate rusoto_sns;
extern crate rusoto_sts;
extern crate ifaces;
extern crate crossbeam;

use rusoto_core::{default_tls_client, AutoRefreshingProvider, DefaultCredentialsProvider, Region};
use rusoto_sts::{StsAssumeRoleSessionCredentialsProvider, StsClient};
use rusoto_sns::*;
use std::time::Duration;
use std::io::{BufReader, SeekFrom};
use std::io::prelude::*;
use std::sync::mpsc::channel;
use std::fs::{read_dir, File};
use aho_corasick::{AcAutomaton, Automaton};
use notify::{watcher, RecursiveMode, Watcher};
use std::path::Path;
use std::str::FromStr;
use std::env;
use std::error::Error;

#[derive(Serialize, Deserialize)]
struct LogFile {
    file: String,
    string: String,
    name: String
}

// struct for our config file
#[derive(Deserialize, Clone)]
struct ConfigFile {
    target_arn: String,
    role_arn: String,
    region: String
}

// struct for our system information
struct SystemInfo {
    hostname: String,
    ipaddr: String
}

trait Watched {
    fn fire(&self, config: &ConfigFile) -> Result<PublishResponse, PublishError>;
    fn monitor(&self, config: &ConfigFile) -> Result<(), Box<Error>>;
}

trait WatchFile {
    fn watch(&self) -> bool;
}

impl Watched for LogFile {
    fn monitor(&self, config: &ConfigFile) -> Result<(), Box<Error>> {

        println!(
            "[INFO] Monitoring file {}",
            Path::new(&self.file).canonicalize().unwrap().display()
        );

        loop {
            if WatchFile::watch(self) {
                self.fire(config)?;
            }
        }
    }

    fn fire(&self, config: &ConfigFile) -> Result<PublishResponse, PublishError> {

        // determine our hostname.
        #[allow(unused_assignments)]
        let mut hostname = String::new();
        if let Ok(mut file) = File::open("/etc/hostname") {
            let mut buffer = String::new();
            let _ = file.read_to_string(&mut buffer).unwrap().to_string();
            hostname = buffer.trim().to_owned();
        } else {
            hostname = "localhost".to_string();
        }

        // need the ipaddr of our interface. will be part of the metadata
        let mut address = String::new();
        for iface in ifaces::Interface::get_all().unwrap() {
            if iface.kind == ifaces::Kind::Ipv4 {
                address = format!("{}", iface.addr.unwrap());
                address = address.replace(":0", "");
            }
            continue;
        }

        // store hostname and ip address in our struct
        let system: SystemInfo = SystemInfo {
            hostname: hostname,
            ipaddr: address
        };

        println!("[INFO] Firing for event '{}'", &self.string);
        // set up our credentials provider for aws
        let provider = DefaultCredentialsProvider::new()?;

        // initiate our sts client
        let sts_client = StsClient::new(
            default_tls_client().unwrap(),
            provider,
            Region::from_str(&config.region.clone()).unwrap()
        );
        // generate a sts provider
        let sts_provider = StsAssumeRoleSessionCredentialsProvider::new(
            sts_client,
            config.role_arn.clone(),
            "feretto".to_owned(),
            None,
            None,
            None,
            None
        );
        // allow our STS to auto-refresh
        let auto_sts_provider = AutoRefreshingProvider::with_refcell(sts_provider);

        // create our s3 client initialization
        let sns = SnsClient::new(
            default_tls_client().unwrap(),
            auto_sts_provider?,
            Region::from_str(&config.region.clone()).unwrap()
        );

        let req = PublishInput {
            message: format!(
                "{}:{}::Triggered {} on {}",
                &system.hostname,
                &system.ipaddr,
                &self.string,
                &self.name
            ),
            subject: Some("feretto: notification".to_string()),
            target_arn: Some(config.target_arn.clone()),
            ..Default::default()
        };

        sns.publish(&req)
    }
}

impl WatchFile for LogFile {
    fn watch(&self) -> bool {
        // Attempt to open the file or error.
        let file = File::open(&self.file).unwrap();

        // Attempt to get the metadata of the file or error.
        let metadata = file.metadata().unwrap();

        // Create a buffered reader for the file.
        let mut reader = BufReader::new(&file);
        // Get the initial position of the file from the metadata.
        let mut pos = metadata.len();
        // read from pos as to not read the entire file.
        reader.seek(SeekFrom::Start(pos)).unwrap();

        let (tx, rx) = channel();
        let mut watcher = watcher(tx, Duration::from_secs(2)).unwrap();

        // Add a path to be watched. All files and directories at that path and
        // below will be monitored for changes.
        watcher.watch(&self.file, RecursiveMode::NonRecursive)
               .unwrap();

        // while loop whenever we recieve a message on the channel
        if let Ok(event) = rx.recv() {

            // create a mutable line to store the contents
            let mut line = String::new();

            // read from pos to eof to a string and store in line
            let resp = reader.read_to_string(&mut line);

            if let Ok(len) = resp {
                if len > 0 {
                    pos += len as u64;
                    reader.seek(SeekFrom::Start(pos)).unwrap();

                    let aut = AcAutomaton::new(vec![self.string.to_owned()]);
                    let mut it = aut.find(line.as_bytes());

                    println!("[INFO] Event occured {:?}", &event);
                    if it.next().is_some() {
                        return true;
                    };
                }
            }
            line.clear();
        }
        false
    }
}

fn main() {

    let args: Vec<_> = env::args().collect();
    if args.len() < 2 {
        println!("feretto <config.json> <configs/>");
    }

    // open our config file
    let config_file = File::open(&args[1]).expect("could not open file");
    // attempt to deserialize the config to our struct
    let config: ConfigFile = serde_json::from_reader(config_file).expect("config has invalid json");

    println!(
        "[INFO] Processing configuration file {}",
        Path::new(&args[1]).canonicalize().unwrap().display()
    );

    // open the directory to all the json files specifying log sources
    let path = read_dir(&args[2]).expect("Unable to read directory");

    // if we got here we should let someone know
    println!("[INFO] Feretto starting up!");

    let config_ref = &config;

    crossbeam::scope(|scope| for file in path {
        scope.spawn(move || {

            let clone_log_file = file.unwrap().path().canonicalize().unwrap().clone();
            let log_direction = File::open(&clone_log_file).expect("Unable to read file");
            let logfile: LogFile = serde_json::from_reader(log_direction).expect("invalid json");

            let _ = Watched::monitor(&logfile, config_ref);
        });
    });
}
<commit_msg>rustfmt<commit_after>#![cfg_attr(feature = "clippy", plugin(clippy))]
#![feature(plugin)]

extern crate aho_corasick;
extern crate crossbeam;
extern crate ifaces;
extern crate notify;
extern crate rusoto_core;
extern crate rusoto_sns;
extern crate rusoto_sts;
#[macro_use]
extern crate serde_derive;
extern crate serde_json;

use rusoto_core::{default_tls_client, AutoRefreshingProvider, DefaultCredentialsProvider, Region};
use rusoto_sts::{StsAssumeRoleSessionCredentialsProvider, StsClient};
use rusoto_sns::*;
use std::time::Duration;
use std::io::{BufReader, SeekFrom};
use std::io::prelude::*;
use std::sync::mpsc::channel;
use std::fs::{read_dir, File};
use aho_corasick::{AcAutomaton, Automaton};
use notify::{watcher, RecursiveMode, Watcher};
use std::path::Path;
use std::str::FromStr;
use std::env;
use std::error::Error;

#[derive(Serialize, Deserialize)]
struct LogFile {
    file: String,
    string: String,
    name: String
}

// struct for our config file
#[derive(Deserialize, Clone)]
struct ConfigFile {
    target_arn: String,
    role_arn: String,
    region: String
}

// struct for our system information
struct SystemInfo {
    hostname: String,
    ipaddr: String
}

trait Watched {
    fn fire(&self, config: &ConfigFile) -> Result<PublishResponse, PublishError>;
    fn monitor(&self, config: &ConfigFile) -> Result<(), Box<Error>>;
}

trait WatchFile {
    fn watch(&self) -> bool;
}

impl Watched for LogFile {
    fn monitor(&self, config: &ConfigFile) -> Result<(), Box<Error>> {
        println!(
            "[INFO] Monitoring file {}",
            Path::new(&self.file).canonicalize().unwrap().display()
        );

        loop {
            if WatchFile::watch(self) {
                self.fire(config)?;
            }
        }
    }

    fn fire(&self, config: &ConfigFile) -> Result<PublishResponse, PublishError> {
        // determine our hostname.
        #[allow(unused_assignments)]
        let mut hostname = String::new();
        if let Ok(mut file) = File::open("/etc/hostname") {
            let mut buffer = String::new();
            let _ = file.read_to_string(&mut buffer).unwrap().to_string();
            hostname = buffer.trim().to_owned();
        } else {
            hostname = "localhost".to_string();
        }

        // need the ipaddr of our interface. will be part of the metadata
        let mut address = String::new();
        for iface in ifaces::Interface::get_all().unwrap() {
            if iface.kind == ifaces::Kind::Ipv4 {
                address = format!("{}", iface.addr.unwrap());
                address = address.replace(":0", "");
            }
            continue;
        }

        // store hostname and ip address in our struct
        let system: SystemInfo = SystemInfo {
            hostname: hostname,
            ipaddr: address
        };

        println!("[INFO] Firing for event '{}'", &self.string);
        // set up our credentials provider for aws
        let provider = DefaultCredentialsProvider::new()?;

        // initiate our sts client
        let sts_client = StsClient::new(
            default_tls_client().unwrap(),
            provider,
            Region::from_str(&config.region.clone()).unwrap()
        );
        // generate a sts provider
        let sts_provider = StsAssumeRoleSessionCredentialsProvider::new(
            sts_client,
            config.role_arn.clone(),
            "feretto".to_owned(),
            None,
            None,
            None,
            None
        );
        // allow our STS to auto-refresh
        let auto_sts_provider = AutoRefreshingProvider::with_refcell(sts_provider);

        // create our s3 client initialization
        let sns = SnsClient::new(
            default_tls_client().unwrap(),
            auto_sts_provider?,
            Region::from_str(&config.region.clone()).unwrap()
        );

        let req = PublishInput {
            message: format!(
                "{}:{}::Triggered {} on {}",
                &system.hostname,
                &system.ipaddr,
                &self.string,
                &self.name
            ),
            subject: Some("feretto: notification".to_string()),
            target_arn: Some(config.target_arn.clone()),
            ..Default::default()
        };

        sns.publish(&req)
    }
}

impl WatchFile for LogFile {
    fn watch(&self) -> bool {
        // Attempt to open the file or error.
        let file = File::open(&self.file).unwrap();

        // Attempt to get the metadata of the file or error.
        let metadata = file.metadata().unwrap();

        // Create a buffered reader for the file.
        let mut reader = BufReader::new(&file);
        // Get the initial position of the file from the metadata.
        let mut pos = metadata.len();
        // read from pos as to not read the entire file.
        reader.seek(SeekFrom::Start(pos)).unwrap();

        let (tx, rx) = channel();
        let mut watcher = watcher(tx, Duration::from_secs(2)).unwrap();

        // Add a path to be watched. All files and directories at that path and
        // below will be monitored for changes.
        watcher.watch(&self.file, RecursiveMode::NonRecursive)
               .unwrap();

        // while loop whenever we recieve a message on the channel
        if let Ok(event) = rx.recv() {
            // create a mutable line to store the contents
            let mut line = String::new();

            // read from pos to eof to a string and store in line
            let resp = reader.read_to_string(&mut line);

            if let Ok(len) = resp {
                if len > 0 {
                    pos += len as u64;
                    reader.seek(SeekFrom::Start(pos)).unwrap();

                    let aut = AcAutomaton::new(vec![self.string.to_owned()]);
                    let mut it = aut.find(line.as_bytes());

                    println!("[INFO] Event occured {:?}", &event);
                    if it.next().is_some() {
                        return true;
                    };
                }
            }
            line.clear();
        }
        false
    }
}

fn main() {
    let args: Vec<_> = env::args().collect();
    if args.len() < 2 {
        println!("feretto <config.json> <configs/>");
    }

    // open our config file
    let config_file = File::open(&args[1]).expect("could not open file");
    // attempt to deserialize the config to our struct
    let config: ConfigFile = serde_json::from_reader(config_file).expect("config has invalid json");

    println!(
        "[INFO] Processing configuration file {}",
        Path::new(&args[1]).canonicalize().unwrap().display()
    );

    // open the directory to all the json files specifying log sources
    let path = read_dir(&args[2]).expect("Unable to read directory");

    // if we got here we should let someone know
    println!("[INFO] Feretto starting up!");

    let config_ref = &config;

    crossbeam::scope(|scope| for file in path {
        scope.spawn(move || {
            let clone_log_file = file.unwrap().path().canonicalize().unwrap().clone();
            let log_direction = File::open(&clone_log_file).expect("Unable to read file");
            let logfile: LogFile = serde_json::from_reader(log_direction).expect("invalid json");

            let _ = Watched::monitor(&logfile, config_ref);
        });
    });
}
<|endoftext|>


<commit_before>
extern crate crypto;
extern crate iron;
extern crate router;
extern crate params;
extern crate hyper;
extern crate logger;

use iron::prelude::*;
use iron::{BeforeMiddleware, AfterMiddleware, typemap};
use iron::middleware::Handler;
use router::{Router};
use iron::status;
use params::Params;
use logger::Logger;
use std::error::Error;

/// generate the md5sum of a given file (io::Read)
pub fn md5sum<T : std::io::Read> (f: &mut T) -> String  {
  use crypto::digest::Digest;

  let mut digest = crypto::md5::Md5::new();
  let mut data: Vec<u8> = Vec::new();

  f.read_to_end(&mut data);
  digest.input(&data);
  digest.result_str()
}

// fn getFile(params: &params::Map) -> Option<&std::io::Read>
// {
//   use std::fs::File;
//   use std::path::Path;
//
// //   #[cfg(debug)]
// //   {
// //     for (key, value) in params.iter() {
// //       println!("{}: {:?}", key, value);
// //     }
// //   }
//
//
//   match params.find(&["filename"]) {
//     Some(ref f) => println!("{:?}", f),
//
//                       { // Open the path in read-only mode, returns `io::Result<File>`
//       let path = Path::new(path);
//       match File::open(path) {
//           // The `description` method of `io::Error` returns a string that
//           // describes the error
//           Err(why) => panic!("couldn't open {}: {}", path.display(),
//                                                     Error::description(&why)),
//           Ok(file) => &file,
//       }
//     },
//     Nome => //None
//             println!("peccato"),
//   }
// }

// curl -i "http://localhost:3000/openact"  -F "filename=@/home/costa/test.csv" -F "name=jason" -F
// "age=2"
fn submit_form_file(req: &mut Request) -> IronResult<Response> {
  let param_res = req.get_ref::<Params>(); // Result<&params::Map, params::ParamsError>
    println!("{:?}", &param_res);

    let md5sum_check = match param_res {
        Ok(ref params) => match params.find(&["md5sum"]) {
          Some(ref passed_md5sum) => {
            match params.find(&["filename"]) {
              None => {
                println!("missing 'filename' field: {:?}", params);
                false
              },
              Some(f) => {
                match *f {
                  params::Value::File(ref file) => println!("the path is: {:?}", file.path() ),
                  _ => println!("non si tratta di un file!!!!")
                }
                true
              }
//               match *f as params::Value {
//                 params::Value::File => {
//                   let file = f as &params::Value::File;
//                   md5sum(file.open()) == passed_md5sum
//                 }
//               }
            }
          },
            _ => false
        },
        Err(why) => {println!("{:?}", why); false},
    };
    Ok(Response::with(status::Ok))
}

fn start_server() {
   let (logger_before, logger_after) = Logger::new(None);
   let mut router = Router::new();
   let mut chain_form_file = Chain::new(submit_form_file);
   chain_form_file.link_before(logger_before);
   chain_form_file.link_after(logger_after);
   router.post("/openact", chain_form_file);
   println!("started server at http://localhost:3000/");
   Iron::new(router).http("localhost:3000").unwrap();
}

#[cfg(test)]
mod tests {

    use std::fs::File;
    use super::md5sum;

#[test]
    fn md5sum_of_file() {
        static FP : &'static str = "/home/costa/pkg/lav/regione/attiweb/attività/20150107/definizione procedura di riavvio/Procedure_Riavvio_omnia.odt";

        let mut odt = match File::open(FP) {
            Err(why) => panic!("Cannot open the test file: {}", why),
            Ok(file) => file,
        };

        assert_eq!(md5sum(&mut odt), "a381cbe043c38a94af0983ffa934f338");
    }

    #[test]
    fn simple_get() {
        use hyper::Client;
        use hyper::header::Connection;
        use std::io::Read;
        use super::start_server;

        // start_server();

        // Create a client.
        let client = Client::new();
        //
        // Creating an outgoing request.
        let mut res = client.get("http://localhost:3000/openact")
            // set a header
            .header(Connection::close())
            // let 'er go!
            .send().unwrap();

        // Read the Response.
        let mut body = String::new();
        res.read_to_string(&mut body).unwrap();

        println!("Response: {}", body);
        assert_eq!(body, "Hello World");
    }

}

fn main() {
    println!("Hello, world!");
    start_server();
}
<commit_msg>check the request for the required parameters<commit_after>
extern crate crypto;
extern crate iron;
extern crate router;
extern crate params;
extern crate hyper;
extern crate logger;

use iron::prelude::*;
use router::{Router};
use iron::status;
use params::Params;
use logger::Logger;
use iron::{BeforeMiddleware};

/// generate the md5sum of a given file (io::Read)
pub fn md5sum<T : std::io::Read> (f: &mut T) -> String  {
  use crypto::digest::Digest;

  let mut digest = crypto::md5::Md5::new();
  let mut data: Vec<u8> = Vec::new();

  match f.read_to_end(&mut data) {
    Err(why) => { println!("Error reading the passed file to calculate the md5sum: {}", why); String::new() }
    Ok(size) => {
      if size > 0 {
        digest.input(&data);
        digest.result_str()
      } else {
        String::new()
      }
    }
  }
}

use params::FromValue;

macro_rules! bad_request {
  // `()` indicates that the macro takes no argument
  ($msg:expr) => (
    Err(IronError::new($msg, status::BadRequest))
  )
}

use std::error::Error;
use std::fmt::{self, Debug};

#[derive(Debug)]
struct StringError(String);

impl fmt::Display for StringError {
  fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
    Debug::fmt(self, f)
  }
}

impl Error for StringError {
  fn description(&self) -> &str { &*self.0 }
}

struct RequireMd5sumParam;

impl RequireMd5sumParam {
  fn value(params: &params::Map) -> String {
    let s = String::from_value(params.find(&["md5sum"]).unwrap()).unwrap();
    println!("'md5sum': {}", s);
    s
  }
}

impl BeforeMiddleware for RequireMd5sumParam {

  fn before(&self, req: &mut Request) -> IronResult<()> {
    let param_res = req.get_ref::<Params>();
    return match param_res {
      Err(why) => {
        bad_request!(why)
      },
      Ok(ref params) => {
        match params.find(&["md5sum"]) {
          None => bad_request!(StringError("the request doesn't contains the parameter 'md5sum'".to_string())),
          Some(passed_md5sum) => {
            // check the type
            match *passed_md5sum {
              params::Value::String(ref p) => Ok(()),
              _ => bad_request!(StringError("the 'md5sum' parameter is not of type 'string'".to_string()))
            }
          }
        }
      }
    }
  }
}

struct CheckFileParam;
impl BeforeMiddleware for CheckFileParam {

  fn before(&self, req: &mut Request) -> IronResult<()> {
    let param_res = req.get_ref::<Params>();
    return match param_res {
      Err(why) => {
        bad_request!(why)
      },
      Ok(ref params) => {
        match params.find(&["file"]) {
          None => bad_request!(StringError("the request doesn't contains the parameter 'file'".to_string())),
          Some(passed_md5sum) => {
            // check the type
            match *passed_md5sum {
              params::Value::File(ref p) => Ok(()),
              _ => bad_request!(StringError("the 'file' parameter is not of type 'file'".to_string()))
            }
          }
        }
      }
    }
  }
}

macro_rules! check_parameter {
  // `()` indicates that the macro takes no argument
  ($name:ident, $pname:expr, $ptype:pat, $rtype:ty) => (
    struct $name;

    impl BeforeMiddleware for $name {

      fn before(&self, req: &mut Request) -> IronResult<()> {
        let param_res = req.get_ref::<Params>();
        return match param_res {
          Err(why) => {
            bad_request!(why)
          },
          Ok(ref params) => {
            match params.find(&[$pname]) {
              None => bad_request!(StringError(format!("the request doesn't contains the parameter '{}'", $pname))),
              Some(passed_md5sum) => {
                // check the type
                match *passed_md5sum {
                  $ptype => Ok(()),
                  _ => bad_request!(StringError(format!("the '{}' parameter is not of the correct type", $pname)))
                }
              }
            }
          }
        }
      }
    }
  )
}
check_parameter!(RequireMd5sumParam2, "md5sum", params::Value::String(_), String);

fn submit_form_file2(req: &mut Request) -> IronResult<Response> {
  // parameters must exists...
  let param_res = req.get_ref::<Params>();
  let md5sum = RequireMd5sumParam::value(param_res.unwrap());
  Ok(Response::with(status::Ok))
}

// curl -i "http://localhost:3000/openact"  -F "filename=@/home/costa/test.csv" -F "name=jason" -F
// "age=2"
fn submit_form_file(req: &mut Request) -> IronResult<Response> {
//   use params::FromValue;

  let param_res = req.get_ref::<Params>(); // Result<&params::Map, params::ParamsError>
    println!("DEBUG - received request: {:?}", &param_res);

    match param_res {
      Err(why) => {
        let msg = format!("{:?}", why);
        println!("{}", msg);
        Ok(Response::with((status::InternalServerError, msg)))
      },
      Ok(ref params) => match params.find(&["md5sum"]) {
        Some(ref passed_md5sum) => {

          match **passed_md5sum {
            params::Value::String(ref passed_md5sum) => {
              match params.find(&["filename"]) {
                None => {
                  let msg = format!("missing 'filename' field: {:?}", params);
                  println!("{}", msg);
                  Ok(Response::with((status::BadRequest, msg)))
                },
                Some(ref f) => {
                  match **f {
                    params::Value::File(ref file_param) => {
                      let file_path = file_param.path().display();
                      let msg = format!("the path is: {:?}", file_path);
                      println!("{}", msg);
                      match file_param.open() {
                        Err(why) => {
                          let msg = format!("cannot open the uploaded file '{:?}' in path '{}' : '{}'", file_param.filename(), file_path, why);
                          println!("{}", msg);
                          Ok(Response::with((status::InternalServerError, msg)))
                        },
                        Ok(ref mut file) => {
                          let calculated_md5sum = &md5sum(file);
                          if calculated_md5sum != passed_md5sum {
                            let msg = format!(
                              "the md5sum '{}' calculate for the file {} doesn't correspond to the parameter '{}'",
                              calculated_md5sum, file_path, passed_md5sum
                            );
                            return Ok(Response::with((status::PreconditionRequired, msg)))
                          }

                          return Ok(Response::with((status::Ok, "ciao mondo")))
//                           use std::process::Command;

//                           match Command::new("file")
//                             .arg("-b")
//                             .arg("--mime-type")
//                             .arg(file_path)
//                             .output() {
//                               Err(why) =>
//                             }
//                             .unwrap_or_else(|e| { Ok(Response::with((status::PreconditionRequired,
//                               format!("error finding the type of the uploaded file {:?}", file_param.filename()) )) });

                        }
                      }

                    },
                    _ => {
                      let msg = format!("The request parameter 'filename' doesn't correspond to a real file: {:?}", f);
                      println!("{}", msg);
                      Ok(Response::with((status::PreconditionRequired, msg)))
                    }
                  }
                }

              }
            }
            _ => {
              let msg = format!(
                "The request parameter 'md5sum':'{:?}'' in the request {:?} doesn't correspond to a string",
                passed_md5sum, param_res);
              println!("{}", msg);
              Ok(Response::with((status::BadRequest, msg)))
            }
          }

        },
        _ => {
          let msg = format!("The request parameter 'md5sum' is required");
          println!("{}", msg);
          Ok(Response::with((status::BadRequest, msg)))
        }
      },

    }

}

fn start_server() {
   let (logger_before, logger_after) = Logger::new(None);
   let mut router = Router::new();
   let mut chain_form_file = Chain::new(submit_form_file2);
   chain_form_file.link_before(logger_before);
   chain_form_file.link_before(RequireMd5sumParam);
   chain_form_file.link_after(logger_after);
   router.post("/openact", chain_form_file);
   println!("started server at http://localhost:3000/");
   Iron::new(router).http("localhost:3000").unwrap();
}

#[cfg(test)]
mod tests {

    use std::fs::File;
    use super::md5sum;

#[test]
    fn md5sum_of_file() {
        static FP : &'static str = "/home/costa/pkg/lav/regione/attiweb/attività/20150107/definizione procedura di riavvio/Procedure_Riavvio_omnia.odt";

        let mut odt = match File::open(FP) {
            Err(why) => panic!("Cannot open the test file: {}", why),
            Ok(file) => file,
        };

        assert_eq!(md5sum(&mut odt), "a381cbe043c38a94af0983ffa934f338");
    }

    #[test]
    fn simple_get() {
        use hyper::Client;
        use hyper::header::Connection;
        use std::io::Read;
        use super::start_server;

        // start_server();

        // Create a client.
        let client = Client::new();
        //
        // Creating an outgoing request.
        let mut res = client.get("http://localhost:3000/openact")
            // set a header
            .header(Connection::close())
            // let 'er go!
            .send().unwrap();

        // Read the Response.
        let mut body = String::new();
        res.read_to_string(&mut body).unwrap();

        println!("Response: {}", body);
        assert_eq!(body, "Hello World");
    }

}

fn main() {
    println!("Hello, world!");
    start_server();
}
<|endoftext|>


<commit_before>#![feature(proc_macro)]
#![allow(dead_code)]
#![feature(plugin)]
#![feature(conservative_impl_trait)]
#![plugin(clippy)]
#![allow(no_effect, unnecessary_operation)]
// Enable this for memory tracking with Instruments/MacOS
// and for much better stacktraces for memory issues
#![feature(alloc_system)]
extern crate alloc_system;

extern crate ordered_float;
extern crate itertools;
extern crate random;
extern crate fnv;

extern crate kay;
#[macro_use]
extern crate kay_macros;
extern crate monet;
extern crate descartes;

mod core;
mod game;

use monet::{Renderer, Control, AddDebugText};
use core::simulation::{Simulation, Tick};
use game::lanes_and_cars::{Lane, TransferLane};
use game::lanes_and_cars::lane_rendering::{LaneAsphalt, LaneMarker, TransferLaneMarkerGaps};
use game::lanes_and_cars::lane_thing_collector::ThingCollector;
use game::lanes_and_cars::planning::{CurrentPlan};
use kay::Individual;

const SECONDS_PER_TICK : f32 = 1.0 / 20.0;

fn main() {
    let mut system = kay::ActorSystem::new();
    unsafe {
        kay::THE_SYSTEM = &mut system as *mut kay::ActorSystem;
    }

    game::setup(&mut system);
    game::setup_ui(&mut system);

    let simulatables = vec![
        system.broadcast_id::<Lane>(),
        system.broadcast_id::<TransferLane>()
    ];
    core::simulation::setup(&mut system, simulatables);

    let renderables = vec![
        system.broadcast_id::<Lane>(),
        system.broadcast_id::<TransferLane>(),
        system.individual_id::<ThingCollector<LaneAsphalt>>(),
        system.individual_id::<ThingCollector<LaneMarker>>(),
        system.individual_id::<ThingCollector<TransferLaneMarkerGaps>>(),
        system.individual_id::<CurrentPlan>(),
    ];
    let window = core::ui::setup_window_and_renderer(&mut system, renderables);

    let mut simulation_panicked : Option<String> = None;
    let mut last_frame = std::time::Instant::now();

    system.process_all_messages();

    loop {
        Renderer::id() << AddDebugText{
            scene_id: 0,
            key: "Frame".chars().collect(),
            value: format!("{:.2} ms", last_frame.elapsed().as_secs() as f32 * 1000.0 + last_frame.elapsed().subsec_nanos() as f32 / 10.0E5).as_str().chars().collect()
        };
        last_frame = std::time::Instant::now();
        if !core::ui::process_events(&window) {return}

        if let Some(error) = simulation_panicked.clone() {
            system.clear_all_clearable_messages();
            system.process_all_messages();
            Renderer::id() << AddDebugText{
                scene_id: 0,
                key: "SIMULATION PANIC".chars().collect(),
                value: error.as_str().chars().collect()
            };
        } else {
            let simulation_result = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
                system.process_all_messages();

                Simulation::id() << Tick{dt: SECONDS_PER_TICK, current_tick: 0};

                system.process_all_messages();

                Renderer::id() << Control::Render;

                system.process_all_messages();
            }));
            if simulation_result.is_err() {
                system.clear_all_clearable_messages();
                let msg = match simulation_result.unwrap_err().downcast::<String>() {
                    Ok(string) => (*string),
                    Err(any) => match any.downcast::<&'static str>() {
                        Ok(static_str) => (*static_str).to_string(),
                        Err(_) => "Weird error type".to_string()
                    }
                };
                println!("Simulation Panic!\n{:?}", msg);
                simulation_panicked = Some(msg);
            }
        }

        Renderer::id() << Control::Submit;

        system.process_all_messages();
    }
}<commit_msg>Box the system to not make the stack explode<commit_after>#![feature(proc_macro)]
#![allow(dead_code)]
#![feature(plugin)]
#![feature(conservative_impl_trait)]
#![plugin(clippy)]
#![allow(no_effect, unnecessary_operation)]
// Enable this for memory tracking with Instruments/MacOS
// and for much better stacktraces for memory issues
#![feature(alloc_system)]
extern crate alloc_system;

extern crate ordered_float;
extern crate itertools;
extern crate random;
extern crate fnv;

extern crate kay;
#[macro_use]
extern crate kay_macros;
extern crate monet;
extern crate descartes;

mod core;
mod game;

use monet::{Renderer, Control, AddDebugText};
use core::simulation::{Simulation, Tick};
use game::lanes_and_cars::{Lane, TransferLane};
use game::lanes_and_cars::lane_rendering::{LaneAsphalt, LaneMarker, TransferLaneMarkerGaps};
use game::lanes_and_cars::lane_thing_collector::ThingCollector;
use game::lanes_and_cars::planning::{CurrentPlan};
use kay::Individual;

const SECONDS_PER_TICK : f32 = 1.0 / 20.0;

fn main() {
    let mut system = Box::new(kay::ActorSystem::new());
    unsafe {
        kay::THE_SYSTEM = &mut *system as *mut kay::ActorSystem;
    }

    game::setup(&mut system);
    game::setup_ui(&mut system);

    let simulatables = vec![
        system.broadcast_id::<Lane>(),
        system.broadcast_id::<TransferLane>()
    ];
    core::simulation::setup(&mut system, simulatables);

    let renderables = vec![
        system.broadcast_id::<Lane>(),
        system.broadcast_id::<TransferLane>(),
        system.individual_id::<ThingCollector<LaneAsphalt>>(),
        system.individual_id::<ThingCollector<LaneMarker>>(),
        system.individual_id::<ThingCollector<TransferLaneMarkerGaps>>(),
        system.individual_id::<CurrentPlan>(),
    ];
    let window = core::ui::setup_window_and_renderer(&mut system, renderables);

    let mut simulation_panicked : Option<String> = None;
    let mut last_frame = std::time::Instant::now();

    system.process_all_messages();

    loop {
        Renderer::id() << AddDebugText{
            scene_id: 0,
            key: "Frame".chars().collect(),
            value: format!("{:.2} ms", last_frame.elapsed().as_secs() as f32 * 1000.0 + last_frame.elapsed().subsec_nanos() as f32 / 10.0E5).as_str().chars().collect()
        };
        last_frame = std::time::Instant::now();
        if !core::ui::process_events(&window) {return}

        if let Some(error) = simulation_panicked.clone() {
            system.clear_all_clearable_messages();
            system.process_all_messages();
            Renderer::id() << AddDebugText{
                scene_id: 0,
                key: "SIMULATION PANIC".chars().collect(),
                value: error.as_str().chars().collect()
            };
        } else {
            let simulation_result = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
                system.process_all_messages();

                Simulation::id() << Tick{dt: SECONDS_PER_TICK, current_tick: 0};

                system.process_all_messages();

                Renderer::id() << Control::Render;

                system.process_all_messages();
            }));
            if simulation_result.is_err() {
                system.clear_all_clearable_messages();
                let msg = match simulation_result.unwrap_err().downcast::<String>() {
                    Ok(string) => (*string),
                    Err(any) => match any.downcast::<&'static str>() {
                        Ok(static_str) => (*static_str).to_string(),
                        Err(_) => "Weird error type".to_string()
                    }
                };
                println!("Simulation Panic!\n{:?}", msg);
                simulation_panicked = Some(msg);
            }
        }

        Renderer::id() << Control::Submit;

        system.process_all_messages();
    }
}<|endoftext|>


<commit_before>extern crate osmio;
extern crate image;
extern crate gif;
extern crate clap;

use clap::{Arg, App, AppSettings};

use std::fs;
use osmio::OSMReader;
use osmio::pbf::PBFReader;
use std::io::{Read, Write, BufReader, BufRead, BufWriter};
use std::collections::HashMap;

use gif::SetParameter;

// (frame_no, (pixel_index, num_changes))
type Frames = Vec<(u32, Vec<(u32, u16)>)>;

struct ColourRamp {
    empty_colour: (u8, u8, u8),
    steps: Vec<(u32, (u8, u8, u8))>,
}

impl ColourRamp {
    fn new_from_filename(filename: &str) -> Self {
        let mut contents = String::new();
        let mut file = fs::File::open(filename).unwrap();
        file.read_to_string(&mut contents).expect("Couldn't read colour ramp file");
        Self::new_from_text(&contents)

    }
    fn new_from_text(source: &str) -> Self {
        let lines: Vec<_> = source.lines().collect();
        let empty_vec = lines[0].split(",").filter_map(|x| x.parse::<u8>().ok()).take(3).collect::<Vec<_>>();
        let empty = (empty_vec[0], empty_vec[1], empty_vec[2]);

        let mut steps = Vec::new();
        for line in lines.iter().skip(1) {
            let line = line.split(",").filter_map(|x| x.parse::<u32>().ok()).take(4).collect::<Vec<_>>();
            let age = line[0];
            let colour = (line[1] as u8, line[2] as u8, line[3] as u8);
            steps.push((age, colour));
        }

        if steps.len() > 254 {
            panic!("Too many steps");
        }

        ColourRamp{ empty_colour: empty, steps: steps }
    }

    fn palette(&self) -> Vec<u8> {
        let mut results = Vec::with_capacity((self.steps.len()+1)*3);
        results.push(self.empty_colour.0);
        results.push(self.empty_colour.1);
        results.push(self.empty_colour.2);

        for &(_, (r, g, b)) in self.steps.iter() {
            results.push(r);
            results.push(g);
            results.push(b);
        }

        results
    }

    fn index_for_magnitude(&self, magnitude: Option<u32>) -> u8 {
        match magnitude {
            None => 0,
            Some(magnitude) => {
                if magnitude > 255 {
                    1
                } else {
                    (255 - magnitude) as u8
                }
            },
            //Some(age) => match self.steps.iter().position(|&(x, _)| x == age) {
            //    None => 0,
            //    Some(i) => (i+1) as u8,
            //}
        }
    }
}

fn read_pbf(filename: &str, height: u32, sec_per_frame: u32, bbox: &[f32; 4]) -> Frames {
    let file = BufReader::new(fs::File::open(&filename).unwrap());
    let mut node_reader = PBFReader::new(file);
    let node_reader = node_reader.nodes();

    let mut results: HashMap<u32, HashMap<u32, u16>> = HashMap::new();

    let left = bbox[0]; let bottom = bbox[1]; let right = bbox[2]; let top = bbox[3];
    let bbox_width = right - left;
    let bbox_height = top - bottom;
    let width = ((bbox_width / bbox_height) * (height as f32)) as u32;

    // 1st April 2005, midnight GMT. We presume no OSM editing before then.
    let osm_epoch = 1109635200;

    // FIXME use a btreemap?

    let mut first_frame_no = std::u32::MAX;
    let mut last_frame_no = 0;

    let mut num_nodes: u64 = 0;
    for node in node_reader {
        if let (Some(lat), Some(lon)) = (node.lat, node.lon) {
            // FIXME should be able to do non-equals but it fails for point at south pole
            if lat >= top || lat <= bottom || lon >= right || lon <= left {
                continue;
            }

            let timestamp = node.timestamp.to_epoch_number() as u64;
            if timestamp < osm_epoch {
                panic!("timestamp before epoch. Change code. {}", timestamp);
            }
            let offset = (timestamp - osm_epoch) as u32;
            // TODO double check that this rounds down
            let frame_no = offset / sec_per_frame;

            if frame_no < first_frame_no {
                first_frame_no = frame_no;
            }
            if frame_no > last_frame_no {
                last_frame_no = frame_no;
            }

            let pixel_idx = latlon_to_pixel_index(lat, lon, width, height, &bbox);
            let curr_val = results.entry(frame_no).or_insert(HashMap::new()).entry(pixel_idx).or_insert(0);
            if *curr_val < std::u16::MAX {
                *curr_val += 1;
            }

            num_nodes += 1;
            if num_nodes % 50_000_000 == 0 {
                println!("Done {} million points", num_nodes/1_000_000);
            }
        }
    }
    println!("Done {} points", num_nodes);
    let num_frames = last_frame_no - first_frame_no + 1;
    println!("There are {} frames, which is {} sec", num_frames, num_frames as f32/30.);

    let mut sorted_results = Vec::with_capacity((last_frame_no-first_frame_no+1) as usize);

    for frame_no in 0..num_frames {
        match results.remove(&(frame_no+first_frame_no)) {
            None => { sorted_results.push((frame_no, Vec::with_capacity(0))) },
            Some(pixels) => {
                let pixels = pixels.into_iter().collect();
                sorted_results.push((frame_no, pixels));
            }
        }
    }

    sorted_results
}

fn write_frames(frames: Frames, filename: &str) {
    let mut file = BufWriter::new(fs::File::create(&filename).unwrap());
    for (frame_no, pixels) in frames.into_iter() {
        write!(file, "{}", frame_no).unwrap();
        for p in pixels {
            write!(file, ",{},{}", p.0, p.1).unwrap();
        }
        write!(file, "\n").unwrap()
    }
}

fn read_frames(filename: &str) -> Frames {
    let file = BufReader::new(fs::File::open(&filename).unwrap());
    let mut results = Frames::new();

    for line in file.lines() {
        let line = line.unwrap();
        let frame_no = line.split(",").nth(0).unwrap().parse().unwrap();
        let pixels: Vec<(u32, u16)> = line.split(",").skip(1).collect::<Vec<_>>().chunks(2).map(|pair| (pair[0].parse().unwrap(), pair[1].parse().unwrap())).collect();
        results.push((frame_no, pixels))
    }

    results
}

fn latlon_to_pixel_index(lat: f32, lon: f32, width: u32, height: u32, bbox: &[f32; 4]) -> u32 {
    let left = bbox[0]; let bottom = bbox[1]; let right = bbox[2]; let top = bbox[3];
    let bbox_width = right - left;
    let bbox_height = top - bottom;

    let lat0 = top - lat;
    let lon0 = lon - left;

    let x = ((lon0/bbox_width)*(width as f32)) as u32;
    let y = ((lat0/bbox_height)*(height as f32)) as u32;

    let i = y * width + x;

    assert!(i < width*height, "{} L{}, lat = {} lon = {} width = {} height = {} bbox = {:?} x = {} y = {} i = {}", file!(), line!(), lat, lon, width, height, bbox, x, y, i);

    i
}

fn create_equirectangular_map(frames: Frames, output_image_filename: &str, height: u32, bbox: &[f32; 4], colour_ramp: &ColourRamp) {
    let mut output_file = fs::File::create(output_image_filename).expect("Can't create image");

    let left = bbox[0]; let bottom = bbox[1]; let right = bbox[2]; let top = bbox[3];
    let bbox_width = right - left;
    let bbox_height = top - bottom;
    let width = ((bbox_width / bbox_height) * (height as f32)) as u32;

    // FIXME change width/height to u16?
    let mut encoder = gif::Encoder::new(&mut output_file, width as u16, height as u16, &colour_ramp.palette()).expect("Couldn't create encoder");
    encoder.set(gif::Repeat::Infinite).expect("Couldn't get inf repeat");

    // TODO have a global palette

    let mut image = vec![None; (width*height) as usize];

    for (frame_no, pixels) in frames.into_iter() {

        for i in 0..image.len() {
            if image[i].is_some() && image[i].unwrap() > 0 {
                image[i] = image[i].map(|x| x-1);
            }
        }

        for (i, magnitude) in pixels {
            // FIXME sometimes the value is invalid
            //assert!(i < width*height, "{} L{}, width = {} height = {} i = {}", file!(), line!(), width, height, i);
            if i < width*height {
                image[i as usize] = Some(magnitude as u32);
            }
        }

        let mut pixels = Vec::with_capacity(image.len() * 4);
        for p in image.iter().cloned() {
            let index = colour_ramp.index_for_magnitude(p);
            pixels.push(index);
        }

        let mut frame = gif::Frame::from_indexed_pixels(width as u16, height as u16, pixels.as_mut_slice());
        // 30 fps, and delay is in units of 10ms.
        frame.delay = 100 / 30;

        encoder.write_frame(&frame).expect("Couldn't write frame");

        if frame_no % 30 == 0 {
            println!("Wrote frame {}", frame_no);
        }

    }

}

fn main() {
    let matches = App::new("osm-history-animation")
                          .arg(Arg::with_name("input").long("input").short("i")
                               .takes_value(true))
                          .arg(Arg::with_name("output") .long("output").short("o")
                               .takes_value(true))
                          .arg(Arg::with_name("height") .long("height").short("h")
                               .takes_value(true))
                          .arg(Arg::with_name("spf") .long("sec-per-frame").short("s")
                               .takes_value(true))
                          .arg(Arg::with_name("colour_ramp") .long("colour-ramp")
                               .takes_value(true))
                          .arg(Arg::with_name("save-intermediate").long("save-intermediate"))
                          .arg(Arg::with_name("load-intermediate").long("load-intermediate"))
                          .arg(Arg::with_name("bbox").long("bbox").takes_value(true).short("b"))
                          .setting(AppSettings::AllowLeadingHyphen)
                          .get_matches();

    let input_filename = matches.value_of("input").unwrap();
    let output_filename = matches.value_of("output").unwrap();
    let height: u32 = matches.value_of("height").unwrap().parse().unwrap();
    let sec_per_frame: u32 = matches.value_of("spf").unwrap().parse().unwrap();

    let bbox = match matches.value_of("bbox") {
        None => [-180., -90., 180., 90.],
        Some(text) => {
            let coords: Vec<f32> = text.split(",").map(|x| x.parse().unwrap() ).collect();
            [coords[0], coords[1], coords[2], coords[3]]
        }
    };

    let frames = if matches.is_present("load-intermediate") {
        println!("Reading frames from {}", input_filename);
        read_frames(&input_filename)
    } else {
        println!("Reading PBF file {}", input_filename);
        read_pbf(&input_filename, height, sec_per_frame, &bbox)
    };

    if matches.is_present("save-intermediate") {
        println!("Saving frame details to {}", output_filename);
        write_frames(frames, &output_filename);
    } else {
        let colour_ramp = ColourRamp::new_from_filename(matches.value_of("colour_ramp").unwrap());
        println!("Creating image {}", output_filename);
        create_equirectangular_map(frames, &output_filename, height, &bbox, &colour_ramp);
    }
    println!("\nFinished");
}
<commit_msg>save some metadata<commit_after>extern crate osmio;
extern crate image;
extern crate gif;
extern crate clap;

use clap::{Arg, App, AppSettings};

use std::fs;
use osmio::OSMReader;
use osmio::pbf::PBFReader;
use std::io::{Read, Write, BufReader, BufRead, BufWriter};
use std::collections::HashMap;

use gif::SetParameter;

// (frame_no, (pixel_index, num_changes))
type Frames = Vec<(u32, Vec<(u32, u16)>)>;

struct ColourRamp {
    empty_colour: (u8, u8, u8),
    steps: Vec<(u32, (u8, u8, u8))>,
}

impl ColourRamp {
    fn new_from_filename(filename: &str) -> Self {
        let mut contents = String::new();
        let mut file = fs::File::open(filename).unwrap();
        file.read_to_string(&mut contents).expect("Couldn't read colour ramp file");
        Self::new_from_text(&contents)

    }
    fn new_from_text(source: &str) -> Self {
        let lines: Vec<_> = source.lines().collect();
        let empty_vec = lines[0].split(",").filter_map(|x| x.parse::<u8>().ok()).take(3).collect::<Vec<_>>();
        let empty = (empty_vec[0], empty_vec[1], empty_vec[2]);

        let mut steps = Vec::new();
        for line in lines.iter().skip(1) {
            let line = line.split(",").filter_map(|x| x.parse::<u32>().ok()).take(4).collect::<Vec<_>>();
            let age = line[0];
            let colour = (line[1] as u8, line[2] as u8, line[3] as u8);
            steps.push((age, colour));
        }

        if steps.len() > 254 {
            panic!("Too many steps");
        }

        ColourRamp{ empty_colour: empty, steps: steps }
    }

    fn palette(&self) -> Vec<u8> {
        let mut results = Vec::with_capacity((self.steps.len()+1)*3);
        results.push(self.empty_colour.0);
        results.push(self.empty_colour.1);
        results.push(self.empty_colour.2);

        for &(_, (r, g, b)) in self.steps.iter() {
            results.push(r);
            results.push(g);
            results.push(b);
        }

        results
    }

    fn index_for_magnitude(&self, magnitude: Option<u32>) -> u8 {
        match magnitude {
            None => 0,
            Some(magnitude) => {
                if magnitude > 255 {
                    1
                } else {
                    (255 - magnitude) as u8
                }
            },
            //Some(age) => match self.steps.iter().position(|&(x, _)| x == age) {
            //    None => 0,
            //    Some(i) => (i+1) as u8,
            //}
        }
    }
}

fn read_pbf(filename: &str, height: u32, sec_per_frame: u32, bbox: &[f32; 4]) -> Frames {
    let file = BufReader::new(fs::File::open(&filename).unwrap());
    let mut node_reader = PBFReader::new(file);
    let node_reader = node_reader.nodes();

    let mut results: HashMap<u32, HashMap<u32, u16>> = HashMap::new();

    let left = bbox[0]; let bottom = bbox[1]; let right = bbox[2]; let top = bbox[3];
    let bbox_width = right - left;
    let bbox_height = top - bottom;
    let width = ((bbox_width / bbox_height) * (height as f32)) as u32;

    // 1st April 2005, midnight GMT. We presume no OSM editing before then.
    let osm_epoch = 1109635200;

    // FIXME use a btreemap?

    let mut first_frame_no = std::u32::MAX;
    let mut last_frame_no = 0;

    let mut num_nodes: u64 = 0;
    for node in node_reader {
        if let (Some(lat), Some(lon)) = (node.lat, node.lon) {
            // FIXME should be able to do non-equals but it fails for point at south pole
            if lat >= top || lat <= bottom || lon >= right || lon <= left {
                continue;
            }

            let timestamp = node.timestamp.to_epoch_number() as u64;
            if timestamp < osm_epoch {
                panic!("timestamp before epoch. Change code. {}", timestamp);
            }
            let offset = (timestamp - osm_epoch) as u32;
            // TODO double check that this rounds down
            let frame_no = offset / sec_per_frame;

            if frame_no < first_frame_no {
                first_frame_no = frame_no;
            }
            if frame_no > last_frame_no {
                last_frame_no = frame_no;
            }

            let pixel_idx = latlon_to_pixel_index(lat, lon, width, height, &bbox);
            let curr_val = results.entry(frame_no).or_insert(HashMap::new()).entry(pixel_idx).or_insert(0);
            if *curr_val < std::u16::MAX {
                *curr_val += 1;
            }

            num_nodes += 1;
            if num_nodes % 50_000_000 == 0 {
                println!("Done {} million points", num_nodes/1_000_000);
            }
        }
    }
    println!("Done {} points", num_nodes);
    let num_frames = last_frame_no - first_frame_no + 1;
    println!("There are {} frames, which is {} sec", num_frames, num_frames as f32/30.);

    let mut sorted_results = Vec::with_capacity((last_frame_no-first_frame_no+1) as usize);

    for frame_no in 0..num_frames {
        match results.remove(&(frame_no+first_frame_no)) {
            None => { sorted_results.push((frame_no, Vec::with_capacity(0))) },
            Some(pixels) => {
                let pixels = pixels.into_iter().collect();
                sorted_results.push((frame_no, pixels));
            }
        }
    }

    sorted_results
}

fn write_frames(frames: Frames, filename: &str, height: u32, sec_per_frame: u32, bbox: &[f32; 4]) {
    let left = bbox[0]; let bottom = bbox[1]; let right = bbox[2]; let top = bbox[3];
    let bbox_width = right - left;
    let bbox_height = top - bottom;
    let width = ((bbox_width / bbox_height) * (height as f32)) as u32;

    let mut file = BufWriter::new(fs::File::create(&filename).unwrap());

    writeln!(file, "metadata version {}", env!("CARGO_PKG_VERSION")).expect("Couldn't write metadata");
    writeln!(file, "metadata height {}", height).expect("Couldn't write metadata");
    writeln!(file, "metadata width {}", width).expect("Couldn't write metadata");
    writeln!(file, "metadata sec_per_frame {}", sec_per_frame).expect("Couldn't write metadata");
    writeln!(file, "metadata left {}", left).expect("Couldn't write metadata");
    writeln!(file, "metadata bottom {}", bottom).expect("Couldn't write metadata");
    writeln!(file, "metadata right {}", right).expect("Couldn't write metadata");
    writeln!(file, "metadata top {}", top).expect("Couldn't write metadata");
    writeln!(file, "").expect("Couldn't write metadata");

    for (frame_no, pixels) in frames.into_iter() {
        write!(file, "{}", frame_no).unwrap();
        for p in pixels {
            write!(file, ",{},{}", p.0, p.1).unwrap();
        }
        write!(file, "\n").unwrap()
    }
}

fn read_frames(filename: &str) -> Frames {
    let file = BufReader::new(fs::File::open(&filename).unwrap());
    let mut results = Frames::new();

    //let metadata: Vec<(String, String)> = file.lines().filter_map(|x| x.ok()).take_while(|x| x.len() > 0).map(|x| { let words: Vec<_> = x.split(" ").skip(1).take(2).collect(); (words[0].clone(), words[1].clone())}).collect();

    for line in file.lines().filter_map(|x| x.ok()).skip_while(|x| x.starts_with("metadata ") || x.len() == 0) {
        let frame_no = line.split(",").nth(0).unwrap().parse().unwrap();
        let pixels: Vec<(u32, u16)> = line.split(",").skip(1).collect::<Vec<_>>().chunks(2).map(|pair| (pair[0].parse().unwrap(), pair[1].parse().unwrap())).collect();
        results.push((frame_no, pixels))
    }

    results
}

fn latlon_to_pixel_index(lat: f32, lon: f32, width: u32, height: u32, bbox: &[f32; 4]) -> u32 {
    let left = bbox[0]; let bottom = bbox[1]; let right = bbox[2]; let top = bbox[3];
    let bbox_width = right - left;
    let bbox_height = top - bottom;

    let lat0 = top - lat;
    let lon0 = lon - left;

    let x = ((lon0/bbox_width)*(width as f32)) as u32;
    let y = ((lat0/bbox_height)*(height as f32)) as u32;

    let i = y * width + x;

    assert!(i < width*height, "{} L{}, lat = {} lon = {} width = {} height = {} bbox = {:?} x = {} y = {} i = {}", file!(), line!(), lat, lon, width, height, bbox, x, y, i);

    i
}

fn create_equirectangular_map(frames: Frames, output_image_filename: &str, height: u32, bbox: &[f32; 4], colour_ramp: &ColourRamp) {
    let mut output_file = fs::File::create(output_image_filename).expect("Can't create image");

    let left = bbox[0]; let bottom = bbox[1]; let right = bbox[2]; let top = bbox[3];
    let bbox_width = right - left;
    let bbox_height = top - bottom;
    let width = ((bbox_width / bbox_height) * (height as f32)) as u32;

    // FIXME change width/height to u16?
    let mut encoder = gif::Encoder::new(&mut output_file, width as u16, height as u16, &colour_ramp.palette()).expect("Couldn't create encoder");
    encoder.set(gif::Repeat::Infinite).expect("Couldn't get inf repeat");

    // TODO have a global palette

    let mut image = vec![None; (width*height) as usize];

    for (frame_no, pixels) in frames.into_iter() {

        for i in 0..image.len() {
            if image[i].is_some() && image[i].unwrap() > 0 {
                image[i] = image[i].map(|x| x-1);
            }
        }

        for (i, magnitude) in pixels {
            // FIXME sometimes the value is invalid
            //assert!(i < width*height, "{} L{}, width = {} height = {} i = {}", file!(), line!(), width, height, i);
            if i < width*height {
                image[i as usize] = Some(magnitude as u32);
            }
        }

        let mut pixels = Vec::with_capacity(image.len() * 4);
        for p in image.iter().cloned() {
            let index = colour_ramp.index_for_magnitude(p);
            pixels.push(index);
        }

        let mut frame = gif::Frame::from_indexed_pixels(width as u16, height as u16, pixels.as_mut_slice());
        // 30 fps, and delay is in units of 10ms.
        frame.delay = 100 / 30;

        encoder.write_frame(&frame).expect("Couldn't write frame");

        if frame_no % 30 == 0 {
            println!("Wrote frame {}", frame_no);
        }

    }

}

fn main() {
    let matches = App::new("osm-history-animation")
                          .arg(Arg::with_name("input").long("input").short("i")
                               .takes_value(true))
                          .arg(Arg::with_name("output") .long("output").short("o")
                               .takes_value(true))
                          .arg(Arg::with_name("height") .long("height").short("h")
                               .takes_value(true))
                          .arg(Arg::with_name("spf") .long("sec-per-frame").short("s")
                               .takes_value(true))
                          .arg(Arg::with_name("colour_ramp") .long("colour-ramp")
                               .takes_value(true))
                          .arg(Arg::with_name("save-intermediate").long("save-intermediate"))
                          .arg(Arg::with_name("load-intermediate").long("load-intermediate"))
                          .arg(Arg::with_name("bbox").long("bbox").takes_value(true).short("b"))
                          .setting(AppSettings::AllowLeadingHyphen)
                          .get_matches();

    let input_filename = matches.value_of("input").unwrap();
    let output_filename = matches.value_of("output").unwrap();
    let height: u32 = matches.value_of("height").unwrap().parse().unwrap();
    let sec_per_frame: u32 = matches.value_of("spf").unwrap().parse().unwrap();

    let bbox = match matches.value_of("bbox") {
        None => [-180., -90., 180., 90.],
        Some(text) => {
            let coords: Vec<f32> = text.split(",").map(|x| x.parse().unwrap() ).collect();
            [coords[0], coords[1], coords[2], coords[3]]
        }
    };

    let frames = if matches.is_present("load-intermediate") {
        println!("Reading frames from {}", input_filename);
        read_frames(&input_filename)
    } else {
        println!("Reading PBF file {}", input_filename);
        read_pbf(&input_filename, height, sec_per_frame, &bbox)
    };

    if matches.is_present("save-intermediate") {
        println!("Saving frame details to {}", output_filename);
        write_frames(frames, &output_filename, height, sec_per_frame, &bbox);
    } else {
        let colour_ramp = ColourRamp::new_from_filename(matches.value_of("colour_ramp").unwrap());
        println!("Creating image {}", output_filename);
        create_equirectangular_map(frames, &output_filename, height, &bbox, &colour_ramp);
    }
    println!("\nFinished");
}
<|endoftext|>


<commit_before>#[macro_use] extern crate macro_attr;
#[macro_use] extern crate enum_derive;

use std::io::Write;
use std::env;

mod keybinds;
use keybinds::*;

mod file;
use file::*;

mod terminal;
use terminal::*;

mod state;
use state::*;

mod indent;

fn get_file_size(term: &Terminal, state: &EditorState) -> (i32, i32) {
    let (screen_w, screen_h) = term.get_size();
    let one_liner_offset = match state.one_liner_active() {
        true => 1,
        false => 0
    };
    let tab_bar_offset = if state.files.len() > 1 {
        1
    } else {
        0
    };
    (screen_w - state.lineno_chars() - 1, screen_h - one_liner_offset - tab_bar_offset - 3)
}

fn render_file(out: &mut Terminal, state: &EditorState) {
    let file_size = get_file_size(out, state);
    let mut x = 1;
    let mut y = 1;

    let file = state.active_file();

    for (line_number_maybe, line) in file.wrapped_lines(file_size) {
        if let Some(line_number) = line_number_maybe {
            out.goto((x, y));
            out.set_color_fg(Color::Grey);
            write!(out, "{:1$}",
                   line_number + 1, file.lineno_chars() as usize).unwrap();
            out.set_color_fg(Color::Reset);
        }
        x += file.lineno_chars() + 1;
        out.goto((x, y));
        write!(out, "{}", line).unwrap();
        x = 1;
        y += 1;
    }
}

fn render_footer(out: &mut Terminal, state: &EditorState) {
    let (screen_width, screen_height) = out.get_size();

    let mut x = 1;
    let mut y = screen_height - 1;
    for (key, action) in state.keys.entries() {
        out.goto((x, y));
        out.set_color_fg(Color::Black);
        out.set_color_bg(Color::White);
        write!(out, "{}", key).unwrap();
        out.set_color_fg(Color::Reset);
        out.set_color_bg(Color::Reset);
        write!(out, " {}", action).unwrap();
        x += 16;
        if x > screen_width {
            x = 1;
            y -= 1;
        }
    }
}

fn render_status(out: &mut Terminal, state: &EditorState) {
    let (_, height) = out.get_size();
    let file_size = get_file_size(out, state);
    let x = 1;
    let y = height;
    out.goto((x, y));
    write!(out, "{}", state.debug(file_size)).unwrap();
}

fn render_one_liner(out: &mut Terminal, state: &EditorState) {
    if let &Some(ref ols) = state.one_liner() {
        let (_, screen_height) = out.get_size();
        let mut y = screen_height - 3;
        if state.files.len() > 1 {
            y -= 1;
        }

        out.goto((1, y));
        out.set_color_fg(Color::Black);
        out.set_color_bg(Color::White);
        write!(out, "{} ", ols.label).unwrap();
        out.set_color_fg(Color::Reset);
        out.set_color_bg(Color::Reset);
        write!(out, "{}", ols.value()).unwrap();
    }
}

fn render_tab_bar(out: &mut Terminal, state: &EditorState) {
    if state.files.len() > 1 {
        let (_, screen_height) = out.get_size();
        let mut x = 1;
        let y = screen_height - 3;

        for (i, f) in state.files.iter().enumerate() {
            out.goto((x, y));
            out.set_color_fg(Color::Black);
            if i == state.active_file {
                out.set_color_bg(Color::White);
            } else {
                out.set_color_bg(Color::Grey);
            }
            write!(out, "{}", f.name).unwrap();
            x += f.name.len() as i32 + 1;
        }
        out.set_color_fg(Color::Reset);
        out.set_color_bg(Color::Reset);
    }
}

fn main() {
    let mut term = Terminal::default();
    term.clear();
    term.flush().unwrap();
    let args: Vec<String> = env::args().collect();
    let filename = args.get(1).cloned().unwrap_or(String::from("README.md"));
    let mut state = EditorState {
        keys: KeybindTable::default(),
        files: vec![File::open(&filename)],
        one_liners: vec![None],
        active_file: 0,
    };
    render_footer(&mut term, &state);
    render_file(&mut term, &state);
    render_status(&mut term, &state);
    let file_size = get_file_size(&term, &state);
    term.goto(state.cursor(file_size));
    term.flush().unwrap();
    let mut file_lines = state.lines_len();
    let mut file_wrapped_lines = state.wrapped_lines(file_size).len();
    let mut file_dirty = false;
    let mut screen_dirty = false;
    for evt in term.keys() {
        let file_size = get_file_size(&term, &state);
        match evt {
            Event::Mouse(_) => (),
            Event::Unsupported(_) => (),
            Event::Key(Key::Null) => (),
            Event::Key(Key::Insert) => (),
            Event::Key(Key::F(_)) => (),
            Event::Key(Key::Esc) => {
                state.one_liner_mut().take();
                screen_dirty = true;
            },
            Event::Key(Key::Ctrl('\t')) => {
                state.next_tab();
                screen_dirty = true;
            }
            Event::Key(k @ Key::Ctrl(_)) | Event::Key(k @ Key::Alt(_)) => {
                match state.keys.lookup(k) {
                    Some(Command::Quit) => break,
                    Some(Command::Refresh) => {
                        state.refresh(file_size);
                        screen_dirty = true;
                    },
                    Some(Command::NewTab) => {
                        state.new_tab();
                        screen_dirty = true;
                    },
                    Some(Command::SaveFile) => {
                        let mut ols = OneLinerState::from(Command::SaveFile);
                        ols.file.lines[0] = state.active_file().name.clone();
                        ols.file.move_cursor_end(file_size);
                        state.set_one_liner(ols);
                        screen_dirty = true;
                    },
                    Some(Command::OpenFile) => {
                        let ols = OneLinerState::from(Command::OpenFile);
                        state.set_one_liner(ols);
                        screen_dirty = true;
                    },
                    Some(Command::CloseFile) => {
                        state.close_tab();
                        if state.files.len() == 0 {
                            break;
                        }
                        screen_dirty = true;
                    },
                    None => (),
                    _ => ()
                }
            },
            Event::Key(Key::Left) => {
                screen_dirty = state.move_cursor_left(file_size);
            },
            Event::Key(Key::Right) => {
                screen_dirty = state.move_cursor_right(file_size);
            },
            Event::Key(Key::Up) => {
                screen_dirty = state.move_cursor_up(file_size);
            },
            Event::Key(Key::Down) => {
                screen_dirty = state.move_cursor_down(file_size);
            },
            Event::Key(Key::Home) => state.move_cursor_home(file_size),
            Event::Key(Key::End) => state.move_cursor_end(file_size),
            Event::Key(Key::PageUp) => {
                state.page_up(file_size);
                screen_dirty = true;
            },
            Event::Key(Key::PageDown) => {
                state.page_down(file_size);
                screen_dirty = true;
            },
            Event::Key(Key::Char('\t')) if state.one_liner_active() => {
                if let &mut Some(ref mut ols) = state.one_liner_mut() {
                    match ols.command {
                        Command::SaveFile | Command::OpenFile => ols.tab(),
                        _ => ()
                    }
                }
                file_dirty = true;
            },
            Event::Key(Key::Char('\t')) => {
                for _ in 0..4 {
                    state.insert(file_size, ' ');
                }
                file_dirty = true;
            },
            Event::Key(Key::Char('\n')) => {
                if let Some((command, value)) = state.consume_one_liner() {
                    match command {
                        Command::SaveFile => {
                            state.save_file(&value);
                        },
                        Command::OpenFile => {
                            state.open_file(&value);
                        },
                        _ => ()
                    };
                } else {
                    state.insert_newline(file_size);
                }
                screen_dirty = true;
            },
            Event::Key(Key::Delete) => {
                state.delete(file_size);
                screen_dirty = true;
            },
            Event::Key(Key::Backspace) => {
                state.backspace(file_size);
                screen_dirty = true;
            },
            Event::Key(Key::Char(c)) => {
                state.insert(file_size, c);
                file_dirty = true;
            },
        }
        let file_size = get_file_size(&term, &state);
        if screen_dirty {
            file_dirty = true;
        }
        if file_dirty {
            let new_file_lines = state.lines_len();
            let new_file_wrapped_lines = state.wrapped_lines(file_size).len();
            if new_file_lines != file_lines {
                screen_dirty = true;
                file_lines = new_file_lines;
            }
            if new_file_wrapped_lines != file_wrapped_lines {
                screen_dirty = true;
                file_wrapped_lines = new_file_wrapped_lines;
            }
        }
        if screen_dirty {
            term.clear();
            render_footer(&mut term, &state);
            render_tab_bar(&mut term, &state);
            screen_dirty = false;
        }
        if file_dirty {
            render_file(&mut term, &state);
            render_one_liner(&mut term, &state);
            file_dirty = false;
        }
        render_status(&mut term, &state);
        term.goto(state.cursor(file_size));
        term.flush().unwrap();
    }
}
<commit_msg>Don't open README.md by default<commit_after>#[macro_use] extern crate macro_attr;
#[macro_use] extern crate enum_derive;

use std::io::Write;
use std::env;

mod keybinds;
use keybinds::*;

mod file;
use file::*;

mod terminal;
use terminal::*;

mod state;
use state::*;

mod indent;

fn get_file_size(term: &Terminal, state: &EditorState) -> (i32, i32) {
    let (screen_w, screen_h) = term.get_size();
    let one_liner_offset = match state.one_liner_active() {
        true => 1,
        false => 0
    };
    let tab_bar_offset = if state.files.len() > 1 {
        1
    } else {
        0
    };
    (screen_w - state.lineno_chars() - 1, screen_h - one_liner_offset - tab_bar_offset - 3)
}

fn render_file(out: &mut Terminal, state: &EditorState) {
    let file_size = get_file_size(out, state);
    let mut x = 1;
    let mut y = 1;

    let file = state.active_file();

    for (line_number_maybe, line) in file.wrapped_lines(file_size) {
        if let Some(line_number) = line_number_maybe {
            out.goto((x, y));
            out.set_color_fg(Color::Grey);
            write!(out, "{:1$}",
                   line_number + 1, file.lineno_chars() as usize).unwrap();
            out.set_color_fg(Color::Reset);
        }
        x += file.lineno_chars() + 1;
        out.goto((x, y));
        write!(out, "{}", line).unwrap();
        x = 1;
        y += 1;
    }
}

fn render_footer(out: &mut Terminal, state: &EditorState) {
    let (screen_width, screen_height) = out.get_size();

    let mut x = 1;
    let mut y = screen_height - 1;
    for (key, action) in state.keys.entries() {
        out.goto((x, y));
        out.set_color_fg(Color::Black);
        out.set_color_bg(Color::White);
        write!(out, "{}", key).unwrap();
        out.set_color_fg(Color::Reset);
        out.set_color_bg(Color::Reset);
        write!(out, " {}", action).unwrap();
        x += 16;
        if x > screen_width {
            x = 1;
            y -= 1;
        }
    }
}

fn render_status(out: &mut Terminal, state: &EditorState) {
    let (_, height) = out.get_size();
    let file_size = get_file_size(out, state);
    let x = 1;
    let y = height;
    out.goto((x, y));
    write!(out, "{}", state.debug(file_size)).unwrap();
}

fn render_one_liner(out: &mut Terminal, state: &EditorState) {
    if let &Some(ref ols) = state.one_liner() {
        let (_, screen_height) = out.get_size();
        let mut y = screen_height - 3;
        if state.files.len() > 1 {
            y -= 1;
        }

        out.goto((1, y));
        out.set_color_fg(Color::Black);
        out.set_color_bg(Color::White);
        write!(out, "{} ", ols.label).unwrap();
        out.set_color_fg(Color::Reset);
        out.set_color_bg(Color::Reset);
        write!(out, "{}", ols.value()).unwrap();
    }
}

fn render_tab_bar(out: &mut Terminal, state: &EditorState) {
    if state.files.len() > 1 {
        let (_, screen_height) = out.get_size();
        let mut x = 1;
        let y = screen_height - 3;

        for (i, f) in state.files.iter().enumerate() {
            out.goto((x, y));
            out.set_color_fg(Color::Black);
            if i == state.active_file {
                out.set_color_bg(Color::White);
            } else {
                out.set_color_bg(Color::Grey);
            }
            write!(out, "{}", f.name).unwrap();
            x += f.name.len() as i32 + 1;
        }
        out.set_color_fg(Color::Reset);
        out.set_color_bg(Color::Reset);
    }
}

fn main() {
    let mut term = Terminal::default();
    term.clear();
    term.flush().unwrap();
    let mut state = EditorState {
        keys: KeybindTable::default(),
        files: vec![],
        one_liners: vec![],
        active_file: 0,
    };
    for filename in env::args().skip(1) {
        state.files.push(File::open(&filename));
        state.one_liners.push(None);
    }
    if state.files.len() == 0 {
        state.files.push(File::empty());
        state.one_liners.push(None);
    }
    render_footer(&mut term, &state);
    render_file(&mut term, &state);
    render_status(&mut term, &state);
    render_tab_bar(&mut term, &state);
    let file_size = get_file_size(&term, &state);
    term.goto(state.cursor(file_size));
    term.flush().unwrap();
    let mut file_lines = state.lines_len();
    let mut file_wrapped_lines = state.wrapped_lines(file_size).len();
    let mut file_dirty = false;
    let mut screen_dirty = false;
    for evt in term.keys() {
        let file_size = get_file_size(&term, &state);
        match evt {
            Event::Mouse(_) => (),
            Event::Unsupported(_) => (),
            Event::Key(Key::Null) => (),
            Event::Key(Key::Insert) => (),
            Event::Key(Key::F(_)) => (),
            Event::Key(Key::Esc) => {
                state.one_liner_mut().take();
                screen_dirty = true;
            },
            Event::Key(Key::Ctrl('\t')) => {
                state.next_tab();
                screen_dirty = true;
            }
            Event::Key(k @ Key::Ctrl(_)) | Event::Key(k @ Key::Alt(_)) => {
                match state.keys.lookup(k) {
                    Some(Command::Quit) => break,
                    Some(Command::Refresh) => {
                        state.refresh(file_size);
                        screen_dirty = true;
                    },
                    Some(Command::NewTab) => {
                        state.new_tab();
                        screen_dirty = true;
                    },
                    Some(Command::SaveFile) => {
                        let mut ols = OneLinerState::from(Command::SaveFile);
                        ols.file.lines[0] = state.active_file().name.clone();
                        ols.file.move_cursor_end(file_size);
                        state.set_one_liner(ols);
                        screen_dirty = true;
                    },
                    Some(Command::OpenFile) => {
                        let ols = OneLinerState::from(Command::OpenFile);
                        state.set_one_liner(ols);
                        screen_dirty = true;
                    },
                    Some(Command::CloseFile) => {
                        state.close_tab();
                        if state.files.len() == 0 {
                            break;
                        }
                        screen_dirty = true;
                    },
                    None => (),
                    _ => ()
                }
            },
            Event::Key(Key::Left) => {
                screen_dirty = state.move_cursor_left(file_size);
            },
            Event::Key(Key::Right) => {
                screen_dirty = state.move_cursor_right(file_size);
            },
            Event::Key(Key::Up) => {
                screen_dirty = state.move_cursor_up(file_size);
            },
            Event::Key(Key::Down) => {
                screen_dirty = state.move_cursor_down(file_size);
            },
            Event::Key(Key::Home) => state.move_cursor_home(file_size),
            Event::Key(Key::End) => state.move_cursor_end(file_size),
            Event::Key(Key::PageUp) => {
                state.page_up(file_size);
                screen_dirty = true;
            },
            Event::Key(Key::PageDown) => {
                state.page_down(file_size);
                screen_dirty = true;
            },
            Event::Key(Key::Char('\t')) if state.one_liner_active() => {
                if let &mut Some(ref mut ols) = state.one_liner_mut() {
                    match ols.command {
                        Command::SaveFile | Command::OpenFile => ols.tab(),
                        _ => ()
                    }
                }
                file_dirty = true;
            },
            Event::Key(Key::Char('\t')) => {
                for _ in 0..4 {
                    state.insert(file_size, ' ');
                }
                file_dirty = true;
            },
            Event::Key(Key::Char('\n')) => {
                if let Some((command, value)) = state.consume_one_liner() {
                    match command {
                        Command::SaveFile => {
                            state.save_file(&value);
                        },
                        Command::OpenFile => {
                            state.open_file(&value);
                        },
                        _ => ()
                    };
                } else {
                    state.insert_newline(file_size);
                }
                screen_dirty = true;
            },
            Event::Key(Key::Delete) => {
                state.delete(file_size);
                screen_dirty = true;
            },
            Event::Key(Key::Backspace) => {
                state.backspace(file_size);
                screen_dirty = true;
            },
            Event::Key(Key::Char(c)) => {
                state.insert(file_size, c);
                file_dirty = true;
            },
        }
        let file_size = get_file_size(&term, &state);
        if screen_dirty {
            file_dirty = true;
        }
        if file_dirty {
            let new_file_lines = state.lines_len();
            let new_file_wrapped_lines = state.wrapped_lines(file_size).len();
            if new_file_lines != file_lines {
                screen_dirty = true;
                file_lines = new_file_lines;
            }
            if new_file_wrapped_lines != file_wrapped_lines {
                screen_dirty = true;
                file_wrapped_lines = new_file_wrapped_lines;
            }
        }
        if screen_dirty {
            term.clear();
            render_footer(&mut term, &state);
            render_tab_bar(&mut term, &state);
            screen_dirty = false;
        }
        if file_dirty {
            render_file(&mut term, &state);
            render_one_liner(&mut term, &state);
            file_dirty = false;
        }
        render_status(&mut term, &state);
        term.goto(state.cursor(file_size));
        term.flush().unwrap();
    }
}
<|endoftext|>


<commit_before>#![feature(libc)]
extern crate libc;

extern crate rustwlc;

use rustwlc::types;
use rustwlc::types::*;
//use rustwlc::types::LibinputDevice;
use rustwlc::handle::{WlcView, WlcOutput};
use rustwlc::types::interface::*;

fn main() {
    let interface: WlcInterface = WlcInterface {
        output: OutputInterface {
            created: output_created,
            destroyed: output_destroyed,
            focus: output_focus,
            resolution: output_resolution,

            render: OutputRenderInterface {
                pre: output_render_pre,
                post: output_render_post
            }
        },
        view: ViewInterface {
            created: view_created,
            destroyed: view_destroyed,
            focus: view_focus,
            move_to_output: view_move_to_output,
            request: RequestInterface {
                geometry: view_request_geometry,
                state: view_request_state,
                move_: view_request_move,
                resize: view_request_resize,
                render: ViewRenderInterface {
                    pre: view_request_render_pre,
                    post: view_request_render_post
                }
            }
        },
        keyboard: KeyboardInterface {
            key: keyboard_key
        },
        pointer: PointerInterface {
            button: pointer_button,
            scroll: pointer_scroll,
            motion: pointer_motion
        },
        touch: TouchInterface {
            touch: touch_touch
        },
        compositor: CompositorInterface {
            ready: compositor_ready
        },
        input: InputInterface {
            created: input_created,
            destroyed: input_destroyed
        }
    };
    // Interfaces don't derive debug
    //println!("Created interface {:?}", interface);

    if !rustwlc::init(interface) {
        panic!("Unable to initialize wlc!");
    }
    rustwlc::run_wlc();
}

// Important rendering functions copied from wlc/example/example.c

fn start_interactive_action(view: WlcView, origin: Point) -> bool {
    true
}

fn stop_interactive_action() {

}

fn start_interactive_move(view: WlcView, origin: Point) {

}

fn start_interactive_resize(view: WlcView, edges: u32, origin: Point) {

}

fn get_topmost_view(output: WlcOutput, offset: Size) {

}

/// From example.c:
/// very simple layout function
/// you probably don't want to layout certain type of windows in wm
fn render_output(output: WlcOutput) {
    let resolution = output.get_resolution();
    //let views = output.get_views();
}

// Hook up basic callbacks

extern fn output_created(output: WlcOutput) -> bool {
    println!("output_created");
    return true;
}

extern fn output_destroyed(output: WlcOutput) {
    println!("output_destroyed");
}

extern fn output_focus(output: WlcOutput, focused: bool) {
    println!("output_focus: {}", focused);
}

extern fn output_resolution(output: WlcOutput, old_size: Size, new_size: Size) {
    println!("output_resolution: {:?} to {:?}", old_size, new_size)
}

extern fn output_render_pre(output: WlcOutput) {
    println!("output_render_pre");
}

extern fn output_render_post(output: WlcOutput) {
    println!("output_render_post");
}

extern fn view_created(view: WlcView) -> bool {
    println!("view_created");
    view.bring_to_front();
    view.focus();
    //render_output(view.get_output());
    true
}

extern fn view_destroyed(view: WlcView) {
    println!("view_destroyed");
    //let next_up =
}

extern fn view_focus(current: WlcView, focused: bool) {
    println!("view_focus: {}", focused);
    //view.set_state()
}

extern fn view_move_to_output(current: WlcView, q1: WlcView, q2: WlcView) {
    println!("view_move_to_output");
}

extern fn view_request_geometry(view: WlcView, geometry: Geometry) {
    println!("view_request_geometry: call wlc_view_set_geometry({:?})", geometry);
}

extern fn view_request_state(view: WlcView, state: ViewState, handled: bool) {
    println!("view_request_state: call wlc_view_set_state({:?})", state);
}

extern fn view_request_move(view: WlcView, dest: Point) {
    println!("view_request_move: to {}, start interactive mode.", dest);
}

extern fn view_request_resize(view: WlcView, edge: ResizeEdge, location: Point) {
    println!("view_request_resize: size {:?}, to {}, start interactive mode.",
             edge, location);
}

extern fn view_request_render_pre(view: WlcView) {
    println!("view_request_render_pre");
}

extern fn view_request_render_post(view: WlcView) {
    println!("view_request_render_post");
}

extern fn keyboard_key(view: WlcView, time: u32, mods: KeyboardModifiers,
                       key: u32, state: KeyState) -> bool {
    false
}

extern fn pointer_button(view: WlcView, button: libc::c_uint, mods: KeyboardModifiers,
                  key: u32, state: ButtonState, point: Point) -> bool {
    println!("pointer_button: key {}, point {}", key, point);

    if state == ButtonState::Pressed {
        view.focus();
    }
    false
}

extern fn pointer_scroll(view: WlcView, button: u32, mods: KeyboardModifiers,
                  axis: ScrollAxis, heights: [u64; 2]) -> bool {
    println!("pointer_scroll");
    false
}

extern fn pointer_motion(view: WlcView, dist: u32, point: Point) {
    println!("Pointer moved {} pixels? to {}", dist, point);
    // TODO wlc_pointer_set_position
}

extern fn touch_touch(view: WlcView, time: libc::c_uint, mods: KeyboardModifiers,
               touch: TouchType, key: i32, point: Point) -> bool {
    false
}

extern fn compositor_ready() {
    println!("Preparing compositor!");
}

extern fn input_created(device: LibinputDevice) -> bool {
    println!("input_created");
    false
}

extern fn input_destroyed(device: LibinputDevice) {
    println!("input_destroyed");
}
<commit_msg>Mouse moves now<commit_after>#![feature(libc)]
extern crate libc;

extern crate rustwlc;

use rustwlc::types;
use rustwlc::types::*;
//use rustwlc::types::LibinputDevice;
use rustwlc::handle::{WlcView, WlcOutput};
use rustwlc::types::interface::*;
use rustwlc::input::pointer;
use rustwlc::input::keyboard;

fn main() {
    let interface: WlcInterface = WlcInterface {
        output: OutputInterface {
            created: output_created,
            destroyed: output_destroyed,
            focus: output_focus,
            resolution: output_resolution,

            render: OutputRenderInterface {
                pre: output_render_pre,
                post: output_render_post
            }
        },
        view: ViewInterface {
            created: view_created,
            destroyed: view_destroyed,
            focus: view_focus,
            move_to_output: view_move_to_output,
            request: RequestInterface {
                geometry: view_request_geometry,
                state: view_request_state,
                move_: view_request_move,
                resize: view_request_resize,
                render: ViewRenderInterface {
                    pre: view_request_render_pre,
                    post: view_request_render_post
                }
            }
        },
        keyboard: KeyboardInterface {
            key: keyboard_key
        },
        pointer: PointerInterface {
            button: pointer_button,
            scroll: pointer_scroll,
            motion: pointer_motion
        },
        touch: TouchInterface {
            touch: touch_touch
        },
        compositor: CompositorInterface {
            ready: compositor_ready
        },
        input: InputInterface {
            created: input_created,
            destroyed: input_destroyed
        }
    };
    // Interfaces don't derive debug
    //println!("Created interface {:?}", interface);

    if !rustwlc::init(interface) {
        panic!("Unable to initialize wlc!");
    }
    rustwlc::run_wlc();
}

// Important rendering functions copied from wlc/example/example.c

fn start_interactive_action(view: WlcView, origin: Point) -> bool {
    true
}

fn stop_interactive_action() {

}

fn start_interactive_move(view: WlcView, origin: Point) {

}

fn start_interactive_resize(view: WlcView, edges: u32, origin: Point) {

}

fn get_topmost_view(output: WlcOutput, offset: Size) {

}

/// From example.c:
/// very simple layout function
/// you probably don't want to layout certain type of windows in wm
fn render_output(output: WlcOutput) {
    let resolution = output.get_resolution();
    //let views = output.get_views();
}

// Hook up basic callbacks

extern fn output_created(output: WlcOutput) -> bool {
    println!("output_created");
    return true;
}

extern fn output_destroyed(output: WlcOutput) {
    println!("output_destroyed");
}

extern fn output_focus(output: WlcOutput, focused: bool) {
    println!("output_focus: {}", focused);
}

extern fn output_resolution(output: WlcOutput, old_size: Size, new_size: Size) {
    println!("output_resolution: {:?} to {:?}", old_size, new_size)
}

extern fn output_render_pre(output: WlcOutput) {
    println!("output_render_pre");
}

extern fn output_render_post(output: WlcOutput) {
    println!("output_render_post");
}

extern fn view_created(view: WlcView) -> bool {
    println!("view_created");
    view.bring_to_front();
    view.focus();
    //render_output(view.get_output());
    true
}

extern fn view_destroyed(view: WlcView) {
    println!("view_destroyed");
    //let next_up =
}

extern fn view_focus(current: WlcView, focused: bool) {
    println!("view_focus: {}", focused);
    //view.set_state()
}

extern fn view_move_to_output(current: WlcView, q1: WlcView, q2: WlcView) {
    println!("view_move_to_output");
}

extern fn view_request_geometry(view: WlcView, geometry: Geometry) {
    println!("view_request_geometry: call wlc_view_set_geometry({:?})", geometry);
}

extern fn view_request_state(view: WlcView, state: ViewState, handled: bool) {
    println!("view_request_state: call wlc_view_set_state({:?})", state);
}

extern fn view_request_move(view: WlcView, dest: Point) {
    println!("view_request_move: to {}, start interactive mode.", dest);
}

extern fn view_request_resize(view: WlcView, edge: ResizeEdge, location: Point) {
    println!("view_request_resize: size {:?}, to {}, start interactive mode.",
             edge, location);
}

extern fn view_request_render_pre(view: WlcView) {
    println!("view_request_render_pre");
}

extern fn view_request_render_post(view: WlcView) {
    println!("view_request_render_post");
}

extern fn keyboard_key(view: WlcView, time: u32, mods: KeyboardModifiers,
                       key: u32, state: KeyState) -> bool {
    false
}

extern fn pointer_button(view: WlcView, button: libc::c_uint, mods: KeyboardModifiers,
                  key: u32, state: ButtonState, point: Point) -> bool {
    println!("pointer_button: key {}, point {}", key, point);

    if state == ButtonState::Pressed {
        view.focus();
    }
    false
}

extern fn pointer_scroll(view: WlcView, button: u32, mods: KeyboardModifiers,
                  axis: ScrollAxis, heights: [u64; 2]) -> bool {
    println!("pointer_scroll");
    false
}

extern fn pointer_motion(view: WlcView, time: u32, point: Point) {
    println!("Pointer moved {} to {}", time, point);
    // TODO wlc_pointer_set_position
    pointer::set_position(point);
}

extern fn touch_touch(view: WlcView, time: libc::c_uint, mods: KeyboardModifiers,
               touch: TouchType, key: i32, point: Point) -> bool {
    false
}

extern fn compositor_ready() {
    println!("Preparing compositor!");
}

extern fn input_created(device: LibinputDevice) -> bool {
    println!("input_created");
    false
}

extern fn input_destroyed(device: LibinputDevice) {
    println!("input_destroyed");
}
<|endoftext|>


<commit_before>
extern crate walkdir;

use std::ffi::OsString;
use std::env;
use std::path::PathBuf;
use std::process::Command;
use walkdir::{DirEntry, WalkDir, WalkDirIterator};

struct CargoMultiCmd {
    command: Command,
    banner: String,
    top_directory: PathBuf,
    directories: Vec<PathBuf>,
}

impl CargoMultiCmd {
    fn new(cmd: &str, args: Vec<String>) -> Self {

        let mut command = Command::new(cmd);
        let mut banner = String::from("Executing ");
        banner.push_str(cmd);
        for arg in args {
            command.arg(OsString::from(&arg));
            banner = banner + " " + &arg;
        }

        CargoMultiCmd {
            command: command,
            banner: banner,
            top_directory: PathBuf::new(),
            directories: Vec::new(),
        }
    }

    fn set_top_dir(&mut self, dir: PathBuf) -> &mut Self {
        self.top_directory = dir;
        self
    }

    fn collect_crate_candidates(&mut self) -> &mut Self {
        self.directories = WalkDir::new(&self.top_directory)
                               .min_depth(1)
                               .max_depth(1)
                               .into_iter()
                               .filter_entry(|e| is_crate(e))
                               .map(|e| e.ok().unwrap().path().to_path_buf())
                               .collect::<Vec<_>>();
        self
    }

    fn announce(&self) -> &Self {
        let mut line = String::new();
        for _ in 0..self.banner.len() {
            line.push('-');
        }
        println!("{}", line);
        println!("{}", self.banner);
        println!("{}", line);
        self
    }

    fn dispatch(&mut self) -> &Self {
        for dir in &self.directories {
            println!("{}:", dir.display());
            let out = self.command
                          .current_dir(dir)
                          .output()
                          .unwrap_or_else(|e| panic!("failed to execute process: {}", e));
            if out.status.success() {
                println!("{}",
                         ident_text(String::from_utf8_lossy(&out.stdout).into_owned()));
            } else {
                println!("{}",
                         ident_text(String::from_utf8_lossy(&out.stderr).into_owned()));
            }
            println!("");
        }
        self
    }
}

fn ident_text(text: String) -> String {
    let mut out = String::new();

    for line in text.lines() {
        out.push_str("        ");
        out.push_str(line);
        out.push('\n');
    }
    out
}

fn is_crate(entry: &DirEntry) -> bool {
    entry.path().join("Cargo.toml").exists()
}

fn main() {
    let args = env::args().skip(2).collect();
    let cwd = env::current_dir().unwrap();
    let mut multi = CargoMultiCmd::new("cargo", args);

    multi.set_top_dir(cwd);
    multi.collect_crate_candidates();
    multi.announce();
    multi.dispatch();
}
<commit_msg>Refactor output logging<commit_after>
extern crate walkdir;

use std::ffi::OsString;
use std::env;
use std::path::PathBuf;
use std::process::Command;
use walkdir::{DirEntry, WalkDir, WalkDirIterator};

struct CargoMultiCmd {
    command: Command,
    banner: String,
    top_directory: PathBuf,
    directories: Vec<PathBuf>,
}

impl CargoMultiCmd {
    fn new(cmd: &str, args: Vec<String>) -> Self {

        let mut command = Command::new(cmd);
        let mut banner = String::from("Executing ");
        banner.push_str(cmd);
        for arg in args {
            command.arg(OsString::from(&arg));
            banner = banner + " " + &arg;
        }

        CargoMultiCmd {
            command: command,
            banner: banner,
            top_directory: PathBuf::new(),
            directories: Vec::new(),
        }
    }

    fn set_top_dir(&mut self, dir: PathBuf) -> &mut Self {
        self.top_directory = dir;
        self
    }

    fn collect_crate_candidates(&mut self) -> &mut Self {
        self.directories = WalkDir::new(&self.top_directory)
                               .min_depth(1)
                               .max_depth(1)
                               .into_iter()
                               .filter_entry(|e| is_crate(e))
                               .map(|e| e.ok().unwrap().path().to_path_buf())
                               .collect::<Vec<_>>();
        self
    }

    fn announce(&self) -> &Self {
        let mut line = String::new();
        for _ in 0..self.banner.len() {
            line.push('-');
        }
        println!("{}", line);
        println!("{}", self.banner);
        println!("{}", line);
        self
    }

    fn dispatch(&mut self) -> &Self {
        for dir in &self.directories {
            println!("{}:", dir.display());
            let out = self.command
                          .current_dir(dir)
                          .output()
                          .unwrap_or_else(|e| panic!("failed to execute process: {}", e));
            if out.status.success() {
                print_ident(out.stdout);
            } else {
                print_ident(out.stderr);
            }
            println!("");
        }
        self
    }
}

fn print_ident(buf: Vec<u8>)
{
    // ::<'a>(v: &'a [u8])
    for line in String::from_utf8_lossy(buf.as_slice()).lines() {
        println!("        {}", line);
    }
}

fn is_crate(entry: &DirEntry) -> bool {
    entry.path().join("Cargo.toml").exists()
}

fn main() {
    let args = env::args().skip(2).collect();
    let cwd = env::current_dir().unwrap();
    let mut multi = CargoMultiCmd::new("cargo", args);

    multi.set_top_dir(cwd);
    multi.collect_crate_candidates();
    multi.announce();
    multi.dispatch();
}
<|endoftext|>