Implemented zip and tar compressing and decompressing. Implemented chunked file uploading
This commit is contained in:
@@ -1,20 +1,41 @@
|
||||
using MoonCore.Blazor.Tailwind.Fm;
|
||||
using MoonCore.Blazor.Tailwind.Fm.Models;
|
||||
using MoonCore.Blazor.Tailwind.Services;
|
||||
using MoonCore.Helpers;
|
||||
using MoonlightServers.Frontend.Services;
|
||||
|
||||
namespace MoonlightServers.Frontend.Helpers;
|
||||
|
||||
public class ServerFileSystemProvider : IFileSystemProvider
|
||||
public class ServerFileSystemProvider : IFileSystemProvider, ICompressFileSystemProvider
|
||||
{
|
||||
private readonly int ServerId;
|
||||
private readonly DownloadService DownloadService;
|
||||
private readonly ServerFileSystemService FileSystemService;
|
||||
|
||||
public CompressType[] CompressTypes { get; } =
|
||||
[
|
||||
new()
|
||||
{
|
||||
Extension = "zip",
|
||||
DisplayName = "ZIP Archive"
|
||||
},
|
||||
new()
|
||||
{
|
||||
Extension = "tar.gz",
|
||||
DisplayName = "GZ Compressed Tar Archive"
|
||||
}
|
||||
];
|
||||
|
||||
private readonly int ServerId;
|
||||
|
||||
public ServerFileSystemProvider(
|
||||
int serverId,
|
||||
ServerFileSystemService fileSystemService
|
||||
ServerFileSystemService fileSystemService,
|
||||
DownloadService downloadService
|
||||
)
|
||||
{
|
||||
ServerId = serverId;
|
||||
FileSystemService = fileSystemService;
|
||||
DownloadService = downloadService;
|
||||
}
|
||||
|
||||
public async Task<FileSystemEntry[]> List(string path)
|
||||
@@ -35,7 +56,7 @@ public class ServerFileSystemProvider : IFileSystemProvider
|
||||
|
||||
public async Task Create(string path, Stream stream)
|
||||
{
|
||||
await FileSystemService.Upload(ServerId, path, stream);
|
||||
await Upload(_ => Task.CompletedTask, path, stream);
|
||||
}
|
||||
|
||||
public async Task Move(string oldPath, string newPath)
|
||||
@@ -55,6 +76,72 @@ public class ServerFileSystemProvider : IFileSystemProvider
|
||||
|
||||
public async Task<Stream> Read(string path)
|
||||
{
|
||||
return await FileSystemService.Download(ServerId, path);
|
||||
var downloadSession = await FileSystemService.Download(ServerId, path);
|
||||
|
||||
using var httpClient = new HttpClient();
|
||||
return await httpClient.GetStreamAsync(downloadSession.DownloadUrl);
|
||||
}
|
||||
|
||||
public async Task Download(Func<int, Task> updateProgress, string path, string fileName)
|
||||
{
|
||||
var downloadSession = await FileSystemService.Download(ServerId, path);
|
||||
|
||||
await DownloadService.DownloadUrl(fileName, downloadSession.DownloadUrl,
|
||||
async (loaded, total) =>
|
||||
{
|
||||
var percent = total == 0 ? 0 : (int)Math.Round((float)loaded / total * 100);
|
||||
await updateProgress.Invoke(percent);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
public async Task Upload(Func<int, Task> updateProgress, string path, Stream stream)
|
||||
{
|
||||
using var httpClient = new HttpClient();
|
||||
|
||||
var uploadSession = await FileSystemService.Upload(ServerId);
|
||||
|
||||
var size = stream.Length;
|
||||
var chunkSize = ByteConverter.FromMegaBytes(20).Bytes;
|
||||
|
||||
var chunks = size / chunkSize;
|
||||
chunks += size % chunkSize > 0 ? 1 : 0;
|
||||
|
||||
for (var chunkId = 0; chunkId < chunks; chunkId++)
|
||||
{
|
||||
var percent = (int)Math.Round((chunkId + 1f) / chunks * 100);
|
||||
await updateProgress.Invoke(percent);
|
||||
|
||||
var buffer = new byte[chunkSize];
|
||||
var bytesRead = await stream.ReadAsync(buffer);
|
||||
|
||||
var uploadForm = new MultipartFormDataContent();
|
||||
uploadForm.Add(new ByteArrayContent(buffer, 0, bytesRead), "file", "file");
|
||||
|
||||
await httpClient.PostAsync(
|
||||
$"{uploadSession.UploadUrl}&totalSize={size}&chunkId={chunkId}&path={path}",
|
||||
uploadForm
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
public async Task Compress(CompressType type, string path, string[] itemsToCompress)
|
||||
{
|
||||
await FileSystemService.Compress(
|
||||
ServerId,
|
||||
type.Extension.Replace(".", ""),
|
||||
itemsToCompress,
|
||||
path
|
||||
);
|
||||
}
|
||||
|
||||
public async Task Decompress(CompressType type, string path, string destination)
|
||||
{
|
||||
await FileSystemService.Decompress(
|
||||
ServerId,
|
||||
type.Extension.Replace(".", ""),
|
||||
path,
|
||||
destination
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,7 @@
|
||||
using System.Net;
|
||||
using MoonCore.Attributes;
|
||||
using MoonCore.Helpers;
|
||||
using MoonlightServers.Shared.Http.Requests.Client.Servers.Files;
|
||||
using MoonlightServers.Shared.Http.Responses.Client.Servers.Files;
|
||||
|
||||
namespace MoonlightServers.Frontend.Services;
|
||||
@@ -42,28 +44,43 @@ public class ServerFileSystemService
|
||||
);
|
||||
}
|
||||
|
||||
public async Task Upload(int serverId, string path, Stream dataStream)
|
||||
public async Task<ServerFilesUploadResponse> Upload(int serverId)
|
||||
{
|
||||
var uploadSession = await ApiClient.GetJson<ServerFilesUploadResponse>(
|
||||
return await ApiClient.GetJson<ServerFilesUploadResponse>(
|
||||
$"api/client/servers/{serverId}/files/upload"
|
||||
);
|
||||
|
||||
using var httpClient = new HttpClient();
|
||||
|
||||
var content = new MultipartFormDataContent();
|
||||
content.Add(new StreamContent(dataStream), "file", path);
|
||||
|
||||
await httpClient.PostAsync(uploadSession.UploadUrl, content);
|
||||
}
|
||||
|
||||
public async Task<Stream> Download(int serverId, string path)
|
||||
public async Task<ServerFilesDownloadResponse> Download(int serverId, string path)
|
||||
{
|
||||
var downloadSession = await ApiClient.GetJson<ServerFilesDownloadResponse>(
|
||||
return await ApiClient.GetJson<ServerFilesDownloadResponse>(
|
||||
$"api/client/servers/{serverId}/files/download?path={path}"
|
||||
);
|
||||
}
|
||||
|
||||
using var httpClient = new HttpClient();
|
||||
|
||||
return await httpClient.GetStreamAsync(downloadSession.DownloadUrl);
|
||||
public async Task Compress(int serverId, string type, string[] items, string destination)
|
||||
{
|
||||
await ApiClient.Post(
|
||||
$"api/client/servers/{serverId}/files/compress",
|
||||
new ServerFilesCompressRequest()
|
||||
{
|
||||
Type = type,
|
||||
Items = items,
|
||||
Destination = destination
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
public async Task Decompress(int serverId, string type, string path, string destination)
|
||||
{
|
||||
await ApiClient.Post(
|
||||
$"api/client/servers/{serverId}/files/decompress",
|
||||
new ServerFilesDecompressRequest()
|
||||
{
|
||||
Type = type,
|
||||
Path = path,
|
||||
Destination = destination
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,19 +1,25 @@
|
||||
@using MoonlightServers.Frontend.Services
|
||||
@using MoonCore.Blazor.Tailwind.Fm
|
||||
@using MoonCore.Blazor.Tailwind.Services
|
||||
@using MoonlightServers.Frontend.Helpers
|
||||
|
||||
@inherits BaseServerTab
|
||||
|
||||
@inject ServerFileSystemService FileSystemService
|
||||
@inject DownloadService DownloadService
|
||||
|
||||
<FileManager FileSystemProvider="Provider" />
|
||||
<FileManager FileSystemProvider="Provider"/>
|
||||
|
||||
@code
|
||||
{
|
||||
private IFileSystemProvider Provider;
|
||||
|
||||
|
||||
protected override void OnInitialized()
|
||||
{
|
||||
Provider = new ServerFileSystemProvider(Server.Id, FileSystemService);
|
||||
Provider = new ServerFileSystemProvider(
|
||||
Server.Id,
|
||||
FileSystemService,
|
||||
DownloadService
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,8 +26,10 @@
|
||||
</PageHeader>
|
||||
</div>
|
||||
|
||||
<DataTable @ref="Table" TItem="ServerDetailResponse" PageSize="15" LoadItemsPaginatedAsync="LoadData">
|
||||
<DataTable @ref="Table" TItem="ServerDetailResponse">
|
||||
<Configuration>
|
||||
<Pagination TItem="ServerDetailResponse" ItemSource="LoadData" />
|
||||
|
||||
<DataTableColumn TItem="ServerDetailResponse" Field="@(x => x.Id)" Name="Id"/>
|
||||
<DataTableColumn TItem="ServerDetailResponse" Field="@(x => x.Name)" Name="Name"/>
|
||||
<DataTableColumn TItem="ServerDetailResponse" Field="@(x => x.NodeId)" Name="Node">
|
||||
|
||||
@@ -27,8 +27,10 @@
|
||||
</PageHeader>
|
||||
</div>
|
||||
|
||||
<DataTable TItem="NodeDetailResponse" PageSize="15" LoadItemsPaginatedAsync="LoadData">
|
||||
<DataTable TItem="NodeDetailResponse">
|
||||
<Configuration>
|
||||
<Pagination TItem="NodeDetailResponse" ItemSource="LoadData" />
|
||||
|
||||
<DataTableColumn TItem="NodeDetailResponse" Field="@(x => x.Id)" Name="Id"/>
|
||||
<DataTableColumn TItem="NodeDetailResponse" Field="@(x => x.Name)" Name="Name">
|
||||
<ColumnTemplate>
|
||||
@@ -103,8 +105,8 @@
|
||||
</ColumnTemplate>
|
||||
</DataTableColumn>
|
||||
<DataTableColumn TItem="NodeDetailResponse"
|
||||
HeaderCss="p-2 font-semibold text-left hidden xl:table-cell"
|
||||
ColumnCss="p-2 text-left font-normal hidden xl:table-cell">
|
||||
HeaderCss="p-2 font-semibold text-left hidden xl:table-cell"
|
||||
ColumnCss="p-2 text-left font-normal hidden xl:table-cell">
|
||||
<ColumnTemplate>
|
||||
<div>
|
||||
<i class="icon-memory-stick text-lg me-1 align-middle text-primary-500"></i>
|
||||
|
||||
@@ -33,9 +33,11 @@
|
||||
</PageHeader>
|
||||
</div>
|
||||
|
||||
<DataTable @ref="Table" TItem="StarDetailResponse" LoadItemsPaginatedAsync="LoadData">
|
||||
<DataTable @ref="Table" TItem="StarDetailResponse">
|
||||
<Configuration>
|
||||
<DataTableColumn TItem="StarDetailResponse" Field="@(x => x.Id)" Name="Id" />
|
||||
<Pagination TItem="StarDetailResponse" ItemSource="LoadData" />
|
||||
|
||||
<DataTableColumn TItem="StarDetailResponse" Field="@(x => x.Id)" Name="Id"/>
|
||||
<DataTableColumn TItem="StarDetailResponse" Field="@(x => x.Name)" Name="Name">
|
||||
<ColumnTemplate>
|
||||
<a class="text-primary-500" href="/admin/servers/stars/update/@(context.Id)">
|
||||
@@ -43,8 +45,8 @@
|
||||
</a>
|
||||
</ColumnTemplate>
|
||||
</DataTableColumn>
|
||||
<DataTableColumn TItem="StarDetailResponse" Field="@(x => x.Version)" Name="Version" />
|
||||
<DataTableColumn TItem="StarDetailResponse" Field="@(x => x.Author)" Name="Author" />
|
||||
<DataTableColumn TItem="StarDetailResponse" Field="@(x => x.Version)" Name="Version"/>
|
||||
<DataTableColumn TItem="StarDetailResponse" Field="@(x => x.Author)" Name="Author"/>
|
||||
<DataTableColumn TItem="StarDetailResponse">
|
||||
<ColumnTemplate>
|
||||
<div class="flex justify-end">
|
||||
@@ -68,7 +70,7 @@
|
||||
<i class="icon-download align-middle"></i>
|
||||
<span class="align-middle">Export</span>
|
||||
</a>
|
||||
|
||||
|
||||
<a href="/admin/servers/stars/update/@(context.Id)" class="text-primary-500 mr-2 sm:mr-3">
|
||||
<i class="icon-pencil text-base"></i>
|
||||
</a>
|
||||
|
||||
Reference in New Issue
Block a user