Skip to main content

hugo_server/
lib.rs

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}