use std::sync::Arc;
use std::net::{SocketAddr, ToSocketAddrs};
use std::thread;
use std::io;
use num_cpus;
use futures::{future, Future, IntoFuture, Stream};
use hyper::{self, StatusCode};
use hyper::server::Http;
use tokio_core::net::TcpListener;
use tokio_core::reactor::{Core, Handle};
use net2::TcpBuilder;
#[cfg(unix)]
use net2::unix::UnixTcpBuilderExt;
use handler::Handler;
use context::Context;
use router::{Route, Router};
use response::Response;
use errors::ListenError;
pub struct Salt<H: Handler + 'static> {
handler: Arc<H>,
threads: usize,
}
impl<H: Handler> Salt<H> {
pub fn new(handler: H) -> Self {
Salt {
handler: Arc::new(handler),
threads: num_cpus::get(),
}
}
pub fn threads(&mut self, threads: usize) {
self.threads = threads;
}
pub fn run<A: ToSocketAddrsExt>(&self, addr: A) -> Result<(), ListenError> {
let addrs = addr.to_socket_addrs_ext()?.collect::<Vec<_>>();
let mut children = Vec::new();
for _ in 0..self.threads {
let addrs = addrs.clone();
let handler = self.handler.clone();
children.push(thread::spawn(move || -> Result<(), ListenError> {
let mut core = Core::new()?;
let mut work = Vec::new();
let handle = core.handle();
let service = Service {
handler: handler,
handle: handle.clone(),
};
for addr in &addrs {
let handle = handle.clone();
let builder = (match *addr {
SocketAddr::V4(_) => TcpBuilder::new_v4(),
SocketAddr::V6(_) => TcpBuilder::new_v6(),
})?;
builder.reuse_address(true)?;
#[cfg(unix)]
builder.reuse_port(true)?;
builder.bind(&addr)?;
let listener = TcpListener::from_listener(
builder.listen(128)?,
addr,
&handle,
)?;
let protocol = Http::new();
let service = service.clone();
let srv = listener.incoming().for_each(move |(socket, addr)| {
protocol.bind_connection(&handle, socket, addr, service.clone());
Ok(())
});
work.push(srv);
}
core.run(future::join_all(work))?;
Ok(())
}));
}
for child in children.drain(..) {
child.join().unwrap()?;
}
Ok(())
}
}
impl Default for Salt<Router> {
fn default() -> Self {
Salt::new(Router::new())
}
}
impl Salt<Router> {
pub fn route<R: Into<Route>>(&mut self, route: R) -> &mut Self {
Arc::get_mut(&mut self.handler).map(|router| router.route(route));
self
}
}
struct Service<H: Handler + 'static> {
handler: Arc<H>,
handle: Handle,
}
impl<H: Handler + 'static> Clone for Service<H> {
fn clone(&self) -> Self {
Service {
handler: self.handler.clone(),
handle: self.handle.clone(),
}
}
}
impl<H: Handler + 'static> hyper::server::Service for Service<H> {
type Request = hyper::Request;
type Response = hyper::Response;
type Error = hyper::Error;
type Future = Box<Future<Item = Self::Response, Error = Self::Error>>;
fn call(&self, request: Self::Request) -> Self::Future {
let ctx = Context::new(request, self.handle.clone());
Box::new(self.handler.call(ctx).into_future().or_else(|_| {
Response::new().with_status(StatusCode::InternalServerError)
}).map(Response::into_hyper_response))
}
}
pub trait ToSocketAddrsExt {
type Iter: Iterator<Item = SocketAddr>;
fn to_socket_addrs_ext(&self) -> io::Result<Self::Iter>;
}
impl<'a> ToSocketAddrsExt for &'a str {
type Iter = <str as ToSocketAddrs>::Iter;
fn to_socket_addrs_ext(&self) -> io::Result<Self::Iter> {
if self.starts_with(':') {
let port: u16 = self[1..].parse().unwrap();
Ok(
(&[
SocketAddr::new("0.0.0.0".parse().unwrap(), port),
SocketAddr::new("::0".parse().unwrap(), port),
][..])
.to_socket_addrs()?
.collect::<Vec<_>>()
.into_iter(),
)
} else {
self.to_socket_addrs()
}
}
}
impl ToSocketAddrsExt for String {
type Iter = <String as ToSocketAddrs>::Iter;
fn to_socket_addrs_ext(&self) -> io::Result<Self::Iter> {
(&**self).to_socket_addrs_ext()
}
}
macro_rules! forward_to_socket_addrs {
($lifetime:tt, $ty:ty) => (
impl<$lifetime> ToSocketAddrsExt for $ty {
type Iter = <$ty as ToSocketAddrs>::Iter;
fn to_socket_addrs_ext(&self) -> io::Result<Self::Iter> {
self.to_socket_addrs()
}
}
);
($ty:ty) => (
impl ToSocketAddrsExt for $ty {
type Iter = <$ty as ToSocketAddrs>::Iter;
fn to_socket_addrs_ext(&self) -> io::Result<Self::Iter> {
self.to_socket_addrs()
}
}
);
}
forward_to_socket_addrs!('a, &'a [SocketAddr]);
forward_to_socket_addrs!('a, (&'a str, u16));
#[cfg(test)]
mod tests {
use super::ToSocketAddrsExt;
#[test]
fn to_socket_addrs_ext_str() {
let addresses = ":7878".to_socket_addrs_ext().unwrap().collect::<Vec<_>>();
assert_eq!(addresses.len(), 2);
assert_eq!(addresses[0], "0.0.0.0:7878".parse().unwrap());
assert_eq!(addresses[1], "[::0]:7878".parse().unwrap());
}
#[test]
fn to_socket_addrs_ext_string() {
let address = ":7878".to_owned();
let addresses = address.to_socket_addrs_ext().unwrap().collect::<Vec<_>>();
assert_eq!(addresses.len(), 2);
assert_eq!(addresses[0], "0.0.0.0:7878".parse().unwrap());
assert_eq!(addresses[1], "[::0]:7878".parse().unwrap());
}
}