diff --git a/rustfmt.toml b/rustfmt.toml index fab79938..f1420ac3 100644 --- a/rustfmt.toml +++ b/rustfmt.toml @@ -1,4 +1,5 @@ edition = "2021" +group_imports = "StdExternalCrate" imports_granularity = "Crate" max_width = 120 newline_style = "Unix" diff --git a/server/src/bin/mina_ocv.rs b/server/src/bin/mina_ocv.rs index 2e83faaa..279abfb6 100644 --- a/server/src/bin/mina_ocv.rs +++ b/server/src/bin/mina_ocv.rs @@ -1,70 +1,8 @@ use anyhow::Result; -use axum::{ - debug_handler, - extract::{Path, State}, - response::{IntoResponse, Response}, - routing::get, - serve as axum_serve, Json, Router, -}; use clap::Parser; -use mina_ocv::{shutdown_signal, Ocv, OcvConfig, Wrapper}; -use std::sync::Arc; -use tokio::net::TcpListener; -use tower_http::cors::CorsLayer; - -#[derive(Clone, Parser)] -struct ServeArgs { - /// API Host. - #[clap(long, env, default_value = "0.0.0.0")] - pub host: String, - /// API Port. - #[clap(long, env, default_value = "8080")] - pub port: u16, - /// OCV Args. - #[command(flatten)] - pub config: OcvConfig, -} +use mina_ocv::ServeArgs; #[tokio::main] async fn main() -> Result<()> { - let ServeArgs { host, port, config } = ServeArgs::parse(); - tracing_subscriber::fmt::init(); - - let listener = TcpListener::bind(format!("{}:{}", host, port)).await?; - tracing::info!("Starting server at http://{}.", listener.local_addr()?); - - let ocv = config.to_ocv().await?; - let router = Router::new() - .route("/api/info", get(get_info)) - .route("/api/proposals", get(get_proposals)) - .route("/api/proposal/:id", get(get_proposal)) - .route("/api/proposal/:id/results", get(get_proposal_result)) - .layer(CorsLayer::permissive()) - .with_state(Arc::new(ocv)); - axum_serve(listener, router).with_graceful_shutdown(shutdown_signal()).await?; - Ok(()) -} - -#[debug_handler] -async fn get_info(ctx: State>) -> Response { - tracing::info!("get_info"); - Wrapper(ctx.info().await).into_response() -} - -#[debug_handler] -async fn get_proposals(ctx: State>) -> Response { - tracing::info!("get_proposals"); - Json(ctx.proposals.clone()).into_response() -} - -#[debug_handler] -async fn get_proposal(ctx: State>, Path(id): Path) -> Response { - tracing::info!("get_proposal {}", id); - Wrapper(ctx.proposal(id).await).into_response() -} - -#[debug_handler] -async fn get_proposal_result(ctx: State>, Path(id): Path) -> Response { - tracing::info!("get_proposal_result {}", id); - Wrapper(ctx.proposal_result(id).await).into_response() + ServeArgs::parse().serve().await } diff --git a/server/src/lib.rs b/server/src/lib.rs index b8187657..1eaa8b05 100644 --- a/server/src/lib.rs +++ b/server/src/lib.rs @@ -3,6 +3,7 @@ mod config; mod ledger; mod ocv; mod proposals; +mod serve; mod util; mod vote; @@ -11,5 +12,6 @@ pub use config::*; pub use ledger::*; pub use ocv::*; pub use proposals::*; +pub use serve::*; pub use util::*; pub use vote::*; diff --git a/server/src/serve.rs b/server/src/serve.rs new file mode 100644 index 00000000..6aded79a --- /dev/null +++ b/server/src/serve.rs @@ -0,0 +1,72 @@ +use std::sync::Arc; + +use anyhow::Result; +use axum::{ + Json, Router, debug_handler, + extract::{Path, State}, + response::IntoResponse, + routing::get, + serve as axum_serve, +}; +use clap::Parser; +use tokio::net::TcpListener; +use tower_http::cors::CorsLayer; + +use crate::{Ocv, OcvConfig, Wrapper, shutdown_signal}; + +#[derive(Clone, Parser)] +pub struct ServeArgs { + /// API Host. + #[clap(long, env, default_value = "0.0.0.0")] + pub host: String, + /// API Port. + #[clap(long, env, default_value = "8080")] + pub port: u16, + /// OCV Args. + #[command(flatten)] + pub config: OcvConfig, +} + +impl ServeArgs { + pub async fn serve(&self) -> Result<()> { + tracing_subscriber::fmt::init(); + + let listener = TcpListener::bind(format!("{}:{}", self.host, self.port)).await?; + tracing::info!("Starting server at http://{}.", listener.local_addr()?); + + let ocv = self.config.to_ocv().await?; + let router = Router::new() + .route("/api/info", get(get_info)) + .route("/api/proposals", get(get_proposals)) + .route("/api/proposal/:id", get(get_proposal)) + .route("/api/proposal/:id/results", get(get_proposal_result)) + .layer(CorsLayer::permissive()) + .with_state(Arc::new(ocv)); + axum_serve(listener, router).with_graceful_shutdown(shutdown_signal()).await?; + Ok(()) + } +} + +#[debug_handler] +async fn get_info(ctx: State>) -> impl IntoResponse { + tracing::info!("get_info"); + Wrapper(ctx.info().await) +} + +#[debug_handler] +async fn get_proposals(ctx: State>) -> impl IntoResponse { + tracing::info!("get_proposals"); + Json(ctx.proposals.to_owned()) +} + +#[debug_handler] +async fn get_proposal(ctx: State>, Path(id): Path) -> impl IntoResponse { + tracing::info!("get_proposal {}", id); + Wrapper(ctx.proposal(id).await) +} + +#[debug_handler] +async fn get_proposal_result(ctx: State>, Path(id): Path) -> impl IntoResponse { + tracing::info!("get_proposal_result {}", id); + Wrapper(ctx.proposal_result(id).await) +}