MVP
This commit is contained in:
parent
61725b4d07
commit
5bf51d108c
5 changed files with 214 additions and 28 deletions
|
@ -2,6 +2,7 @@ using System;
|
|||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using MeowStash.Services;
|
||||
using Microsoft.AspNetCore.Http.HttpResults;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
|
@ -11,8 +12,15 @@ namespace MeowStash.Controllers;
|
|||
[ApiController]
|
||||
public class ResourceController : ControllerBase
|
||||
{
|
||||
[HttpPost("add")]
|
||||
public async Task<IActionResult> AddFiles([FromForm] IFormFileCollection files)
|
||||
public ResourceController(FileIOService io)
|
||||
{
|
||||
_io = io;
|
||||
}
|
||||
|
||||
private readonly FileIOService _io;
|
||||
|
||||
[HttpPost("upload")]
|
||||
public async Task<IActionResult> UploadFiles([FromForm] IFormFileCollection files)
|
||||
{
|
||||
foreach (var file in files)
|
||||
{
|
||||
|
@ -23,4 +31,12 @@ public class ResourceController : ControllerBase
|
|||
|
||||
return NoContent();
|
||||
}
|
||||
|
||||
[HttpPost("upload/fragment/{id}")]
|
||||
public async Task<IActionResult> UploadFileFragment([FromRoute] int uploadId, [FromBody] byte[] dataPacket)
|
||||
{
|
||||
using var buffer = new MemoryStream(dataPacket);
|
||||
await _io.WritePartialFile(uploadId, buffer);
|
||||
return NoContent();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,36 +7,108 @@
|
|||
|
||||
|
||||
<InputFile OnChange="@SendFiles" multiple /><br />
|
||||
<span class="@_umsg_class">@_umsg</span>
|
||||
|
||||
@if (_uploadData.Any())
|
||||
{
|
||||
<div class="uploads">
|
||||
@foreach (var item in _uploadData)
|
||||
{
|
||||
<div class="upload-item">
|
||||
<div class="upload-item-data">
|
||||
<span class="upload-item-name">@item.Key.Name</span>
|
||||
</div>
|
||||
<div class="upload-progress">
|
||||
<span class="upload-progress-value @GetUploadProgressClassesFor(item.Value.Item1)">@item.Value.Item1%</span>
|
||||
<span class="upload-progress-bytes">@item.Value.Item2</span>
|
||||
<div class="upload-progress-bar-container">
|
||||
<div class="upload-progress-bar @GetUploadProgressClassesFor(item.Value.Item1)"
|
||||
style="width: @($"{item.Value.Item1}%");"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
}
|
||||
|
||||
@code {
|
||||
private string _umsg = "", _umsg_class = "text-hidden";
|
||||
|
||||
private string GetUploadProgressClassesFor(float percent)
|
||||
{
|
||||
return percent switch
|
||||
{
|
||||
(< 5f) => "upload-progress-low",
|
||||
(> 5f) and (< 50f) => "upload-progress-submedial",
|
||||
(> 50f) and (< 95f) => "upload-progress-supermedial",
|
||||
(> 95f) and (< 100f) => "upload-progress-nearly-done",
|
||||
100f or (> 100f) => "upload-progress-done",
|
||||
_ => "upload-progress-invalid"
|
||||
};
|
||||
}
|
||||
|
||||
private System.Collections.Concurrent.ConcurrentDictionary<IBrowserFile, (float, long)> _uploadData = new();
|
||||
private CancellationTokenSource _cancel = null!;
|
||||
|
||||
private async Task SendFiles(InputFileChangeEventArgs e)
|
||||
{
|
||||
Console.WriteLine($"Files: {e.FileCount}");
|
||||
if (_cancel != null)
|
||||
{
|
||||
_cancel.Cancel();
|
||||
_cancel.Dispose();
|
||||
}
|
||||
_cancel = new();
|
||||
|
||||
var files = e.GetMultipleFiles(e.FileCount);
|
||||
|
||||
_umsg_class = "text-green";
|
||||
_uploadData = new(files.Count, files.ToDictionary(f => f, _ => (0f, 0L)), null);
|
||||
|
||||
int counter = 1;
|
||||
foreach (var file in files)
|
||||
if (!System.IO.Directory.Exists("/tmp/uploads"))
|
||||
{
|
||||
_umsg = $"Uploading {counter}/{e.FileCount} files...";
|
||||
StateHasChanged();
|
||||
Console.WriteLine($"Fos: /tmp/uploads/{file.Name}");
|
||||
if (!System.IO.Directory.Exists("/tmp/uploads"))
|
||||
{
|
||||
System.IO.Directory.CreateDirectory("/tmp/uploads");
|
||||
}
|
||||
Console.WriteLine($"fosse");
|
||||
await using var fos = System.IO.File.OpenWrite($"/tmp/uploads/{file.Name}");
|
||||
Console.WriteLine("Fos opened");
|
||||
await file.OpenReadStream(1024 * 1024 * 10).CopyToAsync(fos);
|
||||
Console.WriteLine($"File: /tmp/uploads/{file.Name} written...");
|
||||
++counter;
|
||||
System.IO.Directory.CreateDirectory("/tmp/uploads");
|
||||
}
|
||||
|
||||
_umsg = "Done!";
|
||||
var tasks = new List<Task>();
|
||||
|
||||
foreach (var file in files)
|
||||
{
|
||||
tasks.Add(Task.Run(async () =>
|
||||
{
|
||||
await using var fos = System.IO.File.OpenWrite($"/tmp/uploads/{file.Name}");
|
||||
|
||||
var stream = file.OpenReadStream(1024 * 1024 * 1024, _cancel.Token);
|
||||
int read;
|
||||
|
||||
byte[] buffer = new byte[16 * 1024];
|
||||
|
||||
while ((read = await stream.ReadAsync(buffer, 0, buffer.Length, _cancel.Token)) > 0)
|
||||
{
|
||||
if (_cancel.IsCancellationRequested)
|
||||
{
|
||||
stream.Close();
|
||||
return;
|
||||
}
|
||||
|
||||
await fos.WriteAsync(buffer, 0, read);
|
||||
|
||||
long totalRead = _uploadData[file].Item2;
|
||||
totalRead += read;
|
||||
|
||||
float percent = float.Round(((float)totalRead / (float)file.Size * 100f), 2);
|
||||
_uploadData[file] = (percent, totalRead);
|
||||
|
||||
await InvokeAsync(StateHasChanged);
|
||||
await Task.Delay(500, _cancel.Token);
|
||||
}
|
||||
|
||||
stream.Close();
|
||||
|
||||
Console.WriteLine($"File: /tmp/uploads/{file.Name} written...");
|
||||
await InvokeAsync(StateHasChanged);
|
||||
}));
|
||||
}
|
||||
|
||||
await Task.WhenAll(tasks);
|
||||
|
||||
StateHasChanged();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,19 +1,13 @@
|
|||
using Microsoft.AspNetCore.Components;
|
||||
using Microsoft.AspNetCore.Components.Web;
|
||||
|
||||
var builder = WebApplication.CreateBuilder(args);
|
||||
|
||||
// Add services to the container.
|
||||
builder.Services.AddRazorPages();
|
||||
builder.Services.AddServerSideBlazor();
|
||||
|
||||
var app = builder.Build();
|
||||
|
||||
// Configure the HTTP request pipeline.
|
||||
if (!app.Environment.IsDevelopment())
|
||||
{
|
||||
app.UseExceptionHandler("/Error");
|
||||
// The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
|
||||
app.UseHsts();
|
||||
}
|
||||
|
||||
|
|
23
Services/FileIOService.cs
Normal file
23
Services/FileIOService.cs
Normal file
|
@ -0,0 +1,23 @@
|
|||
namespace MeowStash.Services;
|
||||
|
||||
public class FileIOService
|
||||
{
|
||||
public async Task WriteFullFile(string location, byte[] data)
|
||||
{
|
||||
await File.WriteAllBytesAsync(location, data);
|
||||
}
|
||||
|
||||
public async Task WriteFullFile(string location, Stream data)
|
||||
{
|
||||
using var stream = File.OpenWrite(location);
|
||||
await data.CopyToAsync(stream);
|
||||
stream.Close();
|
||||
}
|
||||
|
||||
public async Task WritePartialFile(int id, Stream data)
|
||||
{
|
||||
using var stream = File.Open($"/tmp/{id}", FileMode.Append);
|
||||
await data.CopyToAsync(stream);
|
||||
stream.Close();
|
||||
}
|
||||
}
|
|
@ -86,3 +86,84 @@ a,
|
|||
.blazor-error-boundary::after {
|
||||
content: "An error has occurred.";
|
||||
}
|
||||
|
||||
.upload-item {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.upload-item-name {
|
||||
color: lightgray;
|
||||
}
|
||||
|
||||
.upload-progress {
|
||||
display: block;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.upload-progress-value {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.upload-progress-bytes {
|
||||
color: lightgray;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.upload-progress-bar-container {
|
||||
width: 80%;
|
||||
height: 30px;
|
||||
background-color: gray;
|
||||
border-radius: 10px;
|
||||
}
|
||||
|
||||
span.upload-progress-low {
|
||||
color: lightcoral;
|
||||
}
|
||||
|
||||
span.upload-progress-submedial {
|
||||
color: yellow;
|
||||
}
|
||||
|
||||
span.upload-progress-supermedial {
|
||||
color: greenyellow;
|
||||
}
|
||||
|
||||
span.upload-progress-nearly-done {
|
||||
color: limegreen;
|
||||
}
|
||||
|
||||
span.upload-progress-done {
|
||||
color: green;
|
||||
}
|
||||
|
||||
span.upload-progress-invalid {
|
||||
color: darkgray;
|
||||
}
|
||||
|
||||
.upload-progress-bar {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.upload-progress-bar.upload-progress-low {
|
||||
background-color: lightcoral;
|
||||
}
|
||||
|
||||
.upload-progress-bar.upload-progress-submedial {
|
||||
background-color: yellow;
|
||||
}
|
||||
|
||||
.upload-progress-bar.upload-progress-supermedial {
|
||||
background-color: greenyellow;
|
||||
}
|
||||
|
||||
.upload-progress-bar.upload-progress-nearly-done {
|
||||
background-color: limegreen;
|
||||
}
|
||||
|
||||
.upload-progress-bar.upload-progress-done {
|
||||
background-color: green;
|
||||
}
|
||||
|
||||
.upload-progress-bar.upload-progress-invalid {
|
||||
background-color: darkgray;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue