<commit_before>pub trait XmlStr {
    fn end_of_attribute(&self, quote: &str) -> Option<uint>;
    fn end_of_literal(&self, expected: &str) -> Option<uint>;
    fn end_of_version_num(&self) -> Option<uint>;
    fn end_of_char_data(&self) -> Option<uint>;
    fn end_of_cdata(&self) -> Option<uint>;
    fn end_of_decimal_chars(&self) -> Option<uint>;
    fn end_of_hex_chars(&self) -> Option<uint>;
    fn end_of_comment(&self) -> Option<uint>;
    fn end_of_pi_value(&self) -> Option<uint>;
    fn end_of_start_rest(&self, is_first: |char| -> bool, is_rest: |char| -> bool) -> Option<uint>;
    fn end_of_name(&self) -> Option<uint>;
    fn end_of_space(&self) -> Option<uint>;
    fn end_of_start_tag(&self) -> Option<uint>;
}

impl<'a> XmlStr for &'a str {
    fn end_of_attribute(&self, quote: &str) -> Option<uint> {
        if self.len() == 0 ||
           self.starts_with("&") ||
           self.starts_with("<") ||
           self.starts_with(quote)
        {
            return None;
        }

        let (quote_char, _) = quote.slice_shift_char();
        let quote_char = quote_char.expect("Cant have null quote");

        let mut positions = self.char_indices().skip_while(|&(_, c)| c != '&' && c != '<' && c != quote_char);

        match positions.next() {
            Some((offset, _)) => Some(offset),
            None => Some(self.len())
        }
    }

    fn end_of_literal(&self, expected: &str) -> Option<uint> {
        if self.starts_with(expected) {
            Some(expected.len())
        } else {
            None
        }
    }

    fn end_of_version_num(&self) -> Option<uint> {
        if self.starts_with("1.") {
            let mut positions = self.char_indices().peekable();
            positions.next();
            positions.next();

            // Need at least one character
            match positions.peek() {
                Some(&(_, c)) if c.is_decimal_char() => {},
                _ => return None,
            };

            let mut positions = positions.skip_while(|&(_, c)| c.is_decimal_char());
            match positions.next() {
                Some((offset, _)) => Some(offset),
                None => Some(self.len()),
            }
        } else {
            None
        }
    }

    fn end_of_char_data(&self) -> Option<uint> {
        if self.starts_with("<") ||
           self.starts_with("&") ||
           self.starts_with("]]>")
        {
            return None
        }

        // Using a hex literal because emacs' rust-mode doesn't
        // understand ] in a char literal. :-(
        let mut positions = self.char_indices().skip_while(|&(_, c)| c != '<' && c != '&' && c != '\x5d');

        loop {
            match positions.next() {
                None => return Some(self.len()),
                Some((offset, c)) if c == '<' || c == '&' => return Some(offset),
                Some((offset, _)) => {
                    let tail = self.slice_from(offset);
                    if tail.starts_with("]]>") {
                        return Some(offset)
                    } else {
                        // False alarm, resume scanning
                        continue;
                    }
                },
            }
        }
    }

    fn end_of_cdata(&self) -> Option<uint> {
        match self.find_str("]]>") {
            None => None,
            Some(offset) => Some(offset),
        }
    }

    fn end_of_decimal_chars(&self) -> Option<uint> {
        self.end_of_start_rest(|c| c.is_decimal_char(),
                               |c| c.is_decimal_char())
    }

    fn end_of_hex_chars(&self) -> Option<uint> {
        self.end_of_start_rest(|c| c.is_hex_char(),
                               |c| c.is_hex_char())
    }

    fn end_of_comment(&self) -> Option<uint> {
        // This deliberately does not include the >. -- is not allowed
        // in a comment, so we can just test the end if it matches the
        // complete close delimiter.
        match self.find_str("--") {
            None => None,
            Some(offset) => Some(offset),
        }
    }

    fn end_of_pi_value(&self) -> Option<uint> {
        match self.find_str("?>") {
            None => None,
            Some(offset) => Some(offset),
        }
    }

    fn end_of_start_rest(&self,
                         is_first: |char| -> bool,
                         is_rest: |char| -> bool)
                         -> Option<uint>
    {
        let mut positions = self.char_indices();

        match positions.next() {
            Some((_, c)) if is_first(c) => (),
            Some((_, _)) => return None,
            None => return None,
        };

        let mut positions = positions.skip_while(|&(_, c)| is_rest(c));
        match positions.next() {
            Some((offset, _)) => Some(offset),
            None => Some(self.len()),
        }
    }

    fn end_of_name(&self) -> Option<uint> {
        self.end_of_start_rest(|c| c.is_name_start_char(), |c| c.is_name_char())
    }

    fn end_of_space(&self) -> Option<uint> {
        self.end_of_start_rest(|c| c.is_space_char(), |c| c.is_space_char())
    }

    fn end_of_start_tag(&self) -> Option<uint> {
        let mut positions = self.char_indices();

        match positions.next() {
            Some((_, c)) if '<' == c => (),
            _ => return None,
        };

        match positions.next() {
            Some((offset, c)) =>
                match c {
                    '?' | '!' | '/' => None,
                    _ => Some(offset),
                },
            None => Some(self.len()),
        }
    }
}

trait XmlChar {
    fn is_name_start_char(&self) -> bool;
    fn is_name_char(&self) -> bool;
    fn is_space_char(&self) -> bool;
    fn is_decimal_char(&self) -> bool;
    fn is_hex_char(&self) -> bool;
}

impl XmlChar for char {
    fn is_name_start_char(&self) -> bool {
        match *self {
            ':'                         |
            'A'...'Z'                   |
            '_'                         |
            'a'...'z'                   |
            '\U000000C0'...'\U000000D6' |
            '\U000000D8'...'\U000000F6' |
            '\U000000F8'...'\U000002FF' |
            '\U00000370'...'\U0000037D' |
            '\U0000037F'...'\U00001FFF' |
            '\U0000200C'...'\U0000200D' |
            '\U00002070'...'\U0000218F' |
            '\U00002C00'...'\U00002FEF' |
            '\U00003001'...'\U0000D7FF' |
            '\U0000F900'...'\U0000FDCF' |
            '\U0000FDF0'...'\U0000FFFD' |
            '\U00010000'...'\U000EFFFF' => true,
            _ => false,
        }
    }

    fn is_name_char(&self) -> bool {
        if self.is_name_start_char() { return true; }
        match *self {
            '-'                 |
            '.'                 |
            '0'...'9'           |
            '\u00B7'            |
            '\u0300'...'\u036F' |
            '\u203F'...'\u2040' => true,
            _ => false
        }
    }

    fn is_space_char(&self) -> bool {
        match *self {
            '\x20' |
            '\x09' |
            '\x0D' |
            '\x0A' => true,
            _ => false,
        }
    }

    fn is_decimal_char(&self) -> bool {
        match *self {
            '0'...'9' => true,
            _ => false,
        }
    }

    fn is_hex_char(&self) -> bool {
        match *self {
            '0'...'9' |
            'a'...'f' |
            'A'...'F' => true,
            _ => false,
        }
    }
}

#[cfg(test)]
mod test {

use super::XmlStr;

#[test]
fn end_of_char_data_leading_ampersand() {
    assert_eq!("&".end_of_char_data(), None);
}

#[test]
fn end_of_char_data_leading_less_than() {
    assert_eq!("<".end_of_char_data(), None);
}

#[test]
fn end_of_char_data_leading_cdata_end() {
    assert_eq!("]]>".end_of_char_data(), None);
}

#[test]
fn end_of_char_data_until_ampersand() {
    assert_eq!("hello&world".end_of_char_data(), Some("hello".len()));
}

#[test]
fn end_of_char_data_until_less_than() {
    assert_eq!("hello<world".end_of_char_data(), Some("hello".len()));
}

#[test]
fn end_of_char_data_until_cdata_end() {
    assert_eq!("hello]]>world".end_of_char_data(), Some("hello".len()));
}

#[test]
fn end_of_char_data_includes_right_square() {
    assert_eq!("hello]world".end_of_char_data(), Some("hello]world".len()));
}

}
<commit_msg>Fixes for new return type of slice_shift_char<commit_after>pub trait XmlStr {
    fn end_of_attribute(&self, quote: &str) -> Option<uint>;
    fn end_of_literal(&self, expected: &str) -> Option<uint>;
    fn end_of_version_num(&self) -> Option<uint>;
    fn end_of_char_data(&self) -> Option<uint>;
    fn end_of_cdata(&self) -> Option<uint>;
    fn end_of_decimal_chars(&self) -> Option<uint>;
    fn end_of_hex_chars(&self) -> Option<uint>;
    fn end_of_comment(&self) -> Option<uint>;
    fn end_of_pi_value(&self) -> Option<uint>;
    fn end_of_start_rest(&self, is_first: |char| -> bool, is_rest: |char| -> bool) -> Option<uint>;
    fn end_of_name(&self) -> Option<uint>;
    fn end_of_space(&self) -> Option<uint>;
    fn end_of_start_tag(&self) -> Option<uint>;
}

impl<'a> XmlStr for &'a str {
    fn end_of_attribute(&self, quote: &str) -> Option<uint> {
        if self.len() == 0 ||
           self.starts_with("&") ||
           self.starts_with("<") ||
           self.starts_with(quote)
        {
            return None;
        }

        let (quote_char, _) = quote.slice_shift_char().expect("Cant have null quote");

        let mut positions = self.char_indices().skip_while(|&(_, c)| c != '&' && c != '<' && c != quote_char);

        match positions.next() {
            Some((offset, _)) => Some(offset),
            None => Some(self.len())
        }
    }

    fn end_of_literal(&self, expected: &str) -> Option<uint> {
        if self.starts_with(expected) {
            Some(expected.len())
        } else {
            None
        }
    }

    fn end_of_version_num(&self) -> Option<uint> {
        if self.starts_with("1.") {
            let mut positions = self.char_indices().peekable();
            positions.next();
            positions.next();

            // Need at least one character
            match positions.peek() {
                Some(&(_, c)) if c.is_decimal_char() => {},
                _ => return None,
            };

            let mut positions = positions.skip_while(|&(_, c)| c.is_decimal_char());
            match positions.next() {
                Some((offset, _)) => Some(offset),
                None => Some(self.len()),
            }
        } else {
            None
        }
    }

    fn end_of_char_data(&self) -> Option<uint> {
        if self.starts_with("<") ||
           self.starts_with("&") ||
           self.starts_with("]]>")
        {
            return None
        }

        // Using a hex literal because emacs' rust-mode doesn't
        // understand ] in a char literal. :-(
        let mut positions = self.char_indices().skip_while(|&(_, c)| c != '<' && c != '&' && c != '\x5d');

        loop {
            match positions.next() {
                None => return Some(self.len()),
                Some((offset, c)) if c == '<' || c == '&' => return Some(offset),
                Some((offset, _)) => {
                    let tail = self.slice_from(offset);
                    if tail.starts_with("]]>") {
                        return Some(offset)
                    } else {
                        // False alarm, resume scanning
                        continue;
                    }
                },
            }
        }
    }

    fn end_of_cdata(&self) -> Option<uint> {
        match self.find_str("]]>") {
            None => None,
            Some(offset) => Some(offset),
        }
    }

    fn end_of_decimal_chars(&self) -> Option<uint> {
        self.end_of_start_rest(|c| c.is_decimal_char(),
                               |c| c.is_decimal_char())
    }

    fn end_of_hex_chars(&self) -> Option<uint> {
        self.end_of_start_rest(|c| c.is_hex_char(),
                               |c| c.is_hex_char())
    }

    fn end_of_comment(&self) -> Option<uint> {
        // This deliberately does not include the >. -- is not allowed
        // in a comment, so we can just test the end if it matches the
        // complete close delimiter.
        match self.find_str("--") {
            None => None,
            Some(offset) => Some(offset),
        }
    }

    fn end_of_pi_value(&self) -> Option<uint> {
        match self.find_str("?>") {
            None => None,
            Some(offset) => Some(offset),
        }
    }

    fn end_of_start_rest(&self,
                         is_first: |char| -> bool,
                         is_rest: |char| -> bool)
                         -> Option<uint>
    {
        let mut positions = self.char_indices();

        match positions.next() {
            Some((_, c)) if is_first(c) => (),
            Some((_, _)) => return None,
            None => return None,
        };

        let mut positions = positions.skip_while(|&(_, c)| is_rest(c));
        match positions.next() {
            Some((offset, _)) => Some(offset),
            None => Some(self.len()),
        }
    }

    fn end_of_name(&self) -> Option<uint> {
        self.end_of_start_rest(|c| c.is_name_start_char(), |c| c.is_name_char())
    }

    fn end_of_space(&self) -> Option<uint> {
        self.end_of_start_rest(|c| c.is_space_char(), |c| c.is_space_char())
    }

    fn end_of_start_tag(&self) -> Option<uint> {
        let mut positions = self.char_indices();

        match positions.next() {
            Some((_, c)) if '<' == c => (),
            _ => return None,
        };

        match positions.next() {
            Some((offset, c)) =>
                match c {
                    '?' | '!' | '/' => None,
                    _ => Some(offset),
                },
            None => Some(self.len()),
        }
    }
}

trait XmlChar {
    fn is_name_start_char(&self) -> bool;
    fn is_name_char(&self) -> bool;
    fn is_space_char(&self) -> bool;
    fn is_decimal_char(&self) -> bool;
    fn is_hex_char(&self) -> bool;
}

impl XmlChar for char {
    fn is_name_start_char(&self) -> bool {
        match *self {
            ':'                         |
            'A'...'Z'                   |
            '_'                         |
            'a'...'z'                   |
            '\U000000C0'...'\U000000D6' |
            '\U000000D8'...'\U000000F6' |
            '\U000000F8'...'\U000002FF' |
            '\U00000370'...'\U0000037D' |
            '\U0000037F'...'\U00001FFF' |
            '\U0000200C'...'\U0000200D' |
            '\U00002070'...'\U0000218F' |
            '\U00002C00'...'\U00002FEF' |
            '\U00003001'...'\U0000D7FF' |
            '\U0000F900'...'\U0000FDCF' |
            '\U0000FDF0'...'\U0000FFFD' |
            '\U00010000'...'\U000EFFFF' => true,
            _ => false,
        }
    }

    fn is_name_char(&self) -> bool {
        if self.is_name_start_char() { return true; }
        match *self {
            '-'                 |
            '.'                 |
            '0'...'9'           |
            '\u00B7'            |
            '\u0300'...'\u036F' |
            '\u203F'...'\u2040' => true,
            _ => false
        }
    }

    fn is_space_char(&self) -> bool {
        match *self {
            '\x20' |
            '\x09' |
            '\x0D' |
            '\x0A' => true,
            _ => false,
        }
    }

    fn is_decimal_char(&self) -> bool {
        match *self {
            '0'...'9' => true,
            _ => false,
        }
    }

    fn is_hex_char(&self) -> bool {
        match *self {
            '0'...'9' |
            'a'...'f' |
            'A'...'F' => true,
            _ => false,
        }
    }
}

#[cfg(test)]
mod test {

use super::XmlStr;

#[test]
fn end_of_char_data_leading_ampersand() {
    assert_eq!("&".end_of_char_data(), None);
}

#[test]
fn end_of_char_data_leading_less_than() {
    assert_eq!("<".end_of_char_data(), None);
}

#[test]
fn end_of_char_data_leading_cdata_end() {
    assert_eq!("]]>".end_of_char_data(), None);
}

#[test]
fn end_of_char_data_until_ampersand() {
    assert_eq!("hello&world".end_of_char_data(), Some("hello".len()));
}

#[test]
fn end_of_char_data_until_less_than() {
    assert_eq!("hello<world".end_of_char_data(), Some("hello".len()));
}

#[test]
fn end_of_char_data_until_cdata_end() {
    assert_eq!("hello]]>world".end_of_char_data(), Some("hello".len()));
}

#[test]
fn end_of_char_data_includes_right_square() {
    assert_eq!("hello]world".end_of_char_data(), Some("hello]world".len()));
}

}
<|endoftext|>


<commit_before>use consts::*;
use proto::*;
use io::ZkIo;
use listeners::{ListenerSet, Subscription};
use mio;
use num::FromPrimitive;
use watch::{Watch, Watcher, WatchType, ZkWatch};
use std::io::Read;
use std::net::{SocketAddr, ToSocketAddrs};
use std::result;
use std::sync::atomic::{AtomicIsize, Ordering};
use std::sync::mpsc::{Sender, sync_channel, SyncSender};
use std::time::Duration;
use std::thread;

pub type ZkResult<T> = result::Result<T, ZkError>;

pub struct RawRequest {
    pub opcode: OpCode,
    pub data: ByteBuf,
    pub listener: Option<SyncSender<RawResponse>>,
    pub watch: Option<Watch>
}

pub struct RawResponse {
    pub header: ReplyHeader,
    pub data: ByteBuf
}

pub struct ZooKeeper {
    chroot: Option<String>,
    xid: AtomicIsize,
    io: mio::Sender<RawRequest>,
    listeners: ListenerSet<ZkState>,
}

impl ZooKeeper {

    fn zk_thread<F>(name: &str, task: F) -> ZkResult<thread::JoinHandle<()>>
    where F: FnOnce() + Send + 'static {
        thread::Builder::new()
            .name(name.to_owned())
            .spawn(task)
            .map_err(|_|ZkError::SystemError)
    }

    pub fn connect<W>(connect_string: &str, timeout: Duration, watcher: W) -> ZkResult<ZooKeeper>
    where W: Watcher + 'static {

        let (addrs, chroot) = try!(Self::parse_connect_string(connect_string));

        debug!("Initiating connection to {}", connect_string);

        let watch = ZkWatch::new(watcher, chroot.clone());
        let listeners = ListenerSet::<ZkState>::new();
        let listeners1 = listeners.clone();
        let io = ZkIo::new(addrs.clone(), timeout, watch.sender(), listeners1);
        let sender = io.sender();

        try!(Self::zk_thread("event", move || { watch.run().unwrap() }));
        try!(Self::zk_thread("io", move || { io.run().unwrap() }));

        Ok(ZooKeeper{chroot: chroot,
                     xid: AtomicIsize::new(1),
                     io: sender,
                     listeners: listeners,
        })
    }

    fn parse_connect_string(connect_string: &str) -> ZkResult<(Vec<SocketAddr>, Option<String>)> {
        let (chroot, end) = match connect_string.find('/') {
            Some(start) => {
                match &connect_string[start..connect_string.len()] {
                    "" | "/" => (None, start),
                    chroot => (Some(try!(Self::validate_path(chroot)).to_owned()), start)
                }
            },
            None => (None, connect_string.len())
        };

        let mut addrs = Vec::new();
        for addr_str in connect_string[..end].split(',') {
            let addr = match addr_str.trim().to_socket_addrs() {
                Ok(mut addrs) => match addrs.nth(0) {
                    Some(addr) => addr,
                    None => return Err(ZkError::BadArguments)
                },
                Err(_) => return Err(ZkError::BadArguments)
            };
            addrs.push(addr);
        }

        Ok((addrs, chroot))
    }

    fn xid(&self) -> i32 {
        self.xid.fetch_add(1, Ordering::Relaxed) as i32
    }

    fn request<Req: WriteTo, Resp: ReadFrom>(&self, opcode: OpCode, xid: i32, req: Req, watch: Option<Watch>) -> ZkResult<Resp> {
        let rh = RequestHeader{xid: xid, opcode: opcode};
        let buf = try!(to_len_prefixed_buf(rh, req).map_err(|_|ZkError::MarshallingError));

        let (resp_tx, resp_rx) = sync_channel(0);
        let request = RawRequest{opcode: opcode, data: buf, listener: Some(resp_tx), watch: watch};

        try!(self.io.send(request).map_err(|err| {
            warn!("error sending request: {:?}", err);
            ZkError::ConnectionLoss
        }));

        let mut response = try!(resp_rx.recv().map_err(|err| {
            warn!("error receiving response: {:?}", err);
            ZkError::ConnectionLoss
        }));

        match response.header.err {
            0 => Ok(try!(ReadFrom::read_from(&mut response.data).map_err(|_|ZkError::MarshallingError))),
            e => Err(FromPrimitive::from_i32(e).unwrap())
        }
    }

    fn validate_path(path: &str) -> ZkResult<&str> {
        match path {
            "" => Err(ZkError::BadArguments),
            path => if path.len() > 1 && path.chars().last() == Some('/') {
                    Err(ZkError::BadArguments)
                } else {
                    Ok(path)
                }
        }
    }

    fn path(&self, path: &str) -> ZkResult<String> {
        match self.chroot {
            Some(ref chroot) => match path {
                "/" => Ok(chroot.clone()),
                path => Ok(chroot.clone() + try!(Self::validate_path(path)))
            },
            None => Ok(try!(Self::validate_path(path)).to_owned())
        }
    }

    fn cut_chroot(&self, path: String) -> String {
        if let Some(ref chroot) = self.chroot {
            path[chroot.len()..].to_owned()
        } else {
            path
        }
    }

    pub fn add_auth(&self, scheme: &str, auth: Vec<u8>) -> ZkResult<()> {
        let req = AuthRequest{typ: 0, scheme: scheme.to_owned(), auth: auth};

        let _: EmptyResponse = try!(self.request(OpCode::Auth, -4, req, None));

        Ok(())
    }

    pub fn create(&self, path: &str, data: Vec<u8>, acl: Vec<Acl>, mode: CreateMode) -> ZkResult<String> {
        let req = CreateRequest{path: try!(self.path(path)), data: data, acl: acl, flags: mode as i32};

        let response: CreateResponse = try!(self.request(OpCode::Create, self.xid(), req, None));

        Ok(self.cut_chroot(response.path))
    }

    pub fn delete(&self, path: &str, version: i32) -> ZkResult<()> {
        let req = DeleteRequest{path: try!(self.path(path)), version: version};

        let _: EmptyResponse = try!(self.request(OpCode::Delete, self.xid(), req, None));

        Ok(())
    }

    pub fn exists(&self, path: &str, watch: bool) -> ZkResult<Option<Stat>> {
        let req = ExistsRequest{path: try!(self.path(path)), watch: watch};

        match self.request::<ExistsRequest, ExistsResponse>(OpCode::Exists, self.xid(), req, None) {
            Ok(response) => Ok(Some(response.stat)),
            Err(ZkError::NoNode) => Ok(None),
            Err(e) => Err(e)
        }
    }

    pub fn exists_w<W: FnOnce(&WatchedEvent) + Send + 'static>(&self, path: &str, watcher: W) -> ZkResult<Stat> {
        let req = ExistsRequest{path: try!(self.path(path)), watch: true};

        let watch = Watch{path: path.to_owned(),
                          watch_type: WatchType::Exist,
                          watcher: Box::new(watcher)};

        let response: ExistsResponse = try!(self.request(OpCode::Exists, self.xid(), req, Some(watch)));

        Ok(response.stat)
    }

    pub fn get_acl(&self, path: &str) -> ZkResult<(Vec<Acl>, Stat)> {
        let req = GetAclRequest{path: try!(self.path(path))};

        let response: GetAclResponse = try!(self.request(OpCode::GetAcl, self.xid(), req, None));

        Ok(response.acl_stat)
    }

    pub fn get_children_w<W: FnOnce(&WatchedEvent) + Send + 'static>(&self, path: &str, watcher: W) -> ZkResult<Vec<String>> {
        let req = GetChildrenRequest{path: try!(self.path(path)), watch: true};

        let watch = Watch{path: path.to_owned(),
                          watch_type: WatchType::Child,
                          watcher: Box::new(watcher)};

        let response: GetChildrenResponse = try!(self.request(OpCode::GetChildren, self.xid(), req, Some(watch)));

        Ok(response.children)
    }

    pub fn get_children(&self, path: &str, watch: bool) -> ZkResult<Vec<String>> {
        let req = GetChildrenRequest{path: try!(self.path(path)), watch: watch};

        let response: GetChildrenResponse = try!(self.request(OpCode::GetChildren, self.xid(), req, None));

        Ok(response.children)
    }

    pub fn get_data(&self, path: &str, watch: bool) -> ZkResult<(Vec<u8>, Stat)> {
        let req = GetDataRequest{path: try!(self.path(path)), watch: watch};

        let response: GetDataResponse = try!(self.request(OpCode::GetData, self.xid(), req, None));

        Ok(response.data_stat)
    }

    pub fn get_data_w<W: FnOnce(&WatchedEvent) + Send + 'static>(&self, path: &str, watcher: W) -> ZkResult<(Vec<u8>, Stat)> {
        let req = GetDataRequest{path: try!(self.path(path)), watch: true};

        let watch = Watch{path: path.to_owned(),
                          watch_type: WatchType::Data,
                          watcher: Box::new(watcher)};

        let response: GetDataResponse = try!(self.request(OpCode::GetData, self.xid(), req, Some(watch)));

        Ok(response.data_stat)
    }

    pub fn set_acl(&self, path: &str, acl: Vec<Acl>, version: i32) -> ZkResult<Stat> {
        let req = SetAclRequest{path: try!(self.path(path)), acl: acl, version: version};

        let response: SetAclResponse = try!(self.request(OpCode::SetAcl, self.xid(), req, None));

        Ok(response.stat)
    }

    pub fn set_data(&self, path: &str, data: Vec<u8>, version: i32) -> ZkResult<Stat> {
        let req = SetDataRequest{path: try!(self.path(path)), data: data, version: version};

        let response: SetDataResponse = try!(self.request(OpCode::SetData, self.xid(), req, None));

        Ok(response.stat)
    }

    pub fn add_listener(&self, chan: Sender<ZkState>) -> Subscription {
        self.listeners.subscribe(chan)
    }

    pub fn remove_listener(&self, sub: Subscription) {
        self.listeners.unsubscribe(sub);
    }

    pub fn close(&self) -> ZkResult<()> {
        let _: EmptyResponse = try!(self.request(OpCode::CloseSession, 0, EmptyRequest, None));

        Ok(())
    }
}

impl Drop for ZooKeeper {
    fn drop(&mut self) {
        if let Err(err) = self.close() {
            info!("error closing zookeeper connection in drop: {:?}", err);
        }
    }
}

#[cfg(test)]
mod tests {
    use super::ZooKeeper;
    use std::net::{Ipv4Addr, Ipv6Addr, SocketAddr, SocketAddrV4, SocketAddrV6};

    // TODO This is flaky, host resolving happens in a hectic order, sort?
    #[test]
    fn parse_connect_string() {
        let (addrs, chroot) = ZooKeeper::parse_connect_string("127.0.0.1:2181,::1:2181/mesos").ok().expect("Parse 1");
        assert_eq!(addrs,
                   vec![SocketAddr::V4(SocketAddrV4::new(Ipv4Addr::new(127,0,0,1), 2181)),
                        SocketAddr::V6(SocketAddrV6::new(Ipv6Addr::new(0,0,0,0,0,0,0,1), 2181, 0, 0))]);
        assert_eq!(chroot, Some("/mesos".to_owned()));

        let (addrs, chroot) = ZooKeeper::parse_connect_string("::1:2181").ok().expect("Parse 2");
        assert_eq!(addrs, vec![SocketAddr::V6(SocketAddrV6::new(Ipv6Addr::new(0,0,0,0,0,0,0,1), 2181, 0, 0))]);
        assert_eq!(chroot, None);

        let (addrs, chroot) = ZooKeeper::parse_connect_string("::1:2181/").ok().expect("Parse 3");
        assert_eq!(addrs, vec![SocketAddr::V6(SocketAddrV6::new(Ipv6Addr::new(0,0,0,0,0,0,0,1), 2181, 0, 0))]);
        assert_eq!(chroot, None);
    }

    #[test]
    #[should_panic(expected = "BadArguments")]
    fn parse_connect_string_fails() {
        // This fails with ZooKeeper.java: Path must not end with / character
        ZooKeeper::parse_connect_string("127.0.0.1:2181/mesos/").unwrap();
    }
}
<commit_msg>Disable flaky test on Linux (cheap Travis fix)<commit_after>use consts::*;
use proto::*;
use io::ZkIo;
use listeners::{ListenerSet, Subscription};
use mio;
use num::FromPrimitive;
use watch::{Watch, Watcher, WatchType, ZkWatch};
use std::io::Read;
use std::net::{SocketAddr, ToSocketAddrs};
use std::result;
use std::sync::atomic::{AtomicIsize, Ordering};
use std::sync::mpsc::{Sender, sync_channel, SyncSender};
use std::time::Duration;
use std::thread;

pub type ZkResult<T> = result::Result<T, ZkError>;

pub struct RawRequest {
    pub opcode: OpCode,
    pub data: ByteBuf,
    pub listener: Option<SyncSender<RawResponse>>,
    pub watch: Option<Watch>
}

pub struct RawResponse {
    pub header: ReplyHeader,
    pub data: ByteBuf
}

pub struct ZooKeeper {
    chroot: Option<String>,
    xid: AtomicIsize,
    io: mio::Sender<RawRequest>,
    listeners: ListenerSet<ZkState>,
}

impl ZooKeeper {

    fn zk_thread<F>(name: &str, task: F) -> ZkResult<thread::JoinHandle<()>>
    where F: FnOnce() + Send + 'static {
        thread::Builder::new()
            .name(name.to_owned())
            .spawn(task)
            .map_err(|_|ZkError::SystemError)
    }

    pub fn connect<W>(connect_string: &str, timeout: Duration, watcher: W) -> ZkResult<ZooKeeper>
    where W: Watcher + 'static {

        let (addrs, chroot) = try!(Self::parse_connect_string(connect_string));

        debug!("Initiating connection to {}", connect_string);

        let watch = ZkWatch::new(watcher, chroot.clone());
        let listeners = ListenerSet::<ZkState>::new();
        let listeners1 = listeners.clone();
        let io = ZkIo::new(addrs.clone(), timeout, watch.sender(), listeners1);
        let sender = io.sender();

        try!(Self::zk_thread("event", move || { watch.run().unwrap() }));
        try!(Self::zk_thread("io", move || { io.run().unwrap() }));

        Ok(ZooKeeper{chroot: chroot,
                     xid: AtomicIsize::new(1),
                     io: sender,
                     listeners: listeners,
        })
    }

    fn parse_connect_string(connect_string: &str) -> ZkResult<(Vec<SocketAddr>, Option<String>)> {
        let (chroot, end) = match connect_string.find('/') {
            Some(start) => {
                match &connect_string[start..connect_string.len()] {
                    "" | "/" => (None, start),
                    chroot => (Some(try!(Self::validate_path(chroot)).to_owned()), start)
                }
            },
            None => (None, connect_string.len())
        };

        let mut addrs = Vec::new();
        for addr_str in connect_string[..end].split(',') {
            let addr = match addr_str.trim().to_socket_addrs() {
                Ok(mut addrs) => match addrs.nth(0) {
                    Some(addr) => addr,
                    None => return Err(ZkError::BadArguments)
                },
                Err(_) => return Err(ZkError::BadArguments)
            };
            addrs.push(addr);
        }

        Ok((addrs, chroot))
    }

    fn xid(&self) -> i32 {
        self.xid.fetch_add(1, Ordering::Relaxed) as i32
    }

    fn request<Req: WriteTo, Resp: ReadFrom>(&self, opcode: OpCode, xid: i32, req: Req, watch: Option<Watch>) -> ZkResult<Resp> {
        let rh = RequestHeader{xid: xid, opcode: opcode};
        let buf = try!(to_len_prefixed_buf(rh, req).map_err(|_|ZkError::MarshallingError));

        let (resp_tx, resp_rx) = sync_channel(0);
        let request = RawRequest{opcode: opcode, data: buf, listener: Some(resp_tx), watch: watch};

        try!(self.io.send(request).map_err(|err| {
            warn!("error sending request: {:?}", err);
            ZkError::ConnectionLoss
        }));

        let mut response = try!(resp_rx.recv().map_err(|err| {
            warn!("error receiving response: {:?}", err);
            ZkError::ConnectionLoss
        }));

        match response.header.err {
            0 => Ok(try!(ReadFrom::read_from(&mut response.data).map_err(|_|ZkError::MarshallingError))),
            e => Err(FromPrimitive::from_i32(e).unwrap())
        }
    }

    fn validate_path(path: &str) -> ZkResult<&str> {
        match path {
            "" => Err(ZkError::BadArguments),
            path => if path.len() > 1 && path.chars().last() == Some('/') {
                    Err(ZkError::BadArguments)
                } else {
                    Ok(path)
                }
        }
    }

    fn path(&self, path: &str) -> ZkResult<String> {
        match self.chroot {
            Some(ref chroot) => match path {
                "/" => Ok(chroot.clone()),
                path => Ok(chroot.clone() + try!(Self::validate_path(path)))
            },
            None => Ok(try!(Self::validate_path(path)).to_owned())
        }
    }

    fn cut_chroot(&self, path: String) -> String {
        if let Some(ref chroot) = self.chroot {
            path[chroot.len()..].to_owned()
        } else {
            path
        }
    }

    pub fn add_auth(&self, scheme: &str, auth: Vec<u8>) -> ZkResult<()> {
        let req = AuthRequest{typ: 0, scheme: scheme.to_owned(), auth: auth};

        let _: EmptyResponse = try!(self.request(OpCode::Auth, -4, req, None));

        Ok(())
    }

    pub fn create(&self, path: &str, data: Vec<u8>, acl: Vec<Acl>, mode: CreateMode) -> ZkResult<String> {
        let req = CreateRequest{path: try!(self.path(path)), data: data, acl: acl, flags: mode as i32};

        let response: CreateResponse = try!(self.request(OpCode::Create, self.xid(), req, None));

        Ok(self.cut_chroot(response.path))
    }

    pub fn delete(&self, path: &str, version: i32) -> ZkResult<()> {
        let req = DeleteRequest{path: try!(self.path(path)), version: version};

        let _: EmptyResponse = try!(self.request(OpCode::Delete, self.xid(), req, None));

        Ok(())
    }

    pub fn exists(&self, path: &str, watch: bool) -> ZkResult<Option<Stat>> {
        let req = ExistsRequest{path: try!(self.path(path)), watch: watch};

        match self.request::<ExistsRequest, ExistsResponse>(OpCode::Exists, self.xid(), req, None) {
            Ok(response) => Ok(Some(response.stat)),
            Err(ZkError::NoNode) => Ok(None),
            Err(e) => Err(e)
        }
    }

    pub fn exists_w<W: FnOnce(&WatchedEvent) + Send + 'static>(&self, path: &str, watcher: W) -> ZkResult<Stat> {
        let req = ExistsRequest{path: try!(self.path(path)), watch: true};

        let watch = Watch{path: path.to_owned(),
                          watch_type: WatchType::Exist,
                          watcher: Box::new(watcher)};

        let response: ExistsResponse = try!(self.request(OpCode::Exists, self.xid(), req, Some(watch)));

        Ok(response.stat)
    }

    pub fn get_acl(&self, path: &str) -> ZkResult<(Vec<Acl>, Stat)> {
        let req = GetAclRequest{path: try!(self.path(path))};

        let response: GetAclResponse = try!(self.request(OpCode::GetAcl, self.xid(), req, None));

        Ok(response.acl_stat)
    }

    pub fn get_children_w<W: FnOnce(&WatchedEvent) + Send + 'static>(&self, path: &str, watcher: W) -> ZkResult<Vec<String>> {
        let req = GetChildrenRequest{path: try!(self.path(path)), watch: true};

        let watch = Watch{path: path.to_owned(),
                          watch_type: WatchType::Child,
                          watcher: Box::new(watcher)};

        let response: GetChildrenResponse = try!(self.request(OpCode::GetChildren, self.xid(), req, Some(watch)));

        Ok(response.children)
    }

    pub fn get_children(&self, path: &str, watch: bool) -> ZkResult<Vec<String>> {
        let req = GetChildrenRequest{path: try!(self.path(path)), watch: watch};

        let response: GetChildrenResponse = try!(self.request(OpCode::GetChildren, self.xid(), req, None));

        Ok(response.children)
    }

    pub fn get_data(&self, path: &str, watch: bool) -> ZkResult<(Vec<u8>, Stat)> {
        let req = GetDataRequest{path: try!(self.path(path)), watch: watch};

        let response: GetDataResponse = try!(self.request(OpCode::GetData, self.xid(), req, None));

        Ok(response.data_stat)
    }

    pub fn get_data_w<W: FnOnce(&WatchedEvent) + Send + 'static>(&self, path: &str, watcher: W) -> ZkResult<(Vec<u8>, Stat)> {
        let req = GetDataRequest{path: try!(self.path(path)), watch: true};

        let watch = Watch{path: path.to_owned(),
                          watch_type: WatchType::Data,
                          watcher: Box::new(watcher)};

        let response: GetDataResponse = try!(self.request(OpCode::GetData, self.xid(), req, Some(watch)));

        Ok(response.data_stat)
    }

    pub fn set_acl(&self, path: &str, acl: Vec<Acl>, version: i32) -> ZkResult<Stat> {
        let req = SetAclRequest{path: try!(self.path(path)), acl: acl, version: version};

        let response: SetAclResponse = try!(self.request(OpCode::SetAcl, self.xid(), req, None));

        Ok(response.stat)
    }

    pub fn set_data(&self, path: &str, data: Vec<u8>, version: i32) -> ZkResult<Stat> {
        let req = SetDataRequest{path: try!(self.path(path)), data: data, version: version};

        let response: SetDataResponse = try!(self.request(OpCode::SetData, self.xid(), req, None));

        Ok(response.stat)
    }

    pub fn add_listener(&self, chan: Sender<ZkState>) -> Subscription {
        self.listeners.subscribe(chan)
    }

    pub fn remove_listener(&self, sub: Subscription) {
        self.listeners.unsubscribe(sub);
    }

    pub fn close(&self) -> ZkResult<()> {
        let _: EmptyResponse = try!(self.request(OpCode::CloseSession, 0, EmptyRequest, None));

        Ok(())
    }
}

impl Drop for ZooKeeper {
    fn drop(&mut self) {
        if let Err(err) = self.close() {
            info!("error closing zookeeper connection in drop: {:?}", err);
        }
    }
}

#[cfg(test)]
mod tests {
    use super::ZooKeeper;
    use std::net::{Ipv4Addr, Ipv6Addr, SocketAddr, SocketAddrV4, SocketAddrV6};

    // TODO This is flaky on Travis, it works on my Linux box though.
    #[test]
    #[cfg(target_os = "macos")]
    fn parse_connect_string() {
        let (addrs, chroot) = ZooKeeper::parse_connect_string("127.0.0.1:2181,::1:2181/mesos").ok().expect("Parse 1");
        assert_eq!(addrs,
                   vec![SocketAddr::V4(SocketAddrV4::new(Ipv4Addr::new(127,0,0,1), 2181)),
                        SocketAddr::V6(SocketAddrV6::new(Ipv6Addr::new(0,0,0,0,0,0,0,1), 2181, 0, 0))]);
        assert_eq!(chroot, Some("/mesos".to_owned()));

        let (addrs, chroot) = ZooKeeper::parse_connect_string("::1:2181").ok().expect("Parse 2");
        assert_eq!(addrs, vec![SocketAddr::V6(SocketAddrV6::new(Ipv6Addr::new(0,0,0,0,0,0,0,1), 2181, 0, 0))]);
        assert_eq!(chroot, None);

        let (addrs, chroot) = ZooKeeper::parse_connect_string("::1:2181/").ok().expect("Parse 3");
        assert_eq!(addrs, vec![SocketAddr::V6(SocketAddrV6::new(Ipv6Addr::new(0,0,0,0,0,0,0,1), 2181, 0, 0))]);
        assert_eq!(chroot, None);
    }

    #[test]
    #[should_panic(expected = "BadArguments")]
    fn parse_connect_string_fails() {
        // This fails with ZooKeeper.java: Path must not end with / character
        ZooKeeper::parse_connect_string("127.0.0.1:2181/mesos/").unwrap();
    }
}
<|endoftext|>


<commit_before>use std::net::{TcpListener, ToSocketAddrs};
use tiny_web_server::client;

pub fn listen<A: ToSocketAddrs>(addr: A) {
    let listener = TcpListener::bind(addr).unwrap();

    for stream in listener.incoming() {
        stream.map(|s| client::handle_client(s));
    }
}
<commit_msg>:speaker: output error message<commit_after>use std::net::{TcpListener, ToSocketAddrs};
use tiny_web_server::client;

pub fn listen<A: ToSocketAddrs>(addr: A) {
    let listener = TcpListener::bind(addr).unwrap();

    for stream in listener.incoming() {
        match stream.map(|s| client::handle_client(s)) {
            Ok(_) => { /* successful */ }
            Err(why) => { println!("{}", why) }
        }
    }
}
<|endoftext|>


<commit_before>use std::net::SocketAddr;
use std::os::unix::io::RawFd;

use hyper::service::{make_service_fn, service_fn};
use hyper::{Body, Method, Request, Response, Server, StatusCode};
use tokio::net::TcpListener;
use tokio_stream::StreamExt;
use tracing::{error, info, warn};

use crate::config::Config;
use crate::identity;
use crate::tls::TlsError;
use crate::workload::WorkloadInformation;

use super::Error;

pub struct Inbound {
    cfg: Config,
    listener: TcpListener,
    cert_manager: identity::SecretManager,
    workloads: WorkloadInformation,
}

impl Inbound {
    pub async fn new(
        cfg: Config,
        workloads: WorkloadInformation,
        cert_manager: identity::SecretManager,
    ) -> Result<Inbound, Error> {
        let listener: TcpListener = TcpListener::bind(cfg.inbound_addr)
            .await
            .map_err(Error::Bind)?;
        match crate::socket::set_transparent(&listener) {
            Err(_e) => info!("running without transparent mode"),
            _ => info!("running with transparent mode"),
        };
        Ok(Inbound {
            cfg,
            workloads,
            listener,
            cert_manager,
        })
    }

    pub(super) async fn run(self) {
        let addr = self.listener.local_addr().unwrap();
        if self.cfg.tls {
            // TODO avoid duplication here
            let service = make_service_fn(|_| async {
                Ok::<_, hyper::Error>(service_fn(Self::serve_connect))
            });
            let boring_acceptor = crate::tls::BoringTlsAcceptor {
                acceptor: InboundCertProvider {
                    workloads: self.workloads.clone(),
                    cert_manager: self.cert_manager.clone(),
                },
            };
            let mut listener = hyper::server::conn::AddrIncoming::from_listener(self.listener)
                .expect("hbone bind");
            listener.set_nodelay(true);
            let incoming = hyper::server::accept::from_stream(
                tls_listener::builder(boring_acceptor)
                    .listen(listener)
                    .filter(|conn| {
                        // Avoid 'By default, if a client fails the TLS handshake, that is treated as an error, and the TlsListener will return an Err'
                        if let Err(err) = conn {
                            warn!("TLS handshake error: {}", err);
                            false
                        } else {
                            info!("TLS handshake succeeded");
                            true
                        }
                    }),
            );

            let server = Server::builder(incoming)
                .http2_only(true)
                .http2_initial_stream_window_size(self.cfg.window_size)
                .http2_initial_connection_window_size(self.cfg.connection_window_size)
                .http2_max_frame_size(self.cfg.frame_size)
                .serve(service);

            info!("HBONE listener established {}", addr);

            if let Err(e) = server.await {
                error!("server error: {}", e);
            }
        } else {
            warn!("TLS disabled");
            let service = make_service_fn(|_| async {
                Ok::<_, hyper::Error>(service_fn(Self::serve_connect))
            });

            let server = hyper::server::conn::AddrIncoming::from_listener(self.listener)
                .map(Server::builder)
                .expect("hbone bind")
                .http2_only(true)
                .http2_initial_stream_window_size(self.cfg.window_size)
                .http2_initial_connection_window_size(self.cfg.connection_window_size)
                .http2_max_frame_size(self.cfg.frame_size)
                .serve(service);

            info!("HBONE listener established {}", addr);

            if let Err(e) = server.await {
                error!("server error: {}", e);
            }
        }
    }
    async fn serve_connect(req: Request<Body>) -> Result<Response<Body>, hyper::Error> {
        let mut res = Response::new(Body::empty());
        match req.method() {
            &Method::CONNECT => {
                // TODO: uri or host?
                let uri = req.uri();

                let addr: SocketAddr = uri.to_string().as_str().parse().expect("must be an addr");
                let mut stream = tokio::net::TcpStream::connect(addr).await.expect("connect");
                info!("Got {} request to {}", req.method(), uri);
                *res.status_mut() = StatusCode::OK;
                tokio::task::spawn(async move {
                    match hyper::upgrade::on(req).await {
                        Ok(mut upgraded) => {
                            super::copy_hbone("hbone server", &mut upgraded, &mut stream)
                                .await
                                .expect("hbone server copy");
                        }
                        Err(e) => {
                            // Not sure if this can even happen
                            error!("No upgrade {e}");
                        }
                    }
                });
                // Send back our 200. TODO: 503 on failure to connect
                Ok(res)
            }
            // Return the 404 Not Found for other routes.
            method => {
                info!("Sending 404, got {method}");
                let mut not_found = Response::default();
                *not_found.status_mut() = StatusCode::NOT_FOUND;
                Ok(not_found)
            }
        }
    }
}

#[derive(Clone)]
struct InboundCertProvider {
    cert_manager: identity::SecretManager,
    workloads: WorkloadInformation,
}

#[async_trait::async_trait]
impl crate::tls::CertProvider for InboundCertProvider {
    async fn fetch_cert(&self, fd: RawFd) -> Result<boring::ssl::SslAcceptor, TlsError> {
        let orig = crate::socket::orig_dst_addr_fd(fd).map_err(TlsError::DestinationLookup)?;
        let identity = {
            let remote_addr = super::to_canonical_ip(orig);
            self.workloads
                .find_workload(&remote_addr)
                .ok_or(TlsError::CertificateLookup(remote_addr))?
                .identity()
        };
        info!("tls: accepting connection to {:?} ({})", orig, identity);
        let cert = self.cert_manager.fetch_certificate(identity).await?;
        let acc = cert.acceptor()?;
        Ok(acc)
    }
}
<commit_msg>Fix inbound connect failure panic (#126)<commit_after>use std::net::SocketAddr;
use std::os::unix::io::RawFd;

use hyper::service::{make_service_fn, service_fn};
use hyper::{Body, Method, Request, Response, Server, StatusCode};
use tokio::net::TcpListener;
use tokio_stream::StreamExt;
use tracing::{error, info, warn};

use crate::config::Config;
use crate::identity;
use crate::tls::TlsError;
use crate::workload::WorkloadInformation;

use super::Error;

pub struct Inbound {
    cfg: Config,
    listener: TcpListener,
    cert_manager: identity::SecretManager,
    workloads: WorkloadInformation,
}

impl Inbound {
    pub async fn new(
        cfg: Config,
        workloads: WorkloadInformation,
        cert_manager: identity::SecretManager,
    ) -> Result<Inbound, Error> {
        let listener: TcpListener = TcpListener::bind(cfg.inbound_addr)
            .await
            .map_err(Error::Bind)?;
        match crate::socket::set_transparent(&listener) {
            Err(_e) => info!("running without transparent mode"),
            _ => info!("running with transparent mode"),
        };
        Ok(Inbound {
            cfg,
            workloads,
            listener,
            cert_manager,
        })
    }

    pub(super) async fn run(self) {
        let addr = self.listener.local_addr().unwrap();
        if self.cfg.tls {
            // TODO avoid duplication here
            let service = make_service_fn(|_| async {
                Ok::<_, hyper::Error>(service_fn(Self::serve_connect))
            });
            let boring_acceptor = crate::tls::BoringTlsAcceptor {
                acceptor: InboundCertProvider {
                    workloads: self.workloads.clone(),
                    cert_manager: self.cert_manager.clone(),
                },
            };
            let mut listener = hyper::server::conn::AddrIncoming::from_listener(self.listener)
                .expect("hbone bind");
            listener.set_nodelay(true);
            let incoming = hyper::server::accept::from_stream(
                tls_listener::builder(boring_acceptor)
                    .listen(listener)
                    .filter(|conn| {
                        // Avoid 'By default, if a client fails the TLS handshake, that is treated as an error, and the TlsListener will return an Err'
                        if let Err(err) = conn {
                            warn!("TLS handshake error: {}", err);
                            false
                        } else {
                            info!("TLS handshake succeeded");
                            true
                        }
                    }),
            );

            let server = Server::builder(incoming)
                .http2_only(true)
                .http2_initial_stream_window_size(self.cfg.window_size)
                .http2_initial_connection_window_size(self.cfg.connection_window_size)
                .http2_max_frame_size(self.cfg.frame_size)
                .serve(service);

            info!("HBONE listener established {}", addr);

            if let Err(e) = server.await {
                error!("server error: {}", e);
            }
        } else {
            warn!("TLS disabled");
            let service = make_service_fn(|_| async {
                Ok::<_, hyper::Error>(service_fn(Self::serve_connect))
            });

            let server = hyper::server::conn::AddrIncoming::from_listener(self.listener)
                .map(Server::builder)
                .expect("hbone bind")
                .http2_only(true)
                .http2_initial_stream_window_size(self.cfg.window_size)
                .http2_initial_connection_window_size(self.cfg.connection_window_size)
                .http2_max_frame_size(self.cfg.frame_size)
                .serve(service);

            info!("HBONE listener established {}", addr);

            if let Err(e) = server.await {
                error!("server error: {}", e);
            }
        }
    }
    async fn serve_connect(req: Request<Body>) -> Result<Response<Body>, hyper::Error> {
        let mut res = Response::new(Body::empty());
        match req.method() {
            &Method::CONNECT => {
                // TODO: uri or host?
                let uri = req.uri();
                let addr: SocketAddr = uri.to_string().as_str().parse().expect("must be an addr");
                let stream = tokio::net::TcpStream::connect(addr).await;
                match stream {
                    Err(err) => {
                        warn!("connect to {} failed: {}", addr, err);
                        *res.status_mut() = StatusCode::SERVICE_UNAVAILABLE;
                        Ok(res)
                    }
                    Ok(stream) => {
                        let mut stream = stream;
                        info!("Got {} request to {}", req.method(), uri);
                        *res.status_mut() = StatusCode::OK;
                        tokio::task::spawn(async move {
                            match hyper::upgrade::on(req).await {
                                Ok(mut upgraded) => {
                                    super::copy_hbone("hbone server", &mut upgraded, &mut stream)
                                        .await
                                        .expect("hbone server copy");
                                }
                                Err(e) => {
                                    // Not sure if this can even happen
                                    error!("No upgrade {e}");
                                }
                            }
                        });
                        // Send back our 200.
                        Ok(res)
                    }
                }
            }
            // Return the 404 Not Found for other routes.
            method => {
                info!("Sending 404, got {method}");
                let mut not_found = Response::default();
                *not_found.status_mut() = StatusCode::NOT_FOUND;
                Ok(not_found)
            }
        }
    }
}

#[derive(Clone)]
struct InboundCertProvider {
    cert_manager: identity::SecretManager,
    workloads: WorkloadInformation,
}

#[async_trait::async_trait]
impl crate::tls::CertProvider for InboundCertProvider {
    async fn fetch_cert(&self, fd: RawFd) -> Result<boring::ssl::SslAcceptor, TlsError> {
        let orig = crate::socket::orig_dst_addr_fd(fd).map_err(TlsError::DestinationLookup)?;
        let identity = {
            let remote_addr = super::to_canonical_ip(orig);
            self.workloads
                .find_workload(&remote_addr)
                .ok_or(TlsError::CertificateLookup(remote_addr))?
                .identity()
        };
        info!("tls: accepting connection to {:?} ({})", orig, identity);
        let cert = self.cert_manager.fetch_certificate(identity).await?;
        let acc = cert.acceptor()?;
        Ok(acc)
    }
}
<|endoftext|>


<commit_before>#![no_std]

use libtock_platform::{
    share::Handle, subscribe::OneId, DefaultConfig, ErrorCode, Subscribe, Syscalls, Upcall,
};

/// The Buttonss driver
///
/// # Example
/// ```ignore
/// use libtock2::Buttons;
///
/// // Read button state
/// Buttons::is_pressed(0);
///
/// // Register for events
///
/// let listener = ButtonListener(|button, state| {
///     // make use of the button's state
/// });
///
/// share::scope(|subscribe| {
///     if let Ok(()) = Buttons::register_listener(&listener, subscribe) {
///         // yield
///     }
/// });
/// ```
pub struct Buttons<S: Syscalls>(S);

#[derive(Debug, PartialEq)]
pub enum ButtonState {
    Pressed,
    Released,
    Unknown,
}

impl From<u32> for ButtonState {
    fn from(original: u32) -> ButtonState {
        match original {
            0 => ButtonState::Released,
            1 => ButtonState::Pressed,
            _ => ButtonState::Unknown,
        }
    }
}

impl<S: Syscalls> Buttons<S> {
    /// Run a check against the buttons capsule to ensure it is present.
    ///
    /// Returns `Some(number_of_buttons)` if the driver was present. This does not necessarily mean
    /// that the driver is working, as it may still fail to allocate grant
    /// memory.
    pub fn count() -> Result<u32, ErrorCode> {
        let command_return = S::command(DRIVER_ID, BUTTONS_COUNT, 0, 0);
        if let Some(error) = command_return.get_failure() {
            Err(error)
        } else {
            match command_return.get_success_u32() {
                Some(value) => Ok(value.into()),
                None => {
                    unreachable!()
                }
            }
        }
    }

    pub fn read(button: u32) -> Result<ButtonState, ErrorCode> {
        let command_return = S::command(DRIVER_ID, BUTTONS_READ, button, 0);
        if let Some(error) = command_return.get_failure() {
            Err(error)
        } else {
            match command_return.get_success_u32() {
                Some(value) => Ok(value.into()),
                None => {
                    unreachable!()
                }
            }
        }
    }

    pub fn is_pressed(button: u32) -> bool {
        Self::read(button)
            .map(|state| state == ButtonState::Pressed)
            .unwrap_or(false)
    }

    pub fn is_released(button: u32) -> bool {
        Self::read(button)
            .map(|state| state == ButtonState::Released)
            .unwrap_or(false)
    }

    pub fn enable_interrupts(button: u32) -> Result<(), ErrorCode> {
        if let Some(error) =
            S::command(DRIVER_ID, BUTTONS_ENABLE_INTERRUPTS, button, 0).get_failure()
        {
            Err(error)
        } else {
            Ok(())
        }
    }

    pub fn disable_interrupts(button: u32) -> Result<(), ErrorCode> {
        if let Some(error) =
            S::command(DRIVER_ID, BUTTONS_DISABLE_INTERRUPTS, button, 0).get_failure()
        {
            Err(error)
        } else {
            Ok(())
        }
    }

    pub fn register_listener<'share, F: Fn(u32, ButtonState)>(
        listener: &'share ButtonListener<F>,
        subscribe: Handle<Subscribe<'share, S, DRIVER_ID, 0>>,
    ) -> Result<(), ErrorCode> {
        S::subscribe::<_, _, DefaultConfig, DRIVER_ID, 0>(subscribe, listener)
    }

    pub fn unregister_listener() {
        S::unsubscribe(DRIVER_ID, 0)
    }
}

pub struct ButtonListener<F: Fn(u32, ButtonState)>(F);

impl<F: Fn(u32, ButtonState)> Upcall<OneId<DRIVER_ID, 0>> for ButtonListener<F> {
    fn upcall(&self, button_index: u32, state: u32, _arg2: u32) {
        self.0(button_index, state.into())
    }
}

const DRIVER_ID: u32 = 3;

// Command IDs
const BUTTONS_COUNT: u32 = 0;

const BUTTONS_ENABLE_INTERRUPTS: u32 = 1;
const BUTTONS_DISABLE_INTERRUPTS: u32 = 2;

const BUTTONS_READ: u32 = 3;

#[cfg(test)]
mod tests;
<commit_msg>rebase<commit_after>#![no_std]

use libtock_platform::{
    share::Handle, subscribe::OneId, DefaultConfig, ErrorCode, Subscribe, Syscalls, Upcall,
};

/// The Buttonss driver
///
/// # Example
/// ```ignore
/// use libtock2::Buttons;
///
/// // Read button state
/// Buttons::is_pressed(0);
///
/// // Register for events
///
/// let listener = ButtonListener(|button, state| {
///     // make use of the button's state
/// });
///
/// share::scope(|subscribe| {
///     if let Ok(()) = Buttons::register_listener(&listener, subscribe) {
///         // yield
///     }
/// });
/// ```
pub struct Buttons<S: Syscalls>(S);

#[derive(Debug, PartialEq)]
pub enum ButtonState {
    Pressed,
    Released,
    Unknown,
}

impl From<u32> for ButtonState {
    fn from(original: u32) -> ButtonState {
        match original {
            0 => ButtonState::Released,
            1 => ButtonState::Pressed,
            _ => ButtonState::Unknown,
        }
    }
}

impl<S: Syscalls> Buttons<S> {
    /// Run a check against the buttons capsule to ensure it is present.
    ///
    /// Returns `Some(number_of_buttons)` if the driver was present. This does not necessarily mean
    /// that the driver is working, as it may still fail to allocate grant
    /// memory.
    pub fn count() -> Result<u32, ErrorCode> {
        Ok(S::command(DRIVER_ID, BUTTONS_COUNT, 0, 0).to_result()?)
    }

    pub fn read(button: u32) -> Result<ButtonState, ErrorCode> {
        let button_state: u32 = S::command(DRIVER_ID, BUTTONS_READ, button, 0).to_result()?;
        Ok(button_state.into())
    }

    pub fn is_pressed(button: u32) -> bool {
        Self::read(button)
            .map(|state| state == ButtonState::Pressed)
            .unwrap_or(false)
    }

    pub fn is_released(button: u32) -> bool {
        Self::read(button)
            .map(|state| state == ButtonState::Released)
            .unwrap_or(false)
    }

    pub fn enable_interrupts(button: u32) -> Result<(), ErrorCode> {
        S::command(DRIVER_ID, BUTTONS_ENABLE_INTERRUPTS, button, 0).to_result()
    }

    pub fn disable_interrupts(button: u32) -> Result<(), ErrorCode> {
        S::command(DRIVER_ID, BUTTONS_DISABLE_INTERRUPTS, button, 0).to_result()
    }

    pub fn register_listener<'share, F: Fn(u32, ButtonState)>(
        listener: &'share ButtonListener<F>,
        subscribe: Handle<Subscribe<'share, S, DRIVER_ID, 0>>,
    ) -> Result<(), ErrorCode> {
        S::subscribe::<_, _, DefaultConfig, DRIVER_ID, 0>(subscribe, listener)
    }

    pub fn unregister_listener() {
        S::unsubscribe(DRIVER_ID, 0)
    }
}

pub struct ButtonListener<F: Fn(u32, ButtonState)>(F);

impl<F: Fn(u32, ButtonState)> Upcall<OneId<DRIVER_ID, 0>> for ButtonListener<F> {
    fn upcall(&self, button_index: u32, state: u32, _arg2: u32) {
        self.0(button_index, state.into())
    }
}

const DRIVER_ID: u32 = 3;

// Command IDs
const BUTTONS_COUNT: u32 = 0;

const BUTTONS_ENABLE_INTERRUPTS: u32 = 1;
const BUTTONS_DISABLE_INTERRUPTS: u32 = 2;

const BUTTONS_READ: u32 = 3;

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


<commit_before>//! Types for extensible text message events ([MSC1767]).
//!
//! # Extensible events
//!
//! MSCs [1767] (Text, Emote and Notice), [3551] (Files), [3552] (Images and Stickers), [3553]
//! (Videos), [3246] (Audio), and [3488] (Location) introduce new primary types called extensible
//! events. These types are meant to replace the `m.room.message` primary type and its `msgtype`s.
//! Other MSCs introduce new types with an `m.room.message` fallback, like [MSC3245] (Voice
//! Messages), and types that only have an extensible events format, like [MSC3381] (Polls).
//!
//! # Transition Period
//!
//! MSC1767 defines a transition period that will start after the extensible events are released in
//! a Matrix version. It should last approximately one year, but the end of that period will be
//! formalized in a new Matrix version.
//!
//! The new primary types should not be sent over the Matrix network before the end of the
//! transition period. Instead, transitional `m.room.message` events should be sent. These
//! transitional events include the content of the now legacy `m.room.message` event and the content
//! of the new extensible event types in a single event.
//!
//! # How to use them
//!
//! First, enable the `unstable-mscXXXX` features (where `XXXX` is the number of the MSC) for the
//! needed extensible types.
//!
//! The recommended way to send transitional extensible events while they are unstable and during
//! the transition period is to build one of the new primary types and then to convert it to a
//! [`RoomMessageEventContent`] by using `.into()` or `RoomMessageEventContent::from()`. The
//! provided constructors will copy the relevant data in the legacy fields.
//!
//! For incoming events, a `RoomMessageEventContent` can be converted to an extensible event with
//! the relevant `from_*_room_message` method on the primary type. This conversion will work even
//! with legacy `m.room.message` events that don't have extensible events content.
//!
//! It is also possible to enable extensible events support and continue using
//! `RoomMessageEventContent`'s constructors. The data will be duplicated in both the legacy and
//! extensible events fields.
//!
//! [MSC1767]: https://github.com/matrix-org/matrix-spec-proposals/pull/1767
//! [1767]: https://github.com/matrix-org/matrix-spec-proposals/pull/1767
//! [3551]: https://github.com/matrix-org/matrix-spec-proposals/pull/3551
//! [3552]: https://github.com/matrix-org/matrix-spec-proposals/pull/3552
//! [3553]: https://github.com/matrix-org/matrix-spec-proposals/pull/3553
//! [3246]: https://github.com/matrix-org/matrix-spec-proposals/pull/3246
//! [3488]: https://github.com/matrix-org/matrix-spec-proposals/pull/3488
//! [MSC3245]: https://github.com/matrix-org/matrix-spec-proposals/pull/3245
//! [MSC3381]: https://github.com/matrix-org/matrix-spec-proposals/pull/3381
//! [`RoomMessageEventContent`]: super::room::message::RoomMessageEventContent
use std::{convert::TryFrom, ops::Deref};

use ruma_macros::EventContent;
use serde::{Deserialize, Serialize};
use thiserror::Error;

pub(crate) mod content_serde;

use content_serde::MessageContentSerDeHelper;

use super::room::message::{FormattedBody, MessageFormat, Relation, TextMessageEventContent};

/// The payload for an extensible text message.
///
/// This is the new primary type introduced in [MSC1767] and should not be sent before the end of
/// the transition period. See the documentation of the [`message`] module for more information.
///
/// `MessageEventContent` can be converted to a [`RoomMessageEventContent`] with a
/// [`MessageType::Text`]. You can convert it back with
/// [`MessageEventContent::from_text_room_message()`].
///
/// [MSC1767]: https://github.com/matrix-org/matrix-spec-proposals/pull/1767
/// [`message`]: super::message
/// [`RoomMessageEventContent`]: super::room::message::RoomMessageEventContent
/// [`MessageType::Text`]: super::room::message::MessageType::Text
#[derive(Clone, Debug, Serialize, Deserialize, EventContent)]
#[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)]
#[ruma_event(type = "m.message", kind = MessageLike)]
pub struct MessageEventContent {
    /// The message's text content.
    #[serde(flatten)]
    pub message: MessageContent,

    /// Information about related messages for [rich replies].
    ///
    /// [rich replies]: https://spec.matrix.org/v1.2/client-server-api/#rich-replies
    #[serde(flatten, skip_serializing_if = "Option::is_none")]
    pub relates_to: Option<Relation>,
}

impl MessageEventContent {
    /// A convenience constructor to create a plain text message.
    pub fn plain(body: impl Into<String>) -> Self {
        Self { message: MessageContent::plain(body), relates_to: None }
    }

    /// A convenience constructor to create an HTML message.
    pub fn html(body: impl Into<String>, html_body: impl Into<String>) -> Self {
        Self { message: MessageContent::html(body, html_body), relates_to: None }
    }

    /// A convenience constructor to create a Markdown message.
    ///
    /// Returns an HTML message if some Markdown formatting was detected, otherwise returns a plain
    /// text message.
    #[cfg(feature = "markdown")]
    pub fn markdown(body: impl AsRef<str> + Into<String>) -> Self {
        Self { message: MessageContent::markdown(body), relates_to: None }
    }

    /// Create a new `MessageEventContent` from the given `TextMessageEventContent` and optional
    /// relation.
    pub fn from_text_room_message(
        content: TextMessageEventContent,
        relates_to: Option<Relation>,
    ) -> Self {
        let TextMessageEventContent { body, formatted, message, .. } = content;
        if let Some(message) = message {
            Self { message, relates_to }
        } else {
            Self { message: MessageContent::from_room_message_content(body, formatted), relates_to }
        }
    }
}

/// Text message content.
///
/// A `MessageContent` must contain at least one message to be used as a fallback text
/// representation.
#[derive(Clone, Debug, Deserialize)]
#[serde(try_from = "MessageContentSerDeHelper")]
pub struct MessageContent(pub(crate) Vec<Text>);

impl MessageContent {
    /// Create a `MessageContent` from an array of messages.
    ///
    /// Returns `None` if the array is empty.
    pub fn new(messages: Vec<Text>) -> Option<Self> {
        if messages.is_empty() {
            None
        } else {
            Some(Self(messages))
        }
    }

    /// A convenience constructor to create a plain text message.
    pub fn plain(body: impl Into<String>) -> Self {
        Self(vec![Text::plain(body)])
    }

    /// A convenience constructor to create an HTML message.
    pub fn html(body: impl Into<String>, html_body: impl Into<String>) -> Self {
        Self(vec![Text::html(html_body), Text::plain(body)])
    }

    /// A convenience constructor to create a Markdown message.
    ///
    /// Returns an HTML message if some Markdown formatting was detected, otherwise returns a plain
    /// text message.
    #[cfg(feature = "markdown")]
    pub fn markdown(body: impl AsRef<str> + Into<String>) -> Self {
        let mut message = Vec::with_capacity(2);
        if let Some(html_body) = Text::markdown(&body) {
            message.push(html_body);
        }
        message.push(Text::plain(body));
        Self(message)
    }

    /// Create a new `MessageContent` from the given body and optional formatted body.
    pub fn from_room_message_content(body: String, formatted: Option<FormattedBody>) -> Self {
        if let Some(FormattedBody { body: html_body, .. }) =
            formatted.filter(|formatted| formatted.format == MessageFormat::Html)
        {
            Self::html(body, html_body)
        } else {
            Self::plain(body)
        }
    }

    /// Get the plain text representation of this message.
    pub fn find_plain(&self) -> Option<&str> {
        self.iter()
            .find(|content| content.mimetype == "text/plain")
            .map(|content| content.body.as_ref())
    }

    /// Get the HTML representation of this message.
    pub fn find_html(&self) -> Option<&str> {
        self.iter()
            .find(|content| content.mimetype == "text/html")
            .map(|content| content.body.as_ref())
    }
}

/// The error type returned when trying to construct an empty `MessageContent`.
#[derive(Debug, Error)]
#[non_exhaustive]
#[error("MessageContent cannot be empty")]
pub struct EmptyMessageContentError;

impl TryFrom<Vec<Text>> for MessageContent {
    type Error = EmptyMessageContentError;

    fn try_from(messages: Vec<Text>) -> Result<Self, Self::Error> {
        Self::new(messages).ok_or(EmptyMessageContentError)
    }
}

impl Deref for MessageContent {
    type Target = [Text];

    fn deref(&self) -> &Self::Target {
        &self.0
    }
}

/// Text message content.
#[derive(Clone, Debug, Serialize, Deserialize)]
#[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)]
pub struct Text {
    /// The mime type of the `body`.
    #[serde(default = "Text::default_mimetype")]
    pub mimetype: String,

    /// The text content.
    pub body: String,

    /// The language of the text.
    ///
    /// This must be a valid language code according to [BCP 47](https://www.rfc-editor.org/rfc/bcp/bcp47.txt).
    #[cfg(feature = "unstable-msc3554")]
    #[serde(skip_serializing_if = "Option::is_none")]
    pub lang: Option<String>,
}

impl Text {
    /// Creates a new plain text message body.
    pub fn plain(body: impl Into<String>) -> Self {
        Self {
            mimetype: "text/plain".to_owned(),
            body: body.into(),
            #[cfg(feature = "unstable-msc3554")]
            lang: None,
        }
    }

    /// Creates a new HTML-formatted message body.
    pub fn html(body: impl Into<String>) -> Self {
        Self {
            mimetype: "text/html".to_owned(),
            body: body.into(),
            #[cfg(feature = "unstable-msc3554")]
            lang: None,
        }
    }

    /// Creates a new HTML-formatted message body by parsing the Markdown in `body`.
    ///
    /// Returns `None` if no Markdown formatting was found.
    #[cfg(feature = "markdown")]
    pub fn markdown(body: impl AsRef<str>) -> Option<Self> {
        let body = body.as_ref();
        let mut html_body = String::new();

        pulldown_cmark::html::push_html(&mut html_body, pulldown_cmark::Parser::new(body));

        (html_body != format!("<p>{}</p>\n", body)).then(|| Self::html(html_body))
    }

    fn default_mimetype() -> String {
        "text/plain".to_owned()
    }
}

/// The error type returned when a conversion to an extensible event type fails.
#[derive(Debug, Error)]
#[non_exhaustive]
pub enum TryFromExtensibleError {
    /// A field is missing.
    #[error("missing field `{0}`")]
    MissingField(String),
}
<commit_msg>events: Document the unstable-extensible-events feature<commit_after>//! Types for extensible text message events ([MSC1767]).
//!
//! # Extensible events
//!
//! MSCs [1767] (Text, Emote and Notice), [3551] (Files), [3552] (Images and Stickers), [3553]
//! (Videos), [3246] (Audio), and [3488] (Location) introduce new primary types called extensible
//! events. These types are meant to replace the `m.room.message` primary type and its `msgtype`s.
//! Other MSCs introduce new types with an `m.room.message` fallback, like [MSC3245] (Voice
//! Messages), and types that only have an extensible events format, like [MSC3381] (Polls).
//!
//! # Transition Period
//!
//! MSC1767 defines a transition period that will start after the extensible events are released in
//! a Matrix version. It should last approximately one year, but the end of that period will be
//! formalized in a new Matrix version.
//!
//! The new primary types should not be sent over the Matrix network before the end of the
//! transition period. Instead, transitional `m.room.message` events should be sent. These
//! transitional events include the content of the now legacy `m.room.message` event and the content
//! of the new extensible event types in a single event.
//!
//! # How to use them
//!
//! First, you can enable the `unstable-extensible-events` feature from the `ruma` crate, that
//! will enable all the MSCs for the extensible events that correspond to the legacy `msgtype`s
//! (1767, 3246, 3488, 3551, 3552, 3553). It is also possible to enable only the MSCs you want with
//! the `unstable-mscXXXX` features (where `XXXX` is the number of the MSC).
//!
//! The recommended way to send transitional extensible events while they are unstable and during
//! the transition period is to build one of the new primary types and then to convert it to a
//! [`RoomMessageEventContent`] by using `.into()` or `RoomMessageEventContent::from()`. The
//! provided constructors will copy the relevant data in the legacy fields.
//!
//! For incoming events, a `RoomMessageEventContent` can be converted to an extensible event with
//! the relevant `from_*_room_message` method on the primary type. This conversion will work even
//! with legacy `m.room.message` events that don't have extensible events content.
//!
//! It is also possible to enable extensible events support and continue using
//! `RoomMessageEventContent`'s constructors. The data will be duplicated in both the legacy and
//! extensible events fields.
//!
//! [MSC1767]: https://github.com/matrix-org/matrix-spec-proposals/pull/1767
//! [1767]: https://github.com/matrix-org/matrix-spec-proposals/pull/1767
//! [3551]: https://github.com/matrix-org/matrix-spec-proposals/pull/3551
//! [3552]: https://github.com/matrix-org/matrix-spec-proposals/pull/3552
//! [3553]: https://github.com/matrix-org/matrix-spec-proposals/pull/3553
//! [3246]: https://github.com/matrix-org/matrix-spec-proposals/pull/3246
//! [3488]: https://github.com/matrix-org/matrix-spec-proposals/pull/3488
//! [MSC3245]: https://github.com/matrix-org/matrix-spec-proposals/pull/3245
//! [MSC3381]: https://github.com/matrix-org/matrix-spec-proposals/pull/3381
//! [`RoomMessageEventContent`]: super::room::message::RoomMessageEventContent
use std::{convert::TryFrom, ops::Deref};

use ruma_macros::EventContent;
use serde::{Deserialize, Serialize};
use thiserror::Error;

pub(crate) mod content_serde;

use content_serde::MessageContentSerDeHelper;

use super::room::message::{FormattedBody, MessageFormat, Relation, TextMessageEventContent};

/// The payload for an extensible text message.
///
/// This is the new primary type introduced in [MSC1767] and should not be sent before the end of
/// the transition period. See the documentation of the [`message`] module for more information.
///
/// `MessageEventContent` can be converted to a [`RoomMessageEventContent`] with a
/// [`MessageType::Text`]. You can convert it back with
/// [`MessageEventContent::from_text_room_message()`].
///
/// [MSC1767]: https://github.com/matrix-org/matrix-spec-proposals/pull/1767
/// [`message`]: super::message
/// [`RoomMessageEventContent`]: super::room::message::RoomMessageEventContent
/// [`MessageType::Text`]: super::room::message::MessageType::Text
#[derive(Clone, Debug, Serialize, Deserialize, EventContent)]
#[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)]
#[ruma_event(type = "m.message", kind = MessageLike)]
pub struct MessageEventContent {
    /// The message's text content.
    #[serde(flatten)]
    pub message: MessageContent,

    /// Information about related messages for [rich replies].
    ///
    /// [rich replies]: https://spec.matrix.org/v1.2/client-server-api/#rich-replies
    #[serde(flatten, skip_serializing_if = "Option::is_none")]
    pub relates_to: Option<Relation>,
}

impl MessageEventContent {
    /// A convenience constructor to create a plain text message.
    pub fn plain(body: impl Into<String>) -> Self {
        Self { message: MessageContent::plain(body), relates_to: None }
    }

    /// A convenience constructor to create an HTML message.
    pub fn html(body: impl Into<String>, html_body: impl Into<String>) -> Self {
        Self { message: MessageContent::html(body, html_body), relates_to: None }
    }

    /// A convenience constructor to create a Markdown message.
    ///
    /// Returns an HTML message if some Markdown formatting was detected, otherwise returns a plain
    /// text message.
    #[cfg(feature = "markdown")]
    pub fn markdown(body: impl AsRef<str> + Into<String>) -> Self {
        Self { message: MessageContent::markdown(body), relates_to: None }
    }

    /// Create a new `MessageEventContent` from the given `TextMessageEventContent` and optional
    /// relation.
    pub fn from_text_room_message(
        content: TextMessageEventContent,
        relates_to: Option<Relation>,
    ) -> Self {
        let TextMessageEventContent { body, formatted, message, .. } = content;
        if let Some(message) = message {
            Self { message, relates_to }
        } else {
            Self { message: MessageContent::from_room_message_content(body, formatted), relates_to }
        }
    }
}

/// Text message content.
///
/// A `MessageContent` must contain at least one message to be used as a fallback text
/// representation.
#[derive(Clone, Debug, Deserialize)]
#[serde(try_from = "MessageContentSerDeHelper")]
pub struct MessageContent(pub(crate) Vec<Text>);

impl MessageContent {
    /// Create a `MessageContent` from an array of messages.
    ///
    /// Returns `None` if the array is empty.
    pub fn new(messages: Vec<Text>) -> Option<Self> {
        if messages.is_empty() {
            None
        } else {
            Some(Self(messages))
        }
    }

    /// A convenience constructor to create a plain text message.
    pub fn plain(body: impl Into<String>) -> Self {
        Self(vec![Text::plain(body)])
    }

    /// A convenience constructor to create an HTML message.
    pub fn html(body: impl Into<String>, html_body: impl Into<String>) -> Self {
        Self(vec![Text::html(html_body), Text::plain(body)])
    }

    /// A convenience constructor to create a Markdown message.
    ///
    /// Returns an HTML message if some Markdown formatting was detected, otherwise returns a plain
    /// text message.
    #[cfg(feature = "markdown")]
    pub fn markdown(body: impl AsRef<str> + Into<String>) -> Self {
        let mut message = Vec::with_capacity(2);
        if let Some(html_body) = Text::markdown(&body) {
            message.push(html_body);
        }
        message.push(Text::plain(body));
        Self(message)
    }

    /// Create a new `MessageContent` from the given body and optional formatted body.
    pub fn from_room_message_content(body: String, formatted: Option<FormattedBody>) -> Self {
        if let Some(FormattedBody { body: html_body, .. }) =
            formatted.filter(|formatted| formatted.format == MessageFormat::Html)
        {
            Self::html(body, html_body)
        } else {
            Self::plain(body)
        }
    }

    /// Get the plain text representation of this message.
    pub fn find_plain(&self) -> Option<&str> {
        self.iter()
            .find(|content| content.mimetype == "text/plain")
            .map(|content| content.body.as_ref())
    }

    /// Get the HTML representation of this message.
    pub fn find_html(&self) -> Option<&str> {
        self.iter()
            .find(|content| content.mimetype == "text/html")
            .map(|content| content.body.as_ref())
    }
}

/// The error type returned when trying to construct an empty `MessageContent`.
#[derive(Debug, Error)]
#[non_exhaustive]
#[error("MessageContent cannot be empty")]
pub struct EmptyMessageContentError;

impl TryFrom<Vec<Text>> for MessageContent {
    type Error = EmptyMessageContentError;

    fn try_from(messages: Vec<Text>) -> Result<Self, Self::Error> {
        Self::new(messages).ok_or(EmptyMessageContentError)
    }
}

impl Deref for MessageContent {
    type Target = [Text];

    fn deref(&self) -> &Self::Target {
        &self.0
    }
}

/// Text message content.
#[derive(Clone, Debug, Serialize, Deserialize)]
#[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)]
pub struct Text {
    /// The mime type of the `body`.
    #[serde(default = "Text::default_mimetype")]
    pub mimetype: String,

    /// The text content.
    pub body: String,

    /// The language of the text.
    ///
    /// This must be a valid language code according to [BCP 47](https://www.rfc-editor.org/rfc/bcp/bcp47.txt).
    #[cfg(feature = "unstable-msc3554")]
    #[serde(skip_serializing_if = "Option::is_none")]
    pub lang: Option<String>,
}

impl Text {
    /// Creates a new plain text message body.
    pub fn plain(body: impl Into<String>) -> Self {
        Self {
            mimetype: "text/plain".to_owned(),
            body: body.into(),
            #[cfg(feature = "unstable-msc3554")]
            lang: None,
        }
    }

    /// Creates a new HTML-formatted message body.
    pub fn html(body: impl Into<String>) -> Self {
        Self {
            mimetype: "text/html".to_owned(),
            body: body.into(),
            #[cfg(feature = "unstable-msc3554")]
            lang: None,
        }
    }

    /// Creates a new HTML-formatted message body by parsing the Markdown in `body`.
    ///
    /// Returns `None` if no Markdown formatting was found.
    #[cfg(feature = "markdown")]
    pub fn markdown(body: impl AsRef<str>) -> Option<Self> {
        let body = body.as_ref();
        let mut html_body = String::new();

        pulldown_cmark::html::push_html(&mut html_body, pulldown_cmark::Parser::new(body));

        (html_body != format!("<p>{}</p>\n", body)).then(|| Self::html(html_body))
    }

    fn default_mimetype() -> String {
        "text/plain".to_owned()
    }
}

/// The error type returned when a conversion to an extensible event type fails.
#[derive(Debug, Error)]
#[non_exhaustive]
pub enum TryFromExtensibleError {
    /// A field is missing.
    #[error("missing field `{0}`")]
    MissingField(String),
}
<|endoftext|>


<commit_before>//
//   Copyright 2016 Andrew Hunter
//
//   Licensed under the Apache License, Version 2.0 (the "License");
//   you may not use this file except in compliance with the License.
//   You may obtain a copy of the License at
//
//       http://www.apache.org/licenses/LICENSE-2.0
//
//   Unless required by applicable law or agreed to in writing, software
//   distributed under the License is distributed on an "AS IS" BASIS,
//   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//   See the License for the specific language governing permissions and
//   limitations under the License.
//

use std::rc::*;

use super::component::*;
use super::super::tree::*;

struct FunctionComponent;

impl Component for FunctionComponent {
}

impl Drop for FunctionComponent {
    fn drop(&mut self) {
    }
}

impl<F: Fn(&TreeChange) -> TreeChange + 'static> ComponentFactory for F {
    ///
    /// Creates a component that consumes from a particular tree and publishes to a different tree
    ///
    fn create(self, consumer: ConsumerRef, publisher: PublisherRef) -> ComponentRef {
        let mut our_consumer    = consumer;
        let mut our_publisher   = publisher;
        let action              = Box::new(self);

        our_consumer.subscribe(TreeAddress::Here, TreeExtent::SubTree, Box::new(move |change| {
            let change_result = action(change);
            our_publisher.publish(change_result);
        }));

        return Rc::new(FunctionComponent);
    }
}<commit_msg>Doesn't work: would like to add a variant of ComponentFactory for functions that work only on trees, but rust's typechecker is not smart enough to distinguish different function types<commit_after>//
//   Copyright 2016 Andrew Hunter
//
//   Licensed under the Apache License, Version 2.0 (the "License");
//   you may not use this file except in compliance with the License.
//   You may obtain a copy of the License at
//
//       http://www.apache.org/licenses/LICENSE-2.0
//
//   Unless required by applicable law or agreed to in writing, software
//   distributed under the License is distributed on an "AS IS" BASIS,
//   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//   See the License for the specific language governing permissions and
//   limitations under the License.
//

use std::rc::*;

use super::component::*;
use super::super::tree::*;

struct FunctionComponent;

impl Component for FunctionComponent {
}

impl Drop for FunctionComponent {
    fn drop(&mut self) {
    }
}

///
/// Simplest form of 'component function': a function that receives a `TreeChange` indicating how the
/// input tree has changed, and returns a new change indicating how the output has changed.
///
impl<F: Fn(&TreeChange) -> TreeChange> ComponentFactory for F {
    ///
    /// Creates a component that consumes from a particular tree and publishes to a different tree
    ///
    fn create(self, consumer: ConsumerRef, publisher: PublisherRef) -> ComponentRef {
        let mut our_consumer    = consumer;
        let mut our_publisher   = publisher;
        let action              = Box::new(self);

        our_consumer.subscribe(TreeAddress::Here, TreeExtent::SubTree, Box::new(move |change| {
            let change_result = action(change);
            our_publisher.publish(change_result);
        }));

        return Rc::new(FunctionComponent);
    }
}

///
/// Function that receives a tree and returns a modified tree
///
impl<F: Fn(&TreeRef) -> TreeRef> ComponentFactory for F {
    ///
    /// Creates a component that consumes from a particular tree and publishes to a different tree
    ///
    fn create(self, consumer: ConsumerRef, publisher: PublisherRef) -> ComponentRef {
        let mut our_consumer    = consumer;
        let mut our_publisher   = publisher;
        let action              = Box::new(self);

        let mut tree = "empty".to_tree_node();

        our_consumer.subscribe(TreeAddress::Here, TreeExtent::SubTree, Box::new(move |change| {
            tree = change.apply(tree);

            let new_tree = action(&tree);

            our_publisher.publish(TreeChange::New(&TreeAddress::Here, TreeChangeType::Child, Some(&new_tree)));
        }));

        return Rc::new(FunctionComponent);
    }
}
<|endoftext|>