1#![doc(html_root_url = "https://docs.rs/gotham/0.7.4")]
7#![cfg_attr(feature = "ci", deny(warnings))]
10#![allow(
11 clippy::needless_lifetimes,
12 clippy::should_implement_trait,
13 clippy::unit_arg,
14 clippy::match_wild_err_arm,
15 clippy::new_without_default,
16 clippy::wrong_self_convention,
17 clippy::mutex_atomic,
18 clippy::borrowed_box,
19 clippy::get_unwrap
20)]
21#![warn(missing_docs, rust_2018_idioms, unreachable_pub)]
22#![deny(elided_lifetimes_in_paths, unsafe_code)]
23#![doc(test(no_crate_inject, attr(deny(warnings))))]
24
25pub mod extractor;
26pub mod handler;
27pub mod helpers;
28pub mod middleware;
29pub mod pipeline;
30pub mod prelude;
31pub mod router;
32pub mod service;
33pub mod state;
34
35#[cfg(feature = "testing")]
37pub mod test;
38
39pub mod plain;
41
42#[cfg(feature = "rustls")]
44pub mod tls;
45
46pub use anyhow;
48pub use cookie;
50pub use hyper;
52pub use mime;
54
55#[cfg(feature = "rustls")]
57pub use tokio_rustls::rustls;
58
59use futures_util::TryFutureExt;
60use hyper::server::conn::Http;
61use std::future::Future;
62use std::io;
63use std::net::ToSocketAddrs;
64use std::sync::Arc;
65use thiserror::Error;
66use tokio::io::{AsyncRead, AsyncWrite};
67use tokio::net::{TcpListener, TcpStream};
68use tokio::runtime::{self, Runtime};
69
70use crate::handler::NewHandler;
71use crate::service::GothamService;
72
73pub use plain::*;
74#[cfg(feature = "rustls")]
75pub use tls::start as start_with_tls;
76
77#[derive(Debug, Error)]
79#[non_exhaustive]
80pub enum StartError {
81 #[error("I/O Error: {0}")]
83 IoError(#[from] io::Error),
84}
85
86fn new_runtime(threads: usize) -> Runtime {
87 runtime::Builder::new_multi_thread()
88 .worker_threads(threads)
89 .thread_name("gotham-worker")
90 .enable_all()
91 .build()
92 .unwrap()
93}
94
95async fn tcp_listener<A>(addr: A) -> io::Result<TcpListener>
96where
97 A: ToSocketAddrs + 'static,
98{
99 let addr = addr.to_socket_addrs()?.next().ok_or_else(|| {
100 io::Error::new(io::ErrorKind::Other, "unable to resolve listener address")
101 })?;
102 TcpListener::bind(addr).await
103}
104
105pub async fn bind_server<'a, NH, F, Wrapped, Wrap>(
112 listener: TcpListener,
113 new_handler: NH,
114 wrap: Wrap,
115) -> !
116where
117 NH: NewHandler + 'static,
118 F: Future<Output = Result<Wrapped, ()>> + Unpin + Send + 'static,
119 Wrapped: Unpin + AsyncRead + AsyncWrite + Send + 'static,
120 Wrap: Fn(TcpStream) -> F,
121{
122 let protocol = Arc::new(Http::new());
123 let gotham_service = GothamService::new(new_handler);
124
125 loop {
126 let (socket, addr) = match listener.accept().await {
127 Ok(ok) => ok,
128 Err(err) => {
129 log::error!("Socket Error: {}", err);
130 continue;
131 }
132 };
133
134 let service = gotham_service.connect(addr);
135 let accepted_protocol = protocol.clone();
136 let wrapper = wrap(socket);
137
138 let task = async move {
141 let socket = wrapper.await?;
142
143 accepted_protocol
144 .serve_connection(socket, service)
145 .with_upgrades()
146 .map_err(|_| ())
147 .await?;
148
149 Result::<_, ()>::Ok(())
150 };
151
152 tokio::spawn(task);
153 }
154}