Files
SEBPatch/SafeExamBrowser.Runtime/RuntimeController.cs

119 lines
3.4 KiB
C#

/*
* Copyright (c) 2025 ETH Zürich, IT Services
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
using SafeExamBrowser.Core.Contracts.OperationModel;
using SafeExamBrowser.Core.Contracts.ResponsibilityModel;
using SafeExamBrowser.Logging.Contracts;
using SafeExamBrowser.Runtime.Responsibilities;
using SafeExamBrowser.UserInterface.Contracts.Windows;
using System.Deployment.Internal;
namespace SafeExamBrowser.Runtime
{
internal class RuntimeController
{
private readonly ILogger logger;
private readonly IOperationSequence bootstrapSequence;
private readonly IResponsibilityCollection<RuntimeTask> responsibilities;
private readonly RuntimeContext runtimeContext;
private readonly IRuntimeWindow runtimeWindow;
private readonly ISplashScreen splashScreen;
private bool SessionIsRunning => runtimeContext.Current != default;
internal RuntimeController(
ILogger logger,
IOperationSequence bootstrapSequence,
IResponsibilityCollection<RuntimeTask> responsibilities,
RuntimeContext runtimeContext,
IRuntimeWindow runtimeWindow,
ISplashScreen splashScreen)
{
this.bootstrapSequence = bootstrapSequence;
this.responsibilities = responsibilities;
this.logger = logger;
this.runtimeWindow = runtimeWindow;
this.runtimeContext = runtimeContext;
this.splashScreen = splashScreen;
}
internal bool TryStart()
{
logger.Info("Initiating startup procedure...");
// We need to show the runtime window here already, this way implicitly setting it as the runtime application's main window.
// Otherwise, the splash screen is considered as the main window and thus the operating system and/or WPF does not correctly
// activate the runtime window once bootstrapping has finished, which in turn leads to undesired user interface behavior.
runtimeWindow.Show();
runtimeWindow.BringToForeground();
runtimeWindow.SetIndeterminate();
splashScreen.Show();
splashScreen.BringToForeground();
var initialized = bootstrapSequence.TryPerform() == OperationResult.Success;
if (initialized)
{
responsibilities.Delegate(RuntimeTask.RegisterEvents);
splashScreen.Hide();
logger.Info("Application successfully initialized.");
logger.Log(string.Empty);
logger.Subscribe(runtimeWindow);
responsibilities.Delegate(RuntimeTask.StartSession);
}
else
{
logger.Info("Application startup aborted!");
logger.Log(string.Empty);
responsibilities.Delegate(RuntimeTask.ShowStartupError);
}
return initialized && SessionIsRunning;
}
internal void Terminate()
{
responsibilities.Delegate(RuntimeTask.DeregisterEvents);
if (SessionIsRunning)
{
responsibilities.Delegate(RuntimeTask.StopSession);
}
logger.Unsubscribe(runtimeWindow);
runtimeWindow.Close();
splashScreen.Show();
splashScreen.BringToForeground();
logger.Log(string.Empty);
logger.Info("Initiating shutdown procedure...");
var success = bootstrapSequence.TryRevert() == OperationResult.Success;
if (success)
{
logger.Info("Application successfully finalized.");
logger.Log(string.Empty);
}
else
{
logger.Info("Shutdown procedure failed!");
logger.Log(string.Empty);
responsibilities.Delegate(RuntimeTask.ShowShutdownError);
}
splashScreen.Close();
}
}
}