diff --git a/.gitignore b/.gitignore index 7d13d31..ac67213 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,2 @@ /target /data/ -*.tar.gz diff --git a/Cargo.lock b/Cargo.lock index 61335b6..4e88874 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -265,6 +265,25 @@ dependencies = [ "wasi 0.10.2+wasi-snapshot-preview1", ] +[[package]] +name = "h2" +version = "0.3.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37a82c6d637fc9515a4694bbf1cb2457b79d81ce52b3108bdeea58b07dd34a57" +dependencies = [ + "bytes", + "fnv", + "futures-core", + "futures-sink", + "futures-util", + "http", + "indexmap", + "slab", + "tokio", + "tokio-util", + "tracing", +] + [[package]] name = "hashbrown" version = "0.11.2" @@ -333,6 +352,7 @@ dependencies = [ "futures-channel", "futures-core", "futures-util", + "h2", "http", "http-body", "httparse", @@ -771,20 +791,6 @@ name = "serde" version = "1.0.136" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ce31e24b01e1e524df96f1c2fdd054405f8d7376249a5110886fb4b658484789" -dependencies = [ - "serde_derive", -] - -[[package]] -name = "serde_derive" -version = "1.0.136" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08597e7152fcd306f41838ed3e37be9eaeed2b61c42e2117266a554fab4662f9" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] [[package]] name = "serde_json" @@ -837,7 +843,6 @@ dependencies = [ "hyper", "metrics", "metrics-exporter-prometheus", - "serde", "serde_json", "tar", "tokio", @@ -975,6 +980,7 @@ dependencies = [ "futures-sink", "pin-project-lite", "tokio", + "tracing", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index 3e46c94..4ee7af8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -11,8 +11,8 @@ name = "site" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -axum = { version = "0.5.1" } -hyper = { version = "0.14.18" } +axum = { version = "0.5.1", features = ["http2"] } +hyper = { version = "0.14.18", features = ["full"] } tokio = { version = "1.17.0", features = ["full"] } tracing = "0.1.32" tracing-subscriber = {version = "0.3.10", features = ["env-filter"] } @@ -25,4 +25,3 @@ uuid = { version = "1.0.0-alpha.1", features = ["v4"] } serde_json = "1.0.79" metrics = "0.18.1" metrics-exporter-prometheus = "0.9.0" -serde = { version = "1.0", features = ["derive"] } diff --git a/curl b/curl deleted file mode 100755 index f6ec314..0000000 --- a/curl +++ /dev/null @@ -1,8 +0,0 @@ -#!/usr/bin/env sh - -curl \ - -XPOST \ - -T test.tar.gz \ - -H 'Authorization: Bearer test' \ - -v \ - http://localhost:3000/api/deploy?dir=docs diff --git a/src/api/deploy.rs b/src/api/deploy.rs index 47be32d..2fe8198 100644 --- a/src/api/deploy.rs +++ b/src/api/deploy.rs @@ -1,27 +1,19 @@ use std::{collections::HashSet, io::ErrorKind, path::Path}; use axum::{ - extract::{BodyStream, Extension, Query}, + extract::{BodyStream, Extension}, http::StatusCode, response::IntoResponse, }; use flate2::read::GzDecoder; use futures_util::TryStreamExt; -use serde::Deserialize; use tar::Archive; use tokio_util::io::StreamReader; -use crate::DEFAULT_STATIC_DIR_NAME; - -#[derive(Deserialize)] -pub struct StaticDirParams -{ - dir: Option, -} +use crate::STATIC_DIR_NAME; pub async fn post_deploy( Extension(data_dir): Extension, - Query(params): Query, res: BodyStream, ) -> impl IntoResponse { @@ -34,72 +26,71 @@ pub async fn post_deploy( let mut file = tokio::fs::File::create(&file_path).await.unwrap(); tokio::io::copy(&mut read, &mut file).await; - let mut static_path = Path::new(&data_dir).join(DEFAULT_STATIC_DIR_NAME); - - if params.dir.is_some() { - static_path = static_path.join(params.dir.unwrap()); - } - - // Make sure the static directory exists - tokio::fs::create_dir_all(&static_path).await; - - let fp_clone = file_path.clone(); // Extract the contents of the tarball synchronously - let res = - match tokio::task::spawn_blocking(move || process_archive(&fp_clone, &static_path)).await { - Ok(_) => StatusCode::OK, - Err(_) => StatusCode::INTERNAL_SERVER_ERROR, + match tokio::task::spawn_blocking(move || { + let file = match std::fs::File::open(file_path) { + Ok(v) => v, + Err(_) => return StatusCode::INTERNAL_SERVER_ERROR, + }; + let tar = GzDecoder::new(file); + let mut archive = Archive::new(tar); + + let mut paths = HashSet::new(); + + let entries = match archive.entries() { + Ok(e) => e, + Err(_) => return StatusCode::INTERNAL_SERVER_ERROR, }; - // Remove archive file after use - tokio::fs::remove_file(&file_path).await; + // Extract each entry into the output directory + let static_dir = Path::new(&data_dir).join(STATIC_DIR_NAME); + for entry_res in entries { + if let Ok(mut entry) = entry_res { + if let Err(_) = entry.unpack_in(&static_dir) { + return StatusCode::INTERNAL_SERVER_ERROR; + } - res -} - -fn process_archive(archive_path: &Path, static_dir: &Path) -> Result<(), ()> -{ - let file = std::fs::File::open(archive_path).map_err(|_| ())?; - let tar = GzDecoder::new(file); - let mut archive = Archive::new(tar); - - let mut paths = HashSet::new(); - - let entries = archive.entries().map_err(|_| ())?; - // Extract each entry into the output directory - for entry_res in entries { - let mut entry = entry_res.map_err(|_| ())?; - entry.unpack_in(static_dir).map_err(|_| ())?; - - if let Ok(path) = entry.path() { - paths.insert(path.into_owned()); - } - } - - // Remove any old files that weren't present in new archive - let mut items = vec![]; - - // Start by populating the vec with the initial files - let iter = static_dir.read_dir().map_err(|_| ())?; - iter.filter_map(|r| r.ok()) - .for_each(|e| items.push(e.path())); - - // As long as there are still items in the vec, we keep going - while items.len() > 0 { - let item = items.pop().unwrap(); - tracing::debug!("{:?}", item); - - if !paths.contains(item.strip_prefix(&static_dir).unwrap()) { - if item.is_dir() { - std::fs::remove_dir_all(item); + if let Ok(path) = entry.path() { + paths.insert(path.into_owned()); + } } else { - std::fs::remove_file(item); + return StatusCode::INTERNAL_SERVER_ERROR; } - } else if let Ok(iter) = item.read_dir() { - iter.filter_map(|r| r.ok()) - .for_each(|e| items.push(e.path())); } - } - Ok(()) + // Remove any old files that weren't present in new archive + let mut items = vec![]; + + // Start by populating the vec with the initial files + let iter = match static_dir.read_dir() { + Ok(v) => v, + Err(_) => return StatusCode::INTERNAL_SERVER_ERROR, + }; + iter.filter_map(|r| r.ok()) + .for_each(|e| items.push(e.path())); + + // As long as there are still items in the vec, we keep going + while items.len() > 0 { + let item = items.pop().unwrap(); + tracing::debug!("{:?}", item); + + if !paths.contains(item.strip_prefix(&static_dir).unwrap()) { + if item.is_dir() { + std::fs::remove_dir_all(item); + } else { + std::fs::remove_file(item); + } + } else if let Ok(iter) = item.read_dir() { + iter.filter_map(|r| r.ok()) + .for_each(|e| items.push(e.path())); + } + } + + StatusCode::OK + }) + .await + { + Ok(s) => s, + Err(_) => StatusCode::INTERNAL_SERVER_ERROR, + } } diff --git a/src/main.rs b/src/main.rs index cbc95b9..3e74b13 100644 --- a/src/main.rs +++ b/src/main.rs @@ -14,7 +14,7 @@ mod api; mod matrix; mod metrics; -const DEFAULT_STATIC_DIR_NAME: &str = "static"; +const STATIC_DIR_NAME: &str = "static"; #[tokio::main] async fn main() @@ -30,7 +30,7 @@ async fn main() // Get required variables from env vars let api_key = std::env::var("API_KEY").expect("No API_KEY was provided."); let data_dir = std::env::var("DATA_DIR").expect("No DATA_DIR was provided."); - let static_dir = format!("{}/{}", data_dir, DEFAULT_STATIC_DIR_NAME); + let static_dir = format!("{}/{}", data_dir, STATIC_DIR_NAME); std::fs::create_dir_all(&static_dir);