569 lines
No EOL
23 KiB
C#
569 lines
No EOL
23 KiB
C#
using LANCommander.SDK;
|
|
using LANCommander.SDK.Enums;
|
|
using LANCommander.SDK.Helpers;
|
|
using LANCommander.Server.Data.Models;
|
|
using LANCommander.Server.ImportExport.Importers;
|
|
using LANCommander.Server.ImportExport.Models;
|
|
using LANCommander.Server.ImportExport.Services;
|
|
using LANCommander.Server.Services;
|
|
using Microsoft.Extensions.DependencyInjection;
|
|
using Microsoft.Extensions.Logging;
|
|
using SharpCompress.Archives;
|
|
using SharpCompress.Readers;
|
|
using ZipArchive = SharpCompress.Archives.Zip.ZipArchive;
|
|
|
|
namespace LANCommander.Server.ImportExport;
|
|
|
|
public class ImportContext : IDisposable
|
|
{
|
|
private Guid? Id { get; set; }
|
|
public object Manifest { get; private set; }
|
|
public BaseModel DataRecord { get; private set; }
|
|
public StorageLocation ArchiveStorageLocation { get; set; }
|
|
public IArchive Archive { get; private set; }
|
|
|
|
public IImportItemInfo CurrentItem { get; set; }
|
|
public int Processed;
|
|
public int Total;
|
|
|
|
private Queue<IImportItemInfo> Queue { get; } = new();
|
|
private IEnumerable<Guid> SelectedRecordIds { get; set; } = [];
|
|
|
|
public AsyncEventHandler<ImportStatusUpdate> OnImportStarted { get; set; } = new();
|
|
public AsyncEventHandler<ImportStatusUpdate> OnImportStatusUpdate { get; set; } = new();
|
|
public AsyncEventHandler<ImportStatusUpdate> OnImportComplete { get; set; } = new();
|
|
public AsyncEventHandler<ImportStatusUpdate> OnImportError = new();
|
|
|
|
private readonly ImportService _importService;
|
|
private readonly StorageLocationService _storageLocationService;
|
|
private readonly ILogger<ImportContext> _logger;
|
|
|
|
private string? _uploadedArchivePath;
|
|
|
|
#region Importers
|
|
private readonly ActionImporter _actions;
|
|
private readonly ArchiveImporter _archives;
|
|
private readonly CollectionImporter _collections;
|
|
private readonly CustomFieldImporter _customFields;
|
|
private readonly DeveloperImporter _developers;
|
|
private readonly EngineImporter _engines;
|
|
private readonly GameImporter _games;
|
|
private readonly GenreImporter _genres;
|
|
private readonly KeyImporter _keys;
|
|
private readonly MediaImporter _media;
|
|
private readonly MultiplayerModeImporter _multiplayerModes;
|
|
private readonly PlatformImporter _platforms;
|
|
private readonly PlaySessionImporter _playSessions;
|
|
private readonly PublisherImporter _publishers;
|
|
private readonly RedistributableImporter _redistributables;
|
|
private readonly SaveImporter _saves;
|
|
private readonly SavePathImporter _savePaths;
|
|
private readonly ScriptImporter _scripts;
|
|
private readonly ServerConsoleImporter _serverConsoles;
|
|
private readonly ServerHttpPathImporter _serverHttpPaths;
|
|
private readonly ServerImporter _servers;
|
|
private readonly TagImporter _tags;
|
|
private readonly ToolImporter _tools;
|
|
#endregion
|
|
|
|
public ImportContext(IServiceProvider serviceProvider)
|
|
{
|
|
_actions = serviceProvider.GetRequiredService<ActionImporter>();
|
|
_archives = serviceProvider.GetRequiredService<ArchiveImporter>();
|
|
_collections = serviceProvider.GetRequiredService<CollectionImporter>();
|
|
_customFields = serviceProvider.GetRequiredService<CustomFieldImporter>();
|
|
_developers = serviceProvider.GetRequiredService<DeveloperImporter>();
|
|
_engines = serviceProvider.GetRequiredService<EngineImporter>();
|
|
_games = serviceProvider.GetRequiredService<GameImporter>();
|
|
_genres = serviceProvider.GetRequiredService<GenreImporter>();
|
|
_keys = serviceProvider.GetRequiredService<KeyImporter>();
|
|
_media = serviceProvider.GetRequiredService<MediaImporter>();
|
|
_multiplayerModes = serviceProvider.GetRequiredService<MultiplayerModeImporter>();
|
|
_platforms = serviceProvider.GetRequiredService<PlatformImporter>();
|
|
_playSessions = serviceProvider.GetRequiredService<PlaySessionImporter>();
|
|
_publishers = serviceProvider.GetRequiredService<PublisherImporter>();
|
|
_redistributables = serviceProvider.GetRequiredService<RedistributableImporter>();
|
|
_saves = serviceProvider.GetRequiredService<SaveImporter>();
|
|
_savePaths = serviceProvider.GetRequiredService<SavePathImporter>();
|
|
_scripts = serviceProvider.GetRequiredService<ScriptImporter>();
|
|
_serverConsoles = serviceProvider.GetRequiredService<ServerConsoleImporter>();
|
|
_serverHttpPaths = serviceProvider.GetRequiredService<ServerHttpPathImporter>();
|
|
_servers = serviceProvider.GetRequiredService<ServerImporter>();
|
|
_tags = serviceProvider.GetRequiredService<TagImporter>();
|
|
_tools = serviceProvider.GetRequiredService<ToolImporter>();
|
|
|
|
_importService = serviceProvider.GetRequiredService<ImportService>();
|
|
_storageLocationService = serviceProvider.GetRequiredService<StorageLocationService>();
|
|
_logger = serviceProvider.GetRequiredService<ILogger<ImportContext>>();
|
|
}
|
|
|
|
internal bool InQueue<TRecord>(TRecord record, BaseImporter<TRecord> importer)
|
|
where TRecord : class =>
|
|
Queue.Any(qi => qi.Key == importer.GetKey(record));
|
|
|
|
public void SetId(Guid id) => Id = id;
|
|
|
|
public void TrackUploadedArchive(string path) => _uploadedArchivePath = path;
|
|
|
|
#region Initialize Import
|
|
public async Task<IEnumerable<IImportItemInfo>> InitializeImportAsync(string archivePath)
|
|
{
|
|
_actions.UseContext(this);
|
|
_archives.UseContext(this);
|
|
_collections.UseContext(this);
|
|
_customFields.UseContext(this);
|
|
_developers.UseContext(this);
|
|
_engines.UseContext(this);
|
|
_games.UseContext(this);
|
|
_genres.UseContext(this);
|
|
_keys.UseContext(this);
|
|
_media.UseContext(this);
|
|
_multiplayerModes.UseContext(this);
|
|
_platforms.UseContext(this);
|
|
_playSessions.UseContext(this);
|
|
_publishers.UseContext(this);
|
|
_redistributables.UseContext(this);
|
|
_saves.UseContext(this);
|
|
_savePaths.UseContext(this);
|
|
_scripts.UseContext(this);
|
|
_serverConsoles.UseContext(this);
|
|
_serverHttpPaths.UseContext(this);
|
|
_servers.UseContext(this);
|
|
_tags.UseContext(this);
|
|
_tools.UseContext(this);
|
|
|
|
Archive = ZipArchive.OpenArchive(archivePath, new ReaderOptions());
|
|
|
|
var manifestEntry = Archive.Entries.FirstOrDefault(e => e.Key == ManifestHelper.ManifestFilename);
|
|
|
|
// Legacy purposes
|
|
if (manifestEntry == null)
|
|
manifestEntry = Archive.Entries.FirstOrDefault(e => e.Key == "_manifest.yml");
|
|
|
|
if (manifestEntry == null)
|
|
throw new InvalidOperationException("Invalid import file, cannot load manifest");
|
|
|
|
using (var reader = new StreamReader(manifestEntry.OpenEntryStream()))
|
|
{
|
|
var manifestContents = await reader.ReadToEndAsync();
|
|
var manifestMeta = ManifestHelper.Deserialize<SDK.Models.Manifest.BaseManifest>(manifestContents);
|
|
|
|
// Check for legacy manifest
|
|
if (manifestMeta.IsLegacyManifest())
|
|
{
|
|
if (ManifestHelper.TryDeserialize<Legacy.Models.GameManifest>(manifestContents, out var legacyGameManifest))
|
|
return await InitializeLegacyGameImportAsync(legacyGameManifest);
|
|
}
|
|
|
|
if (ManifestHelper.TryDeserialize<SDK.Models.Manifest.Game>(manifestContents, out var gameManifest))
|
|
return await InitializeGameImportAsync(gameManifest);
|
|
|
|
if (ManifestHelper.TryDeserialize<SDK.Models.Manifest.Redistributable>(manifestContents, out var redistributableManifest))
|
|
return await InitializeRedistributableImportAsync(redistributableManifest);
|
|
|
|
if (ManifestHelper.TryDeserialize<SDK.Models.Manifest.Server>(manifestContents, out var serverManifest))
|
|
return await InitializeServerImportAsync(serverManifest);
|
|
|
|
if (ManifestHelper.TryDeserialize<SDK.Models.Manifest.Tool>(manifestContents, out var toolManifest))
|
|
return await InitializeToolImportAsync(toolManifest);
|
|
|
|
throw new InvalidOperationException("Unknown manifest file");
|
|
}
|
|
}
|
|
|
|
public async Task InitializeMetadataUpdateAsync(SDK.Models.Manifest.Game gameManifest)
|
|
{
|
|
_developers.UseContext(this);
|
|
_engines.UseContext(this);
|
|
_games.UseContext(this);
|
|
_genres.UseContext(this);
|
|
_multiplayerModes.UseContext(this);
|
|
_publishers.UseContext(this);
|
|
_savePaths.UseContext(this);
|
|
_tags.UseContext(this);
|
|
|
|
Manifest = gameManifest;
|
|
|
|
await AddAsync(gameManifest.Developers, _developers);
|
|
|
|
if (gameManifest.Engine != null)
|
|
await AddAsync(gameManifest.Engine, _engines);
|
|
|
|
await AddAsync(gameManifest.Genres, _genres);
|
|
await AddAsync(gameManifest.MultiplayerModes, _multiplayerModes);
|
|
await AddAsync(gameManifest.Publishers, _publishers);
|
|
await AddAsync(gameManifest.SavePaths, _savePaths);
|
|
await AddAsync(gameManifest.Tags, _tags);
|
|
await AddAsync(gameManifest, _games);
|
|
}
|
|
|
|
private async Task<IEnumerable<IImportItemInfo>> InitializeLegacyGameImportAsync(
|
|
Legacy.Models.GameManifest gameManifest)
|
|
{
|
|
var manifest = gameManifest.UpdateManifest();
|
|
|
|
if (gameManifest.Scripts != null)
|
|
foreach (var script in gameManifest.Scripts)
|
|
{
|
|
_scripts.AddAsset(new ImportAssetArchiveEntry
|
|
{
|
|
Name = script.Name,
|
|
RecordId = script.Id,
|
|
Path = $"Scripts/{script.Id}",
|
|
});
|
|
}
|
|
|
|
if (gameManifest.Media != null)
|
|
foreach (var media in gameManifest.Media)
|
|
{
|
|
_media.AddAsset(new ImportAssetArchiveEntry
|
|
{
|
|
RecordId = media.Id,
|
|
Name = media.Type.ToString(),
|
|
Path = $"Media/{media.FileId}",
|
|
});
|
|
}
|
|
|
|
if (gameManifest.Archives != null)
|
|
foreach (var archive in gameManifest.Archives)
|
|
{
|
|
_archives.AddAsset(new ImportAssetArchiveEntry
|
|
{
|
|
RecordId = archive.Id,
|
|
Name = archive.Version,
|
|
Path = $"Archives/{archive.ObjectKey}",
|
|
});
|
|
}
|
|
|
|
return await InitializeGameImportAsync(manifest);
|
|
}
|
|
|
|
private async Task<IEnumerable<IImportItemInfo>> InitializeGameImportAsync(SDK.Models.Manifest.Game gameManifest)
|
|
{
|
|
Manifest = gameManifest;
|
|
|
|
var importItemInfo = new List<IImportItemInfo>();
|
|
|
|
importItemInfo.AddRange(await GetImportItemInfoAsync(gameManifest.Actions, _actions).ToListAsync());
|
|
importItemInfo.AddRange(await GetImportItemInfoAsync(gameManifest.Archives, _archives).ToListAsync());
|
|
importItemInfo.AddRange(await GetImportItemInfoAsync(gameManifest.Collections, _collections).ToListAsync());
|
|
importItemInfo.AddRange(await GetImportItemInfoAsync(gameManifest.CustomFields, _customFields).ToListAsync());
|
|
importItemInfo.AddRange(await GetImportItemInfoAsync(gameManifest.Developers, _developers).ToListAsync());
|
|
|
|
if (gameManifest.Engine != null)
|
|
importItemInfo.AddRange(await GetImportItemInfoAsync([gameManifest.Engine], _engines).ToListAsync());
|
|
|
|
importItemInfo.AddRange(await GetImportItemInfoAsync(gameManifest.Genres, _genres).ToListAsync());
|
|
importItemInfo.AddRange(await GetImportItemInfoAsync(gameManifest.Keys, _keys).ToListAsync());
|
|
importItemInfo.AddRange(await GetImportItemInfoAsync(gameManifest.Media, _media).ToListAsync());
|
|
importItemInfo.AddRange(await GetImportItemInfoAsync(gameManifest.MultiplayerModes, _multiplayerModes).ToListAsync());
|
|
importItemInfo.AddRange(await GetImportItemInfoAsync(gameManifest.Platforms, _platforms).ToListAsync());
|
|
importItemInfo.AddRange(await GetImportItemInfoAsync(gameManifest.PlaySessions, _playSessions).ToListAsync());
|
|
importItemInfo.AddRange(await GetImportItemInfoAsync(gameManifest.Publishers, _publishers).ToListAsync());
|
|
importItemInfo.AddRange(await GetImportItemInfoAsync(gameManifest.Saves, _saves).ToListAsync());
|
|
importItemInfo.AddRange(await GetImportItemInfoAsync(gameManifest.SavePaths, _savePaths).ToListAsync());
|
|
importItemInfo.AddRange(await GetImportItemInfoAsync(gameManifest.Scripts, _scripts).ToListAsync());
|
|
importItemInfo.AddRange(await GetImportItemInfoAsync(gameManifest.Tags, _tags).ToListAsync());
|
|
|
|
return importItemInfo;
|
|
}
|
|
|
|
private async Task<IEnumerable<IImportItemInfo>> InitializeRedistributableImportAsync(SDK.Models.Manifest.Redistributable redistributableManifest)
|
|
{
|
|
Manifest = redistributableManifest;
|
|
|
|
var importItemInfo = new List<IImportItemInfo>();
|
|
|
|
importItemInfo.AddRange(await GetImportItemInfoAsync(redistributableManifest.Archives, _archives).ToListAsync());
|
|
importItemInfo.AddRange(await GetImportItemInfoAsync(redistributableManifest.Scripts, _scripts).ToListAsync());
|
|
|
|
return importItemInfo;
|
|
}
|
|
|
|
private async Task<IEnumerable<IImportItemInfo>> InitializeServerImportAsync(SDK.Models.Manifest.Server serverManifest)
|
|
{
|
|
Manifest = serverManifest;
|
|
|
|
var importItemInfo = new List<IImportItemInfo>();
|
|
|
|
importItemInfo.AddRange(await GetImportItemInfoAsync(serverManifest.Actions, _actions).ToListAsync());
|
|
importItemInfo.AddRange(await GetImportItemInfoAsync(serverManifest.Scripts, _scripts).ToListAsync());
|
|
importItemInfo.AddRange(await GetImportItemInfoAsync(serverManifest.ServerConsoles, _serverConsoles).ToListAsync());
|
|
importItemInfo.AddRange(await GetImportItemInfoAsync(serverManifest.HttpPaths, _serverHttpPaths).ToListAsync());
|
|
|
|
return importItemInfo;
|
|
}
|
|
|
|
private async Task<IEnumerable<IImportItemInfo>> InitializeToolImportAsync(SDK.Models.Manifest.Tool toolManifest)
|
|
{
|
|
Manifest = toolManifest;
|
|
|
|
var importItemInfo = new List<IImportItemInfo>();
|
|
|
|
importItemInfo.AddRange(await GetImportItemInfoAsync(toolManifest.Archives, _archives).ToListAsync());
|
|
importItemInfo.AddRange(await GetImportItemInfoAsync(toolManifest.Scripts, _scripts).ToListAsync());
|
|
|
|
return importItemInfo;
|
|
}
|
|
#endregion
|
|
|
|
public async Task PrepareImportQueueAsync(IEnumerable<Guid> selectedRecordIds, Guid storageLocationId)
|
|
{
|
|
SelectedRecordIds = selectedRecordIds;
|
|
|
|
ArchiveStorageLocation = await _storageLocationService.GetAsync(storageLocationId);
|
|
|
|
if (Manifest is SDK.Models.Manifest.Game gameManifest)
|
|
await AddAsync(gameManifest);
|
|
|
|
if (Manifest is SDK.Models.Manifest.Redistributable redistributableManifest)
|
|
await AddAsync(redistributableManifest);
|
|
|
|
if (Manifest is SDK.Models.Manifest.Server serverManifest)
|
|
await AddAsync(serverManifest);
|
|
|
|
if (Manifest is SDK.Models.Manifest.Tool toolManifest)
|
|
await AddAsync(toolManifest);
|
|
}
|
|
|
|
public async Task AddAsync(SDK.Models.Manifest.Game game)
|
|
{
|
|
await AddAsync(game.Actions, _actions);
|
|
await AddAsync(game.Archives, _archives);
|
|
await AddAsync(game.Collections, _collections);
|
|
await AddAsync(game.CustomFields, _customFields);
|
|
await AddAsync(game.Developers, _developers);
|
|
await AddAsync(game.Engine, _engines);
|
|
await AddAsync(game.Genres, _genres);
|
|
await AddAsync(game.Keys, _keys);
|
|
await AddAsync(game.Media, _media);
|
|
await AddAsync(game.MultiplayerModes, _multiplayerModes);
|
|
await AddAsync(game.Platforms, _platforms);
|
|
await AddAsync(game.PlaySessions, _playSessions);
|
|
await AddAsync(game.Publishers, _publishers);
|
|
await AddAsync(game.Saves, _saves);
|
|
await AddAsync(game.SavePaths, _savePaths);
|
|
await AddAsync(game.Scripts, _scripts);
|
|
await AddAsync(game.Tags, _tags);
|
|
await AddAsync(game, _games);
|
|
}
|
|
|
|
public async Task AddAsync(SDK.Models.Manifest.Redistributable redistributable)
|
|
{
|
|
await AddAsync(redistributable.Archives, _archives);
|
|
await AddAsync(redistributable.Scripts, _scripts);
|
|
await AddAsync(redistributable, _redistributables);
|
|
}
|
|
|
|
public async Task AddAsync(SDK.Models.Manifest.Server server)
|
|
{
|
|
await AddAsync(server.Actions, _actions);
|
|
await AddAsync(server.Scripts, _scripts);
|
|
await AddAsync(server.HttpPaths, _serverHttpPaths);
|
|
await AddAsync(server.ServerConsoles, _serverConsoles);
|
|
await AddAsync(server, _servers);
|
|
}
|
|
|
|
public async Task AddAsync(SDK.Models.Manifest.Tool tool)
|
|
{
|
|
await AddAsync(tool.Archives, _archives);
|
|
await AddAsync(tool.Scripts, _scripts);
|
|
await AddAsync(tool, _tools);
|
|
}
|
|
|
|
private async Task AddAsync<TRecord>(IEnumerable<TRecord> records, BaseImporter<TRecord> importer)
|
|
where TRecord : class
|
|
{
|
|
foreach (var record in records)
|
|
await AddAsync(record, importer);
|
|
}
|
|
|
|
private async Task AddAsync<TRecord>(TRecord? record, BaseImporter<TRecord> importer)
|
|
where TRecord : class
|
|
{
|
|
if (record != null && !InQueue(record, importer) && await importer.CanImportAsync(record))
|
|
{
|
|
var importInfo = await importer.GetImportInfoAsync(record);
|
|
|
|
importInfo.Key = importer.GetKey(record);
|
|
|
|
Queue.Enqueue(importInfo);
|
|
}
|
|
}
|
|
|
|
public async Task ImportQueueAsync()
|
|
{
|
|
Processed = 0;
|
|
Total = Queue.Count;
|
|
|
|
await OnImportStarted?.InvokeAsync(new ImportStatusUpdate
|
|
{
|
|
Index = Processed,
|
|
Total = Total,
|
|
})!;
|
|
|
|
int deferred = 0;
|
|
|
|
while (Queue.Count > 0)
|
|
{
|
|
var queueItem = Queue.Dequeue();
|
|
|
|
await OnImportStatusUpdate?.InvokeAsync(new ImportStatusUpdate
|
|
{
|
|
CurrentItem = queueItem,
|
|
Index = Processed,
|
|
Total = Total,
|
|
})!;
|
|
|
|
var success = await TryImportAsync(queueItem);
|
|
|
|
if (success)
|
|
{
|
|
Processed++;
|
|
deferred = 0;
|
|
continue;
|
|
}
|
|
|
|
Queue.Enqueue(queueItem);
|
|
deferred++;
|
|
|
|
if (deferred >= Queue.Count)
|
|
throw new InvalidOperationException("Import deadlocked: remaining jobs cannot be satisfied.");
|
|
}
|
|
|
|
await OnImportComplete?.InvokeAsync(new ImportStatusUpdate
|
|
{
|
|
Index = Total,
|
|
Total = Total,
|
|
})!;
|
|
|
|
_importService.RemoveContext(Id.Value);
|
|
}
|
|
|
|
private async Task<bool> TryImportAsync(IImportItemInfo queueItem)
|
|
{
|
|
try
|
|
{
|
|
switch (queueItem.Type)
|
|
{
|
|
case ImportExportRecordType.Action:
|
|
return await _actions.ImportAsync(queueItem);
|
|
|
|
case ImportExportRecordType.Archive:
|
|
return await _archives.ImportAsync(queueItem);
|
|
|
|
case ImportExportRecordType.Collection:
|
|
return await _collections.ImportAsync(queueItem);
|
|
|
|
case ImportExportRecordType.CustomField:
|
|
return await _customFields.ImportAsync(queueItem);
|
|
|
|
case ImportExportRecordType.Developer:
|
|
return await _developers.ImportAsync(queueItem);
|
|
|
|
case ImportExportRecordType.Engine:
|
|
return await _engines.ImportAsync(queueItem);
|
|
|
|
case ImportExportRecordType.Game:
|
|
return await _games.ImportAsync(queueItem);
|
|
|
|
case ImportExportRecordType.Genre:
|
|
return await _genres.ImportAsync(queueItem);
|
|
|
|
case ImportExportRecordType.Key:
|
|
return await _keys.ImportAsync(queueItem);
|
|
|
|
case ImportExportRecordType.Media:
|
|
return await _media.ImportAsync(queueItem);
|
|
|
|
case ImportExportRecordType.MultiplayerMode:
|
|
return await _multiplayerModes.ImportAsync(queueItem);
|
|
|
|
case ImportExportRecordType.Platform:
|
|
return await _platforms.ImportAsync(queueItem);
|
|
|
|
case ImportExportRecordType.PlaySession:
|
|
return await _playSessions.ImportAsync(queueItem);
|
|
|
|
case ImportExportRecordType.Publisher:
|
|
return await _publishers.ImportAsync(queueItem);
|
|
|
|
case ImportExportRecordType.Redistributable:
|
|
return await _redistributables.ImportAsync(queueItem);
|
|
|
|
case ImportExportRecordType.Save:
|
|
return await _saves.ImportAsync(queueItem);
|
|
|
|
case ImportExportRecordType.SavePath:
|
|
return await _savePaths.ImportAsync(queueItem);
|
|
|
|
case ImportExportRecordType.Script:
|
|
return await _scripts.ImportAsync(queueItem);
|
|
|
|
case ImportExportRecordType.Server:
|
|
return await _servers.ImportAsync(queueItem);
|
|
|
|
case ImportExportRecordType.ServerConsole:
|
|
return await _serverConsoles.ImportAsync(queueItem);
|
|
|
|
case ImportExportRecordType.ServerHttpPath:
|
|
return await _serverHttpPaths.ImportAsync(queueItem);
|
|
|
|
case ImportExportRecordType.Tag:
|
|
return await _tags.ImportAsync(queueItem);
|
|
|
|
case ImportExportRecordType.Tool:
|
|
return await _tools.ImportAsync(queueItem);
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
_logger.LogError(ex, "Error importing record {RecordName}", queueItem.Name);
|
|
|
|
await OnImportError?.InvokeAsync(new ImportStatusUpdate
|
|
{
|
|
CurrentItem = CurrentItem,
|
|
Index = Processed,
|
|
Total = Total,
|
|
Error = ex.Message,
|
|
})!;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
private async IAsyncEnumerable<ImportItemInfo<TRecord>> GetImportItemInfoAsync<TRecord>(IEnumerable<TRecord> records,
|
|
BaseImporter<TRecord> importer) where TRecord : class
|
|
{
|
|
if (records != null)
|
|
foreach (var record in records)
|
|
{
|
|
if (record != null && record.GetType() == typeof(TRecord))
|
|
{
|
|
var importInfo = await importer.GetImportInfoAsync(record);
|
|
|
|
importInfo.Key = importer.GetKey(record);
|
|
|
|
yield return importInfo;
|
|
}
|
|
}
|
|
}
|
|
|
|
public void Dispose()
|
|
{
|
|
if (Archive != null)
|
|
Archive.Dispose();
|
|
|
|
if (_uploadedArchivePath != null && File.Exists(_uploadedArchivePath))
|
|
{
|
|
try
|
|
{
|
|
File.Delete(_uploadedArchivePath);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
_logger.LogWarning(ex, "Could not delete uploaded import archive at {Path}", _uploadedArchivePath);
|
|
}
|
|
}
|
|
}
|
|
} |