<commit_before>extern crate byteorder;
extern crate slab;

#[macro_use]
extern crate futures;

#[macro_use]
extern crate tokio_core;

use std::env;
use std::net::SocketAddr;
use std::rc::Rc;
use std::cell::{Cell, RefCell};

use byteorder::{LittleEndian, ByteOrder};
use slab::Slab;
use futures::{Async, Poll, Future};
use futures::stream::Stream;
use tokio_core::io::{read_exact, write_all, Io};
use tokio_core::net::TcpListener;
use tokio_core::reactor::Core;

struct ReadStream<R> where R: ::std::io::Read {
    reader: R,
    buffer: Vec<u8>,
    pos: usize,
    frame_end: Option<u8>,
}

impl <R> ReadStream<R> where R: ::std::io::Read {
    fn new(reader: R) -> ReadStream<R> {
        ReadStream {
            reader: reader,
            buffer: Vec::new(),
            pos: 0,
            frame_end: None,
        }
    }
}

impl <R> Stream for ReadStream<R> where R: ::std::io::Read {
    type Item = Vec<u8>;
    type Error = ::std::io::Error;

    fn poll(&mut self) -> Poll<Option<Self::Item>, Self::Error> {
        loop {
            if let Some(frame_end) = self.frame_end {
                let n = try_nb!(self.reader.read(&mut self.buffer[self.pos..frame_end as usize]));
                self.pos += n;
                if self.pos == frame_end as usize {
                    self.pos = 0;
                    let result = ::std::mem::replace(&mut self.buffer, Vec::new());
                    return Ok(Async::Ready(Some(result)))
                }
            } else {
                let mut buf = [0u8];
                let n = try_nb!(self.reader.read(&mut buf));
                if n == 0 { // EOF
                    return Ok(Async::Ready(None))
                }

                self.frame_end = Some(buf[0]);
                self.buffer = vec![0; buf[0] as usize];
            }
        }
    }
}

pub fn main() {
    let addr = env::args().nth(1).unwrap_or("127.0.0.1:8080".to_string());
    let addr = addr.parse::<SocketAddr>().unwrap();

    let mut l = Core::new().unwrap();
    let handle = l.handle();

    // Create a TCP listener which will listen for incoming connections
    let socket = TcpListener::bind(&addr, &handle).unwrap();

    // Once we've got the TCP listener, inform that we have it
    println!("Listening on: {}", addr);

    let subscribers: Rc<RefCell<Slab<::write_queue::Sender, usize>>> =
        Rc::new(RefCell::new(Slab::with_capacity(1024)));

    let done = socket.incoming().for_each(move |(socket, _addr)| {
        // what's the spec?
        // first byte: 0 means publisher, 1 means subscriber.

        let subscribers = subscribers.clone();
        let header = [0u8; 1];
        let future = read_exact(socket, header).and_then(move |(socket, header)| -> Box<Future<Item=(),Error=::std::io::Error>> {
            println!("OK {:?}", header);
            match header[0] {
                0 => {
                    // publisher
                    let num_read = Rc::new(Cell::new(0u64));
                    let num_read1 = num_read.clone();
                    let done = futures::lazy(|| Ok(socket.split()))
                        .and_then(|(reader, writer)| {
                            ReadStream::new(reader).for_each(move |buf| {
                                num_read1.set(num_read1.get() + 1);
                                for ref mut sender in subscribers.borrow_mut().iter_mut() {
                                    if sender.len() < 5 {
                                        drop(sender.send(buf.clone()));
                                    }
                                }
                                Ok(())
                            }).and_then(move |()| {
                                let mut word = [0u8; 8];
                                <LittleEndian as ByteOrder>::write_u64(&mut word, num_read.get());
                                write_all(writer, word).map(|_| ())
                            })
                        });

                    Box::new(done)
                }
                1 => {
                    // subscriber

                    let (sender, queue) = ::write_queue::write_queue(socket);

                    let idx = match subscribers.borrow_mut().insert(sender) {
                        Ok(idx) => idx,
                        Err(_) => unimplemented!(), // should grow the slab.
                    };

                    Box::new(queue.then(move |_| {
                        subscribers.borrow_mut().remove(idx).unwrap();
                        Ok(())
                    }))
                }
                _ => {
                    // error
                    unimplemented!()
                }
            }
        }).map_err(|e| {
            println!("error: {}", e);
        });
        handle.spawn(future);

        // frame format: first byte is length of body. Then there is body.
        Ok(())
    });

    l.run(done).unwrap();
}

pub mod write_queue {
    use std::collections::VecDeque;
    use std::rc::Rc;
    use std::cell::RefCell;
    use futures::{self, task, Async, Future, Poll, Complete, Oneshot};
    use tokio_core::io::WriteAll;

    enum State<W> where W: ::std::io::Write {
        WritingHeader(W, Vec<u8>, Complete<Vec<u8>>),
        Writing(WriteAll<W, Vec<u8>>, Complete<Vec<u8>>),
        BetweenWrites(W),
        Empty,
    }

    /// A write of messages being written.
    pub struct WriteQueue<W> where W: ::std::io::Write {
        inner: Rc<RefCell<Inner>>,
        state: State<W>,
    }

    struct Inner {
        queue: VecDeque<(Vec<u8>, Complete<Vec<u8>>)>,
        sender_count: usize,
        task: Option<task::Task>,
    }

    pub struct Sender {
        inner: Rc<RefCell<Inner>>,
    }

    impl Clone for Sender {
        fn clone(&self) -> Sender {
            self.inner.borrow_mut().sender_count += 1;
            Sender { inner: self.inner.clone() }
        }
    }

    impl Drop for Sender {
        fn drop(&mut self) {
            self.inner.borrow_mut().sender_count -= 1;
        }
    }

    pub fn write_queue<W>(writer: W) -> (Sender, WriteQueue<W>)
        where W: ::std::io::Write
    {
        let inner = Rc::new(RefCell::new(Inner {
            queue: VecDeque::new(),
            task: None,
            sender_count: 1,
        }));

        let queue = WriteQueue {
            inner: inner.clone(),
            state: State::BetweenWrites(writer),
        };

        let sender = Sender { inner: inner };

        (sender, queue)
    }

    impl Sender {
        /// Enqueues a message to be written.
        pub fn send(&mut self, message: Vec<u8>) -> Oneshot<Vec<u8>> {
            let (complete, oneshot) = futures::oneshot();
            self.inner.borrow_mut().queue.push_back((message, complete));

            match self.inner.borrow_mut().task.take() {
                Some(t) => t.unpark(),
                None => (),
            }

            oneshot
        }

        /// Returns the number of messages queued to be written, not including any in-progress write.
        pub fn len(&mut self) -> usize {
            self.inner.borrow().queue.len()
        }
    }

    enum IntermediateState<W> where W: ::std::io::Write {
        WriteHeaderDone,
        WriteDone(Vec<u8>, W),
        StartWrite(Vec<u8>, Complete<Vec<u8>>),
        Resolve,
    }

    impl <W> Future for WriteQueue<W> where W: ::std::io::Write {
        type Item = W; // Resolves when all senders have been dropped and all messages written.
        type Error = ::std::io::Error;

        fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
            loop {
                let next = match self.state {
                    State::WritingHeader(ref mut write, ref buf, ref mut _complete) => {
                        let n = try_nb!(write.write(&[buf.len() as u8]));
                        match n {
                            0 => unimplemented!(), // TODO return error premature EOF
                            1 => IntermediateState::WriteHeaderDone,
                            _ => unreachable!(),
                        }
                    }
                    State::Writing(ref mut write, ref mut _complete) => {
                        let (w, m) = try_ready!(Future::poll(write));
                        IntermediateState::WriteDone(m, w)
                    }
                    State::BetweenWrites(ref mut _writer) => {
                        let front = self.inner.borrow_mut().queue.pop_front();
                        match front {
                            Some((m, complete)) => {
                                IntermediateState::StartWrite(m, complete)
                            }
                            None => {
                                let count = self.inner.borrow().sender_count;
                                if count == 0 {
                                    IntermediateState::Resolve
                                } else {
                                    self.inner.borrow_mut().task = Some(task::park());
                                    return Ok(Async::NotReady)
                                }
                            }
                        }
                    }
                    State::Empty => unreachable!(),
                };

                match next {
                    IntermediateState::WriteHeaderDone => {
                        let new_state = match ::std::mem::replace(&mut self.state, State::Empty) {
                            State::WritingHeader(writer, buf, complete) => {
                                State::Writing(::tokio_core::io::write_all(writer, buf), complete)
                            }
                            _ => unreachable!(),
                        };
                        self.state = new_state;
                    }
                    IntermediateState::WriteDone(m, w) => {
                        match ::std::mem::replace(&mut self.state, State::BetweenWrites(w)) {
                            State::Writing(_, complete) => {
                                complete.complete(m)
                            }
                            _ => unreachable!(),
                        }
                    }
                    IntermediateState::StartWrite(m, c) => {
                        let new_state = match ::std::mem::replace(&mut self.state, State::Empty) {
                            State::BetweenWrites(w) => {
                                State::WritingHeader(w, m, c)
                            }
                            _ => unreachable!(),
                        };
                        self.state = new_state;
                    }
                    IntermediateState::Resolve => {
                        match ::std::mem::replace(&mut self.state, State::Empty) {
                            State::BetweenWrites(w) => {
                                return Ok(Async::Ready(w))
                            }
                            _ => unreachable!(),
                        }
                    }
                }
            }
        }
    }
}
<commit_msg>grow the slab<commit_after>extern crate byteorder;
extern crate slab;

#[macro_use]
extern crate futures;

#[macro_use]
extern crate tokio_core;

use std::env;
use std::net::SocketAddr;
use std::rc::Rc;
use std::cell::{Cell, RefCell};

use byteorder::{LittleEndian, ByteOrder};
use slab::Slab;
use futures::{Async, Poll, Future};
use futures::stream::Stream;
use tokio_core::io::{read_exact, write_all, Io};
use tokio_core::net::TcpListener;
use tokio_core::reactor::Core;

struct ReadStream<R> where R: ::std::io::Read {
    reader: R,
    buffer: Vec<u8>,
    pos: usize,
    frame_end: Option<u8>,
}

impl <R> ReadStream<R> where R: ::std::io::Read {
    fn new(reader: R) -> ReadStream<R> {
        ReadStream {
            reader: reader,
            buffer: Vec::new(),
            pos: 0,
            frame_end: None,
        }
    }
}

impl <R> Stream for ReadStream<R> where R: ::std::io::Read {
    type Item = Vec<u8>;
    type Error = ::std::io::Error;

    fn poll(&mut self) -> Poll<Option<Self::Item>, Self::Error> {
        loop {
            if let Some(frame_end) = self.frame_end {
                let n = try_nb!(self.reader.read(&mut self.buffer[self.pos..frame_end as usize]));
                self.pos += n;
                if self.pos == frame_end as usize {
                    self.pos = 0;
                    let result = ::std::mem::replace(&mut self.buffer, Vec::new());
                    return Ok(Async::Ready(Some(result)))
                }
            } else {
                let mut buf = [0u8];
                let n = try_nb!(self.reader.read(&mut buf));
                if n == 0 { // EOF
                    return Ok(Async::Ready(None))
                }

                self.frame_end = Some(buf[0]);
                self.buffer = vec![0; buf[0] as usize];
            }
        }
    }
}

pub fn main() {
    let addr = env::args().nth(1).unwrap_or("127.0.0.1:8080".to_string());
    let addr = addr.parse::<SocketAddr>().unwrap();

    let mut l = Core::new().unwrap();
    let handle = l.handle();

    // Create a TCP listener which will listen for incoming connections
    let socket = TcpListener::bind(&addr, &handle).unwrap();

    // Once we've got the TCP listener, inform that we have it
    println!("Listening on: {}", addr);

    let subscribers: Rc<RefCell<Slab<::write_queue::Sender, usize>>> =
        Rc::new(RefCell::new(Slab::with_capacity(1024)));

    let done = socket.incoming().for_each(move |(socket, _addr)| {
        // what's the spec?
        // first byte: 0 means publisher, 1 means subscriber.

        let subscribers = subscribers.clone();
        let header = [0u8; 1];
        let future = read_exact(socket, header).and_then(move |(socket, header)| -> Box<Future<Item=(),Error=::std::io::Error>> {
            println!("OK {:?}", header);
            match header[0] {
                0 => {
                    // publisher
                    let num_read = Rc::new(Cell::new(0u64));
                    let num_read1 = num_read.clone();
                    let done = futures::lazy(|| Ok(socket.split()))
                        .and_then(|(reader, writer)| {
                            ReadStream::new(reader).for_each(move |buf| {
                                num_read1.set(num_read1.get() + 1);
                                for ref mut sender in subscribers.borrow_mut().iter_mut() {
                                    if sender.len() < 5 {
                                        drop(sender.send(buf.clone()));
                                    }
                                }
                                Ok(())
                            }).and_then(move |()| {
                                let mut word = [0u8; 8];
                                <LittleEndian as ByteOrder>::write_u64(&mut word, num_read.get());
                                write_all(writer, word).map(|_| ())
                            })
                        });

                    Box::new(done)
                }
                1 => {
                    // subscriber

                    let (sender, queue) = ::write_queue::write_queue(socket);

                    if !subscribers.borrow().has_available() {
                        let len = subscribers.borrow().len();
                        subscribers.borrow_mut().reserve_exact(len);
                    }
                    let idx = match subscribers.borrow_mut().insert(sender) {
                        Ok(idx) => idx,
                        Err(_) => unreachable!(),
                    };

                    Box::new(queue.then(move |_| {
                        subscribers.borrow_mut().remove(idx).unwrap();
                        Ok(())
                    }))
                }
                _ => {
                    // error
                    unimplemented!()
                }
            }
        }).map_err(|e| {
            println!("error: {}", e);
        });
        handle.spawn(future);

        // frame format: first byte is length of body. Then there is body.
        Ok(())
    });

    l.run(done).unwrap();
}

pub mod write_queue {
    use std::collections::VecDeque;
    use std::rc::Rc;
    use std::cell::RefCell;
    use futures::{self, task, Async, Future, Poll, Complete, Oneshot};
    use tokio_core::io::WriteAll;

    enum State<W> where W: ::std::io::Write {
        WritingHeader(W, Vec<u8>, Complete<Vec<u8>>),
        Writing(WriteAll<W, Vec<u8>>, Complete<Vec<u8>>),
        BetweenWrites(W),
        Empty,
    }

    /// A write of messages being written.
    pub struct WriteQueue<W> where W: ::std::io::Write {
        inner: Rc<RefCell<Inner>>,
        state: State<W>,
    }

    struct Inner {
        queue: VecDeque<(Vec<u8>, Complete<Vec<u8>>)>,
        sender_count: usize,
        task: Option<task::Task>,
    }

    pub struct Sender {
        inner: Rc<RefCell<Inner>>,
    }

    impl Clone for Sender {
        fn clone(&self) -> Sender {
            self.inner.borrow_mut().sender_count += 1;
            Sender { inner: self.inner.clone() }
        }
    }

    impl Drop for Sender {
        fn drop(&mut self) {
            self.inner.borrow_mut().sender_count -= 1;
        }
    }

    pub fn write_queue<W>(writer: W) -> (Sender, WriteQueue<W>)
        where W: ::std::io::Write
    {
        let inner = Rc::new(RefCell::new(Inner {
            queue: VecDeque::new(),
            task: None,
            sender_count: 1,
        }));

        let queue = WriteQueue {
            inner: inner.clone(),
            state: State::BetweenWrites(writer),
        };

        let sender = Sender { inner: inner };

        (sender, queue)
    }

    impl Sender {
        /// Enqueues a message to be written.
        pub fn send(&mut self, message: Vec<u8>) -> Oneshot<Vec<u8>> {
            let (complete, oneshot) = futures::oneshot();
            self.inner.borrow_mut().queue.push_back((message, complete));

            match self.inner.borrow_mut().task.take() {
                Some(t) => t.unpark(),
                None => (),
            }

            oneshot
        }

        /// Returns the number of messages queued to be written, not including any in-progress write.
        pub fn len(&mut self) -> usize {
            self.inner.borrow().queue.len()
        }
    }

    enum IntermediateState<W> where W: ::std::io::Write {
        WriteHeaderDone,
        WriteDone(Vec<u8>, W),
        StartWrite(Vec<u8>, Complete<Vec<u8>>),
        Resolve,
    }

    impl <W> Future for WriteQueue<W> where W: ::std::io::Write {
        type Item = W; // Resolves when all senders have been dropped and all messages written.
        type Error = ::std::io::Error;

        fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
            loop {
                let next = match self.state {
                    State::WritingHeader(ref mut write, ref buf, ref mut _complete) => {
                        let n = try_nb!(write.write(&[buf.len() as u8]));
                        match n {
                            0 => unimplemented!(), // TODO return error premature EOF
                            1 => IntermediateState::WriteHeaderDone,
                            _ => unreachable!(),
                        }
                    }
                    State::Writing(ref mut write, ref mut _complete) => {
                        let (w, m) = try_ready!(Future::poll(write));
                        IntermediateState::WriteDone(m, w)
                    }
                    State::BetweenWrites(ref mut _writer) => {
                        let front = self.inner.borrow_mut().queue.pop_front();
                        match front {
                            Some((m, complete)) => {
                                IntermediateState::StartWrite(m, complete)
                            }
                            None => {
                                let count = self.inner.borrow().sender_count;
                                if count == 0 {
                                    IntermediateState::Resolve
                                } else {
                                    self.inner.borrow_mut().task = Some(task::park());
                                    return Ok(Async::NotReady)
                                }
                            }
                        }
                    }
                    State::Empty => unreachable!(),
                };

                match next {
                    IntermediateState::WriteHeaderDone => {
                        let new_state = match ::std::mem::replace(&mut self.state, State::Empty) {
                            State::WritingHeader(writer, buf, complete) => {
                                State::Writing(::tokio_core::io::write_all(writer, buf), complete)
                            }
                            _ => unreachable!(),
                        };
                        self.state = new_state;
                    }
                    IntermediateState::WriteDone(m, w) => {
                        match ::std::mem::replace(&mut self.state, State::BetweenWrites(w)) {
                            State::Writing(_, complete) => {
                                complete.complete(m)
                            }
                            _ => unreachable!(),
                        }
                    }
                    IntermediateState::StartWrite(m, c) => {
                        let new_state = match ::std::mem::replace(&mut self.state, State::Empty) {
                            State::BetweenWrites(w) => {
                                State::WritingHeader(w, m, c)
                            }
                            _ => unreachable!(),
                        };
                        self.state = new_state;
                    }
                    IntermediateState::Resolve => {
                        match ::std::mem::replace(&mut self.state, State::Empty) {
                            State::BetweenWrites(w) => {
                                return Ok(Async::Ready(w))
                            }
                            _ => unreachable!(),
                        }
                    }
                }
            }
        }
    }
}
<|endoftext|>


<commit_before>use std::io;
use std::env;

struct MeanFeatures {
    wordlen: i32,	// The length of each of these
    sentlen: i32,	// characteristics will be averaged
    paralen: i32,	// and compared with other source.
}

struct FreqFeatures {
    comma: i32,
    semicolon: i32,
    quote: i32,
    bangs: i32,
    dashes: i32,
    ands: i32,
    buts: i32,
    however: i32,
    condition: i32,		// Did not want to create confusion with if.
    thats: i32,
    more: i32,
    musts: i32,
    mights: i32,
    thises: i32,
    very: i32,
}

fn main() {
    let args: Vec<String> = env::args().collect();
}<commit_msg>Added args code<commit_after>#![allow(dead_code)]

use std::io;
use std::env;
use std::fs::File;
use std::error::Error;
use std::path::Path;

struct MeanFeatures {
    wordlen: i32,	// The length of each of these characteristics will be
    sentlen: i32,	// averaged and compared with other source.
    //paralen: i32,	// Removing this for now.
}

struct FreqFeatures {
    comma: i32,
    semicolon: i32,
    quote: i32,
    bangs: i32,
    dashes: i32,
    ands: i32,
    buts: i32,
    however: i32,
    condition: i32,		// Prevent confusion with if.
    thats: i32,
    more: i32,
    musts: i32,
    mights: i32,
    thises: i32,
    very: i32,
}

fn main() {
    let args: Vec<String> = env::args().collect();
    let file1 = match File::open(&args[1]) {
        Err(why) => panic!("Couldn't open {}: {}", &args[1], Error::description(&why)),
        Ok(file1) => file1,
    };
    let file2 = match File::open(&args[2]) {
        Err(why) => panic!("Couldn't open {}: {}", &args[2], Error::description(&why)),
        Ok(file2) => file2,
    };
}<|endoftext|>


<commit_before>#[macro_use]
extern crate lazy_static;
extern crate regex;

use std::thread;
use std::sync::mpsc::{channel, Sender};
use std::path::Path;
use std::fs::File;
use std::io;
use std::io::prelude::*;
use std::io::SeekFrom;

mod models;

fn init_log() -> io::Result<()> {
    let log_config = b"[Achievements]
LogLevel=1
FilePrinting=true
ConsolePrinting=true
ScreenPrinting=false

[Power]
LogLevel=1
FilePrinting=true
ConsolePrinting=true
ScreenPrinting=false";

    let hs_dir = Path::new(r"C:\Program Files (x86)\Hearthstone\log.config");
    if !hs_dir.exists() {
        let mut handle = File::create(hs_dir)?;
        handle.write_all(log_config)?;
    }

    Ok(())
}

fn tail_log(tx: Sender<models::Play>) -> io::Result<()> {
    let hearthstone_path = Path::new(r"C:\Program Files (x86)\Hearthstone\Logs\Power.log");
    let mut handle = io::BufReader::new(File::open(hearthstone_path)?);
    handle.seek(SeekFrom::End(0))?;

    loop {
        let mut b = String::new();
        match handle.read_line(&mut b) {
            Ok(0) => {
                continue;
            }
            Ok(_) => {
                match parse_log_line(&b) {
                    Some(play) => tx.send(play).unwrap(),
                    _ => (),
                }
            }
            Err(err) => println!("Error!, {}", err),
        }
    }
}

fn parse_log_line(line: &str) -> Option<models::Play> {
    lazy_static! {
        static ref CARD_UPDATE_PATTERN: regex::Regex = regex::Regex::new(
            r"^.*id=(?P<id>\d*) .*cardId=(?P<card_id>[a-zA-Z0-9_]*) .*player=(?P<player>\d*)")
                .unwrap();
        static ref GAME_COMPLETE_PATTERN: regex::Regex = regex::Regex::new(
            r"^.*TAG_CHANGE Entity=GameEntity tag=STATE value=COMPLETE.*$")
                .unwrap();
    }

    if GAME_COMPLETE_PATTERN.is_match(line) {
        return None;
    }

    CARD_UPDATE_PATTERN
        .captures(line)
        .and_then(|group| {
            let id = group.name("id").map(|m| m.as_str());
            let card_id = group.name("card_id").map(|m| m.as_str());
            let player = group.name("player").map(|m| m.as_str());

            match (id, card_id, player) {
                (Some(id), Some(card_id), Some(player)) if card_id != "" => {
                    Some(models::Play {
                             id: id.to_string(),
                             card_id: card_id.to_string(),
                             player: player.to_string(),
                         })
                }
                _ => None,
            }
        })
}

fn main() {
    println!("Initializing log config");
    init_log().unwrap();
    println!("Initialized log config");

    let (tx, rx) = channel();

    println!("Spawning log thread");
    thread::spawn(|| tail_log(tx));
    println!("Spawned log thread");

    println!("Start receiving events");

    let mut game_state = models::GameState::default();
    while let Ok(play) = rx.recv() {
        let updated = game_state.handle_play(play);
        if updated {
            println!("New state: {:?}", game_state);
            println!();
        }
    }
}
<commit_msg>Sleep log thread when no new bytes are written<commit_after>#[macro_use]
extern crate lazy_static;
extern crate regex;

use std::thread;
use std::sync::mpsc::{channel, Sender};
use std::path::Path;
use std::fs::File;
use std::io;
use std::io::prelude::*;
use std::io::SeekFrom;
use std::time::Duration;

mod models;

fn init_log() -> io::Result<()> {
    let log_config = b"[Achievements]
LogLevel=1
FilePrinting=true
ConsolePrinting=true
ScreenPrinting=false

[Power]
LogLevel=1
FilePrinting=true
ConsolePrinting=true
ScreenPrinting=false";

    let hs_dir = Path::new(r"C:\Program Files (x86)\Hearthstone\log.config");
    if !hs_dir.exists() {
        let mut handle = File::create(hs_dir)?;
        handle.write_all(log_config)?;
    }

    Ok(())
}

fn tail_log(tx: Sender<models::Play>) -> io::Result<()> {
    let hearthstone_path = Path::new(r"C:\Program Files (x86)\Hearthstone\Logs\Power.log");
    let mut handle = io::BufReader::new(File::open(hearthstone_path)?);
    handle.seek(SeekFrom::End(0))?;

    loop {
        let mut b = String::new();
        match handle.read_line(&mut b) {
            Ok(0) => {
                thread::sleep(Duration::from_millis(250));
            }
            Ok(_) => {
                match parse_log_line(&b) {
                    Some(play) => tx.send(play).unwrap(),
                    _ => (),
                }
            }
            Err(err) => println!("Error!, {}", err),
        }
    }
}

fn parse_log_line(line: &str) -> Option<models::Play> {
    lazy_static! {
        static ref CARD_UPDATE_PATTERN: regex::Regex = regex::Regex::new(
            r"^.*id=(?P<id>\d*) .*cardId=(?P<card_id>[a-zA-Z0-9_]*) .*player=(?P<player>\d*)")
                .unwrap();
        static ref GAME_COMPLETE_PATTERN: regex::Regex = regex::Regex::new(
            r"^.*TAG_CHANGE Entity=GameEntity tag=STATE value=COMPLETE.*$")
                .unwrap();
    }

    if GAME_COMPLETE_PATTERN.is_match(line) {
        return None;
    }

    CARD_UPDATE_PATTERN
        .captures(line)
        .and_then(|group| {
            let id = group.name("id").map(|m| m.as_str());
            let card_id = group.name("card_id").map(|m| m.as_str());
            let player = group.name("player").map(|m| m.as_str());

            match (id, card_id, player) {
                (Some(id), Some(card_id), Some(player)) if card_id != "" => {
                    Some(models::Play {
                             id: id.to_string(),
                             card_id: card_id.to_string(),
                             player: player.to_string(),
                         })
                }
                _ => None,
            }
        })
}

fn main() {
    println!("Initializing log config");
    init_log().unwrap();
    println!("Initialized log config");

    let (tx, rx) = channel();

    println!("Spawning log thread");
    thread::spawn(|| tail_log(tx));
    println!("Spawned log thread");

    println!("Start receiving events");

    let mut game_state = models::GameState::default();
    while let Ok(play) = rx.recv() {
        let updated = game_state.handle_play(play);
        if updated {
            println!("New state: {:?}", game_state);
            println!();
        }
    }
}
<|endoftext|>


<commit_before>extern crate telegram_bot;

use telegram_bot::*;

fn main() {
    let api = Api::from_env("TELEGRAM_BOT_TOKEN").unwrap();
    let mut listener = api.listener(ListeningMethod::LongPoll(None));

    let res = listener.listen(|u| {
        if let Some(m) = u.message {
            match m.msg {
                MessageType::Text(t) => {
                    let mut values = t.splitn(2, " ");
                    if let Some(c) = values.next() {
                        match c {
                            "/huy" => { try!(api.send_message(m.chat.id(), format!("{} думает, {} хуй", m.from.first_name, values.next().unwrap_or("Костя")), None, None, None)); },
                            _ => {}
                        }
                    }
                },
                _ => {}
            }
        }

        Ok(ListeningAction::Continue)
    });

    if let Err(e) = res {
        println!("An error occured: {}", e);
    }
}
<commit_msg>made infinite loop<commit_after>extern crate telegram_bot;

use telegram_bot::*;

fn main() {
    let api = Api::from_env("TELEGRAM_BOT_TOKEN").unwrap();
    let mut listener = api.listener(ListeningMethod::LongPoll(None));

    loop {
        let res = listener.listen(|u| {
            if let Some(m) = u.message {
                match m.msg {
                    MessageType::Text(t) => {
                        let mut values = t.splitn(2, " ");
                        if let Some(c) = values.next() {
                            match c {
                                "/huy" => { try!(api.send_message(m.chat.id(), format!("{} думает, {} хуй", m.from.first_name, values.next().unwrap_or("Костя")), None, None, None)); },
                                _ => {}
                            }
                        }
                    },
                    _ => {}
                }
            }

            Ok(ListeningAction::Continue)
        });

        if let Err(e) = res {
            println!("An error occured: {}", e);
        }
    }
}
<|endoftext|>


<commit_before>#[macro_use] extern crate conrod;
extern crate find_folder;
extern crate piston_window;
extern crate netlion;

use std::thread;
use std::sync::{Arc, Mutex};

use conrod::{Labelable, Positionable, Sizeable, Theme, Widget, Canvas, Text, TextBox, DropDownList, Button};
use conrod::color::{Color, Colorable};
use piston_window::{EventLoop, Glyphs, PistonWindow, UpdateEvent, WindowSettings};
use netlion::*;

/// Conrod is backend agnostic. Here, we define the `piston_window` backend to use for our `Ui`.
type Backend = (<piston_window::G2d<'static> as conrod::Graphics>::Texture, Glyphs);
type Ui = conrod::Ui<Backend>;
type UiCell<'a> = conrod::UiCell<'a, Backend>;

fn main() {
    // Construct the window.
    let mut window: PistonWindow = WindowSettings::new("netlion", [800, 600])
        .exit_on_esc(true).build().unwrap();

    // construct our `Ui`.
    let mut ui = {
        let assets = find_folder::Search::KidsThenParents(3, 5)
            .for_folder("conrod").unwrap();
        let font_path = assets.join("assets/fonts/NotoSans/NotoSans-Regular.ttf");
        let theme = Theme::default();
        let glyph_cache = Glyphs::new(&font_path, window.factory.clone());
        Ui::new(glyph_cache.unwrap(), theme)
    };

    let port = &mut String::from("8080");
    let mut net_mode = String::from("tcp");
    let options = &mut vec![String::from("udp"), String::from("tcp")];
    let mut sel_option = Some(1);
    let text = Arc::new(Mutex::new(String::from("Welcome to netlion:\n")));

    window.set_ups(60);

    // Poll events from the window.
    while let Some(event) = window.next() {
        ui.handle_event(&event);
        event.update(|_| ui.set_widgets(|mut ui| {
            let ui = &mut ui;

            // Generate the ID for the Button COUNTER.
            widget_ids!(CANVAS, TEXT_BOX, START, PROTO_LIST, RESULT);

            // Create a background canvas upon which we'll place the button.
            Canvas::new().pad(40.0).set(CANVAS, ui);

            TextBox::new(port)
                .top_left_of(CANVAS)
                .w_h(200.0, 40.0)
                .react(|s: &mut String|{println!("react: {}", s)})
                .set(TEXT_BOX, ui);

            // Draw the button and increment `count` if pressed.
            DropDownList::new(options, &mut sel_option)
                .right_from(TEXT_BOX, 10.0)
                .w_h(150.0, 40.0)
                .react(|selected_idx: &mut Option<usize>, new_idx: usize, s: &str| {
                    *selected_idx = Some(new_idx);
                    net_mode = String::from(s);
                })
                .set(PROTO_LIST, ui);

            Button::new()
                .right_from(PROTO_LIST, 10.0)
                .w_h(80.0, 40.0)
                .label(&String::from("Start"))
                .react(|| {
                    let text = text.clone();
                    start(port, text);
                })
                .set(START, ui);

            Text::new(text.lock().unwrap().as_str())
                // .below(TEXT_BOX)
                .top_left_of(TEXT_BOX)
                .color(Color::Rgba(0.5, 0.5, 0.5, 1.0))
                .align_text_left()
                .line_spacing(10.0)
                .set(RESULT, ui);
        }));

        window.draw_2d(&event, |c, g| ui.draw_if_changed(c, g));
    }
}

fn start(port: &String, text: Arc<Mutex<String>>) {
    let addr = String::from("0.0.0.0:") + port;
    let text = text.clone();

    println!("Starting listener on port {}", port);
    thread::spawn(move || listen_tcp(addr.as_str(), text));
}
<commit_msg>Fix alignment of the text area<commit_after>#[macro_use] extern crate conrod;
extern crate find_folder;
extern crate piston_window;
extern crate netlion;

use std::thread;
use std::sync::{Arc, Mutex};

use conrod::{Labelable, Positionable, Sizeable, Theme, Widget, Canvas, Text, TextBox, DropDownList, Button};
use conrod::color::{Color, Colorable};
use piston_window::{EventLoop, Glyphs, PistonWindow, UpdateEvent, WindowSettings};
use netlion::*;

/// Conrod is backend agnostic. Here, we define the `piston_window` backend to use for our `Ui`.
type Backend = (<piston_window::G2d<'static> as conrod::Graphics>::Texture, Glyphs);
type Ui = conrod::Ui<Backend>;
type UiCell<'a> = conrod::UiCell<'a, Backend>;

fn main() {
    // Construct the window.
    let mut window: PistonWindow = WindowSettings::new("netlion", [800, 600])
        .exit_on_esc(true).build().unwrap();

    // construct our `Ui`.
    let mut ui = {
        let assets = find_folder::Search::KidsThenParents(3, 5)
            .for_folder("conrod").unwrap();
        let font_path = assets.join("assets/fonts/NotoSans/NotoSans-Regular.ttf");
        let theme = Theme::default();
        let glyph_cache = Glyphs::new(&font_path, window.factory.clone());
        Ui::new(glyph_cache.unwrap(), theme)
    };

    let port = &mut String::from("8080");
    let mut net_mode = String::from("tcp");
    let options = &mut vec![String::from("udp"), String::from("tcp")];
    let mut sel_option = Some(1);
    let text = Arc::new(Mutex::new(String::from("Welcome to netlion:\n")));

    window.set_ups(60);

    // Poll events from the window.
    while let Some(event) = window.next() {
        ui.handle_event(&event);
        event.update(|_| ui.set_widgets(|mut ui| {
            let ui = &mut ui;

            // Generate the ID for the Button COUNTER.
            widget_ids!(CANVAS, TEXT_BOX, START, PROTO_LIST, RESULT);

            // Create a background canvas upon which we'll place the button.
            Canvas::new().pad(40.0).set(CANVAS, ui);

            TextBox::new(port)
                .top_left_of(CANVAS)
                .w_h(200.0, 40.0)
                .react(|s: &mut String|{println!("react: {}", s)})
                .set(TEXT_BOX, ui);

            // Draw the button and increment `count` if pressed.
            DropDownList::new(options, &mut sel_option)
                .right_from(TEXT_BOX, 10.0)
                .w_h(150.0, 40.0)
                .react(|selected_idx: &mut Option<usize>, new_idx: usize, s: &str| {
                    *selected_idx = Some(new_idx);
                    net_mode = String::from(s);
                })
                .set(PROTO_LIST, ui);

            Button::new()
                .right_from(PROTO_LIST, 10.0)
                .w_h(80.0, 40.0)
                .label(&String::from("Start"))
                .react(|| {
                    let text = text.clone();
                    start(port, text);
                })
                .set(START, ui);

            Text::new(text.lock().unwrap().as_str())
                .down_from(TEXT_BOX, 10.0)
                .color(Color::Rgba(0.5, 0.5, 0.5, 1.0))
                .align_text_left()
                .line_spacing(10.0)
                .set(RESULT, ui);
        }));

        window.draw_2d(&event, |c, g| ui.draw_if_changed(c, g));
    }
}

fn start(port: &String, text: Arc<Mutex<String>>) {
    let addr = String::from("0.0.0.0:") + port;
    let text = text.clone();

    println!("Starting listener on port {}", port);
    thread::spawn(move || listen_tcp(addr.as_str(), text));
}
<|endoftext|>


<commit_before>use std::fs::File;
use std::io::{Read, Stdin, Result};

#[derive(Debug, Clone, PartialEq)]
enum Instruction {
    MoveLeft(usize),
    MoveRight(usize),
    Inc(u8),
    Dec(u8),
    Input,
    Output,
    LoopEntry(usize),
    LoopExit(usize),
}

use Instruction::*;

#[derive(Debug)]
struct Program {
    instructions: Vec<Instruction>
}

impl Program {
    pub fn new(text: String) -> Program
    {
        // "lex" token stream - aka skip whitespace
        let token = text.chars().filter(move |c| {
            *c == '>' || *c == '<' || *c == '+' || *c == '-' ||
            *c == '.' || *c == ',' || *c == '[' || *c == ']'
        }).collect::<Vec<_>>();
        Program {
            instructions : token.iter().enumerate().map(|(idx, &c)| {
                match c {
                    '<' => MoveLeft(1),
                    '>' => MoveRight(1),
                    '+' => Inc(1),
                    '-' => Dec(1),
                    '.' => Output,
                    ',' => Input,
                    '[' => {
                        let mut bracket_nesting = 1;
                        let mut pc = idx + 1;

                        while (bracket_nesting > 0) && (pc < token.len()) {
                            match token[pc] {
                                '[' => bracket_nesting += 1,
                                ']' => bracket_nesting -= 1,
                                _ => (),
                            };
                            pc += 1;
                        }
                        if 0 == bracket_nesting {
                            pc -= 1;
                        }
                        else {
                            panic!("unmachted '[' at pc={:}", idx);
                        }
                        LoopEntry(pc)
                    },
                    ']' => {
                        let mut bracket_nesting = 1;
                        let mut pc = idx;

                        while (bracket_nesting > 0) && (pc > 0) {
                            pc -= 1;
                            match token[pc] {
                                '[' => bracket_nesting -= 1,
                                ']' => bracket_nesting += 1,
                                _ => (),
                            };
                        }
                        if 0 != bracket_nesting {
                            panic!("unmachted ']' at pc={:}", idx);
                        }
                        LoopExit(pc)
                    },
                    c => panic!("Unknown instruction {:?} at pc={:}", c, idx),
                }
            }).collect::<Vec<_>>()
        }
    }

    pub fn interp(&self) {
        let mut memory = vec![0u8; 30000];

        let mut pc:usize = 0;
        let mut dataptr:usize = 0;
        let mut stdin = std::io::stdin();

        fn get_char(stdin: &mut Stdin) -> u8 {
            let mut buf = [0u8; 1];
            match stdin.read(&mut buf) {
                Err(_) => panic!("Cannot read from stdin"),
                Ok(_) => buf[0]
            }
        }

        while pc < self.instructions.len() {
            match self.instructions[pc] {
                MoveLeft(offset) => dataptr -= offset,
                MoveRight(offset) => dataptr += offset,
                Inc(increment) => memory[dataptr] = memory[dataptr].wrapping_add(increment),
                Dec(decrement) => memory[dataptr] = memory[dataptr].wrapping_sub(decrement),
                Output => print!("{:}", memory[dataptr] as char),
                Input => memory[dataptr] = get_char(&mut stdin),
                LoopEntry(target) => if 0 == memory[dataptr] {
                    pc = target;
                },
                LoopExit(target) => if 0 != memory[dataptr] {
                    pc = target;
                },
                // ref c => panic!("Unknown instruction {:?} at pc={:}", c, pc),
            }
            pc += 1;
        }
    }
}

fn load_program(fname: String) -> Result<Program> {
    let mut file = File::open(fname)?;
    let mut contents: Vec<u8> = Vec::new();
    file.read_to_end(&mut contents)?;
    let text = String::from_utf8(contents).unwrap();

    Ok(Program::new(text))
}

fn main() {
    match load_program("examples/mandelbrot.bf".to_string()) {
        Ok(ref mut p) => {
            //println!("{:?}", p);
            p.interp();
        },
        Err(err) => panic!("Cannot read file because {:?}", err),
    }
}
<commit_msg>simplified parser<commit_after>use std::fs::File;
use std::io::{Read, Stdin, Result};

#[derive(Debug, Clone, PartialEq)]
enum Instruction {
    MoveLeft(usize),
    MoveRight(usize),
    Inc(u8),
    Dec(u8),
    Input,
    Output,
    LoopEntry(usize),
    LoopExit(usize),
}

use Instruction::*;

#[derive(Debug)]
struct Program {
    instructions: Vec<Instruction>
}

impl Program {
    pub fn new(text: String) -> Program {
        // open brackets while parsing
        let mut bracket_stack = Vec::new();
        // idx to patch with index of LoopEntry to patch in
        let mut relocs = Vec::new();
        // "lex" token stream - aka skip whitespace
        let token = text.chars().filter(move |c| {
            *c == '>' || *c == '<' || *c == '+' || *c == '-' ||
            *c == '.' || *c == ',' || *c == '[' || *c == ']'
        });
        let mut instructions = token.enumerate().map(|(idx, c)| {
            match c {
                '<' => MoveLeft(1),
                '>' => MoveRight(1),
                '+' => Inc(1),
                '-' => Dec(1),
                '.' => Output,
                ',' => Input,
                '[' => {
                    bracket_stack.push(idx);
                    // value must be patched later
                    LoopEntry(std::usize::MAX)
                },
                ']' => {
                    if let Some(loop_entry) = bracket_stack.pop() {
                        relocs.push((loop_entry, idx));
                        LoopExit(loop_entry)
                    }
                    else {
                        panic!("Unbalanced {:?} at pc={:}", c, idx);
                    }
                },
                c => panic!("Unknown instruction {:?} at pc={:}", c, idx),
            }
        }).collect::<Vec<_>>();
        if let Some(unbalanced_idx) = bracket_stack.pop() {
            panic!("Unbalanced {:?} at pc={:}", '[', unbalanced_idx);
        }
        for (idx, value) in relocs {
            if idx >= instructions.len() || LoopEntry(std::usize::MAX) != instructions[idx] {
                panic!("Unexpected instruction {:?} at pc={:} for reloc", instructions[idx], idx);
            }
            else {
                instructions[idx] = LoopEntry(value);
            }
        }
        Program {
            instructions : instructions
        }
    }

    pub fn interp(&self) {
        let mut memory = vec![0u8; 30000];

        let mut pc:usize = 0;
        let mut dataptr:usize = 0;
        let mut stdin = std::io::stdin();

        fn get_char(stdin: &mut Stdin) -> u8 {
            let mut buf = [0u8; 1];
            match stdin.read(&mut buf) {
                Err(_) => panic!("Cannot read from stdin"),
                Ok(_) => buf[0]
            }
        }

        while pc < self.instructions.len() {
            match self.instructions[pc] {
                MoveLeft(offset) => dataptr -= offset,
                MoveRight(offset) => dataptr += offset,
                Inc(increment) => memory[dataptr] = memory[dataptr].wrapping_add(increment),
                Dec(decrement) => memory[dataptr] = memory[dataptr].wrapping_sub(decrement),
                Output => print!("{:}", memory[dataptr] as char),
                Input => memory[dataptr] = get_char(&mut stdin),
                LoopEntry(target) => if 0 == memory[dataptr] {
                    pc = target;
                },
                LoopExit(target) => if 0 != memory[dataptr] {
                    pc = target;
                },
                // ref c => panic!("Unknown instruction {:?} at pc={:}", c, pc),
            }
            pc += 1;
        }
    }
}

fn load_program(fname: String) -> Result<Program> {
    let mut file = File::open(fname)?;
    let mut contents: Vec<u8> = Vec::new();
    file.read_to_end(&mut contents)?;
    let text = String::from_utf8(contents).unwrap();

    Ok(Program::new(text))
}

fn main() {
    match load_program("examples/mandelbrot.bf".to_string()) {
        Ok(ref mut p) => {
            //println!("{:?}", p);
            p.interp();
        },
        Err(err) => panic!("Cannot read file because {:?}", err),
    }
}
<|endoftext|>


<commit_before>extern crate fuse;
extern crate libc;
extern crate time;
extern crate hyper;
extern crate rustc_serialize;
extern crate clap;

use std::collections::BTreeMap;
use std::path::Path;
use std::env;
use std::io::prelude::Read;
use libc::{ENOENT, ENOSYS};
use time::Timespec;
use fuse::{FileAttr, FileType, Filesystem, Request, ReplyAttr, ReplyData, ReplyEntry, ReplyDirectory, ReplyOpen};
use hyper::client::{Client, Response};
use rustc_serialize::json::Json;
use clap::{App, Arg};

struct TwitchFileSystem {
    attrs: BTreeMap<u64, FileAttr>,
    inodes: BTreeMap<String, u64>
}

impl TwitchFileSystem {
    fn new() -> TwitchFileSystem {
        let mut attrs = BTreeMap::new();
        let mut inodes = BTreeMap::new();
        let ts = time::now().to_timespec();
        let attr = FileAttr {
            ino: 1,
            size: 0,
            blocks: 0,
            atime: ts,
            mtime: ts,
            ctime: ts,
            crtime: ts,
            kind: FileType::Directory,
            perm: 0o755,
            nlink: 0,
            uid: 0,
            gid: 0,
            rdev: 0,
            flags: 0
        };
        attrs.insert(1, attr);
        inodes.insert("/".to_owned(), 1);
        let mut body = String::new();
        Client::new()
            .get("https://api.twitch.tv/kraken/games/top")
            .send()
            .expect("Couldn't load twitch")
            .read_to_string(&mut body);

        match Json::from_str(&body) {
            Ok(data) => {
                let games = data.find("top").unwrap().as_array().unwrap();
                for (i, game) in games.iter().enumerate() {
                    let attr = FileAttr {
                        ino: i as u64 + 2,
                        size: 0,
                        blocks: 0,
                        atime: ts,
                        mtime: ts,
                        ctime: ts,
                        crtime: ts,
                        kind: FileType::Directory,
                        perm: 0o644,
                        nlink: 0,
                        uid: 0,
                        gid: 0,
                        rdev: 0,
                        flags: 0
                    };
                    let name = game
                        .find_path(&["game", "name"])
                        .unwrap()
                        .as_string()
                        .unwrap();

                    attrs.insert(attr.ino, attr);
                    inodes.insert(name.to_owned(), attr.ino);
                }
            },
            Err(_) => println!("Twitch returned invalid json")
        }
        TwitchFileSystem {attrs: attrs, inodes: inodes}
    }
}

impl Filesystem for TwitchFileSystem {
    fn getattr(&mut self, _req: &Request, ino: u64, reply: ReplyAttr) {
        match self.attrs.get(&ino) {
            Some(attr) => {
                let ttl = Timespec::new(1, 0);
                reply.attr(&ttl, attr);
            },
            None => reply.error(ENOENT)
        }
    }

    fn lookup(&mut self, _req: &Request, parent: u64, name: &Path, reply: ReplyEntry) {
        let inode = match self.inodes.get(name.to_str().unwrap()) {
            Some(inode) => inode,
            None => {
                reply.error(ENOENT);
                return;
            }
        };
        match self.attrs.get(inode) {
            Some(attr) => {
                let ttl = Timespec::new(1, 0);
                reply.entry(&ttl, attr, 0);
            },
            None => reply.error(ENOENT),
        };
    }

    fn readdir(&mut self, _req: &Request, ino: u64, fh: u64, offset: u64, mut reply: ReplyDirectory) {
        if offset == 0 {
            for (game, &inode) in &self.inodes {
                if inode == 1 { continue; }
                let offset = inode;
                reply.add(inode, offset, FileType::RegularFile, &Path::new(game));
            }
            reply.add(1, 0, FileType::Directory, &Path::new("."));
            reply.add(1, 1, FileType::Directory, &Path::new(".."));
        } else if offset == 1 {
            reply.add(1, 0, FileType::Directory, &Path::new("u wot m8"));
        }

        reply.ok();
    }
    fn read(&mut self, _req: &Request, ino: u64, fh: u64, offset: u64, size: u32, reply: ReplyData) {
        reply.data("test".as_bytes());
    }
}

fn main() {
    let matches = App::new("twitch-fs")
        .version(option_env!("CARGO_PKG_VERSION").unwrap_or("unknown version"))
        .arg(Arg::with_name("mountpoint")
             .index(1)
             .required(true))
        .get_matches();

    // unwrap() is safe here because the argument is set as required
    let mountpoint = matches.value_of_os("mountpoint").unwrap();
    let fs = TwitchFileSystem::new();

    fuse::mount(fs , &mountpoint, &[])
}
<commit_msg>Make sure specified mountpoint is actually a directory<commit_after>extern crate fuse;
extern crate libc;
extern crate time;
extern crate hyper;
extern crate rustc_serialize;
extern crate clap;

use std::collections::BTreeMap;
use std::path::Path;
use std::env;
use std::io::prelude::Read;
use libc::{ENOENT, ENOSYS};
use time::Timespec;
use fuse::{FileAttr, FileType, Filesystem, Request, ReplyAttr, ReplyData, ReplyEntry, ReplyDirectory, ReplyOpen};
use hyper::client::{Client, Response};
use rustc_serialize::json::Json;
use clap::{App, Arg};

struct TwitchFileSystem {
    attrs: BTreeMap<u64, FileAttr>,
    inodes: BTreeMap<String, u64>
}

impl TwitchFileSystem {
    fn new() -> TwitchFileSystem {
        let mut attrs = BTreeMap::new();
        let mut inodes = BTreeMap::new();
        let ts = time::now().to_timespec();
        let attr = FileAttr {
            ino: 1,
            size: 0,
            blocks: 0,
            atime: ts,
            mtime: ts,
            ctime: ts,
            crtime: ts,
            kind: FileType::Directory,
            perm: 0o755,
            nlink: 0,
            uid: 0,
            gid: 0,
            rdev: 0,
            flags: 0
        };
        attrs.insert(1, attr);
        inodes.insert("/".to_owned(), 1);
        let mut body = String::new();
        Client::new()
            .get("https://api.twitch.tv/kraken/games/top")
            .send()
            .expect("Couldn't load twitch")
            .read_to_string(&mut body);

        match Json::from_str(&body) {
            Ok(data) => {
                let games = data.find("top").unwrap().as_array().unwrap();
                for (i, game) in games.iter().enumerate() {
                    let attr = FileAttr {
                        ino: i as u64 + 2,
                        size: 0,
                        blocks: 0,
                        atime: ts,
                        mtime: ts,
                        ctime: ts,
                        crtime: ts,
                        kind: FileType::Directory,
                        perm: 0o644,
                        nlink: 0,
                        uid: 0,
                        gid: 0,
                        rdev: 0,
                        flags: 0
                    };
                    let name = game
                        .find_path(&["game", "name"])
                        .unwrap()
                        .as_string()
                        .unwrap();

                    attrs.insert(attr.ino, attr);
                    inodes.insert(name.to_owned(), attr.ino);
                }
            },
            Err(_) => println!("Twitch returned invalid json")
        }
        TwitchFileSystem {attrs: attrs, inodes: inodes}
    }
}

impl Filesystem for TwitchFileSystem {
    fn getattr(&mut self, _req: &Request, ino: u64, reply: ReplyAttr) {
        match self.attrs.get(&ino) {
            Some(attr) => {
                let ttl = Timespec::new(1, 0);
                reply.attr(&ttl, attr);
            },
            None => reply.error(ENOENT)
        }
    }

    fn lookup(&mut self, _req: &Request, parent: u64, name: &Path, reply: ReplyEntry) {
        let inode = match self.inodes.get(name.to_str().unwrap()) {
            Some(inode) => inode,
            None => {
                reply.error(ENOENT);
                return;
            }
        };
        match self.attrs.get(inode) {
            Some(attr) => {
                let ttl = Timespec::new(1, 0);
                reply.entry(&ttl, attr, 0);
            },
            None => reply.error(ENOENT),
        };
    }

    fn readdir(&mut self, _req: &Request, ino: u64, fh: u64, offset: u64, mut reply: ReplyDirectory) {
        if offset == 0 {
            for (game, &inode) in &self.inodes {
                if inode == 1 { continue; }
                let offset = inode;
                reply.add(inode, offset, FileType::RegularFile, &Path::new(game));
            }
            reply.add(1, 0, FileType::Directory, &Path::new("."));
            reply.add(1, 1, FileType::Directory, &Path::new(".."));
        } else if offset == 1 {
            reply.add(1, 0, FileType::Directory, &Path::new("u wot m8"));
        }

        reply.ok();
    }
    fn read(&mut self, _req: &Request, ino: u64, fh: u64, offset: u64, size: u32, reply: ReplyData) {
        reply.data("test".as_bytes());
    }
}

fn is_valid_dir(mountpoint: String) -> Result<(), String> {
    match Path::new(&mountpoint).is_dir() {
        true => Ok(()),
        false => Err("Mountpoint must be a directory".to_string()),
    }
}

fn main() {
    let matches = App::new("twitch-fs")
        .version(option_env!("CARGO_PKG_VERSION").unwrap_or("unknown version"))
        .arg(Arg::with_name("mountpoint")
             .validator(is_valid_dir)
             .index(1)
             .required(true))
        .get_matches();

    // unwrap() is safe here because the argument is set as required
    let mountpoint = matches.value_of_os("mountpoint").unwrap();
    let fs = TwitchFileSystem::new();

    fuse::mount(fs , &mountpoint, &[])
}
<|endoftext|>


<commit_before>use std::fmt;
use std::str::FromStr;

#[derive(Debug, PartialEq)]
enum Atom {
    Number(f64),
    Symbol(String)
}

#[derive(Debug, PartialEq)]
enum Sexp {
    Atom(Atom),
    List(Vec<Sexp>)
}

#[derive(Debug, PartialEq)]
enum ParseAtomError {
    IncorrectSymbolName
}

impl fmt::Display for Atom {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            Atom::Number(n) => {
                write!(f, "{}", n)
            },
            Atom::Symbol(ref name) => {
                write!(f, "'{}", name)
            }
        }
    }
}

impl FromStr for Atom {
    type Err = ParseAtomError;

    fn from_str(s: &str) -> Result<Atom, ParseAtomError> {
        match s.parse::<f64>() {
            Ok(f) => {
                Ok(Atom::Number(f))
            },
            Err(..) => {
                match s.chars().next() {
                    Some(c) if !c.is_numeric() => {
                        Ok(Atom::Symbol(s.to_string()))
                    },
                    _ => {
                        Err(ParseAtomError::IncorrectSymbolName)
                    }
                }
            }
        }
    }
}

fn tokenize(s: &str) -> Vec<String> {
    s.replace("("," ( ")
        .replace(")", " ) ")
        .replace("\n", " ")
        .split(' ')
        .filter(|s| { !s.is_empty() })
        .map(|s| { s.to_string() })
        .collect()
}

#[derive(Debug, PartialEq)]
enum ReadState {
    StartRead,
    OpenList,
    AtomRead(Atom),
    CloseList,
    EndRead,
}

#[derive(Debug, PartialEq)]
enum ReadError {
}

fn read(tokens: Vec<String>) -> Result<Vec<Sexp>, ReadError> {
    let mut state = ReadState::StartRead;
    let mut iter = tokens.iter();
    let mut result = vec![];
    loop {
        match state {
            ReadState::StartRead => {
                match iter.next() {
                    Some(s) if *s == "(" => {
                        state = ReadState::OpenList;
                        result.push(Sexp::List(vec![]));
                    },
                    None => {
                        state = ReadState::EndRead;
                    },
                    _ => {
                        state = ReadState::EndRead;
                    }
                }
            },
            ReadState::OpenList => {
                match iter.next() {
                    Some(s) if *s == ")" => {
                        state = ReadState::CloseList;
                    },
                    Some(s) => {
                        state = ReadState::AtomRead(s.parse::<Atom>().ok().unwrap());
                    },
                    _ => {
                        state = ReadState::EndRead;
                    }
                }
            },
            ReadState::CloseList => {
                match iter.next() {
                    Some(s) if *s == "(" => {
                        state = ReadState::OpenList;
                        result.push(Sexp::List(vec![]));
                    },
                    _ => {
                        state = ReadState::EndRead;
                    }
                }
            },
            ReadState::AtomRead(atom) => {
                if let Some(Sexp::List(mut current_list)) = result.pop() {
                    current_list.push(Sexp::Atom(atom));
                    result.push(Sexp::List(current_list));
                }
                match iter.next() {
                    Some(s) if *s == ")" => {
                        state = ReadState::CloseList;
                    },
                    Some(s) => {
                        state = ReadState::AtomRead(s.parse::<Atom>().ok().unwrap());
                    },
                    _ => {
                        state = ReadState::EndRead;
                    }
                }
            },
            ReadState::EndRead => {
                return Ok(result)
            }
        }
    }
}

#[cfg_attr(test, allow(dead_code))]
fn main() {
}

#[cfg(test)]
mod tests {
    use super::Atom::{self, Number, Symbol};
    use super::Sexp;
    use super::ParseAtomError::IncorrectSymbolName;
    use super::{tokenize, read};

    #[test]
    fn test_parse_integer() {
        assert_eq!(Number(64f64), "64".parse::<Atom>().ok().unwrap())
    }

    #[test]
    fn test_parse_float() {
        assert_eq!(Number(64.5), "64.5".parse::<Atom>().ok().unwrap())
    }

    #[test]
    fn test_parse_symbol() {
        assert_eq!(Symbol("name".to_string()), "name".parse::<Atom>().ok().unwrap())
    }

    #[test]
    fn test_parse_incorrect_symbol_starting_with_digit() {
        assert_eq!(IncorrectSymbolName, "6name".parse::<Atom>().err().unwrap())
    }

    #[test]
    fn test_tokenize_dense_expression() {
        let expected_result = ["(", "def", "a", "1", ")"]
                                .iter()
                                .map(|s| { s.to_string() })
                                .collect();
        assert_eq!(expected_result, tokenize("(def a 1)"))
    }

    #[test]
    fn test_tokenize_sparse_expression() {
        let expected_result = ["(", "def", "a", "1", ")"]
                                .iter()
                                .map(|s| { s.to_string() })
                                .collect();
        assert_eq!(expected_result, tokenize(" ( \n def a\n1)   \n"))
    }

    #[test]
    fn test_read_empty() {
        let expected_result = vec![];
        assert_eq!(expected_result, read(tokenize("")).ok().unwrap())
    }

    #[test]
    fn test_read_single_expression() {
        let expected_result =  vec![Sexp::List(vec![Sexp::Atom(Symbol("def".to_string())),
                                                    Sexp::Atom(Symbol("a".to_string())),
                                                    Sexp::Atom(Number(1f64))])];
        assert_eq!(expected_result, read(tokenize("(def a 1)")).ok().unwrap())
    }

    #[test]
    fn test_read_multiple_expression() {
        let expected_result =  vec![Sexp::List(vec![Sexp::Atom(Symbol("def".to_string())),
                                                    Sexp::Atom(Symbol("a".to_string())),
                                                    Sexp::Atom(Number(1f64))]),
                                    Sexp::List(vec![Sexp::Atom(Symbol("def".to_string())),
                                                    Sexp::Atom(Symbol("b".to_string())),
                                                    Sexp::Atom(Number(2f64))]),
                                    Sexp::List(vec![Sexp::Atom(Symbol("+".to_string())),
                                                    Sexp::Atom(Symbol("a".to_string())),
                                                    Sexp::Atom(Symbol("b".to_string()))])];
        assert_eq!(expected_result, read(tokenize("(def a 1)(def b 2)(+ a b)")).ok().unwrap())
    }
}
<commit_msg>Remove Display impl for Atom<commit_after>use std::str::FromStr;

#[derive(Debug, PartialEq)]
enum Atom {
    Number(f64),
    Symbol(String)
}

#[derive(Debug, PartialEq)]
enum Sexp {
    Atom(Atom),
    List(Vec<Sexp>)
}

#[derive(Debug, PartialEq)]
enum ParseAtomError {
    IncorrectSymbolName
}

impl FromStr for Atom {
    type Err = ParseAtomError;

    fn from_str(s: &str) -> Result<Atom, ParseAtomError> {
        match s.parse::<f64>() {
            Ok(f) => {
                Ok(Atom::Number(f))
            },
            Err(..) => {
                match s.chars().next() {
                    Some(c) if !c.is_numeric() => {
                        Ok(Atom::Symbol(s.to_string()))
                    },
                    _ => {
                        Err(ParseAtomError::IncorrectSymbolName)
                    }
                }
            }
        }
    }
}

fn tokenize(s: &str) -> Vec<String> {
    s.replace("("," ( ")
        .replace(")", " ) ")
        .replace("\n", " ")
        .split(' ')
        .filter(|s| { !s.is_empty() })
        .map(|s| { s.to_string() })
        .collect()
}

#[derive(Debug, PartialEq)]
enum ReadState {
    StartRead,
    OpenList,
    AtomRead(Atom),
    CloseList,
    EndRead,
}

#[derive(Debug, PartialEq)]
enum ReadError {
}

fn read(tokens: Vec<String>) -> Result<Vec<Sexp>, ReadError> {
    let mut state = ReadState::StartRead;
    let mut iter = tokens.iter();
    let mut result = vec![];
    loop {
        match state {
            ReadState::StartRead => {
                match iter.next() {
                    Some(s) if *s == "(" => {
                        state = ReadState::OpenList;
                        result.push(Sexp::List(vec![]));
                    },
                    None => {
                        state = ReadState::EndRead;
                    },
                    _ => {
                        state = ReadState::EndRead;
                    }
                }
            },
            ReadState::OpenList => {
                match iter.next() {
                    Some(s) if *s == ")" => {
                        state = ReadState::CloseList;
                    },
                    Some(s) => {
                        state = ReadState::AtomRead(s.parse::<Atom>().ok().unwrap());
                    },
                    _ => {
                        state = ReadState::EndRead;
                    }
                }
            },
            ReadState::CloseList => {
                match iter.next() {
                    Some(s) if *s == "(" => {
                        state = ReadState::OpenList;
                        result.push(Sexp::List(vec![]));
                    },
                    _ => {
                        state = ReadState::EndRead;
                    }
                }
            },
            ReadState::AtomRead(atom) => {
                if let Some(Sexp::List(mut current_list)) = result.pop() {
                    current_list.push(Sexp::Atom(atom));
                    result.push(Sexp::List(current_list));
                }
                match iter.next() {
                    Some(s) if *s == ")" => {
                        state = ReadState::CloseList;
                    },
                    Some(s) => {
                        state = ReadState::AtomRead(s.parse::<Atom>().ok().unwrap());
                    },
                    _ => {
                        state = ReadState::EndRead;
                    }
                }
            },
            ReadState::EndRead => {
                return Ok(result)
            }
        }
    }
}

#[cfg_attr(test, allow(dead_code))]
fn main() {
}

#[cfg(test)]
mod tests {
    use super::Atom::{self, Number, Symbol};
    use super::Sexp;
    use super::ParseAtomError::IncorrectSymbolName;
    use super::{tokenize, read};

    #[test]
    fn test_parse_integer() {
        assert_eq!(Number(64f64), "64".parse::<Atom>().ok().unwrap())
    }

    #[test]
    fn test_parse_float() {
        assert_eq!(Number(64.5), "64.5".parse::<Atom>().ok().unwrap())
    }

    #[test]
    fn test_parse_symbol() {
        assert_eq!(Symbol("name".to_string()), "name".parse::<Atom>().ok().unwrap())
    }

    #[test]
    fn test_parse_incorrect_symbol_starting_with_digit() {
        assert_eq!(IncorrectSymbolName, "6name".parse::<Atom>().err().unwrap())
    }

    #[test]
    fn test_tokenize_dense_expression() {
        let expected_result = ["(", "def", "a", "1", ")"]
                                .iter()
                                .map(|s| { s.to_string() })
                                .collect();
        assert_eq!(expected_result, tokenize("(def a 1)"))
    }

    #[test]
    fn test_tokenize_sparse_expression() {
        let expected_result = ["(", "def", "a", "1", ")"]
                                .iter()
                                .map(|s| { s.to_string() })
                                .collect();
        assert_eq!(expected_result, tokenize(" ( \n def a\n1)   \n"))
    }

    #[test]
    fn test_read_empty() {
        let expected_result = vec![];
        assert_eq!(expected_result, read(tokenize("")).ok().unwrap())
    }

    #[test]
    fn test_read_single_expression() {
        let expected_result =  vec![Sexp::List(vec![Sexp::Atom(Symbol("def".to_string())),
                                                    Sexp::Atom(Symbol("a".to_string())),
                                                    Sexp::Atom(Number(1f64))])];
        assert_eq!(expected_result, read(tokenize("(def a 1)")).ok().unwrap())
    }

    #[test]
    fn test_read_multiple_expression() {
        let expected_result =  vec![Sexp::List(vec![Sexp::Atom(Symbol("def".to_string())),
                                                    Sexp::Atom(Symbol("a".to_string())),
                                                    Sexp::Atom(Number(1f64))]),
                                    Sexp::List(vec![Sexp::Atom(Symbol("def".to_string())),
                                                    Sexp::Atom(Symbol("b".to_string())),
                                                    Sexp::Atom(Number(2f64))]),
                                    Sexp::List(vec![Sexp::Atom(Symbol("+".to_string())),
                                                    Sexp::Atom(Symbol("a".to_string())),
                                                    Sexp::Atom(Symbol("b".to_string()))])];
        assert_eq!(expected_result, read(tokenize("(def a 1)(def b 2)(+ a b)")).ok().unwrap())
    }
}
<|endoftext|>


<commit_before>extern crate mio;

use mio::*;
use mio::net::{SockAddr};
use mio::net::tcp::{TcpSocket, TcpAcceptor};
use mio::buf::{ByteBuf, MutByteBuf, SliceBuf};

fn main() {
    const SERVER: Token = Token(1);
    let addr = SockAddr::parse("127.0.0.1:13265").unwrap();
    let server = TcpSocket::v4().unwrap()
        .bind(&addr).unwrap()
        .listen(256).unwrap();

    let mut event_loop = EventLoop::<(), ()>::new().unwrap();
    event_loop.register(&server, SERVER).unwrap();

    struct TcpHandler {
        conn: Option<TcpSocket>,
        sock: TcpAcceptor
    };

    impl TcpHandler {
        fn accept(&mut self, event_loop: &mut EventLoop<(), ()>) {
            let conn = self.sock.accept();
            let sock = conn.unwrap().unwrap();
            let tok = Token(2);
            self.conn = Some(sock);
            match self.conn {
                Some(ref c) => { event_loop.register_opt(c, tok, Interest::readable(), PollOpt::edge() | PollOpt::oneshot()); }
                None => { }
            }
        }
    }

    impl Handler<(), ()> for TcpHandler {
        fn readable(&mut self, event_loop: &mut EventLoop<(), ()>, token: Token, _: ReadHint) {
            match token {
                SERVER => {
                    self.accept(event_loop);
                }
                tok => {
                    println!("tok: {}", tok.as_usize());
                    let mut read_buf = ByteBuf::mut_with_capacity(2048);
                    let mut interest = Interest::readable();
                    match self.conn {
                        Some(ref c) => {
                            match c.read(&mut read_buf) {
                                Ok(NonBlock::WouldBlock) => {
                                    panic!("We just got readable, but were unable to read from the socket?");
                                }
                                Ok(NonBlock::Ready(r)) => {
                                    let mut buf = read_buf.flip();
                                    let mut sl = [0; 2048];
                                    buf.read_slice(&mut sl);
                                    print!("{}", String::from_utf8(sl.to_vec()).unwrap());
                                    // self.interest.remove(Interest::readable());
                                    // self.interest.insert(Interest::writable());
                                }
                                Err(e) => {
                                    event_loop.shutdown();
                                    // println!("not implemented; client err={:?}", e);
                                    // interest = Interest::hup();
                                    // self.interest.remove(Interest::readable());
                                }
                            }
                            event_loop.reregister(c, tok, interest, PollOpt::edge() | PollOpt::oneshot());
                        },
                        None => { }
                    }
                }
            }
        }
    }
    let mut tcp_server = TcpHandler {
        conn: None,
        sock: server
    };
    let _ = event_loop.run(&mut tcp_server);
}
<commit_msg>More simplification, adding comments.<commit_after>/*
 * Simple tcp listener, similar to `nc -l 13265`.
 * Will listen for TCP connections on port 13265, accept
 */
extern crate mio;

use mio::*;
use mio::net::{SockAddr};
use mio::net::tcp::{TcpSocket, TcpAcceptor};
use mio::buf::{ByteBuf};

fn main() {
    const SERVER: Token = Token(1);
    let addr = SockAddr::parse("127.0.0.1:13265").unwrap();
    // Listen on `addr`, with a connection backlog of just 1, since we only want to handle one
    // connection. See `man listen`.
    let server = TcpSocket::v4().unwrap()
        .bind(&addr).unwrap()
        .listen(1).unwrap();

    let mut event_loop = EventLoop::<(), ()>::new().unwrap();
    event_loop.register(&server, SERVER).unwrap();

    struct TcpHandler {
        conn: Option<TcpSocket>, // Will store our single socket connection, once established.
        sock: TcpAcceptor // Will store our server.
    };

    impl TcpHandler {
        fn accept(&mut self, event_loop: &mut EventLoop<(), ()>) {
            match self.conn {
                Some(_) => {
                    // If we already have a connection, do nothing.
                    return;
                },
                None => {}
            }
            let conn = self.sock.accept();
            let sock = conn.unwrap().unwrap();
            let tok = Token(2);
            // The following code will move `sock` into our `tcp_server` struct,
            // so we won't be able to access it directly anymore.
            self.conn = Some(sock);
            match self.conn {
                Some(ref c) => {
                    // Register an interest read events with the event_loop. the `edge` option
                    // stipulates that we will only be notified when a read event happens, rather
                    // than as long as reading is possible.
                    // See http://en.wikipedia.org/wiki/Epoll
                    let _ = event_loop.register_opt(c, tok, Interest::readable(), PollOpt::edge());
                }
                None => { }
            }
        }
    }

    impl Handler<(), ()> for TcpHandler {
        fn readable(&mut self, event_loop: &mut EventLoop<(), ()>, token: Token, _: ReadHint) {
            match token {
                SERVER => {
                    // Call `accept` on our `tcp_handler`.
                    self.accept(event_loop);
                }
                Token(2) => {
                    // Artificial limitation -- we'll only read up to 2048 bytes at a time.
                    let mut read_buf = ByteBuf::mut_with_capacity(2048);
                    match self.conn {
                        Some(ref c) => {
                            match c.read(&mut read_buf) {
                                Ok(NonBlock::WouldBlock) => {
                                    panic!("Read operation would block, bailing cuz this shouldn't happen.");
                                }
                                Ok(NonBlock::Ready(_)) => {
                                    // `_` would be the number of bytes read.
                                    // `flip` will return a `ByteBuf` on which we can call
                                    // `read_slice` to get the data available to be read.
                                    // See http://carllerche.github.io/bytes/bytes/struct.ByteBuf.html
                                    let mut buf = read_buf.flip();
                                    let mut sl = [0; 2048];
                                    buf.read_slice(&mut sl);
                                    // Assuming what was written was encoded as UTF8, print what
                                    // was read to STDOUT.
                                    print!("{}", String::from_utf8(sl.to_vec()).unwrap());
                                }
                                Err(e) => {
                                    if e.is_eof() {
                                        println!("Client closed connection, shutting down.");
                                        event_loop.shutdown();
                                    }
                                    else {
                                        panic!(e);
                                    }
                                }
                            }
                        },
                        None => { }
                    }
                },
                _ => { panic!("received token we can't handle".to_string()) }
            }
        }
    }
    let mut tcp_server = TcpHandler {
        conn: None,
        sock: server
    };
    let _ = event_loop.run(&mut tcp_server);
}
<|endoftext|>


<commit_before>#![feature(net)]
#![feature(std_misc)]

use std::thread;
use std::sync::mpsc::{channel, Sender, Receiver};
use std::net::UdpSocket;
use std::net::IpAddr;
use std::old_io::timer;
use std::time::duration::Duration;

// ================================================================================================

const CRTP_VERSION : &'static str = env!("CARGO_PKG_VERSION");

struct SSRC(u32);
struct RtpTimestamp(u32);
struct NtpTimestamp(u64);

struct SenderInfo {
  ntp_ts     : u64, // FIXME: should be NtpTimestamp,
  rtp_ts     : u32, // FIXME: should be RtpTimestamp,
  pckt_count : u32,
  byte_count : u32
}

struct ReportBlock {
  ssrc       : SSRC,
  fract_lost : u8,
  cumul_lost : u32,
  ext_seq    : u32,
  jitter     : u32,
  lsr        : u32,
  dlsr       : u32
}

struct SdesChunk {
  ssrc  : SSRC,
  cname : Option<String>,
  name  : Option<String>,
  email : Option<String>,
  phone : Option<String>,
  loc   : Option<String>,
  tool  : Option<String>,
  note  : Option<String>
}

enum RtcpPacket {
  SR(SSRC, Vec<ReportBlock>, SenderInfo),
  RR(SSRC, Vec<ReportBlock>),
  SDES(Vec<SdesChunk>),
  BYE(Vec<SSRC>, String),
}

struct CompoundRtcpPacket {
  packets : Vec<RtcpPacket>
}

struct RtpPacket;

// ================================================================================================

struct RtpSessionParameters {
  rtp_tx  :   Sender<RtpPacket>,
  rtp_rx  : Receiver<RtpPacket>,
  rtcp_tx :   Sender<CompoundRtcpPacket>,
  rtcp_rx : Receiver<CompoundRtcpPacket>
}

struct RtpSessionStatistics {
  pckt_count : u64
}

struct RtpSession {
  parameters : RtpSessionParameters,
  ssrc       : u32
}

impl RtpSession {
  pub fn new(params : RtpSessionParameters) -> RtpSession {
    RtpSession {
      parameters : params,
      ssrc       : 0    // FIXME
    }
  }

  pub fn run(&mut self) -> RtpSessionStatistics {
    let stats = RtpSessionStatistics{pckt_count : 0};
    stats
  }
}

// ================================================================================================

fn parse_rtp_packet(buf : &mut [u8], buflen : usize) -> Option<RtpPacket> {
  println!("parse_rtp_packet");
  None
}

struct RtpSocket {
  local_addr : IpAddr,
  local_port : u16
}

impl RtpSocket {
  pub fn run(&self) -> (Sender<RtpPacket>, Receiver<RtpPacket>) {
    let rx_socket = UdpSocket::bind(&(self.local_addr, self.local_port)).unwrap();
    let tx_socket = rx_socket.try_clone().unwrap();

    let (to_app, from_net) = channel::<RtpPacket>();
    let (to_net, from_app) = channel::<RtpPacket>();

    thread::spawn(move || {
      // The receiving thread
      loop {
        let mut buf = [0; 1500];
        let (buflen, sender) = rx_socket.recv_from(&mut buf).unwrap();

        match parse_rtp_packet(&mut buf, buflen) {
          Some(packet) => to_app.send(packet).unwrap(),
          None => {
            println!("Unable to parse packet")
          }
        }
      }
    });

    thread::spawn(move || {
      // The sending thread
      let packet = from_app.recv().unwrap();
      // FIXME: send the packet
    });

    (to_net, from_net)
  }
}

// ================================================================================================

fn parse_sr(p : bool, rc : u8, len : usize, packet : &[u8]) -> Option<RtcpPacket> {
  unimplemented!();
}

fn parse_rr(p : bool, rc : u8, len : usize, packet : &[u8]) -> Option<RtcpPacket> {
  unimplemented!();
}

fn parse_sdes(p : bool, rc : u8, len : usize, packet : &[u8]) -> Option<RtcpPacket> {
  unimplemented!();
}

fn parse_bye(p : bool, rc : u8, len : usize, packet : &[u8]) -> Option<RtcpPacket> {
  unimplemented!();
}

fn parse_app(p : bool, rc : u8, len : usize, packet : &[u8]) -> Option<RtcpPacket> {
  unimplemented!();
}

fn parse_rtcp_packet(buf : &mut [u8], buflen : usize) -> Option<CompoundRtcpPacket> {
  if buflen < 4 {
    println!("parse_rtcp_packet: packet is too short to be RTCP");
    return None;
  }

  // FIXME: create a compound packet object

  let mut offset = 0;
  while offset != buflen {
    if offset + 3 >= buflen {
      println!("parse_rtcp_packet: packet is too short");
      return None;
    }

    let v   =   (buf[offset + 0] >> 6) & 0x03;
    let p   =  ((buf[offset + 0] >> 5) & 0x01) == 1;
    let rc  =   (buf[offset + 0] >> 0) & 0x1f;
    let pt  =    buf[offset + 1];
    let len = (((buf[offset + 2] as usize) << 8) & 0xff00) |
              (((buf[offset + 3] as usize) << 0) & 0x0fff);

    if offset + (4 * len) > buflen {
      println!("parse_rtcp_packet: packet is too long");
      return None;
    }

    if v != 2 {
      println!("parse_rtcp_packet: version number mismatch (v={})", v);
      return None;
    }

    let packet = &buf[offset..offset + (4 * (len + 1))];

    let parsed_packet = match pt {
      200 =>   parse_sr(p, rc, len, packet),
      201 =>   parse_rr(p, rc, len, packet),
      202 => parse_sdes(p, rc, len, packet),
      203 =>  parse_bye(p, rc, len, packet),
      204 =>  parse_app(p, rc, len, packet),
      _   => {
        println!("parse_rtcp_packet: unknown packet type (pt={})", pt);
        return None;
      }
    };

    // FIXME: append parsed_packet to the compound packet

    offset += 4 + (4 * len);
  }

  None  // FIXME: return the compound packet
}

struct RtcpSocket {
  local_addr : IpAddr,
  local_port : u16
}

impl RtcpSocket {
  pub fn run(&self) -> (Sender<CompoundRtcpPacket>, Receiver<CompoundRtcpPacket>) {
    let rx_socket = UdpSocket::bind(&(self.local_addr, self.local_port)).unwrap();
    let tx_socket = rx_socket.try_clone().unwrap();

    let (to_app, from_net) = channel::<CompoundRtcpPacket>();
    let (to_net, from_app) = channel::<CompoundRtcpPacket>();

    thread::spawn(move || {
      // The receiving thread
      loop {
        let mut buf = [0; 1500];
        let (buflen, sender) = rx_socket.recv_from(&mut buf).unwrap();

        match parse_rtcp_packet(&mut buf, buflen) {
          Some(packet) => to_app.send(packet).unwrap(),
          None => {
            println!("Unable to parse packet")
          }
        }
      }
    });

    thread::spawn(move || {
      // The sending thread
      let packet = from_app.recv().unwrap();
      // FIXME: send the packet
    });

    (to_net, from_net)
  }
}

// ================================================================================================

fn main() {
  println!("CRTP v{}", CRTP_VERSION);

  let rtp_socket  =  RtpSocket{local_addr: IpAddr::new_v4(0,0,0,0), local_port : 3000};
  let (rtp_tx, rtp_rx) = rtp_socket.run();

  let rtcp_socket = RtcpSocket{local_addr: IpAddr::new_v4(0,0,0,0), local_port : 3001};
  let (rtcp_tx, rtcp_rx) = rtcp_socket.run();

  let session_parameters = RtpSessionParameters {
                             rtp_tx  : rtp_tx,
                             rtp_rx  : rtp_rx,
                             rtcp_tx : rtcp_tx,
                             rtcp_rx : rtcp_rx
                           };

  let mut session = RtpSession::new(session_parameters);
  let session_statistics = session.run();

  timer::sleep(Duration::hours(1));

}

// ================================================================================================
// vim: set ts=2 sw=2 tw=0 et ai:
<commit_msg>Implement parse_sr() and parse_rr(). Not yet tested.<commit_after>#![feature(net)]
#![feature(std_misc)]

use std::thread;
use std::sync::mpsc::{channel, Sender, Receiver};
use std::net::UdpSocket;
use std::net::IpAddr;
use std::old_io::timer;
use std::time::duration::Duration;

// ================================================================================================

const CRTP_VERSION : &'static str = env!("CARGO_PKG_VERSION");

struct SSRC(u32);
struct RtpTimestamp(u32);
struct NtpTimestamp(u64);

struct SenderInfo {
  ntp_ts     : u64, // FIXME: should be NtpTimestamp,
  rtp_ts     : u32, // FIXME: should be RtpTimestamp,
  pckt_count : u32,
  byte_count : u32
}

struct ReportBlock {
  ssrc       : SSRC,
  fract_lost : u8,
  cumul_lost : u32,
  ext_seq    : u32,
  jitter     : u32,
  lsr        : u32,
  dlsr       : u32
}

struct SdesChunk {
  ssrc  : SSRC,
  cname : Option<String>,
  name  : Option<String>,
  email : Option<String>,
  phone : Option<String>,
  loc   : Option<String>,
  tool  : Option<String>,
  note  : Option<String>
}

enum RtcpPacket {
  SR(SSRC, Vec<ReportBlock>, SenderInfo),
  RR(SSRC, Vec<ReportBlock>),
  SDES(Vec<SdesChunk>),
  BYE(Vec<SSRC>, String),
}

struct CompoundRtcpPacket {
  packets : Vec<RtcpPacket>
}

struct RtpPacket;

// ================================================================================================

struct RtpSessionParameters {
  rtp_tx  :   Sender<RtpPacket>,
  rtp_rx  : Receiver<RtpPacket>,
  rtcp_tx :   Sender<CompoundRtcpPacket>,
  rtcp_rx : Receiver<CompoundRtcpPacket>
}

struct RtpSessionStatistics {
  pckt_count : u64
}

struct RtpSession {
  parameters : RtpSessionParameters,
  ssrc       : u32
}

impl RtpSession {
  pub fn new(params : RtpSessionParameters) -> RtpSession {
    RtpSession {
      parameters : params,
      ssrc       : 0    // FIXME
    }
  }

  pub fn run(&mut self) -> RtpSessionStatistics {
    let stats = RtpSessionStatistics{pckt_count : 0};
    stats
  }
}

// ================================================================================================

fn parse_rtp_packet(buf : &mut [u8], buflen : usize) -> Option<RtpPacket> {
  println!("parse_rtp_packet");
  None
}

struct RtpSocket {
  local_addr : IpAddr,
  local_port : u16
}

impl RtpSocket {
  pub fn run(&self) -> (Sender<RtpPacket>, Receiver<RtpPacket>) {
    let rx_socket = UdpSocket::bind(&(self.local_addr, self.local_port)).unwrap();
    let tx_socket = rx_socket.try_clone().unwrap();

    let (to_app, from_net) = channel::<RtpPacket>();
    let (to_net, from_app) = channel::<RtpPacket>();

    thread::spawn(move || {
      // The receiving thread
      loop {
        let mut buf = [0; 1500];
        let (buflen, sender) = rx_socket.recv_from(&mut buf).unwrap();

        match parse_rtp_packet(&mut buf, buflen) {
          Some(packet) => to_app.send(packet).unwrap(),
          None => {
            println!("Unable to parse packet")
          }
        }
      }
    });

    thread::spawn(move || {
      // The sending thread
      let packet = from_app.recv().unwrap();
      // FIXME: send the packet
    });

    (to_net, from_net)
  }
}

// ================================================================================================

fn parse_be_u32(packet : &[u8], offset : usize) -> u32 {
  (((packet[offset + 0] as u32) << 24) & 0xff000000) |
  (((packet[offset + 1] as u32) << 15) & 0x00ff0000) |
  (((packet[offset + 2] as u32) <<  8) & 0x0000ff00) |
  (((packet[offset + 3] as u32) <<  0) & 0x000000ff)
}

fn parse_be_u64(packet : &[u8], offset : usize) -> u64 {
  (((packet[offset + 0] as u64) << 46) & 0xff00000000000000) |
  (((packet[offset + 1] as u64) << 48) & 0x00ff000000000000) |
  (((packet[offset + 2] as u64) << 40) & 0x0000ff0000000000) |
  (((packet[offset + 3] as u64) << 32) & 0x000000ff00000000) |
  (((packet[offset + 4] as u64) << 24) & 0x00000000ff000000) |
  (((packet[offset + 5] as u64) << 16) & 0x0000000000ff0000) |
  (((packet[offset + 6] as u64) <<  8) & 0x000000000000ff00) |
  (((packet[offset + 7] as u64) <<  0) & 0x00000000000000ff)
}

fn parse_report_block(packet : &[u8], offset : usize) -> ReportBlock {
  ReportBlock {
    ssrc       : SSRC(parse_be_u32(packet, offset)),
    fract_lost : packet[offset + 4],
    cumul_lost : parse_be_u32(packet, offset +  4) & 0x00ffffff,
    ext_seq    : parse_be_u32(packet, offset +  8),
    jitter     : parse_be_u32(packet, offset + 12),
    lsr        : parse_be_u32(packet, offset + 16),
    dlsr       : parse_be_u32(packet, offset + 20),
  }
}

fn parse_sr(p : bool, rc : u8, len : usize, packet : &[u8]) -> Option<RtcpPacket> {
  if len < 7 {
    println!("parse_sr: packet is too short to be an SR");
    return None;
  }

  let ssrc = SSRC(parse_be_u32(packet, 4));
  let si   = SenderInfo {
               ntp_ts     : parse_be_u64(packet,  8),
               rtp_ts     : parse_be_u32(packet, 16),
               pckt_count : parse_be_u32(packet, 20),
               byte_count : parse_be_u32(packet, 24)
             };

  let mut rr_list : Vec<ReportBlock> = Vec::new();
  for i in 0..rc {
    let rr = parse_report_block(packet, (28 + (i*24)) as usize);
    rr_list.push(rr);
  }

  Some(RtcpPacket::SR(ssrc, rr_list, si))
}

fn parse_rr(p : bool, rc : u8, len : usize, packet : &[u8]) -> Option<RtcpPacket> {
  if len < 1 {
    println!("parse_sr: packet is too short to be an RR");
    return None;
  }

  let ssrc = SSRC(parse_be_u32(packet, 4));

  let mut rr_list : Vec<ReportBlock> = Vec::new();
  for i in 0..rc {
    let rr = parse_report_block(packet, (8 + (i*24)) as usize);
    rr_list.push(rr);
  }

  Some(RtcpPacket::RR(ssrc, rr_list))
}

fn parse_sdes(p : bool, rc : u8, len : usize, packet : &[u8]) -> Option<RtcpPacket> {
  unimplemented!();
}

fn parse_bye(p : bool, rc : u8, len : usize, packet : &[u8]) -> Option<RtcpPacket> {
  unimplemented!();
}

fn parse_app(p : bool, rc : u8, len : usize, packet : &[u8]) -> Option<RtcpPacket> {
  unimplemented!();
}

fn parse_rtcp_packet(buf : &mut [u8], buflen : usize) -> Option<CompoundRtcpPacket> {
  if buflen < 4 {
    println!("parse_rtcp_packet: packet is too short to be RTCP");
    return None;
  }

  // FIXME: create a compound packet object

  let mut offset = 0;
  while offset != buflen {
    if offset + 3 >= buflen {
      println!("parse_rtcp_packet: packet is too short");
      return None;
    }

    let v   =   (buf[offset + 0] >> 6) & 0x03;
    let p   =  ((buf[offset + 0] >> 5) & 0x01) == 1;
    let rc  =   (buf[offset + 0] >> 0) & 0x1f;
    let pt  =    buf[offset + 1];
    let len = (((buf[offset + 2] as usize) << 8) & 0xff00) |
              (((buf[offset + 3] as usize) << 0) & 0x0fff);

    if offset + (4 * len) > buflen {
      println!("parse_rtcp_packet: packet is too long");
      return None;
    }

    if v != 2 {
      println!("parse_rtcp_packet: version number mismatch (v={})", v);
      return None;
    }

    let packet = &buf[offset..offset + (4 * (len + 1))];

    let parsed_packet = match pt {
      200 =>   parse_sr(p, rc, len, packet),
      201 =>   parse_rr(p, rc, len, packet),
      202 => parse_sdes(p, rc, len, packet),
      203 =>  parse_bye(p, rc, len, packet),
      204 =>  parse_app(p, rc, len, packet),
      _   => {
        println!("parse_rtcp_packet: unknown packet type (pt={})", pt);
        return None;
      }
    };

    // FIXME: append parsed_packet to the compound packet

    offset += 4 + (4 * len);
  }

  None  // FIXME: return the compound packet
}

struct RtcpSocket {
  local_addr : IpAddr,
  local_port : u16
}

impl RtcpSocket {
  pub fn run(&self) -> (Sender<CompoundRtcpPacket>, Receiver<CompoundRtcpPacket>) {
    let rx_socket = UdpSocket::bind(&(self.local_addr, self.local_port)).unwrap();
    let tx_socket = rx_socket.try_clone().unwrap();

    let (to_app, from_net) = channel::<CompoundRtcpPacket>();
    let (to_net, from_app) = channel::<CompoundRtcpPacket>();

    thread::spawn(move || {
      // The receiving thread
      loop {
        let mut buf = [0; 1500];
        let (buflen, sender) = rx_socket.recv_from(&mut buf).unwrap();

        match parse_rtcp_packet(&mut buf, buflen) {
          Some(packet) => to_app.send(packet).unwrap(),
          None => {
            println!("Unable to parse packet")
          }
        }
      }
    });

    thread::spawn(move || {
      // The sending thread
      let packet = from_app.recv().unwrap();
      // FIXME: send the packet
    });

    (to_net, from_net)
  }
}

// ================================================================================================

fn main() {
  println!("CRTP v{}", CRTP_VERSION);

  let rtp_socket  =  RtpSocket{local_addr: IpAddr::new_v4(0,0,0,0), local_port : 3000};
  let (rtp_tx, rtp_rx) = rtp_socket.run();

  let rtcp_socket = RtcpSocket{local_addr: IpAddr::new_v4(0,0,0,0), local_port : 3001};
  let (rtcp_tx, rtcp_rx) = rtcp_socket.run();

  let session_parameters = RtpSessionParameters {
                             rtp_tx  : rtp_tx,
                             rtp_rx  : rtp_rx,
                             rtcp_tx : rtcp_tx,
                             rtcp_rx : rtcp_rx
                           };

  let mut session = RtpSession::new(session_parameters);
  let session_statistics = session.run();

  timer::sleep(Duration::hours(1));

}

// ================================================================================================
// vim: set ts=2 sw=2 tw=0 et ai:
<|endoftext|>