1#![warn(missing_docs)]
2
3mod encrypt;
15mod error;
16pub mod response;
17pub mod route;
18pub mod terminal;
19pub mod tokens;
20
21use http_body_util::Full;
22use hyper::body::{Bytes, Incoming};
23use hyper::server::conn::http2;
24use hyper::service::service_fn;
25use hyper::{Request, Response, StatusCode};
26use hyper_util::rt::TokioIo;
27
28use crate::response::ResponseBuilder;
29use crate::route::{configure_all, match_route, shutdown_all, Route};
30use std::convert::Infallible;
31use std::error::Error;
32use std::net::SocketAddr;
33use std::sync::Arc;
34use std::time::Duration;
35use tokio::net::TcpListener;
36
37#[derive(Clone)]
38struct TokioExecutor;
39
40impl<F> hyper::rt::Executor<F> for TokioExecutor
41where
42 F: std::future::Future + Send + 'static,
43 F::Output: Send + 'static,
44{
45 fn execute(&self, fut: F) {
46 tokio::task::spawn(fut);
47 }
48}
49
50pub struct App {
52 port: u16,
53 shutdown_duration: Duration,
54 root_route: Arc<dyn Route + Send + Sync>,
55}
56
57impl App {
58 pub fn new(
75 port: u16,
76 shutdown_duration: Duration,
77 root_route: Arc<dyn Route + Send + Sync>,
78 ) -> Self {
79 Self {
80 port,
81 shutdown_duration,
82 root_route,
83 }
84 }
85
86 async fn configure(&self) -> Result<(), Box<dyn Error + Send + Sync>> {
87 configure_all(self.root_route.clone()).await
88 }
89
90 async fn map(&self, request: Request<Incoming>) -> Result<Response<Full<Bytes>>, Infallible> {
91 let route = match match_route(request.uri().path(), self.root_route.clone()) {
92 None => {
93 return Ok(ResponseBuilder::new()
94 .status(StatusCode::NOT_FOUND)
95 .body(Full::from(Bytes::new()))
96 .unwrap())
97 }
98 Some(route) => route,
99 };
100
101 match route.handle(request).await {
102 Ok(response) => Ok(response),
103 Err(error) => Ok(ResponseBuilder::new()
104 .status(StatusCode::INTERNAL_SERVER_ERROR)
105 .body(Full::from(error.to_string()))
106 .unwrap()),
107 }
108 }
109
110 async fn shutdown(&self) -> Result<(), Box<dyn Error + Send + Sync>> {
111 shutdown_all(self.root_route.clone()).await
112 }
113
114 pub async fn main(self: Arc<Self>) -> Result<(), Box<dyn Error + Send + Sync>> {
141 self.configure().await?;
142
143 let addr = SocketAddr::from(([127, 0, 0, 1], self.port));
144 let listener = TcpListener::bind(addr).await?;
145
146 let graceful = hyper_util::server::graceful::GracefulShutdown::new();
147 let mut signal = std::pin::pin!(async {
148 tokio::signal::ctrl_c()
149 .await
150 .expect("failed to install CTRL+C signal handler");
151 });
152
153 loop {
154 tokio::select! {
155 Ok((stream, _)) = listener.accept() => {
156 let io = TokioIo::new(stream);
157 let app = self.clone();
158
159 tokio::task::spawn(async move {
160 if let Err(err) = http2::Builder::new(TokioExecutor)
161 .serve_connection(io, service_fn(move |req| {
162 let scoped_app = app.clone();
163 async move { scoped_app.clone().map(req).await }
164 }))
165 .await {
166 log!(fail "HTTP2 error: {}", err);
167 }
168 });
169 },
170
171 _ = &mut signal => {
172 log!(info "Shutting down...");
173 self.shutdown().await?;
174 break;
175 }
176 }
177 }
178
179 tokio::select! {
180 _ = graceful.shutdown() => {
181 log!(info "All connections gracefully closed");
182 },
183 _ = tokio::time::sleep(self.shutdown_duration) => {
184 log!(info "Timed out waiting for connections");
185 }
186 }
187
188 Ok(())
189 }
190}