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
25async 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
51pub 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}