@using Hangfire; @using LANCommander.SDK.Enums @using LANCommander.Server.Jobs.Background; @using LANCommander.UI.Services @using Microsoft.Extensions.Options @inject ArchiveService ArchiveService @inject GameVersionService GameVersionService @inject StorageLocationService StorageLocationService @inject IOptions Settings @inject IMessageService MessageService @inject ConfirmService ConfirmService @inject IJSRuntime JS @inject ILogger Logger @{ RenderFragment Footer = @; }

Drag and Drop

or

Only ZIP files are supported as game archives
@code { [Parameter] public Guid GameId { get; set; } [Parameter] public Guid RedistributableId { get; set; } [Parameter] public Guid ToolId { get; set; } [Parameter] public EventCallback OnArchiveUploaded { get; set; } Archive Archive; string RootPath = Path.GetPathRoot(Directory.GetCurrentDirectory()); IBrowserFile File; ChunkUploader ChunkUploader; Guid StorageLocationId; StorageLocation StorageLocation; bool Visible = false; bool Uploading = false; string Filename; string Status = ""; bool MoveLocalFile = false; private async Task Start() { Uploading = true; // Capture values NOW (at the moment user clicks Upload) // so the callback has correct data regardless of component lifecycle. var gameId = Archive.GameId; var redistributableId = Archive.RedistributableId; var toolId = Archive.ToolId; var version = Archive.Version; await ChunkUploader.Start(async (string objectKeyStr) => { try { if (!Guid.TryParse(objectKeyStr, out var objectKey)) { Logger.LogError("Archive failed to upload - invalid object key"); return; } var uploadedArchive = await ArchiveService.FirstOrDefaultAsync(a => a.ObjectKey == objectKey.ToString()); if (uploadedArchive == null) { Logger.LogError("Archive record not found for object key {ObjectKey}", objectKeyStr); return; } uploadedArchive.GameId = gameId; uploadedArchive.RedistributableId = redistributableId; uploadedArchive.ToolId = toolId; uploadedArchive.Version = version; uploadedArchive.CompressedSize = await ArchiveService.GetCompressedSizeAsync(uploadedArchive); uploadedArchive.UncompressedSize = await ArchiveService.GetUncompressedSizeAsync(uploadedArchive); await ArchiveService.UpdateAsync(uploadedArchive); if (OnArchiveUploaded.HasDelegate) await OnArchiveUploaded.InvokeAsync(uploadedArchive.Id); Uploading = false; Visible = false; try { await InvokeAsync(StateHasChanged); } catch { } } catch (Exception ex) { Logger.LogError(ex, "Failed to process uploaded archive"); } }); } private async Task Clear() { if (ChunkUploader != null) await ChunkUploader.Clear(); } private async Task Cancel() { if (Uploading && ChunkUploader?.IsUploading == true) { var result = await ConfirmService.Show( "The upload will continue in the background. You can track its progress in the sidebar.", "Continue in Background?", ConfirmButtons.OKCancel, ConfirmIcon.Info); if (result == ConfirmResult.OK) { Visible = false; await InvokeAsync(StateHasChanged); } } else { if (ChunkUploader != null) await ChunkUploader.Clear(); Visible = false; } } public async Task Open(Guid? archiveId = null) { if (archiveId.HasValue && archiveId != Guid.Empty) { Archive = await ArchiveService.GetAsync(archiveId.Value); } else { Archive = new Archive(); if (GameId != Guid.Empty) { Archive.GameId = GameId; // Default the version to the game's current version so the upload is tagged // against it unless the uploader chooses a different version number. Archive.Version = await GameVersionService.GetLatestVersionNumberAsync(GameId) ?? string.Empty; } else if (RedistributableId != Guid.Empty) Archive.RedistributableId = RedistributableId; else if (ToolId != Guid.Empty) Archive.ToolId = ToolId; } if (Archive.StorageLocation == null) Archive.StorageLocation = await StorageLocationService.DefaultAsync(StorageLocationType.Archive) ?? new StorageLocation(); Uploading = false; Visible = true; await InvokeAsync(StateHasChanged); } public async Task OnUploadError(string message) { Uploading = false; Visible = false; await InvokeAsync(StateHasChanged); MessageService.Error("Archive failed to upload!"); Logger.LogError($"Archive failed to upload: {message}"); } public async Task OnLocalFileSelected(string path) { try { var objectKey = await ArchiveService.CopyFromLocalFileAsync(path, Archive.StorageLocation.Id, MoveLocalFile); // For local files, run the completion logic directly. var gameId = Archive.GameId; var redistributableId = Archive.RedistributableId; var toolId = Archive.ToolId; var version = Archive.Version; var uploadedArchive = await ArchiveService.FirstOrDefaultAsync(a => a.ObjectKey == objectKey.ToString()); if (uploadedArchive != null) { uploadedArchive.GameId = gameId; uploadedArchive.RedistributableId = redistributableId; uploadedArchive.ToolId = toolId; uploadedArchive.Version = version; uploadedArchive.CompressedSize = await ArchiveService.GetCompressedSizeAsync(uploadedArchive); uploadedArchive.UncompressedSize = await ArchiveService.GetUncompressedSizeAsync(uploadedArchive); await ArchiveService.UpdateAsync(uploadedArchive); if (OnArchiveUploaded.HasDelegate) await OnArchiveUploaded.InvokeAsync(uploadedArchive.Id); } Visible = false; await InvokeAsync(StateHasChanged); MessageService.Success("Archive uploaded!"); } catch (Exception ex) { MessageService.Error("An unknown error occurred while trying to use a local file"); Logger.LogError(ex, "An unknown error occurred while trying to use a local file"); } } }