Created download systems, for files.
This commit is contained in:
parent
f468af89e0
commit
f311e14ec1
|
|
@ -114,4 +114,14 @@ public class FilesController(
|
||||||
|
|
||||||
return RedirectToAction("Index");
|
return RedirectToAction("Index");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async Task<IActionResult> Download(Guid id)
|
||||||
|
{
|
||||||
|
|
||||||
|
var filename = await fileRepository.GetFileName(id);
|
||||||
|
|
||||||
|
var stream = fileRepository.EnumerateFileContentsAsync(id);
|
||||||
|
|
||||||
|
return File(stream, "application/octet-stream", filename);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1,3 +1,4 @@
|
||||||
|
using System.Security.Cryptography.X509Certificates;
|
||||||
using FileStorageService.www.Data;
|
using FileStorageService.www.Data;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
|
@ -8,7 +9,7 @@ public class FileRepository(ApplicationDbContext context)
|
||||||
{
|
{
|
||||||
public static readonly int MAX_BLOCKS = 10_485_760;
|
public static readonly int MAX_BLOCKS = 10_485_760;
|
||||||
|
|
||||||
private readonly Queue<(string, Stream)> _creationQueue = new();
|
private readonly Queue<(string, Stream, TaskCompletionSource<Guid?>)> _creationQueue = new();
|
||||||
private readonly Lock _countLock = new();
|
private readonly Lock _countLock = new();
|
||||||
|
|
||||||
public async Task<List<FileHandle>> GetAllFilesAsync()
|
public async Task<List<FileHandle>> GetAllFilesAsync()
|
||||||
|
|
@ -23,60 +24,89 @@ public class FileRepository(ApplicationDbContext context)
|
||||||
.Include(e => e.FileBlocks).FirstAsync();
|
.Include(e => e.FileBlocks).FirstAsync();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Task<string> GetFileName(Guid id)
|
||||||
|
{
|
||||||
|
return (from handle in context.FileHandles
|
||||||
|
where handle.Id == id
|
||||||
|
select handle.Name).FirstAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Stream EnumerateFileContentsAsync(Guid id)
|
||||||
|
{
|
||||||
|
|
||||||
|
var memoryStream = new MemoryStream();
|
||||||
|
var writer = new BinaryWriter(memoryStream);
|
||||||
|
|
||||||
|
var query = (from block in context.FileBlocks
|
||||||
|
where block.FileHandle.Id == id
|
||||||
|
orderby block.BlockNumber
|
||||||
|
select block.Data);
|
||||||
|
|
||||||
|
foreach (var bytes in query.AsEnumerable())
|
||||||
|
{
|
||||||
|
writer.Write(bytes);
|
||||||
|
writer.Flush();
|
||||||
|
}
|
||||||
|
|
||||||
|
memoryStream.Position = 0;
|
||||||
|
|
||||||
|
return memoryStream;
|
||||||
|
}
|
||||||
|
|
||||||
public Task<Guid?> TryNewFileAsync(string name, Stream reader)
|
public Task<Guid?> TryNewFileAsync(string name, Stream reader)
|
||||||
{
|
{
|
||||||
var tcs = new TaskCompletionSource<Guid?>();
|
var tcs = new TaskCompletionSource<Guid?>();
|
||||||
|
|
||||||
lock (_creationQueue)
|
lock (_creationQueue)
|
||||||
{
|
{
|
||||||
_creationQueue.Enqueue((name, reader));
|
_creationQueue.Enqueue((name, reader, tcs));
|
||||||
}
|
}
|
||||||
|
|
||||||
Task.Run(async () =>
|
Task.Run(async () => await StartProcessFileUpload());
|
||||||
{
|
|
||||||
|
|
||||||
Stream stream;
|
|
||||||
string name;
|
|
||||||
|
|
||||||
lock (_creationQueue)
|
|
||||||
{
|
|
||||||
(name, stream) = _creationQueue.Dequeue();
|
|
||||||
}
|
|
||||||
|
|
||||||
var fileHandle = new FileHandle
|
|
||||||
{
|
|
||||||
Name = name
|
|
||||||
};
|
|
||||||
|
|
||||||
var handle = await CreateFileBlocks(stream, fileHandle);
|
|
||||||
var currentFileCount = handle.FileBlocks.Count();
|
|
||||||
handle.FileBlockCount = currentFileCount;
|
|
||||||
|
|
||||||
lock (_countLock)
|
|
||||||
{
|
|
||||||
var count = context.FileBlocks.Count();
|
|
||||||
|
|
||||||
if (count+currentFileCount > MAX_BLOCKS)
|
|
||||||
{
|
|
||||||
tcs.SetResult(null);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
context.Add(fileHandle);
|
|
||||||
context.SaveChangesAsync();
|
|
||||||
|
|
||||||
tcs.SetResult(fileHandle.Id);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
return tcs.Task;
|
return tcs.Task;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private async Task StartProcessFileUpload()
|
||||||
|
{
|
||||||
|
Stream stream;
|
||||||
|
string name;
|
||||||
|
TaskCompletionSource<Guid?> tcs;
|
||||||
|
|
||||||
|
lock (_creationQueue)
|
||||||
|
{
|
||||||
|
(name, stream, tcs) = _creationQueue.Dequeue();
|
||||||
|
}
|
||||||
|
|
||||||
|
var fileHandle = new FileHandle
|
||||||
|
{
|
||||||
|
Name = name
|
||||||
|
};
|
||||||
|
|
||||||
|
var handle = await CreateFileBlocks(stream, fileHandle);
|
||||||
|
var currentFileCount = handle.FileBlocks.Count();
|
||||||
|
handle.FileBlockCount = currentFileCount;
|
||||||
|
|
||||||
|
lock (_countLock)
|
||||||
|
{
|
||||||
|
var count = context.FileBlocks.Count();
|
||||||
|
|
||||||
|
if (count+currentFileCount > MAX_BLOCKS)
|
||||||
|
{
|
||||||
|
tcs.SetResult(null);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
context.Add(fileHandle);
|
||||||
|
context.SaveChangesAsync();
|
||||||
|
|
||||||
|
tcs.SetResult(fileHandle.Id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private async Task<FileHandle> CreateFileBlocks(Stream reader, FileHandle fileHandle)
|
private async Task<FileHandle> CreateFileBlocks(Stream reader, FileHandle fileHandle)
|
||||||
{
|
{
|
||||||
var blockNumber = 0;
|
var blockNumber = 0;
|
||||||
var blocks = new List<FileBlock>();
|
|
||||||
var buffer = new byte[1024];
|
var buffer = new byte[1024];
|
||||||
|
|
||||||
while (await reader.ReadAsync(buffer) > 0)
|
while (await reader.ReadAsync(buffer) > 0)
|
||||||
|
|
|
||||||
|
|
@ -54,6 +54,9 @@
|
||||||
<a
|
<a
|
||||||
asp-controller="Files" asp-action="Index" asp-route-id="@file.Id"
|
asp-controller="Files" asp-action="Index" asp-route-id="@file.Id"
|
||||||
class="btn btn-primary me-2">View...</a>
|
class="btn btn-primary me-2">View...</a>
|
||||||
|
<a
|
||||||
|
asp-controller="Files" asp-action="Download" asp-route-id="@file.Id"
|
||||||
|
class="btn btn-success me-2">Download</a>
|
||||||
<a
|
<a
|
||||||
asp-controller="Files" asp-action="ConfirmDelete" asp-route-id="@file.Id"
|
asp-controller="Files" asp-action="ConfirmDelete" asp-route-id="@file.Id"
|
||||||
class="btn btn-danger">Delete...</a>
|
class="btn btn-danger">Delete...</a>
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue