using MBN_STOCK_WEBVIEW.Infrastructure; using MMoneyCoderSharp.Data; namespace MBN_STOCK_WEBVIEW; public sealed partial class MainWindow { private LegacyNamedComparisonRestoreService? _namedComparisonRestoreService; private async Task PostNamedComparisonRestoreAsync( string requestId, IReadOnlyList items, CancellationToken cancellationToken) { var candidates = items .Select(static item => new LegacyNamedComparisonRestoreRow( item.ItemIndex, item.IsEnabled, item.Selection.GroupCode, item.Selection.Subject, item.Selection.GraphicType, item.Selection.Subtype, item.Page?.ToString() ?? string.Empty, item.Selection.DataCode)) .Where(LegacyNamedComparisonRestoreService.IsCandidate) .ToArray(); if (candidates.Length == 0) { return; } try { var runtime = _databaseRuntime; if (runtime is null) { PostNamedComparisonRestoreError( requestId, "DATABASE_UNAVAILABLE", "현재 종목 마스터 DB를 사용할 수 없어 비교 행을 재검증하지 못했습니다."); return; } var service = _namedComparisonRestoreService ??= new LegacyNamedComparisonRestoreService(runtime.Executor); var result = await service.ResolveAsync(candidates, cancellationToken); cancellationToken.ThrowIfCancellationRequested(); PostMessage("named-comparison-restore-results", new { requestId, result.RetrievedAt, totalRowCount = result.Rows.Count, rows = result.Rows.Select(ToNamedComparisonRestoreWireRow) }); } catch (OperationCanceledException) when (cancellationToken.IsCancellationRequested) { if (Volatile.Read(ref _playoutCommandInFlight) != 0 && !_lifetimeCancellation.IsCancellationRequested) { PostNamedComparisonRestoreError( requestId, "PLAYOUT_PRIORITY", "송출 명령 우선 처리로 비교 행 재검증을 취소했습니다. 자동 재시도하지 않습니다."); } throw; } catch (DatabaseOperationException) { PostNamedComparisonRestoreError( requestId, "DATABASE_UNAVAILABLE", "현재 종목 마스터 DB에서 비교 행을 재검증하지 못했습니다."); _ = PostDatabaseStatusAsync(_lifetimeCancellation.Token); } catch { PostNamedComparisonRestoreError( requestId, "RESTORE_FAILED", "저장된 비교 행을 현재 명시적 선택으로 안전하게 복원하지 못했습니다."); } } private static object ToNamedComparisonRestoreWireRow( LegacyNamedComparisonRestoreOutcome outcome) { if (outcome.IsResolved) { return new { outcome.ItemIndex, status = "resolved", outcome.ActionId, first = ToLegacyComparisonImportWireTarget(outcome.First!), second = ToLegacyComparisonImportWireTarget(outcome.Second!) }; } return new { outcome.ItemIndex, status = "failed", failure = outcome.Failure switch { LegacyNamedComparisonRestoreFailure.InvalidRow => "INVALID_ROW", LegacyNamedComparisonRestoreFailure.MissingMarketIdentity => "MISSING_MARKET_IDENTITY", LegacyNamedComparisonRestoreFailure.IdentityNotFound => "IDENTITY_NOT_FOUND", LegacyNamedComparisonRestoreFailure.IdentityAmbiguous => "IDENTITY_AMBIGUOUS", LegacyNamedComparisonRestoreFailure.UnsupportedAction => "UNSUPPORTED_ACTION", LegacyNamedComparisonRestoreFailure.DatabaseDataInvalid => "DATABASE_DATA_INVALID", _ => "RESTORE_FAILED" } }; } private void PostNamedComparisonRestoreError( string requestId, string code, string message) { PostMessage("named-comparison-restore-error", new { requestId, code, message, retryable = false }); } }