Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- Dockerfile:
- # Базовый образ для запуска
- FROM mcr.microsoft.com/dotnet/aspnet:9.0 AS base
- WORKDIR /app
- EXPOSE 5000
- # Образ для сборки
- FROM mcr.microsoft.com/dotnet/sdk:9.0 AS build
- WORKDIR /src
- # Копируем файл проекта
- COPY DistributedSystems_Lab3.csproj ./
- RUN dotnet restore DistributedSystems_Lab3.csproj
- # Копируем исходный код
- COPY . .
- RUN dotnet build DistributedSystems_Lab3.csproj -c Release -o /app/build
- # Публикация
- FROM build AS publish
- RUN dotnet publish DistributedSystems_Lab3.csproj -c Release -o /app/publish /p:UseAppHost=false
- # Финальный контейнер
- FROM base AS final
- WORKDIR /app
- COPY --from=publish /app/publish .
- # Запуск
- CMD ["dotnet", "DistributedSystems_Lab3.dll"]
- docker-compose.yml:
- services:
- central:
- container_name: central
- image: myapp
- environment:
- - NodeRole=central
- - ASPNETCORE_URLS=http://+:5000
- ports:
- - "5000:5000"
- networks:
- - app_net
- deploy:
- restart_policy:
- condition: on-failure
- worker1:
- container_name: worker1
- image: myapp
- environment:
- - NodeRole=worker
- - ASPNETCORE_URLS=http://+:5001
- networks:
- - app_net
- volumes:
- - worker1_storage:/app/storage
- deploy:
- restart_policy:
- condition: on-failure
- worker2:
- container_name: worker2
- image: myapp
- environment:
- - NodeRole=worker
- - ASPNETCORE_URLS=http://+:5002
- networks:
- - app_net
- volumes:
- - worker2_storage:/app/storage
- deploy:
- restart_policy:
- condition: on-failure
- worker3:
- container_name: worker3
- image: myapp
- environment:
- - NodeRole=worker
- - ASPNETCORE_URLS=http://+:5003
- networks:
- - app_net
- volumes:
- - worker3_storage:/app/storage
- deploy:
- restart_policy:
- condition: on-failure
- networks:
- app_net:
- driver: bridge
- volumes:
- worker1_storage:
- worker2_storage:
- worker3_storage:
- index.html:
- <!DOCTYPE html>
- <html lang="ru">
- <head>
- <meta charset="UTF-8">
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
- <title>Файловая система</title>
- </head>
- <body>
- <h2>Загрузка файла</h2>
- <input type="file" id="fileInput">
- <button onclick="uploadFile()">Загрузить</button>
- <progress id="uploadProgress" value="0" max="100" style="display: none; width: 100%;"></progress>
- <p id="uploadStatus"></p>
- <h2>Скачать файл</h2>
- <input type="text" id="fileName" placeholder="Имя файла">
- <button onclick="downloadFile()">Скачать</button>
- <p id="downloadStatus"></p>
- <script>
- async function uploadFile() {
- let file = document.getElementById('fileInput').files[0];
- let progressBar = document.getElementById("uploadProgress");
- let statusText = document.getElementById("uploadStatus");
- if (!file) {
- alert("Выберите файл");
- return;
- }
- progressBar.style.display = "block";
- progressBar.value = 0;
- statusText.innerText = "Загрузка началась...";
- let formData = new FormData();
- formData.append("file", file);
- try {
- let response = await fetch('/api/file/save', {
- method: 'POST',
- body: formData
- });
- if (!response.ok) {
- throw new Error(`Ошибка загрузки: ${response.statusText}`);
- }
- let result = await response.text();
- alert(result);
- statusText.innerText = "Загрузка завершена!";
- } catch (error) {
- console.error("Ошибка загрузки:", error);
- alert("Ошибка загрузки файла.");
- statusText.innerText = "Ошибка загрузки!";
- } finally {
- progressBar.style.display = "none"; // Скрыть индикатор
- }
- }
- async function downloadFile() {
- let fileName = document.getElementById('fileName').value;
- if (!fileName) {
- alert("Введите имя файла");
- return;
- }
- let response = await fetch(`/api/file/download/${fileName}`);
- if (response.status == 200) {
- let blob = await response.blob();
- let link = document.createElement("a");
- link.href = window.URL.createObjectURL(blob);
- link.download = fileName;
- document.body.appendChild(link);
- link.click();
- document.body.removeChild(link);
- } else {
- alert("Файл не найден");
- }
- }
- </script>
- </body>
- </html>
- CentralFileStorageService:
- using Microsoft.AspNetCore.Mvc;
- namespace DistributedSystems_Lab3
- {
- public class CentralFileStorageService
- {
- private readonly HttpClient _httpClient;
- private readonly List<string> _workerUrls = new()
- {
- "http://worker1:5001",
- "http://worker2:5002",
- "http://worker3:5003"
- };
- public CentralFileStorageService(HttpClient httpClient)
- {
- _httpClient = httpClient;
- }
- public async Task UploadFile(IFormFile file)
- {
- int partSize = 5 * 1024 * 1024; // 5 MB
- int index = 0;
- string filename = file.FileName;
- using var stream = file.OpenReadStream();
- var buffer = new byte[partSize];
- while (true)
- {
- int bytesRead = await stream.ReadAsync(buffer, 0, buffer.Length);
- if (bytesRead == 0) break;
- var worker = _workerUrls[index % _workerUrls.Count];
- using var content = new MultipartFormDataContent
- {
- { new ByteArrayContent(buffer, 0, bytesRead), "file", $"{filename}_part{index}" }
- };
- await _httpClient.PostAsync($"{worker}/api/worker/save", content);
- index++;
- }
- }
- public async Task<FileResult?> DownloadFile(string filename)
- {
- List<byte[]> fileParts = new();
- // Запрашиваем части у всех worker-ов
- for (int i = 0; i < _workerUrls.Count; i++)
- {
- string partName = $"{filename}_part{i}";
- foreach (var worker in _workerUrls)
- {
- try
- {
- HttpResponseMessage response = await _httpClient.GetAsync($"{worker}/api/storage/load/{partName}");
- if (response.IsSuccessStatusCode)
- {
- byte[] partData = await response.Content.ReadAsByteArrayAsync();
- fileParts.Add(partData);
- break; // Если часть найдена, не запрашиваем у других worker-ов
- }
- }
- catch (Exception ex)
- {
- Console.WriteLine($"Ошибка при загрузке части {partName}: {ex.Message}");
- }
- }
- }
- if (fileParts.Count == 0)
- return null; // Файл не найден
- // Объединяем части в один файл
- byte[] fullFile = fileParts.SelectMany(part => part).ToArray();
- // Отправляем файл пользователю
- return new FileContentResult(fullFile, "application/octet-stream")
- {
- FileDownloadName = filename
- };
- }
- }
- }
- WorkerFileStorageService:
- using Microsoft.AspNetCore.Mvc;
- namespace DistributedSystems_Lab3
- {
- public class WorkerFileStorageService
- {
- private readonly HttpClient _httpClient;
- private readonly string _storagePath = "/app/storage/";
- public WorkerFileStorageService(HttpClient httpClient)
- {
- _httpClient = httpClient;
- }
- // Метод загрузки файла на worker
- public async Task UploadFile(IFormFile file)
- {
- string path = Path.Combine(_storagePath, file.FileName);
- using var stream = new FileStream(path, FileMode.Create);
- await file.CopyToAsync(stream);
- }
- // Метод для получения части файла
- public async Task<byte[]?> GetFilePart(string filename)
- {
- string path = Path.Combine(_storagePath, filename);
- if (!File.Exists(path))
- return null;
- return await File.ReadAllBytesAsync(path);
- }
- }
- }
- FileController:
- using Microsoft.AspNetCore.Mvc;
- namespace DistributedSystems_Lab3
- {
- [Route("api/file")]
- [ApiController]
- public class FileController : ControllerBase
- {
- private readonly CentralFileStorageService _storageService;
- public FileController(CentralFileStorageService storageService)
- {
- _storageService = storageService;
- }
- [HttpPost("save")]
- public async Task<IActionResult> UploadFile([FromForm] IFormFile file)
- {
- if (file == null)
- return BadRequest("Файл не загружен");
- await _storageService.UploadFile(file);
- return Ok($"Файл {file.FileName} загружен");
- }
- [HttpGet("download/{filename}")]
- public async Task<IActionResult> DownloadFile(string filename)
- {
- var file = await _storageService.DownloadFile(filename);
- if (file == null)
- return NotFound("Файл не найден");
- return file;
- }
- }
- }
- WorkerController:
- using Microsoft.AspNetCore.Mvc;
- namespace DistributedSystems_Lab3
- {
- [Route("api/worker")]
- [ApiController]
- public class WorkerController : ControllerBase
- {
- private readonly WorkerFileStorageService _workerStorage;
- public WorkerController(WorkerFileStorageService workerStorage)
- {
- _workerStorage = workerStorage;
- }
- //загрузка файла на воркеры через HTTP
- [HttpPost("save")]
- public async Task<IActionResult> SaveFile([FromForm] IFormFile file)
- {
- if (file == null)
- return BadRequest("Файл не загружен");
- await _workerStorage.UploadFile(file);
- return Ok("Файл сохранен");
- }
- //скачивание файла с воркера через HTTP
- [HttpGet("load/{filename}")]
- public async Task<IActionResult> LoadFile(string filename)
- {
- var filePart = await _workerStorage.GetFilePart(filename);
- if (filePart == null)
- return NotFound("Часть файла не найдена");
- return File(filePart, "application/octet-stream", filename);
- }
- }
- }
- Program.cs:
- using DistributedSystems_Lab3;
- using Microsoft.AspNetCore.Builder;
- using Microsoft.AspNetCore.Hosting;
- using Microsoft.AspNetCore.Http;
- using Microsoft.Extensions.DependencyInjection;
- using Microsoft.Extensions.Hosting;
- using Microsoft.Extensions.Logging;
- using System;
- var builder = WebApplication.CreateBuilder(args);
- string nodeRole = Environment.GetEnvironmentVariable("NodeRole") ?? "worker";
- Console.WriteLine($"Node Role: {nodeRole}");
- builder.Services.AddMvc();
- builder.Services.AddControllers();
- builder.Services.AddSingleton<HttpClient>();
- // Условная регистрация сервисов в зависимости от роли узла
- if (nodeRole == "central")
- {
- builder.Services.AddSingleton<CentralFileStorageService>();
- }
- else
- {
- builder.Services.AddSingleton<WorkerFileStorageService>();
- }
- var app = builder.Build();
- app.MapGet("/", () => Results.Redirect("/index.html"));
- app.UseStaticFiles();
- app.UseRouting();
- app.UseAuthorization();
- app.MapControllers();
- app.Run();
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement