mirror of
				https://github.com/ivanch/tcc.git
				synced 2025-11-04 11:17:36 +00:00 
			
		
		
		
	Compare commits
	
		
			3 Commits
		
	
	
		
			FlaskAPI
			...
			05dad7ade5
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 05dad7ade5 | |||
| cd1e9da710 | |||
| 1dbd8c238f | 
							
								
								
									
										10
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										10
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							@@ -1,4 +1,14 @@
 | 
				
			|||||||
.vs
 | 
					.vs
 | 
				
			||||||
 | 
					__pycache__
 | 
				
			||||||
bin
 | 
					bin
 | 
				
			||||||
obj
 | 
					obj
 | 
				
			||||||
 | 
					*.vscode
 | 
				
			||||||
 | 
					__pycache__
 | 
				
			||||||
 | 
					.idea
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					*/target
 | 
				
			||||||
 | 
					
 | 
				
			||||||
*.png
 | 
					*.png
 | 
				
			||||||
 | 
					*.csv
 | 
				
			||||||
 | 
					*.jpg
 | 
				
			||||||
 | 
					*.mp4
 | 
				
			||||||
@@ -23,6 +23,7 @@ namespace TCC.Controllers
 | 
				
			|||||||
            mstream.Position = 0;
 | 
					            mstream.Position = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            var result = ImageService.BoxBlurImage(mstream, radius);
 | 
					            var result = ImageService.BoxBlurImage(mstream, radius);
 | 
				
			||||||
 | 
					            mstream.Close();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            var blurredImageStream = new MemoryStream();
 | 
					            var blurredImageStream = new MemoryStream();
 | 
				
			||||||
            result.Write(blurredImageStream);
 | 
					            result.Write(blurredImageStream);
 | 
				
			||||||
@@ -31,28 +32,16 @@ namespace TCC.Controllers
 | 
				
			|||||||
            return File(blurredImageStream, "image/png");
 | 
					            return File(blurredImageStream, "image/png");
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        [HttpGet("load-image")]
 | 
					        [HttpGet("load-small-image")]
 | 
				
			||||||
        public async Task<IActionResult> GetSimpleImage()
 | 
					        public async Task<IActionResult> GetSimpleImage()
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            var result = ImageService.GetSimpleImage();
 | 
					            return File(ImageService.GetSimpleImage(), "image/png");
 | 
				
			||||||
 | 
					 | 
				
			||||||
            var imageStream = new MemoryStream();
 | 
					 | 
				
			||||||
            result.Write(imageStream);
 | 
					 | 
				
			||||||
            imageStream.Position = 0;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            return File(imageStream, "image/png");
 | 
					 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        [HttpGet("load-big-image")]
 | 
					        [HttpGet("load-big-image")]
 | 
				
			||||||
        public async Task<IActionResult> GetBigImage()
 | 
					        public async Task<IActionResult> GetBigImage()
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            var result = ImageService.GetBigImage();
 | 
					            return File(ImageService.GetBigImage(), "image/png");
 | 
				
			||||||
 | 
					 | 
				
			||||||
            var imageStream = new MemoryStream();
 | 
					 | 
				
			||||||
            result.Write(imageStream);
 | 
					 | 
				
			||||||
            imageStream.Position = 0;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            return File(imageStream, "image/png");
 | 
					 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        [HttpPost("save-big-image")]
 | 
					        [HttpPost("save-big-image")]
 | 
				
			||||||
@@ -61,6 +50,7 @@ namespace TCC.Controllers
 | 
				
			|||||||
            MemoryStream mstream = new MemoryStream();
 | 
					            MemoryStream mstream = new MemoryStream();
 | 
				
			||||||
            await HttpContext.Request.Body.CopyToAsync(mstream);
 | 
					            await HttpContext.Request.Body.CopyToAsync(mstream);
 | 
				
			||||||
            mstream.Position = 0;
 | 
					            mstream.Position = 0;
 | 
				
			||||||
 | 
					            mstream.Close();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            return Ok();
 | 
					            return Ok();
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -2,6 +2,7 @@ FROM mcr.microsoft.com/dotnet/sdk:6.0-bullseye-slim AS build-env
 | 
				
			|||||||
WORKDIR /App
 | 
					WORKDIR /App
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# Copy everything
 | 
					# Copy everything
 | 
				
			||||||
 | 
					RUN apt update && apt install wget -y
 | 
				
			||||||
COPY * .
 | 
					COPY * .
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# Restore as distinct layers
 | 
					# Restore as distinct layers
 | 
				
			||||||
@@ -10,15 +11,21 @@ RUN dotnet restore
 | 
				
			|||||||
# Build a release
 | 
					# Build a release
 | 
				
			||||||
RUN dotnet build -c Release -o out
 | 
					RUN dotnet build -c Release -o out
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					RUN cd out && \
 | 
				
			||||||
 | 
					    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 && \
 | 
				
			||||||
 | 
					    rm -rf runtimes && \
 | 
				
			||||||
 | 
					    mkdir -p ./static && \
 | 
				
			||||||
 | 
					    mv small-image.png ./static && \
 | 
				
			||||||
 | 
					    mv big-image.png ./static && \
 | 
				
			||||||
 | 
					    mv video.mp4 ./static
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# Build runtime image
 | 
					# Build runtime image
 | 
				
			||||||
FROM mcr.microsoft.com/dotnet/aspnet:6.0-bullseye-slim
 | 
					FROM mcr.microsoft.com/dotnet/aspnet:6.0-bullseye-slim
 | 
				
			||||||
 | 
					
 | 
				
			||||||
WORKDIR /App
 | 
					WORKDIR /App
 | 
				
			||||||
 | 
					
 | 
				
			||||||
RUN wget https://files.ivanch.me/api/public/dl/QFCLgtrG/simpleimage.png && \
 | 
					 | 
				
			||||||
    wget https://files.ivanch.me/api/public/dl/E0VLgWbx/bigimage.png && \
 | 
					 | 
				
			||||||
    rm -rf runtimes
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
COPY --from=build-env /App/out .
 | 
					COPY --from=build-env /App/out .
 | 
				
			||||||
 | 
					
 | 
				
			||||||
ENTRYPOINT ["dotnet", "/App/TCC.APP.dll"]
 | 
					ENTRYPOINT ["dotnet", "/App/TCC.APP.dll"]
 | 
				
			||||||
@@ -4,13 +4,13 @@ namespace tcc_app
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
    public static class ImageHelper
 | 
					    public static class ImageHelper
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        public static MagickImage SimpleImage;
 | 
					        public static byte[] SimpleImage;
 | 
				
			||||||
        public static MagickImage BigImage;
 | 
					        public static byte[] BigImage;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        static ImageHelper()
 | 
					        static ImageHelper()
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            SimpleImage = new MagickImage("simpleimage.png");
 | 
					            SimpleImage = File.ReadAllBytes("static/small-image.png");
 | 
				
			||||||
            BigImage = new MagickImage("bigimage.png");
 | 
					            BigImage = File.ReadAllBytes("static/big-image.png");
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,4 +1,5 @@
 | 
				
			|||||||
using Microsoft.AspNetCore.Server.Kestrel.Core;
 | 
					using Microsoft.AspNetCore.Server.Kestrel.Core;
 | 
				
			||||||
 | 
					using Microsoft.Extensions.FileProviders;
 | 
				
			||||||
using TCC.Services;
 | 
					using TCC.Services;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace TCC
 | 
					namespace TCC
 | 
				
			||||||
@@ -18,9 +19,13 @@ namespace TCC
 | 
				
			|||||||
                options.Limits.MaxRequestBodySize = int.MaxValue; // if don't set default value is: 30 MB
 | 
					                options.Limits.MaxRequestBodySize = int.MaxValue; // if don't set default value is: 30 MB
 | 
				
			||||||
            });
 | 
					            });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 | 
				
			||||||
            var app = builder.Build();
 | 
					            var app = builder.Build();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            app.UseStaticFiles(new StaticFileOptions
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                FileProvider = new PhysicalFileProvider(Path.Combine(builder.Environment.ContentRootPath, "static")),
 | 
				
			||||||
 | 
					                RequestPath = "/static"
 | 
				
			||||||
 | 
					            });
 | 
				
			||||||
            app.MapControllers();
 | 
					            app.MapControllers();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            app.Run();
 | 
					            app.Run();
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -14,7 +14,7 @@
 | 
				
			|||||||
      "dotnetRunMessages": true,
 | 
					      "dotnetRunMessages": true,
 | 
				
			||||||
      "launchBrowser": false,
 | 
					      "launchBrowser": false,
 | 
				
			||||||
      "launchUrl": "weatherforecast",
 | 
					      "launchUrl": "weatherforecast",
 | 
				
			||||||
      "applicationUrl": "http://0.0.0.0:5100",
 | 
					      "applicationUrl": "http://0.0.0.0:9090",
 | 
				
			||||||
      "environmentVariables": {
 | 
					      "environmentVariables": {
 | 
				
			||||||
        "ASPNETCORE_ENVIRONMENT": "Development"
 | 
					        "ASPNETCORE_ENVIRONMENT": "Development"
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -62,14 +62,16 @@ namespace TCC.Services
 | 
				
			|||||||
            file.Close();
 | 
					            file.Close();
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        public MagickImage GetSimpleImage()
 | 
					        public byte[] GetSimpleImage()
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            return ImageHelper.SimpleImage;
 | 
					            return File.ReadAllBytes("static/small-image.png");
 | 
				
			||||||
 | 
					            //return ImageHelper.SimpleImage;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        public MagickImage GetBigImage()
 | 
					        public byte[] GetBigImage()
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            return ImageHelper.BigImage;
 | 
					            return File.ReadAllBytes("static/big-image.png");
 | 
				
			||||||
 | 
					            //return ImageHelper.BigImage;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										33
									
								
								ASP.NET/static/nginx.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										33
									
								
								ASP.NET/static/nginx.html
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,33 @@
 | 
				
			|||||||
 | 
					<!DOCTYPE html>
 | 
				
			||||||
 | 
					<html>
 | 
				
			||||||
 | 
					<head>
 | 
				
			||||||
 | 
					    <title>Welcome to nginx!</title>
 | 
				
			||||||
 | 
					    <style>
 | 
				
			||||||
 | 
					        html {
 | 
				
			||||||
 | 
					            color-scheme: light dark;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        body {
 | 
				
			||||||
 | 
					            width: 35em;
 | 
				
			||||||
 | 
					            margin: 0 auto;
 | 
				
			||||||
 | 
					            font-family: Tahoma, Verdana, Arial, sans-serif;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    </style>
 | 
				
			||||||
 | 
					</head>
 | 
				
			||||||
 | 
					<body>
 | 
				
			||||||
 | 
					    <h1>Welcome to nginx!</h1>
 | 
				
			||||||
 | 
					    <p>
 | 
				
			||||||
 | 
					        If you see this page, the nginx web server is successfully installed and
 | 
				
			||||||
 | 
					        working. Further configuration is required.
 | 
				
			||||||
 | 
					    </p>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    <p>
 | 
				
			||||||
 | 
					        For online documentation and support please refer to
 | 
				
			||||||
 | 
					        <a href="http://nginx.org/">nginx.org</a>.<br />
 | 
				
			||||||
 | 
					        Commercial support is available at
 | 
				
			||||||
 | 
					        <a href="http://nginx.com/">nginx.com</a>.
 | 
				
			||||||
 | 
					    </p>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    <p><em>Thank you for using nginx.</em></p>
 | 
				
			||||||
 | 
					</body>
 | 
				
			||||||
 | 
					</html>
 | 
				
			||||||
							
								
								
									
										1266
									
								
								ActixAPI/Cargo.lock
									
									
									
										generated
									
									
									
										Normal file
									
								
							
							
						
						
									
										1266
									
								
								ActixAPI/Cargo.lock
									
									
									
										generated
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										10
									
								
								ActixAPI/Cargo.toml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								ActixAPI/Cargo.toml
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,10 @@
 | 
				
			|||||||
 | 
					[package]
 | 
				
			||||||
 | 
					name = "ActixAPI"
 | 
				
			||||||
 | 
					version = "0.1.0"
 | 
				
			||||||
 | 
					edition = "2021"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[dependencies]
 | 
				
			||||||
 | 
					actix-web = "4"
 | 
				
			||||||
 | 
					actix-files = "0.6.2"
 | 
				
			||||||
							
								
								
									
										25
									
								
								ActixAPI/Dockerfile
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								ActixAPI/Dockerfile
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,25 @@
 | 
				
			|||||||
 | 
					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/Dj0gkp-m/small-image.png && \
 | 
				
			||||||
 | 
					    wget https://files.ivanch.me/api/public/dl/FqHEPM1Q/big-image.png && \
 | 
				
			||||||
 | 
					    wget https://files.ivanch.me/api/public/dl/nTAYqZwD/video.mp4 && \
 | 
				
			||||||
 | 
					    mv small-image.png ./static && \
 | 
				
			||||||
 | 
					    mv big-image.png ./static && \
 | 
				
			||||||
 | 
					    mv video.mp4 ./static
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					RUN cargo build --release
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					FROM debian:bullseye-slim
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					WORKDIR /app
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					COPY --from=build-env /app/target/release .
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					COPY --from=build-env /app/static .
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					ENTRYPOINT ["./ActixAPI"]
 | 
				
			||||||
							
								
								
									
										40
									
								
								ActixAPI/src/main.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										40
									
								
								ActixAPI/src/main.rs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,40 @@
 | 
				
			|||||||
 | 
					use actix_web::{get, post, web, App, HttpResponse, HttpServer, Responder, HttpRequest, Result};
 | 
				
			||||||
 | 
					use actix_files::NamedFile;
 | 
				
			||||||
 | 
					use std::path::PathBuf;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[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<NamedFile> {
 | 
				
			||||||
 | 
					    let path: &str = req.path();
 | 
				
			||||||
 | 
					    let real_path = &path[1..];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    Ok(NamedFile::open(real_path)?)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[actix_web::main]
 | 
				
			||||||
 | 
					async fn main() -> std::io::Result<()> {
 | 
				
			||||||
 | 
					    println!("Hello, world!");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    HttpServer::new(|| {
 | 
				
			||||||
 | 
					        App::new()
 | 
				
			||||||
 | 
					            .route("/static/{filename:.*}", web::get().to(static_serve))
 | 
				
			||||||
 | 
					            .service(hello)
 | 
				
			||||||
 | 
					            .service(echo)
 | 
				
			||||||
 | 
					            .route("/hey", web::get().to(manual_hello))
 | 
				
			||||||
 | 
					    })
 | 
				
			||||||
 | 
					    .bind(("0.0.0.0", 9090))?
 | 
				
			||||||
 | 
					    .run()
 | 
				
			||||||
 | 
					    .await
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										33
									
								
								ActixAPI/static/nginx.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										33
									
								
								ActixAPI/static/nginx.html
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,33 @@
 | 
				
			|||||||
 | 
					<!DOCTYPE html>
 | 
				
			||||||
 | 
					<html>
 | 
				
			||||||
 | 
					<head>
 | 
				
			||||||
 | 
					    <title>Welcome to nginx!</title>
 | 
				
			||||||
 | 
					    <style>
 | 
				
			||||||
 | 
					        html {
 | 
				
			||||||
 | 
					            color-scheme: light dark;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        body {
 | 
				
			||||||
 | 
					            width: 35em;
 | 
				
			||||||
 | 
					            margin: 0 auto;
 | 
				
			||||||
 | 
					            font-family: Tahoma, Verdana, Arial, sans-serif;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    </style>
 | 
				
			||||||
 | 
					</head>
 | 
				
			||||||
 | 
					<body>
 | 
				
			||||||
 | 
					    <h1>Welcome to nginx!</h1>
 | 
				
			||||||
 | 
					    <p>
 | 
				
			||||||
 | 
					        If you see this page, the nginx web server is successfully installed and
 | 
				
			||||||
 | 
					        working. Further configuration is required.
 | 
				
			||||||
 | 
					    </p>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    <p>
 | 
				
			||||||
 | 
					        For online documentation and support please refer to
 | 
				
			||||||
 | 
					        <a href="http://nginx.org/">nginx.org</a>.<br />
 | 
				
			||||||
 | 
					        Commercial support is available at
 | 
				
			||||||
 | 
					        <a href="http://nginx.com/">nginx.com</a>.
 | 
				
			||||||
 | 
					    </p>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    <p><em>Thank you for using nginx.</em></p>
 | 
				
			||||||
 | 
					</body>
 | 
				
			||||||
 | 
					</html>
 | 
				
			||||||
							
								
								
									
										89
									
								
								scripts/graph.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										89
									
								
								scripts/graph.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,89 @@
 | 
				
			|||||||
 | 
					import numpy as np
 | 
				
			||||||
 | 
					import matplotlib.pyplot as plt
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def plot_graph(x, y, title, x_label, y_label, filename):
 | 
				
			||||||
 | 
					    plt.plot(x, y, 'ro', markersize=1, linewidth=0.5, linestyle='solid')
 | 
				
			||||||
 | 
					    plt.title(title)
 | 
				
			||||||
 | 
					    plt.xlabel(x_label)
 | 
				
			||||||
 | 
					    plt.ylabel(y_label)
 | 
				
			||||||
 | 
					    plt.savefig(f'{filename}.png')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    plt.clf()
 | 
				
			||||||
 | 
					    plt.close('all')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def plot_resource_graph(x_data, y_data, title, x_label, y_label, filename):
 | 
				
			||||||
 | 
					    requests = x_data
 | 
				
			||||||
 | 
					    resource = {
 | 
				
			||||||
 | 
					        'CPU': [p[0] for p in y_data],
 | 
				
			||||||
 | 
					        'RAM': [p[1] for p in y_data],
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    x = np.arange(len(requests))
 | 
				
			||||||
 | 
					    width = 0.25
 | 
				
			||||||
 | 
					    multiplier = 0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fig, ax = plt.subplots(layout='constrained')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    for attribute, measurement in resource.items():
 | 
				
			||||||
 | 
					        offset = width * multiplier
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        rects = ax.bar(x + offset, measurement, width, label=attribute)
 | 
				
			||||||
 | 
					        ax.bar_label(rects, padding=3)
 | 
				
			||||||
 | 
					        multiplier += 1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    # Add some text for labels, title and custom x-axis tick labels, etc.
 | 
				
			||||||
 | 
					    ax.set_xlabel(x_label)
 | 
				
			||||||
 | 
					    ax.set_ylabel(y_label)
 | 
				
			||||||
 | 
					    ax.set_title(title)
 | 
				
			||||||
 | 
					    ax.set_xticks(x + (width/2), requests)
 | 
				
			||||||
 | 
					    ax.legend(loc='upper left', ncols=len(resource.items()))
 | 
				
			||||||
 | 
					    ax.set_ylim(0, 100)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    plt.savefig(f'{filename}.png')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    plt.clf()
 | 
				
			||||||
 | 
					    plt.close('all')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def get_data(filename):
 | 
				
			||||||
 | 
					    lines = []
 | 
				
			||||||
 | 
					    with open(filename, 'r') as f:
 | 
				
			||||||
 | 
					        lines = f.readlines()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    x = []
 | 
				
			||||||
 | 
					    y = []
 | 
				
			||||||
 | 
					    for line in lines:
 | 
				
			||||||
 | 
					        line = line.strip().split(',')
 | 
				
			||||||
 | 
					        if line:
 | 
				
			||||||
 | 
					            x.append(int(line[0]))
 | 
				
			||||||
 | 
					            y.append(float(line[1]))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return x, y
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def get_resource_data(filename):
 | 
				
			||||||
 | 
					    lines = []
 | 
				
			||||||
 | 
					    with open(filename, 'r') as f:
 | 
				
			||||||
 | 
					        lines = f.readlines()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    x = []
 | 
				
			||||||
 | 
					    y = []
 | 
				
			||||||
 | 
					    for line in lines:
 | 
				
			||||||
 | 
					        line = line.strip().split(',')
 | 
				
			||||||
 | 
					        if line:
 | 
				
			||||||
 | 
					            x.append(int(line[0])) # requests
 | 
				
			||||||
 | 
					            y.append([float(v)*100 for v in line[1:]]) # cpu, ram
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return x, y
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def generate_req_graph(filename, framework_name, endpoint_name):
 | 
				
			||||||
 | 
					    x, y = get_data(filename)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    filename = filename.split('/')[-1]
 | 
				
			||||||
 | 
					    new_filename = filename.replace('.csv', '')
 | 
				
			||||||
 | 
					    plot_graph(x, y, f'{framework_name} - {endpoint_name}', 'Número de requisições', 'Requisições por segundo', new_filename)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def generate_resource_graph(filename, framework_name, endpoint_name):
 | 
				
			||||||
 | 
					    x, y = get_resource_data(filename)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    filename = filename.split('/')[-1]
 | 
				
			||||||
 | 
					    new_filename = filename.replace('.csv', '')
 | 
				
			||||||
 | 
					    plot_resource_graph(x, y, f'{framework_name} - {endpoint_name}', 'Uso de recursos', 'Uso (%)', new_filename)
 | 
				
			||||||
							
								
								
									
										17
									
								
								scripts/init.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										17
									
								
								scripts/init.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,17 @@
 | 
				
			|||||||
 | 
					import requests
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def download_file(url):
 | 
				
			||||||
 | 
					    local_filename = url.split('/')[-1]
 | 
				
			||||||
 | 
					    with requests.get(url, stream=True) as r:
 | 
				
			||||||
 | 
					        r.raise_for_status()
 | 
				
			||||||
 | 
					        with open(local_filename, 'wb') as f:
 | 
				
			||||||
 | 
					            for chunk in r.iter_content(chunk_size=8192):
 | 
				
			||||||
 | 
					                # If you have chunk encoded response uncomment if
 | 
				
			||||||
 | 
					                # and set chunk_size parameter to None.
 | 
				
			||||||
 | 
					                #if chunk:
 | 
				
			||||||
 | 
					                f.write(chunk)
 | 
				
			||||||
 | 
					    return local_filename
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def init():
 | 
				
			||||||
 | 
					    download_file('https://files.ivanch.me/api/public/dl/Dj0gkp-m/small-image.png')
 | 
				
			||||||
 | 
					    download_file('https://files.ivanch.me/api/public/dl/FqHEPM1Q/big-image.png')
 | 
				
			||||||
@@ -1,33 +1,155 @@
 | 
				
			|||||||
import requests
 | 
					import requests
 | 
				
			||||||
 | 
					import docker
 | 
				
			||||||
import concurrent.futures
 | 
					import concurrent.futures
 | 
				
			||||||
import time
 | 
					import time
 | 
				
			||||||
 | 
					import sys
 | 
				
			||||||
 | 
					import os
 | 
				
			||||||
 | 
					from graph import generate_req_graph, generate_resource_graph
 | 
				
			||||||
 | 
					from math import floor
 | 
				
			||||||
 | 
					from init import init
 | 
				
			||||||
 | 
					
 | 
				
			||||||
URL_BASE = 'http://localhost:5100'
 | 
					if len(sys.argv) < 2 or len(sys.argv) > 3 or sys.argv[1] == '-h' or sys.argv[1] == '--help':
 | 
				
			||||||
 | 
					    print("Usage: python testes.py <framework name> [container name]")
 | 
				
			||||||
 | 
					    sys.exit(1)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
num_requests = [1000, 5000, 10_000, 50_000, 100_000, 500_000, 1_000_000]
 | 
					init()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def send_request(session, url):
 | 
					THREADS = 10
 | 
				
			||||||
    response = session.get(url)
 | 
					FRAMEWORK_NAME = sys.argv[1]
 | 
				
			||||||
    return response.status_code
 | 
					CONTAINER_NAME = sys.argv[2] if len(sys.argv) > 2 else ""
 | 
				
			||||||
 | 
					URL_BASE = 'http://localhost:9090'
 | 
				
			||||||
 | 
					BLUR_RADIUS = 5
 | 
				
			||||||
 | 
					API_REQUESTS = [
 | 
				
			||||||
 | 
					    ('/image/save-big-image', 'POST', range(0, 10_000, 1_000), open('big-image.png', 'rb').read()),
 | 
				
			||||||
 | 
					    (f'/image/blur?radius={BLUR_RADIUS}', 'POST', range(0, 1_000, 50), open('small-image.png', 'rb').read()),
 | 
				
			||||||
 | 
					    ('/status/ok', 'GET', range(0, 30_000, 5000), None),
 | 
				
			||||||
 | 
					    ('/image/load-small-image', 'GET', range(0, 30_000, 5000), None),
 | 
				
			||||||
 | 
					    ('/static/small-image.png', 'GET', range(0, 30_000, 5000), None),
 | 
				
			||||||
 | 
					    ('/image/load-big-image', 'GET', range(0, 500, 50), None),
 | 
				
			||||||
 | 
					    ('/static/big-image.png', 'GET', range(0, 500, 50), None),
 | 
				
			||||||
 | 
					    ('/static/video.mp4', 'GET', range(0, 10_000, 1_000), None),
 | 
				
			||||||
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def send_request(url, method = 'GET', payload = None):
 | 
				
			||||||
 | 
					    success = False
 | 
				
			||||||
 | 
					    responses = {
 | 
				
			||||||
 | 
					        2: 0, # OK
 | 
				
			||||||
 | 
					        4: 0, # Bad Request
 | 
				
			||||||
 | 
					        5: 0, # Server Error
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    while not success:
 | 
				
			||||||
 | 
					        try:
 | 
				
			||||||
 | 
					            response = None
 | 
				
			||||||
 | 
					            if method == 'GET':
 | 
				
			||||||
 | 
					                response = requests.get(url)
 | 
				
			||||||
 | 
					            elif method == 'POST':
 | 
				
			||||||
 | 
					                response = requests.post(url, data=payload, headers={'Content-Type': 'image/png'})
 | 
				
			||||||
 | 
					        except:
 | 
				
			||||||
 | 
					            continue
 | 
				
			||||||
 | 
					        success = response.status_code == 200
 | 
				
			||||||
 | 
					        responses[floor(response.status_code/100)] += 1
 | 
				
			||||||
 | 
					    return responses
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def getFileNames(endpoint):
 | 
				
			||||||
 | 
					    endpoint = endpoint.replace('/', '')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    files = [
 | 
				
			||||||
 | 
					        f"data/req_{FRAMEWORK_NAME}_{endpoint}.csv",
 | 
				
			||||||
 | 
					        f"data/resource_{FRAMEWORK_NAME}_{endpoint}.csv",
 | 
				
			||||||
 | 
					    ]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return files
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def record(filename, requests, reqpersec):
 | 
				
			||||||
 | 
					    with open(filename, "a") as file:
 | 
				
			||||||
 | 
					        file.write(f"{requests},{reqpersec}\n")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def record_resource(filename, requests, cpu, ram):
 | 
				
			||||||
 | 
					    with open(filename, "a") as file:
 | 
				
			||||||
 | 
					        file.write(f"{requests},{cpu},{ram}\n")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def run_tests(endpoint, method, num_requests, metadata):
 | 
				
			||||||
 | 
					    files = getFileNames(endpoint)
 | 
				
			||||||
 | 
					    for filename in files:
 | 
				
			||||||
 | 
					        if os.path.exists(filename):
 | 
				
			||||||
 | 
					            os.remove(filename)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def main():
 | 
					 | 
				
			||||||
    for num_request in num_requests:
 | 
					    for num_request in num_requests:
 | 
				
			||||||
        with concurrent.futures.ThreadPoolExecutor(max_workers=10) as executor:
 | 
					        if num_request <= 0: continue
 | 
				
			||||||
            url = f'{URL_BASE}/status/ok'
 | 
					
 | 
				
			||||||
 | 
					        ok_responses = 0
 | 
				
			||||||
 | 
					        bad_responses = 0
 | 
				
			||||||
 | 
					        server_errors = 0
 | 
				
			||||||
 | 
					        cpu, ram = 0, 0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        with concurrent.futures.ThreadPoolExecutor(max_workers=THREADS) as executor:
 | 
				
			||||||
 | 
					            url = f'{URL_BASE}{endpoint}'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            start_time = time.time()
 | 
					            start_time = time.time()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            futures = []
 | 
					            futures = []
 | 
				
			||||||
            with requests.Session() as session:
 | 
					            #with requests.Session() as session:
 | 
				
			||||||
                futures = [executor.submit(send_request, session, url) for _ in range(num_request)]
 | 
					            #    futures = [executor.submit(send_request, session, url) for _ in range(num_request)]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            half = floor(num_request/2)
 | 
				
			||||||
 | 
					            for i in range(num_request):
 | 
				
			||||||
 | 
					                futures.append(executor.submit(send_request, url, method, metadata))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                if i == half:
 | 
				
			||||||
 | 
					                    cpu, ram = get_resource_usage()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            concurrent.futures.wait(futures)
 | 
					            concurrent.futures.wait(futures)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            elapsed_time = time.time() - start_time
 | 
					            elapsed_time = time.time() - start_time
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            successful_responses = sum(1 for future in futures if future.result() == 200)
 | 
					            for future in futures:
 | 
				
			||||||
 | 
					                responses = future.result()
 | 
				
			||||||
 | 
					                ok_responses += responses[2]
 | 
				
			||||||
 | 
					                bad_responses += responses[4]
 | 
				
			||||||
 | 
					                server_errors += responses[5]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        print(f"All requests completed in {elapsed_time:.2f} seconds. {elapsed_time/num_request:.4f} seconds per request. {num_request/elapsed_time:.2f} requests per second.")
 | 
					        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}]]")
 | 
				
			||||||
        print(f"Successful responses: {successful_responses}/{num_request}")
 | 
					        record(files[0], num_request, f"{num_request/elapsed_time:.2f}")
 | 
				
			||||||
 | 
					        record_resource(files[1], num_request, cpu, ram)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
main()
 | 
					        generate_req_graph(files[0], FRAMEWORK_NAME, endpoint)
 | 
				
			||||||
 | 
					        generate_resource_graph(files[1], FRAMEWORK_NAME, endpoint)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        time.sleep(3)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def get_resource_usage():
 | 
				
			||||||
 | 
					    if CONTAINER_NAME == "": return 0, 0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    try:
 | 
				
			||||||
 | 
					        client = docker.from_env()
 | 
				
			||||||
 | 
					        stats = client.containers.get(CONTAINER_NAME).stats(stream=False)
 | 
				
			||||||
 | 
					    except:
 | 
				
			||||||
 | 
					        return 0, 0 # unable to get stats
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return get_cpu_usage(stats), get_ram_usage(stats)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def get_cpu_usage(stats):
 | 
				
			||||||
 | 
					    UsageDelta = stats['cpu_stats']['cpu_usage']['total_usage'] - stats['precpu_stats']['cpu_usage']['total_usage']
 | 
				
			||||||
 | 
					    SystemDelta = stats['cpu_stats']['system_cpu_usage'] - stats['precpu_stats']['system_cpu_usage']
 | 
				
			||||||
 | 
					    len_cpu = stats['cpu_stats']['online_cpus']
 | 
				
			||||||
 | 
					    percentage = (UsageDelta / SystemDelta) * len_cpu
 | 
				
			||||||
 | 
					    return f"{percentage:.2f}"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def get_ram_usage(stats):
 | 
				
			||||||
 | 
					    usage = stats['memory_stats']['usage']
 | 
				
			||||||
 | 
					    limit = stats['memory_stats']['limit']
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    percentage = (usage / limit)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    # percent = round(percentage, 2)
 | 
				
			||||||
 | 
					    return f"{percentage:.2f}"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					if __name__ == "__main__":
 | 
				
			||||||
 | 
					    if not os.path.exists("data"):
 | 
				
			||||||
 | 
					        os.mkdir("data")
 | 
				
			||||||
 | 
					    else:
 | 
				
			||||||
 | 
					        os.system("rm -rf data/*")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    for endpoint, method, num_requests, metadata in API_REQUESTS:
 | 
				
			||||||
 | 
					        print(f"# {endpoint}")
 | 
				
			||||||
 | 
					        run_tests(endpoint, method, num_requests, metadata)
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user