feat: complete legacy UI and playout parity migration
This commit is contained in:
@@ -14,6 +14,7 @@ public sealed partial class MainWindow : Window
|
||||
private readonly CancellationTokenSource _lifetimeCancellation = new();
|
||||
private readonly SemaphoreSlim _intentGate = new(1, 1);
|
||||
private readonly LegacyOperatorController _controller;
|
||||
private readonly LegacyIndustrySelectionWorkflow _industryWorkflow;
|
||||
private DatabaseRuntime? _databaseRuntime;
|
||||
private bool _closing;
|
||||
private bool _intentBusy;
|
||||
@@ -22,29 +23,144 @@ public sealed partial class MainWindow : Window
|
||||
public MainWindow()
|
||||
{
|
||||
InitializeComponent();
|
||||
EnsureCloseConfirmationAttached();
|
||||
|
||||
ILegacyStockLookup stockLookup;
|
||||
IIndustrySelectionService industrySelectionService;
|
||||
IThemeSelectionService themeSelectionService;
|
||||
IExpertSelectionService expertSelectionService;
|
||||
ITradingHaltSelectionService tradingHaltSelectionService;
|
||||
IOverseasIndustryIndexSearchService overseasIndustrySearchService;
|
||||
IWorldStockSearchService worldStockSearchService;
|
||||
IManualFinancialScreenService manualFinancialService;
|
||||
IStockSearchService manualFinancialStockSearchService;
|
||||
INamedPlaylistPersistenceService namedPlaylistPersistenceService;
|
||||
IThemeCatalogPersistenceService themeCatalogPersistenceService;
|
||||
IExpertCatalogPersistenceService expertCatalogPersistenceService;
|
||||
IStockMasterIdentityValidationService stockMasterIdentityValidationService;
|
||||
IOperatorCatalogSchemaValidationService operatorCatalogSchemaValidationService;
|
||||
string? initializationError = null;
|
||||
try
|
||||
{
|
||||
_databaseRuntime = DatabaseRuntime.CreateDefault();
|
||||
DataQueryExecutor.Configure(_databaseRuntime.Executor);
|
||||
stockLookup = new LegacyParityStockSearchService(_databaseRuntime.Executor);
|
||||
industrySelectionService = new LegacyIndustrySelectionService(
|
||||
_databaseRuntime.Executor);
|
||||
themeSelectionService = new LegacyThemeSelectionService(
|
||||
_databaseRuntime.Executor);
|
||||
expertSelectionService = new LegacyExpertSelectionService(
|
||||
_databaseRuntime.Executor);
|
||||
tradingHaltSelectionService = new LegacyTradingHaltSelectionService(
|
||||
_databaseRuntime.Executor);
|
||||
overseasIndustrySearchService = new LegacyOverseasIndustryIndexSearchService(
|
||||
_databaseRuntime.Executor);
|
||||
worldStockSearchService = new LegacyWorldStockSearchService(
|
||||
_databaseRuntime.Executor);
|
||||
manualFinancialService = new LegacyManualFinancialScreenService(
|
||||
_databaseRuntime.Executor,
|
||||
new OracleManualFinancialMutationExecutor(
|
||||
_databaseRuntime.ConnectionFactory,
|
||||
_databaseRuntime.Options.Resilience));
|
||||
manualFinancialStockSearchService = new LegacyStockSearchService(
|
||||
_databaseRuntime.Executor);
|
||||
namedPlaylistPersistenceService = new LegacyNamedPlaylistPersistenceService(
|
||||
_databaseRuntime.Executor,
|
||||
new OracleNamedPlaylistMutationExecutor(
|
||||
_databaseRuntime.ConnectionFactory,
|
||||
_databaseRuntime.Options.Resilience));
|
||||
var operatorCatalogMutationExecutor = new OperatorCatalogMutationExecutor(
|
||||
_databaseRuntime.ConnectionFactory,
|
||||
_databaseRuntime.Options.Resilience);
|
||||
themeCatalogPersistenceService = new LegacyThemeCatalogPersistenceService(
|
||||
_databaseRuntime.Executor,
|
||||
operatorCatalogMutationExecutor);
|
||||
expertCatalogPersistenceService = new LegacyExpertCatalogPersistenceService(
|
||||
_databaseRuntime.Executor,
|
||||
operatorCatalogMutationExecutor);
|
||||
stockMasterIdentityValidationService =
|
||||
new LegacyStockMasterIdentityValidationService(_databaseRuntime.Executor);
|
||||
operatorCatalogSchemaValidationService =
|
||||
new LegacyOperatorCatalogSchemaValidationService(_databaseRuntime.Executor);
|
||||
}
|
||||
catch
|
||||
{
|
||||
initializationError =
|
||||
"데이터베이스가 설정되지 않았습니다. 로컬 설정을 확인하세요.";
|
||||
stockLookup = new UnavailableStockLookup(initializationError);
|
||||
industrySelectionService = new UnavailableIndustrySelectionService(
|
||||
initializationError);
|
||||
themeSelectionService = new UnavailableThemeSelectionService(
|
||||
initializationError);
|
||||
expertSelectionService = new UnavailableExpertSelectionService(
|
||||
initializationError);
|
||||
tradingHaltSelectionService = new UnavailableTradingHaltSelectionService(
|
||||
initializationError);
|
||||
overseasIndustrySearchService = new UnavailableOverseasIndustryIndexSearchService(
|
||||
initializationError);
|
||||
worldStockSearchService = new UnavailableWorldStockSearchService(
|
||||
initializationError);
|
||||
manualFinancialService = new UnavailableManualFinancialScreenService(
|
||||
initializationError);
|
||||
manualFinancialStockSearchService = new UnavailableStockSearchService(
|
||||
initializationError);
|
||||
namedPlaylistPersistenceService = new UnavailableNamedPlaylistPersistenceService(
|
||||
initializationError);
|
||||
themeCatalogPersistenceService = new UnavailableThemeCatalogPersistenceService(
|
||||
initializationError);
|
||||
expertCatalogPersistenceService = new UnavailableExpertCatalogPersistenceService(
|
||||
initializationError);
|
||||
stockMasterIdentityValidationService =
|
||||
new UnavailableStockMasterIdentityValidationService(initializationError);
|
||||
operatorCatalogSchemaValidationService =
|
||||
new UnavailableOperatorCatalogSchemaValidationService(initializationError);
|
||||
DataQueryExecutor.Reset();
|
||||
}
|
||||
|
||||
_controller = new LegacyOperatorController(stockLookup);
|
||||
_industryWorkflow = new LegacyIndustrySelectionWorkflow(industrySelectionService);
|
||||
var overseasWorkflow = new LegacyOverseasSelectionWorkflow(
|
||||
overseasIndustrySearchService,
|
||||
worldStockSearchService);
|
||||
var comparisonStore = new LegacyComparisonPairFileStore(
|
||||
Path.Combine(
|
||||
Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData),
|
||||
"MBN_STOCK_WEBVIEW",
|
||||
"Data",
|
||||
"종목비교.dat"),
|
||||
Path.Combine(AppContext.BaseDirectory, "Data", "종목비교.dat"));
|
||||
var manualListsWorkflow = CreateManualListsWorkflow(stockLookup);
|
||||
_controller = new LegacyOperatorController(
|
||||
stockLookup,
|
||||
industryWorkflow: _industryWorkflow,
|
||||
themeWorkflow: new LegacyThemeWorkflow(themeSelectionService),
|
||||
expertWorkflow: new LegacyExpertWorkflowController(expertSelectionService),
|
||||
tradingHaltWorkflow: new LegacyTradingHaltWorkflowController(
|
||||
tradingHaltSelectionService),
|
||||
comparisonWorkflow: new LegacyComparisonWorkflowController(
|
||||
new LegacyComparisonDataService(stockLookup, worldStockSearchService),
|
||||
comparisonStore),
|
||||
manualFinancialWorkflow: new LegacyManualFinancialWorkflow(
|
||||
manualFinancialService,
|
||||
manualFinancialStockSearchService),
|
||||
namedPlaylistWorkflow: new LegacyNamedPlaylistWorkflowController(
|
||||
namedPlaylistPersistenceService),
|
||||
overseasWorkflow: overseasWorkflow,
|
||||
manualListsWorkflow: manualListsWorkflow,
|
||||
operatorCatalogWorkflow: new LegacyOperatorCatalogWorkflowController(
|
||||
themeSelectionService,
|
||||
expertSelectionService,
|
||||
themeCatalogPersistenceService,
|
||||
expertCatalogPersistenceService,
|
||||
manualFinancialStockSearchService,
|
||||
stockMasterIdentityValidationService,
|
||||
operatorCatalogSchemaValidationService));
|
||||
if (initializationError is not null)
|
||||
{
|
||||
_controller.ReportError(initializationError);
|
||||
}
|
||||
|
||||
InitializePlayoutRuntime();
|
||||
|
||||
Root.Loaded += OnRootLoaded;
|
||||
Closed += OnClosed;
|
||||
}
|
||||
@@ -59,10 +175,15 @@ public sealed partial class MainWindow : Window
|
||||
|
||||
ConfigureWindow();
|
||||
await InitializeWebViewAsync();
|
||||
if (!_closing)
|
||||
{
|
||||
await ConnectPlayoutAsync(_lifetimeCancellation.Token);
|
||||
}
|
||||
}
|
||||
|
||||
private void ConfigureWindow()
|
||||
{
|
||||
EnsureCloseConfirmationAttached();
|
||||
var windowHandle = WindowNative.GetWindowHandle(this);
|
||||
var windowId = Microsoft.UI.Win32Interop.GetWindowIdFromWindow(windowHandle);
|
||||
var appWindow = AppWindow.GetFromWindowId(windowId);
|
||||
@@ -208,15 +329,94 @@ public sealed partial class MainWindow : Window
|
||||
return;
|
||||
}
|
||||
|
||||
if (intent is LegacySearchStocksIntent searchIntent &&
|
||||
!(searchIntent.Trigger == LegacySearchTrigger.Button &&
|
||||
searchIntent.Text.Length == 0))
|
||||
if (IsOperatorMutationIntent(intent) && IsOperatorMutationQuarantined())
|
||||
{
|
||||
PostState(_controller.ReportError(
|
||||
"이전 저장 결과가 불명확하여 이번 실행의 추가 변경이 차단되었습니다. DB 또는 로컬 파일을 읽기 전용으로 대조한 뒤 앱을 다시 시작하세요."));
|
||||
return;
|
||||
}
|
||||
|
||||
if (_controller.Current.FixedSectionBatch is not null &&
|
||||
IsOperatorMutationIntent(intent) &&
|
||||
!IsFixedSectionBatchMutationIntent(intent))
|
||||
{
|
||||
PostState(_controller.ReportError(
|
||||
"고정 컷 섹션의 수동 입력 중에는 현재 입력 단계만 변경할 수 있습니다. 완료하거나 취소한 뒤 다른 편성 작업을 실행하세요."));
|
||||
return;
|
||||
}
|
||||
|
||||
if (IsOperatorMutationIntent(intent) && !CanAcceptOperatorMutation())
|
||||
{
|
||||
PostState(_controller.ReportError(
|
||||
"PREPARE 또는 송출 중에는 플레이리스트와 운영 데이터를 변경할 수 없습니다. TAKE OUT 후 다시 시도하세요."));
|
||||
return;
|
||||
}
|
||||
|
||||
if ((intent is LegacySearchStocksIntent searchIntent &&
|
||||
!(searchIntent.Trigger == LegacySearchTrigger.Button &&
|
||||
searchIntent.Text.Length == 0)) ||
|
||||
intent is LegacySelectTabIntent or
|
||||
LegacySearchThemesIntent or LegacySelectThemeIntent or
|
||||
LegacyActivateThemeResultIntent or
|
||||
LegacySearchExpertsIntent or LegacySelectExpertIntent or
|
||||
LegacySearchTradingHaltsIntent or
|
||||
LegacySearchComparisonDomesticIntent or
|
||||
LegacySearchComparisonWorldIntent or
|
||||
LegacySearchOverseasIndustriesIntent or
|
||||
LegacySearchOverseasStocksIntent or
|
||||
LegacyOpenOperatorCatalogIntent or
|
||||
LegacyBeginUc4ThemeCatalogIntent or
|
||||
LegacyEditUc4SelectedThemeIntent or
|
||||
LegacyDeleteUc4SelectedThemeIntent or
|
||||
LegacyBeginUc6ExpertCatalogIntent or
|
||||
LegacyEditUc6SelectedExpertIntent or
|
||||
LegacyDeleteUc6SelectedExpertIntent or
|
||||
LegacySearchOperatorCatalogIntent or
|
||||
LegacySelectOperatorCatalogResultIntent or
|
||||
LegacyBeginCreateThemeCatalogIntent or
|
||||
LegacyBeginCreateExpertCatalogIntent or
|
||||
LegacySearchOperatorCatalogStocksIntent or
|
||||
LegacyActivateOperatorCatalogStockIntent or
|
||||
LegacySetOperatorCatalogDraftBuyAmountIntent or
|
||||
LegacySaveOperatorCatalogIntent or
|
||||
LegacyDeleteOperatorCatalogIntent or
|
||||
LegacyAddComparisonPairIntent or
|
||||
LegacyMoveComparisonPairIntent or
|
||||
LegacyDeleteSelectedComparisonPairIntent or
|
||||
LegacyDeleteAllComparisonPairsIntent or
|
||||
LegacyOpenManualFinancialIntent or
|
||||
LegacySearchManualFinancialIntent or
|
||||
LegacyFindManualFinancialIntent or
|
||||
LegacyLoadManualFinancialIntent or
|
||||
LegacyActivateManualFinancialResultIntent or
|
||||
LegacySearchManualFinancialStocksIntent or
|
||||
LegacySaveManualFinancialIntent or
|
||||
LegacyDeleteManualFinancialIntent or
|
||||
LegacyDeleteAllManualFinancialIntent or
|
||||
LegacyOpenManualListIntent or
|
||||
LegacyRefreshManualListIntent or
|
||||
LegacySaveManualNetSellIntent or
|
||||
LegacySearchManualViIntent or
|
||||
LegacySaveManualViIntent or
|
||||
LegacyImportManualListsIntent or
|
||||
LegacyRefreshNamedPlaylistsIntent or
|
||||
LegacyLoadSelectedNamedPlaylistIntent or
|
||||
LegacyLoadNamedPlaylistByIdIntent or
|
||||
LegacyCreateNamedPlaylistIntent or
|
||||
LegacySaveCurrentNamedPlaylistIntent or
|
||||
LegacySaveCurrentNamedPlaylistToIntent or
|
||||
LegacyDeleteSelectedNamedPlaylistIntent or
|
||||
LegacyExecutePlayoutIntent or
|
||||
LegacySetFadeDurationIntent or
|
||||
LegacyToggleBackgroundIntent or
|
||||
LegacyChooseBackgroundIntent)
|
||||
{
|
||||
_intentBusy = true;
|
||||
PostState(_controller.Current);
|
||||
}
|
||||
|
||||
var state = await HandleIntentAsync(intent, _lifetimeCancellation.Token);
|
||||
ObserveOperatorMutationQuarantine(state);
|
||||
if (!_closing)
|
||||
{
|
||||
_intentBusy = false;
|
||||
@@ -272,6 +472,318 @@ public sealed partial class MainWindow : Window
|
||||
LegacyDropSelectedCutsIntent => _controller.DropSelectedCutsOnPlaylist(),
|
||||
LegacySetPlaylistEnabledIntent enabled =>
|
||||
_controller.SetPlaylistRowEnabled(enabled.RowId, enabled.Enabled),
|
||||
LegacySetAllPlaylistEnabledIntent enabled =>
|
||||
_controller.SetAllPlaylistRowsEnabled(enabled.Enabled),
|
||||
LegacySelectPlaylistRowIntent selection =>
|
||||
_controller.SelectPlaylistRow(
|
||||
selection.RowId,
|
||||
selection.Control,
|
||||
selection.Shift),
|
||||
LegacyMoveSelectedPlaylistRowsIntent move =>
|
||||
_controller.MoveSelectedPlaylistRows(move.Direction),
|
||||
LegacyDeleteSelectedPlaylistRowsIntent =>
|
||||
_controller.DeleteSelectedPlaylistRows(),
|
||||
LegacyDeleteAllPlaylistRowsIntent =>
|
||||
_controller.DeleteAllPlaylistRows(),
|
||||
LegacyToggleActivePlaylistEnabledIntent =>
|
||||
_controller.ToggleActivePlaylistRowEnabled(),
|
||||
LegacySelectPlaylistBoundaryIntent boundary =>
|
||||
_controller.SelectPlaylistBoundary(boundary.Last),
|
||||
LegacySelectTabIntent tab =>
|
||||
await _controller.SelectTabAsync(tab.TabId, cancellationToken),
|
||||
LegacySwapTabsIntent tabs =>
|
||||
await _controller.SwapTabsAsync(
|
||||
tabs.Source,
|
||||
tabs.Target,
|
||||
cancellationToken),
|
||||
LegacySetMovingAveragesIntent movingAverages =>
|
||||
_controller.SetMovingAverages(movingAverages.Ma5, movingAverages.Ma20),
|
||||
LegacyActivateFixedActionIntent action =>
|
||||
await _controller.ActivateFixedActionAsync(
|
||||
action.ActionId,
|
||||
cancellationToken),
|
||||
LegacyActivateFixedSectionIntent section =>
|
||||
await _controller.ActivateFixedSection(
|
||||
section.SectionIndex,
|
||||
cancellationToken),
|
||||
LegacySelectIndustryIntent industry =>
|
||||
_controller.SelectIndustry(industry.Index, industry.DoubleClick),
|
||||
LegacySwapIndustriesIntent =>
|
||||
_controller.SwapIndustries(),
|
||||
LegacyActivateIndustryActionIntent action =>
|
||||
_controller.ActivateIndustryAction(action.ActionId),
|
||||
LegacyActivateIndustrySectionIntent section =>
|
||||
_controller.ActivateIndustrySection(section.SectionIndex),
|
||||
LegacySelectOverseasFixedIndexIntent selection =>
|
||||
_controller.SelectOverseasFixedIndex(selection.TargetId),
|
||||
LegacySearchOverseasIndustriesIntent search =>
|
||||
await _controller.SearchOverseasIndustriesAsync(
|
||||
search.Query,
|
||||
cancellationToken),
|
||||
LegacySearchOverseasStocksIntent search =>
|
||||
await _controller.SearchOverseasStocksAsync(
|
||||
search.Query,
|
||||
cancellationToken),
|
||||
LegacySelectOverseasIndustryIntent selection =>
|
||||
_controller.SelectOverseasIndustry(selection.SelectionId),
|
||||
LegacySelectOverseasStockIntent selection =>
|
||||
_controller.SelectOverseasStock(selection.SelectionId),
|
||||
LegacyActivateOverseasActionIntent action =>
|
||||
_controller.ActivateOverseasAction(action.ActionId),
|
||||
LegacySearchComparisonDomesticIntent search =>
|
||||
await _controller.SearchComparisonDomesticAsync(
|
||||
search.Query,
|
||||
cancellationToken),
|
||||
LegacySearchComparisonWorldIntent search =>
|
||||
await _controller.SearchComparisonWorldAsync(
|
||||
search.Query,
|
||||
cancellationToken),
|
||||
LegacySelectComparisonDomesticIntent selection =>
|
||||
_controller.SelectComparisonDomesticResult(selection.SelectionId),
|
||||
LegacySelectComparisonWorldIntent selection =>
|
||||
_controller.SelectComparisonWorldResult(selection.SelectionId),
|
||||
LegacySelectComparisonFixedIntent selection =>
|
||||
_controller.SelectComparisonFixedTarget(selection.TargetId),
|
||||
LegacyChooseComparisonDomesticIntent selection =>
|
||||
_controller.ChooseComparisonDomesticResult(selection.SelectionId),
|
||||
LegacyChooseComparisonWorldIntent selection =>
|
||||
_controller.ChooseComparisonWorldResult(selection.SelectionId),
|
||||
LegacyChooseComparisonFixedIntent selection =>
|
||||
_controller.ChooseComparisonFixedTarget(selection.TargetId),
|
||||
LegacySwapComparisonTargetsIntent =>
|
||||
_controller.SwapComparisonTargets(),
|
||||
LegacyClearComparisonTargetsIntent =>
|
||||
_controller.ClearComparisonTargets(),
|
||||
LegacyAddComparisonPairIntent =>
|
||||
await _controller.AddComparisonPairAsync(cancellationToken),
|
||||
LegacySelectComparisonPairIntent selection =>
|
||||
_controller.SelectComparisonPair(selection.RowId),
|
||||
LegacyMoveComparisonPairIntent move =>
|
||||
await _controller.MoveComparisonPairAsync(
|
||||
move.Direction,
|
||||
cancellationToken),
|
||||
LegacyDeleteSelectedComparisonPairIntent =>
|
||||
await _controller.DeleteComparisonPairAsync(
|
||||
all: false,
|
||||
cancellationToken),
|
||||
LegacyDeleteAllComparisonPairsIntent =>
|
||||
await _controller.DeleteComparisonPairAsync(
|
||||
all: true,
|
||||
cancellationToken),
|
||||
LegacyActivateComparisonActionIntent action =>
|
||||
_controller.ActivateComparisonAction(action.ActionId),
|
||||
LegacyActivateComparisonSectionIntent section =>
|
||||
_controller.ActivateComparisonSection(section.SectionIndex),
|
||||
LegacySearchThemesIntent search =>
|
||||
await _controller.SearchThemesAsync(
|
||||
search.Query,
|
||||
search.NxtSession,
|
||||
cancellationToken),
|
||||
LegacySelectThemeIntent selection =>
|
||||
await _controller.SelectThemeAsync(
|
||||
selection.ResultId,
|
||||
cancellationToken),
|
||||
LegacyActivateThemeResultIntent activation =>
|
||||
await _controller.ActivateThemeResultAsync(
|
||||
activation.ResultId,
|
||||
cancellationToken),
|
||||
LegacySetThemeSortIntent sort =>
|
||||
_controller.SetThemeSort(sort.SortId),
|
||||
LegacyActivateThemeActionIntent action =>
|
||||
_controller.ActivateThemeAction(action.ActionId),
|
||||
LegacySearchExpertsIntent search =>
|
||||
await _controller.SearchExpertsAsync(search.Query, cancellationToken),
|
||||
LegacySelectExpertIntent selection =>
|
||||
await _controller.SelectExpertAsync(
|
||||
selection.SelectionId,
|
||||
cancellationToken),
|
||||
LegacyActivateExpertActionIntent action =>
|
||||
_controller.ActivateExpertAction(action.ActionId),
|
||||
LegacySearchTradingHaltsIntent search =>
|
||||
await _controller.SearchTradingHaltsAsync(
|
||||
search.Query,
|
||||
cancellationToken),
|
||||
LegacySelectTradingHaltIntent selection =>
|
||||
_controller.SelectTradingHalt(selection.SelectionId),
|
||||
LegacyToggleTradingHaltSortIntent =>
|
||||
_controller.ToggleTradingHaltSort(),
|
||||
LegacyActivateTradingHaltActionIntent action =>
|
||||
_controller.ActivateTradingHaltAction(action.ActionId),
|
||||
LegacyOpenOperatorCatalogIntent catalog =>
|
||||
await _controller.OpenOperatorCatalogAsync(
|
||||
catalog.Entity,
|
||||
cancellationToken),
|
||||
LegacyBeginUc4ThemeCatalogIntent =>
|
||||
await _controller.BeginThemeCatalogFromUc4Async(cancellationToken),
|
||||
LegacyEditUc4SelectedThemeIntent =>
|
||||
await _controller.EditSelectedThemeCatalogAsync(cancellationToken),
|
||||
LegacyDeleteUc4SelectedThemeIntent =>
|
||||
await _controller.DeleteSelectedThemeCatalogAsync(cancellationToken),
|
||||
LegacyBeginUc6ExpertCatalogIntent =>
|
||||
await _controller.BeginExpertCatalogFromUc6Async(cancellationToken),
|
||||
LegacyEditUc6SelectedExpertIntent =>
|
||||
await _controller.EditSelectedExpertCatalogAsync(cancellationToken),
|
||||
LegacyDeleteUc6SelectedExpertIntent =>
|
||||
await _controller.DeleteSelectedExpertCatalogAsync(cancellationToken),
|
||||
LegacyCloseOperatorCatalogIntent =>
|
||||
_controller.CloseOperatorCatalog(),
|
||||
LegacySearchOperatorCatalogIntent search =>
|
||||
await _controller.SearchOperatorCatalogAsync(
|
||||
search.Query,
|
||||
search.NxtSession,
|
||||
cancellationToken),
|
||||
LegacySelectOperatorCatalogResultIntent selection =>
|
||||
await _controller.SelectOperatorCatalogResultAsync(
|
||||
selection.ResultId,
|
||||
cancellationToken),
|
||||
LegacyBeginCreateThemeCatalogIntent create =>
|
||||
await _controller.BeginCreateThemeCatalogAsync(
|
||||
create.Market,
|
||||
cancellationToken),
|
||||
LegacyBeginCreateExpertCatalogIntent =>
|
||||
await _controller.BeginCreateExpertCatalogAsync(cancellationToken),
|
||||
LegacySearchOperatorCatalogStocksIntent search =>
|
||||
await _controller.SearchOperatorCatalogStocksAsync(
|
||||
search.Query,
|
||||
cancellationToken),
|
||||
LegacySelectOperatorCatalogStockIntent selection =>
|
||||
_controller.SelectOperatorCatalogStock(selection.ResultId),
|
||||
LegacyAddOperatorCatalogStockIntent add =>
|
||||
_controller.AddOperatorCatalogStock(add.BuyAmount),
|
||||
LegacyActivateOperatorCatalogStockIntent activation =>
|
||||
_controller.ActivateOperatorCatalogStock(
|
||||
activation.ResultId,
|
||||
activation.BuyAmount),
|
||||
LegacyMoveOperatorCatalogDraftRowIntent move =>
|
||||
_controller.MoveOperatorCatalogDraftRow(move.RowId, move.Direction),
|
||||
LegacyRemoveOperatorCatalogDraftRowIntent remove =>
|
||||
_controller.RemoveOperatorCatalogDraftRow(remove.RowId),
|
||||
LegacySetOperatorCatalogDraftBuyAmountIntent amount =>
|
||||
_controller.SetOperatorCatalogDraftBuyAmount(
|
||||
amount.RowId,
|
||||
amount.BuyAmount),
|
||||
LegacySaveOperatorCatalogIntent save =>
|
||||
await _controller.SaveOperatorCatalogAsync(
|
||||
save.Name,
|
||||
cancellationToken),
|
||||
LegacyDeleteOperatorCatalogIntent =>
|
||||
await _controller.DeleteOperatorCatalogAsync(cancellationToken),
|
||||
LegacyRefreshNamedPlaylistsIntent =>
|
||||
await _controller.RefreshNamedPlaylistsAsync(cancellationToken),
|
||||
LegacySelectNamedPlaylistIntent selection =>
|
||||
_controller.SelectNamedPlaylist(selection.DefinitionId),
|
||||
LegacyLoadSelectedNamedPlaylistIntent =>
|
||||
await _controller.LoadSelectedNamedPlaylistAsync(cancellationToken),
|
||||
LegacyLoadNamedPlaylistByIdIntent load =>
|
||||
await _controller.LoadNamedPlaylistByIdAsync(
|
||||
load.DefinitionId,
|
||||
cancellationToken),
|
||||
LegacyCreateNamedPlaylistIntent create =>
|
||||
await _controller.CreateNamedPlaylistAsync(
|
||||
create.Title,
|
||||
cancellationToken),
|
||||
LegacySaveCurrentNamedPlaylistIntent =>
|
||||
await _controller.SaveCurrentNamedPlaylistAsync(cancellationToken),
|
||||
LegacySaveCurrentNamedPlaylistToIntent save =>
|
||||
await _controller.SaveCurrentNamedPlaylistToAsync(
|
||||
save.DefinitionId,
|
||||
cancellationToken),
|
||||
LegacyDeleteSelectedNamedPlaylistIntent =>
|
||||
await _controller.DeleteSelectedNamedPlaylistAsync(cancellationToken),
|
||||
LegacyOpenManualFinancialIntent manual =>
|
||||
await _controller.OpenManualFinancialAsync(
|
||||
manual.Screen,
|
||||
cancellationToken),
|
||||
LegacyCloseManualFinancialIntent =>
|
||||
_controller.CloseManualFinancial(),
|
||||
LegacySearchManualFinancialIntent search =>
|
||||
await _controller.SearchManualFinancialAsync(
|
||||
search.Query,
|
||||
cancellationToken),
|
||||
LegacyFindManualFinancialIntent find =>
|
||||
await _controller.FindManualFinancialAsync(
|
||||
find.Query,
|
||||
find.Direction,
|
||||
find.Generation,
|
||||
cancellationToken),
|
||||
LegacyToggleManualFinancialNameSortIntent sort =>
|
||||
_controller.ToggleManualFinancialNameSort(sort.Generation),
|
||||
LegacyLoadManualFinancialIntent load =>
|
||||
await _controller.LoadManualFinancialAsync(
|
||||
load.ResultId,
|
||||
cancellationToken),
|
||||
LegacyActivateManualFinancialResultIntent activation =>
|
||||
await _controller.ActivateManualFinancialResultAsync(
|
||||
activation.ResultId,
|
||||
cancellationToken),
|
||||
LegacyBeginManualFinancialCreateIntent =>
|
||||
_controller.BeginManualFinancialCreate(),
|
||||
LegacySearchManualFinancialStocksIntent search =>
|
||||
await _controller.SearchManualFinancialStocksAsync(
|
||||
search.StockName,
|
||||
cancellationToken),
|
||||
LegacySelectManualFinancialStockIntent selection =>
|
||||
_controller.SelectManualFinancialStock(selection.ResultId),
|
||||
LegacySaveManualFinancialIntent save =>
|
||||
await _controller.SaveManualFinancialAsync(
|
||||
save.Record,
|
||||
cancellationToken),
|
||||
LegacyDeleteManualFinancialIntent =>
|
||||
await _controller.DeleteManualFinancialAsync(
|
||||
all: false,
|
||||
cancellationToken),
|
||||
LegacyDeleteAllManualFinancialIntent =>
|
||||
await _controller.DeleteManualFinancialAsync(
|
||||
all: true,
|
||||
cancellationToken),
|
||||
LegacyActivateManualFinancialActionIntent action =>
|
||||
_controller.ActivateManualFinancialAction(action.ActionId),
|
||||
LegacyOpenManualListIntent manual =>
|
||||
manual.Screen == LegacyManualListScreen.NetSell
|
||||
? await _controller.OpenManualNetSellAsync(
|
||||
manual.Audience,
|
||||
cancellationToken)
|
||||
: await _controller.OpenManualViAsync(cancellationToken),
|
||||
LegacyCloseManualListIntent =>
|
||||
_controller.CloseManualLists(),
|
||||
LegacyRefreshManualListIntent =>
|
||||
await _controller.RefreshManualListsAsync(cancellationToken),
|
||||
LegacySetManualNetSellCellIntent cell =>
|
||||
_controller.SetManualNetSellCell(cell.RowId, cell.Field, cell.Value),
|
||||
LegacySaveManualNetSellIntent =>
|
||||
await _controller.SaveManualNetSellAsync(cancellationToken),
|
||||
LegacyAddManualNetSellCutIntent =>
|
||||
_controller.AddManualNetSellPlaylistRow(),
|
||||
LegacySearchManualViIntent search =>
|
||||
await _controller.SearchManualViAsync(search.Query, cancellationToken),
|
||||
LegacySelectManualViResultIntent result =>
|
||||
_controller.SelectManualViSearchResult(result.ResultId),
|
||||
LegacyAddManualViResultIntent result =>
|
||||
_controller.AddManualViSearchResult(result.ResultId),
|
||||
LegacyMoveManualViItemIntent move =>
|
||||
_controller.MoveManualViItem(move.ItemId, move.Direction),
|
||||
LegacyDeleteManualViItemIntent item =>
|
||||
_controller.DeleteManualViItem(item.ItemId),
|
||||
LegacyDeleteAllManualViItemsIntent =>
|
||||
_controller.DeleteAllManualViItems(),
|
||||
LegacySaveManualViIntent =>
|
||||
await _controller.SaveManualViAsync(cancellationToken),
|
||||
LegacyAddManualViCutIntent =>
|
||||
_controller.AddManualViPlaylistRow(),
|
||||
LegacyConfirmManualListIntent =>
|
||||
await _controller.ConfirmManualListsAsync(cancellationToken),
|
||||
LegacyImportManualListsIntent =>
|
||||
await _controller.ImportLegacyManualListsAsync(cancellationToken),
|
||||
LegacyExecutePlayoutIntent playout =>
|
||||
await ExecuteOperatorPlayoutAsync(
|
||||
playout.Command,
|
||||
cancellationToken),
|
||||
LegacySetFadeDurationIntent fade =>
|
||||
await SetFadeDurationAsync(fade.Duration, cancellationToken),
|
||||
LegacyToggleBackgroundIntent =>
|
||||
await ToggleBackgroundAsync(cancellationToken),
|
||||
LegacyChooseBackgroundIntent =>
|
||||
await ChooseBackgroundAsync(cancellationToken),
|
||||
LegacyDismissDialogIntent => _controller.DismissDialog(),
|
||||
_ => _controller.ReportError("지원하지 않는 화면 요청입니다.")
|
||||
};
|
||||
@@ -282,12 +794,17 @@ public sealed partial class MainWindow : Window
|
||||
if (!_closing && _webViewReady && Browser.CoreWebView2 is not null)
|
||||
{
|
||||
Browser.CoreWebView2.PostWebMessageAsJson(
|
||||
LegacyBridgeProtocol.SerializeState(snapshot, _intentBusy));
|
||||
LegacyBridgeProtocol.SerializeState(
|
||||
snapshot,
|
||||
_intentBusy,
|
||||
CreatePlayoutSnapshot()));
|
||||
}
|
||||
}
|
||||
|
||||
private void OnProcessFailed(object? sender, CoreWebView2ProcessFailedEventArgs args)
|
||||
{
|
||||
ObserveOperatorMutationQuarantine(
|
||||
_controller.InvalidateOperatorCatalogBrowserCorrelation());
|
||||
if (!_closing)
|
||||
{
|
||||
ShowError("WebView2 프로세스가 중단되었습니다.", args.ProcessFailedKind.ToString());
|
||||
@@ -314,9 +831,14 @@ public sealed partial class MainWindow : Window
|
||||
}
|
||||
|
||||
_closing = true;
|
||||
ObserveOperatorMutationQuarantine(
|
||||
_controller.InvalidateOperatorCatalogBrowserCorrelation());
|
||||
Root.Loaded -= OnRootLoaded;
|
||||
Closed -= OnClosed;
|
||||
DetachCloseConfirmation();
|
||||
_lifetimeCancellation.Cancel();
|
||||
ShutdownPlayoutRuntime();
|
||||
ShutdownManualListsRuntime();
|
||||
DataQueryExecutor.Reset();
|
||||
|
||||
if (Browser.CoreWebView2 is not null)
|
||||
@@ -335,6 +857,166 @@ public sealed partial class MainWindow : Window
|
||||
// cancellation and release the gate without racing disposed objects.
|
||||
}
|
||||
|
||||
private sealed class UnavailableThemeCatalogPersistenceService
|
||||
: IThemeCatalogPersistenceService
|
||||
{
|
||||
private readonly string _message;
|
||||
|
||||
public UnavailableThemeCatalogPersistenceService(string message)
|
||||
{
|
||||
_message = message;
|
||||
}
|
||||
|
||||
public bool CanMutate => false;
|
||||
|
||||
public Task<string> SuggestNextCodeAsync(
|
||||
ThemeMarket market,
|
||||
CancellationToken cancellationToken = default) =>
|
||||
Task.FromException<string>(new InvalidOperationException(_message));
|
||||
|
||||
public Task<OperatorCatalogMutationReceipt> CreateAsync(
|
||||
ThemeCatalogDefinition definition,
|
||||
CancellationToken cancellationToken = default) =>
|
||||
Task.FromException<OperatorCatalogMutationReceipt>(
|
||||
new InvalidOperationException(_message));
|
||||
|
||||
public Task<OperatorCatalogMutationReceipt> ReplaceAsync(
|
||||
ThemeSelectionIdentity expectedIdentity,
|
||||
string newTitle,
|
||||
IReadOnlyList<ThemeCatalogItem> items,
|
||||
CancellationToken cancellationToken = default) =>
|
||||
Task.FromException<OperatorCatalogMutationReceipt>(
|
||||
new InvalidOperationException(_message));
|
||||
|
||||
public Task<OperatorCatalogMutationReceipt> DeleteAsync(
|
||||
ThemeSelectionIdentity expectedIdentity,
|
||||
CancellationToken cancellationToken = default) =>
|
||||
Task.FromException<OperatorCatalogMutationReceipt>(
|
||||
new InvalidOperationException(_message));
|
||||
}
|
||||
|
||||
private sealed class UnavailableExpertCatalogPersistenceService
|
||||
: IExpertCatalogPersistenceService
|
||||
{
|
||||
private readonly string _message;
|
||||
|
||||
public UnavailableExpertCatalogPersistenceService(string message)
|
||||
{
|
||||
_message = message;
|
||||
}
|
||||
|
||||
public bool CanMutate => false;
|
||||
|
||||
public Task<string> SuggestNextCodeAsync(
|
||||
CancellationToken cancellationToken = default) =>
|
||||
Task.FromException<string>(new InvalidOperationException(_message));
|
||||
|
||||
public Task<OperatorCatalogMutationReceipt> CreateAsync(
|
||||
ExpertCatalogDefinition definition,
|
||||
CancellationToken cancellationToken = default) =>
|
||||
Task.FromException<OperatorCatalogMutationReceipt>(
|
||||
new InvalidOperationException(_message));
|
||||
|
||||
public Task<OperatorCatalogMutationReceipt> ReplaceAsync(
|
||||
ExpertSelectionIdentity expectedIdentity,
|
||||
string newName,
|
||||
IReadOnlyList<ExpertCatalogRecommendation> recommendations,
|
||||
CancellationToken cancellationToken = default) =>
|
||||
Task.FromException<OperatorCatalogMutationReceipt>(
|
||||
new InvalidOperationException(_message));
|
||||
|
||||
public Task<OperatorCatalogMutationReceipt> DeleteAsync(
|
||||
ExpertSelectionIdentity expectedIdentity,
|
||||
CancellationToken cancellationToken = default) =>
|
||||
Task.FromException<OperatorCatalogMutationReceipt>(
|
||||
new InvalidOperationException(_message));
|
||||
}
|
||||
|
||||
private sealed class UnavailableStockMasterIdentityValidationService
|
||||
: IStockMasterIdentityValidationService
|
||||
{
|
||||
private readonly string _message;
|
||||
|
||||
public UnavailableStockMasterIdentityValidationService(string message)
|
||||
{
|
||||
_message = message;
|
||||
}
|
||||
|
||||
public Task<IReadOnlyList<StockMasterIdentity>> ValidateThemeItemsAsync(
|
||||
IReadOnlyList<ThemeCatalogItem> items,
|
||||
CancellationToken cancellationToken = default) =>
|
||||
Task.FromException<IReadOnlyList<StockMasterIdentity>>(
|
||||
new InvalidOperationException(_message));
|
||||
|
||||
public Task<IReadOnlyList<StockMasterIdentity>> ValidateExpertRecommendationsAsync(
|
||||
IReadOnlyList<ExpertCatalogRecommendation> recommendations,
|
||||
CancellationToken cancellationToken = default) =>
|
||||
Task.FromException<IReadOnlyList<StockMasterIdentity>>(
|
||||
new InvalidOperationException(_message));
|
||||
}
|
||||
|
||||
private sealed class UnavailableOperatorCatalogSchemaValidationService
|
||||
: IOperatorCatalogSchemaValidationService
|
||||
{
|
||||
private readonly string _message;
|
||||
|
||||
public UnavailableOperatorCatalogSchemaValidationService(string message)
|
||||
{
|
||||
_message = message;
|
||||
}
|
||||
|
||||
public Task<OperatorCatalogSchemaValidationResult> ValidateAsync(
|
||||
CancellationToken cancellationToken = default) =>
|
||||
Task.FromException<OperatorCatalogSchemaValidationResult>(
|
||||
new InvalidOperationException(_message));
|
||||
}
|
||||
|
||||
private sealed class UnavailableNamedPlaylistPersistenceService
|
||||
: INamedPlaylistPersistenceService
|
||||
{
|
||||
private readonly string _message;
|
||||
|
||||
public UnavailableNamedPlaylistPersistenceService(string message)
|
||||
{
|
||||
_message = message;
|
||||
}
|
||||
|
||||
public bool CanMutate => false;
|
||||
|
||||
public Task<NamedPlaylistListResult> ListAsync(
|
||||
int maximumResults = LegacyNamedPlaylistPersistenceService.DefaultMaximumDefinitions,
|
||||
CancellationToken cancellationToken = default) =>
|
||||
Task.FromException<NamedPlaylistListResult>(
|
||||
new InvalidOperationException(_message));
|
||||
|
||||
public Task<string> SuggestNextProgramCodeAsync(
|
||||
CancellationToken cancellationToken = default) =>
|
||||
Task.FromException<string>(new InvalidOperationException(_message));
|
||||
|
||||
public Task<NamedPlaylistDocument> LoadAsync(
|
||||
string programCode,
|
||||
CancellationToken cancellationToken = default) =>
|
||||
Task.FromException<NamedPlaylistDocument>(
|
||||
new InvalidOperationException(_message));
|
||||
|
||||
public Task CreateDefinitionAsync(
|
||||
string programCode,
|
||||
string title,
|
||||
CancellationToken cancellationToken = default) =>
|
||||
Task.FromException(new InvalidOperationException(_message));
|
||||
|
||||
public Task ReplaceItemsAsync(
|
||||
string programCode,
|
||||
IReadOnlyList<NamedPlaylistStoredItem> items,
|
||||
CancellationToken cancellationToken = default) =>
|
||||
Task.FromException(new InvalidOperationException(_message));
|
||||
|
||||
public Task DeleteAsync(
|
||||
string programCode,
|
||||
CancellationToken cancellationToken = default) =>
|
||||
Task.FromException(new InvalidOperationException(_message));
|
||||
}
|
||||
|
||||
private sealed class UnavailableStockLookup : ILegacyStockLookup
|
||||
{
|
||||
private readonly string _message;
|
||||
@@ -350,4 +1032,185 @@ public sealed partial class MainWindow : Window
|
||||
Task.FromException<LegacyStockSearchData>(
|
||||
new InvalidOperationException(_message));
|
||||
}
|
||||
|
||||
private sealed class UnavailableIndustrySelectionService : IIndustrySelectionService
|
||||
{
|
||||
private readonly string _message;
|
||||
|
||||
public UnavailableIndustrySelectionService(string message)
|
||||
{
|
||||
_message = message;
|
||||
}
|
||||
|
||||
public Task<IReadOnlyList<IndustrySelection>> GetAsync(
|
||||
IndustryMarket market,
|
||||
CancellationToken cancellationToken = default) =>
|
||||
Task.FromException<IReadOnlyList<IndustrySelection>>(
|
||||
new InvalidOperationException(_message));
|
||||
}
|
||||
|
||||
private sealed class UnavailableThemeSelectionService : IThemeSelectionService
|
||||
{
|
||||
private readonly string _message;
|
||||
|
||||
public UnavailableThemeSelectionService(string message)
|
||||
{
|
||||
_message = message;
|
||||
}
|
||||
|
||||
public Task<ThemeSearchResult> SearchAsync(
|
||||
string query,
|
||||
ThemeSession nxtSession,
|
||||
int maximumResults = LegacyThemeSelectionService.DefaultMaximumResults,
|
||||
CancellationToken cancellationToken = default) =>
|
||||
Task.FromException<ThemeSearchResult>(new InvalidOperationException(_message));
|
||||
|
||||
public Task<ThemePreviewResult> PreviewAsync(
|
||||
ThemeSelectionIdentity identity,
|
||||
int maximumItems = LegacyThemeSelectionService.DefaultMaximumPreviewItems,
|
||||
CancellationToken cancellationToken = default) =>
|
||||
Task.FromException<ThemePreviewResult>(new InvalidOperationException(_message));
|
||||
}
|
||||
|
||||
private sealed class UnavailableExpertSelectionService : IExpertSelectionService
|
||||
{
|
||||
private readonly string _message;
|
||||
|
||||
public UnavailableExpertSelectionService(string message)
|
||||
{
|
||||
_message = message;
|
||||
}
|
||||
|
||||
public Task<ExpertSearchResult> SearchAsync(
|
||||
string query = "",
|
||||
int maximumResults = LegacyExpertSelectionService.DefaultMaximumResults,
|
||||
CancellationToken cancellationToken = default) =>
|
||||
Task.FromException<ExpertSearchResult>(new InvalidOperationException(_message));
|
||||
|
||||
public Task<ExpertPreviewResult> PreviewAsync(
|
||||
ExpertSelectionIdentity identity,
|
||||
int maximumItems = LegacyExpertSelectionService.DefaultMaximumPreviewItems,
|
||||
CancellationToken cancellationToken = default) =>
|
||||
Task.FromException<ExpertPreviewResult>(new InvalidOperationException(_message));
|
||||
}
|
||||
|
||||
private sealed class UnavailableTradingHaltSelectionService : ITradingHaltSelectionService
|
||||
{
|
||||
private readonly string _message;
|
||||
|
||||
public UnavailableTradingHaltSelectionService(string message)
|
||||
{
|
||||
_message = message;
|
||||
}
|
||||
|
||||
public Task<TradingHaltSelectionResult> SearchAsync(
|
||||
string query = "",
|
||||
int maximumResults = LegacyTradingHaltSelectionService.DefaultMaximumResults,
|
||||
CancellationToken cancellationToken = default) =>
|
||||
Task.FromException<TradingHaltSelectionResult>(
|
||||
new InvalidOperationException(_message));
|
||||
}
|
||||
|
||||
private sealed class UnavailableManualFinancialScreenService
|
||||
: IManualFinancialScreenService
|
||||
{
|
||||
private readonly string _message;
|
||||
|
||||
public UnavailableManualFinancialScreenService(string message)
|
||||
{
|
||||
_message = message;
|
||||
}
|
||||
|
||||
public bool CanMutate => false;
|
||||
|
||||
public Task<ManualFinancialSearchResult> SearchAsync(
|
||||
ManualFinancialScreenKind screen,
|
||||
string query = "",
|
||||
int maximumResults = LegacyManualFinancialScreenService.DefaultMaximumResults,
|
||||
CancellationToken cancellationToken = default) =>
|
||||
Task.FromException<ManualFinancialSearchResult>(
|
||||
new InvalidOperationException(_message));
|
||||
|
||||
public Task<ManualFinancialSnapshot> GetAsync(
|
||||
ManualFinancialIdentity identity,
|
||||
CancellationToken cancellationToken = default) =>
|
||||
Task.FromException<ManualFinancialSnapshot>(
|
||||
new InvalidOperationException(_message));
|
||||
|
||||
public Task<ManualFinancialMutationReceipt> CreateAsync(
|
||||
ManualFinancialRecord record,
|
||||
CancellationToken cancellationToken = default) =>
|
||||
Task.FromException<ManualFinancialMutationReceipt>(
|
||||
new InvalidOperationException(_message));
|
||||
|
||||
public Task<ManualFinancialMutationReceipt> UpdateAsync(
|
||||
ManualFinancialSnapshot expected,
|
||||
ManualFinancialRecord replacement,
|
||||
CancellationToken cancellationToken = default) =>
|
||||
Task.FromException<ManualFinancialMutationReceipt>(
|
||||
new InvalidOperationException(_message));
|
||||
|
||||
public Task<ManualFinancialMutationReceipt> DeleteAsync(
|
||||
ManualFinancialSnapshot expected,
|
||||
CancellationToken cancellationToken = default) =>
|
||||
Task.FromException<ManualFinancialMutationReceipt>(
|
||||
new InvalidOperationException(_message));
|
||||
|
||||
public Task<ManualFinancialMutationReceipt> DeleteAllAsync(
|
||||
ManualFinancialScreenKind screen,
|
||||
CancellationToken cancellationToken = default) =>
|
||||
Task.FromException<ManualFinancialMutationReceipt>(
|
||||
new InvalidOperationException(_message));
|
||||
}
|
||||
|
||||
private sealed class UnavailableStockSearchService : IStockSearchService
|
||||
{
|
||||
private readonly string _message;
|
||||
|
||||
public UnavailableStockSearchService(string message)
|
||||
{
|
||||
_message = message;
|
||||
}
|
||||
|
||||
public Task<StockSearchResult> SearchAsync(
|
||||
string query,
|
||||
int maximumResults = LegacyStockSearchService.DefaultMaximumResults,
|
||||
CancellationToken cancellationToken = default) =>
|
||||
Task.FromException<StockSearchResult>(new InvalidOperationException(_message));
|
||||
}
|
||||
|
||||
private sealed class UnavailableWorldStockSearchService : IWorldStockSearchService
|
||||
{
|
||||
private readonly string _message;
|
||||
|
||||
public UnavailableWorldStockSearchService(string message)
|
||||
{
|
||||
_message = message;
|
||||
}
|
||||
|
||||
public Task<WorldStockSearchResult> SearchAsync(
|
||||
string query,
|
||||
int maximumResults = LegacyWorldStockSearchService.DefaultMaximumResults,
|
||||
CancellationToken cancellationToken = default) =>
|
||||
Task.FromException<WorldStockSearchResult>(
|
||||
new InvalidOperationException(_message));
|
||||
}
|
||||
|
||||
private sealed class UnavailableOverseasIndustryIndexSearchService
|
||||
: IOverseasIndustryIndexSearchService
|
||||
{
|
||||
private readonly string _message;
|
||||
|
||||
public UnavailableOverseasIndustryIndexSearchService(string message)
|
||||
{
|
||||
_message = message;
|
||||
}
|
||||
|
||||
public Task<OverseasIndustryIndexSearchResult> SearchAsync(
|
||||
string query,
|
||||
int maximumResults = LegacyOverseasIndustryIndexSearchService.DefaultMaximumResults,
|
||||
CancellationToken cancellationToken = default) =>
|
||||
Task.FromException<OverseasIndustryIndexSearchResult>(
|
||||
new InvalidOperationException(_message));
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user