Skip to main content

qvet_api/
lib.rs

1use axum::{
2    extract::Extension,
3    routing::{get, post},
4    Router,
5};
6use oauth2::basic::BasicClient;
7use std::sync::Arc;
8use tower_http::{
9    trace::{DefaultOnResponse, TraceLayer},
10    LatencyUnit,
11};
12use tracing::Level;
13
14mod error;
15mod github;
16mod oauth_handler;
17pub mod runtime;
18mod state;
19
20pub use crate::error::Error;
21use crate::error::Result;
22pub use crate::github::github_oauth2_client;
23use crate::state::State;
24
25/// Tokio signal handler that will wait for a user to press CTRL+C.
26/// We use this in our hyper `Server` method `with_graceful_shutdown`.
27async fn shutdown_signal() {
28    tokio::signal::ctrl_c()
29        .await
30        .expect("Expect shutdown signal handler");
31    tracing::info!("Received Ctrl+C");
32}
33
34pub fn api_app(oauth2_client: BasicClient) -> Router {
35    let state = Arc::new(State { oauth2_client });
36    Router::new()
37        .route("/", get(root))
38        .route("/health", get(health))
39        .route("/oauth2/initiate", post(oauth_handler::oauth2_initiate))
40        .route("/oauth2/callback", post(oauth_handler::oauth2_callback))
41        .layer(Extension(state))
42        .layer(
43            TraceLayer::new_for_http().on_response(
44                DefaultOnResponse::new()
45                    .level(Level::INFO)
46                    .latency_unit(LatencyUnit::Micros),
47            ),
48        )
49}
50
51/// Listen at the given address for a single OAuth2 code grant callback.
52pub async fn serve(address: &std::net::SocketAddr, app: Router) -> Result<()> {
53    tracing::info!("Listening on {address:?}");
54    axum::Server::bind(address)
55        .serve(app.into_make_service())
56        .with_graceful_shutdown(shutdown_signal())
57        .await
58        .map_err(Error::Listener)?;
59
60    Ok(())
61}
62
63async fn root() -> &'static str {
64    "qvet"
65}
66
67async fn health() -> &'static str {
68    "ok"
69}