From 74e65a219586ca18181d54a9dd01514abe6bc3bd Mon Sep 17 00:00:00 2001 From: Aadi Desai <21363892+supleed2@users.noreply.github.com> Date: Thu, 21 Dec 2023 02:33:36 +0000 Subject: [PATCH] Scuffed Day 20 Ideally redo using `git2` later on --- Cargo.lock | 41 ++++++++++++++++++++- Cargo.toml | 3 ++ src/cal/day20.rs | 96 ++++++++++++++++++++++++++++++++++++++++++++++++ src/cal/mod.rs | 2 + 4 files changed, 140 insertions(+), 2 deletions(-) create mode 100644 src/cal/day20.rs diff --git a/Cargo.lock b/Cargo.lock index 6d4ab83..b2c05ea 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -432,6 +432,7 @@ dependencies = [ "axum 0.7.2", "axum-extra", "base64", + "bytes", "chrono", "futures", "image", @@ -444,6 +445,8 @@ dependencies = [ "shuttle-runtime", "shuttle-shared-db", "sqlx", + "tar", + "tempfile", "tokio", "tower-http 0.5.0", "tracing", @@ -796,6 +799,18 @@ dependencies = [ "simd-adler32", ] +[[package]] +name = "filetime" +version = "0.2.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ee447700ac8aa0b2f2bd7bc4462ad686ba06baa6727ac149a2d6277f0d240fd" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall", + "windows-sys 0.52.0", +] + [[package]] name = "finl_unicode" version = "1.2.0" @@ -2407,9 +2422,9 @@ checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" [[package]] name = "rustix" -version = "0.38.26" +version = "0.38.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9470c4bf8246c8daf25f9598dca807fb6510347b1e1cfa55749113850c79d88a" +checksum = "72e572a5e8ca657d7366229cdde4bd14c4eb5499a9573d4d366fe1b599daa316" dependencies = [ "bitflags 2.4.1", "errno", @@ -3168,6 +3183,17 @@ dependencies = [ "libc", ] +[[package]] +name = "tar" +version = "0.4.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b16afcea1f22891c49a00c751c7b63b2233284064f11a200fc624137c51e2ddb" +dependencies = [ + "filetime", + "libc", + "xattr", +] + [[package]] name = "tempfile" version = "3.8.1" @@ -4020,6 +4046,17 @@ dependencies = [ "windows-sys 0.48.0", ] +[[package]] +name = "xattr" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7dae5072fe1f8db8f8d29059189ac175196e410e40ba42d5d4684ae2f750995" +dependencies = [ + "libc", + "linux-raw-sys", + "rustix", +] + [[package]] name = "zerocopy" version = "0.7.30" diff --git a/Cargo.toml b/Cargo.toml index 1be3adb..518768e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -9,6 +9,7 @@ askama_axum = "0.4.0" axum = { version = "0.7.2", features = ["macros", "multipart", "ws"] } axum-extra = { version = "0.9.0", features = ["typed-header"] } base64 = "0.21.5" +bytes = "1.5.0" chrono = { version = "0.4.31", default-features = false, features = ["std"] } futures = "0.3.29" image = "0.24.7" @@ -21,6 +22,8 @@ shuttle-axum = { version = "0.35.0", default-features = false, features = ["axum shuttle-runtime = "0.35.0" shuttle-shared-db = { version = "0.35.1", features = ["postgres"] } sqlx = { version = "0.7.3", features = ["postgres", "runtime-tokio-native-tls"] } +tar = "0.4.40" +tempfile = "3.8.1" tokio = "1.34.0" tower-http = { version = "0.5.0", features = ["fs","trace"] } tracing = "0.1.40" diff --git a/src/cal/day20.rs b/src/cal/day20.rs new file mode 100644 index 0000000..d18cc66 --- /dev/null +++ b/src/cal/day20.rs @@ -0,0 +1,96 @@ +use axum::{body::Bytes, http::StatusCode, response::IntoResponse, routing::post, Router}; +use bytes::Buf; +use std::process::Command; + +pub(crate) fn router() -> Router { + Router::new() + .route("/20/archive_files", post(archive_files)) + .route("/20/archive_files_size", post(archive_files_size)) + .route("/20/cookie", post(cookie)) +} + +async fn archive_files(body: Bytes) -> Result { + Ok(tar::Archive::new(body.reader()) + .entries() + .map_err(|e| (StatusCode::BAD_REQUEST, e.to_string()))? + .count() + .to_string()) +} + +async fn archive_files_size(body: Bytes) -> Result { + Ok(tar::Archive::new(body.reader()) + .entries() + .map_err(|e| (StatusCode::BAD_REQUEST, e.to_string()))? + .filter_map(Result::ok) + .map(|entry| entry.size()) + .sum::() + .to_string()) +} + +async fn cookie(body: Bytes) -> Result { + let dir = tempfile::tempdir_in(".") + .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))?; + + let mut archive = tar::Archive::new(body.reader()); + archive + .unpack(dir.path()) + .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))?; + + let log = Command::new("git") + .args(["log", "christmas", "--format=%cn,%H"]) + .current_dir(dir.path()) + .output() + .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))?; + + if !log.status.success() { + return Err(( + StatusCode::INTERNAL_SERVER_ERROR, + "Git log failed, christmas branch may not exist".to_string(), + )); + } + + let output = String::from_utf8(log.stdout) + .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))?; + + let commits = output + .lines() + .filter_map(|l| l.split_once(',')) + .collect::>(); + + for (author, hash) in commits { + let Ok(Ok(files)) = Command::new("git") + .args(["ls-tree", "-r", hash]) + .current_dir(dir.path()) + .output() + .map(|o| String::from_utf8(o.stdout)) + else { + continue; + }; + + let Some(file) = files.lines().find(|s| s.contains("santa.txt")) else { + continue; + }; + + let Some(blob) = file.split_whitespace().nth(2) else { + continue; + }; + + let Ok(santatxt) = Command::new("git") + .args(["show", blob]) + .current_dir(dir.path()) + .output() + else { + continue; + }; + + if santatxt.status.success() { + if let Ok(s) = String::from_utf8(santatxt.stdout) { + if s.contains("COOKIE") { + return Ok(format!("{author} {hash}")); + } + } + } + } + + Err((StatusCode::BAD_REQUEST, "Commit not found".to_string())) +} diff --git a/src/cal/mod.rs b/src/cal/mod.rs index f544ec4..ba80763 100644 --- a/src/cal/mod.rs +++ b/src/cal/mod.rs @@ -11,6 +11,7 @@ mod day14; mod day15; mod day18; mod day19; +mod day20; pub(crate) fn router(pool: sqlx::PgPool) -> axum::Router { axum::Router::new() @@ -27,4 +28,5 @@ pub(crate) fn router(pool: sqlx::PgPool) -> axum::Router { .nest("/", day15::router()) .nest("/", day18::router(pool)) .nest("/", day19::router()) + .nest("/", day20::router()) }