Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
0a769f7
feat: добавил ServiceDefaults
Donistr Feb 22, 2026
69e6dba
feat: добавил сервис Generator
Donistr Feb 22, 2026
9b66e86
fix: добавил файлы, которые забыл закоммитить
Donistr Feb 22, 2026
4eaaee0
feat: добавил AppHost
Donistr Feb 22, 2026
52dc141
fix: поправил в клиенте карточку студента и сделал чтобы url получени…
Donistr Feb 22, 2026
70c225b
style: запустил code cleanup во всём проекте
Donistr Feb 22, 2026
ae35609
refactor: вынес faker в private static readonly поле
Donistr Feb 22, 2026
8724252
style: сделал revert коммита с клинапом
Donistr Feb 25, 2026
6cab0cf
fix: убрал serilog, чтобы пофиксить структурное логирование
Donistr Feb 25, 2026
c6f84a5
refactor: убрал метод CreateCahcheOptions
Donistr Feb 25, 2026
4c1f771
refactor: улучшил логирование сгенерированного объекта ResidentialBui…
Donistr Feb 25, 2026
51fac4e
fix: поправил cors
Donistr Feb 25, 2026
38f2929
refactor: убрал объявление бесполезной переменной generator
Donistr Feb 25, 2026
fbc4abf
reafactor: исправил порядок импортов
Donistr Feb 26, 2026
7712171
refactor: добавил в контроллер атрибуты с возвращаемыми типами
Donistr Feb 26, 2026
9d30440
fix: изменил клиент под gateway и под 2 лабу
Donistr Mar 4, 2026
3369278
fix: изменил генератор под query параметр
Donistr Mar 4, 2026
ad90a89
feat: добавил ocelot с кастомным quary based балансировщиком нагрузки
Donistr Mar 4, 2026
b900ae7
fix: изменил AppHost под ocelot
Donistr Mar 4, 2026
4208170
fix: убрал бесполезный lock из балансировщика
Donistr Mar 5, 2026
3191a83
refactor: сделал в AppHost.cs создание генераторов через цикл
Donistr Mar 5, 2026
1c6352f
refactor: убрал бесполезный cors у сервиса-генератора
Donistr Mar 5, 2026
8f9d89b
refactor: убрал из конфига оцелота плейсхолдеры из маршрутов
Donistr Mar 5, 2026
472fee8
fix: исправил балансировщик, чтобы он соответствовал заданию
Donistr Mar 5, 2026
8d77860
refactor: убрал i1 из AppHost.cs
Donistr Mar 10, 2026
d8f4141
feat: добавил отправку сгенерированных данных в файловый сервис
Donistr Apr 14, 2026
da0458e
refactor: рефакторинг генератора
Donistr Apr 14, 2026
07bfa04
fix: забыл закоммитить файлы
Donistr Apr 14, 2026
701551a
feat: добавил файловый сервис
Donistr Apr 14, 2026
b25b779
feat: добавил интеграционные тесты
Donistr Apr 14, 2026
4c57cc3
docs: добавил документацию там, где не хватало
Donistr Apr 14, 2026
f7e948b
docs: добавил документацию там, где не хватало
Donistr Apr 14, 2026
e361b72
refactor: удалил ненужный Dockerfile
Donistr Apr 15, 2026
e3b4472
refactor: изменил namespace везде в проекте FileService на правильный
Donistr Apr 16, 2026
a2de00a
refactor: в SnsSubscriberController.ReceiveMessage оставил только оди…
Donistr Apr 16, 2026
93c9ab6
tests: добавил проверку негативных сценариев в интеграционное тестиро…
Donistr Apr 16, 2026
b149b4f
tests: забыл закоммитить убранные лишние тесты
Donistr Apr 16, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 25 additions & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
**/.dockerignore
**/.env
**/.git
**/.gitignore
**/.project
**/.settings
**/.toolstarget
**/.vs
**/.vscode
**/.idea
**/*.*proj.user
**/*.dbmdl
**/*.jfm
**/azds.yaml
**/bin
**/charts
**/docker-compose*
**/Dockerfile*
**/node_modules
**/npm-debug.log
**/obj
**/secrets.dev.yaml
**/values.dev.yaml
LICENSE
README.md
8 changes: 4 additions & 4 deletions Client.Wasm/Components/StudentCard.razor
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,10 @@
</CardHeader>
<CardBody>
<UnorderedList Unstyled>
<UnorderedListItem>Номер <Strong>№X "Название лабораторной"</Strong></UnorderedListItem>
<UnorderedListItem>Вариант <Strong>№Х "Название варианта"</Strong></UnorderedListItem>
<UnorderedListItem>Выполнена <Strong>Фамилией Именем 65ХХ</Strong> </UnorderedListItem>
<UnorderedListItem><Link To="https://puginarug.com/">Ссылка на форк</Link></UnorderedListItem>
<UnorderedListItem>Номер <Strong>№2 «Балансировка нагрузки»</Strong></UnorderedListItem>
<UnorderedListItem>Вариант <Strong>№38 "Query Based"</Strong></UnorderedListItem>
<UnorderedListItem>Выполнена <Strong>Елагиным Денисом 6513</Strong> </UnorderedListItem>
<UnorderedListItem><Link To="https://github.com/Donistr/cloud-development">Ссылка на форк</Link></UnorderedListItem>
</UnorderedList>
</CardBody>
</Card>
2 changes: 1 addition & 1 deletion Client.Wasm/wwwroot/appsettings.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,5 @@
}
},
"AllowedHosts": "*",
"BaseAddress": ""
"BaseAddress": "http://localhost:5300/residential-building"
}
36 changes: 36 additions & 0 deletions CloudDevelopment.sln
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,18 @@ VisualStudioVersion = 17.14.36811.4
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Client.Wasm", "Client.Wasm\Client.Wasm.csproj", "{AE7EEA74-2FE0-136F-D797-854FD87E022A}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ResidentialBuilding.Generator", "ResidentialBuilding.Generator\ResidentialBuilding.Generator.csproj", "{4C3748F7-BE7B-4C97-A656-D0D467E4BC5D}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ResidentialBuilding.AppHost", "ResidentialBuilding.AppHost\ResidentialBuilding.AppHost.csproj", "{248C1F9B-F012-4C7C-A458-4E2D0F918A70}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ResidentialBuilding.ServiceDefaults", "ResidentialBuilding.ServiceDefaults\ResidentialBuilding.ServiceDefaults.csproj", "{3AEE6EF1-603F-411D-89C2-5CE78EBCAEBA}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ResidentialBuilding.Gateway", "ResidentialBuilding.Gateway\ResidentialBuilding.Gateway.csproj", "{2CC59865-F962-47FF-9C2F-1CB6F535316B}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ResidentialBuilding.FileService", "ResidentialBuilding.FileService\ResidentialBuilding.FileService.csproj", "{B5797E57-88BC-41C8-97A8-D226E4596503}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ResidentialBuilding.Tests", "ResidentialBuilding.Tests\ResidentialBuilding.Tests.csproj", "{ADBF06EE-2008-4D96-8337-078A1C1E80DF}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Expand All @@ -15,6 +27,30 @@ Global
{AE7EEA74-2FE0-136F-D797-854FD87E022A}.Debug|Any CPU.Build.0 = Debug|Any CPU
{AE7EEA74-2FE0-136F-D797-854FD87E022A}.Release|Any CPU.ActiveCfg = Release|Any CPU
{AE7EEA74-2FE0-136F-D797-854FD87E022A}.Release|Any CPU.Build.0 = Release|Any CPU
{4C3748F7-BE7B-4C97-A656-D0D467E4BC5D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{4C3748F7-BE7B-4C97-A656-D0D467E4BC5D}.Debug|Any CPU.Build.0 = Debug|Any CPU
{4C3748F7-BE7B-4C97-A656-D0D467E4BC5D}.Release|Any CPU.ActiveCfg = Release|Any CPU
{4C3748F7-BE7B-4C97-A656-D0D467E4BC5D}.Release|Any CPU.Build.0 = Release|Any CPU
{248C1F9B-F012-4C7C-A458-4E2D0F918A70}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{248C1F9B-F012-4C7C-A458-4E2D0F918A70}.Debug|Any CPU.Build.0 = Debug|Any CPU
{248C1F9B-F012-4C7C-A458-4E2D0F918A70}.Release|Any CPU.ActiveCfg = Release|Any CPU
{248C1F9B-F012-4C7C-A458-4E2D0F918A70}.Release|Any CPU.Build.0 = Release|Any CPU
{3AEE6EF1-603F-411D-89C2-5CE78EBCAEBA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{3AEE6EF1-603F-411D-89C2-5CE78EBCAEBA}.Debug|Any CPU.Build.0 = Debug|Any CPU
{3AEE6EF1-603F-411D-89C2-5CE78EBCAEBA}.Release|Any CPU.ActiveCfg = Release|Any CPU
{3AEE6EF1-603F-411D-89C2-5CE78EBCAEBA}.Release|Any CPU.Build.0 = Release|Any CPU
{2CC59865-F962-47FF-9C2F-1CB6F535316B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{2CC59865-F962-47FF-9C2F-1CB6F535316B}.Debug|Any CPU.Build.0 = Debug|Any CPU
{2CC59865-F962-47FF-9C2F-1CB6F535316B}.Release|Any CPU.ActiveCfg = Release|Any CPU
{2CC59865-F962-47FF-9C2F-1CB6F535316B}.Release|Any CPU.Build.0 = Release|Any CPU
{B5797E57-88BC-41C8-97A8-D226E4596503}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{B5797E57-88BC-41C8-97A8-D226E4596503}.Debug|Any CPU.Build.0 = Debug|Any CPU
{B5797E57-88BC-41C8-97A8-D226E4596503}.Release|Any CPU.ActiveCfg = Release|Any CPU
{B5797E57-88BC-41C8-97A8-D226E4596503}.Release|Any CPU.Build.0 = Release|Any CPU
{ADBF06EE-2008-4D96-8337-078A1C1E80DF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{ADBF06EE-2008-4D96-8337-078A1C1E80DF}.Debug|Any CPU.Build.0 = Debug|Any CPU
{ADBF06EE-2008-4D96-8337-078A1C1E80DF}.Release|Any CPU.ActiveCfg = Release|Any CPU
{ADBF06EE-2008-4D96-8337-078A1C1E80DF}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand Down
61 changes: 61 additions & 0 deletions ResidentialBuilding.AppHost/AppHost.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
using Amazon;
using Aspire.Hosting.LocalStack.Container;

var builder = DistributedApplication.CreateBuilder(args);

var cache = builder.AddRedis("residential-building-cache")
.WithRedisInsight(containerName: "residential-building-insight");

var gateway = builder.AddProject<Projects.ResidentialBuilding_Gateway>("gateway")
.WithEndpoint("http", endpoint => endpoint.Port = 5300)
.WithExternalHttpEndpoints();

var awsConfig = builder.AddAWSSDKConfig()
.WithProfile("default")
.WithRegion(RegionEndpoint.EUCentral1);

var localstack = builder
.AddLocalStack("residential-building-localstack", awsConfig: awsConfig, configureContainer: container =>
{
container.Lifetime = ContainerLifetime.Session;
container.DebugLevel = 1;
container.LogLevel = LocalStackLogLevel.Debug;
container.Port = 4566;
container.AdditionalEnvironmentVariables
.Add("DEBUG", "1");
container.AdditionalEnvironmentVariables
.Add("SNS_CERT_URL_HOST", "sns.eu-central-1.amazonaws.com");
});

var awsResources = builder
.AddAWSCloudFormationTemplate("files", "CloudFormation/residential-building-template-sns-s3.yaml", "residential-building")
.WithReference(awsConfig);

const int generatorPortBase = 5200;
for (var i = 1; i <= 5; ++i)
{
var generator = builder.AddProject<Projects.ResidentialBuilding_Generator>($"generator-{i}")
.WithReference(cache, "residential-building-cache")
.WithEndpoint("http", endpoint => endpoint.Port = generatorPortBase + i)
.WithReference(awsResources)
.WithEnvironment("Settings__MessageBroker", "SNS")
.WaitFor(cache)
.WaitFor(awsResources);

gateway.WaitFor(generator);
}

builder.AddProject<Projects.Client_Wasm>("client")
.WithReference(gateway)
.WaitFor(gateway);

var fileService = builder.AddProject<Projects.ResidentialBuilding_FileService>("residential-building-file-service")
.WithReference(awsResources)
.WithEnvironment("Settings__MessageBroker", "SNS")
.WithEnvironment("Settings__S3Hosting", "Localstack")
.WaitFor(awsResources);
fileService.WithEnvironment("AWS__Resources__SNSUrl", "http://host.docker.internal:5280/api/sns");

builder.UseLocalStack(localstack);

builder.Build().Run();
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
AWSTemplateFormatVersion: '2010-09-09'
Description: 'Cloud formation template for residential building project'

Parameters:
BucketName:
Type: String
Description: Name for the S3 bucket
Default: 'residential-building-bucket'

TopicName:
Type: String
Description: Name for the SNS topic
Default: 'residential-building-topic'

Resources:
ResidentialBuildingBucket:
Type: AWS::S3::Bucket
Properties:
BucketName: !Ref BucketName
VersioningConfiguration:
Status: Suspended
Tags:
- Key: Name
Value: !Ref BucketName
- Key: Environment
Value: Sample
PublicAccessBlockConfiguration:
BlockPublicAcls: true
BlockPublicPolicy: true
IgnorePublicAcls: true
RestrictPublicBuckets: true

ResidentialBuildingTopic:
Type: AWS::SNS::Topic
Properties:
TopicName: !Ref TopicName
DisplayName: !Ref TopicName
Tags:
- Key: Name
Value: !Ref TopicName
- Key: Environment
Value: Sample

Outputs:
S3BucketName:
Description: Name of the S3 bucket
Value: !Ref ResidentialBuildingBucket

S3BucketArn:
Description: ARN of the S3 bucket
Value: !GetAtt ResidentialBuildingBucket.Arn

SNSTopicName:
Description: Name of the SNS topic
Value: !GetAtt ResidentialBuildingTopic.TopicName

SNSTopicArn:
Description: ARN of the SNS topic
Value: !Ref ResidentialBuildingTopic
29 changes: 29 additions & 0 deletions ResidentialBuilding.AppHost/Properties/launchSettings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
{
"$schema": "https://json.schemastore.org/launchsettings.json",
"profiles": {
"https": {
"commandName": "Project",
"dotnetRunMessages": true,
"launchBrowser": true,
"applicationUrl": "https://localhost:17129;http://localhost:15221",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development",
"DOTNET_ENVIRONMENT": "Development",
"ASPIRE_DASHBOARD_OTLP_ENDPOINT_URL": "https://localhost:21101",
"ASPIRE_RESOURCE_SERVICE_ENDPOINT_URL": "https://localhost:22255"
}
},
"http": {
"commandName": "Project",
"dotnetRunMessages": true,
"launchBrowser": true,
"applicationUrl": "http://localhost:15221",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development",
"DOTNET_ENVIRONMENT": "Development",
"ASPIRE_DASHBOARD_OTLP_ENDPOINT_URL": "http://localhost:19083",
"ASPIRE_RESOURCE_SERVICE_ENDPOINT_URL": "http://localhost:20274"
}
}
}
}
26 changes: 26 additions & 0 deletions ResidentialBuilding.AppHost/ResidentialBuilding.AppHost.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
<Project Sdk="Microsoft.NET.Sdk">

<Sdk Name="Aspire.AppHost.Sdk" Version="9.5.0" />

<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<UserSecretsId>ed7e1e47-dc98-4419-8424-85412466aa9b</UserSecretsId>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Aspire.Hosting.AppHost" Version="9.5.0" />
<PackageReference Include="Aspire.Hosting.Redis" Version="9.5.0" />
<PackageReference Include="LocalStack.Aspire.Hosting" Version="9.5.3" />
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\ResidentialBuilding.Generator\ResidentialBuilding.Generator.csproj" />
<ProjectReference Include="..\Client.Wasm\Client.Wasm.csproj" />
<ProjectReference Include="..\ResidentialBuilding.Gateway\ResidentialBuilding.Gateway.csproj" />
<ProjectReference Include="..\ResidentialBuilding.FileService\ResidentialBuilding.FileService.csproj" />
</ItemGroup>

</Project>
8 changes: 8 additions & 0 deletions ResidentialBuilding.AppHost/appsettings.Development.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
}
}
12 changes: 12 additions & 0 deletions ResidentialBuilding.AppHost/appsettings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning",
"Aspire.Hosting.Dcp": "Warning"
}
},
"LocalStack": {
"UseLocalStack": true
}
}
68 changes: 68 additions & 0 deletions ResidentialBuilding.FileService/Controller/S3StorageController.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
using Microsoft.AspNetCore.Mvc;
using System.Text;
using System.Text.Json.Nodes;
using ResidentialBuilding.FileService.Service.Storage;

namespace ResidentialBuilding.FileService.Controller;

/// <summary>
/// Контроллер для взаимодейсвия с S3
/// </summary>
/// <param name="fileService">Служба для работы с S3</param>
/// <param name="logger">Логгер</param>
[ApiController]
[Route("api/s3")]
public class S3StorageController(IFileService fileService, ILogger<S3StorageController> logger) : ControllerBase
{
/// <summary>
/// Метод для получения списка хранящихся в S3 файлов
/// </summary>
/// <returns>Список с ключами файлов</returns>
[HttpGet]
[ProducesResponseType(200)]
[ProducesResponseType(500)]
public async Task<ActionResult<List<string>>> ListFiles()
{
logger.LogInformation("Method {method} of {controller} was called.", nameof(ListFiles),
nameof(S3StorageController));
try
{
var list = await fileService.GetFilesList();

logger.LogInformation("Got a list of {count} files from bucket.", list.Count);
return Ok(list);
}
catch (Exception ex)
{
logger.LogError(ex, "Exception occured during {method} of {controller}.", nameof(ListFiles),
nameof(S3StorageController));
return StatusCode(500, new { message = ex.Message });
}
}

/// <summary>
/// Получает строковое представление хранящегося в S3 документа
/// </summary>
/// <param name="key">Ключ файла</param>
/// <returns>Строковое представление файла</returns>
[HttpGet("{key}")]
[ProducesResponseType(200)]
[ProducesResponseType(500)]
public async Task<ActionResult<JsonNode>> GetFile(string key)
{
logger.LogInformation("Method {method} of {controller} was called.", nameof(GetFile),
nameof(S3StorageController));
try
{
var node = await fileService.DownloadFile(key);
logger.LogInformation("Received json of {size} bytes.", Encoding.UTF8.GetByteCount(node.ToJsonString()));
return Ok(node);
}
catch (Exception ex)
{
logger.LogError(ex, "Exception occured during {method} of {controller}.", nameof(GetFile),
nameof(S3StorageController));
return StatusCode(500, new { message = ex.Message });
}
}
}
Loading