/* * 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.Client.Responsibilities; using SafeExamBrowser.Communication.Contracts.Proxies; using SafeExamBrowser.Core.Contracts.OperationModel; using SafeExamBrowser.Core.Contracts.ResponsibilityModel; using SafeExamBrowser.Logging.Contracts; using SafeExamBrowser.UserInterface.Contracts.Windows; namespace SafeExamBrowser.Client { internal class ClientController { private readonly ClientContext context; private readonly ILogger logger; private readonly IOperationSequence operations; private readonly IResponsibilityCollection responsibilities; private readonly IRuntimeProxy runtime; private readonly ISplashScreen splashScreen; internal ClientController( ClientContext context, ILogger logger, IOperationSequence operations, IResponsibilityCollection responsibilities, IRuntimeProxy runtime, ISplashScreen splashScreen) { this.context = context; this.logger = logger; this.operations = operations; this.responsibilities = responsibilities; this.runtime = runtime; this.splashScreen = splashScreen; } internal bool TryStart() { logger.Info("Initiating startup procedure..."); splashScreen.Show(); splashScreen.BringToForeground(); var initialized = false; var result = operations.TryPerform(); if (result == OperationResult.Success) { DelegateStartupResponsibilities(); initialized = TryInformRuntime(); } else { logger.Info($"Application startup {(result == OperationResult.Aborted ? "aborted" : "failed")}!"); logger.Log(string.Empty); } if (initialized) { logger.Info("Application successfully initialized."); logger.Log(string.Empty); DelegateClientReadyResponsibilities(); } splashScreen.Hide(); return initialized; } internal void Terminate() { logger.Log(string.Empty); logger.Info("Initiating shutdown procedure..."); splashScreen.Show(); splashScreen.BringToForeground(); DelegateShutdownResponsibilities(); var success = operations.TryRevert() == OperationResult.Success; if (success) { logger.Info("Application successfully finalized."); logger.Log(string.Empty); } else { logger.Info("Application shutdown failed!"); logger.Log(string.Empty); } splashScreen.Close(); } internal void UpdateAppConfig() { splashScreen.AppConfig = context.AppConfig; } private void DelegateStartupResponsibilities() { responsibilities.Delegate(ClientTask.RegisterEvents); responsibilities.Delegate(ClientTask.ShowShell); responsibilities.Delegate(ClientTask.AutoStartApplications); //responsibilities.Delegate(ClientTask.ScheduleIntegrityVerification); //responsibilities.Delegate(ClientTask.StartMonitoring); } private void DelegateClientReadyResponsibilities() { //responsibilities.Delegate(ClientTask.VerifySessionIntegrity); } private void DelegateShutdownResponsibilities() { responsibilities.Delegate(ClientTask.CloseShell); responsibilities.Delegate(ClientTask.DeregisterEvents); //responsibilities.Delegate(ClientTask.UpdateSessionIntegrity); } private bool TryInformRuntime() { var communication = runtime.InformClientReady(); if (!communication.Success) { logger.Error("Failed to inform runtime that client is ready!"); } return communication.Success; } } }