Add MCDO (#80)
* update api * mcd online editor impl * most of chara data hub impl * some state of things * some refactoring * random bullshit go * more nearby impl * add uid to peformance msg * cleanup/homogenization * some split, update nuget packages * migrate to latest packages where possible, remove lz4net, do some split, idk * some polish and cleanup * more cleanup, beautification, etc. * fixes and cleanups --------- Co-authored-by: Stanley Dimant <root.darkarchon@outlook.com>
This commit is contained in:
@@ -65,6 +65,43 @@ public sealed class FileUploadManager : DisposableMediatorSubscriberBase
|
||||
await _orchestrator.SendRequestAsync(HttpMethod.Post, MareFiles.ServerFilesDeleteAllFullPath(_orchestrator.FilesCdnUri!)).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
public async Task<List<string>> UploadFiles(List<string> hashesToUpload, IProgress<string> progress, CancellationToken? ct = null)
|
||||
{
|
||||
Logger.LogDebug("Trying to upload files");
|
||||
var filesPresentLocally = hashesToUpload.Where(h => _fileDbManager.GetFileCacheByHash(h) != null).ToHashSet(StringComparer.Ordinal);
|
||||
var locallyMissingFiles = hashesToUpload.Except(filesPresentLocally, StringComparer.Ordinal).ToList();
|
||||
if (locallyMissingFiles.Any())
|
||||
{
|
||||
return locallyMissingFiles;
|
||||
}
|
||||
|
||||
progress.Report($"Starting upload for {filesPresentLocally.Count} files");
|
||||
|
||||
var filesToUpload = await FilesSend([.. filesPresentLocally], [], ct ?? CancellationToken.None).ConfigureAwait(false);
|
||||
|
||||
if (filesToUpload.Exists(f => f.IsForbidden))
|
||||
{
|
||||
return [.. filesToUpload.Where(f => f.IsForbidden).Select(f => f.Hash)];
|
||||
}
|
||||
|
||||
Task uploadTask = Task.CompletedTask;
|
||||
int i = 1;
|
||||
foreach (var file in filesToUpload)
|
||||
{
|
||||
progress.Report($"Uploading file {i++}/{filesToUpload.Count}. Please wait until the upload is completed.");
|
||||
Logger.LogDebug("[{hash}] Compressing", file);
|
||||
var data = await _fileDbManager.GetCompressedFileData(file.Hash, ct ?? CancellationToken.None).ConfigureAwait(false);
|
||||
Logger.LogDebug("[{hash}] Starting upload for {filePath}", data.Item1, _fileDbManager.GetFileCacheByHash(data.Item1)!.ResolvedFilepath);
|
||||
await uploadTask.ConfigureAwait(false);
|
||||
uploadTask = UploadFile(data.Item2, file.Hash, false, ct ?? CancellationToken.None);
|
||||
(ct ?? CancellationToken.None).ThrowIfCancellationRequested();
|
||||
}
|
||||
|
||||
await uploadTask.ConfigureAwait(false);
|
||||
|
||||
return [];
|
||||
}
|
||||
|
||||
public async Task<CharacterData> UploadFiles(CharacterData data, List<UserData> visiblePlayers)
|
||||
{
|
||||
CancelUpload();
|
||||
@@ -135,7 +172,7 @@ public sealed class FileUploadManager : DisposableMediatorSubscriberBase
|
||||
_verifiedUploadedHashes.Clear();
|
||||
}
|
||||
|
||||
private async Task UploadFile(byte[] compressedFile, string fileHash, CancellationToken uploadToken)
|
||||
private async Task UploadFile(byte[] compressedFile, string fileHash, bool postProgress, CancellationToken uploadToken)
|
||||
{
|
||||
if (!_orchestrator.IsInitialized) throw new InvalidOperationException("FileTransferManager is not initialized");
|
||||
|
||||
@@ -145,7 +182,7 @@ public sealed class FileUploadManager : DisposableMediatorSubscriberBase
|
||||
|
||||
try
|
||||
{
|
||||
await UploadFileStream(compressedFile, fileHash, false, uploadToken).ConfigureAwait(false);
|
||||
await UploadFileStream(compressedFile, fileHash, false, postProgress, uploadToken).ConfigureAwait(false);
|
||||
_verifiedUploadedHashes[fileHash] = DateTime.UtcNow;
|
||||
}
|
||||
catch (Exception ex)
|
||||
@@ -153,7 +190,7 @@ public sealed class FileUploadManager : DisposableMediatorSubscriberBase
|
||||
if (false && ex is not OperationCanceledException)
|
||||
{
|
||||
Logger.LogWarning(ex, "[{hash}] Error during file upload, trying alternative file upload", fileHash);
|
||||
await UploadFileStream(compressedFile, fileHash, munged: true, uploadToken).ConfigureAwait(false);
|
||||
await UploadFileStream(compressedFile, fileHash, munged: true, postProgress, uploadToken).ConfigureAwait(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -162,14 +199,14 @@ public sealed class FileUploadManager : DisposableMediatorSubscriberBase
|
||||
}
|
||||
}
|
||||
|
||||
private async Task UploadFileStream(byte[] compressedFile, string fileHash, bool munged, CancellationToken uploadToken)
|
||||
private async Task UploadFileStream(byte[] compressedFile, string fileHash, bool munged, bool postProgress, CancellationToken uploadToken)
|
||||
{
|
||||
if (munged)
|
||||
throw new NotImplementedException();
|
||||
|
||||
using var ms = new MemoryStream(compressedFile);
|
||||
|
||||
Progress<UploadProgress> prog = new((prog) =>
|
||||
Progress<UploadProgress>? prog = !postProgress ? null : new((prog) =>
|
||||
{
|
||||
try
|
||||
{
|
||||
@@ -180,6 +217,7 @@ public sealed class FileUploadManager : DisposableMediatorSubscriberBase
|
||||
Logger.LogWarning(ex, "[{hash}] Could not set upload progress", fileHash);
|
||||
}
|
||||
});
|
||||
|
||||
var streamContent = new ProgressableStreamContent(ms, prog);
|
||||
streamContent.Headers.ContentType = new MediaTypeHeaderValue("application/octet-stream");
|
||||
HttpResponseMessage response;
|
||||
@@ -235,7 +273,7 @@ public sealed class FileUploadManager : DisposableMediatorSubscriberBase
|
||||
CurrentUploads.Single(e => string.Equals(e.Hash, file.Hash, StringComparison.Ordinal)).Total = data.Item2.Length;
|
||||
Logger.LogDebug("[{hash}] Starting upload for {filePath}", file.Hash, _fileDbManager.GetFileCacheByHash(file.Hash)!.ResolvedFilepath);
|
||||
await uploadTask.ConfigureAwait(false);
|
||||
uploadTask = UploadFile(data.Item2, file.Hash, uploadToken);
|
||||
uploadTask = UploadFile(data.Item2, file.Hash, true, uploadToken);
|
||||
uploadToken.ThrowIfCancellationRequested();
|
||||
}
|
||||
|
||||
|
||||
@@ -6,16 +6,16 @@ public class ProgressableStreamContent : StreamContent
|
||||
{
|
||||
private const int _defaultBufferSize = 4096;
|
||||
private readonly int _bufferSize;
|
||||
private readonly IProgress<UploadProgress> _progress;
|
||||
private readonly IProgress<UploadProgress>? _progress;
|
||||
private readonly Stream _streamToWrite;
|
||||
private bool _contentConsumed;
|
||||
|
||||
public ProgressableStreamContent(Stream streamToWrite, IProgress<UploadProgress> downloader)
|
||||
public ProgressableStreamContent(Stream streamToWrite, IProgress<UploadProgress>? downloader)
|
||||
: this(streamToWrite, _defaultBufferSize, downloader)
|
||||
{
|
||||
}
|
||||
|
||||
public ProgressableStreamContent(Stream streamToWrite, int bufferSize, IProgress<UploadProgress> progress)
|
||||
public ProgressableStreamContent(Stream streamToWrite, int bufferSize, IProgress<UploadProgress>? progress)
|
||||
: base(streamToWrite, bufferSize)
|
||||
{
|
||||
if (streamToWrite == null)
|
||||
@@ -55,14 +55,14 @@ public class ProgressableStreamContent : StreamContent
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
var length = _streamToWrite.Read(buffer, 0, buffer.Length);
|
||||
var length = await _streamToWrite.ReadAsync(buffer).ConfigureAwait(false);
|
||||
if (length <= 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
uploaded += length;
|
||||
_progress.Report(new UploadProgress(uploaded, size));
|
||||
_progress?.Report(new UploadProgress(uploaded, size));
|
||||
await stream.WriteAsync(buffer.AsMemory(0, length)).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,119 @@
|
||||
using MareSynchronos.API.Dto.CharaData;
|
||||
using Microsoft.AspNetCore.SignalR.Client;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace MareSynchronos.WebAPI;
|
||||
public partial class ApiController
|
||||
{
|
||||
public async Task<CharaDataFullDto?> CharaDataCreate()
|
||||
{
|
||||
if (!IsConnected) return null;
|
||||
|
||||
try
|
||||
{
|
||||
Logger.LogDebug("Creating new Character Data");
|
||||
return await _mareHub!.InvokeAsync<CharaDataFullDto?>(nameof(CharaDataCreate)).ConfigureAwait(false);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.LogWarning(ex, "Failed to create new character data");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<CharaDataFullDto?> CharaDataUpdate(CharaDataUpdateDto updateDto)
|
||||
{
|
||||
if (!IsConnected) return null;
|
||||
|
||||
try
|
||||
{
|
||||
Logger.LogDebug("Updating chara data for {id}", updateDto.Id);
|
||||
return await _mareHub!.InvokeAsync<CharaDataFullDto?>(nameof(CharaDataUpdate), updateDto).ConfigureAwait(false);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.LogWarning(ex, "Failed to update chara data for {id}", updateDto.Id);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<bool> CharaDataDelete(string id)
|
||||
{
|
||||
if (!IsConnected) return false;
|
||||
|
||||
try
|
||||
{
|
||||
Logger.LogDebug("Deleting chara data for {id}", id);
|
||||
return await _mareHub!.InvokeAsync<bool>(nameof(CharaDataDelete), id).ConfigureAwait(false);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.LogWarning(ex, "Failed to delete chara data for {id}", id);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<CharaDataMetaInfoDto?> CharaDataGetMetainfo(string id)
|
||||
{
|
||||
if (!IsConnected) return null;
|
||||
|
||||
try
|
||||
{
|
||||
Logger.LogDebug("Getting metainfo for chara data {id}", id);
|
||||
return await _mareHub!.InvokeAsync<CharaDataMetaInfoDto?>(nameof(CharaDataGetMetainfo), id).ConfigureAwait(false);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.LogWarning(ex, "Failed to get meta info for chara data {id}", id);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<List<CharaDataFullDto>> CharaDataGetOwn()
|
||||
{
|
||||
if (!IsConnected) return [];
|
||||
|
||||
try
|
||||
{
|
||||
Logger.LogDebug("Getting all own chara data");
|
||||
return await _mareHub!.InvokeAsync<List<CharaDataFullDto>>(nameof(CharaDataGetOwn)).ConfigureAwait(false);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.LogWarning(ex, "Failed to get own chara data");
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<List<CharaDataMetaInfoDto>> CharaDataGetShared()
|
||||
{
|
||||
if (!IsConnected) return [];
|
||||
|
||||
try
|
||||
{
|
||||
Logger.LogDebug("Getting all own chara data");
|
||||
return await _mareHub!.InvokeAsync<List<CharaDataMetaInfoDto>>(nameof(CharaDataGetShared)).ConfigureAwait(false);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.LogWarning(ex, "Failed to get shared chara data");
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<CharaDataDownloadDto?> CharaDataDownload(string id)
|
||||
{
|
||||
if (!IsConnected) return null;
|
||||
|
||||
try
|
||||
{
|
||||
Logger.LogDebug("Getting download chara data for {id}", id);
|
||||
return await _mareHub!.InvokeAsync<CharaDataDownloadDto>(nameof(CharaDataDownload), id).ConfigureAwait(false);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.LogWarning(ex, "Failed to get download chara data for {id}", id);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user