diff options
author | Toby Vincent <tobyv@tobyvin.dev> | 2024-03-20 14:22:24 -0500 |
---|---|---|
committer | Toby Vincent <tobyv@tobyvin.dev> | 2024-03-20 19:21:29 -0500 |
commit | f977dce01be9de61a64b94aab883fb43949234b3 (patch) | |
tree | e8b3b5b59b10d43619198ff7d0f9f0e10bed0818 /src |
chore: initial commit
Diffstat (limited to 'src')
-rw-r--r-- | src/error.rs | 26 | ||||
-rw-r--r-- | src/lib.rs | 6 | ||||
-rw-r--r-- | src/main.rs | 18 | ||||
-rw-r--r-- | src/routes.rs | 69 | ||||
-rw-r--r-- | src/state.rs | 1 |
5 files changed, 120 insertions, 0 deletions
diff --git a/src/error.rs b/src/error.rs new file mode 100644 index 0000000..1f4b354 --- /dev/null +++ b/src/error.rs @@ -0,0 +1,26 @@ +use axum::{ + http::StatusCode, + response::{IntoResponse, Response}, + Json, +}; + +pub type Result<T, E = Error> = std::result::Result<T, E>; + +#[derive(thiserror::Error, Debug)] +pub enum Error { + #[error("IO error: {0}")] + IO(#[from] std::io::Error), + + #[error("Axum Error: {0:?}")] + Axum(#[from] axum::Error), +} + +impl IntoResponse for Error { + fn into_response(self) -> Response { + let body = Json(serde_json::json!({ + "error": self.to_string(), + })); + + (StatusCode::INTERNAL_SERVER_ERROR, body).into_response() + } +} diff --git a/src/lib.rs b/src/lib.rs new file mode 100644 index 0000000..d899368 --- /dev/null +++ b/src/lib.rs @@ -0,0 +1,6 @@ +pub use error::{Error, Result}; +pub use routes::serve; + +pub mod error; +pub mod routes; +pub mod state; diff --git a/src/main.rs b/src/main.rs new file mode 100644 index 0000000..7b5d3c2 --- /dev/null +++ b/src/main.rs @@ -0,0 +1,18 @@ +use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt}; + +#[tokio::main] +#[tracing::instrument] +async fn main() -> Result<(), unnamed_server::Error> { + tracing_subscriber::registry() + .with( + tracing_subscriber::EnvFilter::try_from_default_env().unwrap_or_else(|_| { + "example_tracing_aka_logging=debug,tower_http=debug,axum::rejection=trace".into() + }), + ) + .with(tracing_subscriber::fmt::layer()) + .init(); + + let socket_addr = std::net::SocketAddr::from(([127, 0, 0, 1], 30000)); + + unnamed_server::serve(socket_addr).await +} diff --git a/src/routes.rs b/src/routes.rs new file mode 100644 index 0000000..3625eff --- /dev/null +++ b/src/routes.rs @@ -0,0 +1,69 @@ +use axum::Router; +use axum_extra::routing::{RouterExt, TypedPath}; +use tokio::{ + net::{TcpListener, ToSocketAddrs}, + signal, +}; + +use crate::Error; + +#[derive(TypedPath)] +#[typed_path("/ping")] +pub struct Ping; + +/// # Test endpoint +/// +/// Returns "pong" +#[tracing::instrument(ret)] +pub async fn ping(_: Ping) -> &'static str { + "pong" +} + +#[derive(TypedPath)] +#[typed_path("/")] +pub struct Root; + +#[tracing::instrument(ret)] +pub async fn root(_: Root) -> &'static str { + "Hello, World!" +} + +pub async fn serve<A>(addr: A) -> Result<(), Error> +where + A: ToSocketAddrs, +{ + let app = Router::new().typed_get(root).typed_get(ping); + + let listener = TcpListener::bind(addr).await?; + + tracing::info!("Server listening on http://{}", listener.local_addr()?); + + axum::serve(listener, app) + .with_graceful_shutdown(shutdown_signal()) + .await + .map_err(From::from) +} + +async fn shutdown_signal() { + let ctrl_c = async { + signal::ctrl_c() + .await + .expect("failed to install Ctrl+C handler"); + }; + + #[cfg(unix)] + let terminate = async { + signal::unix::signal(signal::unix::SignalKind::terminate()) + .expect("failed to install signal handler") + .recv() + .await; + }; + + #[cfg(not(unix))] + let terminate = std::future::pending::<()>(); + + tokio::select! { + _ = ctrl_c => {}, + _ = terminate => {}, + } +} diff --git a/src/state.rs b/src/state.rs new file mode 100644 index 0000000..78a6654 --- /dev/null +++ b/src/state.rs @@ -0,0 +1 @@ +pub struct AppState; |