#[macro_use]
extern crate log;
use hyper;
use hyper::server::conn::AddrIncoming;
use hyper::server::conn::AddrStream;
use hyper::Server as HyperServer;
use std::clone::Clone;
use std::net::SocketAddr;
use std::sync::Arc;
use tokio::net::{TcpListener, TcpStream};
use tokio_rustls::server::TlsStream;
pub mod errors;
mod hyper_config;
pub mod protocols;
pub mod request;
pub mod response;
pub mod stack;
use self::errors::RhodHyperError; use self::hyper_config::*;
use self::protocols::*;
use self::request::*;
use self::stack::*;
#[derive(Clone)]
pub struct RhodConnInfo {
pub addr: SocketAddr,
pub proto: HttpProtocol,
}
impl RhodConnInfo {
pub fn new(addr: SocketAddr, proto: HttpProtocol) -> RhodConnInfo {
RhodConnInfo { addr, proto }
}
}
pub trait CommunicationChannel: Send + Sync + 'static {
fn new() -> Self;
}
pub struct Rhodium<C: CommunicationChannel> {
stack: Arc<RhodStack<C>>, addr: SocketAddr, protocol: HttpProtocolConf, }
impl<C: CommunicationChannel> Rhodium<C> {
pub fn new(
stack: Arc<RhodStack<C>>,
addr: SocketAddr,
protocol: HttpProtocolConf,
) -> Rhodium<C> {
Rhodium {
stack,
addr,
protocol,
}
}
pub async fn run(self) -> Result<(), RhodHyperError> {
println!("Listening on {}://{}", self.protocol.to_string(), self.addr);
info!("Listening on {}://{}", self.protocol.to_string(), self.addr);
match &self.protocol {
HttpProtocolConf::HTTP => {
match AddrIncoming::bind(&self.addr) {
Ok(addr_incoming) => {
let builder = HyperServer::builder(addr_incoming);
let mk_service = hyper::service::make_service_fn(|socket: &AddrStream| {
let stack = Arc::clone(&self.stack);
let addr = socket.remote_addr();
async move {
Ok::<_, RhodHyperError>(RhodHyperService::new(
stack,
RhodConnInfo::new(addr, HttpProtocol::HTTP),
))
}
});
RhodHyperError::from_hyper_error_result(builder.serve(mk_service).await)
}
Err(e) => Err(RhodHyperError::ConfigError(format!(
"Error when binding (HTTP). {}",
e
))),
}
}
HttpProtocolConf::HTTPS {
cert_file,
key_file,
} => {
match TcpListener::bind(&self.addr).await {
Ok(tcp) => match HyperTlsAcceptor::new(tcp, &cert_file, &key_file) {
Ok(tls_acceptor) => {
let builder = HyperServer::builder(tls_acceptor);
let mk_service =
hyper::service::make_service_fn(|stream: &TlsStream<TcpStream>| {
let stack = Arc::clone(&self.stack);
let addr = stream.get_ref().0.peer_addr();
async move {
match addr {
Ok(peer_addr) => {
Ok::<_, RhodHyperError>(RhodHyperService::new(
stack,
RhodConnInfo::new(
peer_addr,
HttpProtocol::HTTPS,
),
))
}
Err(e) => Err::<RhodHyperService<C>, RhodHyperError>(
RhodHyperError::ConfigError(format!(
"Couldnt parse client IP. {}",
e
)),
),
}
}
});
RhodHyperError::from_hyper_error_result(builder.serve(mk_service).await)
}
Err(e) => Err(RhodHyperError::ConfigError(format!(
"Error when creating TLS Acceptor. {}",
e
))),
},
Err(e) => Err(RhodHyperError::ConfigError(format!(
"Error when binding (HTTPS). {}",
e
))),
}
}
}
}
}