mirror of
https://github.com/ivanch/tcc.git
synced 2025-09-15 08:55:20 +00:00
Compare commits
17 Commits
test
...
ed9942d56e
Author | SHA1 | Date | |
---|---|---|---|
ed9942d56e | |||
00db2190b5 | |||
877c7a0dc3 | |||
acfd94f6ff | |||
9ef644702b | |||
95a85be35d | |||
1eb02db473 | |||
96ecf8de16 | |||
e8ae8935f2 | |||
ac8bff31f2 | |||
2965293bfb | |||
a6a8bd307b | |||
62b8b70689 | |||
77aa085b0c | |||
d5d2ab4956 | |||
2e71c4e8ed | |||
bba35341fb |
6
.gitmodules
vendored
Normal file
6
.gitmodules
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
[submodule "Spring"]
|
||||
path = Spring
|
||||
url = git@github.com:horakhy/springtcc.git
|
||||
[submodule "Express"]
|
||||
path = Express
|
||||
url = git@github.com:horakhy/tcc-express.git
|
8
.idea/.gitignore
generated
vendored
8
.idea/.gitignore
generated
vendored
@@ -1,8 +0,0 @@
|
||||
# Default ignored files
|
||||
/shelf/
|
||||
/workspace.xml
|
||||
# Editor-based HTTP Client requests
|
||||
/httpRequests/
|
||||
# Datasource local storage ignored files
|
||||
/dataSources/
|
||||
/dataSources.local.xml
|
6
.idea/inspectionProfiles/profiles_settings.xml
generated
6
.idea/inspectionProfiles/profiles_settings.xml
generated
@@ -1,6 +0,0 @@
|
||||
<component name="InspectionProjectProfileManager">
|
||||
<settings>
|
||||
<option name="USE_PROJECT_PROFILE" value="false" />
|
||||
<version value="1.0" />
|
||||
</settings>
|
||||
</component>
|
4
.idea/misc.xml
generated
4
.idea/misc.xml
generated
@@ -1,4 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ProjectRootManager" version="2" project-jdk-name="Python 3.10" project-jdk-type="Python SDK" />
|
||||
</project>
|
8
.idea/modules.xml
generated
8
.idea/modules.xml
generated
@@ -1,8 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ProjectModuleManager">
|
||||
<modules>
|
||||
<module fileurl="file://$PROJECT_DIR$/.idea/tcc.iml" filepath="$PROJECT_DIR$/.idea/tcc.iml" />
|
||||
</modules>
|
||||
</component>
|
||||
</project>
|
8
.idea/tcc.iml
generated
8
.idea/tcc.iml
generated
@@ -1,8 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module type="PYTHON_MODULE" version="4">
|
||||
<component name="NewModuleRootManager">
|
||||
<content url="file://$MODULE_DIR$" />
|
||||
<orderEntry type="inheritedJdk" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
</component>
|
||||
</module>
|
6
.idea/vcs.xml
generated
6
.idea/vcs.xml
generated
@@ -1,6 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="VcsDirectoryMappings">
|
||||
<mapping directory="" vcs="Git" />
|
||||
</component>
|
||||
</project>
|
@@ -15,23 +15,6 @@ namespace TCC.Controllers
|
||||
this.ImageService = imageService;
|
||||
}
|
||||
|
||||
[HttpPost("blur")]
|
||||
public async Task<IActionResult> BlurImage([FromQuery] int radius)
|
||||
{
|
||||
MemoryStream mstream = new MemoryStream();
|
||||
await HttpContext.Request.Body.CopyToAsync(mstream);
|
||||
mstream.Position = 0;
|
||||
|
||||
var result = ImageService.BoxBlurImage(mstream, radius);
|
||||
mstream.Close();
|
||||
|
||||
var blurredImageStream = new MemoryStream();
|
||||
result.Write(blurredImageStream);
|
||||
blurredImageStream.Position = 0;
|
||||
|
||||
return File(blurredImageStream, "image/png");
|
||||
}
|
||||
|
||||
[HttpGet("load-small-image")]
|
||||
public async Task<IActionResult> GetSimpleImage()
|
||||
{
|
||||
|
53
ASP.NET/Controllers/SimulationController.cs
Normal file
53
ASP.NET/Controllers/SimulationController.cs
Normal file
@@ -0,0 +1,53 @@
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using tcc_app.Models;
|
||||
|
||||
namespace TCC.Controllers
|
||||
{
|
||||
[ApiController]
|
||||
[Route("simulation")]
|
||||
public class SimulationController : ControllerBase
|
||||
{
|
||||
public SimulationController()
|
||||
{
|
||||
}
|
||||
|
||||
[HttpGet("harmonic-progression")]
|
||||
public async Task<IActionResult> GetHarmonicProgression([FromQuery] int n)
|
||||
{
|
||||
double sum = 0;
|
||||
for (int i = 1; i <= n; i++)
|
||||
{
|
||||
sum += 1.0f / i;
|
||||
}
|
||||
|
||||
return Ok(sum);
|
||||
}
|
||||
|
||||
[HttpPost("json")]
|
||||
public async Task<IActionResult> PostJson([FromBody] PersonJson person)
|
||||
{
|
||||
return Ok(person);
|
||||
}
|
||||
|
||||
[HttpPost("protobuf")]
|
||||
public async Task<IActionResult> PostProtobuf()
|
||||
{
|
||||
PersonProto person;
|
||||
byte[] response;
|
||||
using (var stream = Request.BodyReader.AsStream())
|
||||
{
|
||||
person = ProtoBuf.Serializer.Deserialize<PersonProto>(stream);
|
||||
}
|
||||
|
||||
using (var stream = new MemoryStream())
|
||||
{
|
||||
ProtoBuf.Serializer.Serialize(stream, person);
|
||||
response = stream.ToArray();
|
||||
}
|
||||
|
||||
await Response.Body.WriteAsync(response, 0, response.Length);
|
||||
return new EmptyResult();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@@ -11,7 +11,7 @@ namespace TCC.Controllers
|
||||
[HttpGet("ok")]
|
||||
public async Task<IActionResult> ReturnOk()
|
||||
{
|
||||
return Ok(new { status = 200 });
|
||||
return Ok();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -12,14 +12,16 @@ RUN dotnet restore
|
||||
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 && \
|
||||
wget https://files.ivanch.me/api/public/dl/ch3NV0P8/small-image.png && \
|
||||
wget https://files.ivanch.me/api/public/dl/jNlXYMLR/big-image.png && \
|
||||
wget https://files.ivanch.me/api/public/dl/QdKvaeQI/video.mp4 && \
|
||||
wget https://files.ivanch.me/api/public/dl/YD4vmSsO/nginx.html && \
|
||||
rm -rf runtimes && \
|
||||
mkdir -p ./static && \
|
||||
mv small-image.png ./static && \
|
||||
mv big-image.png ./static && \
|
||||
mv video.mp4 ./static
|
||||
mv video.mp4 ./static && \
|
||||
mv nginx.html ./static
|
||||
|
||||
# Build runtime image
|
||||
FROM mcr.microsoft.com/dotnet/aspnet:6.0-bullseye-slim
|
||||
|
12
ASP.NET/Models/PersonJson.cs
Normal file
12
ASP.NET/Models/PersonJson.cs
Normal file
@@ -0,0 +1,12 @@
|
||||
namespace tcc_app.Models
|
||||
{
|
||||
public class PersonJson
|
||||
{
|
||||
public string Name { get; set; }
|
||||
public int Age { get; set; }
|
||||
public List<string> Friends { get; set; }
|
||||
public string Email { get; set; }
|
||||
public string Phone { get; set; }
|
||||
}
|
||||
|
||||
}
|
24
ASP.NET/Models/PersonProto.cs
Normal file
24
ASP.NET/Models/PersonProto.cs
Normal file
@@ -0,0 +1,24 @@
|
||||
using ProtoBuf;
|
||||
|
||||
namespace tcc_app.Models
|
||||
{
|
||||
[ProtoContract()]
|
||||
public class PersonProto
|
||||
{
|
||||
[ProtoMember(1)]
|
||||
public string Name { get; set; }
|
||||
|
||||
[ProtoMember(2)]
|
||||
public int Age { get; set; }
|
||||
|
||||
[ProtoMember(3)]
|
||||
public List<string> Friends { get; set; }
|
||||
|
||||
[ProtoMember(4)]
|
||||
public string Email { get; set; }
|
||||
|
||||
[ProtoMember(5)]
|
||||
public string Phone { get; set; }
|
||||
}
|
||||
|
||||
}
|
@@ -1,59 +1,9 @@
|
||||
using ImageMagick;
|
||||
|
||||
namespace TCC.Services
|
||||
namespace TCC.Services
|
||||
{
|
||||
public class ImageService
|
||||
{
|
||||
public ImageService() { }
|
||||
|
||||
public MagickImage BoxBlurImage(Stream imageStream, int radius)
|
||||
{
|
||||
var image = new MagickImage(imageStream);
|
||||
var blurredImage = new MagickImage(image);
|
||||
|
||||
blurredImage = BoxBlurImageSeparable(image, blurredImage, radius, 0);
|
||||
blurredImage = BoxBlurImageSeparable(blurredImage, blurredImage, 0, radius);
|
||||
return blurredImage;
|
||||
}
|
||||
|
||||
private MagickImage BoxBlurImageSeparable(MagickImage image, MagickImage blurredImage, int radiusX, int radiusY)
|
||||
{
|
||||
var pixels = image.GetPixels();
|
||||
var blurredPixels = blurredImage.GetPixelsUnsafe();
|
||||
|
||||
foreach (var pixel in pixels)
|
||||
{
|
||||
int x = pixel.X,
|
||||
y = pixel.Y;
|
||||
|
||||
long rTotal = 0, gTotal = 0, bTotal = 0;
|
||||
int pixelCount = 0;
|
||||
for (int offsetY = -radiusY; offsetY <= radiusY; offsetY++)
|
||||
{
|
||||
for (int offsetX = -radiusX; offsetX <= radiusX; offsetX++)
|
||||
{
|
||||
int newX = x + offsetX;
|
||||
int newY = y + offsetY;
|
||||
|
||||
if (newX >= 0 && newX < image.Width && newY >= 0 && newY < image.Height)
|
||||
{
|
||||
var pixelColor = pixels[newX, newY];
|
||||
rTotal += pixelColor.GetChannel(0);
|
||||
gTotal += pixelColor.GetChannel(1);
|
||||
bTotal += pixelColor.GetChannel(2);
|
||||
pixelCount++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
blurredPixels[x, y].SetChannel(0, Convert.ToUInt16(rTotal / pixelCount));
|
||||
blurredPixels[x, y].SetChannel(1, Convert.ToUInt16(gTotal / pixelCount));
|
||||
blurredPixels[x, y].SetChannel(2, Convert.ToUInt16(bTotal / pixelCount));
|
||||
}
|
||||
|
||||
return blurredImage;
|
||||
}
|
||||
|
||||
public void SaveImage(Stream fileStream)
|
||||
{
|
||||
var file = File.Create("image.png");
|
||||
|
@@ -11,8 +11,7 @@
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Magick.NET-Q16-AnyCPU" Version="13.2.0" />
|
||||
<PackageReference Include="Magick.NET.Core" Version="13.2.0" />
|
||||
<PackageReference Include="protobuf-net" Version="3.2.26" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
2
ActixAPI/.dockerignore
Normal file
2
ActixAPI/.dockerignore
Normal file
@@ -0,0 +1,2 @@
|
||||
Dockerfile
|
||||
target/
|
370
ActixAPI/Cargo.lock
generated
370
ActixAPI/Cargo.lock
generated
@@ -7,7 +7,13 @@ name = "ActixAPI"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"actix-files",
|
||||
"actix-protobuf",
|
||||
"actix-web",
|
||||
"futures",
|
||||
"prost",
|
||||
"qstring",
|
||||
"serde",
|
||||
"serde_json",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -62,7 +68,7 @@ dependencies = [
|
||||
"actix-utils",
|
||||
"ahash",
|
||||
"base64",
|
||||
"bitflags 2.4.0",
|
||||
"bitflags 2.4.1",
|
||||
"brotli",
|
||||
"bytes",
|
||||
"bytestring",
|
||||
@@ -96,7 +102,19 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e01ed3140b2f8d422c68afa1ed2e85d996ea619c988ac834d255db32138655cb"
|
||||
dependencies = [
|
||||
"quote",
|
||||
"syn 2.0.32",
|
||||
"syn 2.0.38",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "actix-protobuf"
|
||||
version = "0.10.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a14dd296f850b814ca6f21d9a8ab92232887c07be2082562b5f3e33286f5b24d"
|
||||
dependencies = [
|
||||
"actix-web",
|
||||
"derive_more",
|
||||
"futures-util",
|
||||
"prost",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -209,7 +227,7 @@ dependencies = [
|
||||
"actix-router",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.32",
|
||||
"syn 2.0.38",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -229,21 +247,22 @@ checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe"
|
||||
|
||||
[[package]]
|
||||
name = "ahash"
|
||||
version = "0.8.3"
|
||||
version = "0.8.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2c99f64d1e06488f620f932677e24bc6e2897582980441ae90a671415bd7ec2f"
|
||||
checksum = "91429305e9f0a25f6205c5b8e0d2db09e0708a7a6df0f42212bb56c32c8ac97a"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"getrandom",
|
||||
"once_cell",
|
||||
"version_check",
|
||||
"zerocopy",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "aho-corasick"
|
||||
version = "1.0.5"
|
||||
version = "1.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0c378d78423fdad8089616f827526ee33c19f2fddbd5de1629152c9593ba4783"
|
||||
checksum = "b2969dcb958b36655471fc61f7e416fa76033bdd4bfed0678d8fee1e2d07a1f0"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
]
|
||||
@@ -263,6 +282,12 @@ dependencies = [
|
||||
"alloc-no-stdlib",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "anyhow"
|
||||
version = "1.0.75"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a4668cab20f66d8d020e1fbc0ebe47217433c1b6c8f2040faf858554e394ace6"
|
||||
|
||||
[[package]]
|
||||
name = "askama_escape"
|
||||
version = "0.10.3"
|
||||
@@ -292,9 +317,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "base64"
|
||||
version = "0.21.4"
|
||||
version = "0.21.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9ba43ea6f343b788c8764558649e08df62f86c6ef251fdaeb1ffd010a9ae50a2"
|
||||
checksum = "35636a1494ede3b646cc98f74f8e62c773a38a659ebc777a2cf26b9b74171df9"
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
@@ -304,9 +329,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "2.4.0"
|
||||
version = "2.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b4682ae6287fcf752ecaabbfcc7b6f9b72aa33933dc23a554d853aea8eea8635"
|
||||
checksum = "327762f6e5a765692301e5bb513e0d9fef63be86bbc14528052b1cd3e6f03e07"
|
||||
|
||||
[[package]]
|
||||
name = "block-buffer"
|
||||
@@ -319,9 +344,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "brotli"
|
||||
version = "3.3.4"
|
||||
version = "3.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a1a0b1dbcc8ae29329621f8d4f0d835787c1c38bb1401979b49d13b0b305ff68"
|
||||
checksum = "516074a47ef4bce09577a3b379392300159ce5b1ba2e501ff1c819950066100f"
|
||||
dependencies = [
|
||||
"alloc-no-stdlib",
|
||||
"alloc-stdlib",
|
||||
@@ -330,9 +355,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "brotli-decompressor"
|
||||
version = "2.3.4"
|
||||
version = "2.5.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4b6561fd3f895a11e8f72af2cb7d22e08366bebc2b6b57f7744c4bda27034744"
|
||||
checksum = "4e2e4afe60d7dd600fdd3de8d0f08c2b7ec039712e3b6137ff98b7004e82de4f"
|
||||
dependencies = [
|
||||
"alloc-no-stdlib",
|
||||
"alloc-stdlib",
|
||||
@@ -346,9 +371,9 @@ checksum = "a2bd12c1caf447e69cd4528f47f94d203fd2582878ecb9e9465484c4148a8223"
|
||||
|
||||
[[package]]
|
||||
name = "bytestring"
|
||||
version = "1.3.0"
|
||||
version = "1.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "238e4886760d98c4f899360c834fa93e62cf7f721ac3c2da375cbdf4b8679aae"
|
||||
checksum = "74d80203ea6b29df88012294f62733de21cfeab47f17b41af3a38bc30a03ee72"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
]
|
||||
@@ -388,9 +413,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "cpufeatures"
|
||||
version = "0.2.9"
|
||||
version = "0.2.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a17b76ff3a4162b0b27f354a0c87015ddad39d35f9c0c36607a3bdd175dde1f1"
|
||||
checksum = "ce420fe07aecd3e67c5f910618fe65e94158f6dcc0adf44e00d69ce2bdfe0fd0"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
@@ -416,9 +441,12 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "deranged"
|
||||
version = "0.3.8"
|
||||
version = "0.3.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f2696e8a945f658fd14dc3b87242e6b80cd0f36ff04ea560fa39082368847946"
|
||||
checksum = "0f32d04922c60427da6f9fef14d042d9edddef64cb9d4ce0d64d0685fbeb1fd3"
|
||||
dependencies = [
|
||||
"powerfmt",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "derive_more"
|
||||
@@ -443,6 +471,12 @@ dependencies = [
|
||||
"crypto-common",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "either"
|
||||
version = "1.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a26ae43d7bcc3b814de94796a5e736d4029efb0ee900c12e2d54c993ad1a1e07"
|
||||
|
||||
[[package]]
|
||||
name = "encoding_rs"
|
||||
version = "0.8.33"
|
||||
@@ -454,9 +488,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "flate2"
|
||||
version = "1.0.27"
|
||||
version = "1.0.28"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c6c98ee8095e9d1dcbf2fcc6d95acccb90d1c81db1e44725c6a984b1dbdfb010"
|
||||
checksum = "46303f565772937ffe1d394a4fac6f411c6013172fadde9dcdb1e147a086940e"
|
||||
dependencies = [
|
||||
"crc32fast",
|
||||
"miniz_oxide",
|
||||
@@ -477,34 +511,93 @@ dependencies = [
|
||||
"percent-encoding",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "futures"
|
||||
version = "0.3.29"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "da0290714b38af9b4a7b094b8a37086d1b4e61f2df9122c3cad2577669145335"
|
||||
dependencies = [
|
||||
"futures-channel",
|
||||
"futures-core",
|
||||
"futures-executor",
|
||||
"futures-io",
|
||||
"futures-sink",
|
||||
"futures-task",
|
||||
"futures-util",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "futures-channel"
|
||||
version = "0.3.29"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ff4dd66668b557604244583e3e1e1eada8c5c2e96a6d0d6653ede395b78bbacb"
|
||||
dependencies = [
|
||||
"futures-core",
|
||||
"futures-sink",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "futures-core"
|
||||
version = "0.3.28"
|
||||
version = "0.3.29"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4bca583b7e26f571124fe5b7561d49cb2868d79116cfa0eefce955557c6fee8c"
|
||||
checksum = "eb1d22c66e66d9d72e1758f0bd7d4fd0bee04cad842ee34587d68c07e45d088c"
|
||||
|
||||
[[package]]
|
||||
name = "futures-sink"
|
||||
version = "0.3.28"
|
||||
name = "futures-executor"
|
||||
version = "0.3.29"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f43be4fe21a13b9781a69afa4985b0f6ee0e1afab2c6f454a8cf30e2b2237b6e"
|
||||
|
||||
[[package]]
|
||||
name = "futures-task"
|
||||
version = "0.3.28"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "76d3d132be6c0e6aa1534069c705a74a5997a356c0dc2f86a47765e5617c5b65"
|
||||
|
||||
[[package]]
|
||||
name = "futures-util"
|
||||
version = "0.3.28"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "26b01e40b772d54cf6c6d721c1d1abd0647a0106a12ecaa1c186273392a69533"
|
||||
checksum = "0f4fb8693db0cf099eadcca0efe2a5a22e4550f98ed16aba6c48700da29597bc"
|
||||
dependencies = [
|
||||
"futures-core",
|
||||
"futures-task",
|
||||
"futures-util",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "futures-io"
|
||||
version = "0.3.29"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8bf34a163b5c4c52d0478a4d757da8fb65cabef42ba90515efee0f6f9fa45aaa"
|
||||
|
||||
[[package]]
|
||||
name = "futures-macro"
|
||||
version = "0.3.29"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "53b153fd91e4b0147f4aced87be237c98248656bb01050b96bf3ee89220a8ddb"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.38",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "futures-sink"
|
||||
version = "0.3.29"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e36d3378ee38c2a36ad710c5d30c2911d752cb941c00c72dbabfb786a7970817"
|
||||
|
||||
[[package]]
|
||||
name = "futures-task"
|
||||
version = "0.3.29"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "efd193069b0ddadc69c46389b740bbccdd97203899b48d09c5f7969591d6bae2"
|
||||
|
||||
[[package]]
|
||||
name = "futures-util"
|
||||
version = "0.3.29"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a19526d624e703a3179b3d322efec918b6246ea0fa51d41124525f00f1cc8104"
|
||||
dependencies = [
|
||||
"futures-channel",
|
||||
"futures-core",
|
||||
"futures-io",
|
||||
"futures-macro",
|
||||
"futures-sink",
|
||||
"futures-task",
|
||||
"memchr",
|
||||
"pin-project-lite",
|
||||
"pin-utils",
|
||||
"slab",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -608,6 +701,15 @@ dependencies = [
|
||||
"hashbrown",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "itertools"
|
||||
version = "0.11.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b1c173a5686ce8bfa551b3563d0c2170bf24ca44da99c7ca4bfdab5418c3fe57"
|
||||
dependencies = [
|
||||
"either",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "itoa"
|
||||
version = "1.0.9"
|
||||
@@ -616,9 +718,9 @@ checksum = "af150ab688ff2122fcef229be89cb50dd66af9e01a4ff320cc137eecc9bacc38"
|
||||
|
||||
[[package]]
|
||||
name = "jobserver"
|
||||
version = "0.1.26"
|
||||
version = "0.1.27"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "936cfd212a0155903bcbc060e316fb6cc7cbf2e1907329391ebadc1fe0ce77c2"
|
||||
checksum = "8c37f63953c4c63420ed5fd3d6d398c719489b9f872b9fa683262f8edd363c7d"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
@@ -631,33 +733,32 @@ checksum = "d4345964bb142484797b161f473a503a434de77149dd8c7427788c6e13379388"
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.147"
|
||||
version = "0.2.149"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b4668fb0ea861c1df094127ac5f1da3409a82116a4ba74fca2e58ef927159bb3"
|
||||
checksum = "a08173bc88b7955d1b3145aa561539096c421ac8debde8cbc3612ec635fee29b"
|
||||
|
||||
[[package]]
|
||||
name = "local-channel"
|
||||
version = "0.1.3"
|
||||
version = "0.1.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7f303ec0e94c6c54447f84f3b0ef7af769858a9c4ef56ef2a986d3dcd4c3fc9c"
|
||||
checksum = "b6cbc85e69b8df4b8bb8b89ec634e7189099cea8927a276b7384ce5488e53ec8"
|
||||
dependencies = [
|
||||
"futures-core",
|
||||
"futures-sink",
|
||||
"futures-util",
|
||||
"local-waker",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "local-waker"
|
||||
version = "0.1.3"
|
||||
version = "0.1.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e34f76eb3611940e0e7d53a9aaa4e6a3151f69541a282fd0dad5571420c53ff1"
|
||||
checksum = "4d873d7c67ce09b42110d801813efbc9364414e356be9935700d368351657487"
|
||||
|
||||
[[package]]
|
||||
name = "lock_api"
|
||||
version = "0.4.10"
|
||||
version = "0.4.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c1cc9717a20b1bb222f333e6a92fd32f7d8a18ddc5a3191a11af45dcbf4dcd16"
|
||||
checksum = "3c168f8615b12bc01f9c17e2eb0cc07dcae1940121185446edc3744920e8ef45"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
"scopeguard",
|
||||
@@ -671,9 +772,9 @@ checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f"
|
||||
|
||||
[[package]]
|
||||
name = "memchr"
|
||||
version = "2.6.3"
|
||||
version = "2.6.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8f232d6ef707e1956a43342693d2a31e72989554d58299d7a88738cc95b0d35c"
|
||||
checksum = "f665ee40bc4a3c5590afb1e9677db74a508659dfd71e126420da8274909a0167"
|
||||
|
||||
[[package]]
|
||||
name = "mime"
|
||||
@@ -702,9 +803,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "mio"
|
||||
version = "0.8.8"
|
||||
version = "0.8.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "927a765cd3fc26206e66b296465fa9d3e5ab003e651c1b3c060e7956d96b19d2"
|
||||
checksum = "3dce281c5e46beae905d4de1870d8b1509a9142b62eedf18b443b011ca8343d0"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"log",
|
||||
@@ -739,9 +840,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "parking_lot_core"
|
||||
version = "0.9.8"
|
||||
version = "0.9.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "93f00c865fe7cabf650081affecd3871070f26767e7b2070a3ffae14c654b447"
|
||||
checksum = "4c42a9226546d68acdd9c0a280d17ce19bfe27a46bf68784e4066115788d008e"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"libc",
|
||||
@@ -780,6 +881,12 @@ version = "0.3.27"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "26072860ba924cbfa98ea39c8c19b4dd6a4a25423dbdf219c1eca91aa0cf6964"
|
||||
|
||||
[[package]]
|
||||
name = "powerfmt"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391"
|
||||
|
||||
[[package]]
|
||||
name = "ppv-lite86"
|
||||
version = "0.2.17"
|
||||
@@ -788,13 +895,45 @@ checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de"
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.66"
|
||||
version = "1.0.69"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "18fb31db3f9bddb2ea821cde30a9f70117e3f119938b5ee630b7403aa6e2ead9"
|
||||
checksum = "134c189feb4956b20f6f547d2cf727d4c0fe06722b20a0eec87ed445a97f92da"
|
||||
dependencies = [
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "prost"
|
||||
version = "0.12.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f4fdd22f3b9c31b53c060df4a0613a1c7f062d4115a2b984dd15b1858f7e340d"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"prost-derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "prost-derive"
|
||||
version = "0.12.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "265baba7fabd416cf5078179f7d2cbeca4ce7a9041111900675ea7c4cb8a4c32"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"itertools",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.38",
|
||||
]
|
||||
|
||||
[[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"
|
||||
@@ -836,18 +975,18 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "redox_syscall"
|
||||
version = "0.3.5"
|
||||
version = "0.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "567664f262709473930a4bf9e51bf2ebf3348f2e748ccc50dea20646858f8f29"
|
||||
checksum = "4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa"
|
||||
dependencies = [
|
||||
"bitflags 1.3.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regex"
|
||||
version = "1.9.5"
|
||||
version = "1.10.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "697061221ea1b4a94a624f67d0ae2bfe4e22b8a17b6a192afb11046542cc8c47"
|
||||
checksum = "380b951a9c5e80ddfd6136919eef32310721aa4aacd4889a8d39124b026ab343"
|
||||
dependencies = [
|
||||
"aho-corasick",
|
||||
"memchr",
|
||||
@@ -857,9 +996,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "regex-automata"
|
||||
version = "0.3.8"
|
||||
version = "0.4.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c2f401f4955220693b56f8ec66ee9c78abffd8d1c4f23dc41a23839eb88f0795"
|
||||
checksum = "5f804c7828047e88b2d32e2d7fe5a105da8ee3264f01902f796c8e067dc2483f"
|
||||
dependencies = [
|
||||
"aho-corasick",
|
||||
"memchr",
|
||||
@@ -868,9 +1007,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "regex-syntax"
|
||||
version = "0.7.5"
|
||||
version = "0.8.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dbb5fb1acd8a1a18b3dd5be62d25485eb770e05afb408a9627d14d451bae12da"
|
||||
checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f"
|
||||
|
||||
[[package]]
|
||||
name = "rustc-demangle"
|
||||
@@ -901,35 +1040,35 @@ checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
|
||||
|
||||
[[package]]
|
||||
name = "semver"
|
||||
version = "1.0.18"
|
||||
version = "1.0.20"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b0293b4b29daaf487284529cc2f5675b8e57c61f70167ba415a463651fd6a918"
|
||||
checksum = "836fa6a3e1e547f9a2c4040802ec865b5d85f4014efe00555d7090a3dcaa1090"
|
||||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "1.0.188"
|
||||
version = "1.0.190"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cf9e0fcba69a370eed61bcf2b728575f726b50b55cba78064753d708ddc7549e"
|
||||
checksum = "91d3c334ca1ee894a2c6f6ad698fe8c435b76d504b13d436f0685d648d6d96f7"
|
||||
dependencies = [
|
||||
"serde_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_derive"
|
||||
version = "1.0.188"
|
||||
version = "1.0.190"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4eca7ac642d82aa35b60049a6eccb4be6be75e599bd2e9adb5f875a737654af2"
|
||||
checksum = "67c5609f394e5c2bd7fc51efda478004ea80ef42fee983d5c67a65e34f32c0e3"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.32",
|
||||
"syn 2.0.38",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_json"
|
||||
version = "1.0.106"
|
||||
version = "1.0.108"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2cc66a619ed80bf7a0f6b17dd063a84b88f6dea1813737cf469aef1d081142c2"
|
||||
checksum = "3d1c7e3eac408d115102c4c24ad393e0821bb3a5df4d506a80f85f7a742a526b"
|
||||
dependencies = [
|
||||
"itoa",
|
||||
"ryu",
|
||||
@@ -950,9 +1089,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "sha1"
|
||||
version = "0.10.5"
|
||||
version = "0.10.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f04293dc80c3993519f2d7f6f511707ee7094fe0c6d3406feb330cdb3540eba3"
|
||||
checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"cpufeatures",
|
||||
@@ -979,15 +1118,15 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "smallvec"
|
||||
version = "1.11.0"
|
||||
version = "1.11.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "62bb4feee49fdd9f707ef802e22365a35de4b7b299de4763d44bfea899442ff9"
|
||||
checksum = "942b4a808e05215192e39f4ab80813e599068285906cc91aa64f923db842bd5a"
|
||||
|
||||
[[package]]
|
||||
name = "socket2"
|
||||
version = "0.5.4"
|
||||
version = "0.5.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4031e820eb552adee9295814c0ced9e5cf38ddf1e8b7d566d6de8e2538ea989e"
|
||||
checksum = "7b5fac59a5cb5dd637972e5fca70daf0523c9067fcdc4842f053dae04a18f8e9"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"windows-sys",
|
||||
@@ -1006,9 +1145,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "2.0.32"
|
||||
version = "2.0.38"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "239814284fd6f1a4ffe4ca893952cdd93c224b6a1571c9a9eadd670295c0c9e2"
|
||||
checksum = "e96b79aaa137db8f61e26363a0c9b47d8b4ec75da28b7d1d614c2303e232408b"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@@ -1017,12 +1156,13 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "time"
|
||||
version = "0.3.28"
|
||||
version = "0.3.30"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "17f6bb557fd245c28e6411aa56b6403c689ad95061f50e4be16c274e70a17e48"
|
||||
checksum = "c4a34ab300f2dee6e562c10a046fc05e358b29f9bf92277f30c3c8d82275f6f5"
|
||||
dependencies = [
|
||||
"deranged",
|
||||
"itoa",
|
||||
"powerfmt",
|
||||
"serde",
|
||||
"time-core",
|
||||
"time-macros",
|
||||
@@ -1030,15 +1170,15 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "time-core"
|
||||
version = "0.1.1"
|
||||
version = "0.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7300fbefb4dadc1af235a9cef3737cea692a9d97e1b9cbcd4ebdae6f8868e6fb"
|
||||
checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3"
|
||||
|
||||
[[package]]
|
||||
name = "time-macros"
|
||||
version = "0.2.14"
|
||||
version = "0.2.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1a942f44339478ef67935ab2bbaec2fb0322496cf3cbe84b261e06ac3814c572"
|
||||
checksum = "4ad70d68dba9e1f8aceda7aa6711965dfec1cac869f311a51bd08b3a2ccbce20"
|
||||
dependencies = [
|
||||
"time-core",
|
||||
]
|
||||
@@ -1060,9 +1200,9 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20"
|
||||
|
||||
[[package]]
|
||||
name = "tokio"
|
||||
version = "1.32.0"
|
||||
version = "1.33.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "17ed6077ed6cd6c74735e21f37eb16dc3935f96878b1fe961074089cc80893f9"
|
||||
checksum = "4f38200e3ef7995e5ef13baec2f432a6da0aa9ac495b2c0e8f3b7eec2c92d653"
|
||||
dependencies = [
|
||||
"backtrace",
|
||||
"bytes",
|
||||
@@ -1077,9 +1217,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "tokio-util"
|
||||
version = "0.7.8"
|
||||
version = "0.7.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "806fe8c2c87eccc8b3267cbae29ed3ab2d0bd37fca70ab622e46aaa9375ddb7d"
|
||||
checksum = "5419f34732d9eb6ee4c3578b7989078579b7f039cbbb9ca2c4da015749371e15"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"futures-core",
|
||||
@@ -1091,11 +1231,10 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "tracing"
|
||||
version = "0.1.37"
|
||||
version = "0.1.40"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8ce8c33a8d48bd45d624a6e523445fd21ec13d3653cd51f681abf67418f54eb8"
|
||||
checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"log",
|
||||
"pin-project-lite",
|
||||
"tracing-core",
|
||||
@@ -1103,18 +1242,18 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "tracing-core"
|
||||
version = "0.1.31"
|
||||
version = "0.1.32"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0955b8137a1df6f1a2e9a37d8a6656291ff0297c1a97c24e0d8425fe2312f79a"
|
||||
checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54"
|
||||
dependencies = [
|
||||
"once_cell",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "typenum"
|
||||
version = "1.16.0"
|
||||
version = "1.17.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "497961ef93d974e23eb6f433eb5fe1b7930b659f06d12dec6fc44a8f554c0bba"
|
||||
checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825"
|
||||
|
||||
[[package]]
|
||||
name = "unicase"
|
||||
@@ -1133,9 +1272,9 @@ checksum = "92888ba5573ff080736b3648696b70cafad7d250551175acbaa4e0385b3e1460"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-ident"
|
||||
version = "1.0.11"
|
||||
version = "1.0.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "301abaae475aa91687eb82514b328ab47a211a533026cb25fc3e519b86adfc3c"
|
||||
checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-normalization"
|
||||
@@ -1235,6 +1374,26 @@ version = "0.48.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538"
|
||||
|
||||
[[package]]
|
||||
name = "zerocopy"
|
||||
version = "0.7.23"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e50cbb27c30666a6108abd6bc7577556265b44f243e2be89a8bc4e07a528c107"
|
||||
dependencies = [
|
||||
"zerocopy-derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zerocopy-derive"
|
||||
version = "0.7.23"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a25f293fe55f0a48e7010d65552bb63704f6ceb55a1a385da10d41d8f78e4a3d"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.38",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zstd"
|
||||
version = "0.12.4"
|
||||
@@ -1256,11 +1415,10 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "zstd-sys"
|
||||
version = "2.0.8+zstd.1.5.5"
|
||||
version = "2.0.9+zstd.1.5.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5556e6ee25d32df2586c098bbfa278803692a20d0ab9565e049480d52707ec8c"
|
||||
checksum = "9e16efa8a874a0481a574084d34cc26fdb3b99627480f785888deb6386506656"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"libc",
|
||||
"pkg-config",
|
||||
]
|
||||
|
@@ -8,3 +8,9 @@ edition = "2021"
|
||||
[dependencies]
|
||||
actix-web = "4"
|
||||
actix-files = "0.6.2"
|
||||
qstring = "0.7.2"
|
||||
serde = { version = "1.0", features = ["derive"] }
|
||||
serde_json = "1"
|
||||
futures = "0.3"
|
||||
actix-protobuf = "0.10.0"
|
||||
prost = { version = "0.12", features = ["prost-derive"] }
|
@@ -1,25 +1,23 @@
|
||||
FROM rust:slim-bullseye AS build-env
|
||||
FROM rust:latest
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
RUN apt-get update && apt-get -y install wget && \
|
||||
wget https://files.ivanch.me/api/public/dl/ch3NV0P8/small-image.png && \
|
||||
wget https://files.ivanch.me/api/public/dl/jNlXYMLR/big-image.png && \
|
||||
wget https://files.ivanch.me/api/public/dl/QdKvaeQI/video.mp4 && \
|
||||
wget https://files.ivanch.me/api/public/dl/YD4vmSsO/nginx.html && \
|
||||
|
||||
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 && \
|
||||
RUN cargo build --release && \
|
||||
cp ./target/release/ActixAPI . && \
|
||||
mv small-image.png ./static && \
|
||||
mv big-image.png ./static && \
|
||||
mv video.mp4 ./static
|
||||
mv video.mp4 ./static && \
|
||||
mv nginx.html ./static && \
|
||||
ldconfig /usr/local/lib
|
||||
|
||||
RUN cargo build --release
|
||||
|
||||
FROM debian:bullseye-slim
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
COPY --from=build-env /app/target/release .
|
||||
|
||||
COPY --from=build-env /app/static ./static
|
||||
ENV LD_LIBRARY_PATH=/usr/local/lib
|
||||
|
||||
ENTRYPOINT ["./ActixAPI"]
|
||||
|
@@ -1,19 +1,36 @@
|
||||
use qstring::QString;
|
||||
use actix_web::{get, post, web, App, HttpResponse, HttpServer, Responder, HttpRequest, Result};
|
||||
use actix_files::NamedFile;
|
||||
use std::path::PathBuf;
|
||||
use actix_protobuf::*;
|
||||
use prost::Message;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Clone, PartialEq, Eq, Message)]
|
||||
pub struct PersonProtobuf {
|
||||
#[prost(string, tag = "1")]
|
||||
pub name: String,
|
||||
#[prost(int32, tag = "2")]
|
||||
pub age: i32,
|
||||
#[prost(string, repeated, tag = "3")]
|
||||
pub friends: Vec<String>,
|
||||
#[prost(string, tag = "4")]
|
||||
pub email: String,
|
||||
#[prost(string, tag = "5")]
|
||||
pub phone: String,
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Serialize)]
|
||||
pub struct PersonJson {
|
||||
pub name: String,
|
||||
pub age: i32,
|
||||
pub friends: Vec<String>,
|
||||
pub email: String,
|
||||
pub phone: String,
|
||||
}
|
||||
|
||||
#[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!")
|
||||
HttpResponse::Ok()
|
||||
}
|
||||
|
||||
async fn static_serve(req: HttpRequest) -> Result<NamedFile> {
|
||||
@@ -23,6 +40,55 @@ async fn static_serve(req: HttpRequest) -> Result<NamedFile> {
|
||||
Ok(NamedFile::open(real_path)?)
|
||||
}
|
||||
|
||||
#[get("/simulation/harmonic-progression")]
|
||||
async fn simulation_harmonic_progression(req: HttpRequest) -> impl Responder {
|
||||
let query_str = req.query_string();
|
||||
let qs = QString::from(query_str);
|
||||
let radius = qs.get("n").unwrap_or("1").parse::<f64>().unwrap_or(1.0);
|
||||
|
||||
let mut sum = 0.0;
|
||||
for i in 1..=radius as i32 {
|
||||
sum += 1.0 / i as f64;
|
||||
}
|
||||
|
||||
HttpResponse::Ok().body(format!("{}", sum))
|
||||
}
|
||||
|
||||
#[post("/simulation/json")]
|
||||
async fn simulation_json(msg: web::Json<PersonJson>) -> impl Responder {
|
||||
HttpResponse::Ok().json(web::Json(msg))
|
||||
}
|
||||
|
||||
#[post("/simulation/protobuf")]
|
||||
async fn simulation_protobuf(msg: ProtoBuf<PersonProtobuf>) -> impl Responder {
|
||||
HttpResponse::Ok().protobuf(msg.0)
|
||||
}
|
||||
|
||||
#[get("/image/load-small-image")]
|
||||
async fn load_small_image() -> Result<NamedFile> {
|
||||
let real_path = "static/small-image.png";
|
||||
|
||||
Ok(NamedFile::open(real_path)?)
|
||||
}
|
||||
|
||||
#[get("/image/load-big-image")]
|
||||
async fn load_big_image() -> Result<NamedFile> {
|
||||
let real_path = "static/big-image.png";
|
||||
|
||||
Ok(NamedFile::open(real_path)?)
|
||||
}
|
||||
|
||||
#[post("/image/save-big-image")]
|
||||
async fn save_big_image(image_data: web::Bytes) -> Result<HttpResponse> {
|
||||
// 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}"))
|
||||
}
|
||||
|
||||
#[actix_web::main]
|
||||
async fn main() -> std::io::Result<()> {
|
||||
println!("Hello, world!");
|
||||
@@ -31,10 +97,15 @@ async fn main() -> std::io::Result<()> {
|
||||
App::new()
|
||||
.route("/static/{filename:.*}", web::get().to(static_serve))
|
||||
.service(hello)
|
||||
.service(echo)
|
||||
.route("/hey", web::get().to(manual_hello))
|
||||
.service(load_small_image)
|
||||
.service(load_big_image)
|
||||
.service(save_big_image)
|
||||
.service(simulation_harmonic_progression)
|
||||
.service(simulation_json)
|
||||
.service(simulation_protobuf)
|
||||
.app_data(web::PayloadConfig::new(1024 * 1024 * 1024))
|
||||
})
|
||||
.bind(("0.0.0.0", 9090))?
|
||||
.bind(("0.0.0.0", 5000))?
|
||||
.run()
|
||||
.await
|
||||
}
|
1
Express
Submodule
1
Express
Submodule
Submodule Express added at 3a54792794
@@ -6,16 +6,23 @@ ENV PYTHONUNBUFFERED=1
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
RUN apt-get update && apt-get install -y imagemagick && apt-get install -y wget && ls
|
||||
RUN apt-get update && \
|
||||
apt-get install -y wget unzip && \
|
||||
wget https://github.com/protocolbuffers/protobuf/releases/download/v25.0/protoc-25.0-linux-x86_64.zip && \
|
||||
unzip protoc-25.0-linux-x86_64.zip && \
|
||||
mv bin/protoc /usr/local/bin/ && \
|
||||
rm -rf protoc-25.0-linux-x86_64.zip bin include readme.txt
|
||||
|
||||
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 && \
|
||||
RUN wget https://files.ivanch.me/api/public/dl/ch3NV0P8/small-image.png && \
|
||||
wget https://files.ivanch.me/api/public/dl/jNlXYMLR/big-image.png && \
|
||||
wget https://files.ivanch.me/api/public/dl/QdKvaeQI/video.mp4 && \
|
||||
wget https://files.ivanch.me/api/public/dl/YD4vmSsO/nginx.html && \
|
||||
rm -rf runtimes && \
|
||||
mkdir -p ./static && \
|
||||
mv small-image.png ./static && \
|
||||
mv big-image.png ./static && \
|
||||
mv video.mp4 ./static
|
||||
mv video.mp4 ./static && \
|
||||
mv nginx.html ./static
|
||||
|
||||
COPY . .
|
||||
|
||||
|
@@ -1,11 +1,13 @@
|
||||
from flask import Flask
|
||||
from controllers.status import status_blueprint
|
||||
from controllers.simulation import simulation_blueprint
|
||||
from controllers.image import image_blueprint
|
||||
|
||||
app = Flask(__name__)
|
||||
|
||||
#
|
||||
app.register_blueprint(status_blueprint)
|
||||
app.register_blueprint(simulation_blueprint)
|
||||
app.register_blueprint(image_blueprint)
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
Binary file not shown.
Before Width: | Height: | Size: 36 KiB |
@@ -5,20 +5,6 @@ from flask import request, Response, Blueprint, jsonify, send_file
|
||||
image_blueprint = Blueprint('image_blueprint', __name__)
|
||||
image_service = ImageService()
|
||||
|
||||
@image_blueprint.route('/image/blur', methods=['POST'])
|
||||
def blur_image():
|
||||
radius = int(request.args.get('radius'))
|
||||
image = request.get_data()
|
||||
|
||||
if radius and image:
|
||||
return send_file(image_service.box_blur_image(image, radius),
|
||||
mimetype='image/jpeg',
|
||||
as_attachment=True,
|
||||
download_name='blurred_image.jpeg')
|
||||
|
||||
return "Bad request", 400
|
||||
|
||||
|
||||
@image_blueprint.route('/image/load-small-image', methods=['GET'])
|
||||
def get_simple_image():
|
||||
return send_file(io.BytesIO(image_service.get_simple_image()),
|
||||
|
41
FlaskAPI/controllers/simulation.py
Normal file
41
FlaskAPI/controllers/simulation.py
Normal file
@@ -0,0 +1,41 @@
|
||||
from flask import request, Blueprint, jsonify
|
||||
import person_pb2
|
||||
|
||||
simulation_blueprint = Blueprint('simulation_blueprint', __name__)
|
||||
|
||||
class SimulationController:
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
def harmonic_progression(self, n):
|
||||
sum = 0
|
||||
for i in range(1, n):
|
||||
sum += 1/i
|
||||
|
||||
return sum
|
||||
|
||||
def return_helloworld(self):
|
||||
return jsonify(message="Hello World!")
|
||||
|
||||
simulation_controller = SimulationController()
|
||||
|
||||
@simulation_blueprint.route('/simulation/harmonic-progression', methods=['GET'])
|
||||
def return_ok():
|
||||
n = int(request.args.get('n'))
|
||||
sum = simulation_controller.harmonic_progression(n)
|
||||
|
||||
return str(sum), 200
|
||||
|
||||
@simulation_blueprint.route('/simulation/json', methods=['POST'])
|
||||
def return_helloworld():
|
||||
data = request.json
|
||||
return data, 200
|
||||
|
||||
@simulation_blueprint.route('/simulation/protobuf', methods=['POST'])
|
||||
def return_protobuf():
|
||||
bytes_data = request.data
|
||||
|
||||
helloworld = person_pb2.Person()
|
||||
helloworld.ParseFromString(bytes_data)
|
||||
|
||||
return helloworld.SerializeToString(), 200
|
@@ -2,18 +2,6 @@ from flask import jsonify, Blueprint
|
||||
|
||||
status_blueprint = Blueprint('status_blueprint', __name__)
|
||||
|
||||
|
||||
class StatusController:
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
def return_ok(self):
|
||||
return jsonify(status=200)
|
||||
|
||||
|
||||
status_controller = StatusController()
|
||||
|
||||
|
||||
@status_blueprint.route('/status/ok', methods=['GET'])
|
||||
def return_ok():
|
||||
return jsonify(status=200)
|
||||
return '', 200
|
||||
|
9
FlaskAPI/person.proto
Normal file
9
FlaskAPI/person.proto
Normal file
@@ -0,0 +1,9 @@
|
||||
syntax = "proto3";
|
||||
|
||||
message Person {
|
||||
string name = 1;
|
||||
int32 age = 2;
|
||||
repeated string friends = 3;
|
||||
string email = 4;
|
||||
string phone = 5;
|
||||
}
|
26
FlaskAPI/person_pb2.py
Normal file
26
FlaskAPI/person_pb2.py
Normal file
@@ -0,0 +1,26 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Generated by the protocol buffer compiler. DO NOT EDIT!
|
||||
# source: person.proto
|
||||
# Protobuf Python Version: 4.25.0
|
||||
"""Generated protocol buffer code."""
|
||||
from google.protobuf import descriptor as _descriptor
|
||||
from google.protobuf import descriptor_pool as _descriptor_pool
|
||||
from google.protobuf import symbol_database as _symbol_database
|
||||
from google.protobuf.internal import builder as _builder
|
||||
# @@protoc_insertion_point(imports)
|
||||
|
||||
_sym_db = _symbol_database.Default()
|
||||
|
||||
|
||||
|
||||
|
||||
DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x0cperson.proto\"R\n\x06Person\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\x0b\n\x03\x61ge\x18\x02 \x01(\x05\x12\x0f\n\x07\x66riends\x18\x03 \x03(\t\x12\r\n\x05\x65mail\x18\x04 \x01(\t\x12\r\n\x05phone\x18\x05 \x01(\tb\x06proto3')
|
||||
|
||||
_globals = globals()
|
||||
_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals)
|
||||
_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'person_pb2', _globals)
|
||||
if _descriptor._USE_C_DESCRIPTORS == False:
|
||||
DESCRIPTOR._options = None
|
||||
_globals['_PERSON']._serialized_start=16
|
||||
_globals['_PERSON']._serialized_end=98
|
||||
# @@protoc_insertion_point(module_scope)
|
@@ -1,3 +1,3 @@
|
||||
Flask>=1.0
|
||||
gunicorn>=19.9.0
|
||||
Wand
|
||||
protobuf>=4.25.0
|
@@ -1,42 +1,7 @@
|
||||
from wand.image import Image
|
||||
|
||||
def box_blur_image_separable(image, radius_x, radius_y):
|
||||
blurred_image = image.clone()
|
||||
width, height = image.width, image.height
|
||||
|
||||
for y in range(height):
|
||||
for x in range(width):
|
||||
blurred_image[x, y] = image[x, y]
|
||||
|
||||
r_total, g_total, b_total = 0, 0, 0
|
||||
pixel_count = 0
|
||||
for offset_y in range(-radius_y, radius_y + 1):
|
||||
for offset_x in range(-radius_x, radius_x + 1):
|
||||
new_x = x + offset_x
|
||||
new_y = y + offset_y
|
||||
|
||||
if 0 <= new_x < width and 0 <= new_y < height:
|
||||
r_total += image[new_x, new_y].red_int8
|
||||
g_total += image[new_x, new_y].green_int8
|
||||
b_total += image[new_x, new_y].blue_int8
|
||||
pixel_count += 1
|
||||
|
||||
blurred_image[x, y].red_int8 = int(r_total / pixel_count)
|
||||
blurred_image[x, y].green_int8 = int(g_total / pixel_count)
|
||||
blurred_image[x, y].blue_int8 = int(b_total / pixel_count)
|
||||
|
||||
return blurred_image
|
||||
|
||||
class ImageService:
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
def box_blur_image(self, img, radius):
|
||||
with Image(blob=img) as image:
|
||||
blurred_image = box_blur_image_separable(image, radius, 0)
|
||||
blurred_image = box_blur_image_separable(blurred_image, 0, radius)
|
||||
return blurred_image.make_blob()
|
||||
|
||||
def get_simple_image(self):
|
||||
with open("./static/small-image.png", "rb") as file:
|
||||
return file.read()
|
||||
|
Binary file not shown.
Before Width: | Height: | Size: 44 KiB |
1
Spring
Submodule
1
Spring
Submodule
Submodule Spring added at 281dc59716
@@ -31,10 +31,33 @@ services:
|
||||
build: ./ActixAPI
|
||||
restart: always
|
||||
ports:
|
||||
- "9083:9090"
|
||||
- "9083:5000"
|
||||
deploy:
|
||||
resources:
|
||||
limits:
|
||||
cpus: '1'
|
||||
memory: 1GB
|
||||
tcc-express:
|
||||
image: tcc:express
|
||||
container_name: tcc-express
|
||||
build: ./Express
|
||||
restart: always
|
||||
ports:
|
||||
- "9084:5000"
|
||||
deploy:
|
||||
resources:
|
||||
limits:
|
||||
cpus: '1'
|
||||
memory: 1GB
|
||||
tcc-spring:
|
||||
image: tcc:spring
|
||||
container_name: tcc-spring
|
||||
build: ./Spring
|
||||
restart: always
|
||||
ports:
|
||||
- "9085:8080"
|
||||
deploy:
|
||||
resources:
|
||||
limits:
|
||||
cpus: '1'
|
||||
memory: 1GB
|
||||
|
||||
|
47
scripts/common.py
Normal file
47
scripts/common.py
Normal file
@@ -0,0 +1,47 @@
|
||||
import json
|
||||
import person_pb2
|
||||
|
||||
person_proto = person_pb2.Person()
|
||||
person_proto.name = "John Doe"
|
||||
person_proto.age = 30
|
||||
person_proto.friends.extend(["Jane Doe", "John Smith"])
|
||||
person_proto.email = "john.doe@email.com"
|
||||
person_proto.phone = "123-456-7890"
|
||||
person_proto = person_proto.SerializeToString()
|
||||
|
||||
person_json = {
|
||||
"name": "John Doe",
|
||||
"age": 30,
|
||||
"friends": ["Jane Doe", "John Smith"],
|
||||
"email": "john.doe@email.com",
|
||||
"phone": "123-456-7890"
|
||||
}
|
||||
person_json = json.dumps(person_json)
|
||||
|
||||
FRAMEWORKS = [
|
||||
('Actix', 'tcc-actix', 'orange'),
|
||||
('ASP.NET', 'tcc-aspnet', 'blue'),
|
||||
('Flask', 'tcc-flask', 'grey'),
|
||||
('Express', 'tcc-express', 'red'),
|
||||
('Spring', 'tcc-spring', 'green'),
|
||||
]
|
||||
|
||||
ENDPOINTS = {
|
||||
'Actix': 'http://localhost:9083',
|
||||
'ASP.NET': 'http://localhost:9081',
|
||||
'Flask': 'http://localhost:9082',
|
||||
'Express': 'http://localhost:9084',
|
||||
'Spring': 'http://localhost:9085',
|
||||
}
|
||||
|
||||
AVG_RUNS = 5
|
||||
|
||||
API_REQUESTS = [
|
||||
('/status/ok', 'GET', range(0, 30_000, 5000), None),
|
||||
('/simulation/harmonic-progression?n=100000', 'GET', range(0, 30_000, 5000), None),
|
||||
# ('/simulation/json', 'POST', range(0, 30_000, 5000), (person_json, "application/json")),
|
||||
('/image/save-big-image', 'POST', range(0, 500, 50), (open('big-image.png', 'rb').read(), "image/png")),
|
||||
('/static/small-image.png', 'GET', range(0, 30_000, 5000), None),
|
||||
('/static/big-image.png', 'GET', range(0, 500, 50), None),
|
||||
# ('/simulation/protobuf', 'POST', range(0, 30_000, 5000), (person_proto, "application/protobuf")),
|
||||
]
|
163
scripts/graph.py
163
scripts/graph.py
@@ -1,44 +1,90 @@
|
||||
import numpy as np
|
||||
import matplotlib.pyplot as plt
|
||||
from common import API_REQUESTS, FRAMEWORKS
|
||||
from pylab import plot, show, savefig, xlim, figure, \
|
||||
ylim, legend, boxplot, setp, axes
|
||||
|
||||
FRAMEWORKS_COLORS = [c for _, _, c in FRAMEWORKS]
|
||||
FRAMEWORKS = [f for f, _, _ in FRAMEWORKS]
|
||||
|
||||
def setBoxColors(bp):
|
||||
for i, box in enumerate(bp['boxes']):
|
||||
box.set(color=FRAMEWORKS_COLORS[i])
|
||||
for i, median in enumerate(bp['medians']):
|
||||
# median.set(color=FRAMEWORKS_COLORS[i])
|
||||
median.set(color='white')
|
||||
|
||||
for i in range(len(FRAMEWORKS)):
|
||||
bp['whiskers'][i*2].set(color=FRAMEWORKS_COLORS[i])
|
||||
bp['whiskers'][i*2 + 1].set(color=FRAMEWORKS_COLORS[i])
|
||||
for i in range(len(FRAMEWORKS)):
|
||||
bp['caps'][i*2].set(color=FRAMEWORKS_COLORS[i])
|
||||
bp['caps'][i*2 + 1].set(color=FRAMEWORKS_COLORS[i])
|
||||
|
||||
|
||||
def plot_graph(x_data, y_data, title, x_label, y_label, filename, y_lim = None):
|
||||
old_x_data = x_data
|
||||
old_y_data = y_data
|
||||
|
||||
x_data = []
|
||||
y_data = []
|
||||
|
||||
for i in range(len(old_x_data)):
|
||||
if old_x_data[i] not in x_data:
|
||||
x_data.append(old_x_data[i])
|
||||
y_data.append([])
|
||||
for f in range(len(FRAMEWORKS)):
|
||||
y_data[-1].append([])
|
||||
|
||||
for f in range(len(FRAMEWORKS)):
|
||||
y_data[-1][f].append(old_y_data[f][i])
|
||||
|
||||
fig = figure()
|
||||
ax = axes()
|
||||
|
||||
all_positions = []
|
||||
|
||||
print(filename)
|
||||
# print(y_data)
|
||||
for j in range(len(x_data)):
|
||||
positions = [len(FRAMEWORKS)*j + i + 2*j for i in range(len(FRAMEWORKS))]
|
||||
|
||||
bp = boxplot(y_data[j], positions = positions, widths = 0.6, showfliers=False,
|
||||
patch_artist=True)
|
||||
all_positions.append(positions)
|
||||
setBoxColors(bp)
|
||||
|
||||
for i in range(len(FRAMEWORKS)):
|
||||
medians = []
|
||||
for j in range(len(x_data)):
|
||||
medians.append(np.median(y_data[j][i]))
|
||||
|
||||
positions = [all_positions[x][i] for x in range(len(x_data))]
|
||||
plt.plot(positions, medians, color=FRAMEWORKS_COLORS[i], marker='.', linestyle='--', linewidth=0.3)
|
||||
|
||||
avg_positions = []
|
||||
for positions in all_positions:
|
||||
avg = np.average(positions)
|
||||
avg_positions.append(avg)
|
||||
|
||||
ax.set_xticks(avg_positions)
|
||||
ax.set_xticklabels([str(x) for x in x_data])
|
||||
|
||||
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')
|
||||
if y_lim:
|
||||
plt.ylim(y_lim)
|
||||
|
||||
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],
|
||||
}
|
||||
if filename.startswith('req'):
|
||||
for i, framework in enumerate(FRAMEWORKS):
|
||||
h, = plt.plot([], c=FRAMEWORKS_COLORS[i], label=framework, marker='.', linestyle='--')
|
||||
# h.set_visible(False)
|
||||
|
||||
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.legend()
|
||||
|
||||
plt.tight_layout()
|
||||
plt.savefig(f'{filename}.png')
|
||||
|
||||
plt.clf()
|
||||
@@ -69,21 +115,58 @@ def get_resource_data(filename):
|
||||
for line in lines:
|
||||
line = line.strip().split(',')
|
||||
if line:
|
||||
r = [round(float(line[1])*100), round(float(line[2])*100)]
|
||||
if r[0] > 100:
|
||||
r[0] = 100
|
||||
|
||||
if r[1] > 100:
|
||||
r[1] = 100
|
||||
|
||||
x.append(int(line[0])) # requests
|
||||
y.append([float(v)*100 for v in line[1:]]) # cpu, ram
|
||||
y.append(r) # cpu, ram
|
||||
|
||||
return x, y
|
||||
|
||||
def generate_req_graph(filename, framework_name, endpoint_name):
|
||||
x, y = get_data(filename)
|
||||
x, _ = get_data(filename)
|
||||
y = []
|
||||
|
||||
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)
|
||||
for f in FRAMEWORKS:
|
||||
newfile = filename.replace(framework_name, f)
|
||||
_, y_data = get_data(newfile)
|
||||
|
||||
y.append(y_data)
|
||||
|
||||
graph_file = f'req_{endpoint_name.replace("/", "").replace("?", "")}'
|
||||
plot_graph(x, y, f'Requisições atendidas por segundo - {endpoint_name}', 'Número de requisições', 'Requisições/segundo', graph_file)
|
||||
|
||||
def generate_resource_graph(filename, framework_name, endpoint_name):
|
||||
x, y = get_resource_data(filename)
|
||||
x, _ = 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)
|
||||
for resource_index, resource in enumerate(['cpu', 'ram']):
|
||||
y = []
|
||||
|
||||
for f in FRAMEWORKS:
|
||||
newfile = filename.replace(framework_name, f)
|
||||
_, y_data = get_resource_data(newfile)
|
||||
y.append([data[resource_index] for data in y_data])
|
||||
|
||||
graph_file = f'{resource}_{endpoint_name.replace("/", "").replace("?", "")}'
|
||||
plot_graph(x, y, f'Uso de {resource.upper()} - {endpoint_name}', 'Número de requisições', f'Uso de {resource.upper()} (%)', graph_file)
|
||||
|
||||
if __name__ == '__main__':
|
||||
endpoints = [config[0] for config in API_REQUESTS]
|
||||
|
||||
for endpoint_name in endpoints:
|
||||
framework_name = 'ASP.NET'
|
||||
endpoint_file = endpoint_name.replace('/', '')
|
||||
|
||||
endpoint_name = '/' + endpoint_name.split('/')[-1]
|
||||
|
||||
filename = f'data/resource_ASP.NET_{endpoint_file}.csv'
|
||||
filename = filename.replace("?", "_")
|
||||
generate_resource_graph(filename, framework_name, endpoint_name)
|
||||
|
||||
filename = f'data/req_ASP.NET_{endpoint_file}.csv'
|
||||
filename = filename.replace("?", "_")
|
||||
generate_req_graph(filename, framework_name, endpoint_name)
|
||||
|
@@ -1,4 +1,5 @@
|
||||
import requests
|
||||
import os
|
||||
|
||||
def download_file(url):
|
||||
local_filename = url.split('/')[-1]
|
||||
@@ -13,5 +14,9 @@ def download_file(url):
|
||||
return local_filename
|
||||
|
||||
def init():
|
||||
download_file('https://files.ivanch.me/api/public/dl/iFuXSNhw/small-image.png')
|
||||
download_file('https://files.ivanch.me/api/public/dl/81Bkht5C/big-image.png')
|
||||
if not os.path.exists('small-image.png'):
|
||||
download_file('https://files.ivanch.me/api/public/dl/ch3NV0P8/small-image.png')
|
||||
if not os.path.exists('big-image.png'):
|
||||
download_file('https://files.ivanch.me/api/public/dl/jNlXYMLR/big-image.png')
|
||||
|
||||
init()
|
9
scripts/person.proto
Normal file
9
scripts/person.proto
Normal file
@@ -0,0 +1,9 @@
|
||||
syntax = "proto3";
|
||||
|
||||
message Person {
|
||||
string name = 1;
|
||||
int32 age = 2;
|
||||
repeated string friends = 3;
|
||||
string email = 4;
|
||||
string phone = 5;
|
||||
}
|
26
scripts/person_pb2.py
Normal file
26
scripts/person_pb2.py
Normal file
@@ -0,0 +1,26 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Generated by the protocol buffer compiler. DO NOT EDIT!
|
||||
# source: person.proto
|
||||
# Protobuf Python Version: 4.25.0
|
||||
"""Generated protocol buffer code."""
|
||||
from google.protobuf import descriptor as _descriptor
|
||||
from google.protobuf import descriptor_pool as _descriptor_pool
|
||||
from google.protobuf import symbol_database as _symbol_database
|
||||
from google.protobuf.internal import builder as _builder
|
||||
# @@protoc_insertion_point(imports)
|
||||
|
||||
_sym_db = _symbol_database.Default()
|
||||
|
||||
|
||||
|
||||
|
||||
DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x0cperson.proto\"R\n\x06Person\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\x0b\n\x03\x61ge\x18\x02 \x01(\x05\x12\x0f\n\x07\x66riends\x18\x03 \x03(\t\x12\r\n\x05\x65mail\x18\x04 \x01(\t\x12\r\n\x05phone\x18\x05 \x01(\tb\x06proto3')
|
||||
|
||||
_globals = globals()
|
||||
_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals)
|
||||
_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'person_pb2', _globals)
|
||||
if _descriptor._USE_C_DESCRIPTORS == False:
|
||||
DESCRIPTOR._options = None
|
||||
_globals['_PERSON']._serialized_start=16
|
||||
_globals['_PERSON']._serialized_end=98
|
||||
# @@protoc_insertion_point(module_scope)
|
31
scripts/protobuftest.py
Normal file
31
scripts/protobuftest.py
Normal file
@@ -0,0 +1,31 @@
|
||||
import person_pb2
|
||||
import asyncio
|
||||
import aiohttp
|
||||
|
||||
async def fetch(session):
|
||||
obj = get_object()
|
||||
# async with session.post('http://172.25.96.1:9090/simulation/protobuf', data=obj.SerializeToString(),
|
||||
async with session.post('http://127.0.0.1:5000/simulation/protobuf', data=obj.SerializeToString(),
|
||||
headers={"content-type": "application/protobuf"}) as resp:
|
||||
print(resp.status)
|
||||
data = await resp.read()
|
||||
receiveObj = person_pb2.Person()
|
||||
receiveObj.ParseFromString(data)
|
||||
print(receiveObj)
|
||||
|
||||
async def go(loop):
|
||||
async with aiohttp.ClientSession(loop=loop) as session:
|
||||
await fetch(session)
|
||||
|
||||
def get_object():
|
||||
obj = person_pb2.Person()
|
||||
obj.name = "John Doe"
|
||||
obj.age = 30
|
||||
obj.friends.extend(["Jane Doe", "John Smith"])
|
||||
obj.email = "john.doe@email.com"
|
||||
obj.phone = "123-456-7890"
|
||||
return obj
|
||||
|
||||
loop = asyncio.get_event_loop()
|
||||
loop.run_until_complete(go(loop))
|
||||
loop.close()
|
4
scripts/requirements.txt
Normal file
4
scripts/requirements.txt
Normal file
@@ -0,0 +1,4 @@
|
||||
protobuf>=4.25.0
|
||||
matplotlib
|
||||
numpy
|
||||
docker
|
@@ -2,35 +2,19 @@ import requests
|
||||
import docker
|
||||
import concurrent.futures
|
||||
import time
|
||||
import sys
|
||||
import os
|
||||
from graph import generate_req_graph, generate_resource_graph
|
||||
from math import floor
|
||||
from init import init
|
||||
|
||||
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)
|
||||
from common import FRAMEWORKS, ENDPOINTS, API_REQUESTS, AVG_RUNS
|
||||
|
||||
init()
|
||||
|
||||
THREADS = 10
|
||||
FRAMEWORK_NAME = sys.argv[1]
|
||||
CONTAINER_NAME = sys.argv[2] if len(sys.argv) > 2 else ""
|
||||
FRAMEWORK_NAME = ""
|
||||
CONTAINER_NAME = ""
|
||||
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):
|
||||
def send_request(url, method = 'GET', data = None):
|
||||
success = False
|
||||
responses = {
|
||||
2: 0, # OK
|
||||
@@ -43,7 +27,9 @@ def send_request(url, method = 'GET', payload = None):
|
||||
if method == 'GET':
|
||||
response = requests.get(url)
|
||||
elif method == 'POST':
|
||||
response = requests.post(url, data=payload, headers={'Content-Type': 'image/png'})
|
||||
payload = data[0]
|
||||
content_type = data[1]
|
||||
response = requests.post(url, data=payload, headers={'Content-Type': content_type})
|
||||
except:
|
||||
continue
|
||||
success = response.status_code == 200
|
||||
@@ -77,9 +63,11 @@ def run_tests(endpoint, method, num_requests, metadata):
|
||||
for num_request in num_requests:
|
||||
if num_request <= 0: continue
|
||||
|
||||
for run in range(AVG_RUNS):
|
||||
ok_responses = 0
|
||||
bad_responses = 0
|
||||
server_errors = 0
|
||||
|
||||
cpu, ram = 0, 0
|
||||
|
||||
with concurrent.futures.ThreadPoolExecutor(max_workers=THREADS) as executor:
|
||||
@@ -108,13 +96,14 @@ def run_tests(endpoint, method, num_requests, metadata):
|
||||
bad_responses += responses[4]
|
||||
server_errors += responses[5]
|
||||
|
||||
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"[#{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()
|
||||
|
||||
record(files[0], num_request, f"{num_request/elapsed_time:.2f}")
|
||||
record_resource(files[1], num_request, cpu, ram)
|
||||
|
||||
generate_req_graph(files[0], FRAMEWORK_NAME, endpoint)
|
||||
generate_resource_graph(files[1], FRAMEWORK_NAME, endpoint)
|
||||
|
||||
time.sleep(3)
|
||||
|
||||
def get_resource_usage():
|
||||
@@ -147,9 +136,14 @@ def get_ram_usage(stats):
|
||||
if __name__ == "__main__":
|
||||
if not os.path.exists("data"):
|
||||
os.mkdir("data")
|
||||
else:
|
||||
os.system("rm -rf data/*")
|
||||
|
||||
init()
|
||||
|
||||
for i in range(len(FRAMEWORKS)):
|
||||
FRAMEWORK_NAME = FRAMEWORKS[i][0]
|
||||
CONTAINER_NAME = FRAMEWORKS[i][1]
|
||||
URL_BASE = ENDPOINTS[FRAMEWORK_NAME]
|
||||
|
||||
for endpoint, method, num_requests, metadata in API_REQUESTS:
|
||||
print(f"# {endpoint}")
|
||||
print(f"# {FRAMEWORK_NAME} - {endpoint}")
|
||||
run_tests(endpoint, method, num_requests, metadata)
|
||||
|
Reference in New Issue
Block a user