1mod algolia;
2mod args;
3mod config;
4mod git;
5mod log;
6mod router;
7
8use std::net::SocketAddr;
9use std::time::Duration;
10
11pub use algolia::*;
12pub use args::*;
13use axum::Json;
14use axum::http::StatusCode;
15use axum::response::{IntoResponse, Response};
16use axum_server::Handle;
17pub use config::*;
18pub use git::*;
19pub use log::*;
20pub use router::*;
21use serde::Serialize;
22use tokio::signal;
23
24#[derive(Serialize)]
25struct ErrorResponse {
26 message: String,
27}
28
29pub struct ServerError(StatusCode, anyhow::Error);
30
31impl IntoResponse for ServerError {
32 fn into_response(self) -> Response {
33 tracing::error!("Something went wrong: {}({})", self.1, self.0);
34
35 if self.0 == StatusCode::INTERNAL_SERVER_ERROR {
36 self.0.into_response()
37 } else {
38 (
39 self.0,
40 Json(ErrorResponse {
41 message: self.1.to_string(),
42 }),
43 )
44 .into_response()
45 }
46 }
47}
48
49impl<E> From<E> for ServerError
50where
51 E: Into<anyhow::Error>,
52{
53 fn from(err: E) -> Self {
54 Self(StatusCode::INTERNAL_SERVER_ERROR, err.into())
55 }
56}
57
58pub async fn shutdown_signal(handle: Handle<SocketAddr>) {
59 let ctrl_c = async {
60 signal::ctrl_c()
61 .await
62 .expect("failed to install Ctrl+C handler");
63 };
64
65 #[cfg(unix)]
66 let terminate = async {
67 signal::unix::signal(signal::unix::SignalKind::terminate())
68 .expect("failed to install signal handler")
69 .recv()
70 .await;
71 };
72
73 #[cfg(not(unix))]
74 let terminate = std::future::pending::<()>();
75
76 tokio::select! {
77 _ = ctrl_c => {},
78 _ = terminate => {},
79 }
80
81 tracing::info!("Received termination signal shutting down");
82 handle.graceful_shutdown(Some(Duration::from_secs(10)));
83}