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

//! Boundary parsing for `multipart` requests.

use super::buf_redux::BufReader;
use super::{safemem, twoway};

use log::LogLevel;

use std::cmp;
use std::borrow::Borrow;

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

/// A struct implementing `Read` and `BufRead` that will yield bytes until it sees a given sequence.
#[derive(Debug)]
pub struct BoundaryReader<R> {
    source: BufReader<R>,
    boundary: Vec<u8>,
    search_idx: usize,
    boundary_read: bool,
    at_end: bool,
}

impl<R> BoundaryReader<R> where R: Read {
    #[doc(hidden)]
    pub fn from_reader<B: Into<Vec<u8>>>(reader: R, boundary: B) -> BoundaryReader<R> {
        let mut boundary = boundary.into();
        safemem::prepend(b"--", &mut boundary);

        BoundaryReader {
            source: BufReader::new(reader),
            boundary: boundary,
            search_idx: 0,
            boundary_read: false,
            at_end: false,
        }
    }

    fn read_to_boundary(&mut self) -> io::Result<&[u8]> {
        // Make sure there's enough bytes in the buffer to positively identify the boundary.
        let min_len = self.search_idx + (self.boundary.len() * 2);

        let buf = try!(fill_buf_min(&mut self.source, min_len));

        if buf.len() == 0 {
            debug!("fill_buf_min returned zero-sized buf");
            self.at_end = true;
            return Ok(buf);
        }

        if log_enabled!(LogLevel::Trace) {
            trace!("Buf: {:?}", String::from_utf8_lossy(buf));
        }

        debug!(
            "Before-loop Buf len: {} Search idx: {} Boundary read: {:?}",
            buf.len(), self.search_idx, self.boundary_read
        );

        if !self.boundary_read && self.search_idx < buf.len() {
            let lookahead = &buf[self.search_idx..];

            debug!("Find boundary loop! Lookahead len: {}", lookahead.len());

            // Look for the boundary, or if it isn't found, stop near the end.
            match twoway::find_bytes(lookahead, &self.boundary) {
                Some(found_idx) => {
                    self.search_idx += found_idx;
                    self.boundary_read = true;
                },
                None => {
                    self.search_idx += lookahead.len().saturating_sub(self.boundary.len() + 2);
                }
            }
        }

        debug!(
            "After-loop Buf len: {} Search idx: {} Boundary read: {:?}",
            buf.len(), self.search_idx, self.boundary_read
        );

        // If the two bytes before the boundary are a CR-LF, we need to back up
        // the cursor so we don't yield bytes that client code isn't expecting.
        if self.boundary_read && self.search_idx >= 2 {
            let two_bytes_before = &buf[self.search_idx - 2 .. self.search_idx];

            debug!("Two bytes before: {:?} ({:?}) (\"\\r\\n\": {:?})",
                   String::from_utf8_lossy(two_bytes_before), two_bytes_before, b"\r\n");

            if two_bytes_before == &*b"\r\n" {
                debug!("Subtract two!");
                self.search_idx -= 2;
            }
        }

        let ret_buf = &buf[..self.search_idx];

        if log_enabled!(LogLevel::Trace) {
            trace!("Returning buf: {:?}", String::from_utf8_lossy(ret_buf));
        }

        Ok(ret_buf)
    }

    #[doc(hidden)]
    pub fn consume_boundary(&mut self) -> io::Result<bool> {
        if self.at_end {
            return Ok(true);
        }

        while !(self.boundary_read || self.at_end){
            debug!("Boundary not found yet");

            let buf_len = try!(self.read_to_boundary()).len();

            debug!("Discarding {} bytes", buf_len);

            if buf_len == 0 {
                break;
            }

            self.consume(buf_len);
        }

        self.source.consume(self.search_idx);
        self.search_idx = 0;

        if log_enabled!(LogLevel::Trace) {
            trace!("Consumed up to self.search_idx, remaining buf: {:?}",
                   String::from_utf8_lossy(self.source.get_buf()));
        }

        let consume_amt = {
            let buf = self.source.get_buf();
            self.boundary.len() + if buf.len() >=2 && buf[..2] == *b"\r\n" { 2 } else { 0 }
        };

        self.source.consume(consume_amt);
        self.boundary_read = false;

        let mut bytes_after = [0, 0];

        let read = try!(self.source.read(&mut bytes_after));

        if read == 1 {
            let _ = try!(self.source.read(&mut bytes_after[1..]));
        }

        if bytes_after == *b"--" {
            self.at_end = true;
        } else if bytes_after != *b"\r\n" {
            warn!("Unexpected bytes following boundary: {:?}", String::from_utf8_lossy(&bytes_after));
        }

        if log_enabled!(LogLevel::Trace) {
            trace!("Consumed boundary (at_end: {:?}), remaining buf: {:?}",
                    self.at_end,
                   String::from_utf8_lossy(self.source.get_buf())
            );
        }

        Ok(self.at_end)
    }
}

impl<R> Borrow<R> for BoundaryReader<R> {
    fn borrow(&self) -> &R {
        self.source.get_ref()
    }
}

impl<R> Read for BoundaryReader<R> where R: Read {
    fn read(&mut self, out: &mut [u8]) -> io::Result<usize> {
        let read = {
            let mut buf = try!(self.read_to_boundary());
            // This shouldn't ever be an error so unwrapping is fine.
            buf.read(out).unwrap()
        };

        self.consume(read);
        Ok(read)
    }
}

impl<R> BufRead for BoundaryReader<R> where R: Read {
    fn fill_buf(&mut self) -> io::Result<&[u8]> {
        self.read_to_boundary()
    }

    fn consume(&mut self, amt: usize) {
        let true_amt = cmp::min(amt, self.search_idx);

        debug!("Consume! amt: {} true amt: {}", amt, true_amt);

        self.source.consume(true_amt);
        self.search_idx -= true_amt;
    }
}

fn fill_buf_min<R: Read>(buf: &mut BufReader<R>, min: usize) -> io::Result<&[u8]> {
    if buf.available() < min {
        try!(buf.read_into_buf());
    }

    Ok(buf.get_buf())
}

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

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

    const BOUNDARY: &'static str = "boundary";
    const TEST_VAL: &'static str = "--boundary\r
dashed-value-1\r
--boundary\r
dashed-value-2\r
--boundary--";

    #[test]
    fn test_boundary() {
        let _ = ::env_logger::init();
        debug!("Testing boundary (no split)");

        let src = &mut TEST_VAL.as_bytes();
        let reader = BoundaryReader::from_reader(src, BOUNDARY);

        test_boundary_reader(reader);
    }

    struct SplitReader<'a> {
        left: &'a [u8],
        right: &'a [u8],
    }

    impl<'a> SplitReader<'a> {
        fn split(data: &'a [u8], at: usize) -> SplitReader<'a> {
            let (left, right) = data.split_at(at);

            SplitReader {
                left: left,
                right: right,
            }
        }
    }

    impl<'a> Read for SplitReader<'a> {
        fn read(&mut self, dst: &mut [u8]) -> io::Result<usize> {
            fn copy_bytes_partial(src: &mut &[u8], dst: &mut [u8]) -> usize {
                src.read(dst).unwrap()
            }

            let mut copy_amt = copy_bytes_partial(&mut self.left, dst);

            if copy_amt == 0 {
                copy_amt = copy_bytes_partial(&mut self.right, dst)
            };

            Ok(copy_amt)
        }
    }

    #[test]
    fn test_split_boundary() {
        let _ = ::env_logger::init();
        debug!("Testing boundary (split)");

        // Substitute for `.step_by()` being unstable.
        for split_at in 0 .. TEST_VAL.len(){
            debug!("Testing split at: {}", split_at);

            let src = SplitReader::split(TEST_VAL.as_bytes(), split_at);
            let reader = BoundaryReader::from_reader(src, BOUNDARY);
            test_boundary_reader(reader);
        }

    }

    fn test_boundary_reader<R: Read>(mut reader: BoundaryReader<R>) {
        let ref mut buf = String::new();

        debug!("Read 1");
        let _ = reader.read_to_string(buf).unwrap();
        assert!(buf.is_empty(), "Buffer not empty: {:?}", buf);
        buf.clear();

        debug!("Consume 1");
        reader.consume_boundary().unwrap();

        debug!("Read 2");
        let _ = reader.read_to_string(buf).unwrap();
        assert_eq!(buf, "dashed-value-1");
        buf.clear();

        debug!("Consume 2");
        reader.consume_boundary().unwrap();

        debug!("Read 3");
        let _ = reader.read_to_string(buf).unwrap();
        assert_eq!(buf, "dashed-value-2");
        buf.clear();

        debug!("Consume 3");
        reader.consume_boundary().unwrap();

        debug!("Read 4");
        let _ = reader.read_to_string(buf).unwrap();
        assert_eq!(buf, "");
    }
}
<commit_msg>Add a number of retries to `boundary::fill_buf_min()`<commit_after>// Copyright 2016 `multipart` Crate Developers
//
// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
// http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
// http://opensource.org/licenses/MIT>, at your option. This file may not be
// copied, modified, or distributed except according to those terms.

//! Boundary parsing for `multipart` requests.

use super::buf_redux::BufReader;
use super::{safemem, twoway};

use log::LogLevel;

use std::cmp;
use std::borrow::Borrow;

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

/// A struct implementing `Read` and `BufRead` that will yield bytes until it sees a given sequence.
#[derive(Debug)]
pub struct BoundaryReader<R> {
    source: BufReader<R>,
    boundary: Vec<u8>,
    search_idx: usize,
    boundary_read: bool,
    at_end: bool,
}

impl<R> BoundaryReader<R> where R: Read {
    #[doc(hidden)]
    pub fn from_reader<B: Into<Vec<u8>>>(reader: R, boundary: B) -> BoundaryReader<R> {
        let mut boundary = boundary.into();
        safemem::prepend(b"--", &mut boundary);

        BoundaryReader {
            source: BufReader::new(reader),
            boundary: boundary,
            search_idx: 0,
            boundary_read: false,
            at_end: false,
        }
    }

    fn read_to_boundary(&mut self) -> io::Result<&[u8]> {
        // Make sure there's enough bytes in the buffer to positively identify the boundary.
        let min_len = self.search_idx + (self.boundary.len() * 2);

        let buf = try!(fill_buf_min(&mut self.source, min_len));

        if buf.len() == 0 {
            debug!("fill_buf_min returned zero-sized buf");
            self.at_end = true;
            return Ok(buf);
        }

        if log_enabled!(LogLevel::Trace) {
            trace!("Buf: {:?}", String::from_utf8_lossy(buf));
        }

        debug!(
            "Before-loop Buf len: {} Search idx: {} Boundary read: {:?}",
            buf.len(), self.search_idx, self.boundary_read
        );

        if !self.boundary_read && self.search_idx < buf.len() {
            let lookahead = &buf[self.search_idx..];

            debug!("Find boundary loop! Lookahead len: {}", lookahead.len());

            // Look for the boundary, or if it isn't found, stop near the end.
            match twoway::find_bytes(lookahead, &self.boundary) {
                Some(found_idx) => {
                    self.search_idx += found_idx;
                    self.boundary_read = true;
                },
                None => {
                    self.search_idx += lookahead.len().saturating_sub(self.boundary.len() + 2);
                }
            }
        }

        debug!(
            "After-loop Buf len: {} Search idx: {} Boundary read: {:?}",
            buf.len(), self.search_idx, self.boundary_read
        );

        // If the two bytes before the boundary are a CR-LF, we need to back up
        // the cursor so we don't yield bytes that client code isn't expecting.
        if self.boundary_read && self.search_idx >= 2 {
            let two_bytes_before = &buf[self.search_idx - 2 .. self.search_idx];

            debug!("Two bytes before: {:?} ({:?}) (\"\\r\\n\": {:?})",
                   String::from_utf8_lossy(two_bytes_before), two_bytes_before, b"\r\n");

            if two_bytes_before == &*b"\r\n" {
                debug!("Subtract two!");
                self.search_idx -= 2;
            }
        }

        let ret_buf = &buf[..self.search_idx];

        if log_enabled!(LogLevel::Trace) {
            trace!("Returning buf: {:?}", String::from_utf8_lossy(ret_buf));
        }

        Ok(ret_buf)
    }

    #[doc(hidden)]
    pub fn consume_boundary(&mut self) -> io::Result<bool> {
        if self.at_end {
            return Ok(true);
        }

        while !(self.boundary_read || self.at_end){
            debug!("Boundary not found yet");

            let buf_len = try!(self.read_to_boundary()).len();

            debug!("Discarding {} bytes", buf_len);

            if buf_len == 0 {
                break;
            }

            self.consume(buf_len);
        }

        self.source.consume(self.search_idx);
        self.search_idx = 0;

        if log_enabled!(LogLevel::Trace) {
            trace!("Consumed up to self.search_idx, remaining buf: {:?}",
                   String::from_utf8_lossy(self.source.get_buf()));
        }

        let consume_amt = {
            let buf = self.source.get_buf();
            self.boundary.len() + if buf.len() >=2 && buf[..2] == *b"\r\n" { 2 } else { 0 }
        };

        self.source.consume(consume_amt);
        self.boundary_read = false;

        let mut bytes_after = [0, 0];

        let read = try!(self.source.read(&mut bytes_after));

        if read == 1 {
            let _ = try!(self.source.read(&mut bytes_after[1..]));
        }

        if bytes_after == *b"--" {
            self.at_end = true;
        } else if bytes_after != *b"\r\n" {
            warn!("Unexpected bytes following boundary: {:?}", String::from_utf8_lossy(&bytes_after));
        }

        if log_enabled!(LogLevel::Trace) {
            trace!("Consumed boundary (at_end: {:?}), remaining buf: {:?}",
                    self.at_end,
                   String::from_utf8_lossy(self.source.get_buf())
            );
        }

        Ok(self.at_end)
    }
}

impl<R> Borrow<R> for BoundaryReader<R> {
    fn borrow(&self) -> &R {
        self.source.get_ref()
    }
}

impl<R> Read for BoundaryReader<R> where R: Read {
    fn read(&mut self, out: &mut [u8]) -> io::Result<usize> {
        let read = {
            let mut buf = try!(self.read_to_boundary());
            // This shouldn't ever be an error so unwrapping is fine.
            buf.read(out).unwrap()
        };

        self.consume(read);
        Ok(read)
    }
}

impl<R> BufRead for BoundaryReader<R> where R: Read {
    fn fill_buf(&mut self) -> io::Result<&[u8]> {
        self.read_to_boundary()
    }

    fn consume(&mut self, amt: usize) {
        let true_amt = cmp::min(amt, self.search_idx);

        debug!("Consume! amt: {} true amt: {}", amt, true_amt);

        self.source.consume(true_amt);
        self.search_idx -= true_amt;
    }
}

fn fill_buf_min<R: Read>(buf: &mut BufReader<R>, min: usize) -> io::Result<&[u8]> {
    const MAX_ATTEMPTS: usize = 3;

    let mut attempts = 0;

    while buf.available() < min && attempts < MAX_ATTEMPTS {
        if try!(buf.read_into_buf()) == 0 { break; };
        attempts += 1;
    }

    Ok(buf.get_buf())
}

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

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

    const BOUNDARY: &'static str = "boundary";
    const TEST_VAL: &'static str = "--boundary\r
dashed-value-1\r
--boundary\r
dashed-value-2\r
--boundary--";

    #[test]
    fn test_boundary() {
        let _ = ::env_logger::init();
        debug!("Testing boundary (no split)");

        let src = &mut TEST_VAL.as_bytes();
        let reader = BoundaryReader::from_reader(src, BOUNDARY);

        test_boundary_reader(reader);
    }

    struct SplitReader<'a> {
        left: &'a [u8],
        right: &'a [u8],
    }

    impl<'a> SplitReader<'a> {
        fn split(data: &'a [u8], at: usize) -> SplitReader<'a> {
            let (left, right) = data.split_at(at);

            SplitReader {
                left: left,
                right: right,
            }
        }
    }

    impl<'a> Read for SplitReader<'a> {
        fn read(&mut self, dst: &mut [u8]) -> io::Result<usize> {
            fn copy_bytes_partial(src: &mut &[u8], dst: &mut [u8]) -> usize {
                src.read(dst).unwrap()
            }

            let mut copy_amt = copy_bytes_partial(&mut self.left, dst);

            if copy_amt == 0 {
                copy_amt = copy_bytes_partial(&mut self.right, dst)
            };

            Ok(copy_amt)
        }
    }

    #[test]
    fn test_split_boundary() {
        let _ = ::env_logger::init();
        debug!("Testing boundary (split)");

        // Substitute for `.step_by()` being unstable.
        for split_at in 0 .. TEST_VAL.len(){
            debug!("Testing split at: {}", split_at);

            let src = SplitReader::split(TEST_VAL.as_bytes(), split_at);
            let reader = BoundaryReader::from_reader(src, BOUNDARY);
            test_boundary_reader(reader);
        }

    }

    fn test_boundary_reader<R: Read>(mut reader: BoundaryReader<R>) {
        let ref mut buf = String::new();

        debug!("Read 1");
        let _ = reader.read_to_string(buf).unwrap();
        assert!(buf.is_empty(), "Buffer not empty: {:?}", buf);
        buf.clear();

        debug!("Consume 1");
        reader.consume_boundary().unwrap();

        debug!("Read 2");
        let _ = reader.read_to_string(buf).unwrap();
        assert_eq!(buf, "dashed-value-1");
        buf.clear();

        debug!("Consume 2");
        reader.consume_boundary().unwrap();

        debug!("Read 3");
        let _ = reader.read_to_string(buf).unwrap();
        assert_eq!(buf, "dashed-value-2");
        buf.clear();

        debug!("Consume 3");
        reader.consume_boundary().unwrap();

        debug!("Read 4");
        let _ = reader.read_to_string(buf).unwrap();
        assert_eq!(buf, "");
    }
}
<|endoftext|>


<commit_before>use std::collections::HashMap;
use std::fmt;

use fcp_cryptoauth::keys::ToBase32;
use fcp_cryptoauth::{peek_pk_key, CAWrapper, Credentials, PublicKey, SecretKey};
use rand;
use rand::Rng;

use operation::{BackwardPath, ForwardPath};
use packets::data::DataPacket;
use packets::data::Payload as DataPayload;
use packets::data::DATAPACKET_VERSION;
use packets::route::RoutePacket;
use packets::switch::SwitchPacket;
use utils::new_from_raw_content;

#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
pub struct SessionHandle(pub u32);

#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
pub struct MySessionHandle(pub SessionHandle);

#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
pub struct TheirSessionHandle(pub SessionHandle);

pub struct Session {
    pub path: Option<ForwardPath>,
    pub conn: CAWrapper<()>,
}

impl fmt::Debug for Session {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "Session {{ path: {:?} }}", self.path)
    }
}

impl Session {
    pub fn their_handle(&self) -> Option<TheirSessionHandle> {
        self.conn
            .peer_session_handle()
            .map(SessionHandle)
            .map(TheirSessionHandle)
    }

    pub fn wrap_route_packet(
        &mut self,
        path: ForwardPath,
        route_packet: RoutePacket,
    ) -> Vec<SwitchPacket> {
        let data_packet =
            DataPacket::new(DATAPACKET_VERSION, &DataPayload::RoutePacket(route_packet));

        self.conn
            .wrap_message_immediately(&data_packet.raw())
            .into_iter()
            .map(|r| new_from_raw_content(path, r, self.their_handle()))
            .collect()
    }
}

pub struct SessionManager {
    pub my_pk: PublicKey,
    pub my_sk: SecretKey,
    /// CryptoAuth sessions used to talk to switches/routers. Their packets
    /// themselves are wrapped in SwitchPackets, which are wrapped in the
    /// outer CryptoAuth sessions.
    pub sessions: HashMap<MySessionHandle, Session>,

    /// Map from peer public keys to the session handle I use to decrypt their messages
    pub pk_to_my_handle: HashMap<PublicKey, MySessionHandle>,
}

impl SessionManager {
    pub fn new(my_pk: PublicKey, my_sk: SecretKey) -> SessionManager {
        SessionManager {
            my_pk: my_pk,
            my_sk: my_sk,
            sessions: HashMap::new(),
            pk_to_my_handle: HashMap::new(),
        }
    }

    fn gen_handle(&mut self) -> MySessionHandle {
        loop {
            let handle = MySessionHandle(SessionHandle(rand::thread_rng().next_u32()));
            if !self.sessions.contains_key(&handle) {
                return handle;
            }
        }
    }
    pub fn add_outgoing(
        &mut self,
        path: Option<ForwardPath>,
        node_pk: PublicKey,
    ) -> MySessionHandle {
        assert!(
            node_pk != self.my_pk,
            format!(
                "Tried to add outgoing connection to myself ({}).",
                self.my_pk.to_base32()
            )
        );
        let handle = self.gen_handle();
        let conn = CAWrapper::new_outgoing_connection(
            self.my_pk.clone(),
            self.my_sk.clone(),
            node_pk,
            Credentials::None,
            None,
            (),
            Some((handle.0).0),
        );
        self.pk_to_my_handle.insert(node_pk, handle);
        self.sessions.insert(
            handle,
            Session {
                path: path,
                conn: conn,
            },
        );
        handle
    }

    pub fn on_hello(
        &mut self,
        packet: Vec<u8>,
        switch_packet: &SwitchPacket,
    ) -> (MySessionHandle, Vec<u8>) {
        let pk: PublicKey = peek_pk_key(&packet[..]).expect("Invalid Hello packet.");
        assert!(
            pk != self.my_pk,
            format!(
                "Got an Hello packet from myself ({}).",
                self.my_pk.to_base32()
            )
        );
        let handle = self.gen_handle();
        let (conn, message) = CAWrapper::new_incoming_connection(
            self.my_pk,
            self.my_sk.clone(),
            Credentials::None,
            None,
            Some((handle.0).0),
            packet,
        )
        .unwrap();
        let path = BackwardPath::from(switch_packet.label()).reverse();
        self.sessions.insert(
            handle,
            Session {
                path: Some(path),
                conn: conn,
            },
        );
        (handle, message)
    }

    pub fn on_key(
        &mut self,
        packet: Vec<u8>,
        switch_packet: &SwitchPacket,
    ) -> (MySessionHandle, Vec<DataPacket>) {
        let pk: PublicKey = peek_pk_key(&packet[..]).expect("Invalid Key packet.");
        assert!(
            pk != self.my_pk,
            format!("Got a Key packet from myself ({}).", self.my_pk.to_base32())
        );
        let my_handle = *self.pk_to_my_handle.get(&pk).expect(&format!(
            "Got Key message from a node I never sent a Hello to: {}.",
            pk.to_base32()
        ));
        let path = BackwardPath::from(switch_packet.label()).reverse();
        self.sessions
            .get_mut(&my_handle)
            .expect("Invalid handle")
            .path = Some(path);
        (my_handle, self.unwrap_message(my_handle, packet))
    }

    pub fn unwrap_message(&mut self, handle: MySessionHandle, packet: Vec<u8>) -> Vec<DataPacket> {
        let session = self.sessions.get_mut(&handle).unwrap();
        let raw_packets = session.conn.unwrap_message(packet).unwrap();
        raw_packets
            .into_iter()
            .map(|raw| DataPacket::new_from_raw(raw).expect("Could not decode data packet"))
            .collect()
    }

    pub fn get_session(&mut self, handle: MySessionHandle) -> Option<&mut Session> {
        self.sessions.get_mut(&handle)
    }

    pub fn get_session_for_pk(&mut self, pk: PublicKey) -> Option<&mut Session> {
        for (_handle, session) in self.sessions.iter_mut() {
            if *session.conn.their_pk() == pk {
                return Some(session);
            }
        }
        None
    }

    pub fn get_or_make_session_for_pk(&mut self, pk: PublicKey) -> &mut Session {
        if self.get_session_for_pk(pk).is_none() {
            let handle = self.add_outgoing(None, pk);
            self.sessions.get_mut(&handle).unwrap()
        } else {
            self.get_session_for_pk(pk).unwrap()
        }
    }

    pub fn upkeep(&mut self) -> Vec<SwitchPacket> {
        let mut packets = Vec::new();
        for (_my_handle, ref mut session) in self.sessions.iter_mut() {
            let their_handle = session
                .conn
                .peer_session_handle()
                .map(SessionHandle)
                .map(TheirSessionHandle);
            for ca_message in session.conn.upkeep() {
                if let Some(path) = session.path {
                    packets.push(new_from_raw_content(path, ca_message, their_handle));
                }
            }
        }
        packets
    }
}

#[cfg(test)]
mod tests {}
<commit_msg>Make impl for Session dump state of CAWrapper.<commit_after>use std::collections::HashMap;

use fcp_cryptoauth::keys::ToBase32;
use fcp_cryptoauth::{peek_pk_key, CAWrapper, Credentials, PublicKey, SecretKey};
use rand;
use rand::Rng;

use operation::{BackwardPath, ForwardPath};
use packets::data::DataPacket;
use packets::data::Payload as DataPayload;
use packets::data::DATAPACKET_VERSION;
use packets::route::RoutePacket;
use packets::switch::SwitchPacket;
use utils::new_from_raw_content;

#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
pub struct SessionHandle(pub u32);

#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
pub struct MySessionHandle(pub SessionHandle);

#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
pub struct TheirSessionHandle(pub SessionHandle);

#[derive(Debug)]
pub struct Session {
    pub path: Option<ForwardPath>,
    pub conn: CAWrapper<()>,
}

impl Session {
    pub fn their_handle(&self) -> Option<TheirSessionHandle> {
        self.conn
            .peer_session_handle()
            .map(SessionHandle)
            .map(TheirSessionHandle)
    }

    pub fn wrap_route_packet(
        &mut self,
        path: ForwardPath,
        route_packet: RoutePacket,
    ) -> Vec<SwitchPacket> {
        let data_packet =
            DataPacket::new(DATAPACKET_VERSION, &DataPayload::RoutePacket(route_packet));

        self.conn
            .wrap_message_immediately(&data_packet.raw())
            .into_iter()
            .map(|r| new_from_raw_content(path, r, self.their_handle()))
            .collect()
    }
}

pub struct SessionManager {
    pub my_pk: PublicKey,
    pub my_sk: SecretKey,
    /// CryptoAuth sessions used to talk to switches/routers. Their packets
    /// themselves are wrapped in SwitchPackets, which are wrapped in the
    /// outer CryptoAuth sessions.
    pub sessions: HashMap<MySessionHandle, Session>,

    /// Map from peer public keys to the session handle I use to decrypt their messages
    pub pk_to_my_handle: HashMap<PublicKey, MySessionHandle>,
}

impl SessionManager {
    pub fn new(my_pk: PublicKey, my_sk: SecretKey) -> SessionManager {
        SessionManager {
            my_pk: my_pk,
            my_sk: my_sk,
            sessions: HashMap::new(),
            pk_to_my_handle: HashMap::new(),
        }
    }

    fn gen_handle(&mut self) -> MySessionHandle {
        loop {
            let handle = MySessionHandle(SessionHandle(rand::thread_rng().next_u32()));
            if !self.sessions.contains_key(&handle) {
                return handle;
            }
        }
    }
    pub fn add_outgoing(
        &mut self,
        path: Option<ForwardPath>,
        node_pk: PublicKey,
    ) -> MySessionHandle {
        assert!(
            node_pk != self.my_pk,
            format!(
                "Tried to add outgoing connection to myself ({}).",
                self.my_pk.to_base32()
            )
        );
        let handle = self.gen_handle();
        let conn = CAWrapper::new_outgoing_connection(
            self.my_pk.clone(),
            self.my_sk.clone(),
            node_pk,
            Credentials::None,
            None,
            (),
            Some((handle.0).0),
        );
        self.pk_to_my_handle.insert(node_pk, handle);
        self.sessions.insert(
            handle,
            Session {
                path: path,
                conn: conn,
            },
        );
        handle
    }

    pub fn on_hello(
        &mut self,
        packet: Vec<u8>,
        switch_packet: &SwitchPacket,
    ) -> (MySessionHandle, Vec<u8>) {
        let pk: PublicKey = peek_pk_key(&packet[..]).expect("Invalid Hello packet.");
        assert!(
            pk != self.my_pk,
            format!(
                "Got an Hello packet from myself ({}).",
                self.my_pk.to_base32()
            )
        );
        let handle = self.gen_handle();
        let (conn, message) = CAWrapper::new_incoming_connection(
            self.my_pk,
            self.my_sk.clone(),
            Credentials::None,
            None,
            Some((handle.0).0),
            packet,
        )
        .unwrap();
        let path = BackwardPath::from(switch_packet.label()).reverse();
        self.sessions.insert(
            handle,
            Session {
                path: Some(path),
                conn: conn,
            },
        );
        (handle, message)
    }

    pub fn on_key(
        &mut self,
        packet: Vec<u8>,
        switch_packet: &SwitchPacket,
    ) -> (MySessionHandle, Vec<DataPacket>) {
        let pk: PublicKey = peek_pk_key(&packet[..]).expect("Invalid Key packet.");
        assert!(
            pk != self.my_pk,
            format!("Got a Key packet from myself ({}).", self.my_pk.to_base32())
        );
        let my_handle = *self.pk_to_my_handle.get(&pk).expect(&format!(
            "Got Key message from a node I never sent a Hello to: {}.",
            pk.to_base32()
        ));
        let path = BackwardPath::from(switch_packet.label()).reverse();
        self.sessions
            .get_mut(&my_handle)
            .expect("Invalid handle")
            .path = Some(path);
        (my_handle, self.unwrap_message(my_handle, packet))
    }

    pub fn unwrap_message(&mut self, handle: MySessionHandle, packet: Vec<u8>) -> Vec<DataPacket> {
        let session = self.sessions.get_mut(&handle).unwrap();
        let raw_packets = session.conn.unwrap_message(packet).unwrap();
        raw_packets
            .into_iter()
            .map(|raw| DataPacket::new_from_raw(raw).expect("Could not decode data packet"))
            .collect()
    }

    pub fn get_session(&mut self, handle: MySessionHandle) -> Option<&mut Session> {
        self.sessions.get_mut(&handle)
    }

    pub fn get_session_for_pk(&mut self, pk: PublicKey) -> Option<&mut Session> {
        for (_handle, session) in self.sessions.iter_mut() {
            if *session.conn.their_pk() == pk {
                return Some(session);
            }
        }
        None
    }

    pub fn get_or_make_session_for_pk(&mut self, pk: PublicKey) -> &mut Session {
        if self.get_session_for_pk(pk).is_none() {
            let handle = self.add_outgoing(None, pk);
            self.sessions.get_mut(&handle).unwrap()
        } else {
            self.get_session_for_pk(pk).unwrap()
        }
    }

    pub fn upkeep(&mut self) -> Vec<SwitchPacket> {
        let mut packets = Vec::new();
        for (_my_handle, ref mut session) in self.sessions.iter_mut() {
            let their_handle = session
                .conn
                .peer_session_handle()
                .map(SessionHandle)
                .map(TheirSessionHandle);
            for ca_message in session.conn.upkeep() {
                if let Some(path) = session.path {
                    packets.push(new_from_raw_content(path, ca_message, their_handle));
                }
            }
        }
        packets
    }
}

#[cfg(test)]
mod tests {}
<|endoftext|>


<commit_before>use std::borrow::{Cow, ToOwned};
use std::ffi::{CStr, CString};
use std::str;

#[derive(Hash)]
pub struct PascalStr {
    string: str
}

impl PascalStr {
    #[inline]
    pub fn as_ptr(&self) -> *const u8 {
        (&self.string).as_ptr()
    }

    #[inline]
    pub fn as_mut_ptr(&mut self) -> *mut u8 {
        &mut self.string as *mut str as *mut u8
    }

    #[inline]
    pub fn as_str(&self) -> &str {
        &self.string
    }

    #[inline]
    pub fn as_bytes(&self) -> &[u8] {
        self.string.as_bytes()
    }

    pub fn as_cstr(&self) -> Result<Cow<CStr>, InteriorNullError> {
        unimplemented!()
    }

    #[inline]
    pub fn len(&self) -> usize {
        self.string.len()
    }

    #[inline]
    pub fn chars(&self) -> Chars {
        self.string.chars()
    }

    #[inline]
    pub fn bytes(&self) -> Bytes {
        self.string.bytes()
    }

    #[inline]
    pub fn lines(&self) -> Lines {
        self.string.lines()
    }
}

pub type Chars<'a> = str::Chars<'a>;
pub type Bytes<'a> = str::Bytes<'a>;
pub type Lines<'a> = str::Lines<'a>;

pub struct InteriorNullError;
<commit_msg>impl ToOwned for PascalStr<commit_after>use std::borrow::{Cow, ToOwned};
use std::ffi::{CStr, CString};
use std::str;
use ::utf8::PascalString;

#[derive(Hash)]
pub struct PascalStr {
    string: str
}

impl PascalStr {
    #[inline]
    pub fn as_ptr(&self) -> *const u8 {
        (&self.string).as_ptr()
    }

    #[inline]
    pub fn as_mut_ptr(&mut self) -> *mut u8 {
        &mut self.string as *mut str as *mut u8
    }

    #[inline]
    pub fn as_str(&self) -> &str {
        &self.string
    }

    #[inline]
    pub fn as_bytes(&self) -> &[u8] {
        self.string.as_bytes()
    }

    pub fn as_cstr(&self) -> Result<Cow<CStr>, InteriorNullError> {
        unimplemented!()
    }

    #[inline]
    pub fn len(&self) -> usize {
        self.string.len()
    }

    #[inline]
    pub fn chars(&self) -> Chars {
        self.string.chars()
    }

    #[inline]
    pub fn bytes(&self) -> Bytes {
        self.string.bytes()
    }

    #[inline]
    pub fn lines(&self) -> Lines {
        self.string.lines()
    }
}

impl ToOwned for PascalStr {
    type Owned = PascalString;
    #[inline]
    fn to_owned(&self) -> Self::Owned {
        PascalString::from_str(self.as_str()).unwrap()
    }
}

pub type Chars<'a> = str::Chars<'a>;
pub type Bytes<'a> = str::Bytes<'a>;
pub type Lines<'a> = str::Lines<'a>;

pub struct InteriorNullError;
<|endoftext|>


<commit_before>use ws;
use std; // NOTE: in submodules, lookup path is relative to this module, so we must `use std`
use time;
use uuid::Uuid;
use std::sync::{Arc,Mutex};
use std::collections::HashMap;

#[derive(Debug, Clone, Copy)]
pub struct Connection {
    uuid: Uuid,
}

impl std::fmt::Display for Connection {
    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
        write!(f, "conn{{{}}}", self.uuid)
    }
}

type ConnectionMap = Arc<Mutex<HashMap<Uuid,Connection>>>;

struct WSServer {
    out: ws::Sender,
    connections: ConnectionMap,
}

impl ws::Handler for WSServer {
    fn on_request(&mut self, req: &ws::Request) -> ws::Result<ws::Response> {
        let mut resp = ws::Response::from_request(req).unwrap();

        let mut conn_map = self.connections.lock().unwrap();

        println!("ws:req[{}]", time::precise_time_ns());

        // NOTE(jordan): cookie parser
        let cookies_string = req.header("cookie")
            .and_then(|cookies_bytes| String::from_utf8(cookies_bytes.to_vec()).ok())
            .unwrap_or(String::from(""));
        // NOTE(jordan): split into cookie strings sorted by recency (hence rsplit)
        let cookies : HashMap<&str, &str> = cookies_string
            .rsplit(";")
            .map(|cookie_string| {
                let mut cookie_split = cookie_string.split("=");
                (cookie_split.next().unwrap(), cookie_split.next().unwrap())
            })
            .collect();

        println!("bzwf_anon_wstx = {}", cookies.get("bzwf_anon_wstx").unwrap_or(&"(nerp no dice)"));

        let new_uuid = Uuid::new_v4();
        let new_conn = Connection {
            uuid: new_uuid
        };
        conn_map.insert(new_conn.uuid, new_conn);
        println!("ws:req: new user with uuid {}", new_uuid);
        println!("{} connected users", conn_map.len());

        println!("ws:req: putting cookie: bzwf_anon_wstx={}; ", new_conn);
        let new_bzwf_cookie_str = format!("bzwf_anon_wstx={}; ", new_conn);
        {
            let headers = resp.headers_mut();
            headers.push((
                String::from("Set-Cookie"),
                new_bzwf_cookie_str.as_bytes().to_vec()
            ));
        }

        Ok(resp)
    }

    fn on_message(&mut self, msg: ws::Message) -> ws::Result<()> {
        // TODO
        println!("ws:rcv[{}]: user with uuid {} sent ws msg {}",
                 time::precise_time_ns(),
                 "[[[ we don't have uuids in ws yet ]]]",
                 msg);
        self.out.send("I hear you loud and clear").unwrap();
        Ok(())
    }

    fn on_open(&mut self, _: ws::Handshake) -> ws::Result<()> {
        // TODO
        println!("ws:opn[{}]: user with uuid {} opened ws cxn",
                 time::precise_time_ns(),
                 "[[[ we don't have uuids in ws yet ]]]");
        Ok(())
    }

    fn on_close(&mut self, code: ws::CloseCode, reason: &str) {
        println!("ws:cls[{}]: user with uuid {} closed ws cxn\n\tCode [{:?}] reason: {}",
                 time::precise_time_ns(),
                 "[[[ we don't have uuids in ws yet ]]]",
                 code,
                 reason);
        // TODO
    }

    fn on_error(&mut self, err: ws::Error) {
        println!("ws:err[{}]: user with uuid {} got error {}",
                 time::precise_time_ns(),
                 "[[[ we don't have uuids in ws yet ]]]",
                 err);
        // TODO
    }
}

pub fn server (domain: String, port: i32) -> () {
    let connections : ConnectionMap = Arc::new(Mutex::new(HashMap::new()));
    let addr = format!("{}:{}", domain, port);
    println!("WebSockets server listening on {}", addr);
    ws::listen(addr, |out| WSServer {
        out: out,
        connections: connections.clone(),
    }).unwrap();
}
<commit_msg>Bugfix: cookie parser error handling<commit_after>use ws;
use std; // NOTE: in submodules, lookup path is relative to this module, so we must `use std`
use time;
use uuid::Uuid;
use std::sync::{Arc,Mutex};
use std::collections::HashMap;

#[derive(Debug, Clone, Copy)]
pub struct Connection {
    uuid: Uuid,
}

impl std::fmt::Display for Connection {
    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
        write!(f, "conn{{{}}}", self.uuid)
    }
}

type ConnectionMap = Arc<Mutex<HashMap<Uuid,Connection>>>;

struct WSServer {
    out: ws::Sender,
    connections: ConnectionMap,
}

impl ws::Handler for WSServer {
    fn on_request(&mut self, req: &ws::Request) -> ws::Result<ws::Response> {
        let mut resp = ws::Response::from_request(req).unwrap();

        let mut conn_map = self.connections.lock().unwrap();

        println!("ws:req[{}]", time::precise_time_ns());

        // NOTE(jordan): cookie parser
        let cookies_string = req.header("cookie")
            .and_then(|cookies_bytes| String::from_utf8(cookies_bytes.to_vec()).ok())
            .unwrap_or(String::from(""));
        // NOTE(jordan): split into cookie strings sorted by recency (hence rsplit)
        let cookies : HashMap<&str, &str> = cookies_string
            .rsplit(";")
            .filter_map(|cookie_string| {
                let mut cookie_pair = cookie_string.split("=");
                match (cookie_pair.next(), cookie_pair.next()) {
                    (Some(name), Some(value)) => Some((name, value)),
                    _ => None
                }
            })
            .collect();

        println!("bzwf_anon_wstx = {}", cookies.get("bzwf_anon_wstx").unwrap_or(&"(nerp no dice)"));

        let new_uuid = Uuid::new_v4();
        let new_conn = Connection {
            uuid: new_uuid
        };
        conn_map.insert(new_conn.uuid, new_conn);
        println!("ws:req: new user with uuid {}", new_uuid);
        println!("{} connected users", conn_map.len());

        println!("ws:req: putting cookie: bzwf_anon_wstx={}; ", new_conn);
        let new_bzwf_cookie_str = format!("bzwf_anon_wstx={}; ", new_conn);
        {
            let headers = resp.headers_mut();
            headers.push((
                String::from("Set-Cookie"),
                new_bzwf_cookie_str.as_bytes().to_vec()
            ));
        }

        Ok(resp)
    }

    fn on_message(&mut self, msg: ws::Message) -> ws::Result<()> {
        // TODO
        println!("ws:rcv[{}]: user with uuid {} sent ws msg {}",
                 time::precise_time_ns(),
                 "[[[ we don't have uuids in ws yet ]]]",
                 msg);
        self.out.send("I hear you loud and clear").unwrap();
        Ok(())
    }

    fn on_open(&mut self, _: ws::Handshake) -> ws::Result<()> {
        // TODO
        println!("ws:opn[{}]: user with uuid {} opened ws cxn",
                 time::precise_time_ns(),
                 "[[[ we don't have uuids in ws yet ]]]");
        Ok(())
    }

    fn on_close(&mut self, code: ws::CloseCode, reason: &str) {
        println!("ws:cls[{}]: user with uuid {} closed ws cxn\n\tCode [{:?}] reason: {}",
                 time::precise_time_ns(),
                 "[[[ we don't have uuids in ws yet ]]]",
                 code,
                 reason);
        // TODO
    }

    fn on_error(&mut self, err: ws::Error) {
        println!("ws:err[{}]: user with uuid {} got error {}",
                 time::precise_time_ns(),
                 "[[[ we don't have uuids in ws yet ]]]",
                 err);
        // TODO
    }
}

pub fn server (domain: String, port: i32) -> () {
    let connections : ConnectionMap = Arc::new(Mutex::new(HashMap::new()));
    let addr = format!("{}:{}", domain, port);
    println!("WebSockets server listening on {}", addr);
    ws::listen(addr, |out| WSServer {
        out: out,
        connections: connections.clone(),
    }).unwrap();
}
<|endoftext|>


<commit_before>use event::Event;
use std::collections::HashMap;

pub struct VariableMapper<I> {
    tokenizer: I,
    variables: HashMap<String, String>,
}

impl<I> VariableMapper<I> {
    pub fn new(tokenizer: I) -> VariableMapper<I> {
        VariableMapper {
            tokenizer: tokenizer,
            variables: HashMap::new(),
        }
    }

    fn substitute_variables(&self, value: &str) -> String {
        value.split(' ').map(|value_part|
            match self.variables.get(value_part) {
                Some(v) => &v[..],
                None => value_part,
            }
        ).collect::<Vec<_>>().connect(" ")
    }
}

impl<'a, I> Iterator for VariableMapper<I>
    where I: Iterator<Item = Event<'a>>
{
    type Item = Event<'a>;

    fn next(&mut self) -> Option<Event<'a>> {
        match self.tokenizer.next() {
            Some(Event::Variable(name, value)) => {
                let val = self.substitute_variables(&value);
                self.variables.insert((*name).to_string(), val);
                self.next()
            },
            Some(Event::Property(name, value)) => {
                let real_value = self.substitute_variables(&value);
                Some(Event::Property(name, real_value.into()))
            },
            other => other,
        }
    }
}
<commit_msg>Start of trying to make variablemapper work again<commit_after>use event::{TopLevelEvent, Event, SassRule};
use std::collections::HashMap;

pub struct VariableMapper<I> {
    tokenizer: I,
    variables: HashMap<String, String>,
}

impl<I> VariableMapper<I> {
    pub fn new(tokenizer: I) -> VariableMapper<I> {
        VariableMapper {
            tokenizer: tokenizer,
            variables: HashMap::new(),
        }
    }

    fn substitute_variables(&self, value: &str) -> String {
        value.split(' ').map(|value_part|
            match self.variables.get(value_part) {
                Some(v) => &v[..],
                None => value_part,
            }
        ).collect::<Vec<_>>().connect(" ")
    }
}

impl<'a, I> Iterator for VariableMapper<I>
    where I: Iterator<Item = TopLevelEvent<'a>>
{
    type Item = TopLevelEvent<'a>;

    fn next(&mut self) -> Option<TopLevelEvent<'a>> {
        match self.tokenizer.next() {
            Some(TopLevelEvent::SassVariable { name, value }) => {
                let val = self.substitute_variables(&value);
                self.variables.insert((*name).to_string(), val);
                self.next()
            },
            // Some(Event::Property(name, value)) => {
            //     let real_value = self.substitute_variables(&value);
            //     Some(Event::Property(name, real_value.into()))
            // },
            other => other,
        }
    }
}
<|endoftext|>


<commit_before>use crate::directory::read_only_source::ReadOnlySource;
use crate::directory::{AntiCallToken, TerminatingWrite};
use byteorder::{ByteOrder, LittleEndian};
use crc32fast::Hasher;
use std::io;
use std::io::Write;

const COMMON_FOOTER_SIZE: usize = 4 * 5;

#[derive(Debug, Clone, PartialEq)]
pub struct Footer {
    pub tantivy_version: (u32, u32, u32),
    pub meta: String,
    pub versioned_footer: VersionedFooter,
}

impl Footer {
    pub fn new(versioned_footer: VersionedFooter) -> Self {
        let tantivy_version = (
            env!("CARGO_PKG_VERSION_MAJOR").parse().unwrap(),
            env!("CARGO_PKG_VERSION_MINOR").parse().unwrap(),
            env!("CARGO_PKG_VERSION_PATCH").parse().unwrap(),
        );
        Footer {
            tantivy_version,
            meta: format!(
                "tantivy {}.{}.{}, index v{}",
                tantivy_version.0,
                tantivy_version.1,
                tantivy_version.2,
                versioned_footer.version()
            ),
            versioned_footer,
        }
    }

    pub fn to_bytes(&self) -> Vec<u8> {
        let mut res = self.versioned_footer.to_bytes();
        res.extend_from_slice(self.meta.as_bytes());
        let len = res.len();
        res.resize(len + COMMON_FOOTER_SIZE, 0);
        let mut common_footer = &mut res[len..];
        LittleEndian::write_u32(&mut common_footer, self.meta.len() as u32);
        LittleEndian::write_u32(&mut common_footer[4..], self.tantivy_version.0);
        LittleEndian::write_u32(&mut common_footer[8..], self.tantivy_version.1);
        LittleEndian::write_u32(&mut common_footer[12..], self.tantivy_version.2);
        LittleEndian::write_u32(&mut common_footer[16..], (len + COMMON_FOOTER_SIZE) as u32);
        res
    }

    pub fn from_bytes(data: &[u8]) -> Result<Self, io::Error> {
        let len = data.len();
        if len < COMMON_FOOTER_SIZE + 4 {
            // 4 bytes for index version, stored in versioned footer
            return Err(io::Error::new(
                    io::ErrorKind::UnexpectedEof,
                    format!("File corrupted. The footer len must be over 24, while the entire file len is {}", len)
                    )
            );
        }

        let size = LittleEndian::read_u32(&data[len - 4..]) as usize;
        if len < size as usize {
            return Err(io::Error::new(
                io::ErrorKind::UnexpectedEof,
                format!(
                    "File corrupted. The footer len is {}, while the entire file len is {}",
                    size, len
                ),
            ));
        }
        let footer = &data[len - size as usize..];
        let meta_len = LittleEndian::read_u32(&footer[size - 20..]) as usize;
        let tantivy_major = LittleEndian::read_u32(&footer[size - 16..]);
        let tantivy_minor = LittleEndian::read_u32(&footer[size - 12..]);
        let tantivy_patch = LittleEndian::read_u32(&footer[size - 8..]);
        Ok(Footer {
            tantivy_version: (tantivy_major, tantivy_minor, tantivy_patch),
            meta: String::from_utf8_lossy(&footer[size - meta_len - 20..size - 20]).into_owned(),
            versioned_footer: VersionedFooter::from_bytes(&footer[..size - meta_len - 20])?,
        })
    }

    pub fn extract_footer(source: ReadOnlySource) -> Result<(Footer, ReadOnlySource), io::Error> {
        let footer = Footer::from_bytes(source.as_slice())?;
        let reader = source.slice_to(source.as_slice().len() - footer.size());
        Ok((footer, reader))
    }

    pub fn size(&self) -> usize {
        self.versioned_footer.size() as usize + self.meta.len() + 20
    }
}

#[derive(Debug, Clone, PartialEq)]
pub enum VersionedFooter {
    UnknownVersion { version: u32, size: u32 },
    V0(u32), // crc
}

impl VersionedFooter {
    pub fn to_bytes(&self) -> Vec<u8> {
        match self {
            VersionedFooter::V0(crc) => {
                let mut res = vec![0; 8];
                LittleEndian::write_u32(&mut res, 0);
                LittleEndian::write_u32(&mut res[4..], *crc);
                res
            }
            VersionedFooter::UnknownVersion { .. } => {
                panic!("Unsupported index should never get serialized");
            }
        }
    }

    pub fn from_bytes(footer: &[u8]) -> Result<Self, io::Error> {
        assert!(footer.len() >= 4);
        let version = LittleEndian::read_u32(footer);
        match version {
            0 => {
                if footer.len() == 8 {
                    Ok(VersionedFooter::V0(LittleEndian::read_u32(&footer[4..])))
                } else {
                    Err(io::Error::new(
                        io::ErrorKind::UnexpectedEof,
                        format!(
                            "File corrupted. The versioned footer len is {}, while it should be 8",
                            footer.len()
                        ),
                    ))
                }
            }
            version => Ok(VersionedFooter::UnknownVersion {
                version,
                size: footer.len() as u32,
            }),
        }
    }

    pub fn size(&self) -> u32 {
        match self {
            VersionedFooter::V0(_) => 8,
            VersionedFooter::UnknownVersion { size, .. } => *size,
        }
    }

    pub fn version(&self) -> u32 {
        match self {
            VersionedFooter::V0(_) => 0,
            VersionedFooter::UnknownVersion { version, .. } => *version,
        }
    }

    pub fn crc(&self) -> Option<u32> {
        match self {
            VersionedFooter::V0(crc) => Some(*crc),
            VersionedFooter::UnknownVersion { .. } => None,
        }
    }
}

pub(crate) struct FooterProxy<W: TerminatingWrite> {
    /// always Some except after terminate call
    hasher: Option<Hasher>,
    /// always Some except after terminate call
    writer: Option<W>,
}

impl<W: TerminatingWrite> FooterProxy<W> {
    pub fn new(writer: W) -> Self {
        FooterProxy {
            hasher: Some(Hasher::new()),
            writer: Some(writer),
        }
    }
}

impl<W: TerminatingWrite> Write for FooterProxy<W> {
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
        let count = self.writer.as_mut().unwrap().write(buf)?;
        self.hasher.as_mut().unwrap().update(&buf[..count]);
        Ok(count)
    }

    fn flush(&mut self) -> io::Result<()> {
        self.writer.as_mut().unwrap().flush()
    }
}

impl<W: TerminatingWrite> TerminatingWrite for FooterProxy<W> {
    fn terminate_ref(&mut self, _: AntiCallToken) -> io::Result<()> {
        let crc = self.hasher.take().unwrap().finalize();

        let footer = Footer::new(VersionedFooter::V0(crc)).to_bytes();
        let mut writer = self.writer.take().unwrap();
        writer.write_all(&footer)?;
        writer.terminate()
    }
}

#[cfg(test)]
mod tests {
    use crate::directory::footer::{Footer, VersionedFooter};

    #[test]
    fn test_serialize_deserialize_footer() {
        let crc = 123456;
        let footer = Footer::new(VersionedFooter::V0(crc));
        let footer_bytes = footer.to_bytes();

        assert_eq!(Footer::from_bytes(&footer_bytes).unwrap(), footer);
    }
}
<commit_msg>Petr tik n662 errror incompatible footer version (#696)<commit_after>use crate::directory::read_only_source::ReadOnlySource;
use crate::directory::{AntiCallToken, TerminatingWrite};
use byteorder::{ByteOrder, LittleEndian};
use crc32fast::Hasher;
use std::io;
use std::io::Write;

const COMMON_FOOTER_SIZE: usize = 4 * 5;

type CrcHashU32 = u32;

#[derive(Debug, Clone, PartialEq)]
pub struct Footer {
    pub tantivy_version: (u32, u32, u32),
    pub meta: String,
    pub versioned_footer: VersionedFooter,
}

impl Footer {
    pub fn new(versioned_footer: VersionedFooter) -> Self {
        let tantivy_version = (
            env!("CARGO_PKG_VERSION_MAJOR").parse().unwrap(),
            env!("CARGO_PKG_VERSION_MINOR").parse().unwrap(),
            env!("CARGO_PKG_VERSION_PATCH").parse().unwrap(),
        );
        Footer {
            tantivy_version,
            meta: format!(
                "tantivy v{}.{}.{}, index_format v{}",
                tantivy_version.0,
                tantivy_version.1,
                tantivy_version.2,
                versioned_footer.version()
            ),
            versioned_footer,
        }
    }

    /// Serialises the footer to a byte-array
    /// [      versioned_footer     |     meta      |    common_footer ]
    /// [           0..8            |     8..32     |        32..52    ]
    pub fn to_bytes(&self) -> Vec<u8> {
        let mut res = self.versioned_footer.to_bytes();
        res.extend_from_slice(self.meta.as_bytes());
        let len = res.len();
        res.resize(len + COMMON_FOOTER_SIZE, 0);
        let mut common_footer = &mut res[len..];
        LittleEndian::write_u32(&mut common_footer, self.meta.len() as u32);
        LittleEndian::write_u32(&mut common_footer[4..], self.tantivy_version.0);
        LittleEndian::write_u32(&mut common_footer[8..], self.tantivy_version.1);
        LittleEndian::write_u32(&mut common_footer[12..], self.tantivy_version.2);
        LittleEndian::write_u32(&mut common_footer[16..], (len + COMMON_FOOTER_SIZE) as u32);
        res
    }

    pub fn from_bytes(data: &[u8]) -> Result<Self, io::Error> {
        let len = data.len();
        if len < COMMON_FOOTER_SIZE + 4 {
            // 4 bytes for index version, stored in versioned footer
            return Err(io::Error::new(
                    io::ErrorKind::UnexpectedEof,
                    format!("File corrupted. The footer len must be over 24, while the entire file len is {}", len)
                    )
            );
        }

        let size = LittleEndian::read_u32(&data[len - 4..]) as usize;
        if len < size as usize {
            return Err(io::Error::new(
                io::ErrorKind::UnexpectedEof,
                format!(
                    "The footer len is {}, while the entire file len is {}. \
                     Your index is either corrupted or was built using a tantivy version\
                     anterior to 0.11.",
                    size, len
                ),
            ));
        }
        let footer = &data[len - size as usize..];
        let meta_len = LittleEndian::read_u32(&footer[size - COMMON_FOOTER_SIZE..]) as usize;
        let tantivy_major = LittleEndian::read_u32(&footer[size - 16..]);
        let tantivy_minor = LittleEndian::read_u32(&footer[size - 12..]);
        let tantivy_patch = LittleEndian::read_u32(&footer[size - 8..]);
        Ok(Footer {
            tantivy_version: (tantivy_major, tantivy_minor, tantivy_patch),
            meta: String::from_utf8_lossy(
                &footer[size - meta_len - COMMON_FOOTER_SIZE..size - COMMON_FOOTER_SIZE],
            )
            .into_owned(),
            versioned_footer: VersionedFooter::from_bytes(
                &footer[..size - meta_len - COMMON_FOOTER_SIZE],
            )?,
        })
    }

    pub fn extract_footer(source: ReadOnlySource) -> Result<(Footer, ReadOnlySource), io::Error> {
        let footer = Footer::from_bytes(source.as_slice())?;
        let reader = source.slice_to(source.as_slice().len() - footer.size());
        Ok((footer, reader))
    }

    pub fn size(&self) -> usize {
        self.versioned_footer.size() as usize + self.meta.len() + COMMON_FOOTER_SIZE
    }
}

/// Footer that includes a crc32 hash that enables us to checksum files in the index
#[derive(Debug, Clone, PartialEq)]
pub enum VersionedFooter {
    UnknownVersion { version: u32, size: u32 },
    V0(CrcHashU32), // crc
}

impl VersionedFooter {
    /// Serializes a valid `VersionedFooter` or panics if the version is unknown
    /// [   version    |   crc_hash  ]
    /// [      0..4    |     4..8    ]
    pub fn to_bytes(&self) -> Vec<u8> {
        match self {
            VersionedFooter::V0(crc) => {
                let mut buf = [0u8; 8];
                LittleEndian::write_u32(&mut buf[0..4], 0);
                LittleEndian::write_u32(&mut buf[4..8], *crc);
                buf.to_vec()
            }
            VersionedFooter::UnknownVersion { .. } => {
                panic!("Unsupported index should never get serialized");
            }
        }
    }

    pub fn from_bytes(footer: &[u8]) -> Result<Self, io::Error> {
        assert!(footer.len() >= 4);
        if footer.len() < 4 {
            return Err(io::Error::new(
                io::ErrorKind::InvalidData,
                "Footer should be more than 4 bytes.",
            ));
        }
        let version = LittleEndian::read_u32(footer);
        match version {
            // the first 4 bytes should be zeroed out thus returning a `0`
            0 => {
                if footer.len() != 8 {
                    return Err(io::Error::new(
                        io::ErrorKind::UnexpectedEof,
                        format!(
                            "File corrupted. The versioned footer len is {}, while it should be 8",
                            footer.len()
                        ),
                    ));
                }
                Ok(VersionedFooter::V0(LittleEndian::read_u32(&footer[4..])))
            }
            version => Ok(VersionedFooter::UnknownVersion {
                version,
                size: footer.len() as u32,
            }),
        }
    }

    pub fn size(&self) -> u32 {
        match self {
            VersionedFooter::V0(_) => 8,
            VersionedFooter::UnknownVersion { size, .. } => *size,
        }
    }

    pub fn version(&self) -> u32 {
        match self {
            VersionedFooter::V0(_) => 0,
            VersionedFooter::UnknownVersion { version, .. } => *version,
        }
    }

    pub fn crc(&self) -> Option<CrcHashU32> {
        match self {
            VersionedFooter::V0(crc) => Some(*crc),
            VersionedFooter::UnknownVersion { .. } => None,
        }
    }
}

pub(crate) struct FooterProxy<W: TerminatingWrite> {
    /// always Some except after terminate call
    hasher: Option<Hasher>,
    /// always Some except after terminate call
    writer: Option<W>,
}

impl<W: TerminatingWrite> FooterProxy<W> {
    pub fn new(writer: W) -> Self {
        FooterProxy {
            hasher: Some(Hasher::new()),
            writer: Some(writer),
        }
    }
}

impl<W: TerminatingWrite> Write for FooterProxy<W> {
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
        let count = self.writer.as_mut().unwrap().write(buf)?;
        self.hasher.as_mut().unwrap().update(&buf[..count]);
        Ok(count)
    }

    fn flush(&mut self) -> io::Result<()> {
        self.writer.as_mut().unwrap().flush()
    }
}

impl<W: TerminatingWrite> TerminatingWrite for FooterProxy<W> {
    fn terminate_ref(&mut self, _: AntiCallToken) -> io::Result<()> {
        let crc = self.hasher.take().unwrap().finalize();
        let footer = Footer::new(VersionedFooter::V0(crc)).to_bytes();
        let mut writer = self.writer.take().unwrap();
        writer.write_all(&footer)?;
        writer.terminate()
    }
}

#[cfg(test)]
mod tests {

    use crate::directory::footer::{Footer, VersionedFooter};
    use regex::Regex;

    #[test]
    fn test_serialize_deserialize_footer() {
        let crc = 123456;
        let footer = Footer::new(VersionedFooter::V0(crc));
        let footer_bytes = footer.to_bytes();
        assert_eq!(Footer::from_bytes(&footer_bytes).unwrap(), footer);
    }

    #[test]
    fn footer_length() {
        // test to make sure the ascii art in the doc-strings is correct
        let crc = 1111111 as u32;
        let versioned_footer = VersionedFooter::V0(crc);
        assert_eq!(versioned_footer.size(), 8);
        let footer = Footer::new(versioned_footer);
        let regex_ptn = Regex::new(
            "tantivy v[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\\.{0,10}, index_format v[0-9]{1,5}",
        )
        .unwrap();
        assert!(regex_ptn.find(&footer.meta).is_some());
    }

    #[test]
    fn versioned_footer_from_bytes() {
        use byteorder::{ByteOrder, LittleEndian};
        let v_footer_bytes = vec![0, 0, 0, 0, 12, 35, 89, 18];
        let versioned_footer = VersionedFooter::from_bytes(&v_footer_bytes).unwrap();
        let expected_versioned_footer =
            VersionedFooter::V0(LittleEndian::read_u32(&[12, 35, 89, 18]));
        assert_eq!(versioned_footer, expected_versioned_footer);

        assert_eq!(versioned_footer.to_bytes(), v_footer_bytes);
    }

    #[should_panic(expected = "Unsupported index should never get serialized")]
    #[test]
    fn versioned_footer_panic() {
        use byteorder::{ByteOrder, LittleEndian};
        let v_footer_bytes = vec![1; 8];
        let versioned_footer = VersionedFooter::from_bytes(&v_footer_bytes).unwrap();
        let expected_version = LittleEndian::read_u32(&[1, 1, 1, 1]);
        let expected_versioned_footer = VersionedFooter::UnknownVersion {
            version: expected_version,
            size: v_footer_bytes.len() as u32,
        };
        assert_eq!(versioned_footer, expected_versioned_footer);

        versioned_footer.to_bytes();
    }
}
<|endoftext|>


<commit_before>//! Updates crates.io index and builds new packages

use super::DocBuilder;
use DocBuilderError;
use rustc_serialize::json::Json;
use git2;
use db::connect_db;

impl DocBuilder {
    /// Updates crates.io-index repository and adds new crates into build queue
    pub fn get_new_crates(&self) -> Result<(), DocBuilderError> {

        let repo = try!(git2::Repository::open(&self.options.crates_io_index_path));

        let old_tree = try!(self.head_tree(&repo));
        try!(self.update_repo(&repo));
        let new_tree = try!(self.head_tree(&repo));

        let diff = try!(repo.diff_tree_to_tree(Some(&old_tree), Some(&new_tree), None));
        let conn = try!(connect_db());

        try!(diff.print(git2::DiffFormat::Patch, |_, _, diffline| -> bool {
            let line = String::from_utf8_lossy(diffline.content()).into_owned();
            // crate strings starts with '{'
            // skip if line is not a crate string
            if line.chars().nth(0) != Some('{') {
                return true;
            }
            let json = match Json::from_str(&line[..]) {
                Ok(j) => j,
                Err(err) => {
                    error!("Failed to parse crate string: {}", err);
                    // just continue even if we get an error for a crate
                    return true;
                }
            };

            if let Some((krate, version)) = json.as_object()
                                                .map(|obj| {
                                                    (obj.get("name")
                                                        .and_then(|n| n.as_string()),
                                                     obj.get("vers")
                                                        .and_then(|n| n.as_string()))
                                                }) {

                // Skip again if we can't get crate name and version
                if krate.is_none() || version.is_none() {
                    return true;
                }

                let _ = conn.execute("INSERT INTO queue (name, version) VALUES ($1, $2)",
                                     &[&krate.unwrap(), &version.unwrap()]);
            }

            true
        }));

        Ok(())
    }

    fn update_repo(&self, repo: &git2::Repository) -> Result<(), git2::Error> {
        let mut remote = try!(repo.find_remote("origin"));
        try!(remote.fetch(&["refs/heads/*:refs/remotes/origin/*"], None, None));

        // checkout master
        try!(repo.refname_to_id("refs/remotes/origin/master")
                 .and_then(|oid| repo.find_object(oid, None))
                 .and_then(|object| repo.reset(&object, git2::ResetType::Hard, None)));

        Ok(())
    }

    fn head_tree<'a>(&'a self, repo: &'a git2::Repository) -> Result<git2::Tree, git2::Error> {
        repo.head()
            .ok()
            .and_then(|head| head.target())
            .ok_or(git2::Error::from_str("HEAD SHA1 not found"))
            .and_then(|oid| repo.find_commit(oid))
            .and_then(|commit| commit.tree())
    }

    /// Builds packages from queue
    pub fn build_packages_queue(&mut self) -> Result<(), DocBuilderError> {
        let conn = try!(connect_db());

        for row in &try!(conn.query("SELECT id, name, version FROM queue ORDER BY id ASC", &[])) {
            let id: i32 = row.get(0);
            let name: String = row.get(1);
            let version: String = row.get(2);

            if let Ok(_) = self.build_package(&name[..], &version[..]) {
                // remove package from que
                let _ = conn.execute("DELETE FROM queue WHERE id = $1", &[&id]);
            } else {
                warn!("Failed to build package {}-{} from queue", name, version);
            }
        }

        Ok(())
    }
}

#[cfg(test)]
mod test {
    extern crate env_logger;
    use std::path::PathBuf;
    use {DocBuilder, DocBuilderOptions};

    #[test]
    #[ignore]
    fn test_get_new_crates() {
        let _ = env_logger::init();
        let options = DocBuilderOptions::from_prefix(PathBuf::from("../cratesfyi-prefix"));
        let docbuilder = DocBuilder::new(options);
        assert!(docbuilder.get_new_crates().is_ok());
    }

    #[test]
    #[ignore]
    fn test_build_packages_queue() {
        let _ = env_logger::init();
        let options = DocBuilderOptions::from_prefix(PathBuf::from("../cratesfyi-prefix"));
        let mut docbuilder = DocBuilder::new(options);
        assert!(docbuilder.build_packages_queue().is_ok());
    }
}
<commit_msg>Show error detail if a package fails to build in que<commit_after>//! Updates crates.io index and builds new packages

use super::DocBuilder;
use DocBuilderError;
use rustc_serialize::json::Json;
use git2;
use db::connect_db;

impl DocBuilder {
    /// Updates crates.io-index repository and adds new crates into build queue
    pub fn get_new_crates(&self) -> Result<(), DocBuilderError> {

        let repo = try!(git2::Repository::open(&self.options.crates_io_index_path));

        let old_tree = try!(self.head_tree(&repo));
        try!(self.update_repo(&repo));
        let new_tree = try!(self.head_tree(&repo));

        let diff = try!(repo.diff_tree_to_tree(Some(&old_tree), Some(&new_tree), None));
        let conn = try!(connect_db());

        try!(diff.print(git2::DiffFormat::Patch, |_, _, diffline| -> bool {
            let line = String::from_utf8_lossy(diffline.content()).into_owned();
            // crate strings starts with '{'
            // skip if line is not a crate string
            if line.chars().nth(0) != Some('{') {
                return true;
            }
            let json = match Json::from_str(&line[..]) {
                Ok(j) => j,
                Err(err) => {
                    error!("Failed to parse crate string: {}", err);
                    // just continue even if we get an error for a crate
                    return true;
                }
            };

            if let Some((krate, version)) = json.as_object()
                                                .map(|obj| {
                                                    (obj.get("name")
                                                        .and_then(|n| n.as_string()),
                                                     obj.get("vers")
                                                        .and_then(|n| n.as_string()))
                                                }) {

                // Skip again if we can't get crate name and version
                if krate.is_none() || version.is_none() {
                    return true;
                }

                let _ = conn.execute("INSERT INTO queue (name, version) VALUES ($1, $2)",
                                     &[&krate.unwrap(), &version.unwrap()]);
            }

            true
        }));

        Ok(())
    }

    fn update_repo(&self, repo: &git2::Repository) -> Result<(), git2::Error> {
        let mut remote = try!(repo.find_remote("origin"));
        try!(remote.fetch(&["refs/heads/*:refs/remotes/origin/*"], None, None));

        // checkout master
        try!(repo.refname_to_id("refs/remotes/origin/master")
                 .and_then(|oid| repo.find_object(oid, None))
                 .and_then(|object| repo.reset(&object, git2::ResetType::Hard, None)));

        Ok(())
    }

    fn head_tree<'a>(&'a self, repo: &'a git2::Repository) -> Result<git2::Tree, git2::Error> {
        repo.head()
            .ok()
            .and_then(|head| head.target())
            .ok_or(git2::Error::from_str("HEAD SHA1 not found"))
            .and_then(|oid| repo.find_commit(oid))
            .and_then(|commit| commit.tree())
    }

    /// Builds packages from queue
    pub fn build_packages_queue(&mut self) -> Result<(), DocBuilderError> {
        let conn = try!(connect_db());

        for row in &try!(conn.query("SELECT id, name, version FROM queue ORDER BY id ASC", &[])) {
            let id: i32 = row.get(0);
            let name: String = row.get(1);
            let version: String = row.get(2);

            match self.build_package(&name[..], &version[..]) {
                Ok(_) => { let _ = conn.execute("DELETE FROM queue WHERE id = $1", &[&id]); },
                Err(e) => error!("Failed to build package {}-{} from queue: {}", name, version, e),
            }
        }

        Ok(())
    }
}

#[cfg(test)]
mod test {
    extern crate env_logger;
    use std::path::PathBuf;
    use {DocBuilder, DocBuilderOptions};

    #[test]
    #[ignore]
    fn test_get_new_crates() {
        let _ = env_logger::init();
        let options = DocBuilderOptions::from_prefix(PathBuf::from("../cratesfyi-prefix"));
        let docbuilder = DocBuilder::new(options);
        assert!(docbuilder.get_new_crates().is_ok());
    }

    #[test]
    #[ignore]
    fn test_build_packages_queue() {
        let _ = env_logger::init();
        let options = DocBuilderOptions::from_prefix(PathBuf::from("../cratesfyi-prefix"));
        let mut docbuilder = DocBuilder::new(options);
        assert!(docbuilder.build_packages_queue().is_ok());
    }
}
<|endoftext|>


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

#[no_mangle]
pub extern "C" fn sys_message()
{
	println!("Hello World form eduOS-rs!");
}
<commit_msg>use a nicer test  message<commit_after>// Copyright (c) 2018 Stefan Lankes, RWTH Aachen University
//
// MIT License
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to
// the following conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

use scheduler;

#[no_mangle]
pub extern "C" fn sys_message()
{
	println!("hello from user task {}!", scheduler::get_current_taskid());
}
<|endoftext|>


<commit_before>// http://rosettacode.org/wiki/Towers_of_Hanoi#Rust
// not_tested

fn move(n: int, from: int, to: int, via: int) {
    if n > 0 {
        move(n - 1, from, via, to);
        println!("Move disk from pole {:d} to pole {:d}", from, to);
        move(n - 1, via, to, from);
    }
}

fn main() {
    move(4, 1, 2, 3);
}
<commit_msg>Update towers_of_hanoi.rs<commit_after>// http://rosettacode.org/wiki/Towers_of_Hanoi
// not_tested

fn move(n: int, from: int, to: int, via: int) {
    if n > 0 {
        move(n - 1, from, via, to);
        println!("Move disk from pole {:d} to pole {:d}", from, to);
        move(n - 1, via, to, from);
    }
}

fn main() {
    move(4, 1, 2, 3);
}
<|endoftext|>


<commit_before>use cgmath::EuclideanSpace;
use gilrs::{Axis, Button, Gilrs};
use std::f64::consts::PI;
use winit::{
    event,
    event_loop::{ControlFlow, EventLoop},
};

fn compute_projection_matrix(width: f32, height: f32) -> cgmath::Matrix4<f32> {
    let aspect = width / height;
    let f = 1.0 / (45.0f32.to_radians() / aspect).tan();
    let near = 0.1;

    #[cfg_attr(rustfmt, rustfmt_skip)]
    cgmath::Matrix4::new(
        f/aspect,  0.0,  0.0,   0.0,
        0.0,       f,    0.0,   0.0,
        0.0,       0.0,  0.0,  -1.0,
        0.0,       0.0,  near,  0.0)
}

fn make_swapchain(
    device: &wgpu::Device,
    surface: &wgpu::Surface,
    width: u32,
    height: u32,
) -> wgpu::SwapChain {
    device.create_swap_chain(
        &surface,
        &wgpu::SwapChainDescriptor {
            usage: wgpu::TextureUsage::OUTPUT_ATTACHMENT,
            format: wgpu::TextureFormat::Bgra8UnormSrgb,
            width,
            height,
            present_mode: wgpu::PresentMode::Mailbox,
        },
    )
}
fn make_depth_buffer(device: &wgpu::Device, width: u32, height: u32) -> wgpu::TextureView {
    device
        .create_texture(&wgpu::TextureDescriptor {
            size: wgpu::Extent3d { width, height, depth: 1 },
            mip_level_count: 1,
            sample_count: 1,
            dimension: wgpu::TextureDimension::D2,
            format: wgpu::TextureFormat::Depth32Float,
            usage: wgpu::TextureUsage::OUTPUT_ATTACHMENT,
            label: None,
        })
        .create_default_view()
}

fn main() {
    env_logger::init();

    let mut gilrs = Gilrs::new().unwrap();
    let mut current_gamepad = None;
    for (_id, gamepad) in gilrs.gamepads() {
        current_gamepad = Some(gamepad.id());
    }

    let mapfile = terra::MapFileBuilder::build().unwrap();

    let event_loop = EventLoop::new();
    let instance = wgpu::Instance::new(wgpu::BackendBit::VULKAN);
    let window = winit::window::Window::new(&event_loop).unwrap();
    for monitor in window.available_monitors() {
        if monitor.video_modes().any(|mode| mode.size().width == 1920) {
            window.set_fullscreen(Some(winit::window::Fullscreen::Borderless(monitor)));
            break;
        }
    }
    let mut size = window.inner_size();
    let surface = unsafe { instance.create_surface(&window) };
    let adapter =
        futures::executor::block_on(instance.request_adapter(&wgpu::RequestAdapterOptions {
            power_preference: wgpu::PowerPreference::Default,
            compatible_surface: Some(&surface),
        }))
        .unwrap();
    let (device, mut queue) = futures::executor::block_on(adapter.request_device(
        &wgpu::DeviceDescriptor {
            features: wgpu::Features::empty(),
            limits: wgpu::Limits::default(),
            shader_validation: true,
        },
        None,
    )).unwrap();
    let mut swap_chain = make_swapchain(&device, &surface, size.width, size.height);
    let mut depth_buffer = make_depth_buffer(&device, size.width, size.height);
    let mut proj = compute_projection_matrix(size.width as f32, size.height as f32);

    let planet_radius = 6371000.0;
    let mut angle = 0.0f64;
    let mut lat = 0.0f64;
    let mut long = 0.0f64;
    let mut altitude = 100.0f64;

    let mut terrain = terra::Terrain::new(&device, &mut queue, mapfile).unwrap();

    event_loop.run(move |event, _, control_flow| {
        *control_flow = if cfg!(feature = "metal-auto-capture") {
            ControlFlow::Exit
        } else {
            ControlFlow::Poll
        };
        match event {
            event::Event::WindowEvent { event, .. } => match event {
                event::WindowEvent::CloseRequested => {
                    *control_flow = ControlFlow::Exit;
                }
                event::WindowEvent::KeyboardInput {
                    input:
                        event::KeyboardInput {
                            virtual_keycode: Some(keycode),
                            state: event::ElementState::Pressed,
                            ..
                        },
                    ..
                } => match keycode {
                    event::VirtualKeyCode::Escape => *control_flow = ControlFlow::Exit,
                    event::VirtualKeyCode::Space => altitude += 0.1 * altitude,
                    event::VirtualKeyCode::Semicolon => altitude -= 0.1 * altitude,
                    // event::VirtualKeyCode::Left => eye.x -= 50.0,
                    // event::VirtualKeyCode::Right => eye.x += 50.0,
                    // event::VirtualKeyCode::Up => eye.z -= 50.0,
                    // event::VirtualKeyCode::Down => eye.z += 50.0,
                    _ => {}
                },
                event::WindowEvent::Resized(new_size) => {
                    size = new_size;
                    swap_chain = make_swapchain(&device, &surface, size.width, size.height);
                    depth_buffer = make_depth_buffer(&device, size.width, size.height);
                    proj = compute_projection_matrix(size.width as f32, size.height as f32);
                }
                _ => {}
            },
            event::Event::MainEventsCleared => {
                let frame = &swap_chain
                    .get_next_frame()
                    .unwrap().output.view;

                while let Some(gilrs::Event { id, event: _event, time: _ }) = gilrs.next_event() {
                    current_gamepad = Some(id);
                }
                if let Some(gamepad) = current_gamepad.map(|id| gilrs.gamepad(id)) {
                    lat += angle.cos() * gamepad.value(Axis::LeftStickY) as f64 * 0.01
                        - angle.sin() * gamepad.value(Axis::LeftStickX) as f64 * 0.01;

                    long += -angle.sin() * gamepad.value(Axis::LeftStickY) as f64 * 0.01
                        + angle.cos() * gamepad.value(Axis::LeftStickX) as f64 * 0.01;

                    angle -= gamepad.value(Axis::RightZ) as f64 * 0.01;

                    if gamepad.is_pressed(Button::DPadUp) {
                        altitude += 0.01 * altitude;
                    }
                    if gamepad.is_pressed(Button::DPadDown) {
                        altitude -= 0.01 * altitude;
                    }
                }

                lat = lat.max(-PI).min(PI);
                if long < -PI {
                    long += PI * 2.0;
                }
                if long > PI {
                    long -= PI * 2.0;
                }

                let r = altitude + planet_radius;
                let eye = cgmath::Point3::new(
                    r * lat.cos() * long.cos(),
                    r * lat.cos() * long.sin(),
                    r * lat.sin(),
                );

                let latc = lat + angle.cos() * 0.001;
                let longc = long - angle.sin() * 0.001;

                let center = cgmath::Point3::new(
                    planet_radius * latc.cos() * longc.cos() - eye.x,
                    planet_radius * latc.cos() * longc.sin() - eye.y,
                    planet_radius * latc.sin() - eye.z,
                );
                let up = cgmath::Vector3::new(eye.x as f32, eye.y as f32, eye.z as f32);

                let view = cgmath::Matrix4::look_at(
                    cgmath::Point3::origin(),
                    cgmath::Point3::new(center.x as f32, center.y as f32, center.z as f32),
                    up,
                );

                let view_proj = proj * view;
                let view_proj = mint::ColumnMatrix4 {
                    x: view_proj.x.into(),
                    y: view_proj.y.into(),
                    z: view_proj.z.into(),
                    w: view_proj.w.into(),
                };

                terrain.render(
                    &device,
                    &mut queue,
                    &frame,
                    &depth_buffer,
                    (size.width, size.height),
                    view_proj,
                    eye.into(),
                );
            }
            _ => (),
        }
    });
}
<commit_msg>Change starting location<commit_after>use cgmath::EuclideanSpace;
use gilrs::{Axis, Button, Gilrs};
use std::f64::consts::PI;
use winit::{
    event,
    event_loop::{ControlFlow, EventLoop},
};

fn compute_projection_matrix(width: f32, height: f32) -> cgmath::Matrix4<f32> {
    let aspect = width / height;
    let f = 1.0 / (45.0f32.to_radians() / aspect).tan();
    let near = 0.1;

    #[cfg_attr(rustfmt, rustfmt_skip)]
    cgmath::Matrix4::new(
        f/aspect,  0.0,  0.0,   0.0,
        0.0,       f,    0.0,   0.0,
        0.0,       0.0,  0.0,  -1.0,
        0.0,       0.0,  near,  0.0)
}

fn make_swapchain(
    device: &wgpu::Device,
    surface: &wgpu::Surface,
    width: u32,
    height: u32,
) -> wgpu::SwapChain {
    device.create_swap_chain(
        &surface,
        &wgpu::SwapChainDescriptor {
            usage: wgpu::TextureUsage::OUTPUT_ATTACHMENT,
            format: wgpu::TextureFormat::Bgra8UnormSrgb,
            width,
            height,
            present_mode: wgpu::PresentMode::Mailbox,
        },
    )
}
fn make_depth_buffer(device: &wgpu::Device, width: u32, height: u32) -> wgpu::TextureView {
    device
        .create_texture(&wgpu::TextureDescriptor {
            size: wgpu::Extent3d { width, height, depth: 1 },
            mip_level_count: 1,
            sample_count: 1,
            dimension: wgpu::TextureDimension::D2,
            format: wgpu::TextureFormat::Depth32Float,
            usage: wgpu::TextureUsage::OUTPUT_ATTACHMENT,
            label: None,
        })
        .create_default_view()
}

fn main() {
    env_logger::init();

    let mut gilrs = Gilrs::new().unwrap();
    let mut current_gamepad = None;
    for (_id, gamepad) in gilrs.gamepads() {
        current_gamepad = Some(gamepad.id());
    }

    let mapfile = terra::MapFileBuilder::build().unwrap();

    let event_loop = EventLoop::new();
    let instance = wgpu::Instance::new(wgpu::BackendBit::VULKAN);
    let window = winit::window::Window::new(&event_loop).unwrap();
    for monitor in window.available_monitors() {
        if monitor.video_modes().any(|mode| mode.size().width == 1920) {
            window.set_fullscreen(Some(winit::window::Fullscreen::Borderless(monitor)));
            break;
        }
    }
    let mut size = window.inner_size();
    let surface = unsafe { instance.create_surface(&window) };
    let adapter =
        futures::executor::block_on(instance.request_adapter(&wgpu::RequestAdapterOptions {
            power_preference: wgpu::PowerPreference::Default,
            compatible_surface: Some(&surface),
        }))
        .unwrap();
    let (device, mut queue) = futures::executor::block_on(adapter.request_device(
        &wgpu::DeviceDescriptor {
            features: wgpu::Features::empty(),
            limits: wgpu::Limits::default(),
            shader_validation: true,
        },
        None,
    )).unwrap();
    let mut swap_chain = make_swapchain(&device, &surface, size.width, size.height);
    let mut depth_buffer = make_depth_buffer(&device, size.width, size.height);
    let mut proj = compute_projection_matrix(size.width as f32, size.height as f32);

    let planet_radius = 6371000.0;
    let mut angle = 0.0f64;
    let mut lat = 0.85271f64;
    let mut long = 0.041054f64;
    let mut altitude = 1000000.0f64;

    let mut terrain = terra::Terrain::new(&device, &mut queue, mapfile).unwrap();

    event_loop.run(move |event, _, control_flow| {
        *control_flow = if cfg!(feature = "metal-auto-capture") {
            ControlFlow::Exit
        } else {
            ControlFlow::Poll
        };
        match event {
            event::Event::WindowEvent { event, .. } => match event {
                event::WindowEvent::CloseRequested => {
                    *control_flow = ControlFlow::Exit;
                }
                event::WindowEvent::KeyboardInput {
                    input:
                        event::KeyboardInput {
                            virtual_keycode: Some(keycode),
                            state: event::ElementState::Pressed,
                            ..
                        },
                    ..
                } => match keycode {
                    event::VirtualKeyCode::Escape => *control_flow = ControlFlow::Exit,
                    event::VirtualKeyCode::Space => altitude += 0.1 * altitude,
                    event::VirtualKeyCode::Semicolon => altitude -= 0.1 * altitude,
                    // event::VirtualKeyCode::Left => eye.x -= 50.0,
                    // event::VirtualKeyCode::Right => eye.x += 50.0,
                    // event::VirtualKeyCode::Up => eye.z -= 50.0,
                    // event::VirtualKeyCode::Down => eye.z += 50.0,
                    _ => {}
                },
                event::WindowEvent::Resized(new_size) => {
                    size = new_size;
                    swap_chain = make_swapchain(&device, &surface, size.width, size.height);
                    depth_buffer = make_depth_buffer(&device, size.width, size.height);
                    proj = compute_projection_matrix(size.width as f32, size.height as f32);
                }
                _ => {}
            },
            event::Event::MainEventsCleared => {
                let frame = &swap_chain
                    .get_next_frame()
                    .unwrap().output.view;

                while let Some(gilrs::Event { id, event: _event, time: _ }) = gilrs.next_event() {
                    current_gamepad = Some(id);
                }
                if let Some(gamepad) = current_gamepad.map(|id| gilrs.gamepad(id)) {
                    lat += angle.cos() * gamepad.value(Axis::LeftStickY) as f64 * 0.01
                        - angle.sin() * gamepad.value(Axis::LeftStickX) as f64 * 0.01;

                    long += -angle.sin() * gamepad.value(Axis::LeftStickY) as f64 * 0.01
                        + angle.cos() * gamepad.value(Axis::LeftStickX) as f64 * 0.01;

                    angle -= gamepad.value(Axis::RightZ) as f64 * 0.01;

                    if gamepad.is_pressed(Button::DPadUp) {
                        altitude += 0.01 * altitude;
                    }
                    if gamepad.is_pressed(Button::DPadDown) {
                        altitude -= 0.01 * altitude;
                    }
                }

                lat = lat.max(-PI).min(PI);
                if long < -PI {
                    long += PI * 2.0;
                }
                if long > PI {
                    long -= PI * 2.0;
                }

                let r = altitude + planet_radius;
                let eye = cgmath::Point3::new(
                    r * lat.cos() * long.cos(),
                    r * lat.cos() * long.sin(),
                    r * lat.sin(),
                );

                let latc = lat + angle.cos() * 0.001;
                let longc = long - angle.sin() * 0.001;

                let center = cgmath::Point3::new(
                    planet_radius * latc.cos() * longc.cos() - eye.x,
                    planet_radius * latc.cos() * longc.sin() - eye.y,
                    planet_radius * latc.sin() - eye.z,
                );
                let up = cgmath::Vector3::new(eye.x as f32, eye.y as f32, eye.z as f32);

                let view = cgmath::Matrix4::look_at(
                    cgmath::Point3::origin(),
                    cgmath::Point3::new(center.x as f32, center.y as f32, center.z as f32),
                    up,
                );

                let view_proj = proj * view;
                let view_proj = mint::ColumnMatrix4 {
                    x: view_proj.x.into(),
                    y: view_proj.y.into(),
                    z: view_proj.z.into(),
                    w: view_proj.w.into(),
                };

                terrain.render(
                    &device,
                    &mut queue,
                    &frame,
                    &depth_buffer,
                    (size.width, size.height),
                    view_proj,
                    eye.into(),
                );
            }
            _ => (),
        }
    });
}
<|endoftext|>