<commit_before>use failure::bail;
use reqwest;
use serde::de::DeserializeOwned;
use serde::ser::Serialize;
use prometheus::{HistogramVec, IntCounterVec, HistogramTimer};
use maplit::hashmap;

use crate::errors::*;
use crate::metrics;

pub use reqwest::header::HeaderMap;
pub use reqwest::Response;

pub struct HTTPClient {
    pub api_base: String,
    pub client: reqwest::Client,

    metric_api_responses: Option<IntCounterVec>,
    metric_api_duration: Option<HistogramVec>,
    secret_path: Option<String>,
}

impl HTTPClient {
    pub fn new(api_base: &str) -> Result<HTTPClient> {
        let client = reqwest::Client::builder()
            .redirect(reqwest::redirect::Policy::none())
            .build()?;

        Ok(HTTPClient {
            api_base: api_base.into(),
            client,
            metric_api_responses: None,
            metric_api_duration: None,
            secret_path: None,
        })
    }

    pub fn new_with_headers(api_base: &str, headers: HeaderMap) -> Result<HTTPClient> {
        let client = reqwest::Client::builder()
            .redirect(reqwest::redirect::Policy::none())
            .default_headers(headers)
            .build()?;

        Ok(HTTPClient {
            api_base: api_base.into(),
            client,
            metric_api_responses: None,
            metric_api_duration: None,
            secret_path: None,
        })
    }

    pub fn with_metrics(mut self, responses: IntCounterVec, request_duration: HistogramVec) -> Self {
        self.metric_api_responses = Some(responses);
        self.metric_api_duration = Some(request_duration);

        return self
    }

    pub fn with_secret_path(mut self, path: String) -> Self {
        self.secret_path = Some(path);
        self
    }

    fn make_url(&self, path: &str) -> String {
        if path.is_empty() {
            self.api_base.clone()
        } else if path.starts_with("http://") || path.starts_with("https://") {
            path.to_string()
        } else if path.starts_with("/") {
            self.api_base.clone() + path
        } else {
            self.api_base.clone() + "/" + path
        }
    }

    pub async fn get<T>(&self, path: &str) -> Result<T>
    where
        T: DeserializeOwned + Send + 'static,
    {
        let _timer = self.maybe_start_timer("get", path);
        let res = self.client.get(&self.make_url(path)).send().await;
        let res = self.process_resp(res)?;
        let res = self.parse_json(res).await?;

        self.maybe_record_ok();
        Ok(res)
    }

    pub async fn post<T, U: Serialize>(&self, path: &str, body: &U) -> Result<T>
    where
        T: DeserializeOwned + Send + 'static,
    {
        let _timer = self.maybe_start_timer("post", path);
        let res = self.client.post(&self.make_url(path)).json(body).send().await;
        let res = self.process_resp(res)?;
        let res = self.parse_json(res).await?;

        self.maybe_record_ok();
        Ok(res)
    }

    pub async fn post_void<U: Serialize>(&self, path: &str, body: &U) -> Result<()> {
        let _timer = self.maybe_start_timer("post", path);
        let res = self.client.post(&self.make_url(path)).json(body).send().await;
        self.process_resp(res)?;

        self.maybe_record_ok();
        Ok(())
    }

    pub async fn put<T, U: Serialize>(&self, path: &str, body: &U) -> Result<T>
    where
        T: DeserializeOwned + Send + 'static,
    {
        let _timer = self.maybe_start_timer("put", path);
        let res = self.client.put(&self.make_url(path)).json(body).send().await;
        let res = self.process_resp(res)?;
        let res = self.parse_json(res).await?;

        self.maybe_record_ok();
        Ok(res)
    }

    pub async fn put_void<U: Serialize>(&self, path: &str, body: &U) -> Result<()> {
        let _timer = self.maybe_start_timer("put", path);
        let res = self.client.put(&self.make_url(path)).json(body).send().await;
        self.process_resp(res)?;

        self.maybe_record_ok();
        Ok(())
    }

    pub async fn delete_void(&self, path: &str) -> Result<()> {
        let _timer = self.maybe_start_timer("delete", path);
        let res = self.client.delete(&self.make_url(path)).send().await;
        self.process_resp(res)?;

        self.maybe_record_ok();
        Ok(())
    }

    fn maybe_record_status(&self, status: &str) {
        if let Some(ref m) = self.metric_api_responses {
            m.with(&hashmap!{"status" => status}).inc();
        }
    }

    fn maybe_record_ok(&self) {
        self.maybe_record_status(reqwest::StatusCode::OK.as_str());
    }

    fn maybe_start_timer(&self, method: &str, path: &str) -> Option<HistogramTimer> {
        self.metric_api_duration.clone().map(|ref m| {
            let path = if self.secret_path.is_some() {
                String::new()
            } else {
                metrics::cleanup_path(path)
            };
            m.with(&hashmap!{
                "method" => method,
                "path" => &path,
            }).start_timer()
        })
    }

    fn make_clean_err<T, E: failure::Fail>(&self, e: E) -> Result<T> {
        if let Some(ref s) = self.secret_path {
            let msg = format!("{}", e);
            bail!("{}", msg.replace(s, "<redacted>"));
        } else {
            bail!(e);
        }
    }

    fn process_resp(&self, res: reqwest::Result<Response>) -> Result<Response> {
        let res = match res {
            Ok(r) => r,
            Err(e) => {
                self.maybe_record_status("<unknown>");
                return self.make_clean_err(e);
            }
        };

        match res.error_for_status_ref() {
            Ok(_) => Ok(res),
            Err(e) => {
                self.maybe_record_status(res.status().as_str());
                return self.make_clean_err(e);
            }
        }
    }

    async fn parse_json<T>(&self, res: Response) -> Result<T>
    where
        T: DeserializeOwned + Send + 'static,
    {
        match res.json::<T>().await {
            Ok(r) => Ok(r),
            Err(e) => {
                self.maybe_record_status("<invalid json>");
                return self.make_clean_err(e);
            }
        }
    }
}
<commit_msg>Log response body on error HTTP statuses (#299)<commit_after>use failure::bail;
use reqwest;
use serde::de::DeserializeOwned;
use serde::ser::Serialize;
use prometheus::{HistogramVec, IntCounterVec, HistogramTimer};
use maplit::hashmap;

use crate::errors::*;
use crate::metrics;

pub use reqwest::header::HeaderMap;
pub use reqwest::Response;

pub struct HTTPClient {
    pub api_base: String,
    pub client: reqwest::Client,

    metric_api_responses: Option<IntCounterVec>,
    metric_api_duration: Option<HistogramVec>,
    secret_path: Option<String>,
}

impl HTTPClient {
    pub fn new(api_base: &str) -> Result<HTTPClient> {
        let client = reqwest::Client::builder()
            .redirect(reqwest::redirect::Policy::none())
            .build()?;

        Ok(HTTPClient {
            api_base: api_base.into(),
            client,
            metric_api_responses: None,
            metric_api_duration: None,
            secret_path: None,
        })
    }

    pub fn new_with_headers(api_base: &str, headers: HeaderMap) -> Result<HTTPClient> {
        let client = reqwest::Client::builder()
            .redirect(reqwest::redirect::Policy::none())
            .default_headers(headers)
            .build()?;

        Ok(HTTPClient {
            api_base: api_base.into(),
            client,
            metric_api_responses: None,
            metric_api_duration: None,
            secret_path: None,
        })
    }

    pub fn with_metrics(mut self, responses: IntCounterVec, request_duration: HistogramVec) -> Self {
        self.metric_api_responses = Some(responses);
        self.metric_api_duration = Some(request_duration);

        return self
    }

    pub fn with_secret_path(mut self, path: String) -> Self {
        self.secret_path = Some(path);
        self
    }

    fn make_url(&self, path: &str) -> String {
        if path.is_empty() {
            self.api_base.clone()
        } else if path.starts_with("http://") || path.starts_with("https://") {
            path.to_string()
        } else if path.starts_with("/") {
            self.api_base.clone() + path
        } else {
            self.api_base.clone() + "/" + path
        }
    }

    pub async fn get<T>(&self, path: &str) -> Result<T>
    where
        T: DeserializeOwned + Send + 'static,
    {
        let _timer = self.maybe_start_timer("get", path);
        let res = self.client.get(&self.make_url(path)).send().await;
        let res = self.process_resp(res).await?;
        let res = self.parse_json(res).await?;

        self.maybe_record_ok();
        Ok(res)
    }

    pub async fn post<T, U: Serialize>(&self, path: &str, body: &U) -> Result<T>
    where
        T: DeserializeOwned + Send + 'static,
    {
        let _timer = self.maybe_start_timer("post", path);
        let res = self.client.post(&self.make_url(path)).json(body).send().await;
        let res = self.process_resp(res).await?;
        let res = self.parse_json(res).await?;

        self.maybe_record_ok();
        Ok(res)
    }

    pub async fn post_void<U: Serialize>(&self, path: &str, body: &U) -> Result<()> {
        let _timer = self.maybe_start_timer("post", path);
        let res = self.client.post(&self.make_url(path)).json(body).send().await;
        self.process_resp(res).await?;

        self.maybe_record_ok();
        Ok(())
    }

    pub async fn put<T, U: Serialize>(&self, path: &str, body: &U) -> Result<T>
    where
        T: DeserializeOwned + Send + 'static,
    {
        let _timer = self.maybe_start_timer("put", path);
        let res = self.client.put(&self.make_url(path)).json(body).send().await;
        let res = self.process_resp(res).await?;
        let res = self.parse_json(res).await?;

        self.maybe_record_ok();
        Ok(res)
    }

    pub async fn put_void<U: Serialize>(&self, path: &str, body: &U) -> Result<()> {
        let _timer = self.maybe_start_timer("put", path);
        let res = self.client.put(&self.make_url(path)).json(body).send().await;
        self.process_resp(res).await?;

        self.maybe_record_ok();
        Ok(())
    }

    pub async fn delete_void(&self, path: &str) -> Result<()> {
        let _timer = self.maybe_start_timer("delete", path);
        let res = self.client.delete(&self.make_url(path)).send().await;
        self.process_resp(res).await?;

        self.maybe_record_ok();
        Ok(())
    }

    fn maybe_record_status(&self, status: &str) {
        if let Some(ref m) = self.metric_api_responses {
            m.with(&hashmap!{"status" => status}).inc();
        }
    }

    fn maybe_record_ok(&self) {
        self.maybe_record_status(reqwest::StatusCode::OK.as_str());
    }

    fn maybe_start_timer(&self, method: &str, path: &str) -> Option<HistogramTimer> {
        self.metric_api_duration.clone().map(|ref m| {
            let path = if self.secret_path.is_some() {
                String::new()
            } else {
                metrics::cleanup_path(path)
            };
            m.with(&hashmap!{
                "method" => method,
                "path" => &path,
            }).start_timer()
        })
    }

    fn make_clean_err<T>(&self, e: impl failure::Fail) -> Result<T> {
        if let Some(ref s) = self.secret_path {
            let msg = format!("{}", e);
            bail!("{}", msg.replace(s, "<redacted>"));
        } else {
            bail!(e);
        }
    }

    async fn process_resp(&self, res: reqwest::Result<Response>) -> Result<Response> {
        let res = match res {
            Ok(r) => r,
            Err(e) => {
                self.maybe_record_status("<unknown>");
                return self.make_clean_err(e);
            }
        };

        match res.error_for_status_ref() {
            Ok(_) => Ok(res),
            Err(e) => {
                self.maybe_record_status(res.status().as_str());
                let err: Result<()> = self.make_clean_err(e);
                let text = res.text().await.unwrap_or(String::new());
                bail!("{}. Response body: {}", err.unwrap_err(), text);
            }
        }
    }

    async fn parse_json<T>(&self, res: Response) -> Result<T>
    where
        T: DeserializeOwned + Send + 'static,
    {
        match res.json::<T>().await {
            Ok(r) => Ok(r),
            Err(e) => {
                self.maybe_record_status("<invalid json>");
                return self.make_clean_err(e);
            }
        }
    }
}
<|endoftext|>


<commit_before>#[macro_use]
extern crate log;

extern crate abstract_ns;
extern crate futures;
extern crate getopts;
extern crate ns_dns_tokio;
extern crate rand;
extern crate tokio_core;
extern crate tokio_io;

// the device under test
extern crate net_interceptor;

use abstract_ns::Resolver;
use futures::{Future, Map, Stream, Async, Poll};
use futures::future;
use futures::sync::oneshot;
use futures::sync::oneshot::{Sender};
use ns_dns_tokio::DnsResolver;
use tokio_core::net::{TcpStream, TcpListener};
use tokio_core::reactor::{Core, Handle};
use tokio_io::{AsyncRead, io};

use std::net::{IpAddr, Ipv4Addr, SocketAddr};
use std::fmt::{Debug, Display};
use std::time::{Duration};
use std::sync::{Arc, Mutex};
use std::thread;

use std::io::Error;
use std::ops::Deref;
use std::ops::DerefMut;
use std::borrow::BorrowMut;

use net_interceptor::logging::unittestlogger;

fn add_ten<F>(future: F) -> Map<F, fn(i32) -> i32>
    where F: Future<Item=i32>,
{
    error!("shutdown");
    fn add(a: i32) -> i32 { a + 10 }
    future.map(add)
}

pub struct AbortCondition {
    condition: bool,
    reactor_handle: futures::task::Task,
}

#[derive(Copy, Clone)]
pub struct Releaser {
    block: *const AbortCondition
}

impl AbortCondition {

    fn set(&mut self) {
        debug!("abort condition met");
        self.condition = true;
        self.reactor_handle.unpark();
    }

}

impl Future for AbortCondition {

    type Item = ();
    type Error = Error;

    fn poll(&mut self) -> Poll<(), Error> {
        if  self.condition {
            Ok(Async::Ready(()))
        } else {
            self.reactor_handle = futures::task::park();
            Ok(Async::NotReady)
        }
    }

}

pub struct Stopper {
    sender: Sender<i64>,
}

impl Stopper {

    pub fn stop(&mut self) {
        //self.sender.send(1).unwrap();
    }

}

/*impl Copy for Abort {
    fn clone(&self) -> Abort {
        *self
    }
}
*/
// Here we'll express the handling of `client` and return it as a future
// to be spawned onto the event loop.
/*fn process(client: TcpStream) -> Box<Future<Item = (i64), Error = error>> {
    warn!("received");
    Box::new(futures::future::ok(0));
}
*/
fn blank() -> Result<(), std::io::Error> {
    warn!("blank");
    Ok(())
}

fn direct(stopper: & mut Option<Sender<i64>>) -> Result<(), std::io::Error> {
    warn!("connection received");
//    let mut s = Box::borrow_mut(stopper);
    let mut s : Sender<i64> = stopper.unwrap();
    s.send(1).unwrap();
    Ok(())
}

fn stopper(sender: Sender<i64>) -> Arc<Mutex> {
    let counting = Arc::new(Mutex::new(0));
    thread::spawn(move |sender| {
        debug!("waiting for end")
        let mut num = sender.lock().unwrap();
        debug!("signalling end");
        sender.send(1).unwrap();
    });
    counting
}

#[test]
fn test_infra_connect() {
    unittestlogger();

    // this is the main event loop, powered by tokio core
    let mut core = Core::new().unwrap();
    let handle = core.handle();

    let bind_socket_addr = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 12000);
    let listener = TcpListener::bind(&bind_socket_addr, &handle)
        .expect(&format!("Unable to bind to {}", &bind_socket_addr));
    warn!("Listening on {}", listener.local_addr().unwrap());

    let addr = listener.local_addr().unwrap();
    assert!(addr.port() == 12000, "should accept {}");

//    let mut abort = AbortCondition { condition: false, reactor_handle: futures::task::park() };

    let connections = listener.incoming();
    let (tx, signal) = oneshot::channel::<i64>();

//    let stopper = Arc::new(tx);
    let mut boxed = Some(tx);
    {

    //        let copy = Arc::clone(&stopper);
            //let server = connections.for_each(move |(socket, _peer_addr)| fx(&stopper));
        let server = connections.for_each(move |(socket, _peer_addr)| direct(& mut boxed));
        let wait = core.handle().spawn(server.map_err(|_|()));

    }

    fn abortCondition() -> futures::Poll<(), std::io::Error> {
        warn!("poll");
        if true {
            Ok(Async::Ready(()))
        }
        else {
            futures::task::park().unpark();
            Ok(Async::NotReady)
        }
    }

    //let abort = futures::future::poll_fn(abortCondition);

    //let timeout = tokio_core::reactor::Timeout::new_at(std::time::Duration::seconds(1));
    // run server, stop on panic
//    core.run(server.select2(timeout)).unwrap();
//    core.run(abort).unwrap();
    // core.spawn(server);
//    core.run(server.select(abort)).unwrap();
    core.run(signal).unwrap();
}
<commit_msg>compiles and works<commit_after>#[macro_use]
extern crate log;

extern crate abstract_ns;
extern crate futures;
extern crate getopts;
extern crate ns_dns_tokio;
extern crate rand;
extern crate tokio_core;
extern crate tokio_io;

// the device under test
extern crate net_interceptor;

use abstract_ns::Resolver;
use futures::{Future, Map, Stream, Async, Poll};
use futures::future;
use futures::sync::oneshot;
use futures::sync::oneshot::{Sender};
use ns_dns_tokio::DnsResolver;
use tokio_core::net::{TcpStream, TcpListener};
use tokio_core::reactor::{Core, Handle};
use tokio_io::{AsyncRead, io};

use std::net::{IpAddr, Ipv4Addr, SocketAddr};
use std::fmt::{Debug, Display};
use std::time::{Duration};
use std::sync::{Arc, Mutex, Barrier};
use std::thread;

use std::io::Error;
use std::ops::Deref;
use std::ops::DerefMut;
use std::borrow::BorrowMut;

use net_interceptor::logging::unittestlogger;

fn add_ten<F>(future: F) -> Map<F, fn(i32) -> i32>
    where F: Future<Item=i32>,
{
    error!("shutdown");
    fn add(a: i32) -> i32 { a + 10 }
    future.map(add)
}

pub struct AbortCondition {
    condition: bool,
    reactor_handle: futures::task::Task,
}

impl AbortCondition {

    fn set(&mut self) {
        debug!("abort condition met");
        self.condition = true;
        self.reactor_handle.unpark();
    }

}

impl Future for AbortCondition {

    type Item = ();
    type Error = Error;

    fn poll(&mut self) -> Poll<(), Error> {
        if  self.condition {
            Ok(Async::Ready(()))
        } else {
            self.reactor_handle = futures::task::park();
            Ok(Async::NotReady)
        }
    }

}

fn stopper(sender: Sender<i64>) -> Arc<Barrier> {
    let counting = Arc::new(Barrier::new(2));
    let val_for_thread = counting.clone();
    thread::spawn(move || {
        warn!("waiting for end");
        val_for_thread.wait();
        warn!("signalling end");
        sender.send(1).unwrap();
    });
    counting
}

#[test]
fn test_infra_connect() {
    unittestlogger();

    // this is the main event loop, powered by tokio core
    let mut core = Core::new().unwrap();
    let handle = core.handle();

    let bind_socket_addr = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 12000);
    let listener = TcpListener::bind(&bind_socket_addr, &handle)
        .expect(&format!("Unable to bind to {}", &bind_socket_addr));
    warn!("Listening on {}", listener.local_addr().unwrap());

    let addr = listener.local_addr().unwrap();
    assert!(addr.port() == 12000, "should accept {}");

//    let mut abort = AbortCondition { condition: false, reactor_handle: futures::task::park() };

    let connections = listener.incoming();
    let (tx, signal) = oneshot::channel::<i64>();

    let mut barrier = stopper(tx);
    warn!("stopper activated");

    let server = connections.for_each(move |(socket, _peer_addr)| {
        warn!("println connection from {}", _peer_addr);
        warn!("connection received");
        barrier.wait();
        Ok(())
    });

    let wait = core.handle().spawn(server.map_err(|_|()));

    fn abortCondition() -> futures::Poll<(), std::io::Error> {
        warn!("poll");
        if true {
            Ok(Async::Ready(()))
        }
        else {
            futures::task::park().unpark();
            Ok(Async::NotReady)
        }
    }

    //let abort = futures::future::poll_fn(abortCondition);

    //let timeout = tokio_core::reactor::Timeout::new_at(std::time::Duration::seconds(1));
    // run server, stop on panic
//    core.run(server.select2(timeout)).unwrap();
//    core.run(abort).unwrap();
    // core.spawn(server);
//    core.run(server.select(abort)).unwrap();
    core.run(signal).unwrap();
}
<|endoftext|>


<commit_before>type Node<T> = Option<Box<Link<T>>>;

struct Link<T> {
    value: T,
    next: Node<T>,
}

struct LinkedList<T> {
    head: Link<T>,
}

impl<T> LinkedList<T> {
    pub fn new(value: T) -> LinkedList<T> {
        LinkedList{head: Link{value: value, next: None}}
    }
}

#[test]
fn it_works() {
    let ll = LinkedList::new();
}
<commit_msg>Fucked it<commit_after>type Node<T> = Option<Box<Link<T>>>;

struct Link<T> {
    value: T,
    next: Node<T>,
}

struct LinkedList<T> {
    head: Link<T>,
}

impl<T> LinkedList<T> {
    pub fn new(value: T) -> LinkedList<T> {
        LinkedList{head: Link{value: value, next: None}}
    }

    pub fn insert(&self, value: T) -> LinkedList<T> {
        let h = self.head;
        LinkedList{head: Link{value: value, next: Some(Box::new(h))}}
    }
}

#[test]
fn it_works() {
    let ll = LinkedList::new(1);
}
<|endoftext|>


<commit_before>extern crate toml;

use config::Config;
use search_command::SearchCommand;
use std::env;
use std::fs::File;
use std::io::Read;
use std::process;

pub struct Workflow {
    search: SearchCommand,
}

impl Workflow {
    pub fn search(&self) -> &SearchCommand {
        &self.search
    }
}

pub fn new() -> Workflow {
    let config = match load_config() {
        Ok(c) => c,
        Err(e) => {
            println!("{}", e);
            process::exit(1);
        }
    };
    Workflow {
        search: SearchCommand { config: config.clone() }
    }
}

fn load_config() -> Result<Config, String> {
    let mut config_file = env::home_dir().unwrap();
    config_file.push(".jiraconfig");
    let mut file = File::open(&config_file)
        .map_err(|_| "Missing .jiraconfig".to_string())?;

    let mut toml_string = String::new();
    file.read_to_string(&mut toml_string).unwrap();

    toml::from_str::<Config>(&toml_string)
        .map_err(|e| format!("Invalid format {}", e))
}<commit_msg>:art: Refactor workflow.rs<commit_after>extern crate toml;

use config::Config;
use search_command::SearchCommand;
use std::env;
use std::fs::File;
use std::io::Read;
use std::process;

pub struct Workflow {
    search: SearchCommand,
}

impl Workflow {
    pub fn search(&self) -> &SearchCommand {
        &self.search
    }
}

pub fn new() -> Workflow {
    let config = match load_config() {
        Ok(c) => c,
        Err(e) => {
            println!("{}", e);
            process::exit(1);
        }
    };
    Workflow { search: SearchCommand { config: config } }
}

fn load_config() -> Result<Config, String> {
    let mut config_file = env::home_dir().unwrap();
    config_file.push(".jiraconfig");
    let mut file = File::open(&config_file).map_err(|_| "Missing .jiraconfig".to_string())?;

    let mut toml_string = String::new();
    file.read_to_string(&mut toml_string).unwrap();

    toml::from_str::<Config>(&toml_string).map_err(|e| format!("Invalid format {}", e))
}<|endoftext|>


<commit_before>extern crate thinlinelib;
extern crate yaml_rust;
#[cfg(test)]
mod value_parser {

    static CLASS_STUB: &str = "class //#TEST_CLASS#/Test : public ::testing::Test {

    public:
        //#TEST_CLASS#/Test() {//#CONSTRUCTOR_CONTEXT#/
        }

        virtual ~//#TEST_CLASS#/Test() {//#DESTRUCTOR_CONTEXT#/
        }

    protected:
        virtual void SetUp() {//#SET_UP_CONTEXT#/
        }

        virtual void TearDown() {//#TEAR_DOWN_CONTEXT#/
        }

//#CLASS_CONTEXT#/
};
";

    static FUNCTION_STUB: &str = "TEST_F(//#TEST_CLASS#/Test, //#TEST_NAME#/) {
    //#TEST_CONTEXT#/
}
";

    use std::fs::read_to_string;
    use std::path::Path;
    use thinlinelib::value_parser::ValueParser;
    use yaml_rust::YamlLoader;

    #[test]
    fn get_bool() {
        let yml_path = Path::new("tests")
            .join("testdata")
            .join("config")
            .join("config1.yml");
        let yml_params =
            YamlLoader::load_from_str(read_to_string(yml_path).unwrap().as_str()).unwrap();
        let yml_param = yml_params.get(0);

        // Should succeed
        {
            let build_log = yml_param.unwrap().get_bool(&["build_script", "log"], false);
            assert_eq!(build_log, true);
        }

        // Should fail
        {
            let build_log = yml_param
                .unwrap()
                .get_bool(&["build_script", "none_existing"], true);
            assert_eq!(build_log, true);
        }
    }

    #[test]
    fn get_str() {
        let yml_path = Path::new("tests")
            .join("testdata")
            .join("config")
            .join("config1.yml");
        let yml_params =
            YamlLoader::load_from_str(read_to_string(yml_path).unwrap().as_str()).unwrap();
        let yml_param = yml_params.get(0);

        // Should succeed
        {
            let test_env = yml_param.unwrap().get_str(&["test_env"]);
            assert_eq!(test_env, Some("ctest"));

            let language = yml_param.unwrap().get_str(&["language"]);
            assert_eq!(language, Some("c"));
        }

        // Should fail
        {
            {
                let test_env = yml_param.unwrap().get_str(&["none_existing"]);
                assert!(test_env.is_none());
            }

            {
                let test_env = yml_param.unwrap().get_str(&[]);
                assert!(test_env.is_none());
            }

            let yml_path = Path::new("tests")
                .join("testdata")
                .join("config")
                .join("config4.yml");
            let yml_params =
                YamlLoader::load_from_str(read_to_string(yml_path).unwrap().as_str()).unwrap();
            let yml_param = yml_params.get(0);

            {
                let test_env = yml_param.unwrap().get_str(&["test_env"]);
                assert!(test_env.is_none());
            }
        }
    }

    #[test]
    fn get_str_or_file_content() {
        let yml_path = Path::new("stubs").join("environment").join("env_stubs.yml");
        let yml_params =
            YamlLoader::load_from_str(read_to_string(yml_path).unwrap().as_str()).unwrap();
        let yml_param = yml_params.get(0);

        // Should succeed reading raw
        {
            {
                let function = yml_param.unwrap().get_str_or_file_content(
                    &["google_test", "function"],
                    &Path::new("stubs").join("environment"),
                    "stub",
                );
                assert_eq!(function, Some(FUNCTION_STUB));
            }
        }

        // Should succeed reading file with valid extension
        {
            {
                let class = yml_param.unwrap().get_str_or_file_content(
                    &["google_test", "class"],
                    &Path::new("stubs").join("environment"),
                    "stub",
                );
                assert_eq!(class, Some(CLASS_STUB));
            }
        }

        // Should fail reading file with invalid extension
        {
            {
                let class = yml_param.unwrap().get_str_or_file_content(
                    &["google_test", "class"],
                    &Path::new("stubs").join("environment"),
                    "xyz",
                );
                assert_eq!(class, Some("google_test/class.stub"));
            }
        }

        // Should fail for non existing key path
        {
            {
                let class = yml_param.unwrap().get_str_or_file_content(
                    &["google_test", "non_existing"],
                    &Path::new("stubs").join("environment"),
                    "xyz",
                );
                assert_eq!(class, None);
            }
        }
    }

    #[test]
    fn get_str_vec() {
        let yml_path = Path::new("tests")
            .join("testdata")
            .join("config")
            .join("config1.yml");
        let yml_params =
            YamlLoader::load_from_str(read_to_string(yml_path).unwrap().as_str()).unwrap();
        let yml_param = yml_params.get(0);

        {
            let test_env = yml_param.unwrap().get_str_vec(&["include_dirs"]);
            assert_eq!(test_env, Some(vec!["include", "src"]));
        }

        {
            let test_env = yml_param.unwrap().get_str_vec(&["none_existing"]);
            assert!(test_env.is_none());
        }

        {
            let test_env = yml_param.unwrap().get_str_vec(&[]);
            assert!(test_env.is_none());
        }
    }
}
<commit_msg>Fix value_parser test<commit_after>extern crate thinlinelib;
extern crate yaml_rust;
#[cfg(test)]
mod value_parser {

    static CLASS_STUB: &str = "class #TEST_CLASSTest : public ::testing::Test {

    public:
        #TEST_CLASSTest() {#CONSTRUCTOR_CONTEXT
        }

        virtual ~#TEST_CLASSTest() {#DESTRUCTOR_CONTEXT
        }

    protected:
        virtual void SetUp() {#SET_UP_CONTEXT
        }

        virtual void TearDown() {#TEAR_DOWN_CONTEXT
        }

#CLASS_CONTEXT
};
";

    static FUNCTION_STUB: &str = "TEST_F(#TEST_CLASSTest, #TEST_NAME) {
    #TEST_CONTEXT
}
";

    use std::fs::read_to_string;
    use std::path::Path;
    use thinlinelib::value_parser::ValueParser;
    use yaml_rust::YamlLoader;

    #[test]
    fn get_bool() {
        let yml_path = Path::new("tests")
            .join("testdata")
            .join("config")
            .join("config1.yml");
        let yml_params =
            YamlLoader::load_from_str(read_to_string(yml_path).unwrap().as_str()).unwrap();
        let yml_param = yml_params.get(0);

        // Should succeed
        {
            let build_log = yml_param.unwrap().get_bool(&["build_script", "log"], false);
            assert_eq!(build_log, true);
        }

        // Should fail
        {
            let build_log = yml_param
                .unwrap()
                .get_bool(&["build_script", "none_existing"], true);
            assert_eq!(build_log, true);
        }
    }

    #[test]
    fn get_str() {
        let yml_path = Path::new("tests")
            .join("testdata")
            .join("config")
            .join("config1.yml");
        let yml_params =
            YamlLoader::load_from_str(read_to_string(yml_path).unwrap().as_str()).unwrap();
        let yml_param = yml_params.get(0);

        // Should succeed
        {
            let test_env = yml_param.unwrap().get_str(&["test_env"]);
            assert_eq!(test_env, Some("ctest"));

            let language = yml_param.unwrap().get_str(&["language"]);
            assert_eq!(language, Some("c"));
        }

        // Should fail
        {
            {
                let test_env = yml_param.unwrap().get_str(&["none_existing"]);
                assert!(test_env.is_none());
            }

            {
                let test_env = yml_param.unwrap().get_str(&[]);
                assert!(test_env.is_none());
            }

            let yml_path = Path::new("tests")
                .join("testdata")
                .join("config")
                .join("config4.yml");
            let yml_params =
                YamlLoader::load_from_str(read_to_string(yml_path).unwrap().as_str()).unwrap();
            let yml_param = yml_params.get(0);

            {
                let test_env = yml_param.unwrap().get_str(&["test_env"]);
                assert!(test_env.is_none());
            }
        }
    }

    #[test]
    fn get_str_or_file_content() {
        let yml_path = Path::new("stubs").join("environment").join("env_stubs.yml");
        let yml_params =
            YamlLoader::load_from_str(read_to_string(yml_path).unwrap().as_str()).unwrap();
        let yml_param = yml_params.get(0);

        // Should succeed reading raw
        {
            {
                let function = yml_param.unwrap().get_str_or_file_content(
                    &["google_test", "function"],
                    &Path::new("stubs").join("environment"),
                    "stub",
                );
                assert_eq!(function, Some(FUNCTION_STUB));
            }
        }

        // Should succeed reading file with valid extension
        {
            {
                let class = yml_param.unwrap().get_str_or_file_content(
                    &["google_test", "class"],
                    &Path::new("stubs").join("environment"),
                    "stub",
                );
                assert_eq!(class, Some(CLASS_STUB));
            }
        }

        // Should fail reading file with invalid extension
        {
            {
                let class = yml_param.unwrap().get_str_or_file_content(
                    &["google_test", "class"],
                    &Path::new("stubs").join("environment"),
                    "xyz",
                );
                assert_eq!(class, Some("google_test/class.stub"));
            }
        }

        // Should fail for non existing key path
        {
            {
                let class = yml_param.unwrap().get_str_or_file_content(
                    &["google_test", "non_existing"],
                    &Path::new("stubs").join("environment"),
                    "xyz",
                );
                assert_eq!(class, None);
            }
        }
    }

    #[test]
    fn get_str_vec() {
        let yml_path = Path::new("tests")
            .join("testdata")
            .join("config")
            .join("config1.yml");
        let yml_params =
            YamlLoader::load_from_str(read_to_string(yml_path).unwrap().as_str()).unwrap();
        let yml_param = yml_params.get(0);

        {
            let test_env = yml_param.unwrap().get_str_vec(&["include_dirs"]);
            assert_eq!(test_env, Some(vec!["include", "src"]));
        }

        {
            let test_env = yml_param.unwrap().get_str_vec(&["none_existing"]);
            assert!(test_env.is_none());
        }

        {
            let test_env = yml_param.unwrap().get_str_vec(&[]);
            assert!(test_env.is_none());
        }
    }
}
<|endoftext|>


<commit_before>extern crate clap;
extern crate vcpkg;

use clap::{App, AppSettings, Arg, SubCommand};
use std::env;

fn main() {
    let app = App::new("vcpkg library finder")
        .about("Allows examining what vcpkg will find in a build script")
        .setting(AppSettings::SubcommandRequired)
        .arg(
            Arg::with_name("target")
                .short("t")
                .long("target")
                .value_name("TARGET TRIPLE")
                .help("the rust toolchain triple to find libraries for")
                .takes_value(true)
                .default_value("x86_64-pc-windows-msvc"),
        )
        .subcommand(
            SubCommand::with_name("probe")
                .about("try to find a package")
                .arg(
                    Arg::with_name("package")
                        .index(1)
                        .required(true)
                        .help("probe for a library and display paths and cargo metadata"),
                )
                .arg(
                    Arg::with_name("linkage")
                        .short("l")
                        .long("linkage")
                        .takes_value(true)
                        .possible_values(&["dll", "static"]),
                ),
        );

    let matches = app.get_matches();

    // set TARGET as if we are running under cargo
    env::set_var("TARGET", matches.value_of("target").unwrap());

    if let Some(matches) = matches.subcommand_matches("probe") {
        let lib_name = matches.value_of("package").unwrap();

        let mut cfg = vcpkg::Config::new();
        cfg.cargo_metadata(false);
        cfg.copy_dlls(false);
        if let Some(linkage) = matches.value_of("linkage") {
            match &linkage {
                &"dll" => {
                    // do nothing
                }
                &"static" => {
                    env::set_var("CARGO_CFG_TARGET_FEATURE", "crt-static");
                }
                _ => unreachable!(),
            }
        }

        match cfg.find_package(lib_name) {
            Ok(lib) => {
                println!("Found library {}", lib_name);

                if !lib.include_paths.is_empty() {
                    println!("Include paths:");
                    for line in &lib.include_paths {
                        println!("  {}", line.as_os_str().to_str().unwrap());
                    }
                }

                if !lib.link_paths.is_empty() {
                    println!("Library paths:");
                    for line in &lib.link_paths {
                        println!("  {}", line.as_os_str().to_str().unwrap());
                    }
                }

                if !lib.link_paths.is_empty() {
                    println!("Runtime Library paths:");
                    for line in &lib.dll_paths {
                        println!("  {}", line.as_os_str().to_str().unwrap());
                    }
                }

                if !lib.cargo_metadata.is_empty() {
                    println!("Cargo metadata:");
                    for line in &lib.cargo_metadata {
                        println!("  {}", line);
                    }
                }
                if !lib.found_dlls.is_empty() {
                    println!("Found DLLs:");
                    for line in &lib.found_dlls {
                        println!("  {}", line.display());
                    }
                }
                if !lib.found_libs.is_empty() {
                    println!("Found libs:");
                    for line in &lib.found_libs {
                        println!("  {}", line.display());
                    }
                }
            }
            Err(err) => {
                println!("Failed:  {}", err);
            }
        }
    }
}
<commit_msg>rustfmt<commit_after>extern crate clap;
extern crate vcpkg;

use clap::{App, AppSettings, Arg, SubCommand};
use std::env;

fn main() {
    let app = App::new("vcpkg library finder")
        .about("Allows examining what vcpkg will find in a build script")
        .setting(AppSettings::SubcommandRequired)
        .arg(
            Arg::with_name("target")
                .short("t")
                .long("target")
                .value_name("TARGET TRIPLE")
                .help("the rust toolchain triple to find libraries for")
                .takes_value(true)
                .default_value("x86_64-pc-windows-msvc"),
        ).subcommand(
            SubCommand::with_name("probe")
                .about("try to find a package")
                .arg(
                    Arg::with_name("package")
                        .index(1)
                        .required(true)
                        .help("probe for a library and display paths and cargo metadata"),
                ).arg(
                    Arg::with_name("linkage")
                        .short("l")
                        .long("linkage")
                        .takes_value(true)
                        .possible_values(&["dll", "static"]),
                ),
        );

    let matches = app.get_matches();

    // set TARGET as if we are running under cargo
    env::set_var("TARGET", matches.value_of("target").unwrap());

    if let Some(matches) = matches.subcommand_matches("probe") {
        let lib_name = matches.value_of("package").unwrap();

        let mut cfg = vcpkg::Config::new();
        cfg.cargo_metadata(false);
        cfg.copy_dlls(false);
        if let Some(linkage) = matches.value_of("linkage") {
            match &linkage {
                &"dll" => {
                    // do nothing
                }
                &"static" => {
                    env::set_var("CARGO_CFG_TARGET_FEATURE", "crt-static");
                }
                _ => unreachable!(),
            }
        }

        match cfg.find_package(lib_name) {
            Ok(lib) => {
                println!("Found library {}", lib_name);

                if !lib.include_paths.is_empty() {
                    println!("Include paths:");
                    for line in &lib.include_paths {
                        println!("  {}", line.as_os_str().to_str().unwrap());
                    }
                }

                if !lib.link_paths.is_empty() {
                    println!("Library paths:");
                    for line in &lib.link_paths {
                        println!("  {}", line.as_os_str().to_str().unwrap());
                    }
                }

                if !lib.link_paths.is_empty() {
                    println!("Runtime Library paths:");
                    for line in &lib.dll_paths {
                        println!("  {}", line.as_os_str().to_str().unwrap());
                    }
                }

                if !lib.cargo_metadata.is_empty() {
                    println!("Cargo metadata:");
                    for line in &lib.cargo_metadata {
                        println!("  {}", line);
                    }
                }
                if !lib.found_dlls.is_empty() {
                    println!("Found DLLs:");
                    for line in &lib.found_dlls {
                        println!("  {}", line.display());
                    }
                }
                if !lib.found_libs.is_empty() {
                    println!("Found libs:");
                    for line in &lib.found_libs {
                        println!("  {}", line.display());
                    }
                }
            }
            Err(err) => {
                println!("Failed:  {}", err);
            }
        }
    }
}
<|endoftext|>


<commit_before>#![cfg(not(windows))]

use screen::Key;
use screen::Key::*;
use std::io::{Read, Write};
use std::fs::{File, OpenOptions};
use std::os::unix::io::AsRawFd;
use std::path::*;
use std::process::Command;
use std::process::Stdio;
use std::iter::repeat;
use std::cmp::min;
use ansi;
use ::NEWLINE;

use std::thread;
use std::sync::mpsc::Receiver;
use std::sync::mpsc;

#[allow(non_camel_case_types)] type c_ushort = u16;
#[allow(non_camel_case_types)] type c_int = i32;
#[allow(non_camel_case_types)] type c_ulong = u64;

pub struct Screen {
    tty: Terminal,
    original_stty_state: Vec<u8>,
    pub height: u16,
    pub width: u16,
    pub visible_choices: u16,
    start_line: u16,
}

impl Screen {
    pub fn open_screen() -> Screen {
        let mut tty = Terminal::open_terminal();
        let current_stty_state = tty.stty(&["-g"]);
        tty.initialize();
        let (cols, rows) = tty.winsize().unwrap();
        let visible_choices = min(20, rows - 1);
        let start_line = rows - visible_choices - 1;
        for _ in 0..visible_choices {
            tty.write(NEWLINE.as_bytes());
        }
        tty.write(&ansi::save_cursor());

        Screen {
            tty: tty,
            original_stty_state: current_stty_state,
            height: rows,
            width: cols,
            visible_choices: visible_choices,
            start_line: start_line,
        }
    }

    fn restore_tty(&mut self) {
        self.tty.stty(&[&String::from_utf8(self.original_stty_state.clone()).unwrap()]);
    }

    fn reset_cursor(&mut self) {
        self.tty.write(&ansi::restore_cursor());
        self.tty.write(&ansi::cursor_up(self.visible_choices));
    }

    pub fn move_cursor_to_prompt_line(&mut self, col: u16) {
        self.reset_cursor();
        self.tty.write(&ansi::cursor_right(col));
    }

    pub fn blank_screen(&mut self) {
        self.reset_cursor();
        let blank_line = repeat(' ').take(self.width as usize).collect::<String>();
        for _ in 0..self.visible_choices + 1 {
            self.tty.write(blank_line.as_bytes());
        }
        self.reset_cursor();
    }

    pub fn show_cursor(&mut self) {
        self.tty.write(&ansi::show_cursor());
    }

    pub fn hide_cursor(&mut self) {
        self.tty.write(&ansi::hide_cursor());
    }

    pub fn write(&mut self, s: &str) {
        self.tty.write(s.as_bytes());
    }

    pub fn write_red_inverted(&mut self, s: &str) {
        self.tty.write(&ansi::red());
        self.tty.write(&ansi::inverse());
        self.tty.write(s.as_bytes());
        self.tty.write(&ansi::reset());
    }

    pub fn write_red(&mut self, s: &str) {
        self.tty.write(&ansi::red());
        self.tty.write(s.as_bytes());
        self.tty.write(&ansi::reset());
    }

    pub fn write_inverted(&mut self, s: &str) {
        self.tty.write(&ansi::inverse());
        self.tty.write(s.as_bytes());
        self.tty.write(&ansi::reset());
    }

    // Return all buffered keystrokes, or the next key if buffer is empty.
    pub fn get_buffered_keys(&mut self) -> Vec<Key> {
        let mut ret = Vec::new();
        while let Ok(byte) = self.tty.input.try_recv() {
            ret.push(byte);
        }
        while ret.is_empty() || Screen::more_bytes_needed(&ret) {
            ret.push(self.tty.input.recv().unwrap());
        }
        Terminal::translate_bytes(ret.clone())
    }

    fn more_bytes_needed(bytes: &Vec<u8>) -> bool {
        if let Err(_) = String::from_utf8(bytes.clone()) {
            return true;
        }
        false
    }
}

impl Drop for Screen {
    fn drop(&mut self) {
        self.restore_tty();
    }
}

struct Terminal {
    input: Receiver<u8>,
    input_fd: i32,
    output: File,
}

impl Terminal {
    fn open_terminal() -> Terminal {
        let term_path = Path::new("/dev/tty");
        let mut input_file = File::open(&term_path).unwrap();
        let output_file = OpenOptions::new().write(true).open(&term_path).unwrap();
        let input_fd = input_file.as_raw_fd();
        let (tx, rx) = mpsc::channel();
        thread::spawn(move || {
            loop {
                let mut buf = [0];
                if input_file.read(&mut buf).unwrap() != 1 {
                    panic!("Failed to read a single byte from tty");
                }
                tx.send(buf[0]).unwrap();
            }
        });
        Terminal {
            input: rx,
            input_fd: input_fd,
            output: output_file,
        }
    }

    fn initialize(&mut self) {
        self.stty(&["raw", "-echo", "cbreak", "opost"]);
    }

    fn stty(&mut self, args: &[&str]) -> Vec<u8> {
        extern { fn dup2(src: c_int, dst: c_int) -> c_int;  }
        unsafe {
            // This is a hack until a replacement for InheritFd from old_io is available.
            dup2(self.input_fd, 0);
        }
        let mut process = match Command::new("stty")
            .args(args)
            .stdin(Stdio::inherit())
            .stdout(Stdio::piped())
            .spawn()
        {
            Ok(p) => p,
            Err(e) => panic!("Spawn failed: {}", e),
        };

        let exit = process.wait();

        let mut buf = Vec::new();
        if exit.unwrap().success() {
            process.stdout.as_mut().unwrap().read_to_end(&mut buf).unwrap();
            let mut str = String::from_utf8(buf).unwrap();

            // The output from `stty -g` may include a newline, which we have to strip off. Otherwise,
            // when we go to restore the tty, stty (on some platforms) will fail with an "invalid
            // argument" error.
            ::trim(&mut str);

            str.into_bytes()
        } else {
            process.stderr.as_mut().unwrap().read_to_end(&mut buf).unwrap();
            panic!(String::from_utf8(buf).unwrap());
        }
    }

    fn translate_bytes(bytes: Vec<u8>) -> Vec<Key> {
        let chars = String::from_utf8(bytes).unwrap().chars().collect::<Vec<char>>();
        chars.into_iter().map(|c| Terminal::translate_char(c)).collect()
    }

    fn translate_char(c: char) -> Key {
        let numeric_char = c as u32;
        if c == '\r' {
            Enter
        } else if numeric_char == 9 {
            Tab
        } else if numeric_char == 127 {
            Backspace
        } else if numeric_char & 96 == 0 && numeric_char <= 128u32 {
            let c = c as u8;
            Control((c + 96u8) as char)
        } else {
            Char(c)
        }
    }

    fn write(&mut self, s: &[u8]) {
        self.output.write_all(&s).unwrap();
    }

    fn writeln(&mut self, s: &str) {
        self.output.write(s.as_bytes()).unwrap();
        self.output.write("\n".as_bytes()).unwrap();
    }

    fn winsize(&self) -> Option<(u16, u16)> {
        extern { fn ioctl(fd: c_int, request: c_ulong, ...) -> c_int; }
        #[cfg(any(target_os = "macos", target_os = "freebsd"))]
        const TIOCGWINSZ: c_ulong = 0x40087468;

        #[cfg(any(target_os = "linux", target_os = "android"))]
        const TIOCGWINSZ: c_ulong = 0x00005413;

        #[repr(C)]
        struct TermSize {
            rows: c_ushort,
            cols: c_ushort,
            x: c_ushort,
            y: c_ushort,
        }

        let size = TermSize { rows: 0, cols: 0, x: 0, y: 0 };
        if unsafe { ioctl(self.output.as_raw_fd(), TIOCGWINSZ, &size) } == 0 {
            Some((size.cols as u16, size.rows as u16))
        } else {
            None
        }
    }
}

#[test]
fn winsize_test() {
    // Travis-CI builds run without a tty, making this test impossible.
    if option_env!("TRAVIS").is_some() {
        // TODO: It should be made obvious from the output that this test was skipped
        return;
    }
    let term = Terminal::open_terminal();
    let (cols, rows) = term.winsize().expect("Failed to get window size!");
    // We don't know the window size a priori, but we can at least
    // assert that it is within some kind of sensible range.
    assert!(cols > 40);
    assert!(rows > 40);
    assert!(cols < 1000);
    assert!(rows < 1000);
}
<commit_msg>Add onlcr to stty config<commit_after>#![cfg(not(windows))]

use screen::Key;
use screen::Key::*;
use std::io::{Read, Write};
use std::fs::{File, OpenOptions};
use std::os::unix::io::AsRawFd;
use std::path::*;
use std::process::Command;
use std::process::Stdio;
use std::iter::repeat;
use std::cmp::min;
use ansi;
use ::NEWLINE;

use std::thread;
use std::sync::mpsc::Receiver;
use std::sync::mpsc;

#[allow(non_camel_case_types)] type c_ushort = u16;
#[allow(non_camel_case_types)] type c_int = i32;
#[allow(non_camel_case_types)] type c_ulong = u64;

pub struct Screen {
    tty: Terminal,
    original_stty_state: Vec<u8>,
    pub height: u16,
    pub width: u16,
    pub visible_choices: u16,
    start_line: u16,
}

impl Screen {
    pub fn open_screen() -> Screen {
        let mut tty = Terminal::open_terminal();
        let current_stty_state = tty.stty(&["-g"]);
        tty.initialize();
        let (cols, rows) = tty.winsize().unwrap();
        let visible_choices = min(20, rows - 1);
        let start_line = rows - visible_choices - 1;
        for _ in 0..visible_choices {
            tty.write(NEWLINE.as_bytes());
        }
        tty.write(&ansi::save_cursor());

        Screen {
            tty: tty,
            original_stty_state: current_stty_state,
            height: rows,
            width: cols,
            visible_choices: visible_choices,
            start_line: start_line,
        }
    }

    fn restore_tty(&mut self) {
        self.tty.stty(&[&String::from_utf8(self.original_stty_state.clone()).unwrap()]);
    }

    fn reset_cursor(&mut self) {
        self.tty.write(&ansi::restore_cursor());
        self.tty.write(&ansi::cursor_up(self.visible_choices));
    }

    pub fn move_cursor_to_prompt_line(&mut self, col: u16) {
        self.reset_cursor();
        self.tty.write(&ansi::cursor_right(col));
    }

    pub fn blank_screen(&mut self) {
        self.reset_cursor();
        let blank_line = repeat(' ').take(self.width as usize).collect::<String>();
        for _ in 0..self.visible_choices + 1 {
            self.tty.write(blank_line.as_bytes());
        }
        self.reset_cursor();
    }

    pub fn show_cursor(&mut self) {
        self.tty.write(&ansi::show_cursor());
    }

    pub fn hide_cursor(&mut self) {
        self.tty.write(&ansi::hide_cursor());
    }

    pub fn write(&mut self, s: &str) {
        self.tty.write(s.as_bytes());
    }

    pub fn write_red_inverted(&mut self, s: &str) {
        self.tty.write(&ansi::red());
        self.tty.write(&ansi::inverse());
        self.tty.write(s.as_bytes());
        self.tty.write(&ansi::reset());
    }

    pub fn write_red(&mut self, s: &str) {
        self.tty.write(&ansi::red());
        self.tty.write(s.as_bytes());
        self.tty.write(&ansi::reset());
    }

    pub fn write_inverted(&mut self, s: &str) {
        self.tty.write(&ansi::inverse());
        self.tty.write(s.as_bytes());
        self.tty.write(&ansi::reset());
    }

    // Return all buffered keystrokes, or the next key if buffer is empty.
    pub fn get_buffered_keys(&mut self) -> Vec<Key> {
        let mut ret = Vec::new();
        while let Ok(byte) = self.tty.input.try_recv() {
            ret.push(byte);
        }
        while ret.is_empty() || Screen::more_bytes_needed(&ret) {
            ret.push(self.tty.input.recv().unwrap());
        }
        Terminal::translate_bytes(ret.clone())
    }

    fn more_bytes_needed(bytes: &Vec<u8>) -> bool {
        if let Err(_) = String::from_utf8(bytes.clone()) {
            return true;
        }
        false
    }
}

impl Drop for Screen {
    fn drop(&mut self) {
        self.restore_tty();
    }
}

struct Terminal {
    input: Receiver<u8>,
    input_fd: i32,
    output: File,
}

impl Terminal {
    fn open_terminal() -> Terminal {
        let term_path = Path::new("/dev/tty");
        let mut input_file = File::open(&term_path).unwrap();
        let output_file = OpenOptions::new().write(true).open(&term_path).unwrap();
        let input_fd = input_file.as_raw_fd();
        let (tx, rx) = mpsc::channel();
        thread::spawn(move || {
            loop {
                let mut buf = [0];
                if input_file.read(&mut buf).unwrap() != 1 {
                    panic!("Failed to read a single byte from tty");
                }
                tx.send(buf[0]).unwrap();
            }
        });
        Terminal {
            input: rx,
            input_fd: input_fd,
            output: output_file,
        }
    }

    fn initialize(&mut self) {
        self.stty(&["raw", "-echo", "cbreak", "opost", "onlcr"]);
    }

    fn stty(&mut self, args: &[&str]) -> Vec<u8> {
        extern { fn dup2(src: c_int, dst: c_int) -> c_int;  }
        unsafe {
            // This is a hack until a replacement for InheritFd from old_io is available.
            dup2(self.input_fd, 0);
        }
        let mut process = match Command::new("stty")
            .args(args)
            .stdin(Stdio::inherit())
            .stdout(Stdio::piped())
            .spawn()
        {
            Ok(p) => p,
            Err(e) => panic!("Spawn failed: {}", e),
        };

        let exit = process.wait();

        let mut buf = Vec::new();
        if exit.unwrap().success() {
            process.stdout.as_mut().unwrap().read_to_end(&mut buf).unwrap();
            let mut str = String::from_utf8(buf).unwrap();

            // The output from `stty -g` may include a newline, which we have to strip off. Otherwise,
            // when we go to restore the tty, stty (on some platforms) will fail with an "invalid
            // argument" error.
            ::trim(&mut str);

            str.into_bytes()
        } else {
            process.stderr.as_mut().unwrap().read_to_end(&mut buf).unwrap();
            panic!(String::from_utf8(buf).unwrap());
        }
    }

    fn translate_bytes(bytes: Vec<u8>) -> Vec<Key> {
        let chars = String::from_utf8(bytes).unwrap().chars().collect::<Vec<char>>();
        chars.into_iter().map(|c| Terminal::translate_char(c)).collect()
    }

    fn translate_char(c: char) -> Key {
        let numeric_char = c as u32;
        if c == '\r' {
            Enter
        } else if numeric_char == 9 {
            Tab
        } else if numeric_char == 127 {
            Backspace
        } else if numeric_char & 96 == 0 && numeric_char <= 128u32 {
            let c = c as u8;
            Control((c + 96u8) as char)
        } else {
            Char(c)
        }
    }

    fn write(&mut self, s: &[u8]) {
        self.output.write_all(&s).unwrap();
    }

    fn writeln(&mut self, s: &str) {
        self.output.write(s.as_bytes()).unwrap();
        self.output.write("\n".as_bytes()).unwrap();
    }

    fn winsize(&self) -> Option<(u16, u16)> {
        extern { fn ioctl(fd: c_int, request: c_ulong, ...) -> c_int; }
        #[cfg(any(target_os = "macos", target_os = "freebsd"))]
        const TIOCGWINSZ: c_ulong = 0x40087468;

        #[cfg(any(target_os = "linux", target_os = "android"))]
        const TIOCGWINSZ: c_ulong = 0x00005413;

        #[repr(C)]
        struct TermSize {
            rows: c_ushort,
            cols: c_ushort,
            x: c_ushort,
            y: c_ushort,
        }

        let size = TermSize { rows: 0, cols: 0, x: 0, y: 0 };
        if unsafe { ioctl(self.output.as_raw_fd(), TIOCGWINSZ, &size) } == 0 {
            Some((size.cols as u16, size.rows as u16))
        } else {
            None
        }
    }
}

#[test]
fn winsize_test() {
    // Travis-CI builds run without a tty, making this test impossible.
    if option_env!("TRAVIS").is_some() {
        // TODO: It should be made obvious from the output that this test was skipped
        return;
    }
    let term = Terminal::open_terminal();
    let (cols, rows) = term.winsize().expect("Failed to get window size!");
    // We don't know the window size a priori, but we can at least
    // assert that it is within some kind of sensible range.
    assert!(cols > 40);
    assert!(rows > 40);
    assert!(cols < 1000);
    assert!(rows < 1000);
}
<|endoftext|>


<commit_before>extern crate redis;

use std::env;
use std::fmt;
use std::error::Error;
use std::default::Default;
use std::time::{SystemTime, UNIX_EPOCH};

use rand::{Rng, thread_rng};
use serde::{Serialize, Serializer};
use serde_json;
use serde_json::Value;
use r2d2_redis::RedisConnectionManager;
use r2d2::{Config, Pool, PooledConnection, GetTimeout, InitializationError};

pub type RedisPooledConnection = PooledConnection<RedisConnectionManager>;
pub type RedisPool = Pool<RedisConnectionManager>;

#[derive(Debug)]
pub struct ClientError {
    kind: ErrorKind,
}

#[derive(Debug)]
enum ErrorKind {
    Redis(redis::RedisError),
    PoolTimeout(GetTimeout),
    PoolInit(InitializationError),
}

pub fn create_redis_pool() -> Result<RedisPool, ClientError> {
    let config = Config::builder().build();
    let redis_url = &env::var("REDIS_URL").unwrap_or("redis://127.0.0.1/".to_owned());
    let url = redis::parse_redis_url(redis_url).unwrap();
    let manager = RedisConnectionManager::new(url).unwrap();
    Pool::new(config, manager).map_err(|err| ClientError { kind: ErrorKind::PoolInit(err) })
}

pub struct Job {
    pub class: String,
    pub args: Vec<Value>,
    pub retry: i64,
    pub queue: String,
    pub jid: String,
    pub created_at: u64,
    pub enqueued_at: u64,
}

impl fmt::Display for ClientError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self.kind {
            ErrorKind::Redis(ref err) => err.fmt(f),
            ErrorKind::PoolTimeout(ref err) => err.fmt(f),
            ErrorKind::PoolInit(ref err) => err.fmt(f),
        }
    }
}

impl Error for ClientError {
    fn description(&self) -> &str {
        match self.kind {
            ErrorKind::Redis(ref err) => err.description(),
            ErrorKind::PoolTimeout(ref err) => err.description(),
            ErrorKind::PoolInit(ref err) => err.description(),
        }
    }

    fn cause(&self) -> Option<&Error> {
        match self.kind {
            ErrorKind::Redis(ref err) => Some(err),
            ErrorKind::PoolTimeout(ref err) => Some(err),
            ErrorKind::PoolInit(ref err) => Some(err),
        }
    }
}

impl From<redis::RedisError> for ClientError {
    fn from(error: redis::RedisError) -> ClientError {
        ClientError { kind: ErrorKind::Redis(error) }
    }
}

impl From<GetTimeout> for ClientError {
    fn from(error: GetTimeout) -> ClientError {
        ClientError { kind: ErrorKind::PoolTimeout(error) }
    }
}

impl From<InitializationError> for ClientError {
    fn from(error: InitializationError) -> ClientError {
        ClientError { kind: ErrorKind::PoolInit(error) }
    }
}

impl Default for JobOpts {
    fn default() -> JobOpts {
        let now = SystemTime::now()
            .duration_since(UNIX_EPOCH)
            .unwrap()
            .as_secs() as u64;
        let jid = thread_rng().gen_ascii_chars().take(24).collect::<String>();
        JobOpts {
            retry: 25,
            queue: "default".to_string(),
            jid: jid,
            created_at: now,
            enqueued_at: now,
        }
    }
}

pub struct JobOpts {
    pub retry: i64,
    pub queue: String,
    pub jid: String,
    pub created_at: u64,
    pub enqueued_at: u64,
}

impl Job {
    pub fn new(class: String, args: Vec<Value>, opts: JobOpts) -> Job {
        Job {
            class: class,
            args: args,
            retry: opts.retry,
            queue: opts.queue,
            jid: opts.jid,
            created_at: opts.created_at,
            enqueued_at: opts.enqueued_at,
        }
    }
}

impl Serialize for Job {
    fn serialize<S>(&self, serializer: &mut S) -> Result<(), S::Error>
        where S: Serializer
    {
        let mut state = try!(serializer.serialize_struct("Job", 7));
        try!(serializer.serialize_struct_elt(&mut state, "class", &self.class));
        try!(serializer.serialize_struct_elt(&mut state, "args", &self.args));
        try!(serializer.serialize_struct_elt(&mut state, "retry", &self.retry));
        try!(serializer.serialize_struct_elt(&mut state, "queue", &self.queue));
        try!(serializer.serialize_struct_elt(&mut state, "jid", &self.jid));
        try!(serializer.serialize_struct_elt(&mut state, "created_at", &self.created_at));
        try!(serializer.serialize_struct_elt(&mut state, "enqueued_at", &self.enqueued_at));
        serializer.serialize_struct_end(state)
    }
}

pub struct ClientOpts {
    pub namespace: Option<String>,
}

impl Default for ClientOpts {
    fn default() -> ClientOpts {
        ClientOpts { namespace: None }
    }
}

pub struct Client {
    pub redis_pool: RedisPool,
    pub namespace: Option<String>,
}

impl Client {
    pub fn new(redis_pool: RedisPool, opts: ClientOpts) -> Client {
        Client {
            redis_pool: redis_pool,
            namespace: opts.namespace,
        }
    }

    fn connect(&self) -> Result<RedisPooledConnection, ClientError> {
        match self.redis_pool.get() {
            Ok(conn) => Ok(conn),
            Err(err) => Err(ClientError { kind: ErrorKind::PoolTimeout(err) }),
        }
    }

    pub fn push(&self, job: Job) -> Result<(), ClientError> {
        self.raw_push(vec![job])
    }

    pub fn push_bulk(&self, jobs: Vec<Job>) -> Result<(), ClientError> {
        self.raw_push(jobs)
    }

    fn raw_push(&self, payloads: Vec<Job>) -> Result<(), ClientError> {
        let ref p = payloads[0];
        let to_push = payloads.iter().map(|entry| serde_json::to_string(&entry).unwrap()).collect::<Vec<_>>();
        match self.connect() {
            Ok(conn) => {
                redis::pipe()
                    .atomic()
                    .cmd("SADD")
                    .arg("queues")
                    .arg(p.queue.to_string())
                    .ignore()
                    .cmd("LPUSH")
                    .arg(self.queue_name(&p.queue))
                    .arg(to_push)
                    .query(&*conn)
                    .map_err(|err| ClientError { kind: ErrorKind::Redis(err) })
            }
            Err(err) => Err(err),
        }
    }

    fn queue_name(&self, queue: &str) -> String {
        if let Some(ref ns) = self.namespace {
            format!("{}:queue:{}", ns, queue)
        } else {
            format!("queue:{}", queue)
        }
    }
}
<commit_msg>cargo fmt<commit_after>extern crate redis;

use std::env;
use std::fmt;
use std::error::Error;
use std::default::Default;
use std::time::{SystemTime, UNIX_EPOCH};

use rand::{Rng, thread_rng};
use serde::{Serialize, Serializer};
use serde_json;
use serde_json::Value;
use r2d2_redis::RedisConnectionManager;
use r2d2::{Config, Pool, PooledConnection, GetTimeout, InitializationError};

pub type RedisPooledConnection = PooledConnection<RedisConnectionManager>;
pub type RedisPool = Pool<RedisConnectionManager>;

#[derive(Debug)]
pub struct ClientError {
    kind: ErrorKind,
}

#[derive(Debug)]
enum ErrorKind {
    Redis(redis::RedisError),
    PoolTimeout(GetTimeout),
    PoolInit(InitializationError),
}

pub fn create_redis_pool() -> Result<RedisPool, ClientError> {
    let config = Config::builder().build();
    let redis_url = &env::var("REDIS_URL").unwrap_or("redis://127.0.0.1/".to_owned());
    let url = redis::parse_redis_url(redis_url).unwrap();
    let manager = RedisConnectionManager::new(url).unwrap();
    Pool::new(config, manager).map_err(|err| ClientError { kind: ErrorKind::PoolInit(err) })
}

pub struct Job {
    pub class: String,
    pub args: Vec<Value>,
    pub retry: i64,
    pub queue: String,
    pub jid: String,
    pub created_at: u64,
    pub enqueued_at: u64,
}

impl fmt::Display for ClientError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self.kind {
            ErrorKind::Redis(ref err) => err.fmt(f),
            ErrorKind::PoolTimeout(ref err) => err.fmt(f),
            ErrorKind::PoolInit(ref err) => err.fmt(f),
        }
    }
}

impl Error for ClientError {
    fn description(&self) -> &str {
        match self.kind {
            ErrorKind::Redis(ref err) => err.description(),
            ErrorKind::PoolTimeout(ref err) => err.description(),
            ErrorKind::PoolInit(ref err) => err.description(),
        }
    }

    fn cause(&self) -> Option<&Error> {
        match self.kind {
            ErrorKind::Redis(ref err) => Some(err),
            ErrorKind::PoolTimeout(ref err) => Some(err),
            ErrorKind::PoolInit(ref err) => Some(err),
        }
    }
}

impl From<redis::RedisError> for ClientError {
    fn from(error: redis::RedisError) -> ClientError {
        ClientError { kind: ErrorKind::Redis(error) }
    }
}

impl From<GetTimeout> for ClientError {
    fn from(error: GetTimeout) -> ClientError {
        ClientError { kind: ErrorKind::PoolTimeout(error) }
    }
}

impl From<InitializationError> for ClientError {
    fn from(error: InitializationError) -> ClientError {
        ClientError { kind: ErrorKind::PoolInit(error) }
    }
}

impl Default for JobOpts {
    fn default() -> JobOpts {
        let now = SystemTime::now()
            .duration_since(UNIX_EPOCH)
            .unwrap()
            .as_secs() as u64;
        let jid = thread_rng().gen_ascii_chars().take(24).collect::<String>();
        JobOpts {
            retry: 25,
            queue: "default".to_string(),
            jid: jid,
            created_at: now,
            enqueued_at: now,
        }
    }
}

pub struct JobOpts {
    pub retry: i64,
    pub queue: String,
    pub jid: String,
    pub created_at: u64,
    pub enqueued_at: u64,
}

impl Job {
    pub fn new(class: String, args: Vec<Value>, opts: JobOpts) -> Job {
        Job {
            class: class,
            args: args,
            retry: opts.retry,
            queue: opts.queue,
            jid: opts.jid,
            created_at: opts.created_at,
            enqueued_at: opts.enqueued_at,
        }
    }
}

impl Serialize for Job {
    fn serialize<S>(&self, serializer: &mut S) -> Result<(), S::Error>
        where S: Serializer
    {
        let mut state = try!(serializer.serialize_struct("Job", 7));
        try!(serializer.serialize_struct_elt(&mut state, "class", &self.class));
        try!(serializer.serialize_struct_elt(&mut state, "args", &self.args));
        try!(serializer.serialize_struct_elt(&mut state, "retry", &self.retry));
        try!(serializer.serialize_struct_elt(&mut state, "queue", &self.queue));
        try!(serializer.serialize_struct_elt(&mut state, "jid", &self.jid));
        try!(serializer.serialize_struct_elt(&mut state, "created_at", &self.created_at));
        try!(serializer.serialize_struct_elt(&mut state, "enqueued_at", &self.enqueued_at));
        serializer.serialize_struct_end(state)
    }
}

pub struct ClientOpts {
    pub namespace: Option<String>,
}

impl Default for ClientOpts {
    fn default() -> ClientOpts {
        ClientOpts { namespace: None }
    }
}

pub struct Client {
    pub redis_pool: RedisPool,
    pub namespace: Option<String>,
}

impl Client {
    pub fn new(redis_pool: RedisPool, opts: ClientOpts) -> Client {
        Client {
            redis_pool: redis_pool,
            namespace: opts.namespace,
        }
    }

    fn connect(&self) -> Result<RedisPooledConnection, ClientError> {
        match self.redis_pool.get() {
            Ok(conn) => Ok(conn),
            Err(err) => Err(ClientError { kind: ErrorKind::PoolTimeout(err) }),
        }
    }

    pub fn push(&self, job: Job) -> Result<(), ClientError> {
        self.raw_push(vec![job])
    }

    pub fn push_bulk(&self, jobs: Vec<Job>) -> Result<(), ClientError> {
        self.raw_push(jobs)
    }

    fn raw_push(&self, payloads: Vec<Job>) -> Result<(), ClientError> {
        let ref p = payloads[0];
        let to_push =
            payloads.iter().map(|entry| serde_json::to_string(&entry).unwrap()).collect::<Vec<_>>();
        match self.connect() {
            Ok(conn) => {
                redis::pipe()
                    .atomic()
                    .cmd("SADD")
                    .arg("queues")
                    .arg(p.queue.to_string())
                    .ignore()
                    .cmd("LPUSH")
                    .arg(self.queue_name(&p.queue))
                    .arg(to_push)
                    .query(&*conn)
                    .map_err(|err| ClientError { kind: ErrorKind::Redis(err) })
            }
            Err(err) => Err(err),
        }
    }

    fn queue_name(&self, queue: &str) -> String {
        if let Some(ref ns) = self.namespace {
            format!("{}:queue:{}", ns, queue)
        } else {
            format!("queue:{}", queue)
        }
    }
}
<|endoftext|>


<commit_before>use std::{collections::BTreeMap, convert::TryFrom};

use ruma::{
    events::{
        from_raw_json_value,
        pdu::{EventHash, Pdu, PduStub},
        room::member::{MemberEventContent, MembershipState},
        EventDeHelper, EventType,
    },
    identifiers::{EventId, RoomId, ServerName, UserId},
};
use serde::{de, Serialize};
use serde_json::value::RawValue as RawJsonValue;
use std::time::SystemTime;

pub struct Requester<'a> {
    pub prev_event_ids: Vec<EventId>,
    pub room_id: &'a RoomId,
    pub content: &'a serde_json::Value,
    pub state_key: Option<String>,
    pub sender: &'a UserId,
}

#[derive(Clone, Debug, Serialize)]
#[serde(untagged)]
pub enum StateEvent {
    Full(Pdu),
    Sync(PduStub),
}

impl StateEvent {
    pub fn to_requester(&self) -> Requester<'_> {
        Requester {
            prev_event_ids: self.prev_event_ids(),
            room_id: self.room_id().unwrap(),
            content: self.content(),
            state_key: self.state_key(),
            sender: self.sender(),
        }
    }

    pub fn is_power_event(&self) -> bool {
        match self {
            Self::Full(any_event) => match any_event {
                Pdu::RoomV1Pdu(event) => match event.kind {
                    EventType::RoomPowerLevels
                    | EventType::RoomJoinRules
                    | EventType::RoomCreate => event.state_key == Some("".into()),
                    EventType::RoomMember => {
                        if let Ok(content) =
                            // TODO fix clone
                            serde_json::from_value::<MemberEventContent>(event.content.clone())
                        {
                            if [MembershipState::Leave, MembershipState::Ban]
                                .contains(&content.membership)
                            {
                                return event.sender.as_str()
                                    // TODO is None here a failure
                                    != event.state_key.as_deref().unwrap_or("NOT A STATE KEY");
                            }
                        }

                        false
                    }
                    _ => false,
                },
                Pdu::RoomV3Pdu(event) => event.state_key == Some("".into()),
            },
            Self::Sync(any_event) => match any_event {
                PduStub::RoomV1PduStub(event) => match event.kind {
                    EventType::RoomPowerLevels
                    | EventType::RoomJoinRules
                    | EventType::RoomCreate => event.state_key == Some("".into()),
                    EventType::RoomMember => {
                        if let Ok(content) =
                            serde_json::from_value::<MemberEventContent>(event.content.clone())
                        {
                            if [MembershipState::Leave, MembershipState::Ban]
                                .contains(&content.membership)
                            {
                                return event.sender.as_str()
                                    // TODO does None here mean the same as state_key = ""
                                    != event.state_key.as_deref().unwrap_or("");
                            }
                        }

                        false
                    }
                    _ => false,
                },
                PduStub::RoomV3PduStub(event) => event.state_key == Some("".into()),
            },
        }
    }
    pub fn deserialize_content<C: serde::de::DeserializeOwned>(
        &self,
    ) -> Result<C, serde_json::Error> {
        match self {
            Self::Full(ev) => match ev {
                Pdu::RoomV1Pdu(ev) => serde_json::from_value(ev.content.clone()),
                Pdu::RoomV3Pdu(ev) => serde_json::from_value(ev.content.clone()),
            },
            Self::Sync(ev) => match ev {
                PduStub::RoomV1PduStub(ev) => serde_json::from_value(ev.content.clone()),
                PduStub::RoomV3PduStub(ev) => serde_json::from_value(ev.content.clone()),
            },
        }
    }
    pub fn origin_server_ts(&self) -> &SystemTime {
        match self {
            Self::Full(ev) => match ev {
                Pdu::RoomV1Pdu(ev) => &ev.origin_server_ts,
                Pdu::RoomV3Pdu(ev) => &ev.origin_server_ts,
            },
            Self::Sync(ev) => match ev {
                PduStub::RoomV1PduStub(ev) => &ev.origin_server_ts,
                PduStub::RoomV3PduStub(ev) => &ev.origin_server_ts,
            },
        }
    }
    pub fn event_id(&self) -> EventId {
        match self {
            Self::Full(ev) => match ev {
                Pdu::RoomV1Pdu(ev) => ev.event_id.clone(),
                Pdu::RoomV3Pdu(_) => EventId::try_from(&*format!(
                    "${}",
                    ruma::signatures::reference_hash(
                        &serde_json::to_value(&ev).expect("event is valid, we just created it")
                    )
                    .expect("ruma can calculate reference hashes")
                ))
                .expect("ruma's reference hashes are valid event ids"),
            },
            Self::Sync(ev) => EventId::try_from(&*format!(
                "${}",
                ruma::signatures::reference_hash(
                    &serde_json::to_value(&ev).expect("event is valid, we just created it")
                )
                .expect("ruma can calculate reference hashes")
            ))
            .expect("ruma's reference hashes are valid event ids"),
        }
    }

    pub fn sender(&self) -> &UserId {
        match self {
            Self::Full(ev) => match ev {
                Pdu::RoomV1Pdu(ev) => &ev.sender,
                Pdu::RoomV3Pdu(ev) => &ev.sender,
            },
            Self::Sync(ev) => match ev {
                PduStub::RoomV1PduStub(ev) => &ev.sender,
                PduStub::RoomV3PduStub(ev) => &ev.sender,
            },
        }
    }

    pub fn redacts(&self) -> Option<&EventId> {
        match self {
            Self::Full(ev) => match ev {
                Pdu::RoomV1Pdu(ev) => ev.redacts.as_ref(),
                Pdu::RoomV3Pdu(ev) => ev.redacts.as_ref(),
            },
            Self::Sync(ev) => match ev {
                PduStub::RoomV1PduStub(ev) => ev.redacts.as_ref(),
                PduStub::RoomV3PduStub(ev) => ev.redacts.as_ref(),
            },
        }
    }

    pub fn room_id(&self) -> Option<&RoomId> {
        match self {
            Self::Full(ev) => match ev {
                Pdu::RoomV1Pdu(ev) => Some(&ev.room_id),
                Pdu::RoomV3Pdu(ev) => Some(&ev.room_id),
            },
            Self::Sync(_) => None,
        }
    }
    pub fn kind(&self) -> EventType {
        match self {
            Self::Full(ev) => match ev {
                Pdu::RoomV1Pdu(ev) => ev.kind.clone(),
                Pdu::RoomV3Pdu(ev) => ev.kind.clone(),
            },
            Self::Sync(ev) => match ev {
                PduStub::RoomV1PduStub(ev) => ev.kind.clone(),
                PduStub::RoomV3PduStub(ev) => ev.kind.clone(),
            },
        }
    }
    pub fn state_key(&self) -> Option<String> {
        match self {
            Self::Full(ev) => match ev {
                Pdu::RoomV1Pdu(ev) => ev.state_key.clone(),
                Pdu::RoomV3Pdu(ev) => ev.state_key.clone(),
            },
            Self::Sync(ev) => match ev {
                PduStub::RoomV1PduStub(ev) => ev.state_key.clone(),
                PduStub::RoomV3PduStub(ev) => ev.state_key.clone(),
            },
        }
    }

    pub fn prev_event_ids(&self) -> Vec<EventId> {
        match self {
            Self::Full(ev) => match ev {
                Pdu::RoomV1Pdu(ev) => ev.prev_events.iter().map(|(id, _)| id).cloned().collect(),
                Pdu::RoomV3Pdu(ev) => ev.prev_events.clone(),
            },
            Self::Sync(ev) => match ev {
                PduStub::RoomV1PduStub(ev) => {
                    ev.prev_events.iter().map(|(id, _)| id).cloned().collect()
                }
                PduStub::RoomV3PduStub(ev) => ev.prev_events.to_vec(),
            },
        }
    }

    pub fn auth_events(&self) -> Vec<EventId> {
        match self {
            Self::Full(ev) => match ev {
                Pdu::RoomV1Pdu(ev) => ev.auth_events.iter().map(|(id, _)| id).cloned().collect(),
                Pdu::RoomV3Pdu(ev) => ev.auth_events.to_vec(),
            },
            Self::Sync(ev) => match ev {
                PduStub::RoomV1PduStub(ev) => {
                    ev.auth_events.iter().map(|(id, _)| id).cloned().collect()
                }
                PduStub::RoomV3PduStub(ev) => ev.auth_events.to_vec(),
            },
        }
    }

    pub fn content(&self) -> &serde_json::Value {
        match self {
            Self::Full(ev) => match ev {
                Pdu::RoomV1Pdu(ev) => &ev.content,
                Pdu::RoomV3Pdu(ev) => &ev.content,
            },
            Self::Sync(ev) => match ev {
                PduStub::RoomV1PduStub(ev) => &ev.content,
                PduStub::RoomV3PduStub(ev) => &ev.content,
            },
        }
    }

    pub fn unsigned(&self) -> &BTreeMap<String, serde_json::Value> {
        // CONFIRM: The only way this would fail is if we got bad json, it should fail in ruma
        // before it fails here.
        match self {
            Self::Full(ev) => match ev {
                Pdu::RoomV1Pdu(ev) => &ev.unsigned,
                Pdu::RoomV3Pdu(ev) => &ev.unsigned,
            },
            Self::Sync(ev) => match ev {
                PduStub::RoomV1PduStub(ev) => &ev.unsigned,
                PduStub::RoomV3PduStub(ev) => &ev.unsigned,
            },
        }
    }

    pub fn signatures(&self) -> BTreeMap<Box<ServerName>, BTreeMap<ruma::ServerKeyId, String>> {
        match self {
            Self::Full(ev) => match ev {
                Pdu::RoomV1Pdu(_) => maplit::btreemap! {},
                Pdu::RoomV3Pdu(ev) => ev.signatures.clone(),
            },
            Self::Sync(ev) => match ev {
                PduStub::RoomV1PduStub(ev) => ev.signatures.clone(),
                PduStub::RoomV3PduStub(ev) => ev.signatures.clone(),
            },
        }
    }

    pub fn hashes(&self) -> &EventHash {
        match self {
            Self::Full(ev) => match ev {
                Pdu::RoomV1Pdu(ev) => &ev.hashes,
                Pdu::RoomV3Pdu(ev) => &ev.hashes,
            },
            Self::Sync(ev) => match ev {
                PduStub::RoomV1PduStub(ev) => &ev.hashes,
                PduStub::RoomV3PduStub(ev) => &ev.hashes,
            },
        }
    }

    pub fn is_type_and_key(&self, ev_type: EventType, state_key: &str) -> bool {
        match self {
            Self::Full(ev) => match ev {
                Pdu::RoomV1Pdu(ev) => {
                    ev.kind == ev_type && ev.state_key.as_deref() == Some(state_key)
                }
                Pdu::RoomV3Pdu(ev) => {
                    ev.kind == ev_type && ev.state_key.as_deref() == Some(state_key)
                }
            },
            Self::Sync(ev) => match ev {
                PduStub::RoomV1PduStub(ev) => {
                    ev.kind == ev_type && ev.state_key.as_deref() == Some(state_key)
                }
                PduStub::RoomV3PduStub(ev) => {
                    ev.kind == ev_type && ev.state_key.as_deref() == Some(state_key)
                }
            },
        }
    }
}

impl<'de> de::Deserialize<'de> for StateEvent {
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
    where
        D: de::Deserializer<'de>,
    {
        let json = Box::<RawJsonValue>::deserialize(deserializer)?;
        let EventDeHelper {
            room_id, unsigned, ..
        } = from_raw_json_value(&json)?;

        // Determine whether the event is a full or sync
        // based on the fields present.
        if room_id.is_some() {
            Ok(match unsigned {
                Some(unsigned) if unsigned.redacted_because.is_some() => {
                    panic!("TODO deal with redacted events")
                }
                _ => StateEvent::Full(Pdu::RoomV1Pdu(from_raw_json_value(&json)?)),
            })
        } else {
            Ok(match unsigned {
                Some(unsigned) if unsigned.redacted_because.is_some() => {
                    panic!("TODO deal with redacted events")
                }
                _ => StateEvent::Sync(from_raw_json_value(&json)?),
            })
        }
    }
}
<commit_msg>Add origin getter to StateEvent<commit_after>use std::{collections::BTreeMap, convert::TryFrom};

use ruma::{
    events::{
        from_raw_json_value,
        pdu::{EventHash, Pdu, PduStub},
        room::member::{MemberEventContent, MembershipState},
        EventDeHelper, EventType,
    },
    identifiers::{EventId, RoomId, ServerName, UserId},
};
use serde::{de, Serialize};
use serde_json::value::RawValue as RawJsonValue;
use std::time::SystemTime;

pub struct Requester<'a> {
    pub prev_event_ids: Vec<EventId>,
    pub room_id: &'a RoomId,
    pub content: &'a serde_json::Value,
    pub state_key: Option<String>,
    pub sender: &'a UserId,
}

#[derive(Clone, Debug, Serialize)]
#[serde(untagged)]
pub enum StateEvent {
    Full(Pdu),
    Sync(PduStub),
}

impl StateEvent {
    pub fn to_requester(&self) -> Requester<'_> {
        Requester {
            prev_event_ids: self.prev_event_ids(),
            room_id: self.room_id().unwrap(),
            content: self.content(),
            state_key: self.state_key(),
            sender: self.sender(),
        }
    }

    pub fn is_power_event(&self) -> bool {
        match self {
            Self::Full(any_event) => match any_event {
                Pdu::RoomV1Pdu(event) => match event.kind {
                    EventType::RoomPowerLevels
                    | EventType::RoomJoinRules
                    | EventType::RoomCreate => event.state_key == Some("".into()),
                    EventType::RoomMember => {
                        if let Ok(content) =
                            // TODO fix clone
                            serde_json::from_value::<MemberEventContent>(event.content.clone())
                        {
                            if [MembershipState::Leave, MembershipState::Ban]
                                .contains(&content.membership)
                            {
                                return event.sender.as_str()
                                    // TODO is None here a failure
                                    != event.state_key.as_deref().unwrap_or("NOT A STATE KEY");
                            }
                        }

                        false
                    }
                    _ => false,
                },
                Pdu::RoomV3Pdu(event) => event.state_key == Some("".into()),
            },
            Self::Sync(any_event) => match any_event {
                PduStub::RoomV1PduStub(event) => match event.kind {
                    EventType::RoomPowerLevels
                    | EventType::RoomJoinRules
                    | EventType::RoomCreate => event.state_key == Some("".into()),
                    EventType::RoomMember => {
                        if let Ok(content) =
                            serde_json::from_value::<MemberEventContent>(event.content.clone())
                        {
                            if [MembershipState::Leave, MembershipState::Ban]
                                .contains(&content.membership)
                            {
                                return event.sender.as_str()
                                    // TODO does None here mean the same as state_key = ""
                                    != event.state_key.as_deref().unwrap_or("");
                            }
                        }

                        false
                    }
                    _ => false,
                },
                PduStub::RoomV3PduStub(event) => event.state_key == Some("".into()),
            },
        }
    }
    pub fn deserialize_content<C: serde::de::DeserializeOwned>(
        &self,
    ) -> Result<C, serde_json::Error> {
        match self {
            Self::Full(ev) => match ev {
                Pdu::RoomV1Pdu(ev) => serde_json::from_value(ev.content.clone()),
                Pdu::RoomV3Pdu(ev) => serde_json::from_value(ev.content.clone()),
            },
            Self::Sync(ev) => match ev {
                PduStub::RoomV1PduStub(ev) => serde_json::from_value(ev.content.clone()),
                PduStub::RoomV3PduStub(ev) => serde_json::from_value(ev.content.clone()),
            },
        }
    }
    pub fn origin_server_ts(&self) -> &SystemTime {
        match self {
            Self::Full(ev) => match ev {
                Pdu::RoomV1Pdu(ev) => &ev.origin_server_ts,
                Pdu::RoomV3Pdu(ev) => &ev.origin_server_ts,
            },
            Self::Sync(ev) => match ev {
                PduStub::RoomV1PduStub(ev) => &ev.origin_server_ts,
                PduStub::RoomV3PduStub(ev) => &ev.origin_server_ts,
            },
        }
    }
    pub fn event_id(&self) -> EventId {
        match self {
            Self::Full(ev) => match ev {
                Pdu::RoomV1Pdu(ev) => ev.event_id.clone(),
                Pdu::RoomV3Pdu(_) => EventId::try_from(&*format!(
                    "${}",
                    ruma::signatures::reference_hash(
                        &serde_json::to_value(&ev).expect("event is valid, we just created it")
                    )
                    .expect("ruma can calculate reference hashes")
                ))
                .expect("ruma's reference hashes are valid event ids"),
            },
            Self::Sync(ev) => EventId::try_from(&*format!(
                "${}",
                ruma::signatures::reference_hash(
                    &serde_json::to_value(&ev).expect("event is valid, we just created it")
                )
                .expect("ruma can calculate reference hashes")
            ))
            .expect("ruma's reference hashes are valid event ids"),
        }
    }

    pub fn sender(&self) -> &UserId {
        match self {
            Self::Full(ev) => match ev {
                Pdu::RoomV1Pdu(ev) => &ev.sender,
                Pdu::RoomV3Pdu(ev) => &ev.sender,
            },
            Self::Sync(ev) => match ev {
                PduStub::RoomV1PduStub(ev) => &ev.sender,
                PduStub::RoomV3PduStub(ev) => &ev.sender,
            },
        }
    }

    pub fn redacts(&self) -> Option<&EventId> {
        match self {
            Self::Full(ev) => match ev {
                Pdu::RoomV1Pdu(ev) => ev.redacts.as_ref(),
                Pdu::RoomV3Pdu(ev) => ev.redacts.as_ref(),
            },
            Self::Sync(ev) => match ev {
                PduStub::RoomV1PduStub(ev) => ev.redacts.as_ref(),
                PduStub::RoomV3PduStub(ev) => ev.redacts.as_ref(),
            },
        }
    }

    pub fn room_id(&self) -> Option<&RoomId> {
        match self {
            Self::Full(ev) => match ev {
                Pdu::RoomV1Pdu(ev) => Some(&ev.room_id),
                Pdu::RoomV3Pdu(ev) => Some(&ev.room_id),
            },
            Self::Sync(_) => None,
        }
    }
    pub fn kind(&self) -> EventType {
        match self {
            Self::Full(ev) => match ev {
                Pdu::RoomV1Pdu(ev) => ev.kind.clone(),
                Pdu::RoomV3Pdu(ev) => ev.kind.clone(),
            },
            Self::Sync(ev) => match ev {
                PduStub::RoomV1PduStub(ev) => ev.kind.clone(),
                PduStub::RoomV3PduStub(ev) => ev.kind.clone(),
            },
        }
    }
    pub fn state_key(&self) -> Option<String> {
        match self {
            Self::Full(ev) => match ev {
                Pdu::RoomV1Pdu(ev) => ev.state_key.clone(),
                Pdu::RoomV3Pdu(ev) => ev.state_key.clone(),
            },
            Self::Sync(ev) => match ev {
                PduStub::RoomV1PduStub(ev) => ev.state_key.clone(),
                PduStub::RoomV3PduStub(ev) => ev.state_key.clone(),
            },
        }
    }
    pub fn origin(&self) -> String {
        match self {
            Self::Full(ev) => match ev {
                Pdu::RoomV1Pdu(ev) => ev.origin.clone(),
                Pdu::RoomV3Pdu(ev) => ev.origin.clone(),
            },
            Self::Sync(ev) => match ev {
                PduStub::RoomV1PduStub(ev) => ev.origin.clone(),
                PduStub::RoomV3PduStub(ev) => ev.origin.clone(),
            },
        }
    }

    pub fn prev_event_ids(&self) -> Vec<EventId> {
        match self {
            Self::Full(ev) => match ev {
                Pdu::RoomV1Pdu(ev) => ev.prev_events.iter().map(|(id, _)| id).cloned().collect(),
                Pdu::RoomV3Pdu(ev) => ev.prev_events.clone(),
            },
            Self::Sync(ev) => match ev {
                PduStub::RoomV1PduStub(ev) => {
                    ev.prev_events.iter().map(|(id, _)| id).cloned().collect()
                }
                PduStub::RoomV3PduStub(ev) => ev.prev_events.to_vec(),
            },
        }
    }

    pub fn auth_events(&self) -> Vec<EventId> {
        match self {
            Self::Full(ev) => match ev {
                Pdu::RoomV1Pdu(ev) => ev.auth_events.iter().map(|(id, _)| id).cloned().collect(),
                Pdu::RoomV3Pdu(ev) => ev.auth_events.to_vec(),
            },
            Self::Sync(ev) => match ev {
                PduStub::RoomV1PduStub(ev) => {
                    ev.auth_events.iter().map(|(id, _)| id).cloned().collect()
                }
                PduStub::RoomV3PduStub(ev) => ev.auth_events.to_vec(),
            },
        }
    }

    pub fn content(&self) -> &serde_json::Value {
        match self {
            Self::Full(ev) => match ev {
                Pdu::RoomV1Pdu(ev) => &ev.content,
                Pdu::RoomV3Pdu(ev) => &ev.content,
            },
            Self::Sync(ev) => match ev {
                PduStub::RoomV1PduStub(ev) => &ev.content,
                PduStub::RoomV3PduStub(ev) => &ev.content,
            },
        }
    }

    pub fn unsigned(&self) -> &BTreeMap<String, serde_json::Value> {
        // CONFIRM: The only way this would fail is if we got bad json, it should fail in ruma
        // before it fails here.
        match self {
            Self::Full(ev) => match ev {
                Pdu::RoomV1Pdu(ev) => &ev.unsigned,
                Pdu::RoomV3Pdu(ev) => &ev.unsigned,
            },
            Self::Sync(ev) => match ev {
                PduStub::RoomV1PduStub(ev) => &ev.unsigned,
                PduStub::RoomV3PduStub(ev) => &ev.unsigned,
            },
        }
    }

    pub fn signatures(&self) -> BTreeMap<Box<ServerName>, BTreeMap<ruma::ServerKeyId, String>> {
        match self {
            Self::Full(ev) => match ev {
                Pdu::RoomV1Pdu(_) => maplit::btreemap! {},
                Pdu::RoomV3Pdu(ev) => ev.signatures.clone(),
            },
            Self::Sync(ev) => match ev {
                PduStub::RoomV1PduStub(ev) => ev.signatures.clone(),
                PduStub::RoomV3PduStub(ev) => ev.signatures.clone(),
            },
        }
    }

    pub fn hashes(&self) -> &EventHash {
        match self {
            Self::Full(ev) => match ev {
                Pdu::RoomV1Pdu(ev) => &ev.hashes,
                Pdu::RoomV3Pdu(ev) => &ev.hashes,
            },
            Self::Sync(ev) => match ev {
                PduStub::RoomV1PduStub(ev) => &ev.hashes,
                PduStub::RoomV3PduStub(ev) => &ev.hashes,
            },
        }
    }

    pub fn is_type_and_key(&self, ev_type: EventType, state_key: &str) -> bool {
        match self {
            Self::Full(ev) => match ev {
                Pdu::RoomV1Pdu(ev) => {
                    ev.kind == ev_type && ev.state_key.as_deref() == Some(state_key)
                }
                Pdu::RoomV3Pdu(ev) => {
                    ev.kind == ev_type && ev.state_key.as_deref() == Some(state_key)
                }
            },
            Self::Sync(ev) => match ev {
                PduStub::RoomV1PduStub(ev) => {
                    ev.kind == ev_type && ev.state_key.as_deref() == Some(state_key)
                }
                PduStub::RoomV3PduStub(ev) => {
                    ev.kind == ev_type && ev.state_key.as_deref() == Some(state_key)
                }
            },
        }
    }
}

impl<'de> de::Deserialize<'de> for StateEvent {
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
    where
        D: de::Deserializer<'de>,
    {
        let json = Box::<RawJsonValue>::deserialize(deserializer)?;
        let EventDeHelper {
            room_id, unsigned, ..
        } = from_raw_json_value(&json)?;

        // Determine whether the event is a full or sync
        // based on the fields present.
        if room_id.is_some() {
            Ok(match unsigned {
                Some(unsigned) if unsigned.redacted_because.is_some() => {
                    panic!("TODO deal with redacted events")
                }
                _ => StateEvent::Full(Pdu::RoomV1Pdu(from_raw_json_value(&json)?)),
            })
        } else {
            Ok(match unsigned {
                Some(unsigned) if unsigned.redacted_because.is_some() => {
                    panic!("TODO deal with redacted events")
                }
                _ => StateEvent::Sync(from_raw_json_value(&json)?),
            })
        }
    }
}
<|endoftext|>