<commit_before>use chrono::DateTime;
use chrono::offset::Utc;
use diesel;
use diesel::prelude::*;
use diesel::pg::PgConnection;
use diesel::pg::upsert::*;
use futures::{Future, stream, Stream};
use futures_cpupool::CpuPool;
use hyper::{Body, Client, Uri};
use hyper::client::HttpConnector;
use hyper_tls::HttpsConnector;
use InsertError;
use kuchiki;
use kuchiki::traits::*;
use r2d2_diesel::ConnectionManager;
use r2d2::Pool;
use rusoto_core::{default_tls_client, Region};
use rusoto_credential::ProfileProvider;
use rusoto_s3::{PutObjectRequest, S3Client, S3};
use schema::ads;
use server::AdPost;

#[derive(Queryable, Debug, Clone)]
pub struct Ad {
    id: String,
    html: String,
    political: i32,
    not_political: i32,

    fuzzy_id: Option<i32>,
    title: String,
    message: String,
    thumbnail: String,

    created_at: DateTime<Utc>,
    updated_at: DateTime<Utc>,

    browser_lang: String,

    images: Vec<String>,
}

#[derive(AsChangeset)]
#[table_name = "ads"]
pub struct Images {
    thumbnail: Option<String>,
    images: Vec<String>,
}

impl Ad {
    // This will asynchronously save the images to s3 we may very well end up
    // with broken images. but I can't see any way around it right now.  Also we
    // should think about splitting this up, but I'm fine -- if a little
    // embarassed about it right now. This function swallows errors, and there's
    // a chance we'll end up with no images at the end, but I think we can
    // handle that in the extension's UI.
    pub fn grab_and_store(
        &self,
        client: Client<HttpsConnector<HttpConnector>, Body>,
        db: &Pool<ConnectionManager<PgConnection>>,
        pool: CpuPool,
    ) -> Box<Future<Item = (), Error = ()>> {
        let ad = self.clone();
        let pool_s3 = pool.clone();
        let pool_db = pool.clone();
        let db = db.clone();

        let images = [vec![self.thumbnail.clone()], self.images.clone()];
        let urls = images
            .concat()
            .iter()
            .map(|a| {
                let a: Uri = a.parse().map_err(InsertError::Uri)?;
                Ok(a)
            })
            .collect::<Vec<Result<Uri, InsertError>>>();
        let future = stream::iter(urls)
            // filter ones we already have in the db and ones we can verify as
            // coming from fb, we don't want to become a malware vector :)
            .filter(|u| match u.host() {
                Some(h) => h != "pp-facebook-ads.s3.amazonaws.com" || !h.ends_with("fbcdn.net"),
                None => false
            })
            // grab image
            .and_then(move |img| {
                info!("getting {:?}", img);
                let cloned = img.clone();
                client
                    .get(img)
                    .and_then(|res| {
                        res.body().concat2().and_then(|chunk| Ok((chunk, cloned)))
                    })
                    .map_err(InsertError::Hyper)
            })
            // upload them to s3
            .and_then(move |tuple| {
                let pool = pool_s3.clone();
                // we do this in a worker thread because rusoto isn't on
                // Hyper async yet.
                pool.spawn_fn(move || {
                    let client =
                        S3Client::new(default_tls_client().map_err(InsertError::TLS)?,
                                      ProfileProvider::new().map_err(InsertError::AWS)?,
                                      Region::UsEast1);
                    let req = PutObjectRequest {
                        bucket: "pp-facebook-ads".to_string(),
                        key: tuple.1.path().trim_left_matches("/").to_string(),
                        acl: Some("public-read".to_string()),
                        body: Some(tuple.0.to_vec()),
                        ..PutObjectRequest::default()
                    };

                    client.put_object(&req).map_err(InsertError::S3)?;
                    Ok(tuple.1)
                })
            })
            .map_err(|e| {
                warn!("{:?}", e);
                ()
            })
            .collect()
            // save the new urls to the database. the images variable will
            // include only those that we've successfully saved to s3, so we
            // have to do a funky merge here.
            .and_then(move |images| {
                let imgs = images.clone();
                pool_db.spawn_fn(move || {
                    use schema::ads::dsl::*;
                    let thumb = imgs
                        .iter()
                        .filter(|i| ad.thumbnail.contains(i.path()))
                        .map(|i| "https://pp-facebook-ads.s3.amazonaws.com/".to_string() + i.path())
                        .nth(0);

                    let mut rest = imgs.clone();
                    if let Some(thumb) = thumb.clone() {
                      rest.retain(|x| !thumb.contains(x.path()))
                    };

                    let collection = rest
                        .iter()
                        .filter(|i| ad.images.iter().any(|a| a.contains(i.path())))
                        .map(|i| "https://pp-facebook-ads.s3.amazonaws.com/".to_string() + i.path())
                        .collect::<Vec<String>>();

                    let update = Images {
                        thumbnail: thumb,
                        images: collection
                    };
                    // I don't understand why we're zeroing out the errors here
                    // but ok.
                    let connection = db.get().map_err(|_| ())?;
                    diesel::update(ads.filter(id.eq(ad.id)))
                        .set(&update)
                        .execute(&*connection)
                        .map_err(|_| ())?;
                    Ok(())
                })
            });
        Box::new(future)
    }
}

#[derive(Insertable)]
#[table_name = "ads"]
pub struct NewAd<'a> {
    id: &'a str,
    html: &'a str,
    political: i32,
    not_political: i32,

    title: String,
    message: String,
    thumbnail: String,

    browser_lang: &'a str,
    images: Vec<String>,
}

impl<'a> NewAd<'a> {
    fn get_title(document: &kuchiki::NodeRef) -> Result<String, InsertError> {
        document
            .select("h5 a, h6 a, strong")
            .map_err(InsertError::HTML)?
            .nth(0)
            .and_then(|a| Some(a.text_contents()))
            .ok_or(InsertError::HTML(()))
    }

    fn get_image(document: &kuchiki::NodeRef) -> Result<String, InsertError> {
        document
            .select("img")
            .map_err(InsertError::HTML)?
            .nth(0)
            .and_then(|a| {
                a.attributes.borrow().get("src").and_then(
                    |src| Some(src.to_string()),
                )
            })
            .ok_or(InsertError::HTML(()))
    }
    // Video ads make this a bit messy
    fn get_message(document: &kuchiki::NodeRef) -> Result<String, InsertError> {
        let selectors = vec![".userContent p", "span"];
        let iters = selectors.iter().map(|s| document.select(s)).flat_map(|a| a);

        iters
            .map(|i| {
                i.fold(String::new(), |m, a| m + &a.as_node().to_string())
            })
            .filter(|i| i.len() > 0)
            .nth(0)
            .ok_or(InsertError::HTML(()))
    }

    fn get_images(document: &kuchiki::NodeRef) -> Result<Vec<String>, InsertError> {
        Ok(
            document
                .select("img")
                .map_err(InsertError::HTML)?
                .skip(1)
                .map(|a| {
                    a.attributes.borrow().get("src").and_then(
                        |s| if !s.contains(
                            "rsrc.php",
                        )
                        {
                            Some(s.to_string())
                        } else {
                            None
                        },
                    )
                })
                .filter(|s| s.is_some())
                .map(|s| s.unwrap())
                .collect::<Vec<String>>(),
        )
    }

    pub fn new(ad: &'a AdPost) -> Result<NewAd<'a>, InsertError> {
        let document = kuchiki::parse_html().one(ad.html.clone());

        let message = NewAd::get_message(&document)?;
        let title = NewAd::get_title(&document)?;
        let thumb = NewAd::get_image(&document)?;
        let images = NewAd::get_images(&document)?;

        Ok(NewAd {
            id: &ad.id,
            html: &ad.html,
            political: if ad.political { 1 } else { 0 },
            not_political: if !ad.political { 1 } else { 0 },
            title: title,
            message: message,
            thumbnail: thumb,
            browser_lang: &ad.browser_lang,
            images: images,
        })
    }

    pub fn save(&self, pool: &Pool<ConnectionManager<PgConnection>>) -> Result<Ad, InsertError> {
        use schema::ads;
        use schema::ads::dsl::*;
        let connection = pool.get().map_err(InsertError::Timeout)?;
        let ad: Ad = diesel::insert(&self.on_conflict(
            id,
            do_update().set((
                political.eq(political + self.political),
                not_political.eq(
                    not_political +
                        self.not_political,
                ),
                updated_at.eq(Utc::now()),
            )),
        )).into(ads::table)
            .get_result(&*connection)
            .map_err(InsertError::DataBase)?;
        Ok(ad)
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn ad_parsing() {
        let ad = include_str!("./html-test.txt");
        let post = AdPost {
            id: "test".to_string(),
            html: ad.to_string(),
            political: true,
            browser_lang: "en-US".to_string(),
        };
        let new_ad = NewAd::new(&post).unwrap();
        assert!(new_ad.thumbnail.len() > 0);
        assert_eq!(new_ad.images.len(), 1);
        assert_eq!(
            new_ad.message,
            "
#Valerian is “the best experience since ‘Avatar.’” See it in 3D and RealD3D theaters this Friday. Get tickets now: ValerianTickets.com
"
        );
        assert!(new_ad.title.len() > 0);
    }
}
<commit_msg>All set!<commit_after>use chrono::DateTime;
use chrono::offset::Utc;
use diesel;
use diesel::prelude::*;
use diesel::pg::PgConnection;
use diesel::pg::upsert::*;
use futures::{Future, stream, Stream};
use futures_cpupool::CpuPool;
use hyper::{Body, Client, Uri};
use hyper::client::HttpConnector;
use hyper_tls::HttpsConnector;
use InsertError;
use kuchiki;
use kuchiki::traits::*;
use r2d2_diesel::ConnectionManager;
use r2d2::Pool;
use rusoto_core::{default_tls_client, Region};
use rusoto_credential::ProfileProvider;
use rusoto_s3::{PutObjectRequest, S3Client, S3};
use schema::ads;
use server::AdPost;

#[derive(Queryable, Debug, Clone)]
pub struct Ad {
    id: String,
    html: String,
    political: i32,
    not_political: i32,

    fuzzy_id: Option<i32>,
    title: String,
    message: String,
    thumbnail: String,

    created_at: DateTime<Utc>,
    updated_at: DateTime<Utc>,

    browser_lang: String,

    images: Vec<String>,
}

#[derive(AsChangeset)]
#[table_name = "ads"]
pub struct Images {
    thumbnail: Option<String>,
    images: Vec<String>,
}

impl Ad {
    // This will asynchronously save the images to s3 we may very well end up
    // with broken images. but I can't see any way around it right now.  Also we
    // should think about splitting this up, but I'm fine -- if a little
    // embarassed about it right now. This function swallows errors, and there's
    // a chance we'll end up with no images at the end, but I think we can
    // handle that in the extension's UI.
    pub fn grab_and_store(
        &self,
        client: Client<HttpsConnector<HttpConnector>, Body>,
        db: &Pool<ConnectionManager<PgConnection>>,
        pool: CpuPool,
    ) -> Box<Future<Item = (), Error = ()>> {
        let ad = self.clone();
        let pool_s3 = pool.clone();
        let pool_db = pool.clone();
        let db = db.clone();

        let images = [vec![self.thumbnail.clone()], self.images.clone()];
        let urls = images
            .concat()
            .iter()
            .map(|a| {
                let a: Uri = a.parse().map_err(InsertError::Uri)?;
                Ok(a)
            })
            .collect::<Vec<Result<Uri, InsertError>>>();
        let future = stream::iter(urls)
            // filter ones we already have in the db and ones we can verify as
            // coming from fb, we don't want to become a malware vector :)
            .filter(|u| match u.host() {
                Some(h) => h != "pp-facebook-ads.s3.amazonaws.com" || !h.ends_with("fbcdn.net"),
                None => false
            })
            // grab image
            .and_then(move |img| {
                info!("getting {:?}", img);
                let cloned = img.clone();
                client
                    .get(img)
                    .and_then(|res| {
                        res.body().concat2().and_then(|chunk| Ok((chunk, cloned)))
                    })
                    .map_err(InsertError::Hyper)
            })
            // upload them to s3
            .and_then(move |tuple| {
                let pool = pool_s3.clone();
                // we do this in a worker thread because rusoto isn't on
                // Hyper async yet.
                pool.spawn_fn(move || {
                    let client =
                        S3Client::new(default_tls_client().map_err(InsertError::TLS)?,
                                      ProfileProvider::new().map_err(InsertError::AWS)?,
                                      Region::UsEast1);
                    let req = PutObjectRequest {
                        bucket: "pp-facebook-ads".to_string(),
                        key: tuple.1.path().trim_left_matches("/").to_string(),
                        acl: Some("public-read".to_string()),
                        body: Some(tuple.0.to_vec()),
                        ..PutObjectRequest::default()
                    };

                    client.put_object(&req).map_err(InsertError::S3)?;
                    Ok(tuple.1)
                })
            })
            .map_err(|e| {
                warn!("{:?}", e);
                ()
            })
            .collect()
            // save the new urls to the database. the images variable will
            // include only those that we've successfully saved to s3, so we
            // have to do a funky merge here.
            .and_then(move |images| {
                let imgs = images.clone();
                pool_db.spawn_fn(move || {
                    use schema::ads::dsl::*;
                    let thumb = imgs
                        .iter()
                        .filter(|i| ad.thumbnail.contains(i.path()))
                        .map(|i| "https://pp-facebook-ads.s3.amazonaws.com/".to_string() + i.path().trim_left_matches("/"))
                        .nth(0);

                    let mut rest = imgs.clone();
                    if let Some(thumb) = thumb.clone() {
                      rest.retain(|x| !thumb.contains(x.path()))
                    };

                    let collection = rest
                        .iter()
                        .filter(|i| ad.images.iter().any(|a| a.contains(i.path())))
                        .map(|i| "https://pp-facebook-ads.s3.amazonaws.com/".to_string() + i.path().trim_left_matches("/"))
                        .collect::<Vec<String>>();

                    let update = Images {
                        thumbnail: thumb,
                        images: collection
                    };
                    // I don't understand why we're zeroing out the errors here
                    // but ok.
                    let connection = db.get().map_err(|e| {warn!("{:?}", e); ()})?;
                    diesel::update(ads.filter(id.eq(ad.id)))
                        .set(&update)
                        .execute(&*connection)
                        .map_err(|e| {warn!("{:?}", e); ()})?;
                    info!("saved {:?}", imgs);
                    Ok(())
                })
            });
        Box::new(future)
    }
}

#[derive(Insertable)]
#[table_name = "ads"]
pub struct NewAd<'a> {
    id: &'a str,
    html: &'a str,
    political: i32,
    not_political: i32,

    title: String,
    message: String,
    thumbnail: String,

    browser_lang: &'a str,
    images: Vec<String>,
}

impl<'a> NewAd<'a> {
    fn get_title(document: &kuchiki::NodeRef) -> Result<String, InsertError> {
        document
            .select("h5 a, h6 a, strong")
            .map_err(InsertError::HTML)?
            .nth(0)
            .and_then(|a| Some(a.text_contents()))
            .ok_or(InsertError::HTML(()))
    }

    fn get_image(document: &kuchiki::NodeRef) -> Result<String, InsertError> {
        document
            .select("img")
            .map_err(InsertError::HTML)?
            .nth(0)
            .and_then(|a| {
                a.attributes.borrow().get("src").and_then(
                    |src| Some(src.to_string()),
                )
            })
            .ok_or(InsertError::HTML(()))
    }
    // Video ads make this a bit messy
    fn get_message(document: &kuchiki::NodeRef) -> Result<String, InsertError> {
        let selectors = vec![".userContent p", "span"];
        let iters = selectors.iter().map(|s| document.select(s)).flat_map(|a| a);

        iters
            .map(|i| {
                i.fold(String::new(), |m, a| m + &a.as_node().to_string())
            })
            .filter(|i| i.len() > 0)
            .nth(0)
            .ok_or(InsertError::HTML(()))
    }

    fn get_images(document: &kuchiki::NodeRef) -> Result<Vec<String>, InsertError> {
        Ok(
            document
                .select("img")
                .map_err(InsertError::HTML)?
                .skip(1)
                .map(|a| {
                    a.attributes.borrow().get("src").and_then(
                        |s| if !s.contains(
                            "rsrc.php",
                        )
                        {
                            Some(s.to_string())
                        } else {
                            None
                        },
                    )
                })
                .filter(|s| s.is_some())
                .map(|s| s.unwrap())
                .collect::<Vec<String>>(),
        )
    }

    pub fn new(ad: &'a AdPost) -> Result<NewAd<'a>, InsertError> {
        let document = kuchiki::parse_html().one(ad.html.clone());

        let message = NewAd::get_message(&document)?;
        let title = NewAd::get_title(&document)?;
        let thumb = NewAd::get_image(&document)?;
        let images = NewAd::get_images(&document)?;

        Ok(NewAd {
            id: &ad.id,
            html: &ad.html,
            political: if ad.political { 1 } else { 0 },
            not_political: if !ad.political { 1 } else { 0 },
            title: title,
            message: message,
            thumbnail: thumb,
            browser_lang: &ad.browser_lang,
            images: images,
        })
    }

    pub fn save(&self, pool: &Pool<ConnectionManager<PgConnection>>) -> Result<Ad, InsertError> {
        use schema::ads;
        use schema::ads::dsl::*;
        let connection = pool.get().map_err(InsertError::Timeout)?;
        let ad: Ad = diesel::insert(&self.on_conflict(
            id,
            do_update().set((
                political.eq(political + self.political),
                not_political.eq(
                    not_political +
                        self.not_political,
                ),
                updated_at.eq(Utc::now()),
            )),
        )).into(ads::table)
            .get_result(&*connection)
            .map_err(InsertError::DataBase)?;
        Ok(ad)
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn ad_parsing() {
        let ad = include_str!("./html-test.txt");
        let post = AdPost {
            id: "test".to_string(),
            html: ad.to_string(),
            political: true,
            browser_lang: "en-US".to_string(),
        };
        let new_ad = NewAd::new(&post).unwrap();
        assert!(new_ad.thumbnail.len() > 0);
        assert_eq!(new_ad.images.len(), 1);
        assert_eq!(
            new_ad.message,
            "
#Valerian is “the best experience since ‘Avatar.’” See it in 3D and RealD3D theaters this Friday. Get tickets now: ValerianTickets.com
"
        );
        assert!(new_ad.title.len() > 0);
    }
}
<|endoftext|>


<commit_before>use std::net::{TcpListener, TcpStream, Shutdown};
use std::collections::HashMap;

use std::thread;
use std::sync::{Arc, Mutex};
use std::sync::mpsc::{Sender};
use std::time::{Instant,Duration};

use std::io::prelude::*;

extern crate hmacsha1;
extern crate uuid;
extern crate byteorder;

use shared::{chat,client,opcode,player};
use self::uuid::Uuid;

use self::client::{Client,ClientBase};
use self::chat::{read_text,text_as_bytes};
use distributor::Distributor;
use distributor::Kind as DistKind;
use store::{DataStore,Store};
use self::player::Player;

#[derive(Debug,Clone)]
pub struct Server {
    clients: Arc<Mutex<Vec<ClientBase>>>, // this always grows
    players: Arc<Mutex<HashMap<Uuid, Player>>>, //NOTE: this may make more sense as atomic-vec-keys
    dist: Sender<DistKind<TcpStream>>,
    store: Arc<Mutex<Store>>, //NOTE: this may become a threadpool
}

impl Server {
    pub fn new(ip: &str) {
        let listener = TcpListener::bind(ip).unwrap();

        let (dist_tx, mut distributor) = Distributor::new(Store::default());
        thread::spawn(move || distributor.run());

        let server = Server {
            clients: Arc::new(Mutex::new(vec!())),
            players: Arc::new(Mutex::new(HashMap::new())),
            dist: dist_tx,
            store: Arc::new(Mutex::new(Store::default())),
        };

        if let Ok(mut clients) = server.clients.lock() {
            if let Ok(store) = server.store.lock() {
                *clients = store.clients_get();
            }
        }

        for s in listener.incoming() {
            match s {
                Ok(s) => {
                    let server = server.clone();
                    thread::spawn(|| Server::handler(server,s));
                },
                _ => {},
            }
        }
    }

    #[allow(unused_must_use)]
    fn handler (mut server: Server, mut s: TcpStream) {
        let mut cmd = [0;1];
        let mut time = Instant::now(); //TODO: ping every so often

        //new conn needs auth code
        let m = uuid::Uuid::new_v4();
        s.write_all(m.as_bytes());

        let mut client_id: Option<Uuid> = None;

        'handler: loop {
            if let Ok(_) = s.read_exact(&mut cmd) {
                match cmd[0] {
                    opcode::LOGIN => { //login
                        client_id = Server::login(&mut server, &mut s, m);
                        if let Some(uuid) = client_id {
                            Server::send_players(&mut server, uuid);
                        }
                    },
                    opcode::REGISTER => { //register
                        Server::register(&mut server, &mut s);
                    },
                    _ => {
                        if let Some(uuid) = client_id {
                            match cmd[0] {
                                opcode::CHAT => { //chat
                                    Server::handle_chat(&mut server, &mut s, uuid);
                                },
                                opcode::PLAYER => { //player
                                    if let (_, Some(player)) = Player::from_stream(&mut s, false) {
                                        if let Ok(store) = server.store.lock() {
                                            if store.player_update(&uuid, &player) {
                                                let data = Player::to_bytes(Some(&uuid),&player);
                                                server.dist.send(DistKind::Broadcast(data));

                                                //println!("nick_change:{:?}  {:?}",uuid,player);
                                            }
                                        }
                                    }
                                },
                                opcode::PING => {
                                    server.dist.send(DistKind::Select(uuid,vec![opcode::PING]));
                                    //println!("ping");
                                },
                                opcode::PONG => {
                                    if time.elapsed() > Duration::new(5, 0) {
                                        break 'handler
                                    }
                                },
                                _ => break 'handler
                            }
                        }
                    }
                }
            }
            else { break 'handler } //drop dead client

            // ping every so often
            if let Some(uuid) = client_id {
                if time.elapsed() > Duration::new(15, 0) {
                    time = Instant::now();
                    server.dist.send(DistKind::Select(uuid,vec![opcode::PING]));
                }
            }
        }

        //println!("client dropped");
        let _ = s.flush();
        let _ = s.shutdown(Shutdown::Both);

        if let Some(uuid) = client_id {
            server.dist.send(DistKind::Remove(uuid));
        }
    }

    fn register (server: &mut Server,
                 mut s: &mut TcpStream,) {
        if let Some((c,_)) = Client::load(&mut s) {

            if let Ok(clients) = server.clients.lock() {
                for n in clients.iter() {
                    if &n.id == c.id() { panic!("client already register {:?}",c.id()) }
                }
            }

            if let Ok(store) = server.store.lock() {
                let mut r = false;
                for _ in [..100].iter() { // try to repeatedly add a unique name
                    r = store.player_put(&c.id(), &Player::default());
                    if r { break }
                }

                if r {
                    let _r = store.client_put(&c.base);
                    //println!("registered ({:?}):{:?}",r, c.id());

                    if let Ok(mut clients) = server.clients.lock() {
                        clients.push(c.base.clone());
                    }
                }

            }
        }
    }

    #[allow(unused_must_use)]
    fn handle_chat (server: &mut Server,
             mut s: &mut TcpStream,
             uuid: Uuid) {

        if let Some(text) = read_text(s) {
            //println!("chat-client:{:?}",text.trim());

            //broadcast
            let (mut data, bytes) = text_as_bytes(&text);
            data.extend_from_slice(bytes);
            data.extend_from_slice(uuid.as_bytes()); //refer to uuid

            server.dist.send(DistKind::Broadcast(data));
        }
    }

    #[allow(unused_must_use)]
    fn login (server: &mut Server,
              mut s: &mut TcpStream,
              m: Uuid) -> Option<Uuid> {
        let mut client_id = None;
        let mut player = None;

        if let Some((c,_)) = Client::load(&mut s) {
            let mut reg_key = None;

            if let Ok(clients) = server.clients.lock() {
                for n in clients.iter() {
                    if &n.id == c.id() {
                        reg_key = Some(n.key.clone());
                        client_id = Some(c.id().clone());

                        break
                    }
                }
            }

            if let Some(key) = reg_key {
                let hm = hmacsha1::hmac_sha1(&key, m.as_bytes());
                if c.key() == hm {

                    if let Ok(store) = server.store.lock() {
                        player = store.player_get(c.id());
                    }

                    if let Some(player) = player {
                        if let Ok(stmp) = s.try_clone() {
                            {
                                server.dist.send(DistKind::Add(*c.id(),stmp));

                                if let Ok(mut players) = server.players.lock() {
                                    players.insert(*c.id(),player.clone());
                                    //println!("total players:{:?}",players.len()); //NOTE: this should print on debug only
                                }
                            }

                            //println!("login:{:?}",c.id());
                            let data = Player::to_bytes(Some(c.id()),&player);
                            server.dist.send(DistKind::Broadcast(data));
                        }
                    }
                }
                else {
                    panic!("client invalid login {:?}", c)
                }

            }
            else { panic!("client unregistered {:?}", c) }
        }

       client_id
    }

    #[allow(unused_must_use)]
    //NOTE: this is very innefficient, and hogs the mutex
    //TODO: rework state updates entirely
    fn send_players (server: &mut Server,
                     uuid: Uuid)  {

        if let Ok(players) = server.players.lock() {
            for (ref pid,player) in players.iter() {
                let data = Player::to_bytes(Some(pid),&player);

                server.dist.send(DistKind::Select(uuid,data));
            }

        }
    }
}
<commit_msg>remove player on drop<commit_after>use std::net::{TcpListener, TcpStream, Shutdown};
use std::collections::HashMap;

use std::thread;
use std::sync::{Arc, Mutex};
use std::sync::mpsc::{Sender};
use std::time::{Instant,Duration};

use std::io::prelude::*;

extern crate hmacsha1;
extern crate uuid;
extern crate byteorder;

use shared::{chat,client,opcode,player};
use self::uuid::Uuid;

use self::client::{Client,ClientBase};
use self::chat::{read_text,text_as_bytes};
use distributor::Distributor;
use distributor::Kind as DistKind;
use store::{DataStore,Store};
use self::player::Player;

#[derive(Debug,Clone)]
pub struct Server {
    clients: Arc<Mutex<Vec<ClientBase>>>, // this always grows
    players: Arc<Mutex<HashMap<Uuid, Player>>>, //NOTE: this may make more sense as atomic-vec-keys
    dist: Sender<DistKind<TcpStream>>,
    store: Arc<Mutex<Store>>, //NOTE: this may become a threadpool
}

impl Server {
    pub fn new(ip: &str) {
        let listener = TcpListener::bind(ip).unwrap();

        let (dist_tx, mut distributor) = Distributor::new(Store::default());
        thread::spawn(move || distributor.run());

        let server = Server {
            clients: Arc::new(Mutex::new(vec!())),
            players: Arc::new(Mutex::new(HashMap::new())),
            dist: dist_tx,
            store: Arc::new(Mutex::new(Store::default())),
        };

        if let Ok(mut clients) = server.clients.lock() {
            if let Ok(store) = server.store.lock() {
                *clients = store.clients_get();
            }
        }

        for s in listener.incoming() {
            match s {
                Ok(s) => {
                    let server = server.clone();
                    thread::spawn(|| Server::handler(server,s));
                },
                _ => {},
            }
        }
    }

    #[allow(unused_must_use)]
    fn handler (mut server: Server, mut s: TcpStream) {
        let mut cmd = [0;1];
        let mut time = Instant::now(); //TODO: ping every so often

        //new conn needs auth code
        let m = uuid::Uuid::new_v4();
        s.write_all(m.as_bytes());

        let mut client_id: Option<Uuid> = None;

        'handler: loop {
            if let Ok(_) = s.read_exact(&mut cmd) {
                match cmd[0] {
                    opcode::LOGIN => { //login
                        client_id = Server::login(&mut server, &mut s, m);
                        if let Some(uuid) = client_id {
                            Server::send_players(&mut server, uuid);
                        }
                    },
                    opcode::REGISTER => { //register
                        Server::register(&mut server, &mut s);
                    },
                    _ => {
                        if let Some(uuid) = client_id {
                            match cmd[0] {
                                opcode::CHAT => { //chat
                                    Server::handle_chat(&mut server, &mut s, uuid);
                                },
                                opcode::PLAYER => { //player
                                    if let (_, Some(player)) = Player::from_stream(&mut s, false) {
                                        if let Ok(store) = server.store.lock() {
                                            if store.player_update(&uuid, &player) {
                                                let data = Player::to_bytes(Some(&uuid),&player);
                                                server.dist.send(DistKind::Broadcast(data));

                                                //println!("nick_change:{:?}  {:?}",uuid,player);
                                            }
                                        }
                                    }
                                },
                                opcode::PING => {
                                    server.dist.send(DistKind::Select(uuid,vec![opcode::PING]));
                                    //println!("ping");
                                },
                                opcode::PONG => {
                                    if time.elapsed() > Duration::new(5, 0) {
                                        break 'handler
                                    }
                                },
                                _ => break 'handler
                            }
                        }
                    }
                }
            }
            else { break 'handler } //drop dead client

            // ping every so often
            if let Some(uuid) = client_id {
                if time.elapsed() > Duration::new(15, 0) {
                    time = Instant::now();
                    server.dist.send(DistKind::Select(uuid,vec![opcode::PING]));
                }
            }
        }

        //println!("client dropped");
        let _ = s.flush();
        let _ = s.shutdown(Shutdown::Both);

        if let Some(uuid) = client_id {
            server.dist.send(DistKind::Remove(uuid));
            server.players.lock().unwrap().remove(&uuid); //ok to panic here
        }
    }

    fn register (server: &mut Server,
                 mut s: &mut TcpStream,) {
        if let Some((c,_)) = Client::load(&mut s) {

            if let Ok(clients) = server.clients.lock() {
                for n in clients.iter() {
                    if &n.id == c.id() { panic!("client already register {:?}",c.id()) }
                }
            }

            if let Ok(store) = server.store.lock() {
                let mut r = false;
                for _ in [..100].iter() { // try to repeatedly add a unique name
                    r = store.player_put(&c.id(), &Player::default());
                    if r { break }
                }

                if r {
                    let _r = store.client_put(&c.base);
                    //println!("registered ({:?}):{:?}",r, c.id());

                    if let Ok(mut clients) = server.clients.lock() {
                        clients.push(c.base.clone());
                    }
                }

            }
        }
    }

    #[allow(unused_must_use)]
    fn handle_chat (server: &mut Server,
             mut s: &mut TcpStream,
             uuid: Uuid) {

        if let Some(text) = read_text(s) {
            //println!("chat-client:{:?}",text.trim());

            //broadcast
            let (mut data, bytes) = text_as_bytes(&text);
            data.extend_from_slice(bytes);
            data.extend_from_slice(uuid.as_bytes()); //refer to uuid

            server.dist.send(DistKind::Broadcast(data));
        }
    }

    #[allow(unused_must_use)]
    fn login (server: &mut Server,
              mut s: &mut TcpStream,
              m: Uuid) -> Option<Uuid> {
        let mut client_id = None;
        let mut player = None;

        if let Some((c,_)) = Client::load(&mut s) {
            let mut reg_key = None;

            if let Ok(clients) = server.clients.lock() {
                for n in clients.iter() {
                    if &n.id == c.id() {
                        reg_key = Some(n.key.clone());
                        client_id = Some(c.id().clone());

                        break
                    }
                }
            }

            if let Some(key) = reg_key {
                let hm = hmacsha1::hmac_sha1(&key, m.as_bytes());
                if c.key() == hm {

                    if let Ok(store) = server.store.lock() {
                        player = store.player_get(c.id());
                    }

                    if let Some(player) = player {
                        if let Ok(stmp) = s.try_clone() {
                            {
                                server.dist.send(DistKind::Add(*c.id(),stmp));

                                if let Ok(mut players) = server.players.lock() {
                                    players.insert(*c.id(),player.clone());
                                    //println!("total players:{:?}",players.len()); //NOTE: this should print on debug only
                                }
                            }

                            //println!("login:{:?}",c.id());
                            let data = Player::to_bytes(Some(c.id()),&player);
                            server.dist.send(DistKind::Broadcast(data));
                        }
                    }
                }
                else {
                    panic!("client invalid login {:?}", c)
                }

            }
            else { panic!("client unregistered {:?}", c) }
        }

       client_id
    }

    #[allow(unused_must_use)]
    //NOTE: this is very innefficient, and hogs the mutex
    //TODO: rework state updates entirely
    fn send_players (server: &mut Server,
                     uuid: Uuid)  {

        if let Ok(players) = server.players.lock() {
            for (ref pid,player) in players.iter() {
                let data = Player::to_bytes(Some(pid),&player);

                server.dist.send(DistKind::Select(uuid,data));
            }

        }
    }
}
<|endoftext|>


<commit_before>/*!

# juniper_iron

This repository contains the [Iron][Iron] web framework integration for
[Juniper][Juniper], a [GraphQL][GraphQL] implementation for Rust.

For documentation, including guides and examples, check out [Juniper][Juniper].

A basic usage example can also be found in the [Api documentation][documentation].

## Links

* [Juniper][Juniper]
* [Api Reference][documentation]
* [Iron framework][Iron]

## Integrating with Iron

For example, continuing from the schema created above and using Iron to expose
the schema on an HTTP endpoint supporting both GET and POST requests:

```rust,no_run
extern crate iron;
# #[macro_use] extern crate juniper;
# extern crate juniper_iron;
# use std::collections::HashMap;

use iron::prelude::*;
use juniper_iron::GraphQLHandler;
use juniper::{Context, EmptyMutation};

# use juniper::FieldResult;
#
# struct User { id: String, name: String, friend_ids: Vec<String>  }
# struct QueryRoot;
# struct Database { users: HashMap<String, User> }
#
# graphql_object!(User: Database |&self| {
#     field id() -> FieldResult<&String> {
#         Ok(&self.id)
#     }
#
#     field name() -> FieldResult<&String> {
#         Ok(&self.name)
#     }
#
#     field friends(&executor) -> FieldResult<Vec<&User>> {
#         Ok(self.friend_ids.iter()
#             .filter_map(|id| executor.context().users.get(id))
#             .collect())
#     }
# });
#
# graphql_object!(QueryRoot: Database |&self| {
#     field user(&executor, id: String) -> FieldResult<Option<&User>> {
#         Ok(executor.context().users.get(&id))
#     }
# });

// This function is executed for every request. Here, we would realistically
// provide a database connection or similar. For this example, we'll be
// creating the database from scratch.
fn context_factory(_: &mut Request) -> Database {
    Database {
        users: vec![
            ( "1000".to_owned(), User {
                id: "1000".to_owned(), name: "Robin".to_owned(),
                friend_ids: vec!["1001".to_owned()] } ),
            ( "1001".to_owned(), User {
                id: "1001".to_owned(), name: "Max".to_owned(),
                friend_ids: vec!["1000".to_owned()] } ),
        ].into_iter().collect()
    }
}

impl Context for Database {}

fn main() {
    // GraphQLHandler takes a context factory function, the root object,
    // and the mutation object. If we don't have any mutations to expose, we
    // can use the empty tuple () to indicate absence.
    let graphql_endpoint = GraphQLHandler::new(
        context_factory, QueryRoot, EmptyMutation::<Database>::new());

    // Start serving the schema at the root on port 8080.
    Iron::new(graphql_endpoint).http("localhost:8080").unwrap();
}

```

See the the [`GraphQLHandler`][3] documentation for more information on what request methods are
supported.

[3]: ./struct.GraphQLHandler.html
[Iron]: https://github.com/iron/iron
[Juniper]: https://github.com/graphql-rust/juniper
[GraphQL]: http://graphql.org
[documentation]: https://docs.rs/juniper_iron

*/

#[macro_use]
extern crate iron;
#[cfg(test)]
extern crate iron_test;
extern crate juniper;
extern crate serde_json;
extern crate urlencoded;

use iron::prelude::*;
use iron::middleware::Handler;
use iron::mime::Mime;
use iron::status;
use iron::method;
use urlencoded::{UrlDecodingError, UrlEncodedQuery};

use std::io::Read;
use std::error::Error;
use std::fmt;

use serde_json::error::Error as SerdeError;

use juniper::{GraphQLType, InputValue, RootNode};
use juniper::http;

/// Handler that executes GraphQL queries in the given schema
///
/// The handler responds to GET requests and POST requests only. In GET
/// requests, the query should be supplied in the `query` URL parameter, e.g.
/// `http://localhost:3000/graphql?query={hero{name}}`.
///
/// POST requests support both queries and variables. POST a JSON document to
/// this endpoint containing the field `"query"` and optionally `"variables"`.
/// The variables should be a JSON object containing the variable to value
/// mapping.
pub struct GraphQLHandler<'a, CtxFactory, Query, Mutation, CtxT>
where
    CtxFactory: Fn(&mut Request) -> CtxT + Send + Sync + 'static,
    CtxT: 'static,
    Query: GraphQLType<Context = CtxT> + Send + Sync + 'static,
    Mutation: GraphQLType<Context = CtxT> + Send + Sync + 'static,
{
    context_factory: CtxFactory,
    root_node: RootNode<'a, Query, Mutation>,
}

/// Handler that renders GraphiQL - a graphical query editor interface
pub struct GraphiQLHandler {
    graphql_url: String,
}

fn get_single_value<T>(mut values: Vec<T>) -> IronResult<T> {
    if values.len() == 1 {
        Ok(values.remove(0))
    } else {
        Err(GraphQLIronError::InvalidData("Duplicate URL query parameter").into())
    }
}

fn parse_url_param(params: Option<Vec<String>>) -> IronResult<Option<String>> {
    if let Some(values) = params {
        get_single_value(values).map(Some)
    } else {
        Ok(None)
    }
}

fn parse_variable_param(params: Option<Vec<String>>) -> IronResult<Option<InputValue>> {
    if let Some(values) = params {
        Ok(
            serde_json::from_str::<InputValue>(get_single_value(values)?.as_ref())
                .map(Some)
                .map_err(GraphQLIronError::Serde)?,
        )
    } else {
        Ok(None)
    }
}

impl<'a, CtxFactory, Query, Mutation, CtxT> GraphQLHandler<'a, CtxFactory, Query, Mutation, CtxT>
where
    CtxFactory: Fn(&mut Request) -> CtxT + Send + Sync + 'static,
    CtxT: 'static,
    Query: GraphQLType<Context = CtxT, TypeInfo = ()> + Send + Sync + 'static,
    Mutation: GraphQLType<Context = CtxT, TypeInfo = ()> + Send + Sync + 'static,
{
    /// Build a new GraphQL handler
    ///
    /// The context factory will receive the Iron request object and is
    /// expected to construct a context object for the given schema. This can
    /// be used to construct e.g. database connections or similar data that
    /// the schema needs to execute the query.
    pub fn new(context_factory: CtxFactory, query: Query, mutation: Mutation) -> Self {
        GraphQLHandler {
            context_factory: context_factory,
            root_node: RootNode::new(query, mutation),
        }
    }

    fn handle_get(&self, req: &mut Request) -> IronResult<http::GraphQLRequest> {
        let url_query_string = req.get_mut::<UrlEncodedQuery>()
            .map_err(|e| GraphQLIronError::Url(e))?;

        let input_query = parse_url_param(url_query_string.remove("query"))?
            .ok_or_else(|| GraphQLIronError::InvalidData("No query provided"))?;
        let operation_name = parse_url_param(url_query_string.remove("operationName"))?;
        let variables = parse_variable_param(url_query_string.remove("variables"))?;

        Ok(http::GraphQLRequest::new(
            input_query,
            operation_name,
            variables,
        ))
    }

    fn handle_post(&self, req: &mut Request) -> IronResult<http::GraphQLRequest> {
        let mut request_payload = String::new();
        itry!(req.body.read_to_string(&mut request_payload));

        Ok(
            serde_json::from_str::<http::GraphQLRequest>(request_payload.as_str())
                .map_err(|err| GraphQLIronError::Serde(err))?,
        )
    }

    fn execute(&self, context: &CtxT, request: http::GraphQLRequest) -> IronResult<Response> {
        let response = request.execute(&self.root_node, context);
        let content_type = "application/json".parse::<Mime>().unwrap();
        let json = serde_json::to_string_pretty(&response).unwrap();
        let status = if response.is_ok() {
            status::Ok
        } else {
            status::BadRequest
        };
        Ok(Response::with((content_type, status, json)))
    }
}

impl GraphiQLHandler {
    /// Build a new GraphiQL handler targeting the specified URL.
    ///
    /// The provided URL should point to the URL of the attached `GraphQLHandler`. It can be
    /// relative, so a common value could be `"/graphql"`.
    pub fn new(graphql_url: &str) -> GraphiQLHandler {
        GraphiQLHandler {
            graphql_url: graphql_url.to_owned(),
        }
    }
}

impl<'a, CtxFactory, Query, Mutation, CtxT> Handler
    for GraphQLHandler<'a, CtxFactory, Query, Mutation, CtxT>
where
    CtxFactory: Fn(&mut Request) -> CtxT + Send + Sync + 'static,
    CtxT: 'static,
    Query: GraphQLType<Context = CtxT, TypeInfo = ()> + Send + Sync + 'static,
    Mutation: GraphQLType<Context = CtxT, TypeInfo = ()> + Send + Sync + 'static,
    'a: 'static,
{
    fn handle(&self, mut req: &mut Request) -> IronResult<Response> {
        let context = (self.context_factory)(req);

        let graphql_request = match req.method {
            method::Get => self.handle_get(&mut req)?,
            method::Post => self.handle_post(&mut req)?,
            _ => return Ok(Response::with((status::MethodNotAllowed))),
        };

        self.execute(&context, graphql_request)
    }
}

impl Handler for GraphiQLHandler {
    fn handle(&self, _: &mut Request) -> IronResult<Response> {
        let content_type = "text/html".parse::<Mime>().unwrap();

        Ok(Response::with((
            content_type,
            status::Ok,
            juniper::graphiql::graphiql_source(&self.graphql_url),
        )))
    }
}

#[derive(Debug)]
enum GraphQLIronError {
    Serde(SerdeError),
    Url(UrlDecodingError),
    InvalidData(&'static str),
}

impl fmt::Display for GraphQLIronError {
    fn fmt(&self, mut f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            GraphQLIronError::Serde(ref err) => fmt::Display::fmt(err, &mut f),
            GraphQLIronError::Url(ref err) => fmt::Display::fmt(err, &mut f),
            GraphQLIronError::InvalidData(ref err) => fmt::Display::fmt(err, &mut f),
        }
    }
}

impl Error for GraphQLIronError {
    fn description(&self) -> &str {
        match *self {
            GraphQLIronError::Serde(ref err) => err.description(),
            GraphQLIronError::Url(ref err) => err.description(),
            GraphQLIronError::InvalidData(ref err) => err,
        }
    }

    fn cause(&self) -> Option<&Error> {
        match *self {
            GraphQLIronError::Serde(ref err) => Some(err),
            GraphQLIronError::Url(ref err) => Some(err),
            GraphQLIronError::InvalidData(_) => None,
        }
    }
}

impl From<GraphQLIronError> for IronError {
    fn from(err: GraphQLIronError) -> IronError {
        let message = format!("{}", err);
        IronError::new(err, (status::BadRequest, message))
    }
}

#[cfg(test)]
mod tests {
    use iron::prelude::*;
    use iron_test::{request, response};
    use iron::{Handler, Headers};

    use juniper::tests::model::Database;
    use juniper::http::tests as http_tests;
    use juniper::EmptyMutation;

    use super::GraphQLHandler;

    struct TestIronIntegration;

    impl http_tests::HTTPIntegration for TestIronIntegration {
        fn get(&self, url: &str) -> http_tests::TestResponse {
            make_test_response(request::get(
                &("http://localhost:3000".to_owned() + url),
                Headers::new(),
                &make_handler(),
            ))
        }

        fn post(&self, url: &str, body: &str) -> http_tests::TestResponse {
            make_test_response(request::post(
                &("http://localhost:3000".to_owned() + url),
                Headers::new(),
                body,
                &make_handler(),
            ))
        }
    }

    #[test]
    fn test_iron_integration() {
        let integration = TestIronIntegration;

        http_tests::run_http_test_suite(&integration);
    }

    fn context_factory(_: &mut Request) -> Database {
        Database::new()
    }

    fn make_test_response(response: IronResult<Response>) -> http_tests::TestResponse {
        let response = response.expect("Error response from GraphQL handler");
        let status_code = response
            .status
            .expect("No status code returned from handler")
            .to_u16() as i32;
        let content_type = String::from_utf8(
            response
                .headers
                .get_raw("content-type")
                .expect("No content type header from handler")[0]
                .clone(),
        ).expect("Content-type header invalid UTF-8");
        let body = response::extract_body_to_string(response);

        http_tests::TestResponse {
            status_code: status_code,
            body: Some(body),
            content_type: content_type,
        }
    }

    fn make_handler() -> Box<Handler> {
        Box::new(GraphQLHandler::new(
            context_factory,
            Database::new(),
            EmptyMutation::<Database>::new(),
        ))
    }
}
<commit_msg>Fix warning in `iron_juniper`<commit_after>/*!

# juniper_iron

This repository contains the [Iron][Iron] web framework integration for
[Juniper][Juniper], a [GraphQL][GraphQL] implementation for Rust.

For documentation, including guides and examples, check out [Juniper][Juniper].

A basic usage example can also be found in the [Api documentation][documentation].

## Links

* [Juniper][Juniper]
* [Api Reference][documentation]
* [Iron framework][Iron]

## Integrating with Iron

For example, continuing from the schema created above and using Iron to expose
the schema on an HTTP endpoint supporting both GET and POST requests:

```rust,no_run
extern crate iron;
# #[macro_use] extern crate juniper;
# extern crate juniper_iron;
# use std::collections::HashMap;

use iron::prelude::*;
use juniper_iron::GraphQLHandler;
use juniper::{Context, EmptyMutation};

# use juniper::FieldResult;
#
# struct User { id: String, name: String, friend_ids: Vec<String>  }
# struct QueryRoot;
# struct Database { users: HashMap<String, User> }
#
# graphql_object!(User: Database |&self| {
#     field id() -> FieldResult<&String> {
#         Ok(&self.id)
#     }
#
#     field name() -> FieldResult<&String> {
#         Ok(&self.name)
#     }
#
#     field friends(&executor) -> FieldResult<Vec<&User>> {
#         Ok(self.friend_ids.iter()
#             .filter_map(|id| executor.context().users.get(id))
#             .collect())
#     }
# });
#
# graphql_object!(QueryRoot: Database |&self| {
#     field user(&executor, id: String) -> FieldResult<Option<&User>> {
#         Ok(executor.context().users.get(&id))
#     }
# });

// This function is executed for every request. Here, we would realistically
// provide a database connection or similar. For this example, we'll be
// creating the database from scratch.
fn context_factory(_: &mut Request) -> Database {
    Database {
        users: vec![
            ( "1000".to_owned(), User {
                id: "1000".to_owned(), name: "Robin".to_owned(),
                friend_ids: vec!["1001".to_owned()] } ),
            ( "1001".to_owned(), User {
                id: "1001".to_owned(), name: "Max".to_owned(),
                friend_ids: vec!["1000".to_owned()] } ),
        ].into_iter().collect()
    }
}

impl Context for Database {}

fn main() {
    // GraphQLHandler takes a context factory function, the root object,
    // and the mutation object. If we don't have any mutations to expose, we
    // can use the empty tuple () to indicate absence.
    let graphql_endpoint = GraphQLHandler::new(
        context_factory, QueryRoot, EmptyMutation::<Database>::new());

    // Start serving the schema at the root on port 8080.
    Iron::new(graphql_endpoint).http("localhost:8080").unwrap();
}

```

See the the [`GraphQLHandler`][3] documentation for more information on what request methods are
supported.

[3]: ./struct.GraphQLHandler.html
[Iron]: https://github.com/iron/iron
[Juniper]: https://github.com/graphql-rust/juniper
[GraphQL]: http://graphql.org
[documentation]: https://docs.rs/juniper_iron

*/

#[macro_use]
extern crate iron;
#[cfg(test)]
extern crate iron_test;
extern crate juniper;
extern crate serde_json;
extern crate urlencoded;

use iron::prelude::*;
use iron::middleware::Handler;
use iron::mime::Mime;
use iron::status;
use iron::method;
use urlencoded::{UrlDecodingError, UrlEncodedQuery};

use std::io::Read;
use std::error::Error;
use std::fmt;

use serde_json::error::Error as SerdeError;

use juniper::{GraphQLType, InputValue, RootNode};
use juniper::http;

/// Handler that executes GraphQL queries in the given schema
///
/// The handler responds to GET requests and POST requests only. In GET
/// requests, the query should be supplied in the `query` URL parameter, e.g.
/// `http://localhost:3000/graphql?query={hero{name}}`.
///
/// POST requests support both queries and variables. POST a JSON document to
/// this endpoint containing the field `"query"` and optionally `"variables"`.
/// The variables should be a JSON object containing the variable to value
/// mapping.
pub struct GraphQLHandler<'a, CtxFactory, Query, Mutation, CtxT>
where
    CtxFactory: Fn(&mut Request) -> CtxT + Send + Sync + 'static,
    CtxT: 'static,
    Query: GraphQLType<Context = CtxT> + Send + Sync + 'static,
    Mutation: GraphQLType<Context = CtxT> + Send + Sync + 'static,
{
    context_factory: CtxFactory,
    root_node: RootNode<'a, Query, Mutation>,
}

/// Handler that renders GraphiQL - a graphical query editor interface
pub struct GraphiQLHandler {
    graphql_url: String,
}

fn get_single_value<T>(mut values: Vec<T>) -> IronResult<T> {
    if values.len() == 1 {
        Ok(values.remove(0))
    } else {
        Err(GraphQLIronError::InvalidData("Duplicate URL query parameter").into())
    }
}

fn parse_url_param(params: Option<Vec<String>>) -> IronResult<Option<String>> {
    if let Some(values) = params {
        get_single_value(values).map(Some)
    } else {
        Ok(None)
    }
}

fn parse_variable_param(params: Option<Vec<String>>) -> IronResult<Option<InputValue>> {
    if let Some(values) = params {
        Ok(
            serde_json::from_str::<InputValue>(get_single_value(values)?.as_ref())
                .map(Some)
                .map_err(GraphQLIronError::Serde)?,
        )
    } else {
        Ok(None)
    }
}

impl<'a, CtxFactory, Query, Mutation, CtxT> GraphQLHandler<'a, CtxFactory, Query, Mutation, CtxT>
where
    CtxFactory: Fn(&mut Request) -> CtxT + Send + Sync + 'static,
    CtxT: 'static,
    Query: GraphQLType<Context = CtxT, TypeInfo = ()> + Send + Sync + 'static,
    Mutation: GraphQLType<Context = CtxT, TypeInfo = ()> + Send + Sync + 'static,
{
    /// Build a new GraphQL handler
    ///
    /// The context factory will receive the Iron request object and is
    /// expected to construct a context object for the given schema. This can
    /// be used to construct e.g. database connections or similar data that
    /// the schema needs to execute the query.
    pub fn new(context_factory: CtxFactory, query: Query, mutation: Mutation) -> Self {
        GraphQLHandler {
            context_factory: context_factory,
            root_node: RootNode::new(query, mutation),
        }
    }

    fn handle_get(&self, req: &mut Request) -> IronResult<http::GraphQLRequest> {
        let url_query_string = req.get_mut::<UrlEncodedQuery>()
            .map_err(|e| GraphQLIronError::Url(e))?;

        let input_query = parse_url_param(url_query_string.remove("query"))?
            .ok_or_else(|| GraphQLIronError::InvalidData("No query provided"))?;
        let operation_name = parse_url_param(url_query_string.remove("operationName"))?;
        let variables = parse_variable_param(url_query_string.remove("variables"))?;

        Ok(http::GraphQLRequest::new(
            input_query,
            operation_name,
            variables,
        ))
    }

    fn handle_post(&self, req: &mut Request) -> IronResult<http::GraphQLRequest> {
        let mut request_payload = String::new();
        itry!(req.body.read_to_string(&mut request_payload));

        Ok(
            serde_json::from_str::<http::GraphQLRequest>(request_payload.as_str())
                .map_err(|err| GraphQLIronError::Serde(err))?,
        )
    }

    fn execute(&self, context: &CtxT, request: http::GraphQLRequest) -> IronResult<Response> {
        let response = request.execute(&self.root_node, context);
        let content_type = "application/json".parse::<Mime>().unwrap();
        let json = serde_json::to_string_pretty(&response).unwrap();
        let status = if response.is_ok() {
            status::Ok
        } else {
            status::BadRequest
        };
        Ok(Response::with((content_type, status, json)))
    }
}

impl GraphiQLHandler {
    /// Build a new GraphiQL handler targeting the specified URL.
    ///
    /// The provided URL should point to the URL of the attached `GraphQLHandler`. It can be
    /// relative, so a common value could be `"/graphql"`.
    pub fn new(graphql_url: &str) -> GraphiQLHandler {
        GraphiQLHandler {
            graphql_url: graphql_url.to_owned(),
        }
    }
}

impl<'a, CtxFactory, Query, Mutation, CtxT> Handler
    for GraphQLHandler<'a, CtxFactory, Query, Mutation, CtxT>
where
    CtxFactory: Fn(&mut Request) -> CtxT + Send + Sync + 'static,
    CtxT: 'static,
    Query: GraphQLType<Context = CtxT, TypeInfo = ()> + Send + Sync + 'static,
    Mutation: GraphQLType<Context = CtxT, TypeInfo = ()> + Send + Sync + 'static,
    'a: 'static,
{
    fn handle(&self, mut req: &mut Request) -> IronResult<Response> {
        let context = (self.context_factory)(req);

        let graphql_request = match req.method {
            method::Get => self.handle_get(&mut req)?,
            method::Post => self.handle_post(&mut req)?,
            _ => return Ok(Response::with(status::MethodNotAllowed)),
        };

        self.execute(&context, graphql_request)
    }
}

impl Handler for GraphiQLHandler {
    fn handle(&self, _: &mut Request) -> IronResult<Response> {
        let content_type = "text/html".parse::<Mime>().unwrap();

        Ok(Response::with((
            content_type,
            status::Ok,
            juniper::graphiql::graphiql_source(&self.graphql_url),
        )))
    }
}

#[derive(Debug)]
enum GraphQLIronError {
    Serde(SerdeError),
    Url(UrlDecodingError),
    InvalidData(&'static str),
}

impl fmt::Display for GraphQLIronError {
    fn fmt(&self, mut f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            GraphQLIronError::Serde(ref err) => fmt::Display::fmt(err, &mut f),
            GraphQLIronError::Url(ref err) => fmt::Display::fmt(err, &mut f),
            GraphQLIronError::InvalidData(ref err) => fmt::Display::fmt(err, &mut f),
        }
    }
}

impl Error for GraphQLIronError {
    fn description(&self) -> &str {
        match *self {
            GraphQLIronError::Serde(ref err) => err.description(),
            GraphQLIronError::Url(ref err) => err.description(),
            GraphQLIronError::InvalidData(ref err) => err,
        }
    }

    fn cause(&self) -> Option<&Error> {
        match *self {
            GraphQLIronError::Serde(ref err) => Some(err),
            GraphQLIronError::Url(ref err) => Some(err),
            GraphQLIronError::InvalidData(_) => None,
        }
    }
}

impl From<GraphQLIronError> for IronError {
    fn from(err: GraphQLIronError) -> IronError {
        let message = format!("{}", err);
        IronError::new(err, (status::BadRequest, message))
    }
}

#[cfg(test)]
mod tests {
    use iron::prelude::*;
    use iron_test::{request, response};
    use iron::{Handler, Headers};

    use juniper::tests::model::Database;
    use juniper::http::tests as http_tests;
    use juniper::EmptyMutation;

    use super::GraphQLHandler;

    struct TestIronIntegration;

    impl http_tests::HTTPIntegration for TestIronIntegration {
        fn get(&self, url: &str) -> http_tests::TestResponse {
            make_test_response(request::get(
                &("http://localhost:3000".to_owned() + url),
                Headers::new(),
                &make_handler(),
            ))
        }

        fn post(&self, url: &str, body: &str) -> http_tests::TestResponse {
            make_test_response(request::post(
                &("http://localhost:3000".to_owned() + url),
                Headers::new(),
                body,
                &make_handler(),
            ))
        }
    }

    #[test]
    fn test_iron_integration() {
        let integration = TestIronIntegration;

        http_tests::run_http_test_suite(&integration);
    }

    fn context_factory(_: &mut Request) -> Database {
        Database::new()
    }

    fn make_test_response(response: IronResult<Response>) -> http_tests::TestResponse {
        let response = response.expect("Error response from GraphQL handler");
        let status_code = response
            .status
            .expect("No status code returned from handler")
            .to_u16() as i32;
        let content_type = String::from_utf8(
            response
                .headers
                .get_raw("content-type")
                .expect("No content type header from handler")[0]
                .clone(),
        ).expect("Content-type header invalid UTF-8");
        let body = response::extract_body_to_string(response);

        http_tests::TestResponse {
            status_code: status_code,
            body: Some(body),
            content_type: content_type,
        }
    }

    fn make_handler() -> Box<Handler> {
        Box::new(GraphQLHandler::new(
            context_factory,
            Database::new(),
            EmptyMutation::<Database>::new(),
        ))
    }
}
<|endoftext|>


<commit_before>use definitions::bytecode;
use definitions::typedef::*;
use error::*;
use ieee754::Ieee754;
use num::traits::Num;
use num::traits::cast::FromPrimitive;
use output::Mountable;
use std::fs::File;
use std::io::prelude::*;
use std::mem;
use std::ops::{BitOrAssign, ShlAssign};
use std::path::Path;

/// We can adjust the buffer register count here
pub const BUF_REG_COUNT: usize = 32;

/// A register type for comparing two values
struct CompareRegister {
    cra: Word,
    crb: Word,
}

#[derive(Default)]
struct ImageData {
    /// The currently loaded image
    data: Image,
    /// The program counter
    pc: Address,
}

impl ImageData {
    pub fn from_path<P: AsRef<Path>>(&mut self, path: P) -> VMResult<()> {
        let mut image_file = File::open(path).chain_err(|| "unable to open game image file")?;
        image_file.read_to_end(&mut self.data).chain_err(|| "unable to read game image file")?;

        Ok(())
    }

    fn advance_pc(&mut self) {
        self.pc += 1;
    }

    fn current_byte(&mut self) -> VMResult<Byte> {
        if self.pc < self.data.len() {
            Ok(self.data[self.pc])
        } else {
            bail!("program counter out of bounds");
        }
    }

    fn jmp(&mut self, addr: Address) {
        self.pc = addr;
    }

    fn read<T: FromPrimitive + Num + ShlAssign<u8> + BitOrAssign>(&mut self) -> VMResult<T> {
        // Build a Word from single bytes
        let mut res: T = T::zero();

        let length = mem::size_of::<T>();

        for _ in 0..length {
            res <<= 8u8;
            self.advance_pc();
            let current_byte = self.current_byte().chain_err(|| "unable to read current byte")?;
            if let Some(number) = T::from_u8(current_byte) {
                res |= number;
            } else {
                bail!("unable to convert from u8");
            }

        }

        Ok(res)
    }
}

#[derive(Default)]
struct StackData {
    /// The stack pointer
    ptr: Address,
    data: Vec<Word>,
}

/// The whole state of the VM
pub struct VM {
    /// The buffer registers
    buf_regs: [Word; BUF_REG_COUNT],
    cmp_reg: CompareRegister,
    image: ImageData,
    stack: StackData,
}

impl VM {
    pub fn new() -> VM {
        VM {
            image: ImageData::default(),
            stack: StackData::default(),
            buf_regs: [0; BUF_REG_COUNT],
            cmp_reg: CompareRegister { cra: 0, crb: 0 },
        }
    }

    pub fn exec<P: AsRef<Path>>(&mut self, path: P) -> VMResult<()> {
        self.image.from_path(path)?;

        while self.image.pc < self.image.data.len() {
            let byte = self.image.current_byte().chain_err(|| "unable to read current byte")?;

            match byte {
                bytecode::HALT => break,
                bytecode::ADD => self.add().chain_err(|| "unable to execute 'add' instruction")?,
                bytecode::SUB => self.sub().chain_err(|| "unable to execute 'sub' instruction")?,
                bytecode::MUL => self.mul().chain_err(|| "unable to execute 'mul' instruction")?,
                bytecode::DIV => self.div().chain_err(|| "unable to execute 'div' instruction")?,
                bytecode::PUSH => {
                    let res = self.image.read().chain_err(|| "unable to read word")?;

                    self.push_word(res).chain_err(|| "unable to push value to the stack")?;
                }
                bytecode::JMP => {
                    let addr: Word = self.image.read().chain_err(|| "unable to read word")?;

                    self.image.jmp(addr as Address);
                    continue;
                }
                bytecode::JZ => {
                    let addr: Word = self.image.read().chain_err(|| "unable to read word")?;

                    let top_of_stack = self.peek_number()
                        .chain_err(|| "unable to get current top of stack")?;

                    if top_of_stack == 0.0 {
                        self.image.jmp(addr as Address);
                        continue;
                    }
                }
                bytecode::JNZ => {
                    let addr: Word = self.image.read().chain_err(|| "unable to read word")?;

                    let top_of_stack = self.peek_number()
                        .chain_err(|| "unable to get current top of stack")?;

                    if top_of_stack != 0.0 {
                        self.image.jmp(addr as Address);
                        continue;
                    }
                }
                _ => {
                    bail!(
                        "unexpected opcode {:02x} at address {:?}",
                        byte,
                        self.image.pc
                    )
                }
            }

            self.image.advance_pc();
        }

        Ok(())
    }

    pub fn mount<T: Mountable>(&mut self, device: T) -> VMResult<()> {
        device.run();

        Ok(())
    }

    fn push_word(&mut self, value: Word) -> VMResult<()> {
        if !self.stack.data.is_empty() {
            self.stack.ptr += 1;
        }

        self.stack.data.push(value);

        Ok(())
    }

    fn push_number(&mut self, value: Number) -> VMResult<()> {
        self.push_word(value.bits())
    }

    fn pop_word(&mut self) -> VMResult<Word> {
        if self.stack.data.is_empty() {
            bail!("unable to pop word off an empty Stack");
        }

        let res = self.stack.data.remove(self.stack.ptr);
        if !self.stack.data.is_empty() {
            self.stack.ptr -= 1;
        }

        Ok(res)
    }

    fn pop_number(&mut self) -> VMResult<Number> {
        let top = self.pop_word().chain_err(|| "unable to pop word off the stack")?;
        Ok(Number::from_bits(top))
    }

    fn add(&mut self) -> VMResult<()> {
        let b = self.pop_number().chain_err(|| "unable to pop word off the stack")?;
        let a = self.pop_number().chain_err(|| "unable to pop word off the stack")?;
        self.push_number(a + b).chain_err(|| "unable to push value to the stack")?;
        Ok(())
    }

    fn sub(&mut self) -> VMResult<()> {
        let b = self.pop_number().chain_err(|| "unable to pop word off the stack")?;
        let a = self.pop_number().chain_err(|| "unable to pop word off the stack")?;
        self.push_number(a - b).chain_err(|| "unable to push to stack")?;
        Ok(())
    }

    fn mul(&mut self) -> VMResult<()> {
        let b = self.pop_number().chain_err(|| "unable to pop word off the stack")?;
        let a = self.pop_number().chain_err(|| "unable to pop word off the stack")?;
        self.push_number(a * b).chain_err(|| "unable to push to stack")?;
        Ok(())
    }

    fn div(&mut self) -> VMResult<()> {
        let b = self.pop_number().chain_err(|| "unable to pop word off the stack")?;
        let a = self.pop_number().chain_err(|| "unable to pop word off the stack")?;
        self.push_number(a / b).chain_err(|| "unable to push to stack")?;
        Ok(())
    }

    fn peek_word(&mut self) -> VMResult<Word> {
        if self.stack.ptr < self.stack.data.len() {
            Ok(self.stack.data[self.stack.ptr])
        } else {
            bail!("stack pointer out of bounds");
        }
    }

    fn peek_number(&mut self) -> VMResult<Number> {
        let top = self.peek_word().chain_err(|| "unable to peek for word")?;
        Ok(Number::from_bits(top))
    }
}
<commit_msg>Moved stack methods into separate struct<commit_after>use definitions::bytecode;
use definitions::typedef::*;
use error::*;
use ieee754::Ieee754;
use num::traits::Num;
use num::traits::cast::FromPrimitive;
use output::Mountable;
use std::fs::File;
use std::io::prelude::*;
use std::mem;
use std::ops::{BitOrAssign, ShlAssign};
use std::path::Path;

/// We can adjust the buffer register count here
pub const BUF_REG_COUNT: usize = 32;

/// A register type for comparing two values
struct CompareRegister {
    cra: Word,
    crb: Word,
}

#[derive(Default)]
struct ImageData {
    /// The currently loaded image
    data: Image,
    /// The program counter
    pc: Address,
}

impl ImageData {
    pub fn from_path<P: AsRef<Path>>(&mut self, path: P) -> VMResult<()> {
        let mut image_file = File::open(path).chain_err(|| "unable to open game image file")?;
        image_file.read_to_end(&mut self.data).chain_err(|| "unable to read game image file")?;

        Ok(())
    }

    fn advance_pc(&mut self) {
        self.pc += 1;
    }

    fn current_byte(&mut self) -> VMResult<Byte> {
        if self.pc < self.data.len() {
            Ok(self.data[self.pc])
        } else {
            bail!("program counter out of bounds");
        }
    }

    fn jmp(&mut self, addr: Address) {
        self.pc = addr;
    }

    fn read_next<T: FromPrimitive + Num + ShlAssign<u8> + BitOrAssign>(&mut self) -> VMResult<T> {
        // Build a Word from single bytes
        let mut res: T = T::zero();

        let length = mem::size_of::<T>();

        for _ in 0..length {
            res <<= 8u8;
            self.advance_pc();
            let current_byte = self.current_byte().chain_err(|| "unable to read current byte")?;
            if let Some(number) = T::from_u8(current_byte) {
                res |= number;
            } else {
                bail!("unable to convert from u8");
            }

        }

        Ok(res)
    }
}

#[derive(Default)]
struct StackData {
    /// The stack pointer
    ptr: Address,
    data: Vec<Word>,
}

impl StackData {
    fn peek_word(&mut self) -> VMResult<Word> {
        if self.ptr < self.data.len() {
            Ok(self.data[self.ptr])
        } else {
            bail!("stack pointer out of bounds");
        }
    }

    fn peek_number(&mut self) -> VMResult<Number> {
        let top = self.peek_word().chain_err(|| "unable to peek for word")?;
        Ok(Number::from_bits(top))
    }

    fn push_word(&mut self, value: Word) -> VMResult<()> {
        if !self.data.is_empty() {
            self.ptr += 1;
        }

        self.data.push(value);

        Ok(())
    }

    fn push_number(&mut self, value: Number) -> VMResult<()> {
        self.push_word(value.bits())
    }

    fn pop_word(&mut self) -> VMResult<Word> {
        if self.data.is_empty() {
            bail!("unable to pop word off an empty Stack");
        }

        let res = self.data.remove(self.ptr);
        if !self.data.is_empty() {
            self.ptr -= 1;
        }

        Ok(res)
    }

    fn pop_number(&mut self) -> VMResult<Number> {
        let top = self.pop_word().chain_err(|| "unable to pop word off the stack")?;
        Ok(Number::from_bits(top))
    }

    fn add(&mut self) -> VMResult<()> {
        let b = self.pop_number().chain_err(|| "unable to pop word off the stack")?;
        let a = self.pop_number().chain_err(|| "unable to pop word off the stack")?;
        self.push_number(a + b).chain_err(|| "unable to push value to the stack")?;
        Ok(())
    }

    fn sub(&mut self) -> VMResult<()> {
        let b = self.pop_number().chain_err(|| "unable to pop word off the stack")?;
        let a = self.pop_number().chain_err(|| "unable to pop word off the stack")?;
        self.push_number(a - b).chain_err(|| "unable to push to stack")?;
        Ok(())
    }

    fn mul(&mut self) -> VMResult<()> {
        let b = self.pop_number().chain_err(|| "unable to pop word off the stack")?;
        let a = self.pop_number().chain_err(|| "unable to pop word off the stack")?;
        self.push_number(a * b).chain_err(|| "unable to push to stack")?;
        Ok(())
    }

    fn div(&mut self) -> VMResult<()> {
        let b = self.pop_number().chain_err(|| "unable to pop word off the stack")?;
        let a = self.pop_number().chain_err(|| "unable to pop word off the stack")?;
        self.push_number(a / b).chain_err(|| "unable to push to stack")?;
        Ok(())
    }
}

/// The whole state of the VM
pub struct VM {
    /// The buffer registers
    buf_regs: [Word; BUF_REG_COUNT],
    cmp_reg: CompareRegister,
    image: ImageData,
    stack: StackData,
}

impl VM {
    pub fn new() -> VM {
        VM {
            image: ImageData::default(),
            stack: StackData::default(),
            buf_regs: [0; BUF_REG_COUNT],
            cmp_reg: CompareRegister { cra: 0, crb: 0 },
        }
    }

    pub fn exec<P: AsRef<Path>>(&mut self, path: P) -> VMResult<()> {
        self.image.from_path(path)?;

        while self.image.pc < self.image.data.len() {
            let byte = self.image.current_byte().chain_err(|| "unable to read current byte")?;

            match byte {
                bytecode::HALT => break,
                bytecode::ADD => {
                    self.stack.add().chain_err(|| "unable to execute 'add' instruction")?
                }
                bytecode::SUB => {
                    self.stack.sub().chain_err(|| "unable to execute 'sub' instruction")?
                }
                bytecode::MUL => {
                    self.stack.mul().chain_err(|| "unable to execute 'mul' instruction")?
                }
                bytecode::DIV => {
                    self.stack.div().chain_err(|| "unable to execute 'div' instruction")?
                }
                bytecode::PUSH => {
                    let res = self.image.read_next().chain_err(|| "unable to read word")?;

                    self.stack.push_word(res).chain_err(|| "unable to push value to the stack")?;
                }
                bytecode::JMP => {
                    let addr: Word = self.image.read_next().chain_err(|| "unable to read word")?;

                    self.image.jmp(addr as Address);
                    continue;
                }
                bytecode::JZ => {
                    let addr: Word = self.image.read_next().chain_err(|| "unable to read word")?;

                    let top_of_stack = self.stack
                        .peek_number()
                        .chain_err(|| "unable to get current top of stack")?;

                    if top_of_stack == 0.0 {
                        self.image.jmp(addr as Address);
                        continue;
                    }
                }
                bytecode::JNZ => {
                    let addr: Word = self.image.read_next().chain_err(|| "unable to read word")?;

                    let top_of_stack = self.stack
                        .peek_number()
                        .chain_err(|| "unable to get current top of stack")?;

                    if top_of_stack != 0.0 {
                        self.image.jmp(addr as Address);
                        continue;
                    }
                }
                _ => {
                    bail!(
                        "unexpected opcode {:02x} at address {:?}",
                        byte,
                        self.image.pc
                    )
                }
            }

            self.image.advance_pc();
        }

        Ok(())
    }

    pub fn mount<T: Mountable>(&mut self, device: T) -> VMResult<()> {
        device.run();

        Ok(())
    }
}
<|endoftext|>


<commit_before>extern crate robots;

use robots::actors::{Actor,ActorCell};
use std::sync::Mutex;
use std::any::Any;
use std::thread;
use std::time;
use super::super::gpioaccess::{DirectionProxied,PinProxyContract,PwmProxyContract};
use super::super::gpioaccess::proxyimpl::{PinProxy,PwmProxy};

#[derive(Copy, Clone, PartialEq,Debug)]
pub enum PinCommands {
	Blink(u64),
	Switch,
}

pub struct PinActor {
	pinproxy :  Mutex<PinProxy>,
}

impl Actor for PinActor {
	fn receive(&self, _message: Box<Any>, _context: ActorCell) {
		if let Ok(_message) = Box::<Any>::downcast::<PinCommands>(_message){
			match *_message {
				PinCommands::Blink(times) => {
					let pin = self.pinproxy.lock().unwrap();
					match pin.export() {
						Ok(()) => {
							println!("Pin exported");
							for _ in 1..times {
								pin.set_direction(DirectionProxied::Out);
								pin.set_direction(DirectionProxied::High);
								thread::sleep(time::Duration::from_millis(200));
								pin.set_direction(DirectionProxied::Low);
								thread::sleep(time::Duration::from_millis(200));
								println!("Blink");
							}
							match pin.unexport() {
								Ok(()) => {
									println!("Pin unexported");
								}
								_ => {}
							}
						}
						_ => {}
					}
				},
				PinCommands::Switch => { }
			}
		}
	}
}

impl PinActor{
	pub fn new(pin_number: u64) -> PinActor {
		PinActor{ pinproxy : Mutex::new(PinProxy::new(pin_number)) }
	}
}

#[derive(Copy, Clone, PartialEq,Debug)]
pub enum PwmCommands {
	MoveToDegree(u16)
}

pub struct PwmActor {
	pwmproxy :  Mutex<PwmProxy>,
}

impl Actor for PwmActor {
	fn receive(&self, _message: Box<Any>, _context: ActorCell) {
		println!("pwm received message");
		if let Ok(_message) = Box::<Any>::downcast::<PwmCommands>(_message){
			println!("pwm recognized command");
			match *_message {
				PwmCommands::MoveToDegree(degree) => {
					println!("pwm movetodegree");
					let pwm = self.pwmproxy.lock().unwrap();
					match pwm.export() {
						Ok(()) => {
							println!("Pwm exported");
							match pwm.enable(true)
							{
								Ok(()) => {
									println!("Pwm enable");
									match pwm.set_period_ns(20_000)
									{
										Ok(()) => {
											println!("Pwm setting period");
											for x in 1..10 {
												println!("Pwm {}",x);
												pwm.increase_to_max(1000, 20);
												pwm.decrease_to_minimum(1000, 20);
											}
										}
										_ => println!("Pwm set period failed")
									}
								}
								_ => println!("Pwm enabled failed")
							}
							match pwm.unexport() {
								Ok(()) => {
									println!("Pwm unexported");
								}
								_ => println!("Pwm unexport failed")
							}
						}
						_ => println!("Pwm export failed")
					}
					println!("pwm done");
				}
			}
		}
	}
}

impl PwmActor{
	pub fn new(number: u32) -> PwmActor {
		match PwmProxy::new(0,number)
		{
			Ok(pwmproxy) =>  PwmActor{ pwmproxy : Mutex::new(pwmproxy) },
			_ => { panic!("Can't create pwm actor!") },
		}
	}
}<commit_msg>first set period then enable<commit_after>extern crate robots;

use robots::actors::{Actor,ActorCell};
use std::sync::Mutex;
use std::any::Any;
use std::thread;
use std::time;
use super::super::gpioaccess::{DirectionProxied,PinProxyContract,PwmProxyContract};
use super::super::gpioaccess::proxyimpl::{PinProxy,PwmProxy};

#[derive(Copy, Clone, PartialEq,Debug)]
pub enum PinCommands {
	Blink(u64),
	Switch,
}

pub struct PinActor {
	pinproxy :  Mutex<PinProxy>,
}

impl Actor for PinActor {
	fn receive(&self, _message: Box<Any>, _context: ActorCell) {
		if let Ok(_message) = Box::<Any>::downcast::<PinCommands>(_message){
			match *_message {
				PinCommands::Blink(times) => {
					let pin = self.pinproxy.lock().unwrap();
					match pin.export() {
						Ok(()) => {
							println!("Pin exported");
							for _ in 1..times {
								pin.set_direction(DirectionProxied::Out);
								pin.set_direction(DirectionProxied::High);
								thread::sleep(time::Duration::from_millis(200));
								pin.set_direction(DirectionProxied::Low);
								thread::sleep(time::Duration::from_millis(200));
								println!("Blink");
							}
							match pin.unexport() {
								Ok(()) => {
									println!("Pin unexported");
								}
								_ => {}
							}
						}
						_ => {}
					}
				},
				PinCommands::Switch => { }
			}
		}
	}
}

impl PinActor{
	pub fn new(pin_number: u64) -> PinActor {
		PinActor{ pinproxy : Mutex::new(PinProxy::new(pin_number)) }
	}
}

#[derive(Copy, Clone, PartialEq,Debug)]
pub enum PwmCommands {
	MoveToDegree(u16)
}

pub struct PwmActor {
	pwmproxy :  Mutex<PwmProxy>,
}

impl Actor for PwmActor {
	fn receive(&self, _message: Box<Any>, _context: ActorCell) {
		println!("pwm received message");
		if let Ok(_message) = Box::<Any>::downcast::<PwmCommands>(_message){
			println!("pwm recognized command");
			match *_message {
				PwmCommands::MoveToDegree(degree) => {
					println!("pwm movetodegree");
					let pwm = self.pwmproxy.lock().unwrap();
					match pwm.export() {
						Ok(()) => {
							println!("Pwm exported");
							match pwm.set_period_ns(20_000)
							{
								Ok(()) => {
									println!("Pwm setting period");
									match pwm.enable(true)
									{
										Ok(()) => {
											println!("Pwm enable");
											for x in 1..10 {
												println!("Pwm {}",x);
												pwm.increase_to_max(1000, 20);
												pwm.decrease_to_minimum(1000, 20);
											}
										}
										_ => println!("Pwm enabled failed")
									}
								}
								_ => println!("Pwm set period failed")
							}
							match pwm.unexport() {
								Ok(()) => {
									println!("Pwm unexported");
								}
								_ => println!("Pwm unexport failed")
							}
						}
						_ => println!("Pwm export failed")
					}
					println!("pwm done");
				}
			}
		}
	}
}

impl PwmActor{
	pub fn new(number: u32) -> PwmActor {
		match PwmProxy::new(0,number)
		{
			Ok(pwmproxy) =>  PwmActor{ pwmproxy : Mutex::new(pwmproxy) },
			_ => { panic!("Can't create pwm actor!") },
		}
	}
}<|endoftext|>