feat: initialize existing development playout PCs
This commit is contained in:
@@ -10,6 +10,10 @@ public partial class App : Application
|
||||
private Window? _window;
|
||||
private AppInstance? _mainInstance;
|
||||
|
||||
internal static bool IsDevelopmentLiveLaunch { get; private set; }
|
||||
|
||||
internal static bool IsDevelopmentLiveLaunchRequested { get; private set; }
|
||||
|
||||
public App()
|
||||
{
|
||||
InitializeComponent();
|
||||
@@ -55,9 +59,14 @@ public partial class App : Application
|
||||
: DevelopmentLiveLaunchBootstrap.ResolveLaunchArguments(
|
||||
args.Arguments,
|
||||
Environment.GetCommandLineArgs());
|
||||
IsDevelopmentLiveLaunchRequested = string.Equals(
|
||||
launchArguments,
|
||||
DevelopmentLiveLaunchBootstrap.ExactLaunchArgument,
|
||||
StringComparison.Ordinal);
|
||||
var developmentLive = DevelopmentLiveLaunchBootstrap.TryApply(
|
||||
launchArguments,
|
||||
isDebugBuild);
|
||||
IsDevelopmentLiveLaunch = developmentLive.IsApplied;
|
||||
System.Diagnostics.Debug.WriteLine(
|
||||
$"Development Live bootstrap: {developmentLive.Code}");
|
||||
|
||||
|
||||
@@ -178,9 +178,10 @@
|
||||
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
|
||||
</Content>
|
||||
<!--
|
||||
The active legacy DB INI contains credentials. It is available beside the
|
||||
executable for local F5/unpackaged development only and is never MSIX Content.
|
||||
Historical copies, backups, archives and afiedt.buf.txt are not included at all.
|
||||
The active legacy DB INI contains credentials and is never a build input or
|
||||
MSIX Content. Local F5 and packaged development use the current user's
|
||||
LocalAppData overlay. Historical copies, backups, archives and
|
||||
afiedt.buf.txt are not included at all.
|
||||
-->
|
||||
<Manifest Include="$(ApplicationManifest)" />
|
||||
</ItemGroup>
|
||||
@@ -192,10 +193,13 @@
|
||||
<Message Condition="'$(LegacyRuntimeAssetsMode)' == 'Auto' and
|
||||
'$(LegacyRuntimeAssetsEnabled)' != 'true'"
|
||||
Importance="high"
|
||||
Text="Legacy runtime assets were not found. Building the safe source-only DryRun app. Full runtime use requires a Required build with the approved external root." />
|
||||
Text="Legacy runtime assets were not found. Building the safe source-only DryRun app. Run scripts\Initialize-ExistingDevelopmentPc.ps1 before Development Live." />
|
||||
<Message Condition="'$(LegacyRuntimeAssetsEnabled)' == 'true'"
|
||||
Importance="high"
|
||||
Text="Verified full legacy runtime assets are enabled. Database credentials remain in the current user's LocalAppData overlay." />
|
||||
<Error Condition="'$(LegacyRuntimeAssetsValidationEnabled)' == 'true' and
|
||||
!Exists('$(LegacyRuntimeSourceRoot)')"
|
||||
Text="Legacy runtime source root was not found: $(LegacyRuntimeSourceRoot). Set /p:LegacyRuntimeSourceRoot to the read-only MBN_STOCK_N bin\Debug directory, or use /p:LegacyRuntimeAssetsMode=Auto for a source-only DryRun build." />
|
||||
Text="Legacy runtime source root was not found: $(LegacyRuntimeSourceRoot). Run scripts\Initialize-ExistingDevelopmentPc.ps1 to create the verified local Required binding, or use /p:LegacyRuntimeAssetsMode=Auto for a source-only DryRun build." />
|
||||
<Error Condition="'$(LegacyRuntimeAssetsValidationEnabled)' == 'true' and
|
||||
!Exists('$(LegacyCutsSourceRoot)')"
|
||||
Text="Legacy Cuts source directory was not found: $(LegacyCutsSourceRoot)." />
|
||||
|
||||
@@ -34,10 +34,17 @@ public sealed partial class MainWindow
|
||||
{
|
||||
var explicitLocalConfigurationExists = File.Exists(
|
||||
PlayoutOptionsLoader.DefaultPath);
|
||||
_playoutOptions = PlayoutOptionsLoader.Load(
|
||||
operatorSceneDirectory: _appliedOperatorSettings.SceneDirectory,
|
||||
operatorBackgroundDirectory: _appliedOperatorSettings.BackgroundDirectory,
|
||||
forceSafeDryRun: IsSourceOnlyBuild);
|
||||
_playoutOptions =
|
||||
_isDevelopmentLiveLaunch &&
|
||||
!_developmentLiveStartupBlocked
|
||||
? PlayoutOptionsLoader.LoadDevelopmentLive(
|
||||
baseDirectory: AppContext.BaseDirectory)
|
||||
: PlayoutOptionsLoader.Load(
|
||||
operatorSceneDirectory: _appliedOperatorSettings.SceneDirectory,
|
||||
operatorBackgroundDirectory: _appliedOperatorSettings.BackgroundDirectory,
|
||||
forceSafeDryRun: IsSourceOnlyBuild ||
|
||||
_isDevelopmentLiveLaunchRequested ||
|
||||
_developmentLiveStartupBlocked);
|
||||
ResetRefreshState();
|
||||
var startupComposition = LegacyParityStartupCompositionResolver.Resolve(
|
||||
_playoutOptions,
|
||||
|
||||
@@ -35,6 +35,8 @@ public sealed partial class MainWindow : Window
|
||||
}
|
||||
|
||||
private readonly CancellationTokenSource _lifetimeCancellation = new();
|
||||
private readonly bool _isDevelopmentLiveLaunch;
|
||||
private readonly bool _isDevelopmentLiveLaunchRequested;
|
||||
private readonly SemaphoreSlim _intentGate = new(1, 1);
|
||||
private readonly SemaphoreSlim _orderedLocalSelectionIntentGate = new(1, 1);
|
||||
private readonly SemaphoreSlim _orderedPlayoutIntentGate = new(1, 1);
|
||||
@@ -49,6 +51,7 @@ public sealed partial class MainWindow : Window
|
||||
private LegacyOperatorSettings _operatorSettings;
|
||||
private DatabaseRuntime? _databaseRuntime;
|
||||
private bool _closing;
|
||||
private bool _developmentLiveStartupBlocked;
|
||||
private bool _interactionMetricsRefreshQueued;
|
||||
private bool _intentBusy;
|
||||
private bool _windowSubclassAttached;
|
||||
@@ -59,6 +62,8 @@ public sealed partial class MainWindow : Window
|
||||
|
||||
public MainWindow()
|
||||
{
|
||||
_isDevelopmentLiveLaunch = App.IsDevelopmentLiveLaunch;
|
||||
_isDevelopmentLiveLaunchRequested = App.IsDevelopmentLiveLaunchRequested;
|
||||
// Capture and remove Gate A bearer material before XAML can create WebView2.
|
||||
// Only the native process keeps the capability digest for this launch.
|
||||
_playoutLaunchAuthorization =
|
||||
@@ -73,15 +78,22 @@ public sealed partial class MainWindow : Window
|
||||
EnsureCloseConfirmationAttached();
|
||||
var localApplicationData = Environment.GetFolderPath(
|
||||
Environment.SpecialFolder.LocalApplicationData);
|
||||
var runtimeCutMenuOverridePath = string.IsNullOrWhiteSpace(localApplicationData)
|
||||
var runtimeCutMenuOverridePath =
|
||||
_isDevelopmentLiveLaunch ||
|
||||
string.IsNullOrWhiteSpace(localApplicationData)
|
||||
? null
|
||||
: Path.Combine(
|
||||
localApplicationData,
|
||||
"MBN_STOCK_WEBVIEW",
|
||||
"Res",
|
||||
"종목.ini");
|
||||
var selectedResourceDirectory = _appliedOperatorSettings.ResourceDirectory;
|
||||
var cutMenuComposition = selectedResourceDirectory is null
|
||||
var selectedResourceDirectory = _isDevelopmentLiveLaunch
|
||||
? null
|
||||
: _appliedOperatorSettings.ResourceDirectory;
|
||||
var cutMenuComposition = _isDevelopmentLiveLaunch
|
||||
? LegacyRuntimeStockCutMenuLoader.ResolveFromBaseDirectory(
|
||||
AppContext.BaseDirectory)
|
||||
: selectedResourceDirectory is null
|
||||
? LegacyRuntimeStockCutMenuLoader.ResolveFromCandidates(
|
||||
runtimeCutMenuOverridePath,
|
||||
AppContext.BaseDirectory)
|
||||
@@ -111,6 +123,7 @@ public sealed partial class MainWindow : Window
|
||||
IOperatorCatalogSchemaValidationService operatorCatalogSchemaValidationService;
|
||||
CorePagePlanProvider? fixedPagePlanProvider = null;
|
||||
string? initializationError = null;
|
||||
var databaseInitializationSucceeded = false;
|
||||
try
|
||||
{
|
||||
if (IsSourceOnlyBuild)
|
||||
@@ -127,6 +140,8 @@ public sealed partial class MainWindow : Window
|
||||
: Path.Combine(selectedResourceDirectory, "MmoneyCoder.ini");
|
||||
_databaseRuntime = _playoutLaunchAuthorization.IsGateA
|
||||
? DatabaseRuntime.CreateDefault()
|
||||
: _isDevelopmentLiveLaunch
|
||||
? DatabaseRuntime.CreateDevelopmentLiveLocalOverride()
|
||||
: DatabaseRuntime.CreateLegacyExecutableDefault(
|
||||
AppContext.BaseDirectory,
|
||||
legacyOverridePath: selectedLegacyDatabaseIni,
|
||||
@@ -185,9 +200,12 @@ public sealed partial class MainWindow : Window
|
||||
new LegacyStockMasterIdentityValidationService(_databaseRuntime.Executor);
|
||||
operatorCatalogSchemaValidationService =
|
||||
new LegacyOperatorCatalogSchemaValidationService(_databaseRuntime.Executor);
|
||||
databaseInitializationSucceeded = true;
|
||||
}
|
||||
catch
|
||||
{
|
||||
_databaseRuntime = null;
|
||||
fixedPagePlanProvider = null;
|
||||
initializationError = IsSourceOnlyBuild
|
||||
? "소스 전용 DryRun에서는 데이터베이스 연결을 사용하지 않습니다."
|
||||
: "데이터베이스가 설정되지 않았습니다. 로컬 설정을 확인하세요.";
|
||||
@@ -225,6 +243,14 @@ public sealed partial class MainWindow : Window
|
||||
DataQueryExecutor.Reset();
|
||||
}
|
||||
|
||||
if (_isDevelopmentLiveLaunch && !databaseInitializationSucceeded)
|
||||
{
|
||||
// Development Live is one fail-closed startup transaction. A
|
||||
// missing or partially initialized protected DB runtime must not
|
||||
// leave the independently armed playout gate eligible for use.
|
||||
_developmentLiveStartupBlocked = true;
|
||||
}
|
||||
|
||||
_industryWorkflow = new LegacyIndustrySelectionWorkflow(
|
||||
industrySelectionService,
|
||||
actionLayout: runtimeUiCatalogs.IndustryLayout);
|
||||
@@ -310,7 +336,10 @@ public sealed partial class MainWindow : Window
|
||||
if (!_closing)
|
||||
{
|
||||
StartDatabaseHealthMonitor();
|
||||
await ConnectPlayoutAsync(_lifetimeCancellation.Token);
|
||||
if (!_developmentLiveStartupBlocked)
|
||||
{
|
||||
await ConnectPlayoutAsync(_lifetimeCancellation.Token);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user