Files
MBN_STOCK_WEBVIEW/src/MBN_STOCK_WEBVIEW.LegacyParityApp/MainWindow.ManualLists.cs

233 lines
9.5 KiB
C#

using MBN_STOCK_WEBVIEW.Core.Playout.Scenes;
using MBN_STOCK_WEBVIEW.Infrastructure;
using MBN_STOCK_WEBVIEW.LegacyApplication;
namespace MBN_STOCK_WEBVIEW.LegacyParityApp;
public sealed partial class MainWindow
{
private const string OperatorDataDirectoryEnvironmentVariable =
"MBN_STOCK_OPERATOR_DATA_DIRECTORY";
private S5025TrustedManualFileStore? _manualNetSellStore;
private ViTrustedManualFileStore? _manualViStore;
private LegacyManualOperatorDataImporter? _manualDataImporter;
private LegacyManualListsWorkflow CreateManualListsWorkflow(
ILegacyStockLookup stockLookup)
{
ILegacyManualListStore store;
try
{
if (!string.IsNullOrWhiteSpace(Environment.GetEnvironmentVariable(
OperatorDataDirectoryEnvironmentVariable)))
{
store = new UnavailableManualListStore(
"UNSAFE_CONFIGURATION",
"외부 경로 설정은 사용하지 않습니다. 앱 전용 로컬 저장소만 사용할 수 있습니다.");
return new LegacyManualListsWorkflow(store, stockLookup);
}
var directory = TrustedManualDirectory.PreparePrivateWritableDirectory(
Path.Combine(
Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData),
"MBN_STOCK_WEBVIEW",
"OperatorData"));
var inspection = LegacyManualOperatorDataRuntimeGuard.Inspect(directory);
if (!inspection.IsReady)
{
var interrupted = inspection.State ==
LegacyManualOperatorDataRuntimeState.InterruptedImport;
store = new UnavailableManualListStore(
interrupted ? "IMPORT_INTERRUPTED" : "IMPORTED_STATE_INVALID",
interrupted
? "이전 원본 데이터 가져오기가 중단되어 수동 파일을 열지 않았습니다."
: "수동 데이터 가져오기 표식과 파일 상태가 일치하지 않습니다.");
return new LegacyManualListsWorkflow(store, stockLookup);
}
_manualNetSellStore = new S5025TrustedManualFileStore(directory);
_manualViStore = new ViTrustedManualFileStore(directory);
_manualDataImporter = new LegacyManualOperatorDataImporter(
directory,
new FixedLegacyManualOperatorDataSource());
store = new TrustedManualListStore(
_manualNetSellStore,
_manualViStore,
_manualDataImporter);
}
catch
{
_manualDataImporter?.Dispose();
_manualViStore?.Dispose();
_manualNetSellStore?.Dispose();
_manualDataImporter = null;
_manualViStore = null;
_manualNetSellStore = null;
store = new UnavailableManualListStore(
"INITIALIZATION_FAILED",
"수동 순매도/VI 로컬 저장소를 초기화하지 못했습니다.");
}
return new LegacyManualListsWorkflow(store, stockLookup);
}
private void ShutdownManualListsRuntime()
{
var importer = Interlocked.Exchange(ref _manualDataImporter, null);
var viStore = Interlocked.Exchange(ref _manualViStore, null);
var netStore = Interlocked.Exchange(ref _manualNetSellStore, null);
if (importer is null && viStore is null && netStore is null)
{
return;
}
_ = Task.Run(async () =>
{
await _intentGate.WaitAsync().ConfigureAwait(false);
try
{
importer?.Dispose();
viStore?.Dispose();
netStore?.Dispose();
}
finally
{
_intentGate.Release();
}
});
}
private sealed class TrustedManualListStore : ILegacyManualListStore
{
private readonly S5025TrustedManualFileStore _netStore;
private readonly ViTrustedManualFileStore _viStore;
private readonly LegacyManualOperatorDataImporter _importer;
public TrustedManualListStore(
S5025TrustedManualFileStore netStore,
ViTrustedManualFileStore viStore,
LegacyManualOperatorDataImporter importer)
{
_netStore = netStore;
_viStore = viStore;
_importer = importer;
}
public LegacyManualListStoreAvailability Availability { get; } =
new(true, "READY", null);
public Task<IReadOnlyList<S5025TrustedManualRow>> ReadNetSellAsync(
S5025ManualAudience audience,
CancellationToken cancellationToken = default) =>
_netStore.ReadAsync(audience, cancellationToken);
public Task WriteNetSellAsync(
S5025ManualAudience audience,
IReadOnlyList<S5025TrustedManualRow> rows,
CancellationToken cancellationToken = default) =>
_netStore.WriteAsync(audience, rows, cancellationToken);
public async Task<LegacyManualViStoreSnapshot> ReadViAsync(
CancellationToken cancellationToken = default)
{
var snapshot = await _viStore.ReadSnapshotAsync(cancellationToken)
.ConfigureAwait(false);
return Map(snapshot);
}
public async Task<LegacyManualViWriteReceipt> WriteViAsync(
IReadOnlyList<LegacyManualViStoredItem> items,
CancellationToken cancellationToken = default)
{
var result = await _viStore.WriteAsync(
items.Select(item => new ViTrustedManualItem(item.Code, item.Name)).ToArray(),
cancellationToken).ConfigureAwait(false);
return new LegacyManualViWriteReceipt(Map(result.Snapshot), result.Persisted);
}
public async Task<LegacyManualImportReceipt> ImportAsync(
CancellationToken cancellationToken = default)
{
try
{
var result = await _importer.ImportAsync(cancellationToken)
.ConfigureAwait(false);
return new LegacyManualImportReceipt(
result.MarkerVersion,
result.SourceSha256,
result.ImportedAt,
result.NetSellRowCount,
result.ViItemCount);
}
catch (LegacyManualOperatorImportException exception)
{
throw new LegacyManualImportStoreException(
ImportFailureCode(exception.Failure),
exception.OutcomeUnknown);
}
}
private static LegacyManualViStoreSnapshot Map(ViTrustedManualSnapshot snapshot) =>
new(
Array.AsReadOnly(snapshot.Items.Select(item =>
new LegacyManualViStoredItem(item.Code, item.Name)).ToArray()),
snapshot.RowVersion);
private static string ImportFailureCode(LegacyManualOperatorImportFailure failure) =>
failure switch
{
LegacyManualOperatorImportFailure.SourceUnavailable => "SOURCE_UNAVAILABLE",
LegacyManualOperatorImportFailure.SourceInvalid => "SOURCE_INVALID",
LegacyManualOperatorImportFailure.AlreadyImported => "ALREADY_IMPORTED",
LegacyManualOperatorImportFailure.DestinationNotEmpty =>
"DESTINATION_NOT_EMPTY",
LegacyManualOperatorImportFailure.InterruptedImport => "INTERRUPTED_IMPORT",
LegacyManualOperatorImportFailure.ImportFailed => "IMPORT_FAILED",
LegacyManualOperatorImportFailure.RollbackFailed => "ROLLBACK_FAILED",
_ => "IMPORT_FAILED"
};
}
private sealed class UnavailableManualListStore : ILegacyManualListStore
{
private readonly string _message;
public UnavailableManualListStore(string code, string message)
{
_message = message;
Availability = new LegacyManualListStoreAvailability(false, code, message);
}
public LegacyManualListStoreAvailability Availability { get; }
public Task<IReadOnlyList<S5025TrustedManualRow>> ReadNetSellAsync(
S5025ManualAudience audience,
CancellationToken cancellationToken = default) =>
Task.FromException<IReadOnlyList<S5025TrustedManualRow>>(
new InvalidOperationException(_message));
public Task WriteNetSellAsync(
S5025ManualAudience audience,
IReadOnlyList<S5025TrustedManualRow> rows,
CancellationToken cancellationToken = default) =>
Task.FromException(new InvalidOperationException(_message));
public Task<LegacyManualViStoreSnapshot> ReadViAsync(
CancellationToken cancellationToken = default) =>
Task.FromException<LegacyManualViStoreSnapshot>(
new InvalidOperationException(_message));
public Task<LegacyManualViWriteReceipt> WriteViAsync(
IReadOnlyList<LegacyManualViStoredItem> items,
CancellationToken cancellationToken = default) =>
Task.FromException<LegacyManualViWriteReceipt>(
new InvalidOperationException(_message));
public Task<LegacyManualImportReceipt> ImportAsync(
CancellationToken cancellationToken = default) =>
Task.FromException<LegacyManualImportReceipt>(
new LegacyManualImportStoreException("UNAVAILABLE", false));
}
}