From 2f91c3636f2f208d71ca34f445e0e0240b8db525 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Henrique?= Date: Thu, 28 Sep 2023 20:40:45 -0300 Subject: [PATCH 1/5] add actix --- ActixAPI/Cargo.lock | 18 +++++++++++---- ActixAPI/Cargo.toml | 3 ++- ActixAPI/Dockerfile | 11 ++++++++- ActixAPI/src/main.rs | 53 ++++++++++++++++++++++++++------------------ docker-compose.yml | 2 +- 5 files changed, 59 insertions(+), 28 deletions(-) diff --git a/ActixAPI/Cargo.lock b/ActixAPI/Cargo.lock index 3d688d4..3784675 100644 --- a/ActixAPI/Cargo.lock +++ b/ActixAPI/Cargo.lock @@ -9,6 +9,7 @@ dependencies = [ "actix-files", "actix-web", "magick_rust", + "qstring", ] [[package]] @@ -299,9 +300,9 @@ checksum = "9ba43ea6f343b788c8764558649e08df62f86c6ef251fdaeb1ffd010a9ae50a2" [[package]] name = "bindgen" -version = "0.66.1" +version = "0.68.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2b84e06fc203107bfbad243f4aba2af864eb7db3b1cf46ea0a023b0b433d2a7" +checksum = "726e4313eb6ec35d2730258ad4e15b547ee75d6afaa1361a922e78e59b7d8078" dependencies = [ "bitflags 2.4.0", "cexpr", @@ -785,9 +786,9 @@ checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f" [[package]] name = "magick_rust" -version = "0.19.0" +version = "0.19.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce666df6ace809001c625ad383f4727657c7c7881df43b3b71486e8e9f07d017" +checksum = "c912b69250bcd5d024852a1a75c567d3b5d881871a55b741018741632a921bf8" dependencies = [ "bindgen", "libc", @@ -952,6 +953,15 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "qstring" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d464fae65fff2680baf48019211ce37aaec0c78e9264c84a3e484717f965104e" +dependencies = [ + "percent-encoding", +] + [[package]] name = "quote" version = "1.0.33" diff --git a/ActixAPI/Cargo.toml b/ActixAPI/Cargo.toml index 7f3cd04..776380e 100644 --- a/ActixAPI/Cargo.toml +++ b/ActixAPI/Cargo.toml @@ -8,4 +8,5 @@ edition = "2021" [dependencies] actix-web = "4" actix-files = "0.6.2" -magick_rust = "0.19.0" +magick_rust = "0.19.1" +qstring = "0.7.2" diff --git a/ActixAPI/Dockerfile b/ActixAPI/Dockerfile index dce9b80..15fc885 100644 --- a/ActixAPI/Dockerfile +++ b/ActixAPI/Dockerfile @@ -16,10 +16,19 @@ RUN cargo build --release FROM debian:bullseye-slim +ENV MAGICK_VERSION 7.1 + +RUN curl https://imagemagick.org/archive/ImageMagick.tar.gz | tar xz \ + && cd ImageMagick-${MAGICK_VERSION}* \ + && ./configure --with-magick-plus-plus=no --with-perl=no \ + && make \ + && make install \ + && cd .. \ + && rm -r ImageMagick-${MAGICK_VERSION}* + WORKDIR /app COPY --from=build-env /app/target/release . - COPY --from=build-env /app/static ./static ENTRYPOINT ["./ActixAPI"] diff --git a/ActixAPI/src/main.rs b/ActixAPI/src/main.rs index 1f93dbb..6abe78d 100644 --- a/ActixAPI/src/main.rs +++ b/ActixAPI/src/main.rs @@ -1,22 +1,13 @@ +use qstring::QString; use actix_web::{get, post, web, App, HttpResponse, HttpServer, Responder, HttpRequest, Result}; use actix_files::NamedFile; -use magick_rust::{MagickWand, ToMagick}; -use magick_rust::{self, FilterType}; +use magick_rust::MagickWand; #[get("/status/ok")] async fn hello() -> impl Responder { HttpResponse::Ok().body("{\"status\": 200}") } -#[post("/echo")] -async fn echo(req_body: String) -> impl Responder { - HttpResponse::Ok().body(req_body) -} - -async fn manual_hello() -> impl Responder { - HttpResponse::Ok().body("Hey there!") -} - async fn static_serve(req: HttpRequest) -> Result { let path: &str = req.path(); let real_path = &path[1..]; @@ -24,19 +15,39 @@ async fn static_serve(req: HttpRequest) -> Result { Ok(NamedFile::open(real_path)?) } +#[get("/image/load-small-image")] +async fn load_small_image() -> Result { + let real_path = "static/small-image.png"; + + Ok(NamedFile::open(real_path)?) +} + +#[get("/image/load-big-image")] +async fn load_big_image() -> Result { + let real_path = "static/big-image.png"; + + Ok(NamedFile::open(real_path)?) +} + #[post("/image/blur")] -async fn blur_image(image_data: web::Bytes) -> Result { +async fn blur_image(image_data: web::Bytes, req: HttpRequest) -> Result { // Load the image from the incoming bytes - let image = ToMagick::::to_magick(image_data).unwrap(); + let mut wand = MagickWand::new(); + wand.read_image_blob(&image_data).unwrap(); - // Apply a blur filter to the image - let blurred_image = image.blur(FilterType::Gaussian, 0.0).unwrap(); + let query_str = req.query_string(); + let qs = QString::from(query_str); + let radius = qs.get("radius").unwrap_or("5").parse::().unwrap_or(5.0); - // Convert the blurred image back to bytes - let blurred_image_bytes = blurred_image.to_bytes().unwrap(); + // Blur the image + wand.blur_image(radius, radius).unwrap(); + // Convert the image back to bytes + let blurred_image_bytes = wand.write_image_blob("png").unwrap(); + + // Return the blurred image bytes Ok(HttpResponse::Ok() - .content_type("image/jpeg") + .content_type("image/png") .body(blurred_image_bytes)) } @@ -48,11 +59,11 @@ async fn main() -> std::io::Result<()> { App::new() .route("/static/{filename:.*}", web::get().to(static_serve)) .service(hello) - .service(echo) + .service(load_small_image) + .service(load_big_image) .service(blur_image) - .route("/hey", web::get().to(manual_hello)) }) - .bind(("0.0.0.0", 9090))? + .bind(("0.0.0.0", 5000))? .run() .await } \ No newline at end of file diff --git a/docker-compose.yml b/docker-compose.yml index a26c77c..373409b 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -31,7 +31,7 @@ services: build: ./ActixAPI restart: always ports: - - "9083:9090" + - "9083:5000" deploy: resources: limits: From 2e3398f683e6c069e1cc8cdefe28e10f72d2d1ec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Henrique?= Date: Thu, 28 Sep 2023 21:00:55 -0300 Subject: [PATCH 2/5] average runs --- scripts/common.py | 2 ++ scripts/graph.py | 1 - scripts/testes.py | 67 ++++++++++++++++++++++++++++------------------- tcc-express | 1 + 4 files changed, 43 insertions(+), 28 deletions(-) create mode 160000 tcc-express diff --git a/scripts/common.py b/scripts/common.py index 6fcea30..0c04643 100644 --- a/scripts/common.py +++ b/scripts/common.py @@ -13,6 +13,8 @@ ENDPOINTS = { } BLUR_RADIUS = 5 +AVG_RUNS = 3 + API_REQUESTS = [ ('/status/ok', 'GET', range(0, 30_000, 5000), None), ('/image/save-big-image', 'POST', range(0, 10_000, 1_000), open('big-image.png', 'rb').read()), diff --git a/scripts/graph.py b/scripts/graph.py index 067f995..483268b 100644 --- a/scripts/graph.py +++ b/scripts/graph.py @@ -1,6 +1,5 @@ import numpy as np import matplotlib.pyplot as plt -import os from common import API_REQUESTS, FRAMEWORKS FRAMEWORKS = [f for f, _ in FRAMEWORKS] diff --git a/scripts/testes.py b/scripts/testes.py index 0bfffb7..93c7f5a 100644 --- a/scripts/testes.py +++ b/scripts/testes.py @@ -2,11 +2,10 @@ import requests import docker import concurrent.futures import time -import sys import os from math import floor from init import init -from common import FRAMEWORKS, ENDPOINTS, API_REQUESTS +from common import FRAMEWORKS, ENDPOINTS, API_REQUESTS, AVG_RUNS init() @@ -62,43 +61,57 @@ def run_tests(endpoint, method, num_requests, metadata): for num_request in num_requests: if num_request <= 0: continue - ok_responses = 0 - bad_responses = 0 - server_errors = 0 - cpu, ram = 0, 0 + total_cpu, total_ram = 0, 0 + total_time = 0 - with concurrent.futures.ThreadPoolExecutor(max_workers=THREADS) as executor: - url = f'{URL_BASE}{endpoint}' + for run in range(AVG_RUNS): + ok_responses = 0 + bad_responses = 0 + server_errors = 0 - start_time = time.time() + with concurrent.futures.ThreadPoolExecutor(max_workers=THREADS) as executor: + url = f'{URL_BASE}{endpoint}' - futures = [] - #with requests.Session() as session: - # futures = [executor.submit(send_request, session, url) for _ in range(num_request)] + start_time = time.time() - half = floor(num_request/2) - for i in range(num_request): - futures.append(executor.submit(send_request, url, method, metadata)) + futures = [] + #with requests.Session() as session: + # futures = [executor.submit(send_request, session, url) for _ in range(num_request)] - if i == half: - cpu, ram = get_resource_usage() + half = floor(num_request/2) + for i in range(num_request): + futures.append(executor.submit(send_request, url, method, metadata)) - concurrent.futures.wait(futures) + if i == half: + cpu, ram = get_resource_usage() + total_cpu += float(cpu) + total_ram += float(ram) - elapsed_time = time.time() - start_time + concurrent.futures.wait(futures) - for future in futures: - responses = future.result() - ok_responses += responses[2] - bad_responses += responses[4] - server_errors += responses[5] + elapsed_time = time.time() - start_time + total_time += elapsed_time + + for future in futures: + responses = future.result() + ok_responses += responses[2] + bad_responses += responses[4] + server_errors += responses[5] + + print(f"[#{run}] {num_request}: {elapsed_time:.2f} seconds. {elapsed_time/num_request:.4f} seconds per request. {num_request/elapsed_time:.2f} requests per second. [OK: {ok_responses}, Bad Request: {bad_responses}, Server Error: {server_errors}]]") + + client = docker.from_env() + client.containers.get(CONTAINER_NAME).restart() + + time.sleep(3) + + cpu = total_cpu / AVG_RUNS + ram = total_ram / AVG_RUNS + elapsed_time = total_time / AVG_RUNS - print(f"{num_request}: {elapsed_time:.2f} seconds. {elapsed_time/num_request:.4f} seconds per request. {num_request/elapsed_time:.2f} requests per second. [OK: {ok_responses}, Bad Request: {bad_responses}, Server Error: {server_errors}]]") record(files[0], num_request, f"{num_request/elapsed_time:.2f}") record_resource(files[1], num_request, cpu, ram) - time.sleep(3) - def get_resource_usage(): if CONTAINER_NAME == "": return 0, 0 diff --git a/tcc-express b/tcc-express new file mode 160000 index 0000000..504b592 --- /dev/null +++ b/tcc-express @@ -0,0 +1 @@ +Subproject commit 504b59278f6024219814649f2715b70561251c65 From 4fa2ae956fe440058488fb92a0a7b3328054bc0b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Henrique?= Date: Thu, 28 Sep 2023 21:03:32 -0300 Subject: [PATCH 3/5] curl --- ActixAPI/Dockerfile | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/ActixAPI/Dockerfile b/ActixAPI/Dockerfile index 15fc885..6270dff 100644 --- a/ActixAPI/Dockerfile +++ b/ActixAPI/Dockerfile @@ -18,7 +18,8 @@ FROM debian:bullseye-slim ENV MAGICK_VERSION 7.1 -RUN curl https://imagemagick.org/archive/ImageMagick.tar.gz | tar xz \ +RUN apt update && apt install curl -y \ + && curl https://imagemagick.org/archive/ImageMagick.tar.gz | tar xz \ && cd ImageMagick-${MAGICK_VERSION}* \ && ./configure --with-magick-plus-plus=no --with-perl=no \ && make \ From 4535ed5cf628eac70c74419003cd5067bda00096 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Henrique?= Date: Thu, 28 Sep 2023 22:35:06 -0300 Subject: [PATCH 4/5] fix actix docker --- ActixAPI/.dockerignore | 2 ++ ActixAPI/Dockerfile | 37 ++++++++++++++++++------------------- 2 files changed, 20 insertions(+), 19 deletions(-) create mode 100644 ActixAPI/.dockerignore diff --git a/ActixAPI/.dockerignore b/ActixAPI/.dockerignore new file mode 100644 index 0000000..8487999 --- /dev/null +++ b/ActixAPI/.dockerignore @@ -0,0 +1,2 @@ +Dockerfile +target/ \ No newline at end of file diff --git a/ActixAPI/Dockerfile b/ActixAPI/Dockerfile index 6270dff..aa2f7da 100644 --- a/ActixAPI/Dockerfile +++ b/ActixAPI/Dockerfile @@ -1,23 +1,10 @@ -FROM rust:slim-bullseye AS build-env - -WORKDIR /app - -COPY . . - -RUN apt update && apt install wget -y && \ - wget https://files.ivanch.me/api/public/dl/iFuXSNhw/small-image.png && \ - wget https://files.ivanch.me/api/public/dl/81Bkht5C/big-image.png && \ - wget https://files.ivanch.me/api/public/dl/nAndfAjK/video.mp4 && \ - mv small-image.png ./static && \ - mv big-image.png ./static && \ - mv video.mp4 ./static - -RUN cargo build --release - -FROM debian:bullseye-slim +FROM rust:latest ENV MAGICK_VERSION 7.1 +RUN apt-get update \ + && apt-get -y install wget curl build-essential clang pkg-config libjpeg-turbo-progs libpng-dev + RUN apt update && apt install curl -y \ && curl https://imagemagick.org/archive/ImageMagick.tar.gz | tar xz \ && cd ImageMagick-${MAGICK_VERSION}* \ @@ -29,7 +16,19 @@ RUN apt update && apt install curl -y \ WORKDIR /app -COPY --from=build-env /app/target/release . -COPY --from=build-env /app/static ./static +RUN wget https://files.ivanch.me/api/public/dl/iFuXSNhw/small-image.png && \ + wget https://files.ivanch.me/api/public/dl/81Bkht5C/big-image.png && \ + wget https://files.ivanch.me/api/public/dl/nAndfAjK/video.mp4 + +COPY . . + +RUN cargo build --release && \ + cp ./target/release/ActixAPI . && \ + mv small-image.png ./static && \ + mv big-image.png ./static && \ + mv video.mp4 ./static && \ + ldconfig /usr/local/lib + +ENV LD_LIBRARY_PATH=/usr/local/lib ENTRYPOINT ["./ActixAPI"] From 6d8ec28dbb8628d1ec96d3791203d42be8d32626 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Henrique?= Date: Thu, 28 Sep 2023 22:53:09 -0300 Subject: [PATCH 5/5] save image --- ActixAPI/src/main.rs | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/ActixAPI/src/main.rs b/ActixAPI/src/main.rs index 6abe78d..878169d 100644 --- a/ActixAPI/src/main.rs +++ b/ActixAPI/src/main.rs @@ -29,6 +29,17 @@ async fn load_big_image() -> Result { Ok(NamedFile::open(real_path)?) } +#[post("/image/save-big-image")] +async fn save_big_image(image_data: web::Bytes) -> Result { + // Write bytes to file + std::fs::write("image.png", &image_data).unwrap(); + + // Return the blurred image bytes + Ok(HttpResponse::Ok() + .content_type("application/json") + .body("{\"status\": 200}")) +} + #[post("/image/blur")] async fn blur_image(image_data: web::Bytes, req: HttpRequest) -> Result { // Load the image from the incoming bytes @@ -61,7 +72,9 @@ async fn main() -> std::io::Result<()> { .service(hello) .service(load_small_image) .service(load_big_image) + .service(save_big_image) .service(blur_image) + .app_data(web::PayloadConfig::new(1024 * 1024 * 1024)) }) .bind(("0.0.0.0", 5000))? .run()