This refactor splits the import and export functionality out of the ImportContext and adds an ExportContext. This also introduced separate importer and exporter implementations. Additionally, adding archive, save, scripts, and server files to the final export archive has been implemented at the exporter implementation for each instead of handling it in the context. This should be a good pattern if other files need to be added down the road.
263 lines
No EOL
8 KiB
Text
263 lines
No EOL
8 KiB
Text
@using LANCommander.SDK.Enums
|
|
@using LANCommander.Server.ImportExport
|
|
@using LANCommander.Server.ImportExport.Factories
|
|
@using LANCommander.Server.ImportExport.Models
|
|
@using LANCommander.Server.ImportExport.Services
|
|
@inherits FeedbackComponent<ImportDialogOptions>
|
|
@inject GameService GameService
|
|
@inject ArchiveService ArchiveService
|
|
@inject StorageLocationService StorageLocationService
|
|
@inject ImportContextFactory ImportContextFactory
|
|
@inject IMessageService MessageService
|
|
@inject ILogger<ImportUploadDialog> Logger
|
|
|
|
@if (!Uploaded)
|
|
{
|
|
<Flex Vertical Gap="FlexGap.Small">
|
|
<ChunkUploader
|
|
@ref="ChunkUploader"
|
|
Accept=".lcx"
|
|
@bind-File="File"
|
|
@bind-Status="Status"
|
|
StorageLocationId="StorageLocation.Id"
|
|
OnUploadCompleted="OnUploadCompleted"
|
|
OnUploadError="OnUploadError">
|
|
<Text>
|
|
<p>Drag and Drop</p>
|
|
<p>or</p>
|
|
<p>
|
|
<Button Type="@ButtonType.Primary" Style="margin-top: 8px;">Browse</Button>
|
|
</p>
|
|
</Text>
|
|
<Hint>@Options.Hint</Hint>
|
|
</ChunkUploader>
|
|
|
|
<StorageLocationSelector @bind-Value="StorageLocation" Type="StorageLocationType.Archive"/>
|
|
</Flex>
|
|
|
|
<Flex Justify="FlexJustify.End" Gap="FlexGap.Small" Style="margin-top: 16px;">
|
|
<FilePickerButton
|
|
EntrySelectable="@(entry => !String.IsNullOrWhiteSpace(entry.Name) && entry.Name.ToLower().EndsWith(".lcx"))"
|
|
OnSelected="OnLocalFileSelected"
|
|
Root="@RootPath"
|
|
Disabled="@(Status != "")">
|
|
Use Local File
|
|
</FilePickerButton>
|
|
<Button OnClick="Upload" Disabled="@(File == null || Status != "")" Type="@ButtonType.Primary">Upload</Button>
|
|
<Button OnClick="Cancel">Cancel</Button>
|
|
</Flex>
|
|
}
|
|
else
|
|
{
|
|
<Collapse>
|
|
@foreach (var group in ImportItems.GroupBy(i => i.Flag))
|
|
{
|
|
<Panel Key="@group.Key.ToString()">
|
|
<HeaderTemplate>
|
|
<Flex Direction="FlexDirection.Horizontal" Gap="FlexGap.Small">
|
|
<Checkbox @bind-Checked="SelectedFlags[group.Key]" />
|
|
<Flex Direction="FlexDirection.Horizontal" Justify="FlexJustify.SpaceBetween">
|
|
<Text>@group.Key (@(group.Count()))</Text>
|
|
|
|
@{
|
|
var size = group.Sum(i => i.Size);
|
|
|
|
if (size > 0)
|
|
{
|
|
<ByteSize Value="size" />
|
|
}
|
|
}
|
|
</Flex>
|
|
</Flex>
|
|
</HeaderTemplate>
|
|
<ChildContent>
|
|
<AntList DataSource="group">
|
|
<ChildContent Context="item">
|
|
<ListItem>
|
|
<Flex Direction="FlexDirection.Horizontal" Justify="FlexJustify.SpaceBetween">
|
|
<Text>@item.Name</Text>
|
|
|
|
@if (item.Size > 0)
|
|
{
|
|
<ByteSize Value="item.Size"/>
|
|
}
|
|
</Flex>
|
|
</ListItem>
|
|
</ChildContent>
|
|
</AntList>
|
|
</ChildContent>
|
|
</Panel>
|
|
}
|
|
</Collapse>
|
|
|
|
<Flex Justify="FlexJustify.End" Gap="FlexGap.Small" Style="margin-top: 16px;">
|
|
<Button OnClick="Import" Type="@ButtonType.Primary">Import</Button>
|
|
<Button OnClick="Cancel">Cancel</Button>
|
|
</Flex>
|
|
}
|
|
|
|
@code {
|
|
IBrowserFile File;
|
|
ChunkUploader ChunkUploader;
|
|
StorageLocation StorageLocation = new();
|
|
ImportContext ImportContext;
|
|
|
|
IEnumerable<ImportItemInfo> ImportItems = new List<ImportItemInfo>();
|
|
|
|
string RootPath = Path.GetPathRoot(Directory.GetCurrentDirectory());
|
|
|
|
bool Uploaded = false;
|
|
bool IsValid = false;
|
|
string Filename;
|
|
string Status;
|
|
|
|
Dictionary<ImportRecordFlags, bool> SelectedFlags = Enum.GetValues<ImportRecordFlags>()
|
|
.ToDictionary(
|
|
f => f,
|
|
_ => true);
|
|
|
|
protected override async Task OnInitializedAsync()
|
|
{
|
|
ImportContext = ImportContextFactory.Create();
|
|
|
|
ImportContext.OnRecordError += RecordError;
|
|
ImportContext.OnRecordAdded += RecordAdded;
|
|
ImportContext.OnRecordProcessed += RecordProcessed;
|
|
|
|
StorageLocation = await StorageLocationService.FirstAsync(l => l.Default && l.Type == StorageLocationType.Archive);
|
|
}
|
|
|
|
private void RecordProcessed(object? sender, object e)
|
|
{
|
|
|
|
}
|
|
|
|
private void RecordAdded(object? sender, object e)
|
|
{
|
|
|
|
}
|
|
|
|
private void RecordError(object? sender, object e)
|
|
{
|
|
|
|
}
|
|
|
|
async Task Upload()
|
|
{
|
|
await ChunkUploader.Start();
|
|
}
|
|
|
|
async Task Import()
|
|
{
|
|
var flags = SelectedFlags
|
|
.Where(f => f.Value)
|
|
.Aggregate(ImportRecordFlags.None, (cur, f) => cur | f.Key);
|
|
|
|
try
|
|
{
|
|
await ImportContext.PrepareImportQueueAsync(flags);
|
|
await ImportContext.ImportQueueAsync();
|
|
|
|
MessageService.Success("Game successfully imported!");
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
MessageService.Error("Game could not be imported!");
|
|
Logger?.LogError(ex, "An unknown error occurred while trying to import");
|
|
}
|
|
|
|
await Clear();
|
|
ImportContext.Dispose();
|
|
await CloseFeedbackAsync();
|
|
}
|
|
|
|
async Task Clear()
|
|
{
|
|
await ChunkUploader.Clear();
|
|
}
|
|
|
|
async Task Cancel()
|
|
{
|
|
await ChunkUploader.Clear();
|
|
await CloseFeedbackAsync();
|
|
}
|
|
|
|
public override async Task OnFeedbackCancelAsync(ModalClosingEventArgs args)
|
|
{
|
|
await Clear();
|
|
|
|
ImportContext.Dispose();
|
|
|
|
await base.OnFeedbackCancelAsync(args);
|
|
}
|
|
|
|
public override async Task OnFeedbackOkAsync(ModalClosingEventArgs args)
|
|
{
|
|
await ChunkUploader.Clear();
|
|
|
|
ImportContext.Dispose();
|
|
|
|
await base.OnFeedbackOkAsync(args);
|
|
}
|
|
|
|
public async Task OnUploadCompleted(string data)
|
|
{
|
|
if (Guid.TryParse(data, out var objectKey))
|
|
{
|
|
try
|
|
{
|
|
var archivePath = await ArchiveService.GetArchiveFileLocationAsync(objectKey.ToString());
|
|
|
|
ImportItems = await ImportContext.InitializeImportAsync(archivePath);
|
|
|
|
Uploaded = true;
|
|
|
|
await InvokeAsync(StateHasChanged);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Logger?.LogError(ex, "An unknown error occurred while trying to import");
|
|
MessageService.Error("An unknown error occurred while trying to import");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
await InvokeAsync(StateHasChanged);
|
|
|
|
MessageService.Error("Import file failed to upload!");
|
|
Logger.LogError("Import file failed to upload!");
|
|
|
|
await (base.OkCancelRef?.OnCancel?.Invoke() ?? Task.CompletedTask);
|
|
await CloseFeedbackAsync();
|
|
}
|
|
|
|
await Clear();
|
|
}
|
|
|
|
public async Task OnUploadError(string message)
|
|
{
|
|
await InvokeAsync(StateHasChanged);
|
|
|
|
MessageService.Error("An error occurred while trying to import");
|
|
Logger?.LogError($"An error occurred while trying to import: {message}");
|
|
|
|
await CloseFeedbackAsync();
|
|
}
|
|
|
|
public async Task OnLocalFileSelected(string path)
|
|
{
|
|
try
|
|
{
|
|
ImportItems = await ImportContext.InitializeImportAsync(path);
|
|
|
|
Uploaded = true;
|
|
|
|
await InvokeAsync(StateHasChanged);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Logger?.LogError(ex, "An unknown error occurred while trying to import");
|
|
MessageService.Error("An unknown error occurred while trying to import");
|
|
}
|
|
}
|
|
} |