<commit_before>// Copyright (c) 2013-2016 Sandstorm Development Group, Inc. and contributors
// Licensed under the MIT License:
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

use std::rc::Rc;
use std::cell::RefCell;
use std::collections::HashMap;

use capnp_rpc::{RpcSystem, twoparty, rpc_twoparty_capnp};
use pubsub_capnp::{publisher, subscriber, handle};

use gj::{EventLoop, Promise, TaskReaper, TaskSet};

struct SubscriberMap {
    subscribers: HashMap<u64, subscriber::Client>,
}

impl SubscriberMap {
    fn new() -> SubscriberMap {
        SubscriberMap { subscribers: HashMap::new() }
    }
}

struct HandleImpl {
    id: u64,
    subscribers: Rc<RefCell<SubscriberMap>>,
}

impl HandleImpl {
    fn new(id: u64, subscribers: Rc<RefCell<SubscriberMap>>) -> HandleImpl {
        HandleImpl { id: id, subscribers: subscribers }
    }
}

impl Drop for HandleImpl {
    fn drop(&mut self) {
        self.subscribers.borrow_mut().subscribers.remove(&self.id);
    }
}

impl handle::Server for HandleImpl {}

struct PublisherImpl {
    next_id: u64,
    subscribers: Rc<RefCell<SubscriberMap>>,
}

impl PublisherImpl {
    pub fn new() -> (PublisherImpl, Rc<RefCell<SubscriberMap>>) {
        let subscribers = Rc::new(RefCell::new(SubscriberMap::new()));
        (PublisherImpl { next_id: 0, subscribers: subscribers.clone() },
         subscribers.clone())
    }
}

impl publisher::Server for PublisherImpl {
    fn register(&mut self,
                params: publisher::RegisterParams,
                mut results: publisher::RegisterResults,)
                -> Promise<(), ::capnp::Error>
    {
        println!("Register");
        self.subscribers.borrow_mut().subscribers.insert(self.next_id,
                                                         pry!(pry!(params.get()).get_subscriber()));

        results.get().set_handle(
            handle::ToClient::new(HandleImpl::new(self.next_id, self.subscribers.clone()))
                .from_server::<::capnp_rpc::Server>());

        self.next_id += 1;
        Promise::ok(())
    }
}

pub fn accept_loop(listener: ::gjio::SocketListener,
                   task_set: Rc<RefCell<TaskSet<(), Box<::std::error::Error>>>>,
                   publisher: publisher::Client)
                   -> Promise<(), ::std::io::Error>
{
    listener.accept().then(move |stream| {
        let mut network =
            twoparty::VatNetwork::new(stream.clone(), stream,
                                      rpc_twoparty_capnp::Side::Server, Default::default());
        let disconnect_promise = network.on_disconnect();

        let rpc_system = RpcSystem::new(Box::new(network), Some(publisher.clone().client));

        task_set.borrow_mut().add(disconnect_promise.attach(rpc_system).lift());
        accept_loop(listener, task_set, publisher)
    })
}

struct Reaper;

impl TaskReaper<(), Box<::std::error::Error>> for Reaper {
    fn task_failed(&mut self, error: Box<::std::error::Error>) {
        println!("Task failed: {}", error);
    }
}

fn send_to_subscribers(subscribers: Rc<RefCell<SubscriberMap>>,
                       timer: ::gjio::Timer,
                       task_set: Rc<RefCell<TaskSet<(), Box<::std::error::Error>>>>)
                       -> Promise<(), Box<::std::error::Error>>
{
    timer.after_delay(::std::time::Duration::new(1, 0)).lift().then(move |()| {
        {
            for (_, subscriber) in subscribers.borrow().subscribers.iter() {
                let mut request = subscriber.push_value_request();
                request.get().set_value(1.23);
                task_set.borrow_mut().add(request.send().promise.map(|_| Ok(())).lift());
            }
        }
        send_to_subscribers(subscribers, timer, task_set)
    })
}

pub fn main() {
    let args: Vec<String> = ::std::env::args().collect();
    if args.len() != 3 {
        println!("usage: {} server HOST:PORT", args[0]);
        return;
    }

    EventLoop::top_level(move |wait_scope| -> Result<(), Box<::std::error::Error>> {
        use std::net::ToSocketAddrs;
        let mut event_port = try!(::gjio::EventPort::new());
        let network = event_port.get_network();
        let addr = try!(args[2].to_socket_addrs()).next().expect("could not parse address");
        let mut address = network.get_tcp_address(addr);
        let listener = try!(address.listen());

        let (publisher_impl, subscribers) = PublisherImpl::new();

        let publisher = publisher::ToClient::new(publisher_impl).from_server::<::capnp_rpc::Server>();

        let task_set = Rc::new(RefCell::new(TaskSet::new(Box::new(Reaper))));

        let task_set_clone = task_set.clone();

        task_set.borrow_mut().add(send_to_subscribers(subscribers, event_port.get_timer(), task_set_clone));

        try!(accept_loop(listener, task_set, publisher).wait(wait_scope, &mut event_port));

        Ok(())
    }).expect("top level error");
}
<commit_msg>Better error type.<commit_after>// Copyright (c) 2013-2016 Sandstorm Development Group, Inc. and contributors
// Licensed under the MIT License:
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

use std::rc::Rc;
use std::cell::RefCell;
use std::collections::HashMap;

use capnp_rpc::{RpcSystem, twoparty, rpc_twoparty_capnp};
use pubsub_capnp::{publisher, subscriber, handle};

use gj::{EventLoop, Promise, TaskReaper, TaskSet};

struct SubscriberMap {
    subscribers: HashMap<u64, subscriber::Client>,
}

impl SubscriberMap {
    fn new() -> SubscriberMap {
        SubscriberMap { subscribers: HashMap::new() }
    }
}

struct HandleImpl {
    id: u64,
    subscribers: Rc<RefCell<SubscriberMap>>,
}

impl HandleImpl {
    fn new(id: u64, subscribers: Rc<RefCell<SubscriberMap>>) -> HandleImpl {
        HandleImpl { id: id, subscribers: subscribers }
    }
}

impl Drop for HandleImpl {
    fn drop(&mut self) {
        self.subscribers.borrow_mut().subscribers.remove(&self.id);
    }
}

impl handle::Server for HandleImpl {}

struct PublisherImpl {
    next_id: u64,
    subscribers: Rc<RefCell<SubscriberMap>>,
}

impl PublisherImpl {
    pub fn new() -> (PublisherImpl, Rc<RefCell<SubscriberMap>>) {
        let subscribers = Rc::new(RefCell::new(SubscriberMap::new()));
        (PublisherImpl { next_id: 0, subscribers: subscribers.clone() },
         subscribers.clone())
    }
}

impl publisher::Server for PublisherImpl {
    fn register(&mut self,
                params: publisher::RegisterParams,
                mut results: publisher::RegisterResults,)
                -> Promise<(), ::capnp::Error>
    {
        println!("Register");
        self.subscribers.borrow_mut().subscribers.insert(self.next_id,
                                                         pry!(pry!(params.get()).get_subscriber()));

        results.get().set_handle(
            handle::ToClient::new(HandleImpl::new(self.next_id, self.subscribers.clone()))
                .from_server::<::capnp_rpc::Server>());

        self.next_id += 1;
        Promise::ok(())
    }
}

pub fn accept_loop(listener: ::gjio::SocketListener,
                   task_set: Rc<RefCell<TaskSet<(), ::capnp::Error>>>,
                   publisher: publisher::Client)
                   -> Promise<(), ::std::io::Error>
{
    listener.accept().then(move |stream| {
        let mut network =
            twoparty::VatNetwork::new(stream.clone(), stream,
                                      rpc_twoparty_capnp::Side::Server, Default::default());
        let disconnect_promise = network.on_disconnect();

        let rpc_system = RpcSystem::new(Box::new(network), Some(publisher.clone().client));

        task_set.borrow_mut().add(disconnect_promise.attach(rpc_system));
        accept_loop(listener, task_set, publisher)
    })
}

struct Reaper;

impl TaskReaper<(), ::capnp::Error> for Reaper {
    fn task_failed(&mut self, error: ::capnp::Error) {
        println!("Task failed: {}", error);
    }
}

fn send_to_subscribers(subscribers: Rc<RefCell<SubscriberMap>>,
                       timer: ::gjio::Timer,
                       task_set: Rc<RefCell<TaskSet<(), ::capnp::Error>>>)
                       -> Promise<(), ::capnp::Error>
{
    timer.after_delay(::std::time::Duration::new(1, 0)).lift().then(move |()| {
        {
            for (_, subscriber) in subscribers.borrow().subscribers.iter() {
                let mut request = subscriber.push_value_request();
                request.get().set_value(1.23);
                task_set.borrow_mut().add(request.send().promise.map(|_| Ok(())));
            }
        }
        send_to_subscribers(subscribers, timer, task_set)
    })
}

pub fn main() {
    let args: Vec<String> = ::std::env::args().collect();
    if args.len() != 3 {
        println!("usage: {} server HOST:PORT", args[0]);
        return;
    }

    EventLoop::top_level(move |wait_scope| -> Result<(), Box<::std::error::Error>> {
        use std::net::ToSocketAddrs;
        let mut event_port = try!(::gjio::EventPort::new());
        let network = event_port.get_network();
        let addr = try!(args[2].to_socket_addrs()).next().expect("could not parse address");
        let mut address = network.get_tcp_address(addr);
        let listener = try!(address.listen());

        let (publisher_impl, subscribers) = PublisherImpl::new();

        let publisher = publisher::ToClient::new(publisher_impl).from_server::<::capnp_rpc::Server>();

        let task_set = Rc::new(RefCell::new(TaskSet::new(Box::new(Reaper))));

        let task_set_clone = task_set.clone();

        task_set.borrow_mut().add(send_to_subscribers(subscribers, event_port.get_timer(), task_set_clone));

        try!(accept_loop(listener, task_set, publisher).wait(wait_scope, &mut event_port));

        Ok(())
    }).expect("top level error");
}
<|endoftext|>


<commit_before>// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

#[license = "MIT/ASL2"];
#[crate_id = "github.com/DaGenix/rust-crypto#rust-crypto-util:0.1"];

#[allow(deprecated_owned_vector)];

extern crate getopts;
extern crate rust_crypto = "rust-crypto";

use std::io;
use std::os;
use std::slice;

use getopts::{optopt, optflag, getopts, Matches};

use rust_crypto::scrypt;

fn print_usage() {
    println!("Usage: rust-crypto-util <algorithm> [options]");
    println!("-h, --help\tUsage");
    println!("");
    println!("Algorithms:");
    println!(" * Scrypt (scrypt)");
    println!("");
    println!("Scrypt options:");
    println!("--logn\t\tThe Log N parameter");
    println!("-r\t\tThe R parameter");
    println!("-p\t\tThe P parameter");
    println!("--dklen\t\tThe DkLen parameter");
    println!("--rawsalt\tThe salt parameter is supplied on STDIN");
    println!("--rawpassword\tThe password parameter is supplied on STDIN");
    println!("--rawoutput\tThe resulting value should be output directly to STDOUT");
}

fn run_scrypt(matches: &Matches) {
    if !matches.opt_present("logn") || !matches.opt_present("r") || !matches.opt_present("p") ||
       !matches.opt_present("dklen") {
        print_usage();
        return;
    }
    let logn = from_str::<u8>(matches.opt_str("logn").unwrap()).unwrap();
    let r = from_str::<u32>(matches.opt_str("r").unwrap()).unwrap();
    let p = from_str::<u32>(matches.opt_str("p").unwrap()).unwrap();
    let dklen = from_str::<uint>(matches.opt_str("dklen").unwrap()).unwrap();

    if !matches.opt_present("rawsalt") || !matches.opt_present("rawpassword") ||
       !matches.opt_present("rawoutput") {
        println!("Required options missing.");
        return;
    }

    let salt_len = io::stdio::stdin_raw().read_be_u32().unwrap();
    let salt = io::stdio::stdin_raw().read_bytes(salt_len as uint).unwrap();
    let pass_len = io::stdio::stdin_raw().read_be_u32().unwrap();
    let pass = io::stdio::stdin_raw().read_bytes(pass_len as uint).unwrap();

    let params = scrypt::ScryptParams::new(logn, r, p);
    let mut output = slice::from_elem(dklen, 0u8);
    scrypt::scrypt(pass, salt, &params, output);

    match io::stdout().write(output) {
        Ok(_) => { },
        Err(_) => fail!("Error writing result")
    }
}

fn main() {
    let args = os::args();

    let opts = ~[
        // General parameters:
        optflag("h", "help", "Print help"),

        // Scrypt parameters:
        optopt("", "logn", "Log-N parameter for Scrypt", ""),
        optopt("r", "", "R parameter for Scrypt", ""),
        optopt("p", "", "P parameter for Scrypt", ""),
        optopt("", "dklen", "Length of the derived key", ""),
        optflag("", "rawsalt", "Use a raw salt value"),
        optflag("", "rawpassword", "Use a raw password value"),
        optflag("", "rawoutput", "Use raw output mode"),
    ];

    let matches = match getopts(args.tail(), opts) {
        Ok(m) => { m }
        Err(f) => { fail!(f.to_err_msg()) }
    };

    if matches.opt_present("h") || matches.opt_present("help") {
        print_usage();
        return;
    }

    if matches.free.is_empty() {
        print_usage();
        return;
    }
    let algorithm_name: &str = matches.free[0];

    match algorithm_name {
        "scrypt" => run_scrypt(&matches),
        _ => {
            print_usage();
            return;
        }
    }
}
<commit_msg>read_bytes() was renamed to read_exact()<commit_after>// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

#[license = "MIT/ASL2"];
#[crate_id = "github.com/DaGenix/rust-crypto#rust-crypto-util:0.1"];

#[allow(deprecated_owned_vector)];

extern crate getopts;
extern crate rust_crypto = "rust-crypto";

use std::io;
use std::os;
use std::slice;

use getopts::{optopt, optflag, getopts, Matches};

use rust_crypto::scrypt;

fn print_usage() {
    println!("Usage: rust-crypto-util <algorithm> [options]");
    println!("-h, --help\tUsage");
    println!("");
    println!("Algorithms:");
    println!(" * Scrypt (scrypt)");
    println!("");
    println!("Scrypt options:");
    println!("--logn\t\tThe Log N parameter");
    println!("-r\t\tThe R parameter");
    println!("-p\t\tThe P parameter");
    println!("--dklen\t\tThe DkLen parameter");
    println!("--rawsalt\tThe salt parameter is supplied on STDIN");
    println!("--rawpassword\tThe password parameter is supplied on STDIN");
    println!("--rawoutput\tThe resulting value should be output directly to STDOUT");
}

fn run_scrypt(matches: &Matches) {
    if !matches.opt_present("logn") || !matches.opt_present("r") || !matches.opt_present("p") ||
       !matches.opt_present("dklen") {
        print_usage();
        return;
    }
    let logn = from_str::<u8>(matches.opt_str("logn").unwrap()).unwrap();
    let r = from_str::<u32>(matches.opt_str("r").unwrap()).unwrap();
    let p = from_str::<u32>(matches.opt_str("p").unwrap()).unwrap();
    let dklen = from_str::<uint>(matches.opt_str("dklen").unwrap()).unwrap();

    if !matches.opt_present("rawsalt") || !matches.opt_present("rawpassword") ||
       !matches.opt_present("rawoutput") {
        println!("Required options missing.");
        return;
    }

    let salt_len = io::stdio::stdin_raw().read_be_u32().unwrap();
    let salt = io::stdio::stdin_raw().read_exact(salt_len as uint).unwrap();
    let pass_len = io::stdio::stdin_raw().read_be_u32().unwrap();
    let pass = io::stdio::stdin_raw().read_exact(pass_len as uint).unwrap();

    let params = scrypt::ScryptParams::new(logn, r, p);
    let mut output = slice::from_elem(dklen, 0u8);
    scrypt::scrypt(pass, salt, &params, output);

    match io::stdout().write(output) {
        Ok(_) => { },
        Err(_) => fail!("Error writing result")
    }
}

fn main() {
    let args = os::args();

    let opts = ~[
        // General parameters:
        optflag("h", "help", "Print help"),

        // Scrypt parameters:
        optopt("", "logn", "Log-N parameter for Scrypt", ""),
        optopt("r", "", "R parameter for Scrypt", ""),
        optopt("p", "", "P parameter for Scrypt", ""),
        optopt("", "dklen", "Length of the derived key", ""),
        optflag("", "rawsalt", "Use a raw salt value"),
        optflag("", "rawpassword", "Use a raw password value"),
        optflag("", "rawoutput", "Use raw output mode"),
    ];

    let matches = match getopts(args.tail(), opts) {
        Ok(m) => { m }
        Err(f) => { fail!(f.to_err_msg()) }
    };

    if matches.opt_present("h") || matches.opt_present("help") {
        print_usage();
        return;
    }

    if matches.free.is_empty() {
        print_usage();
        return;
    }
    let algorithm_name: &str = matches.free[0];

    match algorithm_name {
        "scrypt" => run_scrypt(&matches),
        _ => {
            print_usage();
            return;
        }
    }
}
<|endoftext|>


<commit_before>extern crate websocket;
extern crate futures;
extern crate futures_cpupool;
extern crate tokio_core;
extern crate serde;
extern crate serde_json;
#[macro_use]
extern crate serde_derive;

use websocket::message::OwnedMessage;
use websocket::server::InvalidConnection;
use websocket::async::Server;

use tokio_core::reactor::{Handle, Core};

use futures::{Future, Sink, Stream};
use futures::future::{self, Loop};
use futures::sync::mpsc;
use futures_cpupool::CpuPool;

use std::sync::{RwLock, Arc};
use std::thread;
use std::rc::Rc;
use std::fmt::Debug;
use std::time::Duration;
use std::ops::Deref;

fn main() {
    let mut core = Core::new().expect("Failed to create Tokio event loop");
    let handle = core.handle();
    let remote = core.remote();
    let server = Server::bind("localhost:8081", &handle).expect("Failed to create server");
    let pool = Rc::new(CpuPool::new_num_cpus());
    let connections = Arc::new(RwLock::new(Vec::new()));
    let state = Arc::new(RwLock::new(State::new()));
    let (read_channel_out, read_channel_in) = mpsc::unbounded();
    let handle_inner = handle.clone();
    let connections_inner = connections.clone();
    let connection_handler = server.incoming()
        // we don't wanna save the stream if it drops
        .map_err(|InvalidConnection { error, .. }| error)
        .for_each(move |(upgrade, addr)| {
            let connections = connections_inner.clone();
            println!("Got a connection from: {}", addr);
            if !upgrade.protocols().iter().any(|s| s == "rust-websocket") {
                spawn_future(upgrade.reject(), "Upgrade Rejection", &handle_inner);
                return Ok(());
            }
            let read_channel_out = read_channel_out.clone();
            let handle = handle_inner.clone();
            let f = upgrade
                .use_protocol("rust-websocket")
                .accept()
                .and_then(move |(framed, _)| {
                    let (sink, stream) = framed.split();
                    spawn_future(read_channel_out.send(stream), "Senk sink to connection pool", &handle);
                    connections.write().unwrap().push(Arc::new(RwLock::new(sink)));
                    Ok(())
                });
            spawn_future(f, "Handle new connection", &handle_inner);
            Ok(())
        })
        .map_err(|_| ());

    let state_read = state.clone();
    let remote_write = remote.clone();
    let read_handler = pool.spawn_fn(|| {
        read_channel_in.for_each(move |stream| {
            let state_read = state_read.clone();
            remote_write.spawn(|_| {
                stream.for_each(move |msg| {
                                    handle_incoming(&mut state_read.write().unwrap(), &msg);
                                    Ok(())
                                })
                    .map_err(|_| ())
            });
            Ok(())
        })
    });

    let (write_channel_out, write_channel_in) = futures::sync::mpsc::unbounded();

    type MessageCodec = websocket::async::MessageCodec<OwnedMessage>;
    type Framed = websocket::client::async::Framed<tokio_core::net::TcpStream, MessageCodec>;
    type SplitSink = futures::stream::SplitSink<Framed>;
    let write_handler = pool.spawn_fn(move || {
        write_channel_in.for_each(move |(sink, state): (Arc<RwLock<SplitSink>>,
                                                        Arc<RwLock<State>>)| {
                let msg = serde_json::to_string(state.read().unwrap().deref()).unwrap();
                println!("Sending message: {}", msg);
                sink.write()
                    .unwrap()
                    .start_send(OwnedMessage::Text(msg))
                    .unwrap();
                sink.write()
                    .unwrap()
                    .poll_complete()
                    .unwrap();
                Ok(())
            })
            .map_err(|_| ())
    });

    let game_loop = pool.spawn_fn(move || {
        future::loop_fn(write_channel_out, move |write_channel_out| {
            thread::sleep(Duration::from_millis(100));
            for conn in connections.write().unwrap().iter() {
                write_channel_out.clone()
                    .send((conn.clone(), state.clone()))
                    .wait()
                    .unwrap();
            }
            match 1 {
                1 => Ok(Loop::Continue(write_channel_out)),
                2 => Ok(Loop::Break(())),
                _ => Err(()),
            }
        })
    });

    let handlers =
        game_loop.select2(connection_handler.select2(read_handler.select(write_handler)));
    core.run(handlers).map_err(|_| println!("err")).unwrap();
}

fn spawn_future<F, I, E>(f: F, desc: &'static str, handle: &Handle)
    where F: Future<Item = I, Error = E> + 'static,
          E: Debug
{
    handle.spawn(f.map_err(move |e| println!("Error in {}: '{:?}'", desc, e))
                     .map(move |_| println!("{}: Finished.", desc)));
}

fn handle_incoming(_: &mut State, msg: &OwnedMessage) {
    if let OwnedMessage::Text(ref txt) = *msg {
        println!("Received message: {}", txt);
        //state.msg = txt.clone();
    }
}

#[derive(Serialize, Deserialize)]
struct State {
    positions: Vec<Pos>,
}

impl State {
    fn new() -> Self {
        Self { positions: Vec::new() }
    }
}

#[derive(Serialize, Deserialize)]
struct Pos {
    x: i32,
    y: i32,
}

/*
impl Pos {
    fn new(x: i32, y: i32) -> Self {
        Self { x, y }
    }

    fn add_x(&mut self, x: i32) -> &mut Self {
        self.x += x;
        self
    }

    fn add_y(&mut self, y: i32) -> &mut Self {
        self.y += y;
        self
    }

    fn add(&mut self, x: i32, y: i32) -> &mut Self {
        self.x += x;
        self.y += y;
        self
    }
}
*/
<commit_msg>Core: Run rustfmt<commit_after>extern crate websocket;
extern crate futures;
extern crate futures_cpupool;
extern crate tokio_core;
extern crate serde;
extern crate serde_json;
#[macro_use]
extern crate serde_derive;

use websocket::message::OwnedMessage;
use websocket::server::InvalidConnection;
use websocket::async::Server;

use tokio_core::reactor::{Handle, Core};

use futures::{Future, Sink, Stream};
use futures::future::{self, Loop};
use futures::sync::mpsc;
use futures_cpupool::CpuPool;

use std::sync::{RwLock, Arc};
use std::thread;
use std::rc::Rc;
use std::fmt::Debug;
use std::time::Duration;
use std::ops::Deref;

fn main() {
    let mut core = Core::new().expect("Failed to create Tokio event loop");
    let handle = core.handle();
    let remote = core.remote();
    let server = Server::bind("localhost:8081", &handle).expect("Failed to create server");
    let pool = Rc::new(CpuPool::new_num_cpus());
    let connections = Arc::new(RwLock::new(Vec::new()));
    let state = Arc::new(RwLock::new(State::new()));
    let (read_channel_out, read_channel_in) = mpsc::unbounded();
    let handle_inner = handle.clone();
    let connections_inner = connections.clone();
    let connection_handler = server.incoming()
        // we don't wanna save the stream if it drops
        .map_err(|InvalidConnection { error, .. }| error)
        .for_each(move |(upgrade, addr)| {
            let connections = connections_inner.clone();
            println!("Got a connection from: {}", addr);
            if !upgrade.protocols().iter().any(|s| s == "rust-websocket") {
                spawn_future(upgrade.reject(), "Upgrade Rejection", &handle_inner);
                return Ok(());
            }
            let read_channel_out = read_channel_out.clone();
            let handle = handle_inner.clone();
            let f = upgrade
                .use_protocol("rust-websocket")
                .accept()
                .and_then(move |(framed, _)| {
                    let (sink, stream) = framed.split();
                    let f = read_channel_out.send(stream);
                    spawn_future(f, "Senk sink to connection pool", &handle);
                    connections.write().unwrap().push(Arc::new(RwLock::new(sink)));
                    Ok(())
                });
            spawn_future(f, "Handle new connection", &handle_inner);
            Ok(())
        })
        .map_err(|_| ());

    let state_read = state.clone();
    let remote_write = remote.clone();
    let read_handler = pool.spawn_fn(|| {
        read_channel_in.for_each(move |stream| {
            let state_read = state_read.clone();
            remote_write.spawn(|_| {
                stream.for_each(move |msg| {
                                    handle_incoming(&mut state_read.write().unwrap(), &msg);
                                    Ok(())
                                })
                    .map_err(|_| ())
            });
            Ok(())
        })
    });

    let (write_channel_out, write_channel_in) = futures::sync::mpsc::unbounded();

    type MessageCodec = websocket::async::MessageCodec<OwnedMessage>;
    type Framed = websocket::client::async::Framed<tokio_core::net::TcpStream, MessageCodec>;
    type SplitSink = futures::stream::SplitSink<Framed>;
    let write_handler = pool.spawn_fn(move || {
        write_channel_in.for_each(move |(sink, state): (Arc<RwLock<SplitSink>>,
                                                        Arc<RwLock<State>>)| {
                let msg = serde_json::to_string(state.read().unwrap().deref()).unwrap();
                println!("Sending message: {}", msg);
                sink.write()
                    .unwrap()
                    .start_send(OwnedMessage::Text(msg))
                    .unwrap();
                sink.write()
                    .unwrap()
                    .poll_complete()
                    .unwrap();
                Ok(())
            })
            .map_err(|_| ())
    });

    let game_loop = pool.spawn_fn(move || {
        future::loop_fn(write_channel_out, move |write_channel_out| {
            thread::sleep(Duration::from_millis(100));
            for conn in connections.write().unwrap().iter() {
                write_channel_out.clone()
                    .send((conn.clone(), state.clone()))
                    .wait()
                    .unwrap();
            }
            match 1 {
                1 => Ok(Loop::Continue(write_channel_out)),
                2 => Ok(Loop::Break(())),
                _ => Err(()),
            }
        })
    });

    let handlers =
        game_loop.select2(connection_handler.select2(read_handler.select(write_handler)));
    core.run(handlers).map_err(|_| println!("err")).unwrap();
}

fn spawn_future<F, I, E>(f: F, desc: &'static str, handle: &Handle)
    where F: Future<Item = I, Error = E> + 'static,
          E: Debug
{
    handle.spawn(f.map_err(move |e| println!("Error in {}: '{:?}'", desc, e))
                     .map(move |_| println!("{}: Finished.", desc)));
}

fn handle_incoming(_: &mut State, msg: &OwnedMessage) {
    if let OwnedMessage::Text(ref txt) = *msg {
        println!("Received message: {}", txt);
        //state.msg = txt.clone();
    }
}

#[derive(Serialize, Deserialize)]
struct State {
    positions: Vec<Pos>,
}

impl State {
    fn new() -> Self {
        Self { positions: Vec::new() }
    }
}

#[derive(Serialize, Deserialize)]
struct Pos {
    x: i32,
    y: i32,
}

/*
impl Pos {
    fn new(x: i32, y: i32) -> Self {
        Self { x, y }
    }

    fn add_x(&mut self, x: i32) -> &mut Self {
        self.x += x;
        self
    }

    fn add_y(&mut self, y: i32) -> &mut Self {
        self.y += y;
        self
    }

    fn add(&mut self, x: i32, y: i32) -> &mut Self {
        self.x += x;
        self.y += y;
        self
    }
}
*/
<|endoftext|>


<commit_before>use rusqlite::Connection;
use std::result;

#[derive(Debug)]
pub struct WhenenvEnviroment {
    id: i32,
    fk_session: i32,
    fk_variable_name: i32,
}

pub fn table_create_enviroment(conn: &Connection) {
    conn.execute(
        "CREATE TABLE WHENENV_ENVIROMENT (
                  id                    INTEGER PRIMARY KEY ASC,
                  fk_session            INTEGER NOT NULL,
                  fk_variable_name           INTEGER NOT NULL,
                  FOREIGN KEY(fk_session) REFERENCES WHENENV_SESSION(id) ON UPDATE CASCADE
                  FOREIGN KEY(fk_variable_name) REFERENCES VARIABLE_NAME(id) ON UPDATE CASCADE
                  )",
        &[],
    ).unwrap();
}

pub fn insert_enviroment(
    conn: &Connection,
    job: &i32,
    variable: &i32,
) -> Result<i32, &'static str> {
    let me = WhenenvEnviroment {
        id: 0,
        fk_session: *job,
        fk_variable_name: *variable,
    };
    let enviroment_instance = conn.execute(
        "INSERT INTO WHENENV_ENVIROMENT (fk_session, fk_variable_name)
                  VALUES (?1, ?2)",
        &[&me.fk_session, &me.fk_variable_name],
    );
    if enviroment_instance.is_err() {
        return Err("Insert failed");
    }
    enviroment_instance.unwrap();
    return Ok(0);
}

pub fn list_enviroment(conn: &Connection) -> Vec<WhenenvEnviroment> {
    let mut stmt = conn.prepare(
        "SELECT id, fk_session, fk_variable_name  FROM WHENENV_ENVIROMENT",
    ).unwrap();
    let wraped_fs_file_iter = stmt.query_map(&[], |row| {
        WhenenvEnviroment {
            id: row.get(0),
            fk_session: row.get(1),
            fk_variable_name: row.get(2),
        }
    });
    let mut items = Vec::<WhenenvEnviroment>::new();
    if wraped_fs_file_iter.is_err() {
        return items;

    }
    let fs_file_iter = wraped_fs_file_iter.unwrap();
    for person in fs_file_iter {

        items.push(person.unwrap());
    }
    return items;
}

pub fn enviroment_list(conn: &Connection) {
    let mut stmt = conn.prepare(
        "SELECT id, fk_session, fk_variable_name  FROM WHENENV_ENVIROMENT",
    ).unwrap();
    let person_iter = stmt.query_map(&[], |row| {
        WhenenvEnviroment {
            id: row.get(0),
            fk_session: row.get(1),
            fk_variable_name: row.get(2),
        }
    }).unwrap();

    for person in person_iter {
        println!("Found enviroment {:?}", person.unwrap());
    }
}

pub fn pk_enviroment_by_name(
    conn: &Connection,
    job: &i32,
    variable: &i32,
    pk: &mut i32,
) -> Result<i32, &'static str> {
    let mut stmt = conn.prepare("SELECT id, fk_session, fk_variable_name  FROM WHENENV_ENVIROMENT WHERE fk_session = ?1 AND fk_variable_name = ?2").unwrap();
    let enviroment_iter = stmt.query_map(&[job, variable], |row| {
        WhenenvEnviroment {
            id: row.get(0),
            fk_session: row.get(1),
            fk_variable_name: row.get(2),
        }
    });
    if enviroment_iter.is_err() {
        return Err("Insert failed dfdf");
    }
    let result = enviroment_iter.unwrap();
    let mut found = 0;
    let mut items = Vec::<i32>::new();
    for person in result {
        let bill = person.unwrap();
        *pk = bill.id;
        found = 1;
    }
    if found != 0 {
        return Ok(found);
    }
    return Err("None found");
}
<commit_msg>Change Database schema to amke enviroment have value<commit_after>use rusqlite::Connection;
use std::result;

#[derive(Debug)]
pub struct WhenenvEnviroment {
    id: i32,
    fk_session: i32,
    fk_variable_pair: i32,
}

pub fn table_create_enviroment(conn: &Connection) {
    conn.execute(
        "CREATE TABLE WHENENV_ENVIROMENT (
                  id                    INTEGER PRIMARY KEY ASC,
                  fk_session            INTEGER NOT NULL,
                  fk_variable_pair           INTEGER NOT NULL,
                  FOREIGN KEY(fk_session) REFERENCES WHENENV_SESSION(id) ON UPDATE CASCADE
                  FOREIGN KEY(fk_variable_pair) REFERENCES VARIABLE_PAIR(id) ON UPDATE CASCADE
                  )",
        &[],
    ).unwrap();
}

pub fn insert_enviroment(
    conn: &Connection,
    job: &i32,
    variable: &i32,
) -> Result<i32, &'static str> {
    let me = WhenenvEnviroment {
        id: 0,
        fk_session: *job,
        fk_variable_pair: *variable,
    };
    let enviroment_instance = conn.execute(
        "INSERT INTO WHENENV_ENVIROMENT (fk_session, fk_variable_pair)
                  VALUES (?1, ?2)",
        &[&me.fk_session, &me.fk_variable_pair],
    );
    if enviroment_instance.is_err() {
        return Err("Insert failed");
    }
    enviroment_instance.unwrap();
    return Ok(0);
}

pub fn list_enviroment(conn: &Connection) -> Vec<WhenenvEnviroment> {
    let mut stmt = conn.prepare(
        "SELECT id, fk_session, fk_variable_pair  FROM WHENENV_ENVIROMENT",
    ).unwrap();
    let wraped_fs_file_iter = stmt.query_map(&[], |row| {
        WhenenvEnviroment {
            id: row.get(0),
            fk_session: row.get(1),
            fk_variable_pair: row.get(2),
        }
    });
    let mut items = Vec::<WhenenvEnviroment>::new();
    if wraped_fs_file_iter.is_err() {
        return items;

    }
    let fs_file_iter = wraped_fs_file_iter.unwrap();
    for person in fs_file_iter {

        items.push(person.unwrap());
    }
    return items;
}

pub fn enviroment_list(conn: &Connection) {
    let mut stmt = conn.prepare(
        "SELECT id, fk_session, fk_variable_pair  FROM WHENENV_ENVIROMENT",
    ).unwrap();
    let person_iter = stmt.query_map(&[], |row| {
        WhenenvEnviroment {
            id: row.get(0),
            fk_session: row.get(1),
            fk_variable_pair: row.get(2),
        }
    }).unwrap();

    for person in person_iter {
        println!("Found enviroment {:?}", person.unwrap());
    }
}

pub fn pk_enviroment_by_name(
    conn: &Connection,
    job: &i32,
    variable: &i32,
    pk: &mut i32,
) -> Result<i32, &'static str> {
    let mut stmt = conn.prepare("SELECT id, fk_session, fk_variable_pair  FROM WHENENV_ENVIROMENT WHERE fk_session = ?1 AND fk_variable_pair = ?2").unwrap();
    let enviroment_iter = stmt.query_map(&[job, variable], |row| {
        WhenenvEnviroment {
            id: row.get(0),
            fk_session: row.get(1),
            fk_variable_pair: row.get(2),
        }
    });
    if enviroment_iter.is_err() {
        return Err("Insert failed dfdf");
    }
    let result = enviroment_iter.unwrap();
    let mut found = 0;
    let mut items = Vec::<i32>::new();
    for person in result {
        let bill = person.unwrap();
        *pk = bill.id;
        found = 1;
    }
    if found != 0 {
        return Ok(found);
    }
    return Err("None found");
}
<|endoftext|>


<commit_before>//! Manages serial port state and communication with clients,
//! and handling requests / responses

use std::collections::HashSet;
use std::sync::mpsc::{Receiver, TryRecvError};
use std::thread;
use std::time::Duration;

use base64;

use errors::*;
use messages::*;
use sub_manager::*;
use port_manager::*;
use writelock_manager::*;
use common::*;

/// Serial port management module supporting one
/// writer and multiple readers
///
/// Clients can lock a port for writing, but
/// subscribe to data from multiple ports for reads
///
/// The Manager takes actions in response to
/// [SerialRequest::*](../messages/index.html) messages sent on
/// on its receiver
pub struct Manager {
  /// Manage write lock status
  writelock_manager: WriteLockManager,
  /// Manage ports
  port_manager: PortManager,
  /// Manage subscriptions
  sub_manager: SubscriptionManager,
  /// Receiver for serial requests
  receiver: Receiver<(String, SerialRequest)>,
  /// Receiver for response subscription requests
  subsc_receiver: SubscReceiver,
}

impl Manager {
  ///Constructor
  pub fn new(
    receiver: Receiver<(String, SerialRequest)>,
    subsc_receiver: SubscReceiver,
  ) -> Manager {
    Manager {
      writelock_manager: WriteLockManager::new(),
      port_manager: PortManager::new(),
      sub_manager: SubscriptionManager::new(),
      receiver: receiver,
      subsc_receiver: subsc_receiver,
    }
  }

  ///Spawn an instance in a new thread.
  pub fn spawn(
    receiver: Receiver<(String, SerialRequest)>,
    subsc_receiver: SubscReceiver,
  ) -> thread::JoinHandle<()> {
    thread::spawn(move || { Manager::new(receiver, subsc_receiver).run(); })
  }

  /// Main loop
  fn run(&mut self) {

    // Bad ports we couldn't read from
    // A set of SerialResponse::Errors built from
    // from the serial port read/write error responses
    let mut bad_ports = HashSet::<String>::new();
    // Shutdown flag
    let mut shutdown = false;
    // Check about 30 times a second
    let sleep_dur = Duration::from_millis(33);

    while !shutdown {
      // Sleep for a little bit to avoid pegging cpu
      // TODO Dynamic timing loop
      thread::sleep(sleep_dur);

      // Handle serial operation requests
      match self.receiver.try_recv() {
        Err(e) => {
          match e {
            TryRecvError::Empty => {
              // nothing to do
            }
            TryRecvError::Disconnected => {
              // Remote end hung up, time to shutdown
              info!("Shutting down SerialPortManager");
              shutdown = true;
            }
          }
        }
        Ok(req) => self.handle_serial_request(&req.0, req.1),
      }

      // Check for new data on each port
      for (port_name, result) in self.port_manager.read_all_ports() {
        match result {
          Ok(data) => {
            let response = match String::from_utf8(data) {
              // We need to send as binary
              Err(e) => {
                SerialResponse::Read {
                  port: port_name.to_string(),
                  data: base64::encode(&e.into_bytes()),
                  base64: Some(true),
                }
              }
              Ok(s) => {
                SerialResponse::Read {
                  port: port_name.to_string(),
                  data: s,
                  base64: Some(false),
                }
              }
            };
            self.broadcast_message_for_port(&port_name, response);
          }
          // Send data reads
          Err(e) => {
            warn!("Error reading port!");
            warn!("{}", e);
            bad_ports.insert(port_name);
          }
        }
      }

      //Handle write requests
      let mut recv_count = 0;
      let mut do_recv = true;
      while do_recv {
        recv_count += 1;
        match self.subsc_receiver.try_recv() {
          Ok(sub_request) => self.sub_manager.add_subscription(sub_request),
          Err(e) => {
            match e {
              TryRecvError::Disconnected => {
                // Does this mean all senders have disconnected?
                // Or just one?
                debug!("Got disconnected when trying to get serial request");
              }
              TryRecvError::Empty => do_recv = false,
            }
          }
        }

        // Don't let this loop get stuck here forever
        // starving the outer loop
        if recv_count == 50 {
          do_recv = false;
        }
      }

      // Cleanup bad serial ports that failed read or write
      // We remove them from everything before
      self.cleanup_bad_ports(&bad_ports);
      bad_ports.clear();
    }
  }

  /// Handles and dispatches SerialRequest sent by
  /// the channel
  fn handle_serial_request(&mut self, sub_id: &String, msg: SerialRequest) {
    let response = match msg {
      SerialRequest::Open { port } => self.handle_open_port(sub_id, port),
      SerialRequest::WriteLock { port } => self.handle_write_lock(sub_id, port),
      SerialRequest::ReleaseWriteLock { port } => self.handle_release_write_lock(sub_id, port),
      SerialRequest::Write { port, data, base64 } => {
        self.handle_write_port(sub_id, port, data, base64.unwrap_or(false))
      }
      SerialRequest::Close { port } => self.handle_close_port(sub_id, port),
      SerialRequest::List {} => self.handle_list_ports(sub_id),
    };
    if let Err(e) = response {
      warn!("Error '{}' occured handling serial request message", e);
      // Send error?
      self.send_message(&sub_id, to_serial_response_error(e));

    }
  }

  /// Handle write port requests
  fn handle_write_port(
    &mut self,
    sub_id: &String,
    port_name: String,
    data: String,
    base_64: bool,
  ) -> Result<()> {
    self.check_sub_id(&sub_id)?;
    self.check_owns_writelock(&port_name, &sub_id)?;
    match base_64 {
      true => {
        base64::decode(&data)
          .map_err(|e| ErrorKind::Base64(e).into())
          .and_then(|d| self.port_manager.write_port(&port_name, &d))
          .map(|_| self.send_message(&sub_id, SerialResponse::Wrote { port: port_name }),)
      }
      false => {
        self
          .port_manager
          .write_port(&port_name, data.as_bytes())
          .map(|_| self.send_message(&sub_id, SerialResponse::Wrote { port: port_name }),)
      }
    }
  }

  /// Handle write lock requests
  fn handle_write_lock(&mut self, sub_id: &String, port_name: String) -> Result<()> {
    self.check_sub_id(&sub_id)?;
    self
      .writelock_manager
      .lock_port(&port_name, &sub_id)
      .map(|_| self.send_message(&sub_id, SerialResponse::WriteLocked { port: port_name }),)
  }

  /// Handle write requests
  fn handle_release_write_lock(
    &mut self,
    sub_id: &String,
    port_name: Option<String>,
  ) -> Result<()> {
    self.check_sub_id(sub_id)?;
    match port_name {
      None => {
        self.writelock_manager.unlock_all_ports_for_sub(&sub_id);
        Ok(
          self.send_message(
            &sub_id,
            SerialResponse::WriteLockReleased { port: port_name },
          ),
        )
      }
      Some(port_name) => {
        self
          .writelock_manager
          .unlock_port(&port_name, &sub_id)
          .map(
            |_| {
              self.send_message(
                &sub_id,
                SerialResponse::WriteLockReleased { port: Some(port_name) },
              )
            },
          )
      }
    }
  }

  /// Handle open port requests
  fn handle_open_port(&mut self, sub_id: &String, port_name: String) -> Result<()> {
    self.check_sub_id(&sub_id)?;
    self.port_manager.open_port(&port_name)?;
    self
      .sub_manager
      .add_port(&sub_id, &port_name)
      .map(|_| self.send_message(&sub_id, SerialResponse::Opened { port: port_name }),)
  }

  /// Handle list ports request
  fn handle_list_ports(&mut self, sub_id: &String) -> Result<()> {
    self.check_sub_id(&sub_id)?;
    let port_names: Result<Vec<String>> =
      self
        .port_manager
        .list_ports()
        .map(|v| v.iter().map(|v| v.port_name.clone()).collect());
    let resp = port_names.map(|pns| SerialResponse::List { ports: pns });
    self.send_message(
      &sub_id,
      resp.unwrap_or(
        SerialResponse::Error {
          display: "".to_string(),
          description: "".to_string(),
        },
      ),
    );
    Ok(())
  }

  /// Handle close port requests
  /// FIXME: have this method delegate closing all ports
  /// for a sub to another method, will simplify final
  /// implementation and message sending.
  fn handle_close_port(&mut self, sub_id: &String, port_name: Option<String>) -> Result<()> {
    self.check_sub_id(&sub_id)?;
    // Unsubscribe from ports
    match port_name {
      None => {
        self.sub_manager.clear_ports(Some(&sub_id));
        Ok(())
      }
      Some(ref pn) => self.sub_manager.remove_port(&sub_id, &pn),
    }?;
    // Remove write locks
    match port_name {
      None => {
        self.writelock_manager.unlock_all_ports_for_sub(sub_id);
        Ok(())
      }
      Some(ref pn) => self.writelock_manager.unlock_port(&pn, sub_id),
    }?;
    // TODO: Ensure close messages are sent, etc

    // Close ports with no subscribers
    let open_ports = self.port_manager.open_ports();
    let subscribed_ports = self.sub_manager.subscribed_ports();
    let ports_with_no_subs = open_ports.difference(&subscribed_ports);

    // For each open port that isn't subscribed,
    for port_to_close in ports_with_no_subs {
      // close it
      self.port_manager.close_port(&port_to_close);
      // remove the write lock
      self.writelock_manager.clear_lock(&port_to_close);
      // Let them know its closed
      let close_resp = SerialResponse::Closed { port: port_to_close.clone() };
      self.send_message(&sub_id, close_resp);
    }
    Ok(())
  }

  /// Cleanup any bad ports
  fn cleanup_bad_ports(&mut self, bad_ports: &HashSet<String>) {
    for port_name in bad_ports.iter() {
      // Tell everyone port is sick
      let err_resp = to_serial_response_error(ErrorKind::PortReadError(port_name.to_owned()).into(),);
      self.broadcast_message_for_port(port_name, err_resp);
      // Tell everyone the sick ports were closed
      let close_resp = SerialResponse::Closed { port: port_name.clone() };
      self.broadcast_message_for_port(port_name, close_resp);
      // Close bad ports
      self.port_manager.close_port(port_name);
      // Remove write locks on bad ports
      self.writelock_manager.clear_lock(port_name);
      // Remove bad ports from subscriptions
      self.sub_manager.remove_port_from_all(port_name);
    }
  }

  fn send_message(&mut self, sub_id: &String, msg: SerialResponse) {
    if let Err(e) = self.sub_manager.send_message(sub_id, msg) {
      warn!("Error sending serial response to sub_id '{}'", sub_id);
      let mut bad_subs = Vec::new();
      bad_subs.push(e);
      self.cleanup_bad_subs(bad_subs);
    }
  }

  /// Broadcast a message to all subscribers and
  /// then cleanup any subs that errored
  fn broadcast_message(&mut self, msg: SerialResponse) {
    let bad_subs = self.sub_manager.broadcast_message(msg);
    self.cleanup_bad_subs(bad_subs);
  }

  /// Broadcast a message to all subscribers interested in the
  /// given port and then cleanup any subs that errored
  fn broadcast_message_for_port(&mut self, port_name: &String, msg: SerialResponse) {
    let bad_subs = self
      .sub_manager
      .broadcast_message_for_port(port_name, msg);
    self.cleanup_bad_subs(bad_subs);
  }

  /// Cleanup any bad subs where a message send failed
  fn cleanup_bad_subs(&mut self, bad_subs: Vec<Error>) {
    for e in bad_subs {
      if let Error(ErrorKind::SubscriberSendError(sub_id), _) = e {
        // Remove subscriptions
        self.sub_manager.end_subscription(&sub_id);
        // Remove all write locks held by dead subscription
        self.writelock_manager.unlock_all_ports_for_sub(&sub_id);
      }
    }
  }

  fn check_sub_id(&self, sub_id: &String) -> Result<()> {
    self.sub_manager.check_subscription_exists(sub_id)
  }

  fn check_owns_writelock(&self, port_name: &String, sub_id: &String) -> Result<()> {
    self
      .writelock_manager
      .check_owns_write_lock(port_name, sub_id)
  }
}
<commit_msg>Refactored close port message support<commit_after>//! Manages serial port state and communication with clients,
//! and handling requests / responses

use std::collections::HashSet;
use std::sync::mpsc::{Receiver, TryRecvError};
use std::thread;
use std::time::Duration;

use base64;

use errors::*;
use messages::*;
use sub_manager::*;
use port_manager::*;
use writelock_manager::*;
use common::*;

/// Serial port management module supporting one
/// writer and multiple readers
///
/// Clients can lock a port for writing, but
/// subscribe to data from multiple ports for reads
///
/// The Manager takes actions in response to
/// [SerialRequest::*](../messages/index.html) messages sent on
/// on its receiver
pub struct Manager {
  /// Manage write lock status
  writelock_manager: WriteLockManager,
  /// Manage ports
  port_manager: PortManager,
  /// Manage subscriptions
  sub_manager: SubscriptionManager,
  /// Receiver for serial requests
  receiver: Receiver<(String, SerialRequest)>,
  /// Receiver for response subscription requests
  subsc_receiver: SubscReceiver,
}

impl Manager {
  ///Constructor
  pub fn new(
    receiver: Receiver<(String, SerialRequest)>,
    subsc_receiver: SubscReceiver,
  ) -> Manager {
    Manager {
      writelock_manager: WriteLockManager::new(),
      port_manager: PortManager::new(),
      sub_manager: SubscriptionManager::new(),
      receiver: receiver,
      subsc_receiver: subsc_receiver,
    }
  }

  ///Spawn an instance in a new thread.
  pub fn spawn(
    receiver: Receiver<(String, SerialRequest)>,
    subsc_receiver: SubscReceiver,
  ) -> thread::JoinHandle<()> {
    thread::spawn(move || { Manager::new(receiver, subsc_receiver).run(); })
  }

  /// Main loop
  fn run(&mut self) {

    // Bad ports we couldn't read from
    // A set of SerialResponse::Errors built from
    // from the serial port read/write error responses
    let mut bad_ports = HashSet::<String>::new();
    // Shutdown flag
    let mut shutdown = false;
    // Check about 30 times a second
    let sleep_dur = Duration::from_millis(33);

    while !shutdown {
      // Sleep for a little bit to avoid pegging cpu
      // TODO Dynamic timing loop
      thread::sleep(sleep_dur);

      // Handle serial operation requests
      match self.receiver.try_recv() {
        Err(e) => {
          match e {
            TryRecvError::Empty => {
              // nothing to do
            }
            TryRecvError::Disconnected => {
              // Remote end hung up, time to shutdown
              info!("Shutting down SerialPortManager");
              shutdown = true;
            }
          }
        }
        Ok(req) => self.handle_serial_request(&req.0, req.1),
      }

      // Check for new data on each port
      for (port_name, result) in self.port_manager.read_all_ports() {
        match result {
          Ok(data) => {
            let response = match String::from_utf8(data) {
              // We need to send as binary
              Err(e) => {
                SerialResponse::Read {
                  port: port_name.to_string(),
                  data: base64::encode(&e.into_bytes()),
                  base64: Some(true),
                }
              }
              Ok(s) => {
                SerialResponse::Read {
                  port: port_name.to_string(),
                  data: s,
                  base64: Some(false),
                }
              }
            };
            self.broadcast_message_for_port(&port_name, response);
          }
          // Send data reads
          Err(e) => {
            warn!("Error reading port!");
            warn!("{}", e);
            bad_ports.insert(port_name);
          }
        }
      }

      //Handle write requests
      let mut recv_count = 0;
      let mut do_recv = true;
      while do_recv {
        recv_count += 1;
        match self.subsc_receiver.try_recv() {
          Ok(sub_request) => self.sub_manager.add_subscription(sub_request),
          Err(e) => {
            match e {
              TryRecvError::Disconnected => {
                // Does this mean all senders have disconnected?
                // Or just one?
                debug!("Got disconnected when trying to get serial request");
              }
              TryRecvError::Empty => do_recv = false,
            }
          }
        }

        // Don't let this loop get stuck here forever
        // starving the outer loop
        if recv_count == 50 {
          do_recv = false;
        }
      }

      // Cleanup bad serial ports that failed read or write
      // We remove them from everything before
      self.cleanup_bad_ports(&bad_ports);
      bad_ports.clear();
    }
  }

  /// Handles and dispatches SerialRequest sent by
  /// the channel
  fn handle_serial_request(&mut self, sub_id: &String, msg: SerialRequest) {
    let response = match msg {
      SerialRequest::Open { port } => self.handle_open_port(sub_id, port),
      SerialRequest::WriteLock { port } => self.handle_write_lock(sub_id, port),
      SerialRequest::ReleaseWriteLock { port } => self.handle_release_write_lock(sub_id, port),
      SerialRequest::Write { port, data, base64 } => {
        self.handle_write_port(sub_id, port, data, base64.unwrap_or(false))
      }
      SerialRequest::Close { port } => self.handle_close_port(sub_id, port),
      SerialRequest::List {} => self.handle_list_ports(sub_id),
    };
    if let Err(e) = response {
      warn!("Error '{}' occured handling serial request message", e);
      // Send error?
      self.send_message(&sub_id, to_serial_response_error(e));

    }
  }

  /// Handle write port requests
  fn handle_write_port(
    &mut self,
    sub_id: &String,
    port_name: String,
    data: String,
    base_64: bool,
  ) -> Result<()> {
    self.check_sub_id(&sub_id)?;
    self.check_owns_writelock(&port_name, &sub_id)?;
    match base_64 {
      true => {
        base64::decode(&data)
          .map_err(|e| ErrorKind::Base64(e).into())
          .and_then(|d| self.port_manager.write_port(&port_name, &d))
          .map(|_| self.send_message(&sub_id, SerialResponse::Wrote { port: port_name }),)
      }
      false => {
        self
          .port_manager
          .write_port(&port_name, data.as_bytes())
          .map(|_| self.send_message(&sub_id, SerialResponse::Wrote { port: port_name }),)
      }
    }
  }

  /// Handle write lock requests
  fn handle_write_lock(&mut self, sub_id: &String, port_name: String) -> Result<()> {
    self.check_sub_id(&sub_id)?;
    self
      .writelock_manager
      .lock_port(&port_name, &sub_id)
      .map(|_| self.send_message(&sub_id, SerialResponse::WriteLocked { port: port_name }),)
  }

  /// Handle write requests
  fn handle_release_write_lock(
    &mut self,
    sub_id: &String,
    port_name: Option<String>,
  ) -> Result<()> {
    self.check_sub_id(sub_id)?;
    match port_name {
      None => {
        self.writelock_manager.unlock_all_ports_for_sub(&sub_id);
        Ok(
          self.send_message(
            &sub_id,
            SerialResponse::WriteLockReleased { port: port_name },
          ),
        )
      }
      Some(port_name) => {
        self
          .writelock_manager
          .unlock_port(&port_name, &sub_id)
          .map(
            |_| {
              self.send_message(
                &sub_id,
                SerialResponse::WriteLockReleased { port: Some(port_name) },
              )
            },
          )
      }
    }
  }

  /// Handle open port requests
  fn handle_open_port(&mut self, sub_id: &String, port_name: String) -> Result<()> {
    self.check_sub_id(&sub_id)?;
    self.port_manager.open_port(&port_name)?;
    self
      .sub_manager
      .add_port(&sub_id, &port_name)
      .map(|_| self.send_message(&sub_id, SerialResponse::Opened { port: port_name }),)
  }

  /// Handle list ports request
  fn handle_list_ports(&mut self, sub_id: &String) -> Result<()> {
    self.check_sub_id(&sub_id)?;
    let port_names: Result<Vec<String>> =
      self
        .port_manager
        .list_ports()
        .map(|v| v.iter().map(|v| v.port_name.clone()).collect());
    let resp = port_names.map(|pns| SerialResponse::List { ports: pns });
    self.send_message(
      &sub_id,
      resp.unwrap_or(
        SerialResponse::Error {
          display: "".to_string(),
          description: "".to_string(),
        },
      ),
    );
    Ok(())
  }

  /// Handle close port requests
  fn handle_close_port(&mut self, sub_id: &String, port_name: Option<String>) -> Result<()> {
    match port_name {
      Some(port_name) => self.handle_close_port_for_sub(sub_id, port_name),
      None => self.handle_close_all_ports_for_sub(sub_id)
    }
  }

  /// Handle closing a signle port for a sub
  fn handle_close_port_for_sub(&mut self, sub_id: &String, port_name: String) -> Result<()> {
    self.sub_manager.remove_port(&sub_id, &port_name)?;
    self.writelock_manager.unlock_port_if_locked_by(&port_name, &sub_id);
    // self.cleanup_ports_with_no_subs();
    let close_resp = SerialResponse::Closed { port: port_name.clone() };
    self.send_message(&sub_id, close_resp);
    Ok(())
  }

  /// Handle closing all ports for sub
  fn handle_close_all_ports_for_sub(&mut self, sub_id: &String) -> Result<()> {
    self.sub_manager.clear_ports(Some(&sub_id));
    self.writelock_manager.unlock_all_ports_for_sub(sub_id);

    // Close ports with no subscribers
    let open_ports = self.port_manager.open_ports();
    let subscribed_ports = self.sub_manager.subscribed_ports();
    let ports_with_no_subs = open_ports.difference(&subscribed_ports);

    // For each open port that isn't subscribed,
    for port_to_close in ports_with_no_subs {
      // close it, REDUNDANT?
      self.port_manager.close_port(&port_to_close);
      // remove the write lock, REDUNDANT?
      self.writelock_manager.clear_lock(&port_to_close);
      // Let them know its closed
      let close_resp = SerialResponse::Closed { port: port_to_close.clone() };
      self.send_message(&sub_id, close_resp);
    }
    Ok(())
  }

  /// Cleanup any bad ports
  fn cleanup_bad_ports(&mut self, bad_ports: &HashSet<String>) {
    for port_name in bad_ports.iter() {
      // Tell everyone port is sick
      let err_resp = to_serial_response_error(ErrorKind::PortReadError(port_name.to_owned()).into(),);
      self.broadcast_message_for_port(port_name, err_resp);
      // Tell everyone the sick ports were closed
      let close_resp = SerialResponse::Closed { port: port_name.clone() };
      self.broadcast_message_for_port(port_name, close_resp);
      // Close bad ports
      self.port_manager.close_port(port_name);
      // Remove write locks on bad ports
      self.writelock_manager.clear_lock(port_name);
      // Remove bad ports from subscriptions
      self.sub_manager.remove_port_from_all(port_name);
    }
  }

  fn send_message(&mut self, sub_id: &String, msg: SerialResponse) {
    if let Err(e) = self.sub_manager.send_message(sub_id, msg) {
      warn!("Error sending serial response to sub_id '{}'", sub_id);
      let mut bad_subs = Vec::new();
      bad_subs.push(e);
      self.cleanup_bad_subs(bad_subs);
    }
  }

  /// Broadcast a message to all subscribers and
  /// then cleanup any subs that errored
  fn broadcast_message(&mut self, msg: SerialResponse) {
    let bad_subs = self.sub_manager.broadcast_message(msg);
    self.cleanup_bad_subs(bad_subs);
  }

  /// Broadcast a message to all subscribers interested in the
  /// given port and then cleanup any subs that errored
  fn broadcast_message_for_port(&mut self, port_name: &String, msg: SerialResponse) {
    let bad_subs = self
      .sub_manager
      .broadcast_message_for_port(port_name, msg);
    self.cleanup_bad_subs(bad_subs);
  }

  /// Cleanup any bad subs where a message send failed
  fn cleanup_bad_subs(&mut self, bad_subs: Vec<Error>) {
    for e in bad_subs {
      if let Error(ErrorKind::SubscriberSendError(sub_id), _) = e {
        // Remove subscriptions
        self.sub_manager.end_subscription(&sub_id);
        // Remove all write locks held by dead subscription
        self.writelock_manager.unlock_all_ports_for_sub(&sub_id);
      }
    }
  }

  fn check_sub_id(&self, sub_id: &String) -> Result<()> {
    self.sub_manager.check_subscription_exists(sub_id)
  }

  fn check_owns_writelock(&self, port_name: &String, sub_id: &String) -> Result<()> {
    self
      .writelock_manager
      .check_owns_write_lock(port_name, sub_id)
  }
}
<|endoftext|>


<commit_before>extern crate combine;
extern crate combine_language;
extern crate mnemosyne as core;

use combine::*;
use combine_language::{ LanguageEnv
                      , LanguageDef
                      , Identifier
                      };
use combine::primitives::{ Stream
                         , Positioner
                         , SourcePosition
                         };

use core::semantic::*;
use core::semantic::annotations::UnscopedState;
use core::position::*;

type ParseFn<'a, I, T> = fn (&LanguageEnv<'a, I>, State<I>)
                            -> ParseResult<T, I>;

/// Wraps a parsing function with a language definition environment.
///
/// TODO: this could probably push identifiers to the symbol table here?
#[derive(Copy)]
struct MnParser<'a: 'b, 'b, I, T>
where I: Stream<Item=char>
    , I::Range: 'b
    , I: 'b {
        env: &'b LanguageEnv<'a, I>
      , parser: ParseFn<'a, I, T>
}

impl<'a, 'b, I, T> Clone for MnParser<'a, 'b, I, T>
where I: Stream<Item=char>
    , I::Range: 'b
    , I: 'b
    , 'a: 'b {

    fn clone(&self) -> Self {
        MnParser { env: self.env , parser: self.parser }
    }
}

impl<'a, 'b, I, T> Parser for MnParser<'a, 'b, I, T>
where I: Stream<Item=char>
    , I::Range: 'b
    , I: 'b
    , 'a: 'b {

    type Input = I;
    type Output = T;

    fn parse_state(&mut self, input: State<I>) -> ParseResult<T, I> {
        (self.parser)(self.env, input)
    }

}

struct MnEnv<'a, I>
where I: Stream<Item = char>
    , I::Item: Positioner<Position = SourcePosition> {
    env: LanguageEnv<'a, I>
}

impl <'a, I> std::ops::Deref for MnEnv<'a, I>
where I: Stream<Item=char> {
    type Target = LanguageEnv<'a, I>;
    fn deref(&self) -> &LanguageEnv<'a, I> { &self.env }
}

impl<'a, 'b, I> MnEnv<'a, I>
where I: Stream<Item=char>
    , I::Item: Positioner<Position = SourcePosition>
    , I::Range: 'b {

        /// Wrap a function into a MnParser with this environment
        fn parser<T>(&'b self, parser: ParseFn<'a, I, T>)
                    -> MnParser<'a, 'b, I, T> {
            MnParser { env: self, parser: parser }
        }

}

fn def<'a, I>(env: &LanguageEnv<'a, I>,
              input: State<I>) -> ParseResult<ast::Form<'a, UnscopedState>, I>
where I: Stream<Item=char> {

    unimplemented!()
}

fn expr<'a, I>(env: &LanguageEnv<'a, I>, input: State<I>)
              -> ParseResult<ast::Expr<'a, UnscopedState>, I>
where I: Stream<Item=char> {
    // env.parens( choice([ form(
    //                     ])
    //           )
    //    .parse_state(input)
    unimplemented!()

}

pub fn parse_module<N: ?Sized>(code: &str) -> Result<Vec<N>, ParseError<&str>>
where N: ASTNode + Sized {
    let alpha_ext = "+-*/<=>!?:$%_~^";
    let ops = "+-*/|=<>";
    let env = LanguageEnv::new(LanguageDef {
        ident: Identifier {
            start: letter().or(satisfy(|c| alpha_ext.contains(c)))
          , rest: alpha_num().or(satisfy(|c| alpha_ext.contains(c)))
          , reserved: [ "and"               , "begin"
                      , "case"              , "cond"
                      , "data"              , "define"
                      , "defn"              , "delay"
                      , "do"                , "else"
                      , "if"                , "lambda"
                      , "let"               , "let*"
                      , "letrec"            , "or"
                      , "quasiquote"        , "quote"
                      , "set!"              , "unquote"
                      , "unquote-splicing"
                      ].iter().map(|x| (*x).into()).collect()
        }
      , op: Identifier {
            start: satisfy(|c| ops.contains(c))
          , rest:  satisfy(|c| ops.contains(c))
          , reserved: [ "=>", "->", "\\", "|"].iter().map(|x| (*x).into())
                                                     .collect()
        }
      , comment_line: string(";").map(|_| ())
      , comment_start: string("#|").map(|_| ())
      , comment_end: string("|#").map(|_| ())
    });

    env.white_space()
       .parse(code);

    unimplemented!()
}
<commit_msg>Start prototypes for parse functions<commit_after>extern crate combine;
extern crate combine_language;
extern crate mnemosyne as core;

use combine::*;
use combine_language::{ LanguageEnv
                      , LanguageDef
                      , Identifier
                      };
use combine::primitives::{ Stream
                         , Positioner
                         , SourcePosition
                         };

use core::semantic::*;
use core::semantic::annotations::UnscopedState;
use core::semantic::ast::*;
use core::position::*;

type ParseFn<'a, I, T> = fn (&LanguageEnv<'a, I>, State<I>)
                            -> ParseResult<T, I>;

type U = UnscopedState;

/// Wraps a parsing function with a language definition environment.
///
/// TODO: this could probably push identifiers to the symbol table here?
#[derive(Copy)]
struct MnParser<'a: 'b, 'b, I, T>
where I: Stream<Item=char>
    , I::Range: 'b
    , I: 'b {
        env: &'b LanguageEnv<'a, I>
      , parser: ParseFn<'a, I, T>
}

impl<'a, 'b, I, T> Clone for MnParser<'a, 'b, I, T>
where I: Stream<Item=char>
    , I::Range: 'b
    , I: 'b
    , 'a: 'b {

    fn clone(&self) -> Self {
        MnParser { env: self.env , parser: self.parser }
    }
}

impl<'a, 'b, I, T> Parser for MnParser<'a, 'b, I, T>
where I: Stream<Item=char>
    , I::Range: 'b
    , I: 'b
    , 'a: 'b {

    type Input = I;
    type Output = T;

    fn parse_state(&mut self, input: State<I>) -> ParseResult<T, I> {
        (self.parser)(self.env, input)
    }

}

struct MnEnv<'a, I>
where I: Stream<Item = char>
    , I::Item: Positioner<Position = SourcePosition> {
    env: LanguageEnv<'a, I>
}

impl <'a, I> std::ops::Deref for MnEnv<'a, I>
where I: Stream<Item=char> {
    type Target = LanguageEnv<'a, I>;
    fn deref(&self) -> &LanguageEnv<'a, I> { &self.env }
}

impl<'a, 'b, I> MnEnv<'a, I>
where I: Stream<Item=char>
    , I::Item: Positioner<Position = SourcePosition>
    , I::Range: 'b {

        /// Wrap a function into a MnParser with this environment
        fn parser<T>(&'b self, parser: ParseFn<'a, I, T>)
                    -> MnParser<'a, 'b, I, T> {
            MnParser { env: self, parser: parser }
        }

        fn parse_def(&self, input: State<I>) -> ParseResult<Form<'a, U>, I> {
            unimplemented!()
        }

        fn parse_expr(&self, input: State<I>) -> ParseResult<Expr<'a, U>, I> {
            unimplemented!()
        }

        fn expr(&'b self) -> MnParser<'a, 'b, I, Expr<'a, U>> {
            unimplemented!()
        }

        fn def(&'b self) -> MnParser<'a, 'b, I, Form<'a, U>> {
            unimplemented!()
        }
}
pub fn parse_module<N: ?Sized>(code: &str) -> Result<Vec<N>, ParseError<&str>>
where N: ASTNode + Sized {
    let alpha_ext = "+-*/<=>!?:$%_~^";
    let ops = "+-*/|=<>";
    let env = LanguageEnv::new(LanguageDef {
        ident: Identifier {
            start: letter().or(satisfy(|c| alpha_ext.contains(c)))
          , rest: alpha_num().or(satisfy(|c| alpha_ext.contains(c)))
          , reserved: [ "and"               , "begin"
                      , "case"              , "cond"
                      , "data"              , "define"
                      , "defn"              , "delay"
                      , "do"                , "else"
                      , "if"                , "lambda"
                      , "let"               , "let*"
                      , "letrec"            , "or"
                      , "quasiquote"        , "quote"
                      , "set!"              , "unquote"
                      , "unquote-splicing"
                      ].iter().map(|x| (*x).into()).collect()
        }
      , op: Identifier {
            start: satisfy(|c| ops.contains(c))
          , rest:  satisfy(|c| ops.contains(c))
          , reserved: [ "=>", "->", "\\", "|"].iter().map(|x| (*x).into())
                                                     .collect()
        }
      , comment_line: string(";").map(|_| ())
      , comment_start: string("#|").map(|_| ())
      , comment_end: string("|#").map(|_| ())
    });

    env.white_space()
       .parse(code);

    unimplemented!()
}
<|endoftext|>


<commit_before>// aux-build:issue-86620-1.rs

extern crate issue_86620_1;

use issue_86620_1::*;

// @!has issue_86620/struct.S.html '//div[@id="method.vzip"]//a[@class="fnname"]/@href' #tymethod.vzip
pub struct S;
<commit_msg>add check on anchor link<commit_after>// aux-build:issue-86620-1.rs

extern crate issue_86620_1;

use issue_86620_1::*;

// @!has issue_86620/struct.S.html '//div[@id="method.vzip"]//a[@class="fnname"]/@href' #tymethod.vzip
// @has issue_86620/struct.S.html '//div[@id="method.vzip"]//a[@class="anchor"]/@href' #method.vzip
pub struct S;
<|endoftext|>


<commit_before>use jsonpath_lib::select;
use lazy_static::lazy_static;
use regex::{Regex, RegexBuilder};
use serde_json::Value;
use std::borrow::Cow;
use std::{env, fmt, fs};

mod cache;
mod config;
mod error;

use cache::Cache;
use config::parse_config;
use error::CkError;

fn main() -> Result<(), String> {
    let config = parse_config(env::args().collect());

    let mut failed = Vec::new();
    let mut cache = Cache::new(&config.doc_dir);
    let commands = get_commands(&config.template)
        .map_err(|_| format!("Jsondocck failed for {}", &config.template))?;

    for command in commands {
        if let Err(e) = check_command(command, &mut cache) {
            failed.push(e);
        }
    }

    if failed.is_empty() {
        Ok(())
    } else {
        for i in failed {
            eprintln!("{}", i);
        }
        Err(format!("Jsondocck failed for {}", &config.template))
    }
}

#[derive(Debug)]
pub struct Command {
    negated: bool,
    kind: CommandKind,
    args: Vec<String>,
    lineno: usize,
}

#[derive(Debug)]
pub enum CommandKind {
    Has,
    Count,
    Is,
    Set,
}

impl CommandKind {
    fn validate(&self, args: &[String], command_num: usize, lineno: usize) -> bool {
        let count = match self {
            CommandKind::Has => (1..=3).contains(&args.len()),
            CommandKind::Count | CommandKind::Is => 3 == args.len(),
            CommandKind::Set => 4 == args.len(),
        };

        if !count {
            print_err(&format!("Incorrect number of arguments to `@{}`", self), lineno);
            return false;
        }

        if args[0] == "-" && command_num == 0 {
            print_err(&format!("Tried to use the previous path in the first command"), lineno);
            return false;
        }

        if let CommandKind::Count = self {
            if args[2].parse::<usize>().is_err() {
                print_err(&format!("Third argument to @count must be a valid usize"), lineno);
                return false;
            }
        }

        true
    }
}

impl fmt::Display for CommandKind {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        let text = match self {
            CommandKind::Has => "has",
            CommandKind::Count => "count",
            CommandKind::Is => "is",
            CommandKind::Set => "set",
        };
        write!(f, "{}", text)
    }
}

lazy_static! {
    static ref LINE_PATTERN: Regex = RegexBuilder::new(
        r#"
        \s(?P<invalid>!?)@(?P<negated>!?)
        (?P<cmd>[A-Za-z]+(?:-[A-Za-z]+)*)
        (?P<args>.*)$
    "#
    )
    .ignore_whitespace(true)
    .unicode(true)
    .build()
    .unwrap();
}

fn print_err(msg: &str, lineno: usize) {
    eprintln!("Invalid command: {} on line {}", msg, lineno)
}

/// Get a list of commands from a file. Does the work of ensuring the commands
/// are syntactically valid.
fn get_commands(template: &str) -> Result<Vec<Command>, ()> {
    let mut commands = Vec::new();
    let mut errors = false;
    let file = fs::read_to_string(template).unwrap();

    for (lineno, line) in file.split('\n').enumerate() {
        let lineno = lineno + 1;

        let cap = match LINE_PATTERN.captures(line) {
            Some(c) => c,
            None => continue,
        };

        let negated = cap.name("negated").unwrap().as_str() == "!";
        let cmd = cap.name("cmd").unwrap().as_str();

        let cmd = match cmd {
            "has" => CommandKind::Has,
            "count" => CommandKind::Count,
            "is" => CommandKind::Is,
            "set" => CommandKind::Set,
            _ => {
                print_err(&format!("Unrecognized command name `@{}`", cmd), lineno);
                errors = true;
                continue;
            }
        };

        if let Some(m) = cap.name("invalid") {
            if m.as_str() == "!" {
                print_err(
                    &format!(
                        "`!@{0}{1}`, (help: try with `@!{1}`)",
                        if negated { "!" } else { "" },
                        cmd,
                    ),
                    lineno,
                );
                errors = true;
                continue;
            }
        }

        let args = cap.name("args").map_or(Some(vec![]), |m| shlex::split(m.as_str()));

        let args = match args {
            Some(args) => args,
            None => {
                print_err(
                    &format!(
                        "Invalid arguments to shlex::split: `{}`",
                        cap.name("args").unwrap().as_str()
                    ),
                    lineno,
                );
                errors = true;
                continue;
            }
        };

        if !cmd.validate(&args, commands.len(), lineno) {
            errors = true;
            continue;
        }

        commands.push(Command { negated, kind: cmd, args, lineno })
    }

    if !errors { Ok(commands) } else { Err(()) }
}

/// Performs the actual work of ensuring a command passes. Generally assumes the command
/// is syntactically valid.
fn check_command(command: Command, cache: &mut Cache) -> Result<(), CkError> {
    // FIXME: Be more granular about why, (e.g. syntax error, count not equal)
    let result = match command.kind {
        CommandKind::Has => {
            match command.args.len() {
                // @has <path> = file existence
                1 => cache.get_file(&command.args[0]).is_ok(),
                // @has <path> <jsonpath> = check path exists
                2 => {
                    let val = cache.get_value(&command.args[0])?;
                    let results = select(&val, &command.args[1]).unwrap();
                    !results.is_empty()
                }
                // @has <path> <jsonpath> <value> = check *any* item matched by path equals value
                3 => {
                    let val = cache.get_value(&command.args[0])?;
                    let results = select(&val, &command.args[1]).unwrap();
                    let pat = string_to_value(&command.args[2], cache);
                    results.contains(&pat.as_ref())
                }
                _ => unreachable!(),
            }
        }
        CommandKind::Count => {
            // @count <path> <jsonpath> <count> = Check that the jsonpath matches exactly [count] times
            assert_eq!(command.args.len(), 3);
            let expected: usize = command.args[2].parse().unwrap();

            let val = cache.get_value(&command.args[0])?;
            let results = select(&val, &command.args[1]).unwrap();
            results.len() == expected
        }
        CommandKind::Is => {
            // @has <path> <jsonpath> <value> = check *exactly one* item matched by path, and it equals value
            assert_eq!(command.args.len(), 3);
            let val = cache.get_value(&command.args[0])?;
            let results = select(&val, &command.args[1]).unwrap();
            let pat = string_to_value(&command.args[2], cache);
            results.len() == 1 && results[0] == pat.as_ref()
        }
        CommandKind::Set => {
            // @set <name> = <path> <jsonpath>
            assert_eq!(command.args.len(), 4);
            assert_eq!(command.args[1], "=", "Expected an `=`");
            let val = cache.get_value(&command.args[2])?;
            let results = select(&val, &command.args[3]).unwrap();
            assert_eq!(results.len(), 1);
            match results.len() {
                0 => false,
                1 => {
                    let r = cache.variables.insert(command.args[0].clone(), results[0].clone());
                    assert!(r.is_none(), "Name collision: {} is duplicated", command.args[0]);
                    true
                }
                _ => {
                    panic!(
                        "Got multiple results in `@set` for `{}`: {:?}",
                        &command.args[3], results
                    );
                }
            }
        }
    };

    if result == command.negated {
        if command.negated {
            Err(CkError::FailedCheck(
                format!(
                    "`@!{} {}` matched when it shouldn't",
                    command.kind,
                    command.args.join(" ")
                ),
                command,
            ))
        } else {
            // FIXME: In the future, try 'peeling back' each step, and see at what level the match failed
            Err(CkError::FailedCheck(
                format!(
                    "`@{} {}` didn't match when it should",
                    command.kind,
                    command.args.join(" ")
                ),
                command,
            ))
        }
    } else {
        Ok(())
    }
}

fn string_to_value<'a>(s: &str, cache: &'a Cache) -> Cow<'a, Value> {
    if s.starts_with("$") {
        Cow::Borrowed(&cache.variables[&s[1..]])
    } else {
        Cow::Owned(serde_json::from_str(s).unwrap())
    }
}
<commit_msg>Improve some jsondocck errors<commit_after>use jsonpath_lib::select;
use lazy_static::lazy_static;
use regex::{Regex, RegexBuilder};
use serde_json::Value;
use std::borrow::Cow;
use std::{env, fmt, fs};

mod cache;
mod config;
mod error;

use cache::Cache;
use config::parse_config;
use error::CkError;

fn main() -> Result<(), String> {
    let config = parse_config(env::args().collect());

    let mut failed = Vec::new();
    let mut cache = Cache::new(&config.doc_dir);
    let commands = get_commands(&config.template)
        .map_err(|_| format!("Jsondocck failed for {}", &config.template))?;

    for command in commands {
        if let Err(e) = check_command(command, &mut cache) {
            failed.push(e);
        }
    }

    if failed.is_empty() {
        Ok(())
    } else {
        for i in failed {
            eprintln!("{}", i);
        }
        Err(format!("Jsondocck failed for {}", &config.template))
    }
}

#[derive(Debug)]
pub struct Command {
    negated: bool,
    kind: CommandKind,
    args: Vec<String>,
    lineno: usize,
}

#[derive(Debug)]
pub enum CommandKind {
    Has,
    Count,
    Is,
    Set,
}

impl CommandKind {
    fn validate(&self, args: &[String], command_num: usize, lineno: usize) -> bool {
        let count = match self {
            CommandKind::Has => (1..=3).contains(&args.len()),
            CommandKind::Count | CommandKind::Is => 3 == args.len(),
            CommandKind::Set => 4 == args.len(),
        };

        if !count {
            print_err(&format!("Incorrect number of arguments to `@{}`", self), lineno);
            return false;
        }

        if args[0] == "-" && command_num == 0 {
            print_err(&format!("Tried to use the previous path in the first command"), lineno);
            return false;
        }

        if let CommandKind::Count = self {
            if args[2].parse::<usize>().is_err() {
                print_err(&format!("Third argument to @count must be a valid usize"), lineno);
                return false;
            }
        }

        true
    }
}

impl fmt::Display for CommandKind {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        let text = match self {
            CommandKind::Has => "has",
            CommandKind::Count => "count",
            CommandKind::Is => "is",
            CommandKind::Set => "set",
        };
        write!(f, "{}", text)
    }
}

lazy_static! {
    static ref LINE_PATTERN: Regex = RegexBuilder::new(
        r#"
        \s(?P<invalid>!?)@(?P<negated>!?)
        (?P<cmd>[A-Za-z]+(?:-[A-Za-z]+)*)
        (?P<args>.*)$
    "#
    )
    .ignore_whitespace(true)
    .unicode(true)
    .build()
    .unwrap();
}

fn print_err(msg: &str, lineno: usize) {
    eprintln!("Invalid command: {} on line {}", msg, lineno)
}

/// Get a list of commands from a file. Does the work of ensuring the commands
/// are syntactically valid.
fn get_commands(template: &str) -> Result<Vec<Command>, ()> {
    let mut commands = Vec::new();
    let mut errors = false;
    let file = fs::read_to_string(template).unwrap();

    for (lineno, line) in file.split('\n').enumerate() {
        let lineno = lineno + 1;

        let cap = match LINE_PATTERN.captures(line) {
            Some(c) => c,
            None => continue,
        };

        let negated = cap.name("negated").unwrap().as_str() == "!";
        let cmd = cap.name("cmd").unwrap().as_str();

        let cmd = match cmd {
            "has" => CommandKind::Has,
            "count" => CommandKind::Count,
            "is" => CommandKind::Is,
            "set" => CommandKind::Set,
            _ => {
                print_err(&format!("Unrecognized command name `@{}`", cmd), lineno);
                errors = true;
                continue;
            }
        };

        if let Some(m) = cap.name("invalid") {
            if m.as_str() == "!" {
                print_err(
                    &format!(
                        "`!@{0}{1}`, (help: try with `@!{1}`)",
                        if negated { "!" } else { "" },
                        cmd,
                    ),
                    lineno,
                );
                errors = true;
                continue;
            }
        }

        let args = cap.name("args").map_or(Some(vec![]), |m| shlex::split(m.as_str()));

        let args = match args {
            Some(args) => args,
            None => {
                print_err(
                    &format!(
                        "Invalid arguments to shlex::split: `{}`",
                        cap.name("args").unwrap().as_str()
                    ),
                    lineno,
                );
                errors = true;
                continue;
            }
        };

        if !cmd.validate(&args, commands.len(), lineno) {
            errors = true;
            continue;
        }

        commands.push(Command { negated, kind: cmd, args, lineno })
    }

    if !errors { Ok(commands) } else { Err(()) }
}

/// Performs the actual work of ensuring a command passes. Generally assumes the command
/// is syntactically valid.
fn check_command(command: Command, cache: &mut Cache) -> Result<(), CkError> {
    // FIXME: Be more granular about why, (e.g. syntax error, count not equal)
    let result = match command.kind {
        CommandKind::Has => {
            match command.args.len() {
                // @has <path> = file existence
                1 => cache.get_file(&command.args[0]).is_ok(),
                // @has <path> <jsonpath> = check path exists
                2 => {
                    let val = cache.get_value(&command.args[0])?;
                    let results = select(&val, &command.args[1]).unwrap();
                    !results.is_empty()
                }
                // @has <path> <jsonpath> <value> = check *any* item matched by path equals value
                3 => {
                    let val = cache.get_value(&command.args[0])?;
                    let results = select(&val, &command.args[1]).unwrap();
                    let pat = string_to_value(&command.args[2], cache);
                    let has = results.contains(&pat.as_ref());
                    // Give better error for when @has check fails
                    if !command.negated && !has {
                        return Err(CkError::FailedCheck(
                            format!(
                                "{} matched to {:?} but didn't have {:?}",
                                &command.args[1],
                                results,
                                pat.as_ref()
                            ),
                            command,
                        ));
                    } else {
                        has
                    }
                }
                _ => unreachable!(),
            }
        }
        CommandKind::Count => {
            // @count <path> <jsonpath> <count> = Check that the jsonpath matches exactly [count] times
            assert_eq!(command.args.len(), 3);
            let expected: usize = command.args[2].parse().unwrap();

            let val = cache.get_value(&command.args[0])?;
            let results = select(&val, &command.args[1]).unwrap();
            results.len() == expected
        }
        CommandKind::Is => {
            // @has <path> <jsonpath> <value> = check *exactly one* item matched by path, and it equals value
            assert_eq!(command.args.len(), 3);
            let val = cache.get_value(&command.args[0])?;
            let results = select(&val, &command.args[1]).unwrap();
            let pat = string_to_value(&command.args[2], cache);
            results.len() == 1 && results[0] == pat.as_ref()
        }
        CommandKind::Set => {
            // @set <name> = <path> <jsonpath>
            assert_eq!(command.args.len(), 4);
            assert_eq!(command.args[1], "=", "Expected an `=`");
            let val = cache.get_value(&command.args[2])?;
            let results = select(&val, &command.args[3]).unwrap();
            assert_eq!(
                results.len(),
                1,
                "Didn't get 1 result for `{}`: got {:?}",
                command.args[3],
                results
            );
            match results.len() {
                0 => false,
                1 => {
                    let r = cache.variables.insert(command.args[0].clone(), results[0].clone());
                    assert!(r.is_none(), "Name collision: {} is duplicated", command.args[0]);
                    true
                }
                _ => {
                    panic!(
                        "Got multiple results in `@set` for `{}`: {:?}",
                        &command.args[3], results
                    );
                }
            }
        }
    };

    if result == command.negated {
        if command.negated {
            Err(CkError::FailedCheck(
                format!(
                    "`@!{} {}` matched when it shouldn't",
                    command.kind,
                    command.args.join(" ")
                ),
                command,
            ))
        } else {
            // FIXME: In the future, try 'peeling back' each step, and see at what level the match failed
            Err(CkError::FailedCheck(
                format!(
                    "`@{} {}` didn't match when it should",
                    command.kind,
                    command.args.join(" ")
                ),
                command,
            ))
        }
    } else {
        Ok(())
    }
}

fn string_to_value<'a>(s: &str, cache: &'a Cache) -> Cow<'a, Value> {
    if s.starts_with("$") {
        Cow::Borrowed(&cache.variables[&s[1..]])
    } else {
        Cow::Owned(serde_json::from_str(s).unwrap())
    }
}
<|endoftext|>