233 lines
9.5 KiB
C#
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));
|
|
}
|
|
}
|