1#![doc(html_root_url = "https://docs.rs/gotham/0.8.0")]
8#![cfg_attr(feature = "ci", deny(warnings))]
11#![allow(
12 clippy::needless_lifetimes,
13 clippy::should_implement_trait,
14 clippy::unit_arg,
15 clippy::match_wild_err_arm,
16 clippy::new_without_default,
17 clippy::wrong_self_convention,
18 clippy::mutex_atomic,
19 clippy::borrowed_box,
20 clippy::get_unwrap
21)]
22#![warn(missing_docs, rust_2018_idioms, unreachable_pub)]
23#![deny(elided_lifetimes_in_paths, unsafe_code)]
24#![doc(test(no_crate_inject, attr(deny(warnings))))]
25
26pub mod extractor;
27pub mod handler;
28pub mod helpers;
29pub mod middleware;
30pub mod pipeline;
31pub mod prelude;
32pub mod router;
33pub mod service;
34pub mod state;
35
36#[cfg(feature = "testing")]
38pub mod test;
39
40pub mod plain;
42
43#[cfg(feature = "__tls")]
45pub mod tls;
46
47pub use anyhow;
49pub use bytes;
51pub use cookie;
53pub use http;
55pub use http_body;
57pub use http_body_util;
59pub use hyper;
61pub use hyper_util;
63pub use mime;
65pub use tower_service;
67
68#[cfg(feature = "__tls")]
70pub use tokio_rustls::rustls;
71
72use futures_util::TryFutureExt;
73use hyper_util::rt::{TokioExecutor, TokioIo};
74use std::future::Future;
75use std::io;
76use std::net::ToSocketAddrs;
77use std::sync::Arc;
78use thiserror::Error;
79use tokio::io::{AsyncRead, AsyncWrite};
80use tokio::net::{TcpListener, TcpStream};
81use tokio::runtime::{self, Runtime};
82
83use crate::handler::NewHandler;
84use crate::service::GothamService;
85
86pub use plain::*;
87#[cfg(feature = "__tls")]
88pub use tls::start as start_with_tls;
89
90#[derive(Debug, Error)]
92#[non_exhaustive]
93pub enum StartError {
94 #[error("I/O Error: {0}")]
96 IoError(#[from] io::Error),
97}
98
99fn new_runtime(threads: usize) -> Runtime {
100 runtime::Builder::new_multi_thread()
101 .worker_threads(threads)
102 .thread_name("gotham-worker")
103 .enable_all()
104 .build()
105 .unwrap()
106}
107
108async fn tcp_listener<A>(addr: A) -> io::Result<TcpListener>
109where
110 A: ToSocketAddrs + 'static,
111{
112 let addr = addr
113 .to_socket_addrs()?
114 .next()
115 .ok_or_else(|| io::Error::other("unable to resolve listener address"))?;
116 TcpListener::bind(addr).await
117}
118
119pub async fn bind_server<NH, F, Wrapped, Wrap>(
126 listener: TcpListener,
127 new_handler: NH,
128 wrap: Wrap,
129) -> !
130where
131 NH: NewHandler + 'static,
132 F: Future<Output = Result<Wrapped, ()>> + Unpin + Send + 'static,
133 Wrapped: Unpin + AsyncRead + AsyncWrite + Send + 'static,
134 Wrap: Fn(TcpStream) -> F,
135{
136 let protocol = Arc::new(hyper_util::server::conn::auto::Builder::new(
137 TokioExecutor::new(),
138 ));
139 let gotham_service = GothamService::new(new_handler);
140
141 loop {
142 let (socket, addr) = match listener.accept().await {
143 Ok(ok) => ok,
144 Err(err) => {
145 log::error!("Socket Error: {}", err);
146 continue;
147 }
148 };
149
150 let service = gotham_service.connect(addr);
151 let accepted_protocol = Arc::clone(&protocol);
152 let wrapper = wrap(socket);
153
154 let task = async move {
157 let socket = wrapper.await?;
158
159 accepted_protocol
160 .serve_connection_with_upgrades(TokioIo::new(socket), service)
161 .map_err(drop)
162 .await?;
163
164 Result::<_, ()>::Ok(())
165 };
166
167 tokio::spawn(task);
168 }
169}