<commit_before>use iron::prelude::*;
use maud::{Markup, PreEscaped, Render};
use pulldown_cmark;

use models::User;

fn layout(r: &Request, title: Option<&str>, body: Markup) -> Markup {
    layout_inner(r, title, title, body)
}

fn layout_inner(r: &Request, head_title: Option<&str>, body_title: Option<&str>, body: Markup) -> Markup {
    html! {
        (PreEscaped("<!DOCTYPE html>"))
        html {
            meta charset="utf-8" /
            title {
                @if let Some(head_title) = head_title {
                    (head_title) " - "
                }
                "Karkinos"
            }
            meta name="viewport" content="width=device-width" /
            link rel="stylesheet" href=(url_for!(r, "static", "path" => "styles.css")) /
            body {
                h1 a href="/" {
                    span.thecrab "🦀"
                    "Karkinos"
                }
                @if let Some(body_title) = body_title {
                    h2 a href=(r.url) title="Link to this page" (body_title)
                }
                (body)
            }
        }
    }
}

pub fn home(r: &Request) -> Markup {
    layout(r, None, html! {
        (search_form(r, None))
        p {
            span.karkinos "KARKINOS"
            " is a database of people interested in the "
            a href="https://www.rust-lang.org" "Rust programming language"
            ". It uses the same data as "
            a href="http://rustaceans.org" "rustaceans.org"
            ", but presents it through a different interface."
        }
        p "I created Karkinos for these reasons:"
        ul {
            li "To provide access for users who browse with JavaScript disabled;"
            li "To rewrite the backend in Rust (instead of Node.js);"
            li {
                "As a proving ground for my template engine, "
                a href="https://github.com/lfairy/maud" "Maud"
                ";"
            }
            li "To screw around with CSS (this is the most important reason)."
        }
        p {
            "Karkinos is named after a very special "
            a href="https://en.wikipedia.org/wiki/Cancer_(constellation)#Names" "giant crab"
            "."
        }
        p {
            "The source code for this site can be found on "
            a href="https://github.com/lfairy/karkinos" "GitHub"
            "."
        }
    })
}

fn search_form(r: &Request, value: Option<&str>) -> Markup {
    html! {
        form action=(url_for!(r, "search")) {
            input name="q" id="q" type="search" placeholder="Search" value=(value.unwrap_or("")) /
        }
        @if value.is_none() {
            script (PreEscaped("document.getElementById('q').select()"))
        }
    }
}

pub fn not_found(r: &Request) -> Markup {
    layout(r, Some("Not found"), html! {
        p {
            "The page at "
            strong (r.url)
            " could not be found."
        }
        p a href="/" "‹ Back to home page"
    })
}

pub fn search(r: &Request) -> Markup {
    layout(r, Some("Search"), html! {
        (search_form(r, None))
    })
}

pub fn search_results<'u, I>(r: &Request, query: &str, results: I) -> Markup where
    I: Iterator<Item=(Result<&'u User, &'u str>, String, u64)>,
{
    let title = format!("Search results for “{}”", query);
    let results = results.map(|(user, id, weight)| match user {
        Ok(user) => (user_box(r, &id, &user), id, weight),
        Err(..) => ((id.clone(), html! {}), id, weight),
    });
    let mut results = results.peekable();
    layout_inner(r, Some(&title), None, html! {
        (search_form(r, Some(query)))
        @if results.peek().is_none() {
            p "No results found."
        }
        @for ((user_title, user_markup), id, weight) in results {
            h3 title={ "Weight: " (weight) } {
                a href=(url_for!(r, "user", "id" => &id[..])) (user_title)
            }
            (user_markup)
            hr /
        }
    })
}

pub fn user(r: &Request, id: &str, user: &User) -> Markup {
    let (title, body) = user_box(r, id, user);
    layout(r, Some(&title), body)
}

fn user_box(_r: &Request, id: &str, user: &User) -> (String, Markup) {
    let title = if let Some(ref name) = user.name {
        format!("{} ({})", name, id)
    } else {
        id.to_string()
    };
    (title, html! {
        table {
            @if let Some(ref nick) = user.irc {
                tr {
                    th "IRC"
                    td {
                        (nick)
                        @if !user.irc_channels.is_empty() {
                            " on "
                            @for (i, channel) in user.irc_channels.iter().enumerate() {
                                @if i > 0 { ", " }
                                a href={ "irc://irc.mozilla.org/" (channel) } {
                                    "#" (channel)
                                }
                            }
                        }
                    }
                }
            }
            @if let Some(ref x) = user.discourse {
                tr {
                    th "Discourse"
                    td a href={ "https://users.rust-lang.org/users/" (x) } (x)
                }
            }
            @if let Some(ref x) = user.reddit {
                tr {
                    th "Reddit"
                    td a href={ "https://reddit.com/user/" (x) } (x)
                }
            }
            @if let Some(ref x) = user.twitter {
                tr {
                    th "Twitter"
                    td a href={ "https://twitter.com/" (x) } (x)
                }
            }
            @if let Some(ref x) = user.website {
                tr {
                    th "Website"
                    td a href=(x) (x)
                }
            }
            @if let Some(ref x) = user.blog {
                tr {
                    th "Blog"
                    td a href=(x) (x)
                }
            }
            @if let Some(ref x) = user.email {
                tr {
                    th "Email"
                    td a href={ "mailto:" (x) } (x)
                }
            }
        }
        @if let Some(ref x) = user.notes {
            div.notes (Markdown(x))
        }
    })
}

pub fn user_error(r: &Request, id: &str, error: &str) -> Markup {
    layout(r, Some(id), html! {
        p {
            "The user "
            strong (id)
            " exists, but their entry could not be parsed."
        }
        p {
            "(Error: " (error) ")"
        }
    })
}

pub fn user_not_found(r: &Request, id: &str) -> Markup {
    layout(r, Some(id), html! {
        p {
            "The user "
            strong (id)
            " could not be found."
        }
        p a href="/" "‹ Back to home page"
    })
}

struct Markdown<'a>(&'a str);

impl<'a> Render for Markdown<'a> {
    fn render_to(&self, buffer: &mut String) {
        let parser = pulldown_cmark::Parser::new(self.0);
        pulldown_cmark::html::push_html(buffer, parser);
    }
}
<commit_msg>Tweak markup for search box<commit_after>use iron::prelude::*;
use maud::{Markup, PreEscaped, Render};
use pulldown_cmark;

use models::User;

fn layout(r: &Request, title: Option<&str>, body: Markup) -> Markup {
    layout_inner(r, title, title, body)
}

fn layout_inner(r: &Request, head_title: Option<&str>, body_title: Option<&str>, body: Markup) -> Markup {
    html! {
        (PreEscaped("<!DOCTYPE html>"))
        html {
            meta charset="utf-8" /
            title {
                @if let Some(head_title) = head_title {
                    (head_title) " - "
                }
                "Karkinos"
            }
            meta name="viewport" content="width=device-width" /
            link rel="stylesheet" href=(url_for!(r, "static", "path" => "styles.css")) /
            body {
                h1 a href="/" {
                    span.thecrab "🦀"
                    "Karkinos"
                }
                @if let Some(body_title) = body_title {
                    h2 a href=(r.url) title="Link to this page" (body_title)
                }
                (body)
            }
        }
    }
}

pub fn home(r: &Request) -> Markup {
    layout(r, None, html! {
        (search_form(r, ""))
        p {
            span.karkinos "KARKINOS"
            " is a database of people interested in the "
            a href="https://www.rust-lang.org" "Rust programming language"
            ". It uses the same data as "
            a href="http://rustaceans.org" "rustaceans.org"
            ", but presents it through a different interface."
        }
        p "I created Karkinos for these reasons:"
        ul {
            li "To provide access for users who browse with JavaScript disabled;"
            li "To rewrite the backend in Rust (instead of Node.js);"
            li {
                "As a proving ground for my template engine, "
                a href="https://github.com/lfairy/maud" "Maud"
                ";"
            }
            li "To screw around with CSS (this is the most important reason)."
        }
        p {
            "Karkinos is named after a very special "
            a href="https://en.wikipedia.org/wiki/Cancer_(constellation)#Names" "giant crab"
            "."
        }
        p {
            "The source code for this site can be found on "
            a href="https://github.com/lfairy/karkinos" "GitHub"
            "."
        }
    })
}

fn search_form(r: &Request, value: &str) -> Markup {
    html! {
        form action=(url_for!(r, "search")) {
            input name="q" id="q" type="search" placeholder="Search"
                autocomplete="off" value=(value) /
        }
        script (PreEscaped(r#"
            var searchBox = document.getElementById('q')
            if (!searchBox.value) searchBox.select()
        "#))
    }
}

pub fn not_found(r: &Request) -> Markup {
    layout(r, Some("Not found"), html! {
        p {
            "The page at "
            strong (r.url)
            " could not be found."
        }
        p a href="/" "‹ Back to home page"
    })
}

pub fn search(r: &Request) -> Markup {
    layout(r, Some("Search"), html! {
        (search_form(r, ""))
    })
}

pub fn search_results<'u, I>(r: &Request, query: &str, results: I) -> Markup where
    I: Iterator<Item=(Result<&'u User, &'u str>, String, u64)>,
{
    let title = format!("Search results for “{}”", query);
    let results = results.map(|(user, id, weight)| match user {
        Ok(user) => (user_box(r, &id, &user), id, weight),
        Err(..) => ((id.clone(), html! {}), id, weight),
    });
    let mut results = results.peekable();
    layout_inner(r, Some(&title), None, html! {
        (search_form(r, query))
        @if results.peek().is_none() {
            p "No results found."
        }
        @for ((user_title, user_markup), id, weight) in results {
            h3 title={ "Weight: " (weight) } {
                a href=(url_for!(r, "user", "id" => &id[..])) (user_title)
            }
            (user_markup)
            hr /
        }
    })
}

pub fn user(r: &Request, id: &str, user: &User) -> Markup {
    let (title, body) = user_box(r, id, user);
    layout(r, Some(&title), body)
}

fn user_box(_r: &Request, id: &str, user: &User) -> (String, Markup) {
    let title = if let Some(ref name) = user.name {
        format!("{} ({})", name, id)
    } else {
        id.to_string()
    };
    (title, html! {
        table {
            @if let Some(ref nick) = user.irc {
                tr {
                    th "IRC"
                    td {
                        (nick)
                        @if !user.irc_channels.is_empty() {
                            " on "
                            @for (i, channel) in user.irc_channels.iter().enumerate() {
                                @if i > 0 { ", " }
                                a href={ "irc://irc.mozilla.org/" (channel) } {
                                    "#" (channel)
                                }
                            }
                        }
                    }
                }
            }
            @if let Some(ref x) = user.discourse {
                tr {
                    th "Discourse"
                    td a href={ "https://users.rust-lang.org/users/" (x) } (x)
                }
            }
            @if let Some(ref x) = user.reddit {
                tr {
                    th "Reddit"
                    td a href={ "https://reddit.com/user/" (x) } (x)
                }
            }
            @if let Some(ref x) = user.twitter {
                tr {
                    th "Twitter"
                    td a href={ "https://twitter.com/" (x) } (x)
                }
            }
            @if let Some(ref x) = user.website {
                tr {
                    th "Website"
                    td a href=(x) (x)
                }
            }
            @if let Some(ref x) = user.blog {
                tr {
                    th "Blog"
                    td a href=(x) (x)
                }
            }
            @if let Some(ref x) = user.email {
                tr {
                    th "Email"
                    td a href={ "mailto:" (x) } (x)
                }
            }
        }
        @if let Some(ref x) = user.notes {
            div.notes (Markdown(x))
        }
    })
}

pub fn user_error(r: &Request, id: &str, error: &str) -> Markup {
    layout(r, Some(id), html! {
        p {
            "The user "
            strong (id)
            " exists, but their entry could not be parsed."
        }
        p {
            "(Error: " (error) ")"
        }
    })
}

pub fn user_not_found(r: &Request, id: &str) -> Markup {
    layout(r, Some(id), html! {
        p {
            "The user "
            strong (id)
            " could not be found."
        }
        p a href="/" "‹ Back to home page"
    })
}

struct Markdown<'a>(&'a str);

impl<'a> Render for Markdown<'a> {
    fn render_to(&self, buffer: &mut String) {
        let parser = pulldown_cmark::Parser::new(self.0);
        pulldown_cmark::html::push_html(buffer, parser);
    }
}
<|endoftext|>


<commit_before>use regex::{Captures, Regex};
use term::{self, color, Terminal};

/// Finds all matches for the given pattern on the given subject and prints out
/// the subject with matches highlighted.
pub fn print_matches(pattern: &str, subject: &str, matches_only: bool) {
    // Attempt to compile the given regex pattern.
    let regex = match Regex::new(&pattern) {
        Ok(result) => { result },
        Err(err) => {
            println!("Invalid regular expression pattern '{}': {}",
                     pattern, err);
            return;
        }
    };

    // Loop over each match in the subject and pretty-print the match as well as
    // any trailing, non-matching text preceding the match.
    let mut last_index = 0;
    let mut i = 0;
    for captures in regex.captures_iter(subject) {
        let positions = captures.pos(0).unwrap();

        if !matches_only {
            print!("{}", &subject[last_index .. positions.0]);
        } else {
            print!("#{}: ", i);
        }
        print_captures(captures);
        if matches_only {
            println!("");
            i += 1;
        }

        last_index = positions.1;
    }

    // Print trailing unmatched text if there is any.
    if !matches_only && last_index < subject.len() {
        print!("{}", &subject[last_index ..]);
    }
    println!("");
}

/// Prints out a capture group using color formatting.
fn print_captures(captures: Captures) {
    let mut terminal = term::stdout().unwrap();
    let color_cycle = [color::BLUE, color::GREEN, color::MAGENTA, color::YELLOW];
    let mut color_index = 1;

    // Get the string of the entire match and the relative offset in the subject.
    let string = captures.at(0).unwrap();
    let offsets = captures.pos(0).unwrap();

    // To highlight sub-matches, divide the match string into a series of
    // resizeable regions that store their range and their color. As we loop
    // over each capture, find the parent region the current capture group fits
    // into, and split the region in two, with a new region for the current
    // capture between it. Worst-case time is O(3n^2), where n is the number of
    // subgroups in the regular expression.
    let mut regions: Vec<(usize, usize, u16)> = Vec::new();
    regions.push((offsets.0, offsets.1, color::BLUE));

    for i in 1..captures.len() {
        let pos = captures.pos(i).unwrap();

        for j in 0..regions.len() {
            if pos.0 >= regions[j].0 && pos.1 <= regions[j].1 {
                // Define two new regions that overlap the old one.
                let middle = (pos.0, pos.1, color_cycle[color_index]);
                let right = (pos.1, regions[j].1, regions[j].2);
                // Shrink the old region to be the leftmost one.
                regions[j].1 = pos.0;

                // Insert the new regions.
                regions.insert(j + 1, middle);
                regions.insert(j + 2, right);

                // Choose next color next time.
                color_index = (color_index + 1) % 4;
                break;
            }
        }
    }

    // Now print out the prepared regions; this part is pretty easy, since the
    // region parser already did all the work.
    for i in 0..regions.len() {
        terminal.bg(regions[i].2).unwrap();
        print!("{}", &string[regions[i].0 - offsets.0 .. regions[i].1 - offsets.0]);
    }

    // Reset coloring to normal.
    terminal.reset().unwrap();
}
<commit_msg>Fix panic for unmatched submatches<commit_after>use regex::{Captures, Regex};
use term::{self, color, Terminal};

/// Finds all matches for the given pattern on the given subject and prints out
/// the subject with matches highlighted.
pub fn print_matches(pattern: &str, subject: &str, matches_only: bool) {
    // Attempt to compile the given regex pattern.
    let regex = match Regex::new(&pattern) {
        Ok(result) => { result },
        Err(err) => {
            println!("Invalid regular expression pattern '{}': {}",
                     pattern, err);
            return;
        }
    };

    // Loop over each match in the subject and pretty-print the match as well as
    // any trailing, non-matching text preceding the match.
    let mut last_index = 0;
    let mut i = 0;
    for captures in regex.captures_iter(subject) {
        let positions = captures.pos(0).unwrap();

        if !matches_only {
            print!("{}", &subject[last_index .. positions.0]);
        } else {
            print!("#{}: ", i);
        }
        print_captures(captures);
        if matches_only {
            println!("");
            i += 1;
        }

        last_index = positions.1;
    }

    // Print trailing unmatched text if there is any.
    if !matches_only && last_index < subject.len() {
        print!("{}", &subject[last_index ..]);
    }
    println!("");
}

/// Prints out a capture group using color formatting.
fn print_captures(captures: Captures) {
    let mut terminal = term::stdout().unwrap();
    let color_cycle = [color::BLUE, color::GREEN, color::MAGENTA, color::YELLOW];
    let mut color_index = 1;

    // Get the string of the entire match and the relative offset in the subject.
    let string = captures.at(0).unwrap();
    let offsets = captures.pos(0).unwrap();

    // To highlight sub-matches, divide the match string into a series of
    // resizeable regions that store their range and their color. As we loop
    // over each capture, find the parent region the current capture group fits
    // into, and split the region in two, with a new region for the current
    // capture between it. Worst-case time is O(3n^2), where n is the number of
    // subgroups in the regular expression.
    let mut regions: Vec<(usize, usize, u16)> = Vec::new();
    regions.push((offsets.0, offsets.1, color::BLUE));

    for i in 1..captures.len() {
        let pos = match captures.pos(i) {
            None => continue,
            Some(pos) => pos
        };

        for j in 0..regions.len() {
            if pos.0 >= regions[j].0 && pos.1 <= regions[j].1 {
                // Define two new regions that overlap the old one.
                let middle = (pos.0, pos.1, color_cycle[color_index]);
                let right = (pos.1, regions[j].1, regions[j].2);
                // Shrink the old region to be the leftmost one.
                regions[j].1 = pos.0;

                // Insert the new regions.
                regions.insert(j + 1, middle);
                regions.insert(j + 2, right);

                // Choose next color next time.
                color_index = (color_index + 1) % 4;
                break;
            }
        }
    }

    // Now print out the prepared regions; this part is pretty easy, since the
    // region parser already did all the work.
    for i in 0..regions.len() {
        terminal.bg(regions[i].2).unwrap();
        print!("{}", &string[regions[i].0 - offsets.0 .. regions[i].1 - offsets.0]);
    }

    // Reset coloring to normal.
    terminal.reset().unwrap();
}
<|endoftext|>


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

#![allow(dead_code)]
// This is experimental for now...

pub struct SchemaLoader<'a> {
    schemas : ::std::collections::hash_map::HashMap<u64, ::capnp::private::RawSchema<'a>>,
}

impl <'a> SchemaLoader<'a> {
    pub fn new() -> SchemaLoader<'a> {
        SchemaLoader {
            schemas : ::std::collections::hash_map::HashMap::new(),
        }
    }

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

#![allow(dead_code)]
// This is experimental for now...

use ::capnp::Word;
use ::capnp::private::RawSchema;
use ::std::cell::RefCell;

pub struct Arena {
    allocations : RefCell<Vec<Vec<Word>>>,
}

impl Arena {
    pub fn new() -> Arena {
        Arena { allocations : RefCell::new(Vec::new()) }
    }

    pub fn alloc<'a>(&'a self, length : usize) -> &'a mut [Word] {
        let mut v = ::capnp::Word::allocate_zeroed_vec(length);
        let result = unsafe {::std::slice::from_raw_parts_mut(v.as_mut_ptr(), v.len())};
        self.allocations.borrow_mut().push(v);
        result
    }
}

pub struct SchemaLoader<'a> {
    arena : &'a Arena,
    schemas : ::std::collections::hash_map::HashMap<u64, RawSchema<'a>>,
}

impl <'a> SchemaLoader<'a> {
    pub fn new(arena : &'a Arena) -> SchemaLoader<'a> {
        SchemaLoader {
            arena : arena,
            schemas : ::std::collections::hash_map::HashMap::new(),
        }
    }

    pub fn load(&mut self, reader : ::schema_capnp::node::Reader) {
        let id = reader.get_id();
        let num_words = reader.total_size().word_count;
        self.schemas.get(&id);
        let _words = self.arena.alloc(num_words as usize);
        //ScratchSpaceMallocMessageBuilder::new
    }
}
<|endoftext|>


<commit_before>use std::cell::RefCell;
use std::collections::{HashMap, HashSet};
use std::io;
use std::rc::Rc;

use asnom::structure::StructureTag;
use asnom::structures::{Tag, Sequence, Integer, OctetString, Boolean};
use asnom::common::TagClass::*;

use filter::parse;

use futures::{Async, Future, Poll, Stream};
use futures::sync::{mpsc, oneshot};
use tokio_proto::multiplex::RequestId;
use tokio_service::Service;

use ldap::bundle;
use ldap::{Ldap, LdapOp};
use protocol::{LdapResult, ProtoBundle};

#[derive(Clone, Copy, Debug, PartialEq)]
pub enum Scope {
    Base     = 0,
    OneLevel = 1,
    Subtree  = 2,
}

#[derive(Clone, Copy, Debug, PartialEq)]
pub enum DerefAliases {
    Never             = 0,
    InSearch          = 1,
    FindingBaseObject = 2,
    Always            = 3,
}

pub enum SearchItem {
    Entry(StructureTag),
    Referral(StructureTag),
    Done(RequestId, LdapResult, Option<StructureTag>),
}

pub struct SearchStream {
    id: RequestId,
    bundle: Rc<RefCell<ProtoBundle>>,
    _tx_i: mpsc::UnboundedSender<SearchItem>,
    rx_i: mpsc::UnboundedReceiver<SearchItem>,
    tx_r: Option<oneshot::Sender<(LdapResult, Option<StructureTag>)>>,
    refs: Vec<HashSet<String>>,
}

impl Stream for SearchStream {
    type Item = StructureTag;
    type Error = io::Error;

    fn poll(&mut self) -> Poll<Option<Self::Item>, Self::Error> {
        loop {
            let item = try_ready!(self.rx_i.poll().map_err(|_e| io::Error::new(io::ErrorKind::Other, "poll search stream")));
            match item {
                Some(SearchItem::Done(_id, mut result, controls)) => {
                    result.refs.extend(self.refs.drain(..));
                    let mut bundle = self.bundle.borrow_mut();
                    let msgid = match bundle.search_helpers.get(&self.id) {
                        Some(ref helper) => helper.msgid,
                        None => return Ok(Async::Ready(None)),
                    };
                    bundle.search_helpers.remove(&self.id);
                    bundle.id_map.remove(&msgid);
                    let tx_r = self.tx_r.take().expect("oneshot tx");
                    tx_r.send((result, controls)).map_err(|_e| io::Error::new(io::ErrorKind::Other, "send result"))?;
                    return Ok(Async::Ready(None));
                },
                Some(SearchItem::Entry(tag)) => return Ok(Async::Ready(Some(tag))),
                Some(SearchItem::Referral(tag)) => {
                    self.refs.push(tag.expect_constructed().expect("referrals").into_iter()
                        .map(|t| t.expect_primitive().expect("octet string"))
                        .map(String::from_utf8)
                        .map(|s| s.expect("uri"))
                        .collect());
                    continue;
                },
                None => return Ok(Async::Ready(None)),
            }
        }
    }
}

#[derive(Debug)]
pub struct SearchEntry {
    dn: String,
    attrs: HashMap<String, Vec<String>>,
}

impl SearchEntry {
    pub fn construct(tag: StructureTag) -> SearchEntry {
        let mut tags = tag.match_id(4).and_then(|t| t.expect_constructed()).expect("entry").into_iter();
        let dn = String::from_utf8(tags.next().expect("element").expect_primitive().expect("octet string"))
            .expect("dn");
        let mut attr_vals = HashMap::new();
        let attrs = tags.next().expect("element").expect_constructed().expect("attrs").into_iter();
        for a_v in attrs {
            let mut part_attr = a_v.expect_constructed().expect("partial attribute").into_iter();
            let a_type = String::from_utf8(part_attr.next().expect("element").expect_primitive().expect("octet string"))
                .expect("attribute type");
            let values = part_attr.next().expect("element").expect_constructed().expect("values").into_iter()
                .map(|t| t.expect_primitive().expect("octet string"))
                .map(String::from_utf8)
                .map(|s| s.expect("value"))
                .collect();
            attr_vals.insert(a_type, values);
        }
        SearchEntry {
            dn: dn,
            attrs: attr_vals,
        }
    }
}

impl Ldap {
    pub fn search(&self,
                    base: String,
                    scope: Scope,
                    deref: DerefAliases,
                    typesonly: bool,
                    filter: String,
                    attrs: Vec<String>) ->
        Box<Future<Item=(SearchStream, oneshot::Receiver<(LdapResult, Option<StructureTag>)>), Error=io::Error>> {
        let req = Tag::Sequence(Sequence {
            id: 3,
            class: Application,
            inner: vec![
                   Tag::OctetString(OctetString {
                       inner: base.into_bytes(),
                       .. Default::default()
                   }),
                   Tag::Integer(Integer {
                       inner: scope as i64,
                       .. Default::default()
                   }),
                   Tag::Integer(Integer {
                       inner: deref as i64,
                       .. Default::default()
                   }),
                   Tag::Integer(Integer {
                       inner: 0,
                       .. Default::default()
                   }),
                   Tag::Integer(Integer {
                       inner: 0,
                       .. Default::default()
                   }),
                   Tag::Boolean(Boolean {
                       inner: typesonly,
                       .. Default::default()
                   }),
                   parse(&filter).unwrap(),
                   Tag::Sequence(Sequence {
                       inner: attrs.into_iter().map(|s|
                            Tag::OctetString(OctetString { inner: s.into_bytes(), ..Default::default() })).collect(),
                       .. Default::default()
                   })
            ],
        });

        let (tx_i, rx_i) = mpsc::unbounded::<SearchItem>();
        let (tx_r, rx_r) = oneshot::channel::<(LdapResult, Option<StructureTag>)>();
        let bundle = bundle(self);
        let fut = self.call(LdapOp::Multi(req, tx_i.clone())).and_then(move |res| {
            let id = match res {
                (Tag::Integer(Integer { id: _, class: _, inner }), _) => inner,
                _ => unimplemented!(),
            };
            Ok((SearchStream {
                id: id as RequestId,
                bundle: bundle,
                _tx_i: tx_i,
                rx_i: rx_i,
                tx_r: Some(tx_r),
                refs: Vec::new(),
            }, rx_r))
        });

        Box::new(fut)
    }
}
<commit_msg>Rename alias deref constants<commit_after>use std::cell::RefCell;
use std::collections::{HashMap, HashSet};
use std::io;
use std::rc::Rc;

use asnom::structure::StructureTag;
use asnom::structures::{Tag, Sequence, Integer, OctetString, Boolean};
use asnom::common::TagClass::*;

use filter::parse;

use futures::{Async, Future, Poll, Stream};
use futures::sync::{mpsc, oneshot};
use tokio_proto::multiplex::RequestId;
use tokio_service::Service;

use ldap::bundle;
use ldap::{Ldap, LdapOp};
use protocol::{LdapResult, ProtoBundle};

#[derive(Clone, Copy, Debug, PartialEq)]
pub enum Scope {
    Base     = 0,
    OneLevel = 1,
    Subtree  = 2,
}

#[derive(Clone, Copy, Debug, PartialEq)]
pub enum DerefAliases {
    Never     = 0,
    Searching = 1,
    Finding   = 2,
    Always    = 3,
}

pub enum SearchItem {
    Entry(StructureTag),
    Referral(StructureTag),
    Done(RequestId, LdapResult, Option<StructureTag>),
}

pub struct SearchStream {
    id: RequestId,
    bundle: Rc<RefCell<ProtoBundle>>,
    _tx_i: mpsc::UnboundedSender<SearchItem>,
    rx_i: mpsc::UnboundedReceiver<SearchItem>,
    tx_r: Option<oneshot::Sender<(LdapResult, Option<StructureTag>)>>,
    refs: Vec<HashSet<String>>,
}

impl Stream for SearchStream {
    type Item = StructureTag;
    type Error = io::Error;

    fn poll(&mut self) -> Poll<Option<Self::Item>, Self::Error> {
        loop {
            let item = try_ready!(self.rx_i.poll().map_err(|_e| io::Error::new(io::ErrorKind::Other, "poll search stream")));
            match item {
                Some(SearchItem::Done(_id, mut result, controls)) => {
                    result.refs.extend(self.refs.drain(..));
                    let mut bundle = self.bundle.borrow_mut();
                    let msgid = match bundle.search_helpers.get(&self.id) {
                        Some(ref helper) => helper.msgid,
                        None => return Ok(Async::Ready(None)),
                    };
                    bundle.search_helpers.remove(&self.id);
                    bundle.id_map.remove(&msgid);
                    let tx_r = self.tx_r.take().expect("oneshot tx");
                    tx_r.send((result, controls)).map_err(|_e| io::Error::new(io::ErrorKind::Other, "send result"))?;
                    return Ok(Async::Ready(None));
                },
                Some(SearchItem::Entry(tag)) => return Ok(Async::Ready(Some(tag))),
                Some(SearchItem::Referral(tag)) => {
                    self.refs.push(tag.expect_constructed().expect("referrals").into_iter()
                        .map(|t| t.expect_primitive().expect("octet string"))
                        .map(String::from_utf8)
                        .map(|s| s.expect("uri"))
                        .collect());
                    continue;
                },
                None => return Ok(Async::Ready(None)),
            }
        }
    }
}

#[derive(Debug)]
pub struct SearchEntry {
    dn: String,
    attrs: HashMap<String, Vec<String>>,
}

impl SearchEntry {
    pub fn construct(tag: StructureTag) -> SearchEntry {
        let mut tags = tag.match_id(4).and_then(|t| t.expect_constructed()).expect("entry").into_iter();
        let dn = String::from_utf8(tags.next().expect("element").expect_primitive().expect("octet string"))
            .expect("dn");
        let mut attr_vals = HashMap::new();
        let attrs = tags.next().expect("element").expect_constructed().expect("attrs").into_iter();
        for a_v in attrs {
            let mut part_attr = a_v.expect_constructed().expect("partial attribute").into_iter();
            let a_type = String::from_utf8(part_attr.next().expect("element").expect_primitive().expect("octet string"))
                .expect("attribute type");
            let values = part_attr.next().expect("element").expect_constructed().expect("values").into_iter()
                .map(|t| t.expect_primitive().expect("octet string"))
                .map(String::from_utf8)
                .map(|s| s.expect("value"))
                .collect();
            attr_vals.insert(a_type, values);
        }
        SearchEntry {
            dn: dn,
            attrs: attr_vals,
        }
    }
}

impl Ldap {
    pub fn search(&self,
                    base: String,
                    scope: Scope,
                    deref: DerefAliases,
                    typesonly: bool,
                    filter: String,
                    attrs: Vec<String>) ->
        Box<Future<Item=(SearchStream, oneshot::Receiver<(LdapResult, Option<StructureTag>)>), Error=io::Error>> {
        let req = Tag::Sequence(Sequence {
            id: 3,
            class: Application,
            inner: vec![
                   Tag::OctetString(OctetString {
                       inner: base.into_bytes(),
                       .. Default::default()
                   }),
                   Tag::Integer(Integer {
                       inner: scope as i64,
                       .. Default::default()
                   }),
                   Tag::Integer(Integer {
                       inner: deref as i64,
                       .. Default::default()
                   }),
                   Tag::Integer(Integer {
                       inner: 0,
                       .. Default::default()
                   }),
                   Tag::Integer(Integer {
                       inner: 0,
                       .. Default::default()
                   }),
                   Tag::Boolean(Boolean {
                       inner: typesonly,
                       .. Default::default()
                   }),
                   parse(&filter).unwrap(),
                   Tag::Sequence(Sequence {
                       inner: attrs.into_iter().map(|s|
                            Tag::OctetString(OctetString { inner: s.into_bytes(), ..Default::default() })).collect(),
                       .. Default::default()
                   })
            ],
        });

        let (tx_i, rx_i) = mpsc::unbounded::<SearchItem>();
        let (tx_r, rx_r) = oneshot::channel::<(LdapResult, Option<StructureTag>)>();
        let bundle = bundle(self);
        let fut = self.call(LdapOp::Multi(req, tx_i.clone())).and_then(move |res| {
            let id = match res {
                (Tag::Integer(Integer { id: _, class: _, inner }), _) => inner,
                _ => unimplemented!(),
            };
            Ok((SearchStream {
                id: id as RequestId,
                bundle: bundle,
                _tx_i: tx_i,
                rx_i: rx_i,
                tx_r: Some(tx_r),
                refs: Vec::new(),
            }, rx_r))
        });

        Box::new(fut)
    }
}
<|endoftext|>


<commit_before>
use std::io::{TcpListener};
use std::io::{Listener, Acceptor};
use std::io::{IoResult};
use std::io::net;
use std::io;
use std::collections::hashmap::{HashMap};

use channel::{ChannelEvent};
use client::{SharedClient, Client, ClientId};
use msg::{MessageHandler};
use cmd;

/// Forwards the message to a channel
pub struct ChannelProxy {
    name: String,
    tx: Sender<ChannelEvent>,
    server_tx: Sender<Event>
}

impl ChannelProxy {
    pub fn new(name: String,
           tx: Sender<ChannelEvent>,
           server_tx: Sender<Event>) -> ChannelProxy {
        ChannelProxy {
            name: name,
            tx: tx,
            server_tx: server_tx
        }
    }
    pub fn send(&self, event: ChannelEvent) {
        match self.tx.send_opt(event) {
            Ok(_) => {},
            Err(_) => {
                let _ = self.server_tx.send_opt(ChannelLost(self.name.clone()));
            }
        }
    }
}

pub struct Server {
    host: String,
    ip: String,
    port: u16,
    tx: Option<Sender<Event>>,
    // TODO put unregisterd clients in a staging Map
    clients: HashMap<ClientId, SharedClient>,
    pub registered: HashMap<String, SharedClient>,
    pub channels: HashMap<String, ChannelProxy>
}

/// Enumeration of the events the server can receive
pub enum Event {
    /// Message received from a client
    MessageReceived(ClientId, Box<MessageHandler + Send>),
    /// Connection to a client established
    ClientConnected(Client),
    /// The task of Channel(name) failed
    ChannelLost(String),
}

/// Convenience function to run the server
pub fn run_server(host: &str) -> IoResult<Server> {
    let server = try!(Server::new(host));
    server.serve_forever()
}

/// Irc server
impl Server {
    /// Creates a new IRC server instance.
    pub fn new(host: &str) -> IoResult<Server> {
        let addresses = try!(net::get_host_addresses(host));
        debug!("{}", addresses)
        // Listen only on ipv4 for now…
        let ip = match addresses.iter().filter(
            |&v| match v { &net::ip::Ipv4Addr(_, _, _, _) => true, _ => false }
        ).nth(0) {
            Some(ip) => ip,
            None => return Err(io::IoError {
                kind: io::OtherIoError,
                desc: "cannnot resolve ip",
                detail: None
            })
        };
        Ok(Server {
            host: host.to_string(),
            ip: format!("{}", ip),
            port: 6667,
            tx: None,
            clients: HashMap::new(),
            registered: HashMap::new(),
            channels: HashMap::new()
        })
    }

    /// Starts the main loop and listens on the specified host and port.
    pub fn serve_forever(mut self) -> IoResult<Server> {
        // todo change this to a more general event dispatching loop
        let message_rx = try!(self.start_listening());
        for event in message_rx.iter() {
            match event {
                MessageReceived(client_id, handler) => {
                    let client = match self.clients.find(&client_id) {
                        Some(client) => Some(client.clone()),
                        None => None
                    };
                    match client {
                        Some(client) => handler.invoke(&mut self, client),
                        None => error!(
                            "Client {} not found when sending message.",
                            client_id
                        )
                    }
                },
                ClientConnected(client) => {
                    let client = client.as_shared();
                    self.clients.insert(client.borrow().id(), client);
                }
                ChannelLost(name) => {
                    self.channels.remove(&name);
                }
            }
        }
        Ok(self)
    }

    fn start_listening(&mut self) -> IoResult<Receiver<(Event)>>  {
        let listener = TcpListener::bind(self.ip.as_slice(), self.port);
        info!("started listening on {}:{} ({})", self.ip, self.port, self.host);
        let acceptor = try!(listener.listen());
        let (tx, rx) = channel();
        self.tx = Some(tx.clone());
        let host = self.host.clone();
        spawn(proc() {
            let mut a = acceptor; // https://github.com/rust-lang/rust/issues/11958
            for maybe_stream in a.incoming() {
                match maybe_stream {
                    Err(err) => { error!("{}", err) }
                    Ok(stream) => {
                        match Client::listen(host.clone(), stream, tx.clone()) {
                            Ok(()) => {
                            },
                            Err(err) => {
                                error!("{}", err)
                            }
                        }
                    }
                }
            }
        });
        Ok(rx)
    }

    /// Getter for hostname
    pub fn host(&self) -> &str {
        self.host.as_slice()
    }

    /// Getter for hostname
    pub fn tx(&self) -> Option<Sender<Event>> {
        self.tx.clone()
    }

    pub fn remove_client(&mut self, client: &SharedClient) {
        let client = client.borrow();
        self.registered.remove(&client.nickname);
        self.clients.remove(&client.id());
    }

    /// Sends a welcome message to a newly registered client
    pub fn send_welcome_msg(&self, client: &SharedClient) {
        client.borrow().send_response(cmd::RPL_WELCOME, None, None)
    }
}<commit_msg>improve error message<commit_after>
use std::io::{TcpListener};
use std::io::{Listener, Acceptor};
use std::io::{IoResult};
use std::io::net;
use std::io;
use std::collections::hashmap::{HashMap};

use channel::{ChannelEvent};
use client::{SharedClient, Client, ClientId};
use msg::{MessageHandler};
use cmd;

/// Forwards the message to a channel
pub struct ChannelProxy {
    name: String,
    tx: Sender<ChannelEvent>,
    server_tx: Sender<Event>
}

impl ChannelProxy {
    pub fn new(name: String,
           tx: Sender<ChannelEvent>,
           server_tx: Sender<Event>) -> ChannelProxy {
        ChannelProxy {
            name: name,
            tx: tx,
            server_tx: server_tx
        }
    }
    pub fn send(&self, event: ChannelEvent) {
        match self.tx.send_opt(event) {
            Ok(_) => {},
            Err(_) => {
                let _ = self.server_tx.send_opt(ChannelLost(self.name.clone()));
            }
        }
    }
}

pub struct Server {
    host: String,
    ip: String,
    port: u16,
    tx: Option<Sender<Event>>,
    // TODO put unregisterd clients in a staging Map
    clients: HashMap<ClientId, SharedClient>,
    pub registered: HashMap<String, SharedClient>,
    pub channels: HashMap<String, ChannelProxy>
}

/// Enumeration of the events the server can receive
pub enum Event {
    /// Message received from a client
    MessageReceived(ClientId, Box<MessageHandler + Send>),
    /// Connection to a client established
    ClientConnected(Client),
    /// The task of Channel(name) failed
    ChannelLost(String),
}

/// Convenience function to run the server
pub fn run_server(host: &str) -> IoResult<Server> {
    let server = try!(Server::new(host));
    server.serve_forever()
}

/// Irc server
impl Server {
    /// Creates a new IRC server instance.
    pub fn new(host: &str) -> IoResult<Server> {
        let addresses = try!(net::get_host_addresses(host));
        debug!("{}", addresses)
        // Listen only on ipv4 for now…
        let ip = match addresses.iter().filter(
            |&v| match v { &net::ip::Ipv4Addr(_, _, _, _) => true, _ => false }
        ).nth(0) {
            Some(ip) => ip,
            None => return Err(io::IoError {
                kind: io::OtherIoError,
                desc: "cannot get host address",
                detail: None
            })
        };
        Ok(Server {
            host: host.to_string(),
            ip: format!("{}", ip),
            port: 6667,
            tx: None,
            clients: HashMap::new(),
            registered: HashMap::new(),
            channels: HashMap::new()
        })
    }

    /// Starts the main loop and listens on the specified host and port.
    pub fn serve_forever(mut self) -> IoResult<Server> {
        // todo change this to a more general event dispatching loop
        let message_rx = try!(self.start_listening());
        for event in message_rx.iter() {
            match event {
                MessageReceived(client_id, handler) => {
                    let client = match self.clients.find(&client_id) {
                        Some(client) => Some(client.clone()),
                        None => None
                    };
                    match client {
                        Some(client) => handler.invoke(&mut self, client),
                        None => error!(
                            "Client {} not found when sending message.",
                            client_id
                        )
                    }
                },
                ClientConnected(client) => {
                    let client = client.as_shared();
                    self.clients.insert(client.borrow().id(), client);
                }
                ChannelLost(name) => {
                    self.channels.remove(&name);
                }
            }
        }
        Ok(self)
    }

    fn start_listening(&mut self) -> IoResult<Receiver<(Event)>>  {
        let listener = TcpListener::bind(self.ip.as_slice(), self.port);
        info!("started listening on {}:{} ({})", self.ip, self.port, self.host);
        let acceptor = try!(listener.listen());
        let (tx, rx) = channel();
        self.tx = Some(tx.clone());
        let host = self.host.clone();
        spawn(proc() {
            let mut a = acceptor; // https://github.com/rust-lang/rust/issues/11958
            for maybe_stream in a.incoming() {
                match maybe_stream {
                    Err(err) => { error!("{}", err) }
                    Ok(stream) => {
                        match Client::listen(host.clone(), stream, tx.clone()) {
                            Ok(()) => {
                            },
                            Err(err) => {
                                error!("{}", err)
                            }
                        }
                    }
                }
            }
        });
        Ok(rx)
    }

    /// Getter for hostname
    pub fn host(&self) -> &str {
        self.host.as_slice()
    }

    /// Getter for hostname
    pub fn tx(&self) -> Option<Sender<Event>> {
        self.tx.clone()
    }

    pub fn remove_client(&mut self, client: &SharedClient) {
        let client = client.borrow();
        self.registered.remove(&client.nickname);
        self.clients.remove(&client.id());
    }

    /// Sends a welcome message to a newly registered client
    pub fn send_welcome_msg(&self, client: &SharedClient) {
        client.borrow().send_response(cmd::RPL_WELCOME, None, None)
    }
}<|endoftext|>


<commit_before>use message;

pub struct Server {
    id: i32,
}

static CONNACK_OK : [u8; 4] = [32, 2, 0, 0];
static PING_RESP : [u8; 2] = [0xd0, 0];

impl Server {
    pub fn new() -> Self {
        Server { id: 4 }
    }

    pub fn new_message<C: Client>(&mut self, client: &mut C, bytes: &[u8]) {
        let message_type = message::message_type(bytes);
        match message_type {
            message::MqttType::Connect => {
                client.send(&CONNACK_OK);
            },
            message::MqttType::PingReq => {
                client.send(&PING_RESP);
            },
            _ => panic!("Unknown message type")
        }
    }

    pub fn new_bytes<C: Client>(&mut self, client: &mut C, bytes: &[u8]) {
        let mut slice = bytes;

        while slice.len() > 0 {
            let remaining_len = message::remaining_length(bytes);
            let total_len = remaining_len + 2;

            if slice.len() >= total_len {
                let msg = &slice[0 .. total_len];
                slice = &slice[total_len ..];
                self.new_message(client, msg);
            } else {
                slice = &[];
            }
        }
    }
}

pub trait Client {
    fn send(&mut self, bytes: &[u8]);
}

struct TestClient {
    msgs: Vec<Vec<u8>>,
}

impl TestClient {
    fn new() -> Self {
        TestClient { msgs: vec!() }
    }

    fn last_msg(&self) -> &[u8] {
        self.msgs.last().unwrap()
    }
}

impl Client for TestClient {
    fn send(&mut self, bytes: &[u8]) {
        self.msgs.push(bytes.to_vec());
    }
}

#[test]
fn test_connect() {
    let connect_bytes = &[
        0x10u8, 0x2a, // fixed header
        0x00, 0x06, 'M' as u8, 'Q' as u8, 'I' as u8, 's' as u8, 'd' as u8, 'p' as u8,
        0x03, // protocol version
        0xcc, // connection flags 1100111x user, pw, !wr, w(01), w, !c, x
        0x00, 0x0a, // keepalive of 100
        0x00, 0x03, 'c' as u8, 'i' as u8, 'd' as u8, // client ID
        0x00, 0x04, 'w' as u8, 'i' as u8, 'l' as u8, 'l' as u8, // will topic
        0x00, 0x04, 'w' as u8, 'm' as u8, 's' as u8, 'g' as u8, // will msg
        0x00, 0x07, 'g' as u8, 'l' as u8, 'i' as u8, 'f' as u8, 't' as u8, 'e' as u8, 'l' as u8, // username
        0x00, 0x02, 'p' as u8, 'w' as u8, // password
        ][0..];

    let mut server = Server::new();
    let mut client = TestClient::new();

    server.new_message(&mut client, connect_bytes);
    assert_eq!(client.last_msg(), &CONNACK_OK);
}

#[test]
fn test_ping() {
    let ping_bytes =  &[0xc0u8, 0][0..];

    let mut server = Server::new();
    let mut client = TestClient::new();

    server.new_message(&mut client, ping_bytes);

    assert_eq!(client.last_msg(), &PING_RESP);
}

#[test]
fn test_pings_all_at_once() {
    let ping_bytes = &[0xc0u8, 0, 0xc0, 0, 0xc0, 0, 0xc0, 0][0..];

    let mut server = Server::new();
    let mut client = TestClient::new();

    server.new_bytes(&mut client, ping_bytes);

    assert_eq!(client.last_msg(), &PING_RESP);
    assert_eq!(client.msgs.len(), 4);
    for msg in client.msgs {
        assert_eq!(msg, &PING_RESP);
    }
}

#[test]
fn test_pings_multiple_time_unbroken() {
    let ping_bytes = &[0xc0u8, 0, 0xc0, 0][0..];

    let mut server = Server::new();
    let mut client = TestClient::new();

    server.new_bytes(&mut client, ping_bytes);
    assert_eq!(client.msgs.len(), 2);

    server.new_bytes(&mut client, ping_bytes);
    assert_eq!(client.msgs.len(), 4);
}
<commit_msg>Stream handles messages sent multiple times<commit_after>use message;

pub struct Server {
    id: i32,
}

static CONNACK_OK : [u8; 4] = [32, 2, 0, 0];
static PING_RESP : [u8; 2] = [0xd0, 0];

impl Server {
    pub fn new() -> Self {
        Server { id: 4 }
    }

    pub fn new_message<C: Client>(&mut self, client: &mut C, bytes: &[u8]) {
        let message_type = message::message_type(bytes);
        match message_type {
            message::MqttType::Connect => {
                client.send(&CONNACK_OK);
            },
            message::MqttType::PingReq => {
                client.send(&PING_RESP);
            },
            _ => panic!("Unknown message type")
        }
    }

    pub fn new_bytes<C: Client>(&mut self, client: &mut C, bytes: &[u8]) {
        let mut slice = bytes;

        while slice.len() > 0 {
            let remaining_len = message::remaining_length(bytes);
            let total_len = remaining_len + 2;

            if slice.len() >= total_len {
                let msg = &slice[0 .. total_len];
                slice = &slice[total_len ..];
                self.new_message(client, msg);
            } else {
                slice = &[];
            }
        }
    }
}

struct Stream {
    buffer: Vec<u8>,
    bytes_start: usize,
}

impl Stream {
    pub fn new() -> Self {
        Stream { buffer: vec![0; 1024], bytes_start: 0 }
    }

    pub fn buffer(&mut self) -> &mut Vec<u8> {
        &mut self.buffer
    }

    pub fn handle_messages<C: Client>(&mut self, bytes_read: usize, server: &mut Server, client: &mut C) {
        let mut slice = &self.buffer[self.bytes_start .. self.bytes_start + bytes_read];
        let mut total_len = 2;
        while slice.len() >= total_len {
            total_len = message::remaining_length(slice) + 2; //2 for fixed header size
            let msg = &slice[0 .. total_len];
            slice = &slice[total_len..];
            server.new_message(client, msg);
        }
    }
}

pub trait Client {
    fn send(&mut self, bytes: &[u8]);
}

struct TestClient {
    msgs: Vec<Vec<u8>>,
}

impl TestClient {
    fn new() -> Self {
        TestClient { msgs: vec!() }
    }

    fn last_msg(&self) -> &[u8] {
        self.msgs.last().unwrap()
    }

    fn read(&self, buffer: &mut [u8], bytes: &[u8]) -> usize {
        for i in 0..bytes.len() {
            buffer[i] = bytes[i];
        }
        bytes.len()
    }
}

impl Client for TestClient {
    fn send(&mut self, bytes: &[u8]) {
        self.msgs.push(bytes.to_vec());
    }
}

#[test]
fn test_connect() {
    let connect_bytes = &[
        0x10u8, 0x2a, // fixed header
        0x00, 0x06, 'M' as u8, 'Q' as u8, 'I' as u8, 's' as u8, 'd' as u8, 'p' as u8,
        0x03, // protocol version
        0xcc, // connection flags 1100111x user, pw, !wr, w(01), w, !c, x
        0x00, 0x0a, // keepalive of 100
        0x00, 0x03, 'c' as u8, 'i' as u8, 'd' as u8, // client ID
        0x00, 0x04, 'w' as u8, 'i' as u8, 'l' as u8, 'l' as u8, // will topic
        0x00, 0x04, 'w' as u8, 'm' as u8, 's' as u8, 'g' as u8, // will msg
        0x00, 0x07, 'g' as u8, 'l' as u8, 'i' as u8, 'f' as u8, 't' as u8, 'e' as u8, 'l' as u8, // username
        0x00, 0x02, 'p' as u8, 'w' as u8, // password
        ][0..];

    let mut server = Server::new();
    let mut client = TestClient::new();

    server.new_message(&mut client, connect_bytes);
    assert_eq!(client.last_msg(), &CONNACK_OK);
}

#[test]
fn test_ping() {
    let ping_bytes =  &[0xc0u8, 0][0..];

    let mut server = Server::new();
    let mut client = TestClient::new();

    server.new_message(&mut client, ping_bytes);

    assert_eq!(client.last_msg(), &PING_RESP);
}

#[test]
fn test_pings_all_at_once() {
    let ping_bytes = &[0xc0u8, 0, 0xc0, 0, 0xc0, 0, 0xc0, 0][0..];

    let mut server = Server::new();
    let mut client = TestClient::new();
    let mut stream = Stream::new();

    let bytes_read = client.read(stream.buffer(), ping_bytes);
    stream.handle_messages(bytes_read, &mut server, &mut client);

    assert_eq!(client.msgs.len(), 4);
    for msg in client.msgs {
        assert_eq!(msg, &PING_RESP);
    }
}

#[test]
fn test_pings_multiple_time_unbroken() {
    let ping_bytes = &[0xc0u8, 0, 0xc0, 0][0..];

    let mut server = Server::new();
    let mut client = TestClient::new();
    let mut stream = Stream::new();

    let bytes_read = client.read(stream.buffer(), ping_bytes);
    stream.handle_messages(bytes_read, &mut server, &mut client);
    assert_eq!(client.msgs.len(), 2);

    let bytes_read = client.read(stream.buffer(), ping_bytes);
    stream.handle_messages(bytes_read, &mut server, &mut client);
    assert_eq!(client.msgs.len(), 4);

    for msg in client.msgs {
        assert_eq!(msg, &PING_RESP);
    }
}
<|endoftext|>


<commit_before>use std::sync::Arc;
use std::thread;
use std::net::SocketAddr;
use std::net::ToSocketAddrs;
use std::sync::mpsc;
use std::panic::catch_unwind;
use std::panic::AssertUnwindSafe;
use std::any::Any;

use solicit::http::HttpError;
use solicit::http::Header;
use solicit::http::StaticHeader;

use futures;
use futures::Future;
use futures::stream::Stream;
use tokio_core;
use tokio_core::reactor;
use tokio_core::net::TcpListener;

use method::*;
use error::*;
use futures_grpc::*;
use futures_misc::*;
use solicit_misc::*;
use grpc::*;
use grpc_frame::*;
use assert_types::*;
use http_server::*;
use http_common::*;

pub trait MethodHandler<Req, Resp> {
    fn handle(&self, req: GrpcStreamSend<Req>) -> GrpcStreamSend<Resp>;
}

pub struct MethodHandlerUnary<F> {
    f: Arc<F>
}

pub struct MethodHandlerServerStreaming<F> {
    f: Arc<F>
}

pub struct MethodHandlerClientStreaming<F> {
    f: Arc<F>
}

pub struct MethodHandlerBidi<F> {
    _f: Arc<F>
}

impl<F> MethodHandlerUnary<F> {
    pub fn new<Req, Resp>(f: F) -> Self
        where F : Fn(Req) -> GrpcFutureSend<Resp> + Send + Sync,
    {
        MethodHandlerUnary {
            f: Arc::new(f),
        }
    }
}

impl<F> MethodHandlerClientStreaming<F> {
    pub fn new<Req, Resp>(f: F) -> Self
        where F : Fn(GrpcStreamSend<Req>) -> GrpcFutureSend<Resp> + Send + Sync,
    {
        MethodHandlerClientStreaming {
            f: Arc::new(f),
        }
    }
}

impl<F> MethodHandlerServerStreaming<F> {
    pub fn new<Req, Resp>(f: F) -> Self
        where F : Fn(Req) -> GrpcStreamSend<Resp> + Send + Sync,
    {
        MethodHandlerServerStreaming {
            f: Arc::new(f),
        }
    }
}

impl<F> MethodHandlerBidi<F> {
    pub fn new<Req, Resp>(f: F) -> Self
        where F : Fn(GrpcStreamSend<Req>) -> GrpcStreamSend<Resp> + Send + Sync,
    {
        MethodHandlerBidi {
            _f: Arc::new(f),
        }
    }
}

impl<Req, Resp, F> MethodHandler<Req, Resp> for MethodHandlerUnary<F>
    where
        Req : Send + 'static,
        Resp : Send + 'static,
        F : Fn(Req) -> GrpcFutureSend<Resp> + Send + Sync + 'static,
{
    fn handle(&self, req: GrpcStreamSend<Req>) -> GrpcStreamSend<Resp> {
        let f = self.f.clone();
        Box::new(future_to_stream_once(stream_single(req).and_then(move |req| f(req))))
    }
}

impl<Req, Resp, F> MethodHandler<Req, Resp> for MethodHandlerClientStreaming<F>
    where
        Resp : Send + 'static,
        F : Fn(GrpcStreamSend<Req>) -> GrpcFutureSend<Resp> + Send + Sync + 'static,
{
    fn handle(&self, req: GrpcStreamSend<Req>) -> GrpcStreamSend<Resp> {
        Box::new(future_to_stream_once((self.f)(req)))
    }
}

impl<Req, Resp, F> MethodHandler<Req, Resp> for MethodHandlerServerStreaming<F>
    where
        Req : Send + 'static,
        Resp : Send + 'static,
        F : Fn(Req) -> GrpcStreamSend<Resp> + Send + Sync + 'static,
{
    fn handle(&self, req: GrpcStreamSend<Req>) -> GrpcStreamSend<Resp> {
        let f = self.f.clone();
        Box::new(
            future_flatten_to_stream(
                stream_single(req).map(move |req| f(req))))
    }
}

impl<Req, Resp, F> MethodHandler<Req, Resp> for MethodHandlerBidi<F>
    where
        Resp : Send + 'static,
        F : Fn(GrpcStreamSend<Req>) -> GrpcStreamSend<Resp> + Send + Sync + 'static,
{
    fn handle(&self, _req: GrpcStreamSend<Req>) -> GrpcStreamSend<Resp> {
        unimplemented!()
    }
}

trait MethodHandlerDispatch {
    fn start_request(&self, req: GrpcStreamSend<Vec<u8>>) -> GrpcStreamSend<Vec<u8>>;
}

struct MethodHandlerDispatchAsyncImpl<Req, Resp> {
    desc: Arc<MethodDescriptor<Req, Resp>>,
    method_handler: Box<MethodHandler<Req, Resp> + Sync + Send>,
}

fn any_to_string(any: Box<Any + Send + 'static>) -> String {
    if any.is::<String>() {
        *any.downcast::<String>().unwrap()
    } else if any.is::<&str>() {
        (*any.downcast::<&str>().unwrap()).to_owned()
    } else {
        "unknown any".to_owned()
    }
}

impl<Req, Resp> MethodHandlerDispatch for MethodHandlerDispatchAsyncImpl<Req, Resp>
    where
        Req : Send + 'static,
        Resp : Send + 'static,
{
    fn start_request(&self, req_grpc_frames: GrpcStreamSend<Vec<u8>>) -> GrpcStreamSend<Vec<u8>> {
        let desc = self.desc.clone();
        let req = req_grpc_frames.and_then(move |frame| desc.req_marshaller.read(&frame));
        let resp =
            catch_unwind(AssertUnwindSafe(|| self.method_handler.handle(Box::new(req))));
        match resp {
            Ok(resp) => {
                let desc_copy = self.desc.clone();
                Box::new(resp
                    .and_then(move |resp| desc_copy.resp_marshaller.write(&resp)))
            }
            Err(e) => {
                let message = any_to_string(e);
                Box::new(future_to_stream_once(futures::failed(GrpcError::Panic(message))))
            }
        }
    }
}

pub struct ServerMethod {
    name: String,
    dispatch: Box<MethodHandlerDispatch + Sync + Send>,
}

impl ServerMethod {
    pub fn new<Req, Resp, H>(method: Arc<MethodDescriptor<Req, Resp>>, handler: H) -> ServerMethod
        where
            Req : Send + 'static,
            Resp : Send + 'static,
            H : MethodHandler<Req, Resp> + 'static + Sync + Send,
    {
        ServerMethod {
            name: method.name.clone(),
            dispatch: Box::new(MethodHandlerDispatchAsyncImpl {
                desc: method,
                method_handler: Box::new(handler),
            }),
        }
    }
}

pub struct ServerServiceDefinition {
    methods: Vec<ServerMethod>,
}

impl ServerServiceDefinition {
    pub fn new(methods: Vec<ServerMethod>) -> ServerServiceDefinition {
        ServerServiceDefinition {
            methods: methods,
        }
    }

    pub fn find_method(&self, name: &str) -> &ServerMethod {
        self.methods.iter()
            .filter(|m| m.name == name)
            .next()
            .expect(&format!("unknown method: {}", name))
    }

    // TODO: stream
    pub fn handle_method(&self, name: &str, message: GrpcStreamSend<Vec<u8>>) -> GrpcStreamSend<Vec<u8>> {
        self.find_method(name).dispatch.start_request(message)
    }
}

struct LoopToServer {
    // used only once to send shutdown signal
    shutdown_tx: tokio_core::channel::Sender<()>,
    local_addr: SocketAddr,
}

fn _assert_loop_to_server() {
    assert_send::<LoopToServer>();
}

pub struct GrpcServer {
    loop_to_server: LoopToServer,
    thread_join_handle: Option<thread::JoinHandle<()>>,
}

impl GrpcServer {
    pub fn new(port: u16, service_definition: ServerServiceDefinition) -> GrpcServer {
        let listen_addr = ("::", port).to_socket_addrs().unwrap().next().unwrap();

        let (get_from_loop_tx, get_from_loop_rx) = mpsc::channel();

        let join_handle = thread::spawn(move || {
            run_server_event_loop(listen_addr, service_definition, get_from_loop_tx);
        });

        let loop_to_server = get_from_loop_rx.recv().unwrap();

        GrpcServer {
            loop_to_server: loop_to_server,
            thread_join_handle: Some(join_handle),
        }
    }

    pub fn local_addr(&self) -> &SocketAddr {
        &self.loop_to_server.local_addr
    }
}

// We shutdown client in destructor.
impl Drop for GrpcServer {
    fn drop(&mut self) {
        // ignore error because even loop may be already dead
        self.loop_to_server.shutdown_tx.send(()).ok();

        // do not ignore errors because we own event loop thread
        self.thread_join_handle.take().unwrap().join().unwrap();
    }
}

struct GrpcHttpServerHandlerFactory {
    service_definition: Arc<ServerServiceDefinition>,
}

fn stream_500(message: &str) -> HttpStreamStreamSend {
    Box::new(stream_once(HttpStreamPart::last_headers(vec![
        Header::new(":status", "500"),
        Header::new(HEADER_GRPC_MESSAGE, message.to_owned()),
    ])))
}

impl HttpService for GrpcHttpServerHandlerFactory {
    fn new_request(&mut self, headers: Vec<StaticHeader>, req: HttpStreamStreamSend) -> HttpStreamStreamSend {

        let path = match slice_get_header(&headers, ":path") {
            Some(path) => path.to_owned(),
            None => return stream_500("no :path header"),
        };

        let grpc_request = GrpcFrameFromHttpFramesStreamRequest::new(req);

        // TODO: catch unwind
        let grpc_frames = self.service_definition.handle_method(&path, Box::new(grpc_request));

        let http_parts = stream_concat3(
            stream_once(HttpStreamPart::intermediate_headers(vec![
                Header::new(":status", "200"),
            ])),
            grpc_frames
                .map(|frame| HttpStreamPart::intermediate_data(write_grpc_frame_to_vec(&frame)))
                .then(|result| {
                    match result {
                        Ok(part) => { let r: Result<_, HttpError> = Ok(part); r }
                        Err(e) =>
                            Ok(HttpStreamPart::last_headers(vec![
                                Header::new(":status", "500"),
                                Header::new(HEADER_GRPC_MESSAGE, format!("error: {:?}", e)),
                            ]))
                    }
                }),
            stream_once(HttpStreamPart::last_headers(vec![
                Header::new(HEADER_GRPC_STATUS, "0"),
            ])));

        Box::new(http_parts)
    }
}

fn run_server_event_loop(
    listen_addr: SocketAddr,
    service_definition: ServerServiceDefinition,
    send_to_back: mpsc::Sender<LoopToServer>)
{
    let service_definition = Arc::new(service_definition);

    let mut lp = reactor::Core::new().expect("loop new");

    let (shutdown_tx, shutdown_rx) = tokio_core::channel::channel(&lp.handle()).unwrap();

    let shutdown_rx = shutdown_rx.map_err(GrpcError::from);

    let listen = TcpListener::bind(&listen_addr, &lp.handle()).unwrap();

    let stuff = stream_repeat(lp.handle());

    let local_addr = listen.local_addr().unwrap();
    send_to_back
        .send(LoopToServer { shutdown_tx: shutdown_tx, local_addr: local_addr })
        .expect("send back");

    let loop_run = listen.incoming().map_err(GrpcError::from).zip(stuff).for_each(move |((socket, _peer_addr), loop_handle)| {
        loop_handle.spawn(HttpServerConnectionAsync::new(&loop_handle, socket, GrpcHttpServerHandlerFactory {
            service_definition: service_definition.clone(),
        }).map_err(|e| { println!("{:?}", e); () }));
        Ok(())
    });

    let shutdown = shutdown_rx.into_future().map_err(|(e, _)| GrpcError::from(e)).and_then(|_| {
        // Must complete with error,
        // so `join` with this future cancels another future.
        futures::failed::<(), _>(GrpcError::Other("shutdown"))
    });

    // Wait for either completion of connection (i. e. error)
    // or shutdown signal.
    let done = loop_run.join(shutdown);

    // TODO: do not ignore error
    lp.run(done).ok();
}
<commit_msg>implement bidi<commit_after>use std::sync::Arc;
use std::thread;
use std::net::SocketAddr;
use std::net::ToSocketAddrs;
use std::sync::mpsc;
use std::panic::catch_unwind;
use std::panic::AssertUnwindSafe;
use std::any::Any;

use solicit::http::HttpError;
use solicit::http::Header;
use solicit::http::StaticHeader;

use futures;
use futures::Future;
use futures::stream::Stream;
use tokio_core;
use tokio_core::reactor;
use tokio_core::net::TcpListener;

use method::*;
use error::*;
use futures_grpc::*;
use futures_misc::*;
use solicit_misc::*;
use grpc::*;
use grpc_frame::*;
use assert_types::*;
use http_server::*;
use http_common::*;

pub trait MethodHandler<Req, Resp> {
    fn handle(&self, req: GrpcStreamSend<Req>) -> GrpcStreamSend<Resp>;
}

pub struct MethodHandlerUnary<F> {
    f: Arc<F>
}

pub struct MethodHandlerServerStreaming<F> {
    f: Arc<F>
}

pub struct MethodHandlerClientStreaming<F> {
    f: Arc<F>
}

pub struct MethodHandlerBidi<F> {
    f: Arc<F>
}

impl<F> MethodHandlerUnary<F> {
    pub fn new<Req, Resp>(f: F) -> Self
        where F : Fn(Req) -> GrpcFutureSend<Resp> + Send + Sync,
    {
        MethodHandlerUnary {
            f: Arc::new(f),
        }
    }
}

impl<F> MethodHandlerClientStreaming<F> {
    pub fn new<Req, Resp>(f: F) -> Self
        where F : Fn(GrpcStreamSend<Req>) -> GrpcFutureSend<Resp> + Send + Sync,
    {
        MethodHandlerClientStreaming {
            f: Arc::new(f),
        }
    }
}

impl<F> MethodHandlerServerStreaming<F> {
    pub fn new<Req, Resp>(f: F) -> Self
        where F : Fn(Req) -> GrpcStreamSend<Resp> + Send + Sync,
    {
        MethodHandlerServerStreaming {
            f: Arc::new(f),
        }
    }
}

impl<F> MethodHandlerBidi<F> {
    pub fn new<Req, Resp>(f: F) -> Self
        where F : Fn(GrpcStreamSend<Req>) -> GrpcStreamSend<Resp> + Send + Sync,
    {
        MethodHandlerBidi {
            f: Arc::new(f),
        }
    }
}

impl<Req, Resp, F> MethodHandler<Req, Resp> for MethodHandlerUnary<F>
    where
        Req : Send + 'static,
        Resp : Send + 'static,
        F : Fn(Req) -> GrpcFutureSend<Resp> + Send + Sync + 'static,
{
    fn handle(&self, req: GrpcStreamSend<Req>) -> GrpcStreamSend<Resp> {
        let f = self.f.clone();
        Box::new(future_to_stream_once(stream_single(req).and_then(move |req| f(req))))
    }
}

impl<Req, Resp, F> MethodHandler<Req, Resp> for MethodHandlerClientStreaming<F>
    where
        Resp : Send + 'static,
        F : Fn(GrpcStreamSend<Req>) -> GrpcFutureSend<Resp> + Send + Sync + 'static,
{
    fn handle(&self, req: GrpcStreamSend<Req>) -> GrpcStreamSend<Resp> {
        Box::new(future_to_stream_once((self.f)(req)))
    }
}

impl<Req, Resp, F> MethodHandler<Req, Resp> for MethodHandlerServerStreaming<F>
    where
        Req : Send + 'static,
        Resp : Send + 'static,
        F : Fn(Req) -> GrpcStreamSend<Resp> + Send + Sync + 'static,
{
    fn handle(&self, req: GrpcStreamSend<Req>) -> GrpcStreamSend<Resp> {
        let f = self.f.clone();
        Box::new(
            future_flatten_to_stream(
                stream_single(req).map(move |req| f(req))))
    }
}

impl<Req, Resp, F> MethodHandler<Req, Resp> for MethodHandlerBidi<F>
    where
        Resp : Send + 'static,
        F : Fn(GrpcStreamSend<Req>) -> GrpcStreamSend<Resp> + Send + Sync + 'static,
{
    fn handle(&self, req: GrpcStreamSend<Req>) -> GrpcStreamSend<Resp> {
        Box::new((self.f)(req))
    }
}

trait MethodHandlerDispatch {
    fn start_request(&self, req: GrpcStreamSend<Vec<u8>>) -> GrpcStreamSend<Vec<u8>>;
}

struct MethodHandlerDispatchAsyncImpl<Req, Resp> {
    desc: Arc<MethodDescriptor<Req, Resp>>,
    method_handler: Box<MethodHandler<Req, Resp> + Sync + Send>,
}

fn any_to_string(any: Box<Any + Send + 'static>) -> String {
    if any.is::<String>() {
        *any.downcast::<String>().unwrap()
    } else if any.is::<&str>() {
        (*any.downcast::<&str>().unwrap()).to_owned()
    } else {
        "unknown any".to_owned()
    }
}

impl<Req, Resp> MethodHandlerDispatch for MethodHandlerDispatchAsyncImpl<Req, Resp>
    where
        Req : Send + 'static,
        Resp : Send + 'static,
{
    fn start_request(&self, req_grpc_frames: GrpcStreamSend<Vec<u8>>) -> GrpcStreamSend<Vec<u8>> {
        let desc = self.desc.clone();
        let req = req_grpc_frames.and_then(move |frame| desc.req_marshaller.read(&frame));
        let resp =
            catch_unwind(AssertUnwindSafe(|| self.method_handler.handle(Box::new(req))));
        match resp {
            Ok(resp) => {
                let desc_copy = self.desc.clone();
                Box::new(resp
                    .and_then(move |resp| desc_copy.resp_marshaller.write(&resp)))
            }
            Err(e) => {
                let message = any_to_string(e);
                Box::new(future_to_stream_once(futures::failed(GrpcError::Panic(message))))
            }
        }
    }
}

pub struct ServerMethod {
    name: String,
    dispatch: Box<MethodHandlerDispatch + Sync + Send>,
}

impl ServerMethod {
    pub fn new<Req, Resp, H>(method: Arc<MethodDescriptor<Req, Resp>>, handler: H) -> ServerMethod
        where
            Req : Send + 'static,
            Resp : Send + 'static,
            H : MethodHandler<Req, Resp> + 'static + Sync + Send,
    {
        ServerMethod {
            name: method.name.clone(),
            dispatch: Box::new(MethodHandlerDispatchAsyncImpl {
                desc: method,
                method_handler: Box::new(handler),
            }),
        }
    }
}

pub struct ServerServiceDefinition {
    methods: Vec<ServerMethod>,
}

impl ServerServiceDefinition {
    pub fn new(methods: Vec<ServerMethod>) -> ServerServiceDefinition {
        ServerServiceDefinition {
            methods: methods,
        }
    }

    pub fn find_method(&self, name: &str) -> &ServerMethod {
        self.methods.iter()
            .filter(|m| m.name == name)
            .next()
            .expect(&format!("unknown method: {}", name))
    }

    // TODO: stream
    pub fn handle_method(&self, name: &str, message: GrpcStreamSend<Vec<u8>>) -> GrpcStreamSend<Vec<u8>> {
        self.find_method(name).dispatch.start_request(message)
    }
}

struct LoopToServer {
    // used only once to send shutdown signal
    shutdown_tx: tokio_core::channel::Sender<()>,
    local_addr: SocketAddr,
}

fn _assert_loop_to_server() {
    assert_send::<LoopToServer>();
}

pub struct GrpcServer {
    loop_to_server: LoopToServer,
    thread_join_handle: Option<thread::JoinHandle<()>>,
}

impl GrpcServer {
    pub fn new(port: u16, service_definition: ServerServiceDefinition) -> GrpcServer {
        let listen_addr = ("::", port).to_socket_addrs().unwrap().next().unwrap();

        let (get_from_loop_tx, get_from_loop_rx) = mpsc::channel();

        let join_handle = thread::spawn(move || {
            run_server_event_loop(listen_addr, service_definition, get_from_loop_tx);
        });

        let loop_to_server = get_from_loop_rx.recv().unwrap();

        GrpcServer {
            loop_to_server: loop_to_server,
            thread_join_handle: Some(join_handle),
        }
    }

    pub fn local_addr(&self) -> &SocketAddr {
        &self.loop_to_server.local_addr
    }
}

// We shutdown client in destructor.
impl Drop for GrpcServer {
    fn drop(&mut self) {
        // ignore error because even loop may be already dead
        self.loop_to_server.shutdown_tx.send(()).ok();

        // do not ignore errors because we own event loop thread
        self.thread_join_handle.take().unwrap().join().unwrap();
    }
}

struct GrpcHttpServerHandlerFactory {
    service_definition: Arc<ServerServiceDefinition>,
}

fn stream_500(message: &str) -> HttpStreamStreamSend {
    Box::new(stream_once(HttpStreamPart::last_headers(vec![
        Header::new(":status", "500"),
        Header::new(HEADER_GRPC_MESSAGE, message.to_owned()),
    ])))
}

impl HttpService for GrpcHttpServerHandlerFactory {
    fn new_request(&mut self, headers: Vec<StaticHeader>, req: HttpStreamStreamSend) -> HttpStreamStreamSend {

        let path = match slice_get_header(&headers, ":path") {
            Some(path) => path.to_owned(),
            None => return stream_500("no :path header"),
        };

        let grpc_request = GrpcFrameFromHttpFramesStreamRequest::new(req);

        // TODO: catch unwind
        let grpc_frames = self.service_definition.handle_method(&path, Box::new(grpc_request));

        let http_parts = stream_concat3(
            stream_once(HttpStreamPart::intermediate_headers(vec![
                Header::new(":status", "200"),
            ])),
            grpc_frames
                .map(|frame| HttpStreamPart::intermediate_data(write_grpc_frame_to_vec(&frame)))
                .then(|result| {
                    match result {
                        Ok(part) => { let r: Result<_, HttpError> = Ok(part); r }
                        Err(e) =>
                            Ok(HttpStreamPart::last_headers(vec![
                                Header::new(":status", "500"),
                                Header::new(HEADER_GRPC_MESSAGE, format!("error: {:?}", e)),
                            ]))
                    }
                }),
            stream_once(HttpStreamPart::last_headers(vec![
                Header::new(HEADER_GRPC_STATUS, "0"),
            ])));

        Box::new(http_parts)
    }
}

fn run_server_event_loop(
    listen_addr: SocketAddr,
    service_definition: ServerServiceDefinition,
    send_to_back: mpsc::Sender<LoopToServer>)
{
    let service_definition = Arc::new(service_definition);

    let mut lp = reactor::Core::new().expect("loop new");

    let (shutdown_tx, shutdown_rx) = tokio_core::channel::channel(&lp.handle()).unwrap();

    let shutdown_rx = shutdown_rx.map_err(GrpcError::from);

    let listen = TcpListener::bind(&listen_addr, &lp.handle()).unwrap();

    let stuff = stream_repeat(lp.handle());

    let local_addr = listen.local_addr().unwrap();
    send_to_back
        .send(LoopToServer { shutdown_tx: shutdown_tx, local_addr: local_addr })
        .expect("send back");

    let loop_run = listen.incoming().map_err(GrpcError::from).zip(stuff).for_each(move |((socket, _peer_addr), loop_handle)| {
        loop_handle.spawn(HttpServerConnectionAsync::new(&loop_handle, socket, GrpcHttpServerHandlerFactory {
            service_definition: service_definition.clone(),
        }).map_err(|e| { println!("{:?}", e); () }));
        Ok(())
    });

    let shutdown = shutdown_rx.into_future().map_err(|(e, _)| GrpcError::from(e)).and_then(|_| {
        // Must complete with error,
        // so `join` with this future cancels another future.
        futures::failed::<(), _>(GrpcError::Other("shutdown"))
    });

    // Wait for either completion of connection (i. e. error)
    // or shutdown signal.
    let done = loop_run.join(shutdown);

    // TODO: do not ignore error
    lp.run(done).ok();
}
<|endoftext|>