#![cfg_attr(docsrs, feature(doc_cfg))]
use std::io::ErrorKind;
use std::io::Write;
use std::io::{self};
use std::net::SocketAddr;
use std::str::FromStr;
pub mod body;
#[cfg(all(feature = "client", not(feature = "compio")))]
#[cfg_attr(docsrs, doc(cfg(feature = "client")))]
pub mod client;
pub mod config;
pub mod extractors;
#[cfg(feature = "file-stream")]
#[cfg_attr(docsrs, doc(cfg(feature = "file-stream")))]
pub mod file_stream;
mod handler;
pub mod middleware;
#[cfg(feature = "plugins")]
#[cfg_attr(docsrs, doc(cfg(feature = "plugins")))]
pub mod plugins;
pub mod responder;
pub mod redirect;
mod route;
pub mod router;
#[cfg(not(feature = "compio"))]
mod server;
pub mod sse;
pub mod queue;
pub mod state;
#[cfg(feature = "signals")]
pub mod signals;
pub mod r#static;
#[cfg(feature = "tako-tracing")]
#[cfg_attr(docsrs, doc(cfg(feature = "tako-tracing")))]
pub mod tracing;
pub mod types;
#[cfg(not(feature = "compio"))]
pub mod ws;
#[cfg(feature = "compio-ws")]
#[cfg_attr(docsrs, doc(cfg(feature = "compio-ws")))]
pub mod ws_compio;
#[cfg(feature = "async-graphql")]
#[cfg_attr(docsrs, doc(cfg(feature = "async-graphql")))]
pub mod graphql;
#[cfg(feature = "graphiql")]
#[cfg_attr(docsrs, doc(cfg(feature = "graphiql")))]
pub mod graphiql;
#[cfg(any(feature = "utoipa", feature = "vespera"))]
#[cfg_attr(docsrs, doc(cfg(any(feature = "utoipa", feature = "vespera"))))]
pub mod openapi;
#[cfg(feature = "zero-copy-extractors")]
#[cfg_attr(docsrs, doc(cfg(feature = "zero-copy-extractors")))]
pub mod zero_copy_extractors;
pub use bytes::Bytes;
pub use http::Method;
pub use http::StatusCode;
pub use http::header;
pub use http_body_util::Full;
pub use responder::NOT_FOUND;
#[cfg(not(feature = "compio"))]
pub use server::serve;
#[cfg(not(feature = "compio"))]
pub use server::serve_with_shutdown;
#[cfg(feature = "compio")]
pub use server_compio::serve;
#[cfg(feature = "compio")]
pub use server_compio::serve_with_shutdown;
#[cfg(not(feature = "compio"))]
pub async fn bind_with_port_fallback(addr: &str) -> io::Result<tokio::net::TcpListener> {
let mut socket_addr =
SocketAddr::from_str(addr).map_err(|e| io::Error::new(ErrorKind::InvalidInput, e))?;
let start_port = socket_addr.port();
loop {
let addr_str = socket_addr.to_string();
match tokio::net::TcpListener::bind(&addr_str).await {
Ok(listener) => {
if socket_addr.port() != start_port {
println!(
"Port {} was in use, starting on {} instead",
start_port,
socket_addr.port()
);
}
return Ok(listener);
}
Err(err) if err.kind() == ErrorKind::AddrInUse => {
let next_port = socket_addr.port().saturating_add(1);
if !ask_to_use_next_port(socket_addr.port(), next_port)? {
return Err(err);
}
socket_addr.set_port(next_port);
}
Err(err) => return Err(err),
}
}
}
#[cfg(feature = "compio")]
pub async fn bind_with_port_fallback(addr: &str) -> io::Result<compio::net::TcpListener> {
let mut socket_addr =
SocketAddr::from_str(addr).map_err(|e| io::Error::new(ErrorKind::InvalidInput, e))?;
let start_port = socket_addr.port();
loop {
let addr_str = socket_addr.to_string();
match compio::net::TcpListener::bind(&addr_str).await {
Ok(listener) => {
if socket_addr.port() != start_port {
println!(
"Port {} was in use, starting on {} instead",
start_port,
socket_addr.port()
);
}
return Ok(listener);
}
Err(err) if err.kind() == ErrorKind::AddrInUse => {
let next_port = socket_addr.port().saturating_add(1);
if !ask_to_use_next_port(socket_addr.port(), next_port)? {
return Err(err);
}
socket_addr.set_port(next_port);
}
Err(err) => return Err(err),
}
}
}
fn ask_to_use_next_port(current: u16, next: u16) -> io::Result<bool> {
loop {
print!(
"Port {} is already in use. Start on {} instead? [Y/n]: ",
current, next
);
io::stdout().flush()?;
let mut input = String::new();
io::stdin().read_line(&mut input)?;
let trimmed = input.trim();
if trimmed.is_empty()
|| trimmed.eq_ignore_ascii_case("y")
|| trimmed.eq_ignore_ascii_case("yes")
{
return Ok(true);
}
if trimmed.eq_ignore_ascii_case("n") || trimmed.eq_ignore_ascii_case("no") {
return Ok(false);
}
println!("Please answer 'y' or 'n'.");
}
}
#[cfg(all(not(feature = "compio-tls"), feature = "tls"))]
#[cfg_attr(docsrs, doc(cfg(feature = "tls")))]
pub mod server_tls;
#[cfg(feature = "compio")]
#[cfg_attr(docsrs, doc(cfg(feature = "compio")))]
pub mod server_compio;
#[cfg(feature = "compio-tls")]
#[cfg_attr(docsrs, doc(cfg(feature = "compio")))]
pub mod server_tls_compio;
#[cfg(all(feature = "http3", not(feature = "compio")))]
#[cfg_attr(docsrs, doc(cfg(feature = "http3")))]
pub mod server_h3;
pub mod server_tcp;
pub mod server_udp;
#[cfg(all(unix, not(feature = "compio")))]
pub mod server_unix;
#[cfg(not(feature = "compio"))]
pub mod proxy_protocol;
#[cfg(feature = "grpc")]
#[cfg_attr(docsrs, doc(cfg(feature = "grpc")))]
pub mod grpc;
#[cfg(all(feature = "webtransport", not(feature = "compio")))]
#[cfg_attr(docsrs, doc(cfg(feature = "webtransport")))]
pub mod webtransport;
#[cfg(all(feature = "http3", not(feature = "compio")))]
#[cfg_attr(docsrs, doc(cfg(feature = "http3")))]
pub use server_h3::serve_h3;
#[cfg(all(feature = "http3", not(feature = "compio")))]
#[cfg_attr(docsrs, doc(cfg(feature = "http3")))]
pub use server_h3::serve_h3_with_shutdown;
#[cfg(all(not(feature = "compio"), feature = "tls"))]
#[cfg_attr(docsrs, doc(cfg(feature = "tls")))]
pub use server_tls::serve_tls;
#[cfg(all(not(feature = "compio"), feature = "tls"))]
#[cfg_attr(docsrs, doc(cfg(feature = "tls")))]
pub use server_tls::serve_tls_with_shutdown;
#[cfg(feature = "compio-tls")]
#[cfg_attr(docsrs, doc(cfg(feature = "tls")))]
pub use server_tls_compio::serve_tls;
#[cfg(feature = "compio-tls")]
#[cfg_attr(docsrs, doc(cfg(feature = "tls")))]
pub use server_tls_compio::serve_tls_with_shutdown;
#[cfg(feature = "jemalloc")]
#[cfg_attr(docsrs, doc(cfg(feature = "jemalloc")))]
#[global_allocator]
static GLOBAL: tikv_jemallocator::Jemalloc = tikv_jemallocator::Jemalloc;