Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- I am trying to implement a decentralized file storage system on ASP and docker. I managed to make a file saving function, it works. But there are problems with the rest of the functions. I managed to implement loading and deleting blocks. But it is not possible to do the same with whole files. I tried different ways, but my queries were looping, or I couldn't get metadata from the workers, or something else. Besides, the exists function doesn't work for me. What is the best way to implement uploading and deleting an entire file, as well as searching for files/blocks?
- Description of my classes:
- ChordNode is a node in the Chord ring that stores the identifier and references to neighbors.
- ChordRing – manages the structure of the Chord ring, adds/deletes nodes, and searches for key owners.
- FingerEntry – describes one entry in the routing table (finger table) for accelerated search in Chord.
- KeyValueController is a controller that works with blocks.
- Metadata – describes meta information about the file: name, size, parts, etc.
- PartMetadata – contains information about a specific block: its index, size, hash, and storage node.
- MetadataService is responsible for storing and managing the metadata of files and their parts.
- WorkerController is a worker controller for processing user requests.
- WorkerFileStorageService – worker storage
- Code:
- 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>
- <link rel="stylesheet" href="css/styles.css">
- </head>
- <body>
- <div class="container">
- <h2>Сохранить файл</h2>
- <input type="file" id="fileInput">
- <button onclick="saveBlock()">Сохранить</button>
- <div class="progress-container" id="uploadProgressContainer">
- <div class=" progress-bar" id="uploadProgressBar"></div>
- </div>
- <p id="uploadStatus"></p>
- <h2>Получить файл</h2>
- <input type="text" id="fileNameDownload" placeholder="Имя файла">
- <button onclick="getBlock()">Получить</button>
- <div class="progress-container" id="downloadProgressContainer">
- <div class="progress-bar" id="downloadProgressBar"></div>
- </div>
- <p id="downloadStatus"></p>
- <h2>Проверка файла</h2>
- <input type="text" id="fileNameCheck" placeholder="Имя файла">
- <button onclick="checkKey()">Проверить</button>
- <p id="searchStatus"></p>
- <h2>Удалить файл</h2>
- <input type="text" id="fileNameDelete" placeholder="Имя файла">
- <button onclick="deleteKey()">Удалить</button>
- <p id="deleteStatus"></p>
- </div>
- <script>
- async function saveBlock() {
- const file = document.getElementById('fileInput').files[0];
- const status = document.getElementById("uploadStatus");
- const progressBar = document.getElementById("uploadProgressBar");
- if (!file) {
- alert("Выберите файл!");
- return;
- }
- progressBar.style.width = "0%";
- status.innerText = "Загрузка...";
- const formData = new FormData();
- formData.append("file", file); // Имя файла берется из объекта file
- const xhr = new XMLHttpRequest();
- xhr.open("POST", "/api/worker/upload", true);
- xhr.upload.onprogress = function (event) {
- if (event.lengthComputable) {
- const percent = event.loaded / event.total * 100;
- progressBar.style.width = percent + "%";
- }
- };
- xhr.onload = () => {
- if (xhr.status === 200) {
- status.innerText = "Файл сохранен!";
- progressBar.style.width = "100%";
- } else {
- status.innerText = "Ошибка!";
- }
- };
- xhr.onerror = () => {
- status.innerText = "Ошибка сети!";
- };
- xhr.send(formData);
- }
- async function getBlock() {
- const fileName = document.getElementById('fileNameDownload').value;
- const status = document.getElementById("downloadStatus");
- const progressBar = document.getElementById("downloadProgressContainer").querySelector(".progress-bar");
- if (!fileName) {
- alert("Введите имя файла!");
- return;
- }
- progressBar.style.width = "0%";
- status.innerText = "Загрузка...";
- const xhr = new XMLHttpRequest();
- xhr.open("GET", `/api/worker/download/${encodeURIComponent(fileName)}`, true);
- xhr.responseType = "blob";
- xhr.onprogress = function (event) {
- if (event.lengthComputable) {
- const percent = event.loaded / event.total * 100;
- progressBar.style.width = percent + "%";
- }
- };
- xhr.onload = function () {
- if (xhr.status === 200) {
- const blob = xhr.response;
- const contentDisposition = xhr.getResponseHeader("Content-Disposition");
- let fileName = "downloaded_file";
- if (contentDisposition) {
- const match = contentDisposition.match(/filename[^;=\n]*=((['"]).*?\2|[^;\n]*)/);
- if (match != null && match[1]) {
- fileName = match[1].replace(/['"]/g, "");
- }
- }
- const link = document.createElement("a");
- link.href = URL.createObjectURL(blob);
- link.download = fileName;
- document.body.appendChild(link);
- link.click();
- document.body.removeChild(link);
- URL.revokeObjectURL(link.href);
- progressBar.style.width = "100%";
- status.innerText = "Файл получен!";
- } else {
- status.innerText = "Файл не найден!";
- }
- };
- xhr.onerror = function () {
- status.innerText = "Ошибка получения файла!";
- };
- xhr.send();
- }
- async function checkKey() {
- const fileName = document.getElementById('fileNameCheck').value;
- const status = document.getElementById("searchStatus");
- try {
- const response = await fetch(`/api/worker/exists/${encodeURIComponent(fileName)}`);
- if (response.ok) {
- status.innerText = "Файл найден";
- } else if (response.status === 404) {
- status.innerText = "Файл не найден";
- } else {
- status.innerText = "Ошибка при проверке!";
- }
- } catch (error) {
- status.innerText = "Ошибка запроса!";
- }
- }
- async function deleteKey() {
- const fileName = document.getElementById('fileNameDelete').value;
- const status = document.getElementById("deleteStatus");
- try {
- const response = await fetch(`/api/worker/delete/${encodeURIComponent(fileName)}`, {
- method: "DELETE"
- });
- if (response.ok) {
- status.innerText = "Файл удалён";
- } else if (response.status === 404) {
- status.innerText = "Файл не найден!";
- } else {
- status.innerText = "Ошибка удаления!";
- }
- } catch (error) {
- status.innerText = "Ошибка запроса!";
- }
- }
- </script>
- </body>
- </html>
- 2) Docker-compose.yml:
- services:
- worker1:
- container_name: worker1
- image: myapp
- environment:
- - ASPNETCORE_URLS=http://+:5001
- - CURRENT_NODE_URL=http://worker1:5001
- ports:
- - "5001:5001"
- networks:
- - app_net
- volumes:
- - worker1_storage:/app/storage
- - worker1_metadata:/app/local_metadata
- deploy:
- restart_policy:
- condition: on-failure
- worker2:
- container_name: worker2
- image: myapp
- environment:
- - ASPNETCORE_URLS=http://+:5002
- - CURRENT_NODE_URL=http://worker2:5002
- ports:
- - "5002:5002"
- networks:
- - app_net
- volumes:
- - worker2_storage:/app/storage
- - worker2_metadata:/app/local_metadata
- deploy:
- restart_policy:
- condition: on-failure
- worker3:
- container_name: worker3
- image: myapp
- environment:
- - ASPNETCORE_URLS=http://+:5003
- - CURRENT_NODE_URL=http://worker3:5003
- ports:
- - "5003:5003"
- networks:
- - app_net
- volumes:
- - worker3_storage:/app/storage
- - worker3_metadata:/app/local_metadata
- deploy:
- restart_policy:
- condition: on-failure
- worker4:
- container_name: worker4
- image: myapp
- environment:
- - ASPNETCORE_URLS=http://+:5004
- - CURRENT_NODE_URL=http://worker4:5004
- ports:
- - "5004:5004"
- networks:
- - app_net
- volumes:
- - worker4_storage:/app/storage
- - worker4_metadata:/app/local_metadata
- deploy:
- restart_policy:
- condition: on-failure
- worker5:
- container_name: worker5
- image: myapp
- environment:
- - ASPNETCORE_URLS=http://+:5005
- - CURRENT_NODE_URL=http://worker5:5005
- ports:
- - "5005:5005"
- networks:
- - app_net
- volumes:
- - worker5_storage:/app/storage
- - worker5_metadata:/app/local_metadata
- deploy:
- restart_policy:
- condition: on-failure
- networks:
- app_net:
- driver: bridge
- volumes:
- worker1_storage:
- worker2_storage:
- worker3_storage:
- worker4_storage:
- worker5_storage:
- worker1_metadata:
- worker2_metadata:
- worker3_metadata:
- worker4_metadata:
- worker5_metadata:
- 3) ChordNode.cs:
- using DistributedSystems_Lab4;
- public class ChordNode
- {
- public int Id { get; }
- public string Url { get; }
- public ChordNode? Successor { get; set; }
- public ChordNode? Predecessor { get; set; }
- public List<FingerEntry> FingerTable { get; set; }
- private readonly MetadataService metadataService;
- // Конструктор
- public ChordNode(int id, string url)
- {
- Id = id;
- Url = url;
- FingerTable = new List<FingerEntry>();
- metadataService = new MetadataService();
- }
- public void AddMetadata(string key, Metadata metadata)
- {
- metadataService.SaveFileMetadata(key, metadata.Parts);
- }
- public Metadata? GetMetadata(string key)
- {
- var parts = metadataService.GetFileMetadata(key);
- if (parts == null)
- return null;
- return new Metadata
- {
- FileName = key,
- Parts = parts
- };
- }
- public void RemoveMetadata(string key)
- {
- metadataService.DeleteFileMetadata(key);
- }
- public override string ToString() => $"{Url} ({Id})";
- }
- 4) ChordRing.cs:
- using DistributedSystems_Lab4;
- using System.Collections.Generic;
- using System.Linq;
- using System.Security.Cryptography;
- using System.Text;
- public class ChordRing
- {
- private readonly List<ChordNode> nodes = new List<ChordNode>();
- private readonly int m = 5; // Количество бит для хэширования
- public void InitializeFingerTables()
- {
- foreach (var node in nodes)
- {
- node.FingerTable.Clear();
- for (int i = 0; i < m; i++)
- {
- int start = (node.Id + (int)Math.Pow(2, i)) % (int)Math.Pow(2, m);
- node.FingerTable.Add(new FingerEntry { Start = start, Node = FindNodeForFingerTable(start) });
- }
- }
- }
- private ChordNode FindNodeForFingerTable(int start)
- {
- var node = nodes.BinarySearch(new ChordNode(start, ""), Comparer<ChordNode>.Create((a, b) => a.Id.CompareTo(b.Id)));
- if (node < 0) node = ~node;
- return node < nodes.Count ? nodes[node] : nodes[0];
- }
- // Добавляем узел
- public void AddNode(string url)
- {
- int id = Hash(url);
- if (nodes.Any(n => n.Id == id)) return;
- var newNode = new ChordNode(id, url);
- nodes.Add(newNode);
- nodes.Sort((a, b) => a.Id.CompareTo(b.Id));
- UpdateLinks();
- InitializeFingerTables();
- }
- public void RemoveNode(string url)
- {
- int index = nodes.FindIndex(n => n.Url == url);
- if (index >= 0)
- {
- nodes.RemoveAt(index);
- UpdateLinks();
- InitializeFingerTables();
- }
- }
- private void UpdateLinks()
- {
- int count = nodes.Count;
- for (int i = 0; i < count; i++)
- {
- var current = nodes[i];
- current.Successor = nodes[(i + 1) % count];
- current.Predecessor = nodes[(i - 1 + count) % count];
- }
- }
- public ChordNode FindResponsibleNode(string key)
- {
- int keyHash = Hash(key);
- var node = nodes.BinarySearch(new ChordNode(keyHash, ""), Comparer<ChordNode>.Create((a, b) => a.Id.CompareTo(b.Id)));
- if (node < 0) node = ~node;
- return node < nodes.Count ? nodes[node] : nodes[0];
- }
- public void ReplicateMetadata(string key, Metadata metadata)
- {
- var node = FindResponsibleNode(key);
- node.AddMetadata(key, metadata);
- node.Successor?.AddMetadata(key, metadata);
- node.Predecessor?.AddMetadata(key, metadata);
- }
- public static int Hash(string input)
- {
- using var sha1 = SHA1.Create();
- var hash = sha1.ComputeHash(Encoding.UTF8.GetBytes(input));
- return Math.Abs(BitConverter.ToInt32(hash, 0));
- }
- public IEnumerable<ChordNode> GetAllNodes() => nodes;
- }
- 5) FingerEntry.cs:
- namespace DistributedSystems_Lab4
- {
- public class FingerEntry
- {
- public int Start { get; set; }
- public ChordNode? Node { get; set; }
- }
- }
- 6) Metadata.cs:
- namespace DistributedSystems_Lab4
- {
- public class Metadata
- {
- public string FileName { get; set; }
- public List<PartMetadata> Parts { get; set; } = new List<PartMetadata>();
- }
- }
- 7) PartMetadata.cs:
- namespace DistributedSystems_Lab4
- {
- public class PartMetadata
- {
- public string Chunk { get; set; } = "";
- public string PartName { get; set; } = "";
- public string WorkerUrl { get; set; } = "";
- public PartMetadata() { }
- public PartMetadata(string chunk, string partName, string workerUrl)
- {
- Chunk = chunk;
- PartName = partName;
- WorkerUrl = workerUrl;
- }
- }
- }
- 8) MetadataService.cs:
- using System.Text.Json;
- namespace DistributedSystems_Lab4
- {
- public class MetadataService
- {
- private readonly string metadataPath = "/app/local_metadata/";
- private Dictionary<string, List<PartMetadata>> fileMetadata = new();
- public MetadataService()
- {
- if (!Directory.Exists(metadataPath))
- Directory.CreateDirectory(metadataPath);
- LoadMetadata();
- }
- public void SaveFileMetadata(string key, List<PartMetadata> metadata)
- {
- LoadMetadata(); // обязательно перед изменением
- fileMetadata[key] = metadata;
- SaveMetadata();
- }
- public List<PartMetadata>? GetFileMetadata(string key)
- {
- LoadMetadata();
- return fileMetadata.TryGetValue(key, out var metadata) ? metadata : null;
- }
- public void DeleteFileMetadata(string key)
- {
- LoadMetadata();
- if (fileMetadata.ContainsKey(key))
- {
- fileMetadata.Remove(key);
- SaveMetadata();
- }
- }
- private void SaveMetadata()
- {
- var path = Path.Combine(metadataPath, "metadata.json");
- var json = JsonSerializer.Serialize(fileMetadata);
- File.WriteAllText(path, json);
- }
- private void LoadMetadata()
- {
- var path = Path.Combine(metadataPath, "metadata.json");
- if (File.Exists(path))
- {
- var json = File.ReadAllText(path);
- fileMetadata = JsonSerializer.Deserialize<Dictionary<string, List<PartMetadata>>>(json)
- ?? new Dictionary<string, List<PartMetadata>>();
- }
- else
- {
- fileMetadata = new Dictionary<string, List<PartMetadata>>();
- SaveMetadata(); // Создать пустой
- }
- }
- }
- }
- 9) WorkerController.cs:
- using Microsoft.AspNetCore.Mvc;
- using Microsoft.Extensions.Logging;
- using System.IO;
- using System.Net.Http;
- using System.Text.RegularExpressions;
- using System.Threading.Tasks;
- using System.Linq;
- using System.Security.Cryptography;
- using System.Text.Json;
- using System.Collections.Generic;
- namespace DistributedSystems_Lab4
- {
- [ApiController]
- [Route("api/worker")]
- public class WorkerController : ControllerBase
- {
- private readonly WorkerFileStorageService workerStorage;
- private readonly IHttpClientFactory httpClientFactory;
- private readonly ILogger logger;
- public WorkerController(WorkerFileStorageService workerStorage, ILogger<WorkerController> logger, IHttpClientFactory httpClientFactory)
- {
- this.workerStorage = workerStorage;
- this.logger = logger;
- this.httpClientFactory = httpClientFactory;
- }
- [HttpPost("upload")]
- public async Task<IActionResult> Upload([FromForm] IFormFile file)
- {
- if (file == null || file.Length == 0)
- return BadRequest("Файл пустой");
- const int blockSize = 5 * 1024 * 1024;
- var chord = workerStorage.getChordRing();
- var client = httpClientFactory.CreateClient();
- var allMetadataList = new List<PartMetadata>();
- var localMetadataList = new List<PartMetadata>();
- string currentUrl = Environment.GetEnvironmentVariable("CURRENT_NODE_URL") ?? "unknown";
- int index = 0;
- byte[] buffer = new byte[blockSize];
- using var stream = file.OpenReadStream();
- int bytesRead;
- while ((bytesRead = await stream.ReadAsync(buffer, 0, buffer.Length)) > 0)
- {
- var partName = $"{file.FileName}_part_{index}";
- var node = chord.FindResponsibleNode(partName);
- var blockStream = new MemoryStream(buffer, 0, bytesRead);
- var content = new MultipartFormDataContent();
- content.Add(new StreamContent(blockStream), "file", partName);
- var response = await client.PutAsync($"{node.Url}/store/{partName}?fileName={file.FileName}", content);
- if (response.IsSuccessStatusCode)
- {
- var meta = new PartMetadata
- {
- Chunk = ComputeHash(buffer, bytesRead),
- PartName = partName,
- WorkerUrl = node.Url
- };
- allMetadataList.Add(meta);
- if (node.Url == currentUrl)
- localMetadataList.Add(meta);
- }
- index++;
- }
- if (localMetadataList.Any())
- workerStorage.SaveMetadata(file.FileName, localMetadataList);
- else
- workerStorage.SaveMetadata(file.FileName, new List<PartMetadata>()); // пустой файл
- return Ok($"Загружено {allMetadataList.Count} блоков");
- }
- private string ComputeHash(byte[] buffer, int length)
- {
- using var sha1 = SHA1.Create();
- var hash = sha1.ComputeHash(buffer, 0, length);
- return BitConverter.ToString(hash).Replace("-", "").ToLowerInvariant();
- }
- [HttpGet("download/{name}")]
- public async Task<IActionResult> Download(string name)
- {
- var client = httpClientFactory.CreateClient();
- if (name.Contains("part"))
- {
- var stream = await workerStorage.GetBlockAsync(name);
- if (stream != null)
- return File(stream, "application/octet-stream", name);
- var nextUrl = GetNextWorkerUrl();
- if (nextUrl != null)
- {
- var response = await client.GetAsync($"{nextUrl}/api/worker/download/{name}");
- if (response.IsSuccessStatusCode)
- return File(await response.Content.ReadAsStreamAsync(), "application/octet-stream", name);
- }
- return NotFound("Блок не найден");
- }
- else
- {
- var allBlocks = workerStorage.ListBlocks()
- .Where(b => b.StartsWith(name + "_part_"))
- .OrderBy(b => ExtractPartIndex(b))
- .ToList();
- if (!allBlocks.Any())
- {
- var nextUrl = GetNextWorkerUrl();
- if (nextUrl != null)
- {
- var response = await client.GetAsync($"{nextUrl}/api/worker/download/{name}");
- if (response.IsSuccessStatusCode)
- return File(await response.Content.ReadAsStreamAsync(), "application/octet-stream", name);
- }
- return NotFound("Файл не найден");
- }
- var memoryStream = new MemoryStream();
- foreach (var part in allBlocks)
- {
- var stream = await workerStorage.GetBlockAsync(part);
- if (stream != null)
- await stream.CopyToAsync(memoryStream);
- }
- memoryStream.Position = 0;
- return File(memoryStream, "application/octet-stream", name);
- }
- }
- [HttpDelete("delete/{name}")]
- public async Task<IActionResult> Delete(string name)
- {
- var client = httpClientFactory.CreateClient();
- if (name.Contains("part"))
- {
- if (workerStorage.HasBlock(name))
- {
- var deleted = workerStorage.DeleteBlock(name);
- if (deleted)
- return Ok("Блок удалён.");
- }
- var nextUrl = GetNextWorkerUrl();
- if (nextUrl != null)
- {
- var response = await client.DeleteAsync($"{nextUrl}/api/worker/delete/{name}");
- if (response.IsSuccessStatusCode)
- return Ok("Удалён другим воркером");
- }
- return NotFound("Блок не найден");
- }
- else
- {
- var allNodes = GetAllWorkerUrls();
- var allParts = new List<PartMetadata>();
- foreach (var nodeUrl in allNodes)
- {
- try
- {
- var metaResponse = await client.GetAsync($"{nodeUrl}/api/worker/meta/{name}");
- if (metaResponse.IsSuccessStatusCode)
- {
- var json = await metaResponse.Content.ReadAsStringAsync();
- var parts = JsonSerializer.Deserialize<List<PartMetadata>>(json);
- if (parts != null)
- allParts.AddRange(parts);
- }
- }
- catch { }
- }
- bool allDeleted = true;
- foreach (var part in allParts)
- {
- try
- {
- var del = await client.DeleteAsync($"{part.WorkerUrl}/store/{part.PartName}");
- if (!del.IsSuccessStatusCode)
- allDeleted = false;
- }
- catch { allDeleted = false; }
- }
- return allDeleted ? Ok("Удалено") : StatusCode(500, "Удаление частично");
- }
- }
- [HttpGet("exists/{name}")]
- public IActionResult Exists(string name)
- {
- return workerStorage.HasBlock(name) ? Ok("Есть") : NotFound("Нет");
- }
- [HttpGet("meta/{name}")]
- public IActionResult GetMetadata(string name)
- {
- var meta = workerStorage.GetMetadata(name);
- return meta == null ? NotFound("Нет") : Ok(meta);
- }
- [HttpGet("listFiles")]
- public IActionResult List()
- {
- return Ok(workerStorage.ListBlocks());
- }
- private int ExtractPartIndex(string partName)
- {
- var match = Regex.Match(partName, @"_part_(\\d+)$");
- return match.Success ? int.Parse(match.Groups[1].Value) : 0;
- }
- private string? GetNextWorkerUrl()
- {
- var current = Environment.GetEnvironmentVariable("CURRENT_NODE_URL");
- var all = GetAllWorkerUrls();
- int index = Array.IndexOf(all, current);
- return index == -1 ? null : all[(index + 1) % all.Length];
- }
- private string[] GetAllWorkerUrls() => new[]
- {
- "http://worker1:5001",
- "http://worker2:5002",
- "http://worker3:5003",
- "http://worker4:5004",
- "http://worker5:5005"
- };
- }
- }
- 10) WorkerFileStorageService.cs:
- using Microsoft.AspNetCore.Http;
- using Microsoft.Extensions.Logging;
- using System.IO;
- using System.Threading.Tasks;
- using System.Collections.Generic;
- using System.Linq;
- namespace DistributedSystems_Lab4
- {
- public class WorkerFileStorageService
- {
- private readonly ILogger logger;
- private readonly MetadataService metadataService;
- private readonly string storagePath = "/app/storage/";
- private readonly ChordRing chordRing;
- public WorkerFileStorageService(ILogger<WorkerFileStorageService> logger, MetadataService metadataService)
- {
- this.logger = logger;
- this.metadataService = metadataService;
- this.chordRing = new ChordRing();
- if (!Directory.Exists(storagePath))
- Directory.CreateDirectory(storagePath);
- InitializeChordRing();
- }
- private void InitializeChordRing()
- {
- var nodeUrls = new[]
- {
- "http://worker1:5001",
- "http://worker2:5002",
- "http://worker3:5003",
- "http://worker4:5004",
- "http://worker5:5005"
- };
- foreach (var url in nodeUrls)
- {
- chordRing.AddNode(url);
- logger.LogInformation($"Добавлен узел в ChordRing: {url}");
- }
- chordRing.InitializeFingerTables();
- }
- public ChordRing getChordRing() => chordRing;
- public void SaveMetadata(string fileName, List<PartMetadata> parts)
- {
- metadataService.SaveFileMetadata(fileName, parts);
- }
- public List<PartMetadata>? GetMetadata(string key)
- {
- return metadataService.GetFileMetadata(key);
- }
- // перегрузка SaveBlockAsync с fileName
- public async Task SaveBlockAsync(string blockName, IFormFile file, string fileName)
- {
- var path = Path.Combine(storagePath, blockName);
- using var stream = new FileStream(path, FileMode.Create);
- await file.CopyToAsync(stream);
- var partMeta = new PartMetadata
- {
- Chunk = blockName.GetHashCode().ToString(),
- PartName = blockName,
- WorkerUrl = Environment.GetEnvironmentVariable("CURRENT_NODE_URL") ?? "unknown"
- };
- // Сохраняем по ИМЕНИ ФАЙЛА, а не по имени блока
- var existing = metadataService.GetFileMetadata(fileName) ?? new List<PartMetadata>();
- existing.Add(partMeta);
- metadataService.SaveFileMetadata(fileName, existing);
- }
- public async Task<Stream?> GetBlockAsync(string name)
- {
- string path = Path.Combine(storagePath, name);
- try
- {
- if (File.Exists(path))
- {
- return new FileStream(path, FileMode.Open, FileAccess.Read);
- }
- }
- catch (Exception ex)
- {
- logger.LogError($"Ошибка при загрузке блока {name}: {ex.Message}");
- }
- return null;
- }
- public bool HasBlock(string name)
- {
- string path = Path.Combine(storagePath, name);
- return File.Exists(path);
- }
- public bool DeleteBlock(string name)
- {
- string path = Path.Combine(storagePath, name);
- if (File.Exists(path))
- {
- File.Delete(path);
- metadataService.DeleteFileMetadata(name);
- return true;
- }
- return false;
- }
- public IEnumerable<string> ListBlocks()
- {
- return Directory.GetFiles(storagePath).Select(Path.GetFileName);
- }
- }
- }
- 11) Program.cs:
- using DistributedSystems_Lab4;
- using Microsoft.AspNetCore.Builder;
- using Microsoft.AspNetCore.DataProtection;
- using Microsoft.AspNetCore.Hosting;
- using Microsoft.AspNetCore.Http;
- using Microsoft.AspNetCore.Http.Features;
- using Microsoft.Extensions.DependencyInjection;
- using Microsoft.Extensions.Hosting;
- using Microsoft.Extensions.Logging;
- using System;
- var builder = WebApplication.CreateBuilder(args);
- builder.Logging.ClearProviders();
- builder.Logging.AddSimpleConsole(options =>
- {
- options.IncludeScopes = false;
- options.SingleLine = true;
- options.TimestampFormat = "yyyy-MM-dd HH:mm:ss ";
- });
- builder.Services.AddMvc();
- builder.Services.Configure<Microsoft.AspNetCore.Http.Features.FormOptions>(options =>
- {
- options.MultipartBodyLengthLimit = 10L * 1024 * 1024 * 1024; // 10GB
- });
- builder.WebHost.ConfigureKestrel(serverOptions =>
- {
- serverOptions.Limits.MaxRequestBodySize = 10L * 1024 * 1024 * 1024; // 10GB
- });
- builder.Services.Configure<FormOptions>(o =>
- {
- o.MultipartBodyLengthLimit = 10L * 1024 * 1024 * 1024; // 50 MB
- });
- builder.Services.AddControllers();
- builder.Services.AddHttpClient();
- builder.Services.AddSingleton<WorkerFileStorageService>();
- builder.Services.AddSingleton<FingerEntry>();
- builder.Services.AddSingleton<MetadataService>();
- var app = builder.Build();
- app.Logger.LogInformation("Start");
- 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