#![doc(html_root_url = "https://docs.rs/gotham/0.7.4")]
#![cfg_attr(feature = "ci", deny(warnings))]
#![allow(
clippy::needless_lifetimes,
clippy::should_implement_trait,
clippy::unit_arg,
clippy::match_wild_err_arm,
clippy::new_without_default,
clippy::wrong_self_convention,
clippy::mutex_atomic,
clippy::borrowed_box,
clippy::get_unwrap
)]
#![warn(missing_docs, rust_2018_idioms, unreachable_pub)]
#![deny(elided_lifetimes_in_paths, unsafe_code)]
#![doc(test(no_crate_inject, attr(deny(warnings))))]
pub mod extractor;
pub mod handler;
pub mod helpers;
pub mod middleware;
pub mod pipeline;
pub mod prelude;
pub mod router;
pub mod service;
pub mod state;
#[cfg(feature = "testing")]
pub mod test;
pub mod plain;
#[cfg(feature = "rustls")]
pub mod tls;
pub use anyhow;
pub use cookie;
pub use hyper;
pub use mime;
#[cfg(feature = "rustls")]
pub use tokio_rustls::rustls;
use futures_util::TryFutureExt;
use hyper::server::conn::Http;
use std::future::Future;
use std::io;
use std::net::ToSocketAddrs;
use std::sync::Arc;
use thiserror::Error;
use tokio::io::{AsyncRead, AsyncWrite};
use tokio::net::{TcpListener, TcpStream};
use tokio::runtime::{self, Runtime};
use crate::handler::NewHandler;
use crate::service::GothamService;
pub use plain::*;
#[cfg(feature = "rustls")]
pub use tls::start as start_with_tls;
#[derive(Debug, Error)]
#[non_exhaustive]
pub enum StartError {
#[error("I/O Error: {0}")]
IoError(#[from] io::Error),
}
fn new_runtime(threads: usize) -> Runtime {
runtime::Builder::new_multi_thread()
.worker_threads(threads)
.thread_name("gotham-worker")
.enable_all()
.build()
.unwrap()
}
async fn tcp_listener<A>(addr: A) -> io::Result<TcpListener>
where
A: ToSocketAddrs + 'static,
{
let addr = addr.to_socket_addrs()?.next().ok_or_else(|| {
io::Error::new(io::ErrorKind::Other, "unable to resolve listener address")
})?;
TcpListener::bind(addr).await
}
pub async fn bind_server<'a, NH, F, Wrapped, Wrap>(
listener: TcpListener,
new_handler: NH,
wrap: Wrap,
) -> !
where
NH: NewHandler + 'static,
F: Future<Output = Result<Wrapped, ()>> + Unpin + Send + 'static,
Wrapped: Unpin + AsyncRead + AsyncWrite + Send + 'static,
Wrap: Fn(TcpStream) -> F,
{
let protocol = Arc::new(Http::new());
let gotham_service = GothamService::new(new_handler);
loop {
let (socket, addr) = match listener.accept().await {
Ok(ok) => ok,
Err(err) => {
log::error!("Socket Error: {}", err);
continue;
}
};
let service = gotham_service.connect(addr);
let accepted_protocol = protocol.clone();
let wrapper = wrap(socket);
let task = async move {
let socket = wrapper.await?;
accepted_protocol
.serve_connection(socket, service)
.with_upgrades()
.map_err(|_| ())
.await?;
Result::<_, ()>::Ok(())
};
tokio::spawn(task);
}
}