diff --git a/Cargo.lock b/Cargo.lock index c341cf0..323de25 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -192,6 +192,28 @@ dependencies = [ "tower-service", ] +[[package]] +name = "axum-extra" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "523ae92256049a3b02d3bb4df80152386cd97ddba0c8c5077619bdc8c4b1859b" +dependencies = [ + "axum 0.7.2", + "axum-core 0.4.1", + "bytes", + "futures-util", + "headers 0.4.0", + "http 1.0.0", + "http-body 1.0.0", + "http-body-util", + "mime", + "pin-project-lite", + "serde", + "tower", + "tower-layer", + "tower-service", +] + [[package]] name = "backtrace" version = "0.3.69" @@ -260,6 +282,8 @@ name = "cch23-8bit" version = "0.1.0" dependencies = [ "axum 0.7.2", + "axum-extra", + "base64", "serde", "serde_json", "shuttle-axum", @@ -620,13 +644,28 @@ checksum = "06683b93020a07e3dbcf5f8c0f6d40080d725bea7936fc01ad345c01b97dc270" dependencies = [ "base64", "bytes", - "headers-core", + "headers-core 0.2.0", "http 0.2.11", "httpdate", "mime", "sha1", ] +[[package]] +name = "headers" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "322106e6bd0cba2d5ead589ddb8150a13d7c4217cf80d7c4f682ca994ccc6aa9" +dependencies = [ + "base64", + "bytes", + "headers-core 0.3.0", + "http 1.0.0", + "httpdate", + "mime", + "sha1", +] + [[package]] name = "headers-core" version = "0.2.0" @@ -636,6 +675,15 @@ dependencies = [ "http 0.2.11", ] +[[package]] +name = "headers-core" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "54b4a22553d4242c49fddb9ba998a99962b5cc6f22cb5a3482bec22522403ce4" +dependencies = [ + "http 1.0.0", +] + [[package]] name = "heck" version = "0.4.1" @@ -1636,7 +1684,7 @@ dependencies = [ "chrono", "comfy-table", "crossterm 0.27.0", - "headers", + "headers 0.3.9", "http 0.2.11", "http-body 0.4.5", "hyper 0.14.27", diff --git a/Cargo.toml b/Cargo.toml index 8b668ba..ca42180 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -5,6 +5,8 @@ edition = "2021" [dependencies] axum = "0.7.2" +axum-extra = { version = "0.9.0", features = ["typed-header"] } +base64 = "0.21.5" serde = { version = "1.0.193", features = ["derive"] } serde_json = "1.0.108" shuttle-axum = { version = "0.35.0", default-features = false, features = ["axum-0-7"] } diff --git a/src/cal/day01.rs b/src/cal/day01.rs index 2af1e5b..ed8ee25 100644 --- a/src/cal/day01.rs +++ b/src/cal/day01.rs @@ -7,7 +7,7 @@ pub(crate) fn router() -> Router { async fn cube_bits(Path(ids): Path) -> Result { let res = ids .split('/') - .map(|id| id.parse::()) + .map(str::parse::) .collect::, _>>() .map_err(|_| StatusCode::BAD_REQUEST)? .into_iter() diff --git a/src/cal/day07.rs b/src/cal/day07.rs new file mode 100644 index 0000000..2b76c54 --- /dev/null +++ b/src/cal/day07.rs @@ -0,0 +1,62 @@ +use axum::{http::StatusCode, response::IntoResponse, routing::get, Json, Router}; +use axum_extra::{headers::Cookie, TypedHeader}; +use base64::{engine::general_purpose, Engine as _}; +use std::collections::HashMap; + +pub(crate) fn router() -> Router { + Router::new() + .route("/7/decode", get(decode)) + .route("/7/bake", get(bake)) +} + +async fn decode( + TypedHeader(cookie): TypedHeader, +) -> Result { + let recipe = cookie + .get("recipe") + .ok_or((StatusCode::BAD_REQUEST, "recipe cookie missing".to_string()))?; + let decoded = general_purpose::STANDARD + .decode(recipe) + .map_err(|e| (StatusCode::BAD_REQUEST, format!("{e:?}")))?; + let json = + String::from_utf8(decoded).map_err(|e| (StatusCode::BAD_REQUEST, format!("{e:?}")))?; + Ok(json) +} + +#[derive(serde::Deserialize)] +struct Bake { + recipe: HashMap, + pantry: HashMap, +} + +#[derive(serde::Serialize)] +struct Cookies { + cookies: i32, + pantry: HashMap, +} + +async fn bake( + TypedHeader(cookie): TypedHeader, +) -> Result, (StatusCode, String)> { + let recipe = cookie + .get("recipe") + .ok_or((StatusCode::BAD_REQUEST, "recipe cookie missing".to_string()))?; + let decoded = general_purpose::STANDARD + .decode(recipe) + .map_err(|e| (StatusCode::BAD_REQUEST, format!("{e:?}")))?; + let Bake { recipe, mut pantry } = serde_json::from_slice(&decoded) + .map_err(|e| (StatusCode::BAD_REQUEST, format!("{e:?}")))?; + if let Some(cookies) = recipe + .iter() + .map(|(i, a)| pantry.get(i).map(|p| p / a)) + .collect::>>() + .and_then(|v| v.into_iter().min()) + { + for (i, a) in recipe { + *pantry.get_mut(&i).unwrap() -= a * cookies; + } + Ok(Json(Cookies { cookies, pantry })) + } else { + Ok(Json(Cookies { cookies: 0, pantry })) + } +} diff --git a/src/cal/mod.rs b/src/cal/mod.rs index b302856..094f8e6 100644 --- a/src/cal/mod.rs +++ b/src/cal/mod.rs @@ -2,6 +2,7 @@ mod day00; mod day01; mod day04; mod day06; +mod day07; pub(crate) fn router() -> axum::Router { axum::Router::new() @@ -9,4 +10,5 @@ pub(crate) fn router() -> axum::Router { .nest("/", day01::router()) .nest("/", day04::router()) .nest("/", day06::router()) + .nest("/", day07::router()) }