From edb1a1aa965c2ba81dae448e2140bcadcce8275f Mon Sep 17 00:00:00 2001 From: Sardorbek Pulatov Date: Sat, 20 May 2023 19:58:31 +0200 Subject: [PATCH 1/2] close #8 --- .github/workflows/rust.yml | 1 + Cargo.lock | 61 ++++++++++++++++++++++++++++++++++++++ Cargo.toml | 4 ++- src/apis/create_bucket.rs | 6 ++-- src/apis/mod.rs | 4 ++- src/apis/put_handler.rs | 42 ++++++++++++++++++++++++++ src/apis/put_object.rs | 23 ++++++++++++++ src/main.rs | 9 +++++- 8 files changed, 143 insertions(+), 7 deletions(-) create mode 100644 src/apis/put_handler.rs create mode 100644 src/apis/put_object.rs diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index e68dead..5e02894 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -32,4 +32,5 @@ jobs: sleep 10 aws --endpoint-url http://localhost:9090 s3 mb s3://sardo aws --endpoint-url http://localhost:9090 s3 ls + aws --endpoint-url http://localhost:9090 s3 cp ./Cargo.toml s3://sardo diff --git a/Cargo.lock b/Cargo.lock index c714c9d..a465d00 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -570,12 +570,65 @@ dependencies = [ "percent-encoding", ] +[[package]] +name = "futures" +version = "0.3.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23342abe12aba583913b2e62f22225ff9c950774065e4bfb61a19cd9770fec40" +dependencies = [ + "futures-channel", + "futures-core", + "futures-executor", + "futures-io", + "futures-sink", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-channel" +version = "0.3.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "955518d47e09b25bbebc7a18df10b81f0c766eaf4c4f1cccef2fca5f2a4fb5f2" +dependencies = [ + "futures-core", + "futures-sink", +] + [[package]] name = "futures-core" version = "0.3.28" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4bca583b7e26f571124fe5b7561d49cb2868d79116cfa0eefce955557c6fee8c" +[[package]] +name = "futures-executor" +version = "0.3.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ccecee823288125bd88b4d7f565c9e58e41858e47ab72e8ea2d64e93624386e0" +dependencies = [ + "futures-core", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-io" +version = "0.3.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fff74096e71ed47f8e023204cfd0aa1289cd54ae5430a9523be060cdb849964" + +[[package]] +name = "futures-macro" +version = "0.3.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89ca545a94061b6365f2c7355b4b32bd20df3ff95f02da9329b34ccc3bd6ee72" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.16", +] + [[package]] name = "futures-sink" version = "0.3.28" @@ -594,10 +647,16 @@ version = "0.3.28" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "26b01e40b772d54cf6c6d721c1d1abd0647a0106a12ecaa1c186273392a69533" dependencies = [ + "futures-channel", "futures-core", + "futures-io", + "futures-macro", + "futures-sink", "futures-task", + "memchr", "pin-project-lite", "pin-utils", + "slab", ] [[package]] @@ -1101,9 +1160,11 @@ checksum = "f91339c0467de62360649f8d3e185ca8de4224ff281f66000de5eb2a77a79041" name = "s3-chelak" version = "0.1.0" dependencies = [ + "actix-router", "actix-web", "chrono", "clap", + "futures", "quick-xml", "serde", "tracing", diff --git a/Cargo.toml b/Cargo.toml index 2d8c857..55ce074 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,7 +8,9 @@ authors = ["Sardorbek Pulatov "] [dependencies] actix-web = "4.3" -clap = { version = "4.2.7", features = ["derive"] } +actix-router = "0.5" +clap = { version = "4.2", features = ["derive"] } +futures = "0.3" tracing = "0.1" tracing-subscriber = "0.3" serde = { version = "1.0", features = ["derive"] } diff --git a/src/apis/create_bucket.rs b/src/apis/create_bucket.rs index fd9dded..47b39d1 100644 --- a/src/apis/create_bucket.rs +++ b/src/apis/create_bucket.rs @@ -1,4 +1,4 @@ -use actix_web::{error, put, web, Error, HttpRequest, HttpResponse}; +use actix_web::{error, put, web, Error, HttpResponse}; use serde::{Deserialize, Serialize}; #[derive(Deserialize, Serialize, Debug)] @@ -23,12 +23,10 @@ pub struct BucketError { pub host_id: String, } -#[put("/{bucket_name}")] pub async fn create_bucket( - bucket_name: web::Path, + bucket_name: String, data: web::Data, ) -> Result { - let bucket_name = bucket_name.into_inner(); let working_folder = &data.working_folder; let bucket_path = format!("{}/{}", working_folder, bucket_name); diff --git a/src/apis/mod.rs b/src/apis/mod.rs index 404d5cc..2385c94 100644 --- a/src/apis/mod.rs +++ b/src/apis/mod.rs @@ -1,2 +1,4 @@ -pub mod list_buckets; pub mod create_bucket; +pub mod list_buckets; +pub mod put_object; +pub mod put_handler; diff --git a/src/apis/put_handler.rs b/src/apis/put_handler.rs new file mode 100644 index 0000000..5f77b9d --- /dev/null +++ b/src/apis/put_handler.rs @@ -0,0 +1,42 @@ +use actix_router::{Path, Resource, ResourceDef, Url}; + +use crate::apis::create_bucket::create_bucket; +use crate::apis::put_object::put_object; +use actix_web::{put, web, Error, HttpRequest, HttpResponse}; + +#[put("/{tail}*")] +pub async fn handle_put( + _: web::Path, + req: HttpRequest, + data: web::Data, + mut payload: Option, +) -> Result { + let mut path = Path::new(Url::new(req.uri().clone())); + + let routes = [ + ("/{bucket}/{object_name}", "bucket and object"), + ("/{bucket}", "bucket"), + ]; + + for (pattern, description) in &routes { + if ResourceDef::new(*pattern).capture_match_info(&mut path) { + return match (path.get("bucket"), path.get("object_name")) { + (Some(bucket), Some(object_name)) if *description == "bucket and object" => { + put_object( + bucket.to_string(), + object_name.to_string(), + data, + payload.unwrap(), + ) + .await + } + (Some(bucket), None) if *description == "bucket" => { + create_bucket(bucket.to_string(), data).await + } + _ => return Ok(HttpResponse::InternalServerError().finish()), + }; + } + } + + Err(actix_web::error::ErrorNotFound("Not Found")) +} diff --git a/src/apis/put_object.rs b/src/apis/put_object.rs new file mode 100644 index 0000000..a30cc5c --- /dev/null +++ b/src/apis/put_object.rs @@ -0,0 +1,23 @@ +use actix_web::{put, web, Error, FromRequest, HttpRequest, HttpResponse}; +use futures::StreamExt; +use std::fs::File; +use std::io::Write; + +pub async fn put_object( + bucket_name: String, + object_name: String, + data: web::Data, + mut payload: web::Payload, +) -> Result { + let working_folder = &data.working_folder; + + let filepath = format!("{}/{}/{}", working_folder, bucket_name, object_name); + let mut file = File::create(&filepath)?; + + while let Some(bytes) = payload.next().await { + let data = bytes.unwrap(); + file.write_all(&data)?; + } + + Ok(HttpResponse::Ok().finish()) +} diff --git a/src/main.rs b/src/main.rs index 1651d95..e634493 100644 --- a/src/main.rs +++ b/src/main.rs @@ -2,11 +2,16 @@ use std::fs; use actix_web::{middleware, web, App, HttpRequest, HttpResponse, HttpServer, Responder}; use clap::Parser; +use tracing::error; +use tracing::log::warn; pub mod apis; pub mod utils; async fn not_found(request: HttpRequest) -> impl Responder { + error!("Headers {:?}.", request.headers()); + warn!("Cannot find {}.", request.path()); + error!("Request Body {:?}.", request); HttpResponse::NotFound().body(format!("Cannot find {}.", request.path())) } @@ -38,12 +43,14 @@ async fn main() -> std::io::Result<()> { let server = HttpServer::new(move || { App::new() .wrap(middleware::Logger::default()) - .service(apis::create_bucket::create_bucket) + .service(apis::put_handler::handle_put) + // .service(apis::create_bucket::create_bucket) .service(apis::list_buckets::list_buckets) .default_service(web::route().to(not_found)) .app_data(web::Data::new(AppState { working_folder: config.working_folder.clone(), })) + .wrap(middleware::Logger::default()) }); let server_url = format!("{}:{}", config.server_url, config.server_port); From 0aa92ab132da8527357a42fc70bc65950c8f1ad8 Mon Sep 17 00:00:00 2001 From: Sardorbek Pulatov Date: Sat, 20 May 2023 19:59:20 +0200 Subject: [PATCH 2/2] update docs --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index d5d169b..258aa88 100644 --- a/README.md +++ b/README.md @@ -127,7 +127,7 @@ $ ./s3-chelak --server-url "my_custom_url" --server-port "8080" --working-folder | PutBucketTagging | :x: | | PutBucketVersioning | :x: | | PutBucketWebsite | :x: | -| PutObject | :x: | +| PutObject | :white_check_mark: | | PutObjectAcl | :x: | | PutObjectLegalHold | :x: | | PutObjectLockConfiguration | :x: |