<commit_before>extern crate argparse;
extern crate glob;
extern crate regex;

use argparse::{ArgumentParser, StoreTrue, Store, StoreOption, Print};
use std::io::BufRead;
use glob::glob;
use regex::Regex;

fn identity<T>(x: T) -> T {x}

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

fn get_possible_files_from_glob() -> Result<Vec<std::path::PathBuf>, glob::PatternError> {
    // Dir.glob("**/*").reject { |p| File.directory?(p) }.map { |p| Path.new(p) }
    return glob("**/*").map(|paths| paths.flat_map(identity).filter(|path| path.is_file()).collect())
}

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

fn is_test_file(path: &String) -> bool {
    let re = Regex::new(r"^(features/|test/|spec/|tests/)").unwrap();
    re.is_match(path.as_str())
}

fn strip_test_words(filename: &String) -> String {
    let re = Regex::new(r"(test_)?(?P<p>\w+?)(_rake_spec|_spec|_test|_steps)?(\.rb|\.exs|\.ex|\.js|\.py)?$").unwrap();
    re.replace_all(filename.as_str(), "$p")
}

fn cleanse_path(path: &String) -> String {
    let re = Regex::new(r"^(\./|\r|\n| )").unwrap();
    re.replace_all(path.as_str(), "")
}

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

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

    println!("debug: {}", options.debug);
    println!("required path: {}", options.path);

    if let Some(unwrapped_file) = options.file {
        println!("file: {}", unwrapped_file);
        if unwrapped_file == "-" {
            let stdin = std::io::stdin();
            for line in stdin.lock().lines() {
              println!("{}", line.unwrap());
            }
        } else {
            // figure out how to open specified file and read in as content
        }
    } else {
        match get_possible_files_from_glob() {
            Ok(paths) => {
                // - get collection of possible alternate file paths
                // - cleanse possible paths (stripping prefixed ./ and postfixed \r,\n,sp)
                // - if path is test file
                //      - reduce set to paths that match filename stripped of test words and extensions
                //      - reduce set to non-test files
                //   else
                //      - reduce set to paths that match filename stripped of test words and extensions
                //      - reduce set to test files
                // - score the reduced set of possible paths, tracking the highest score
                // - return the path with the highest score

                let cleansed_path = cleanse_path(&options.path);
                let filename = get_filename_minus_extension(&options.path);
                if is_test_file(&cleansed_path) {
                    let filename = strip_test_words(&filename);
                    let reduced_paths = paths.iter()
                        .map(|path| cleanse_path(&path.to_str().unwrap().to_string()))
                        .filter(|path| path.contains(filename.as_str()))  // filter to paths that contain the filename
                        .filter(|path| !is_test_file(&path)); // filter to paths that aren't test files
                    for path in reduced_paths {
                        println!("{:?}", path);
                    }
                } else {
                    let reduced_paths = paths.iter()
                        .map(|path| cleanse_path(&path.to_str().unwrap().to_string()))
                        .filter(|path| path.contains(filename.as_str())) // filter to paths that contain the filename
                        .filter(|path| is_test_file(&path)); // filter to paths that ARE test files
                    for path in reduced_paths {
                        println!("{:?}", path);
                    }
                }
            },
            Err(e) => println!("{:?}", e)
        }
    }

}
<commit_msg>Added longest common substring and scoring<commit_after>extern crate argparse;
extern crate glob;
extern crate regex;

use argparse::{ArgumentParser, StoreTrue, Store, StoreOption, Print};
use std::io::BufRead;
use glob::glob;
use regex::Regex;

fn identity<T>(x: T) -> T {x}

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

fn get_possible_files_from_glob() -> Result<Vec<std::path::PathBuf>, glob::PatternError> {
    // Dir.glob("**/*").reject { |p| File.directory?(p) }.map { |p| Path.new(p) }
    glob("**/*").map(|paths| paths.flat_map(identity).filter(|path| path.is_file()).collect())
}

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

fn is_test_file(path: &String) -> bool {
    let re = Regex::new(r"^(features/|test/|spec/|tests/)").unwrap();
    re.is_match(path.as_str())
}

fn strip_test_words(filename: &String) -> String {
    let re = Regex::new(r"(test_)?(?P<p>\w+?)(_rake_spec|_spec|_test|_steps)?(\.rb|\.exs|\.ex|\.js|\.py)?$").unwrap();
    re.replace_all(filename.as_str(), "$p")
}

fn cleanse_path(path: &String) -> String {
    let re = Regex::new(r"^(\./|\r|\n| )").unwrap();
    re.replace_all(path.as_str(), "")
}

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

    let mut m: Vec<Vec<i32>> = Vec::new();
    for x in 0..s1.len() {
        let mut v: Vec<i32> = Vec::new();
        for y in 0..s2.len() {
            v.push(0);
        }
        m.push(v);
    }

    let mut longest_length = 0;
    let mut longest_end_pos = 0;

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

    let start: usize = longest_end_pos as usize - longest_length as usize + 1;
    let end: usize = longest_end_pos as usize;
    s1[start..end].to_string()
}

fn score(s1: &String, s2: &String) -> f32 {
    // TODO: Improve performance. At the moment the find_longest_common_substring
    // method is the most costly operation in this app. This leaves us with a few
    // levers to move in terms of improving performance. Specifically, we could
    // find a more performant algorithm, or find a way to reduce the number of
    // times it has to be called, or use threading to do a scatter and gather
    // approach.
    let longest_match = find_longest_common_substring(s1, s2);
    (longest_match.len() as f32/s2.len() as f32) * (longest_match.len() as f32/s1.len() as f32)
}

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

    let mut highest_score: f32 = 0.0;
    let mut best_match: String = "".to_string();

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

    //println!("debug: {}", options.debug);
    //println!("required path: {}", options.path);
    let cleansed_path = cleanse_path(&options.path);

    if let Some(unwrapped_file) = options.file {
        println!("file: {}", unwrapped_file);
        if unwrapped_file == "-" {
            let stdin = std::io::stdin();
            for line in stdin.lock().lines() {
              println!("{}", line.unwrap());
            }
        } else {
            // figure out how to open specified file and read in as content
        }
    } else {
        match get_possible_files_from_glob() {
            Ok(paths) => {
                // - get collection of possible alternate file paths
                // - cleanse possible paths (stripping prefixed ./ and postfixed \r,\n,sp)
                // - if path is test file
                //      - reduce set to paths that match filename stripped of test words and extensions
                //      - reduce set to non-test files
                //   else
                //      - reduce set to paths that match filename stripped of test words and extensions
                //      - reduce set to test files
                // - score the reduced set of possible paths, tracking the highest score
                // - return the path with the highest score

                let filename = get_filename_minus_extension(&options.path);
                if is_test_file(&cleansed_path) {
                    let filename = strip_test_words(&filename);
                    let reduced_paths = paths.iter()
                        .map(|path| cleanse_path(&path.to_str().unwrap().to_string()))
                        .filter(|path| path.contains(filename.as_str()))  // filter to paths that contain the filename
                        .filter(|path| !is_test_file(&path)); // filter to paths that aren't test files
                    for path in reduced_paths {
                        let s = score(&path, &cleansed_path);
                        if s > highest_score {
                            highest_score = s;
                            best_match = path;
                        }
                    }
                } else {
                    let reduced_paths = paths.iter()
                        .map(|path| cleanse_path(&path.to_str().unwrap().to_string()))
                        .filter(|path| path.contains(filename.as_str())) // filter to paths that contain the filename
                        .filter(|path| is_test_file(&path)); // filter to paths that ARE test files
                    for path in reduced_paths {
                        let s = score(&path, &cleansed_path);
                        if s > highest_score {
                            highest_score = s;
                            best_match = path;
                        }
                    }
                }
            },
            Err(e) => println!("{:?}", e)
        }
        println!("{}", best_match);
    }

}
<|endoftext|>


<commit_before>extern crate rand;
use std::net::{Ipv4Addr, SocketAddrV4, UdpSocket};
use std::io::{BufReader, Read, Error};
use std::fs::File;

#[ repr(u8) ]
enum PacketType{
    RRQ = 1,
    WRQ,
    DATA,
    ACK,
    ERROR
}

static NETASCII: &'static str = "netascii";
static OCTET: &'static str = "octet";

fn create_rrq_wrq_packet(p_type: PacketType, file_name: String, mode : &'static str)->Vec<u8>{
    let mut v = Vec::with_capacity(2+file_name.len()+1+mode.len()+1);
    v.push(0);
    v.push(p_type as u8);
    v.extend(file_name.as_bytes());
    v.push(0);//zero terminator
    v.extend(mode.as_bytes());
    v.push(0);//zero terminator
    v
}

struct FileStream<Read>{
    file_name : String,
    start : u64,
    end:u64,
    buf:[u8;512],
    reader : BufReader<Read>
}

impl FileStream<std::fs::File>{ //std::fs::File because we are talking concrete implementation
    fn new(file_name:String)->Option<Self>{
        let f = match std::fs::File::open(file_name.clone()){
            Ok(handle) => Some(handle),
            Err(msg) => None

        };
        if f.is_some(){
            let mut fs = FileStream{
                file_name:file_name,
                start: 0,
                end: 0,
                reader : BufReader::with_capacity(512, f.unwrap()),
                buf : [0;512]
            };
            Some(fs)
        }
        else{
            println!("cant open file");
            None
        }
    }
}

impl Iterator for FileStream<std::fs::File>{
    type Item = ([u8;512], usize);
    fn next(&mut self)->Option<Self::Item>{
        let num_bytes_read = self.reader.read(&mut self.buf);
        println!("{:?}", num_bytes_read);
        let mut arr = [0;512];
        let mut i = 0usize;
        for c in self.buf.iter(){
            arr[i] = *c;
            i += 1;
        }
        Some((arr, num_bytes_read.unwrap()))
    }
}

/*
fn create_data_packet()->Vec<u8>{

}
*/

fn recv() -> Result<(), Error> {
    // Define the local connection information
    let ip = Ipv4Addr::new(127, 0, 0, 1);
    let connection = SocketAddrV4::new(ip, 6900);

    println!("rcvr waiting for incoming data");
    // Bind the socket
    let socket = try!(UdpSocket::bind(connection));
    println!("rcvr waiting for incoming data");

    // Read from the socket
    let mut buf = [0; 512];
    let (amt, src) = try!(socket.recv_from(&mut buf));
    match buf[1]{
        3 =>{
            let block_num = buf[3];
            let block_size = amt - 4;
            if block_size < 512{
                println!("recvr recvd: {:?}", &buf[0 .. amt]);
                println!("Last block of the file received");
            }

        },
        _ => {}
    }

    // Print only the valid data (slice)
    println!("recv sending...");
    socket.send_to(&[5,4,3], src);

    Ok(())
}

fn send() -> Result<(), Error> {
    // Define the local connection (to send the data from)
    let ip = Ipv4Addr::new(127, 0, 0, 1);
    //TODO generate port # using rand
    let connection = SocketAddrV4::new(ip, 9992);

    // Bind the socket
    let socket = try!(UdpSocket::bind(connection));

    // Define the remote connection (to send the data to)
    let connection2 = SocketAddrV4::new(ip, 6900);

    // Send data via the socket
    let mut fs = FileStream::new("/home/abhi/code/rust/fei/target/debug/foo.txt".to_string()).unwrap();
    let (buf, num_bytes_read) = fs.next().unwrap();
    let mut v = Vec::with_capacity(num_bytes_read + 4);
    v.push(0);
    v.push(3);
    v.push(0);
    let mut cnt = 0;
    v.push(cnt);
    v.extend_from_slice(&buf[0..num_bytes_read]);
    try!(socket.send_to(v.as_slice(), connection2));

    let mut buf  = [0; 10];
    socket.recv_from(&mut buf);

    println!("sender recvd {:?}", buf);
    Ok(())
}

fn main() {

    let args : Vec<_> = std::env::args().collect();
    println!("{}", args[1]);
    if args[1] == "0"{
        println!("passed 0");
        match recv(){
            Ok(_) => {},
            Err(msg) => println!("{}", msg)

        }
    }
    else{
        println!("passed 1");
        send();
    }
}
<commit_msg>Use bit shifting to compose block number in the ACK<commit_after>extern crate rand;
use std::net::{Ipv4Addr, SocketAddrV4, UdpSocket};
use std::io::{BufReader, Read, Error};
use std::fs::File;

#[ repr(u8) ]
enum PacketType{
    RRQ = 1,
    WRQ,
    DATA,
    ACK,
    ERROR
}

static NETASCII: &'static str = "netascii";
static OCTET: &'static str = "octet";

fn create_rrq_wrq_packet(p_type: PacketType, file_name: String, mode : &'static str)->Vec<u8>{
    let mut v = Vec::with_capacity(2+file_name.len()+1+mode.len()+1);
    v.push(0);
    v.push(p_type as u8);
    v.extend(file_name.as_bytes());
    v.push(0);//zero terminator
    v.extend(mode.as_bytes());
    v.push(0);//zero terminator
    v
}

struct FileStream<Read>{
    file_name : String,
    start : u64,
    end:u64,
    buf:[u8;512],
    reader : BufReader<Read>
}

impl FileStream<std::fs::File>{ //std::fs::File because we are talking concrete implementation
    fn new(file_name:String)->Option<Self>{
        let f = match std::fs::File::open(file_name.clone()){
            Ok(handle) => Some(handle),
            Err(msg) => None

        };
        if f.is_some(){
            let mut fs = FileStream{
                file_name:file_name,
                start: 0,
                end: 0,
                reader : BufReader::with_capacity(512, f.unwrap()),
                buf : [0;512]
            };
            Some(fs)
        }
        else{
            println!("cant open file");
            None
        }
    }
}

impl Iterator for FileStream<std::fs::File>{
    type Item = ([u8;512], usize);
    fn next(&mut self)->Option<Self::Item>{
        let num_bytes_read = self.reader.read(&mut self.buf);
        println!("{:?}", num_bytes_read);
        let mut arr = [0;512];
        let mut i = 0usize;
        for c in self.buf.iter(){
            arr[i] = *c;
            i += 1;
        }
        Some((arr, num_bytes_read.unwrap()))
    }
}

/*
fn create_data_packet()->Vec<u8>{

}
*/

fn recv() -> Result<(), Error> {
    // Define the local connection information
    let ip = Ipv4Addr::new(127, 0, 0, 1);
    let connection = SocketAddrV4::new(ip, 6900);

    println!("rcvr waiting for incoming data");
    // Bind the socket
    let socket = try!(UdpSocket::bind(connection));
    println!("rcvr waiting for incoming data");

    // Read from the socket
    let mut buf = [0u8; 516]; //UDP packet is 516 bytes
    let (amt, src) = try!(socket.recv_from(&mut buf));
    match buf[1]{
        3 =>{
            let block_num = buf[3];
            let block_size = amt - 4;
            if block_size < 512{
                println!("recvr recvd: {:?}", &buf[0 .. amt]);
                println!("Last block of the file received");
            }
            //send ACK

            let mut high = 0u8;
            let mut low = 0u8;
            if block_num <= 0xFF{
                low = block_size as u8;
            }
            else{
                low = block_num & 0xFF;
                high = block_num & 0xFF00;
            }

            socket.send_to(&[0,PacketType::ACK as u8, high, low], src);
        },
        _ => {}
    }

    // Print only the valid data (slice)
    println!("recv sending...");

    Ok(())
}

fn send() -> Result<(), Error> {
    // Define the local connection (to send the data from)
    let ip = Ipv4Addr::new(127, 0, 0, 1);
    //TODO generate port # using rand
    let connection = SocketAddrV4::new(ip, 9992);

    // Bind the socket
    let socket = try!(UdpSocket::bind(connection));

    // Define the remote connection (to send the data to)
    let connection2 = SocketAddrV4::new(ip, 6900);

    // Send data via the socket
    let mut fs = FileStream::new("/home/abhi/code/rust/fei/target/debug/foo.txt".to_string()).unwrap();
    let (buf, num_bytes_read) = fs.next().unwrap();
    let mut v = Vec::with_capacity(num_bytes_read + 4);
    v.push(0);
    v.push(3);
    v.push(0);
    let mut cnt = 0;
    v.push(cnt);
    v.extend_from_slice(&buf[0..num_bytes_read]);
    try!(socket.send_to(v.as_slice(), connection2));

    let mut buf  = [0; 10];
    socket.recv_from(&mut buf);

    println!("sender recvd {:?}", buf);
    Ok(())
}

fn main() {

    let args : Vec<_> = std::env::args().collect();
    println!("{}", args[1]);
    if args[1] == "0"{
        println!("passed 0");
        match recv(){
            Ok(_) => {},
            Err(msg) => println!("{}", msg)

        }
    }
    else{
        println!("passed 1");
        send();
    }
}
<|endoftext|>


<commit_before>extern crate clap;
extern crate notify;
extern crate term;

use clap::App;
use notify::{RecommendedWatcher, Error, Watcher};
use std::io::Write;
use std::thread;
use std::string::String;
use std::path::Path;
use std::process::Command;
use std::convert::Into;
use std::sync::mpsc::channel;
use term::color;

fn out<S:Into<String>>(label: &str, msg: S, color: color::Color) -> std::io::Result<()> {
  let mut out = term::stdout().unwrap();
  try!(out.reset());
  try!(out.fg(color));
  try!(write!(&mut std::io::stdout(), "{:>12}", format!("Capgun {}", label)));
  try!(out.reset());
  try!(write!(&mut std::io::stdout(), " {}\n", msg.into()));
  try!(out.flush());
  Ok(())
}

fn err<S:Into<String>>(label: &str, msg: S) -> std::io::Result<()> {
  let mut out = term::stderr().unwrap();
  try!(out.reset());
  try!(out.fg(color::RED));
  try!(write!(&mut std::io::stderr(), "{:>12}", format!("Capgun {}", label)));
  try!(out.reset());
  try!(write!(&mut std::io::stderr(), " {}\n", msg.into()));
  try!(out.flush());
  Ok(())
}

fn main() {
  let matches = App::new("capgun")
    .about("fires off commands when files change")
    .args_from_usage(
      "-c, --command=<CMD> 'cmd to run when files under <INPUT> change'
       <INPUT> 'Sets the directory to watch'"
    )
    .get_matches();

  let cmd = matches.value_of("CMD").unwrap();
  let input = matches.value_of("INPUT").unwrap();

  let _ = out("Watching", input, color::BRIGHT_CYAN);

  let (tx, rx) = channel();
  let watch: Result<RecommendedWatcher, Error> = Watcher::new(tx);

  match watch {
    Ok(mut watcher) =>  {
      match watcher.watch(&Path::new(input)) {
        Ok(_) => {},
        Err(e) => {
          let _ = err("Error", format!("Failed to load gun {:?}", e));
          return
        },
      }

      loop {
        thread::sleep_ms(5000);
        match rx.recv() {
          Ok(e) => fire(e, cmd),
          Err(e) => {
            let _ = err("Missfire", &(format!("{:?}", e)[..]));
            return
          }
        }
      }
    },
    Err(_) => println!("Couldn't generate directory watcher")
  }
}

fn fire(e: notify::Event, cmd:  &str) {
  match e.op {
    Ok(_) => {
      let mut split = cmd.split(" ");
      let mut task = Command::new(split.next().unwrap());
      for s in split {
        task.arg(s);
      }
      let output = task.output()
        .unwrap_or_else(|e| panic!("Failed to fire: {} {}", cmd, e));

      println!("{}", String::from_utf8_lossy(&output.stdout));
      match writeln!(&mut std::io::stderr(), "{}", String::from_utf8_lossy(&output.stderr)) {
        Err(x) => panic!("Unable to write to stderr: {}", x),
        Ok(_) => {}
      }
      if output.status.success() {
        let _ = out("Hit", cmd, color::BRIGHT_GREEN);
      } else {
        let _ = err("Miss", cmd);
      }
    },
    Err(e) => println!("{:?}", e),
  }
}
<commit_msg>inherit parent process io to retain cargo's color profile<commit_after>extern crate clap;
extern crate notify;
extern crate term;

use clap::App;
use notify::{RecommendedWatcher, Error, Watcher};
use std::io::Write;
use std::thread;
use std::string::String;
use std::path::Path;
use std::process::{Command, Stdio};
use std::convert::Into;
use std::sync::mpsc::channel;
use term::color;

fn out<S:Into<String>>(label: &str, msg: S, color: color::Color) -> std::io::Result<()> {
  let mut out = term::stdout().unwrap();
  try!(out.reset());
  try!(out.fg(color));
  try!(write!(&mut std::io::stdout(), "{:>12}", format!("Capgun {}", label)));
  try!(out.reset());
  try!(write!(&mut std::io::stdout(), " {}\n", msg.into()));
  try!(out.flush());
  Ok(())
}

fn err<S:Into<String>>(label: &str, msg: S) -> std::io::Result<()> {
  let mut out = term::stderr().unwrap();
  try!(out.reset());
  try!(out.fg(color::RED));
  try!(write!(&mut std::io::stderr(), "{:>12}", format!("Capgun {}", label)));
  try!(out.reset());
  try!(write!(&mut std::io::stderr(), " {}\n", msg.into()));
  try!(out.flush());
  Ok(())
}

fn main() {
  let matches = App::new("capgun")
    .about("fires off commands when files change")
    .args_from_usage(
      "-c, --command=<CMD> 'cmd to run when files under <INPUT> change'
       <INPUT> 'Sets the directory to watch'"
    )
    .get_matches();

  let cmd = matches.value_of("CMD").unwrap();
  let input = matches.value_of("INPUT").unwrap();

  let _ = out("Watching", input, color::BRIGHT_CYAN);

  let (tx, rx) = channel();
  let watch: Result<RecommendedWatcher, Error> = Watcher::new(tx);

  match watch {
    Ok(mut watcher) =>  {
      match watcher.watch(&Path::new(input)) {
        Ok(_) => {},
        Err(e) => {
          let _ = err("Error", format!("Failed to load gun {:?}", e));
          return
        },
      }

      loop {
        thread::sleep_ms(5000);
        match rx.recv() {
          Ok(e) => fire(e, cmd),
          Err(e) => {
            let _ = err("Missfire", &(format!("{:?}", e)[..]));
            return
          }
        }
      }
    },
    Err(_) => println!("Couldn't generate directory watcher")
  }
}

fn fire(e: notify::Event, cmd:  &str) {
  match e.op {
    Ok(_) => {
      let mut split = cmd.split(" ");
      let mut task = Command::new(split.next().unwrap());
      for s in split {
        task.arg(s);
      }
      let output = task
        .stdin(Stdio::inherit())
        .stdout(Stdio::inherit())
        .stderr(Stdio::inherit())
        .output()
        .unwrap_or_else(|e| panic!("Failed to fire: {} {}", cmd, e));

      println!("{}", String::from_utf8_lossy(&output.stdout));
      match writeln!(&mut std::io::stderr(), "{}", String::from_utf8_lossy(&output.stderr)) {
        Err(x) => panic!("Unable to write to stderr: {}", x),
        Ok(_) => {}
      }
      if output.status.success() {
        let _ = out("Hit", cmd, color::BRIGHT_GREEN);
      } else {
        let _ = err("Miss", cmd);
      }
    },
    Err(e) => println!("{:?}", e),
  }
}
<|endoftext|>


<commit_before>/*
 * A simple program that aims to extract various string constants from a JAR file (Java)
 */

extern crate classreader;
extern crate zip;
extern crate docopt;
extern crate rustc_serialize;
extern crate java_properties;

use docopt::Docopt;
use classreader::*;
use std::fs::File;
use java_properties::PropertiesIter;
use std::io::BufReader;

const USAGE: &'static str = "
Java Strings extractor.

Usage:
  jstrings <source>...
  javaminer (-h | --help)

Options:
  -h --help     Show this screen.

Source can be one or more class or jar files.
";

#[derive(Debug, RustcDecodable)]
struct Args {
	arg_source: Vec<String>
}

fn main() {
    let args: Args = Docopt::new(USAGE)
                            .and_then(|d| d.decode())
                            .unwrap_or_else(|e| e.exit());
    for f in args.arg_source {
        if f.ends_with(".class") {
            process_class_file(&f);
        } else if f.ends_with(".jar") {
            process_jar_file(&f);
        } else if f.ends_with(".properties") {
            process_properties_file(&f);
		}
    }
}

fn process_jar_file(file_name: &String) {
    let file = File::open(file_name).expect("couldn't find a file!");
    let mut zip = zip::ZipArchive::new(file).expect("could not read JAR");
    for i in 0..zip.len() {
        let mut class_file = zip.by_index(i).unwrap();
        if class_file.name().ends_with(".class") {
            let class = ClassReader::new_from_reader(&mut class_file).unwrap();
            process_class(&class);
        } else if class_file.name().ends_with(".properties") {
			process_properties(class_file);
		}
    }
}

fn process_class_file(file_name: &String) {
    let class = ClassReader::new_from_path(&file_name).unwrap();
    process_class(&class);
}

fn process_class(class: &Class) {
    assert_eq!(0xCAFEBABE, class.magic);
    for jstr in &class.constant_pool {
		match jstr {
			&ConstantPoolInfo::String(index) => {
				println!("{}", get_string(&class, index as usize));
			},
			_ => {}
		}
	}
}

/// Get constant from a pool, correcting for java's 1-based indexes.
fn get_const(class: &Class, i: usize) -> &ConstantPoolInfo {
    &class.constant_pool[i - 1]
}

/// Get string from constant pool
fn get_string(class: &Class, index: usize) -> String {
    match get_const(class, index) {
        &ConstantPoolInfo::Utf8(ref s) => s.clone(),
        _ => "?".to_string()
    }
}

fn process_properties_file(file_name: &String) {
	let f = File::open(file_name).expect("couldn't find a file!");
	process_properties(BufReader::new(f));
}

fn process_properties<R: std::io::Read>(f: R) {
    PropertiesIter::new(f).read_into(|_, v| {
      println!("{}", v);
    }).expect("failed to read a properties file");
}
<commit_msg>Fix indentation<commit_after>/*
 * A simple program that aims to extract various string constants from a JAR file (Java)
 */

extern crate classreader;
extern crate zip;
extern crate docopt;
extern crate rustc_serialize;
extern crate java_properties;

use docopt::Docopt;
use classreader::*;
use std::fs::File;
use java_properties::PropertiesIter;
use std::io::BufReader;

const USAGE: &'static str = "
Java Strings extractor.

Usage:
  jstrings <source>...
  javaminer (-h | --help)

Options:
  -h --help     Show this screen.

Source can be one or more class or jar files.
";

#[derive(Debug, RustcDecodable)]
struct Args {
    arg_source: Vec<String>
}

fn main() {
    let args: Args = Docopt::new(USAGE)
                            .and_then(|d| d.decode())
                            .unwrap_or_else(|e| e.exit());
    for f in args.arg_source {
        if f.ends_with(".class") {
            process_class_file(&f);
        } else if f.ends_with(".jar") {
            process_jar_file(&f);
        } else if f.ends_with(".properties") {
            process_properties_file(&f);
        }
    }
}

fn process_jar_file(file_name: &String) {
    let file = File::open(file_name).expect("couldn't find a file!");
    let mut zip = zip::ZipArchive::new(file).expect("could not read JAR");
    for i in 0..zip.len() {
        let mut class_file = zip.by_index(i).unwrap();
        if class_file.name().ends_with(".class") {
            let class = ClassReader::new_from_reader(&mut class_file).unwrap();
            process_class(&class);
        } else if class_file.name().ends_with(".properties") {
            process_properties(class_file);
        }
    }
}

fn process_class_file(file_name: &String) {
    let class = ClassReader::new_from_path(&file_name).unwrap();
    process_class(&class);
}

fn process_class(class: &Class) {
    assert_eq!(0xCAFEBABE, class.magic);
    for jstr in &class.constant_pool {
        match jstr {
            &ConstantPoolInfo::String(index) => {
                println!("{}", get_string(&class, index as usize));
            },
            _ => {}
        }
    }
}

/// Get constant from a pool, correcting for java's 1-based indexes.
fn get_const(class: &Class, i: usize) -> &ConstantPoolInfo {
    &class.constant_pool[i - 1]
}

/// Get string from constant pool
fn get_string(class: &Class, index: usize) -> String {
    match get_const(class, index) {
        &ConstantPoolInfo::Utf8(ref s) => s.clone(),
        _ => "?".to_string()
    }
}

fn process_properties_file(file_name: &String) {
    let f = File::open(file_name).expect("couldn't find a file!");
    process_properties(BufReader::new(f));
}

fn process_properties<R: std::io::Read>(f: R) {
    PropertiesIter::new(f).read_into(|_, v| {
      println!("{}", v);
    }).expect("failed to read a properties file");
}
<|endoftext|>


<commit_before>/*
* rust-clean - Copyright (c) 2014 Gomez Guillaume.
*
* This software is provided 'as-is', without any express or implied warranty.
* In no event will the authors be held liable for any damages arising from
* the use of this software.
*
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
*
* 1. The origin of this software must not be misrepresented; you must not claim
*    that you wrote the original software. If you use this software in a product,
*    an acknowledgment in the product documentation would be appreciated but is
*    not required.
*
* 2. Altered source versions must be plainly marked as such, and must not be
*    misrepresented as being the original software.
*
* 3. This notice may not be removed or altered from any source distribution.
*/

#![feature(core, collections, old_io, path_ext)]

use std::fs::{self, PathExt};
use std::path::Path;

struct CleanOptions {
    recursive: bool,
    verbose: bool,
    confirmation: bool
}

fn ask_confirmation(file: &Path) -> bool {
    loop {
        print!("clean: remove \x1b[37;1m'{}'\x1b[0m (y/n) ? ", file.to_str().unwrap());
        match std::old_io::stdio::stdin().read_line() {
            Ok(s) => {
                let tmp_s = s.replace("\r\n", "").replace("\n", "");

                if tmp_s == "y" || tmp_s == "yes" {
                    return true;
                } else if tmp_s == "n" || tmp_s == "no" {
                    return false;
                }
            }
            Err(_) => {}
        }
    }
}

fn start_clean(options: &CleanOptions, entry: &Path) {
    if entry.exists() {
        if entry.is_dir() {
            if options.recursive || entry.to_str().unwrap() == "." {
                match fs::read_dir(entry) {
                    Ok(res) => {
                        if options.verbose {
                            println!("\x1b[36;1m-> Entering {}\x1b[0m", entry.to_str().unwrap());
                        }
                        for tmp in res {
                            match tmp {
                                Ok(current) => start_clean(options, &current.path()),
                                Err(e) => println!("Error: {:?}", e)
                            };
                        }
                        if options.verbose {
                            println!("\x1b[34;1m<- Leaving {}\x1b[0m", entry.to_str().unwrap());
                        }
                    }
                    Err(e) => {
                        println!("\x1b[31;1mProblem with this directory: {} -> {}\x1b[0m", entry.to_str().unwrap(), e);
                    }
                }
            }
        } else {
            match entry.file_name() {
                Some(s) => {
                    match s.to_str() {
                        Some(ss) => if ss.ends_with("~") {
                            if !options.confirmation || ask_confirmation(&Path::new(s)) {
                                match fs::remove_file(entry) {
                                    Ok(_) => {
                                        if options.verbose {
                                            println!("\x1b[32;1m{} deleted\x1b[0m", entry.to_str().unwrap());
                                        }
                                    }
                                    Err(e) => {
                                        println!("\x1b[31;1mProblem with this file: {} -> {}\x1b[0m", entry.to_str().unwrap(), e);
                                    }
                                }
                            }
                        },
                        _ => {}
                    }
                }
                None => {
                    println!("\x1b[31;1mProblem with this file: {}\x1b[0m", entry.to_str().unwrap());
                }
            }
        }
    } else {
        println!("\x1b[31;1mProblem with this entry: {}\x1b[0m", entry.to_str().unwrap());
    }
}

fn print_help() {
    println!("./clean [options] [files | dirs]");
    println!("    -r : recursive mode");
    println!("    -v : verbose mode");
    println!("    -i : prompt before every removal");
    println!("--help : print this help");
}

fn main() {
    let mut args = Vec::new();

    for argument in std::env::args() {
        args.push(argument);
    }
    let mut options = CleanOptions{recursive: false, verbose: false, confirmation: false};
    let mut files = Vec::new();

    args.remove(0);
    for tmp in args.iter() {
        if tmp.clone().into_bytes()[0] == '-' as u8 {
            let mut tmp_arg = String::from_str(tmp);

            tmp_arg.remove(0);
            if tmp_arg.len() > 0 {
                for character in tmp_arg.into_bytes().iter() {
                    match *character as char {
                        '-' => {
                            if tmp.as_slice() == "--help" {
                                print_help();
                                return;
                            }
                        }
                        'r' => {
                            options.recursive = true;
                        }
                        'v' => {
                            options.verbose = true;
                        }
                        'i' => {
                            options.confirmation = true;
                        }
                        _ => {
                            panic!("Unknown option: '{}', to have the options list, please launch with '-h' option\n", character);
                        }
                    }
                }
            } else {
                files.push(Path::new(tmp));
            }
        }
    }
    if files.len() == 0 {
        files.push(Path::new("."));
    }
    if options.verbose {
        println!("\x1b[33;1m=== VERBOSE MODE ===\x1b[0m");
    }
    for tmp in files.iter() {
        start_clean(&options, tmp);
    }
    if options.verbose {
        println!("\x1b[33;1mEnd of execution\x1b[0m");
    }
}<commit_msg>Update to last rustc and add -l option<commit_after>/*
* rust-clean - Copyright (c) 2014 Gomez Guillaume.
*
* This software is provided 'as-is', without any express or implied warranty.
* In no event will the authors be held liable for any damages arising from
* the use of this software.
*
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
*
* 1. The origin of this software must not be misrepresented; you must not claim
*    that you wrote the original software. If you use this software in a product,
*    an acknowledgment in the product documentation would be appreciated but is
*    not required.
*
* 2. Altered source versions must be plainly marked as such, and must not be
*    misrepresented as being the original software.
*
* 3. This notice may not be removed or altered from any source distribution.
*/

use std::fs::{self, PathExt};
use std::path::Path;
use std::str::FromStr;

struct CleanOptions {
    recursive: bool,
    verbose: bool,
    confirmation: bool,
    level: u32
}

fn ask_confirmation(file: &Path) -> bool {
    loop {
        print!("clean: remove \x1b[37;1m'{}'\x1b[0m (y/n) ? ", file.to_str().unwrap());
        let mut s = String::new();

        match std::io::stdin().read_line(&mut s) {
            Ok(_) => {
                let tmp_s = s.replace("\r\n", "").replace("\n", "");

                if tmp_s == "y" || tmp_s == "yes" {
                    return true;
                } else if tmp_s == "n" || tmp_s == "no" {
                    return false;
                }
            }
            Err(_) => {}
        }
    }
}

fn start_clean(options: &CleanOptions, entry: &Path, level: u32) {
    let m = ::std::fs::metadata(&entry).unwrap();

    if m.is_file() || m.is_dir() {
        if m.is_dir() {
            if (options.recursive || entry.to_str().unwrap() == ".") &&
                (options.level == 0 || level <= options.level) {
                match fs::read_dir(entry) {
                    Ok(res) => {
                        if options.verbose {
                            println!("\x1b[36;1m-> Entering {}\x1b[0m", entry.to_str().unwrap());
                        }
                        for tmp in res {
                            match tmp {
                                Ok(current) => {
                                    start_clean(options, &current.path(), level + 1);
                                },
                                Err(e) => println!("Error: {:?}", e)
                            };
                        }
                        if options.verbose {
                            println!("\x1b[34;1m<- Leaving {}\x1b[0m", entry.to_str().unwrap());
                        }
                    }
                    Err(e) => {
                        println!("\x1b[31;1mProblem with this directory: {} -> {}\x1b[0m", entry.to_str().unwrap(), e);
                    }
                }
            }
        } else {
            match entry.file_name() {
                Some(s) => {
                    match s.to_str() {
                        Some(ss) => if ss.ends_with("~") {
                            if !options.confirmation || ask_confirmation(&Path::new(s)) {
                                match fs::remove_file(entry) {
                                    Ok(_) => {
                                        if options.verbose {
                                            println!("\x1b[32;1m{} deleted\x1b[0m", entry.to_str().unwrap());
                                        }
                                    }
                                    Err(e) => {
                                        println!("\x1b[31;1mProblem with this file: {} -> {}\x1b[0m", entry.to_str().unwrap(), e);
                                    }
                                }
                            }
                        },
                        _ => {}
                    }
                }
                None => {
                    println!("\x1b[31;1mProblem with this file: {}\x1b[0m", entry.to_str().unwrap());
                }
            }
        }
    } else {
        println!("\x1b[31;1mProblem with this entry: {}\x1b[0m", entry.to_str().unwrap());
    }
}

fn print_help() {
    println!("./clean [options] [files | dirs]");
    println!("    -r          : recursive mode");
    println!("    -v          : verbose mode");
    println!("    -i          : prompt before every removal");
    println!("    -l=[number] : Add a level for recursive mode");
    println!("--help : print this help");
}

fn main() {
    let mut args = Vec::new();

    for argument in std::env::args() {
        args.push(argument);
    }
    let mut options = CleanOptions{recursive: false, verbose: false, confirmation: false, level: 0};
    let mut files = Vec::new();

    args.remove(0);
    for tmp in args.iter() {
        if tmp.clone().into_bytes()[0] == '-' as u8 {
            let mut tmp_arg = tmp.to_owned();

            tmp_arg.remove(0);
            if tmp_arg.len() > 0 {
                for character in tmp_arg.into_bytes().iter() {
                    match *character as char {
                        '-' => {
                            if &*tmp == "--help" {
                                print_help();
                                return;
                            }
                        }
                        'r' => {
                            options.recursive = true;
                        }
                        'v' => {
                            options.verbose = true;
                        }
                        'i' => {
                            options.confirmation = true;
                        }
                        'l' => {
                            if tmp.len() < 4 || &tmp[0..3] != "-l=" {
                                println!("The \"-l\" option has to be used like this:");
                                println!("clean -r -l=2");
                                return;
                            }
                            options.level = match u32::from_str(&tmp[3..]) {
                                Ok(u) => u,
                                Err(_) => {
                                    println!("Please enter a valid number!");
                                    return;
                                }
                            };
                            println!("Level is set to {}", options.level);
                            break;
                        }
                        _ => {
                            println!("Unknown option: '{}', to have the options list, please launch with '-h' option", *character as char);
                            return;
                        }
                    }
                }
            }/* else {
                files.push(Path::new(tmp));
            }*/
        } else {
            files.push(Path::new(tmp));
        }
    }
    if files.len() == 0 {
        files.push(Path::new("."));
    }
    if options.verbose {
        println!("\x1b[33;1m=== VERBOSE MODE ===\x1b[0m");
    }
    for tmp in files.iter() {
        println!("reading : {:?}", tmp);
        start_clean(&options, tmp, 0);
    }
    if options.verbose {
        println!("\x1b[33;1mEnd of execution\x1b[0m");
    }
}<|endoftext|>


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

//! # SymbolAPI
//!
//! SymbolAPI is a microservice which accepts lists of debug symbol names + memory addresses, and
//! returns a list of symbolicated function names.
//!

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

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

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

use breakpad_symbols::{Symbolizer, SimpleSymbolSupplier};
use flate2::read::GzDecoder;
use hyper::Client;
use hyper::header::{ContentEncoding, Encoding};
use hyper::server::{Server, Request, Response};
use hyper::status::StatusCode;
use rustc_serialize::json;

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

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

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

    let default_port = 5000;
    let port;
    match env::var("PORT") {
        Ok(val) => port = val,
        Err(_) => {
            println!("$PORT unset, using default {}", default_port);
            port = format!("{}", default_port);
        }
    }

    let address = &*format!("0.0.0.0:{}", port);

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

/// Stacks come in as a JSON array, but really is a hash map of `<index, address>`
/// where `index` is the position of the `memoryMap` JSON result.
pub fn stacks_to_stack_map(decoded_stacks: Vec<Vec<(i8,u64)>>) -> HashMap<i8, Vec<u64>> {
    debug!("decoded_stacks: {:?}", decoded_stacks);

    let mut stack_map: HashMap<i8, Vec<u64>> = HashMap::new();
    for stack in &decoded_stacks[0] {
        let (index, offset) = *stack;

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

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

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

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

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

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

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

            let symbol_url = get_config("symbol_urls.public");
            debug!("symbol url: {:?}", symbol_url);
            let stack_map = stacks_to_stack_map(decoded.stacks);

            // FIXME limit the number of possible threads spawned by client()
            // TODO maybe push these into a queue and have a thread pool service the queue?
            let symbol_response: SymbolResponse = client(symbol_url, decoded.memoryMap, stack_map);
            let json_response = match json::encode(&symbol_response) {
                Ok(x) => x,
                Err(x) => panic!("cannot JSON encode {:?}, {:?}", symbol_response, x)
            };
            res.write_all(json_response.as_bytes()).unwrap();

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

    debug!("finished serving request");
}

/// Creates multiple client connections to fetch debug symbols from S3 bucket and symbolicate using
/// memory and stack maps, aggregates results and returns SymbolResult.
pub fn client(url: String, memory_map: Vec<(String,String)>, stack_map: HashMap<i8, Vec<u64>>) -> SymbolResponse {
    let mut handles = vec![];
    let mut counter: i8 = 0;
    for (debug_file, debug_id) in memory_map {
        let debug_file_name = debug_file.clone();
        let pdb = debug_file.find(".pdb").unwrap();
        let (symbol_name, _) = debug_file.split_at(pdb);
        let symbol_file = format!("{}.sym", symbol_name);
        let this_url = format!("{}/{}/{}/{}", url, debug_file, debug_id, symbol_file);

        let mut symbol_path = PathBuf::new();
        symbol_path.push(get_config("symbols.path"));

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

        let stack_map_copy = stack_map.clone();

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

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

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

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

                let c = Client::new();
                let mut res = c.get(&this_url).send().unwrap();
                let is_gzipped = match res.headers.get::<ContentEncoding>() {
                    Some(x) => x.contains(&Encoding::Gzip),
                    None => false,
                };

                let mut body = String::new();
                if is_gzipped {
                    let mut raw_body = vec!();
                    res.read_to_end(&mut raw_body).unwrap();
                    let mut d = match GzDecoder::new(&raw_body[..]) {
                        Ok(x) => x,
                        Err(x) => panic!("cannot gunzip {:?}, {:?}", raw_body, x)
                    };
                    d.read_to_string(&mut body).unwrap();
                } else {
                    res.read_to_string(&mut body).unwrap();
                }

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

            debug!("symbol_path: {:?}", &symbol_path);

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

            (debug_file_name, symbols, known_module)
        }));

        counter += 1;
    }

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

    let mut symbolicated_stacks = vec!();

    // pass anything with index -1 through
    for stacks in stack_map.get(&-1) {
        for address in stacks {
            symbolicated_stacks.push(
                format!("0x{:x}", address)
            );
        }
    }

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

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

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

    result
}

/// Returns individual values from the configuration file.
fn get_config(value_name: &str) -> String {
    let mut f = match File::open("config/symbolapi.toml") {
        Ok(x) => x,
        Err(x) => panic!("cannot open config file config/symbolapi.toml: {}", x)
    };
    let mut s = String::new();
    f.read_to_string(&mut s).unwrap();
    let value: toml::Value = match s.parse() {
        Ok(x) => x,
        Err(x) => panic!("cannot parse config file: {:?}", x)
    };

    let result = match value.lookup(value_name) {
        Some(x) => x,
        None => panic!("config value not found for {}", value_name)
    };

    result.as_str().unwrap().to_string()
}
<commit_msg>mention parsing<commit_after>// Copyright 2015 Robert Helmer <rhelmer@rhelmer.org>. See the LICENSE
// file at the top-level directory of this distribution.

//! # SymbolAPI
//!
//! SymbolAPI is a microservice which accepts lists of debug symbol names + memory addresses, and
//! returns a list of symbolicated function names.
//!

/// The goal is to take an HTTP JSON request such as:
/// ```
/// {"stacks":[
///   [
///     [0,11723767],
///     [1, 65802]
///    ]
///  ],
///  "memoryMap":[
///    ["xul.pdb","44E4EC8C2F41492B9369D6B9A059577C2"],
///    ["wntdll.pdb","D74F79EB1F8D4A45ABCD2F476CCABACC2"]
///  ],
///  "version":4
/// }
/// ```
/// The symbolapi service then downloads the corresponding symbol files (e.g. from S3), parses them,
/// and returns the function names for the corresponding addresses (in the "stacks" array)
/// and returns JSON such as:
/// ```
/// {"symbolicatedStacks": [
///   [
///     "XREMain::XRE_mainRun() (in xul.pdb)",
///     "KiUserCallbackDispatcher (in wntdll.pdb)"]
///   ],
///   "knownModules": [true, true]
/// }
/// ```

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

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

use breakpad_symbols::{Symbolizer, SimpleSymbolSupplier};
use flate2::read::GzDecoder;
use hyper::Client;
use hyper::header::{ContentEncoding, Encoding};
use hyper::server::{Server, Request, Response};
use hyper::status::StatusCode;
use rustc_serialize::json;

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

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

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

    let default_port = 5000;
    let port;
    match env::var("PORT") {
        Ok(val) => port = val,
        Err(_) => {
            println!("$PORT unset, using default {}", default_port);
            port = format!("{}", default_port);
        }
    }

    let address = &*format!("0.0.0.0:{}", port);

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

/// Stacks come in as a JSON array, but really is a hash map of `<index, address>`
/// where `index` is the position of the `memoryMap` JSON result.
pub fn stacks_to_stack_map(decoded_stacks: Vec<Vec<(i8,u64)>>) -> HashMap<i8, Vec<u64>> {
    debug!("decoded_stacks: {:?}", decoded_stacks);

    let mut stack_map: HashMap<i8, Vec<u64>> = HashMap::new();
    for stack in &decoded_stacks[0] {
        let (index, offset) = *stack;

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

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

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

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

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

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

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

            let symbol_url = get_config("symbol_urls.public");
            debug!("symbol url: {:?}", symbol_url);
            let stack_map = stacks_to_stack_map(decoded.stacks);

            // FIXME limit the number of possible threads spawned by client()
            // TODO maybe push these into a queue and have a thread pool service the queue?
            let symbol_response: SymbolResponse = client(symbol_url, decoded.memoryMap, stack_map);
            let json_response = match json::encode(&symbol_response) {
                Ok(x) => x,
                Err(x) => panic!("cannot JSON encode {:?}, {:?}", symbol_response, x)
            };
            res.write_all(json_response.as_bytes()).unwrap();

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

    debug!("finished serving request");
}

/// Creates multiple client connections to fetch debug symbols from S3 bucket and symbolicate using
/// memory and stack maps, aggregates results and returns SymbolResult.
pub fn client(url: String, memory_map: Vec<(String,String)>, stack_map: HashMap<i8, Vec<u64>>) -> SymbolResponse {
    let mut handles = vec![];
    let mut counter: i8 = 0;
    for (debug_file, debug_id) in memory_map {
        let debug_file_name = debug_file.clone();
        let pdb = debug_file.find(".pdb").unwrap();
        let (symbol_name, _) = debug_file.split_at(pdb);
        let symbol_file = format!("{}.sym", symbol_name);
        let this_url = format!("{}/{}/{}/{}", url, debug_file, debug_id, symbol_file);

        let mut symbol_path = PathBuf::new();
        symbol_path.push(get_config("symbols.path"));

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

        let stack_map_copy = stack_map.clone();

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

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

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

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

                let c = Client::new();
                let mut res = c.get(&this_url).send().unwrap();
                let is_gzipped = match res.headers.get::<ContentEncoding>() {
                    Some(x) => x.contains(&Encoding::Gzip),
                    None => false,
                };

                let mut body = String::new();
                if is_gzipped {
                    let mut raw_body = vec!();
                    res.read_to_end(&mut raw_body).unwrap();
                    let mut d = match GzDecoder::new(&raw_body[..]) {
                        Ok(x) => x,
                        Err(x) => panic!("cannot gunzip {:?}, {:?}", raw_body, x)
                    };
                    d.read_to_string(&mut body).unwrap();
                } else {
                    res.read_to_string(&mut body).unwrap();
                }

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

            debug!("symbol_path: {:?}", &symbol_path);

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

            (debug_file_name, symbols, known_module)
        }));

        counter += 1;
    }

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

    let mut symbolicated_stacks = vec!();

    // pass anything with index -1 through
    for stacks in stack_map.get(&-1) {
        for address in stacks {
            symbolicated_stacks.push(
                format!("0x{:x}", address)
            );
        }
    }

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

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

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

    result
}

/// Returns individual values from the configuration file.
fn get_config(value_name: &str) -> String {
    let mut f = match File::open("config/symbolapi.toml") {
        Ok(x) => x,
        Err(x) => panic!("cannot open config file config/symbolapi.toml: {}", x)
    };
    let mut s = String::new();
    f.read_to_string(&mut s).unwrap();
    let value: toml::Value = match s.parse() {
        Ok(x) => x,
        Err(x) => panic!("cannot parse config file: {:?}", x)
    };

    let result = match value.lookup(value_name) {
        Some(x) => x,
        None => panic!("config value not found for {}", value_name)
    };

    result.as_str().unwrap().to_string()
}
<|endoftext|>


<commit_before>//! Doc placeholder

extern crate opencl;
extern crate sdl2;

use sdl2::keyboard::Keycode;
use sdl2::pixels::{self, Color};
use sdl2::rect::Rect;

const KERNEL_SOURCE: &'static str = r"
__kernel void multiply_by_scalar(__global float const* const src_buf,
                                 __private float const coeff,
                                 __global float* dst_buf) {
    uint i = get_global_id(0);
    dst_buf[i] = src_buf[i] * coeff;
}
";

fn init_kernel() {
    let (device, ctx, queue) = opencl::util::create_compute_context()
                                   .expect("Could not initialise OpenCL");
    const COEFF: f32 = 5.4321;

    let vec_src = vec![1.0f32, 2.0, 3.0, 4.0, 5.0];

    let cl_src_buf = ctx.create_buffer::<f32>(vec_src.len(), opencl::cl::CL_MEM_READ_ONLY);
    let cl_dst_buf = ctx.create_buffer::<f32>(vec_src.len(), opencl::cl::CL_MEM_WRITE_ONLY);

    queue.write(&cl_src_buf, &&vec_src[..], ());

    let program = {
        let p = ctx.create_program_from_source(KERNEL_SOURCE);
        p.build(&device).expect("Could not build program");
        p
    };

    let kernel = program.create_kernel("multiply_by_scalar");
    kernel.set_arg(0, &cl_src_buf);
    kernel.set_arg(1, &COEFF);
    kernel.set_arg(2, &cl_dst_buf);

    let event = queue.enqueue_async_kernel(&kernel, vec_src.len(), None, ());

    let vec_dst: Vec<f32> = queue.get(&cl_dst_buf, &event);

    println!("  {:?}", &vec_src[..]);
    println!("* {:?}", COEFF);
    println!("= {:?}", &vec_dst[..]);
}

fn main() {
    init_kernel();

    let sdl = sdl2::init().expect("Could not intialise SDL library");
    let mut renderer = sdl.video()
                          .expect("Could not initialise video")
                          .window("mandlebrot", 800, 600)
                          .position_centered()
                          .build()
                          .expect("Could not create a window from the video subsystem")
                          .renderer()
                          .accelerated()
                          .present_vsync()
                          .target_texture()
                          .build()
                          .expect("Could not get renderer from window");

    renderer.set_draw_color(Color::RGB(255, 0, 0));

    let sz = renderer.window().map(|w| w.size()).unwrap_or((0, 0));
    let mut tex = renderer.create_texture_streaming(pixels::PixelFormatEnum::ARGB8888, sz).unwrap();

    let mut events = sdl.event_pump().expect("Could not initialise events");

    'mainloop: loop {
        for e in events.poll_iter() {
            use sdl2::event::Event;
            match e {
                Event::Quit {..} |
                Event::KeyDown {keycode: Some(Keycode::Escape), ..} => break 'mainloop,
                _ => {}
            }
        }
        renderer.clear();

        tex.with_lock(None, |pixels, pitch| {
               let (mut row, mut col) = (1, 1);
               for pixel in pixels {
                   if col >= pitch {
                       row += 1;
                       col = 1;
                   } else {
                       col += 1;
                   }
                   *pixel = 0x00 + col as u8;
               }
           })
           .expect("Could not write pixels to screen texture");

        renderer.copy(&tex, None, Some(Rect::new_unwrap(0, 0, 800, 600)));

        renderer.present();
    }
}
<commit_msg>Multiply row by col to get a more interesting image<commit_after>//! Doc placeholder

extern crate opencl;
extern crate sdl2;

use sdl2::keyboard::Keycode;
use sdl2::pixels::{self, Color};
use sdl2::rect::Rect;

const KERNEL_SOURCE: &'static str = r"
__kernel void multiply_by_scalar(__global float const* const src_buf,
                                 __private float const coeff,
                                 __global float* dst_buf) {
    uint i = get_global_id(0);
    dst_buf[i] = src_buf[i] * coeff;
}
";

fn init_kernel() {
    let (device, ctx, queue) = opencl::util::create_compute_context()
                                   .expect("Could not initialise OpenCL");
    const COEFF: f32 = 5.4321;

    let vec_src = vec![1.0f32, 2.0, 3.0, 4.0, 5.0];

    let cl_src_buf = ctx.create_buffer::<f32>(vec_src.len(), opencl::cl::CL_MEM_READ_ONLY);
    let cl_dst_buf = ctx.create_buffer::<f32>(vec_src.len(), opencl::cl::CL_MEM_WRITE_ONLY);

    queue.write(&cl_src_buf, &&vec_src[..], ());

    let program = {
        let p = ctx.create_program_from_source(KERNEL_SOURCE);
        p.build(&device).expect("Could not build program");
        p
    };

    let kernel = program.create_kernel("multiply_by_scalar");
    kernel.set_arg(0, &cl_src_buf);
    kernel.set_arg(1, &COEFF);
    kernel.set_arg(2, &cl_dst_buf);

    let event = queue.enqueue_async_kernel(&kernel, vec_src.len(), None, ());

    let vec_dst: Vec<f32> = queue.get(&cl_dst_buf, &event);

    println!("  {:?}", &vec_src[..]);
    println!("* {:?}", COEFF);
    println!("= {:?}", &vec_dst[..]);
}

fn main() {
    init_kernel();

    let sdl = sdl2::init().expect("Could not intialise SDL library");
    let mut renderer = sdl.video()
                          .expect("Could not initialise video")
                          .window("mandlebrot", 800, 600)
                          .position_centered()
                          .build()
                          .expect("Could not create a window from the video subsystem")
                          .renderer()
                          .accelerated()
                          .present_vsync()
                          .target_texture()
                          .build()
                          .expect("Could not get renderer from window");

    renderer.set_draw_color(Color::RGB(255, 0, 0));

    let sz = renderer.window().map(|w| w.size()).unwrap_or((0, 0));
    let mut tex = renderer.create_texture_streaming(pixels::PixelFormatEnum::ARGB8888, sz).unwrap();

    let mut events = sdl.event_pump().expect("Could not initialise events");

    'mainloop: loop {
        for e in events.poll_iter() {
            use sdl2::event::Event;
            match e {
                Event::Quit {..} |
                Event::KeyDown {keycode: Some(Keycode::Escape), ..} => break 'mainloop,
                _ => {}
            }
        }
        renderer.clear();

        tex.with_lock(None, |pixels, pitch| {
               let (mut row, mut col) = (1, 1);
               for pixel in pixels {
                   if col >= pitch {
                       row += 1;
                       col = 1;
                   } else {
                       col += 1;
                   }
                   *pixel = (row * col) as u8;
               }
           })
           .expect("Could not write pixels to screen texture");

        renderer.copy(&tex, None, Some(Rect::new_unwrap(0, 0, 800, 600)));

        renderer.present();
    }
}
<|endoftext|>


<commit_before>extern crate websocket;

use std::thread;
use websocket::{Server, Message, Sender, Receiver};
use websocket::header::WebSocketProtocol;

extern crate iron;

use iron::prelude::*;
use iron::status;
use iron::mime::Mime;
use std::fs;
use std::fs::File;
use std::path::Path;
use std::os;
use std::env;
use std::io::Read;
use std::string::*;

fn main() {

    let args = env::args();
    let mut iter = args.skip(1); // skip the program name

    let mut s = String::new();

    match iter.next() {
      Some(file_name) => {
        println!("{}", file_name);
        let path = &Path::new(&file_name);
        let f = File::open(path);
        match f {
          Ok(mut of) => {
            match of.read_to_string(&mut s) {
              Err(e) => {
                println!("err: {:?}", e);
                return ();
                },
              Ok(len) => {
                println!("read {} bytes", len)
                },
            }
            },
          Err(e) => {
            println!("err: {:?}", e);
            return ();
            },
          }
        println!("serving file: {}", file_name);
        println!("from localhost:3000");
        }
      None => {
        println!("no args!");
        }
    }

    thread::spawn(move || {
      winsockets_main();
      });

    Iron::new(move |req: &mut Request| {
        let content_type = "text/html".parse::<Mime>().unwrap();
        Ok(Response::with((content_type, status::Ok, &*s)))
    }).http("localhost:3000").unwrap();
}

fn winsockets_main() {
	let server = Server::bind("127.0.0.1:1234").unwrap();

	for connection in server {
		// Spawn a new thread for each connection.
		thread::spawn(move || {
			let request = connection.unwrap().read_request().unwrap(); // Get the request
			let headers = request.headers.clone(); // Keep the headers so we can check them

			request.validate().unwrap(); // Validate the request

			let mut response = request.accept(); // Form a response

			if let Some(&WebSocketProtocol(ref protocols)) = headers.get() {
				if protocols.contains(&("rust-websocket".to_string())) {
					// We have a protocol we want to use
					response.headers.set(WebSocketProtocol(vec!["rust-websocket".to_string()]));
				}
			}

			let mut client = response.send().unwrap(); // Send the response

			let ip = client.get_mut_sender()
				.get_mut()
				.peer_addr()
				.unwrap();

			println!("Connection from {}", ip);

			let message = Message::Text("Hello".to_string());
			client.send_message(message).unwrap();

			let (mut sender, mut receiver) = client.split();

			for message in receiver.incoming_messages() {
				let message = message.unwrap();
        println!("message: {:?}", message);

        let replyy = Message::Text("replyyyblah".to_string());

				match message {
					Message::Close(_) => {
						let message = Message::Close(None);
						sender.send_message(message).unwrap();
						println!("Client {} disconnected", ip);
						return;
					}
					Message::Ping(data) => {
            println!("Message::Ping(data)");
						let message = Message::Pong(data);
						sender.send_message(message).unwrap();
					}
					// _ => sender.send_message(message).unwrap(),
					_ => {
            println!("sending replyy");
            sender.send_message(replyy).unwrap()
            }
				}
			}
		});
	}
}

<commit_msg>json parse in rust.<commit_after>extern crate websocket;

use std::thread;
use websocket::{Server, Message, Sender, Receiver};
use websocket::header::WebSocketProtocol;

extern crate iron;

use iron::prelude::*;
use iron::status;
use iron::mime::Mime;
use std::fs;
use std::fs::File;
use std::path::Path;
use std::os;
use std::env;
use std::io::Read;
use std::string::*;

extern crate serde_json;
use serde_json::Value;

fn main() {

    let args = env::args();
    let mut iter = args.skip(1); // skip the program name

    let mut s = String::new();

    match iter.next() {
      Some(file_name) => {
        println!("{}", file_name);
        let path = &Path::new(&file_name);
        let f = File::open(path);
        match f {
          Ok(mut of) => {
            match of.read_to_string(&mut s) {
              Err(e) => {
                println!("err: {:?}", e);
                return ();
                },
              Ok(len) => {
                println!("read {} bytes", len)
                },
            }
            },
          Err(e) => {
            println!("err: {:?}", e);
            return ();
            },
          }
        println!("serving file: {}", file_name);
        println!("from localhost:3000");

        let data: Value = serde_json::from_str(&s[..]).unwrap();

        println!("serdeval: {:?}", data);

        }
      None => {
        println!("no args!");
        }
    }

    thread::spawn(move || {
      winsockets_main();
      });

    Iron::new(move |req: &mut Request| {
        let content_type = "text/html".parse::<Mime>().unwrap();
        Ok(Response::with((content_type, status::Ok, &*s)))
    }).http("localhost:3000").unwrap();
}

fn winsockets_main() {
	let server = Server::bind("127.0.0.1:1234").unwrap();

	for connection in server {
		// Spawn a new thread for each connection.
		thread::spawn(move || {
			let request = connection.unwrap().read_request().unwrap(); // Get the request
			let headers = request.headers.clone(); // Keep the headers so we can check them

			request.validate().unwrap(); // Validate the request

			let mut response = request.accept(); // Form a response

			if let Some(&WebSocketProtocol(ref protocols)) = headers.get() {
				if protocols.contains(&("rust-websocket".to_string())) {
					// We have a protocol we want to use
					response.headers.set(WebSocketProtocol(vec!["rust-websocket".to_string()]));
				}
			}

			let mut client = response.send().unwrap(); // Send the response

			let ip = client.get_mut_sender()
				.get_mut()
				.peer_addr()
				.unwrap();

			println!("Connection from {}", ip);

			let message = Message::Text("Hello".to_string());
			client.send_message(message).unwrap();

			let (mut sender, mut receiver) = client.split();

			for message in receiver.incoming_messages() {
				let message = message.unwrap();
        println!("message: {:?}", message);

        let replyy = Message::Text("replyyyblah".to_string());

				match message {
					Message::Close(_) => {
						let message = Message::Close(None);
						sender.send_message(message).unwrap();
						println!("Client {} disconnected", ip);
						return;
					}
					Message::Ping(data) => {
            println!("Message::Ping(data)");
						let message = Message::Pong(data);
						sender.send_message(message).unwrap();
					}
					// _ => sender.send_message(message).unwrap(),
					_ => {
            println!("sending replyy");
            sender.send_message(replyy).unwrap()
            }
				}
			}
		});
	}
}

<|endoftext|>