From 990c10c75f86244b0c2d39994b9416298e52009e Mon Sep 17 00:00:00 2001 From: thatscringebro Date: Tue, 5 May 2026 21:21:30 -0400 Subject: [PATCH] hello world --- .gitignore | 2 + Cargo.toml | 12 ++++++ src/main.rs | 96 ++++++++++++++++++++++++++++++++++++++++++++ templates/hello.html | 2 + 4 files changed, 112 insertions(+) create mode 100644 Cargo.toml create mode 100644 src/main.rs create mode 100644 templates/hello.html diff --git a/.gitignore b/.gitignore index 0b188bc..2d3d79c 100644 --- a/.gitignore +++ b/.gitignore @@ -16,3 +16,5 @@ target/ # and can be added to the global gitignore or merged into this file. For a more nuclear # option (not recommended) you can uncomment the following to ignore the entire idea folder. #.idea/ + +Cargo.lock diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..c2318fa --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,12 @@ +[package] +name = "git-ui" +version = "0.1.0" +edition = "2024" + +[dependencies] +askama = "0.16.0" +axum = "0.8.9" +tokio = { version = "1.52.2", features = ["full"] } +tower-http = { version = "0.6.9", features = ["trace"] } +tracing = "0.1.44" +tracing-subscriber = { version = "0.3.23", features = ["env-filter"] } diff --git a/src/main.rs b/src/main.rs new file mode 100644 index 0000000..5e1f865 --- /dev/null +++ b/src/main.rs @@ -0,0 +1,96 @@ +use askama::Template; +use axum::{ + Router, + body::Bytes, + extract::{self, MatchedPath}, + http::{HeaderMap, Request, StatusCode}, + response::{Html, IntoResponse, Response}, + routing::get, +}; +use tokio::time::Duration; +use tower_http::{classify::ServerErrorsFailureClass, trace::TraceLayer}; +use tracing::{Span, info_span}; +use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt}; + +#[tokio::main] +async fn main() { + tracing_subscriber::registry() + .with( + tracing_subscriber::EnvFilter::try_from_default_env() + .unwrap_or_else(|_| format!("{}=debug", env!("CARGO_CRATE_NAME")).into()), + ) + .with(tracing_subscriber::fmt::layer()) + .init(); + let app = app(); + let listener = tokio::net::TcpListener::bind("0.0.0.0:3000").await.unwrap(); + tracing::debug!("listening on {}", listener.local_addr().unwrap()); + let _ = axum::serve(listener, app).await; +} + +fn app() -> Router { + Router::new().route("/greet/{name}", get(greet)).layer( + TraceLayer::new_for_http() + .make_span_with(|request: &Request<_>| { + let matched_path = request + .extensions() + .get::() + .map(MatchedPath::as_str); + let path = &request.uri().to_string(); + + info_span!( + "http_request", + method = ?request.method(), + matched_path, + path, + some_other_field = tracing::field::Empty, + ) + }) + .on_request(|_request: &Request<_>, _span: &Span| { + tracing::debug!("started processing request") + }) + .on_response(|_response: &Response, _latency: Duration, _span: &Span| { + tracing::debug!("finished processing request") + }) + .on_body_chunk(|_chunk: &Bytes, _latency: Duration, _span: &Span| { + tracing::debug!("sending body chunk") + }) + .on_eos( + |_trailers: Option<&HeaderMap>, _stream_duration: Duration, _span: &Span| { + tracing::debug!("stream closed") + }, + ) + .on_failure( + |_error: ServerErrorsFailureClass, _latency: Duration, _span: &Span| { + tracing::error!("something went wrong") + }, + ), + ) +} + +async fn greet(extract::Path(name): extract::Path) -> impl IntoResponse { + let template = HelloTemplate { name }; + HtmlTemplate(template) +} + +#[derive(Template)] +#[template(path = "hello.html")] +struct HelloTemplate { + name: String, +} + +struct HtmlTemplate(T); +impl IntoResponse for HtmlTemplate +where + T: Template, +{ + fn into_response(self) -> Response { + match self.0.render() { + Ok(html) => Html(html).into_response(), + Err(err) => ( + StatusCode::INTERNAL_SERVER_ERROR, + format!("Failed to render template. Error: {err}"), + ) + .into_response(), + } + } +} diff --git a/templates/hello.html b/templates/hello.html new file mode 100644 index 0000000..9696ea1 --- /dev/null +++ b/templates/hello.html @@ -0,0 +1,2 @@ + +

Hello, {{ name }}!