1use axum::{extract::Request, response::Response};
41use color_eyre::eyre::WrapErr;
42use listenfd::ListenFd;
43use std::{convert::Infallible, error::Error, net::SocketAddr};
44use tokio::net::TcpListener;
45use tower_cookies::CookieManagerLayer;
46use tower_service::Service;
47
48pub mod cookies {
49 mod cookie_key;
50 pub use cookie_key::CookieKey;
51
52 mod cookie_jar;
53 pub use cookie_jar::CookieJar;
54
55 pub use tower_cookies::Cookie;
56
57 pub use tower_cookies::cookie::SameSite;
58}
59
60pub mod page;
61
62pub mod session;
63
64pub mod trace;
65
66pub async fn run_server<AS: Clone + Sync + Send + 'static, S, E>(
67 routes: axum::Router<AS>,
68) -> color_eyre::Result<()>
69where
70 for<'a> axum::Router<AS>: tower_service::Service<
71 axum::serve::IncomingStream<'a, tokio::net::TcpListener>,
72 Error = Infallible,
73 Response = S,
74 > + Send
75 + Clone,
76 S: Service<Request, Response = Response, Error = Infallible> + Clone + Send + 'static,
77 S::Future: Send,
78 axum::serve::Serve<tokio::net::TcpListener, axum::Router<AS>, S>:
79 IntoFuture<Output = Result<(), E>>,
80 E: Error + Send + Sync + 'static,
81{
82 let tracer = trace::Tracer;
83 let trace_layer = tower_http::trace::TraceLayer::new_for_http()
84 .make_span_with(tracer)
85 .on_response(tracer);
86
87 let app = routes.layer(trace_layer).layer(CookieManagerLayer::new());
88
89 let port = std::env::var("PORT").unwrap_or_else(|_| "3000".to_string());
90 let port: u16 = port.parse()?;
91 let addr = SocketAddr::from(([0, 0, 0, 0], port));
92
93 let listener = if let Some(fd_listener) = ListenFd::from_env().take_tcp_listener(0)? {
95 let socket_addr = fd_listener.local_addr()?;
97
98 tracing::info!("Zero-downtime reloading enabled");
99 tracing::info!(
100 "Using listener passed from systemfd on address {}",
101 socket_addr
102 );
103
104 TcpListener::from_std(fd_listener)?
106 } else {
107 tracing::info!("Starting server on port {}", port);
109 TcpListener::bind(&addr)
110 .await
111 .wrap_err("Failed to open port")?
112 };
113
114 let addr = listener.local_addr()?;
115 tracing::info!("Listening on {}", addr);
116
117 axum::serve(listener, app)
118 .await
119 .wrap_err("Failed to run server")
120}