2019-06-06 15:44:03 +02:00
|
|
|
|
/*
|
2024-03-05 18:37:42 +01:00
|
|
|
|
* Copyright (c) 2024 ETH Zürich, IT Services
|
2019-06-06 15:44:03 +02:00
|
|
|
|
*
|
|
|
|
|
* 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/.
|
|
|
|
|
*/
|
|
|
|
|
|
2019-06-18 10:18:56 +02:00
|
|
|
|
using System;
|
2019-08-30 09:55:26 +02:00
|
|
|
|
using SafeExamBrowser.Communication.Contracts.Events;
|
|
|
|
|
using SafeExamBrowser.Communication.Contracts.Hosts;
|
|
|
|
|
using SafeExamBrowser.Configuration.Contracts;
|
|
|
|
|
using SafeExamBrowser.Core.Contracts.OperationModel;
|
|
|
|
|
using SafeExamBrowser.Lockdown.Contracts;
|
|
|
|
|
using SafeExamBrowser.Logging.Contracts;
|
2019-06-06 15:44:03 +02:00
|
|
|
|
|
|
|
|
|
namespace SafeExamBrowser.Service
|
|
|
|
|
{
|
2020-03-16 13:38:25 +01:00
|
|
|
|
internal class ServiceController
|
2019-06-06 15:44:03 +02:00
|
|
|
|
{
|
2019-07-03 08:59:27 +02:00
|
|
|
|
private ILogger logger;
|
|
|
|
|
private Func<string, ILogObserver> logWriterFactory;
|
2019-06-07 15:26:03 +02:00
|
|
|
|
private IOperationSequence bootstrapSequence;
|
2019-06-18 10:18:56 +02:00
|
|
|
|
private IOperationSequence sessionSequence;
|
2019-06-07 15:26:03 +02:00
|
|
|
|
private IServiceHost serviceHost;
|
|
|
|
|
private SessionContext sessionContext;
|
2019-07-04 09:12:28 +02:00
|
|
|
|
private ISystemConfigurationUpdate systemConfigurationUpdate;
|
2019-07-03 08:59:27 +02:00
|
|
|
|
private ILogObserver sessionWriter;
|
2019-06-07 15:26:03 +02:00
|
|
|
|
|
2019-06-11 09:53:33 +02:00
|
|
|
|
private ServiceConfiguration Session
|
2019-06-07 15:26:03 +02:00
|
|
|
|
{
|
2019-06-18 10:18:56 +02:00
|
|
|
|
get { return sessionContext.Configuration; }
|
2019-06-07 15:26:03 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private bool SessionIsRunning
|
|
|
|
|
{
|
2019-06-27 08:32:37 +02:00
|
|
|
|
get { return sessionContext.IsRunning; }
|
2019-06-07 15:26:03 +02:00
|
|
|
|
}
|
|
|
|
|
|
2020-03-16 13:38:25 +01:00
|
|
|
|
internal ServiceController(
|
2019-06-18 10:18:56 +02:00
|
|
|
|
ILogger logger,
|
2019-07-03 08:59:27 +02:00
|
|
|
|
Func<string, ILogObserver> logWriterFactory,
|
2019-06-07 15:26:03 +02:00
|
|
|
|
IOperationSequence bootstrapSequence,
|
2019-06-18 10:18:56 +02:00
|
|
|
|
IOperationSequence sessionSequence,
|
2019-06-07 15:26:03 +02:00
|
|
|
|
IServiceHost serviceHost,
|
2019-07-04 09:12:28 +02:00
|
|
|
|
SessionContext sessionContext,
|
|
|
|
|
ISystemConfigurationUpdate systemConfigurationUpdate)
|
2019-06-07 15:26:03 +02:00
|
|
|
|
{
|
2019-06-18 10:18:56 +02:00
|
|
|
|
this.logger = logger;
|
2019-07-03 08:59:27 +02:00
|
|
|
|
this.logWriterFactory = logWriterFactory;
|
2019-06-07 15:26:03 +02:00
|
|
|
|
this.bootstrapSequence = bootstrapSequence;
|
|
|
|
|
this.sessionSequence = sessionSequence;
|
|
|
|
|
this.serviceHost = serviceHost;
|
|
|
|
|
this.sessionContext = sessionContext;
|
2019-07-04 09:12:28 +02:00
|
|
|
|
this.systemConfigurationUpdate = systemConfigurationUpdate;
|
2019-06-07 15:26:03 +02:00
|
|
|
|
}
|
|
|
|
|
|
2020-03-16 13:38:25 +01:00
|
|
|
|
internal bool TryStart()
|
2019-06-06 15:44:03 +02:00
|
|
|
|
{
|
2019-06-18 10:18:56 +02:00
|
|
|
|
logger.Info("Initiating startup procedure...");
|
|
|
|
|
|
2019-06-07 15:26:03 +02:00
|
|
|
|
var result = bootstrapSequence.TryPerform();
|
|
|
|
|
var success = result == OperationResult.Success;
|
|
|
|
|
|
2019-06-18 10:18:56 +02:00
|
|
|
|
if (success)
|
|
|
|
|
{
|
|
|
|
|
RegisterEvents();
|
|
|
|
|
|
|
|
|
|
logger.Info("Service successfully initialized.");
|
|
|
|
|
logger.Log(string.Empty);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
logger.Info("Service startup aborted!");
|
|
|
|
|
logger.Log(string.Empty);
|
|
|
|
|
}
|
|
|
|
|
|
2019-06-07 15:26:03 +02:00
|
|
|
|
return success;
|
2019-06-06 15:44:03 +02:00
|
|
|
|
}
|
|
|
|
|
|
2020-03-16 13:38:25 +01:00
|
|
|
|
internal void Terminate()
|
2019-06-06 15:44:03 +02:00
|
|
|
|
{
|
2019-06-18 10:18:56 +02:00
|
|
|
|
DeregisterEvents();
|
|
|
|
|
|
2019-06-07 15:26:03 +02:00
|
|
|
|
if (SessionIsRunning)
|
|
|
|
|
{
|
2019-06-18 10:18:56 +02:00
|
|
|
|
StopSession();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
logger.Log(string.Empty);
|
|
|
|
|
logger.Info("Initiating termination procedure...");
|
|
|
|
|
|
|
|
|
|
var result = bootstrapSequence.TryRevert();
|
|
|
|
|
var success = result == OperationResult.Success;
|
|
|
|
|
|
|
|
|
|
if (success)
|
|
|
|
|
{
|
|
|
|
|
logger.Info("Service successfully terminated.");
|
|
|
|
|
logger.Log(string.Empty);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
logger.Info("Service termination failed!");
|
|
|
|
|
logger.Log(string.Empty);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void StartSession()
|
|
|
|
|
{
|
2019-07-03 08:59:27 +02:00
|
|
|
|
InitializeSessionLogging();
|
2019-06-18 10:18:56 +02:00
|
|
|
|
logger.Info(AppendDivider("Session Start Procedure"));
|
|
|
|
|
|
|
|
|
|
var result = sessionSequence.TryPerform();
|
|
|
|
|
|
|
|
|
|
if (result == OperationResult.Success)
|
|
|
|
|
{
|
|
|
|
|
logger.Info(AppendDivider("Session Running"));
|
2019-06-07 15:26:03 +02:00
|
|
|
|
}
|
2019-06-18 10:18:56 +02:00
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
logger.Info(AppendDivider("Session Start Failed"));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void StopSession()
|
|
|
|
|
{
|
|
|
|
|
logger.Info(AppendDivider("Session Stop Procedure"));
|
|
|
|
|
|
|
|
|
|
var result = sessionSequence.TryRevert();
|
|
|
|
|
|
|
|
|
|
if (result == OperationResult.Success)
|
|
|
|
|
{
|
|
|
|
|
logger.Info(AppendDivider("Session Terminated"));
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
logger.Info(AppendDivider("Session Stop Failed"));
|
|
|
|
|
}
|
2019-07-03 08:59:27 +02:00
|
|
|
|
|
|
|
|
|
FinalizeSessionLogging();
|
2019-06-18 10:18:56 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void RegisterEvents()
|
|
|
|
|
{
|
|
|
|
|
serviceHost.SessionStartRequested += ServiceHost_SessionStartRequested;
|
|
|
|
|
serviceHost.SessionStopRequested += ServiceHost_SessionStopRequested;
|
2019-07-04 09:12:28 +02:00
|
|
|
|
serviceHost.SystemConfigurationUpdateRequested += ServiceHost_SystemConfigurationUpdateRequested;
|
2019-06-18 10:18:56 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void DeregisterEvents()
|
|
|
|
|
{
|
|
|
|
|
serviceHost.SessionStartRequested -= ServiceHost_SessionStartRequested;
|
|
|
|
|
serviceHost.SessionStopRequested -= ServiceHost_SessionStopRequested;
|
2019-07-04 09:12:28 +02:00
|
|
|
|
serviceHost.SystemConfigurationUpdateRequested -= ServiceHost_SystemConfigurationUpdateRequested;
|
2019-06-18 10:18:56 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void ServiceHost_SessionStartRequested(SessionStartEventArgs args)
|
|
|
|
|
{
|
|
|
|
|
if (!SessionIsRunning)
|
|
|
|
|
{
|
|
|
|
|
sessionContext.Configuration = args.Configuration;
|
|
|
|
|
|
|
|
|
|
StartSession();
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
logger.Warn("Received session start request, even though a session is already running!");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void ServiceHost_SessionStopRequested(SessionStopEventArgs args)
|
|
|
|
|
{
|
|
|
|
|
if (SessionIsRunning)
|
|
|
|
|
{
|
2019-06-19 15:40:21 +02:00
|
|
|
|
if (Session.SessionId == args.SessionId)
|
|
|
|
|
{
|
|
|
|
|
StopSession();
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
logger.Warn("Received session stop request with wrong session ID!");
|
|
|
|
|
}
|
2019-06-18 10:18:56 +02:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
logger.Warn("Received session stop request, even though no session is currently running!");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2019-07-04 09:12:28 +02:00
|
|
|
|
private void ServiceHost_SystemConfigurationUpdateRequested()
|
|
|
|
|
{
|
|
|
|
|
logger.Info("Received request to initiate system configuration update.");
|
|
|
|
|
systemConfigurationUpdate.ExecuteAsync();
|
|
|
|
|
}
|
|
|
|
|
|
2019-06-18 10:18:56 +02:00
|
|
|
|
private string AppendDivider(string message)
|
|
|
|
|
{
|
|
|
|
|
var dashesLeft = new String('-', 48 - message.Length / 2 - message.Length % 2);
|
|
|
|
|
var dashesRight = new String('-', 48 - message.Length / 2);
|
2019-06-07 15:26:03 +02:00
|
|
|
|
|
2019-06-18 10:18:56 +02:00
|
|
|
|
return $"### {dashesLeft} {message} {dashesRight} ###";
|
2019-06-06 15:44:03 +02:00
|
|
|
|
}
|
2019-07-03 08:59:27 +02:00
|
|
|
|
|
|
|
|
|
private void InitializeSessionLogging()
|
|
|
|
|
{
|
|
|
|
|
if (Session?.AppConfig?.ServiceLogFilePath != null)
|
|
|
|
|
{
|
|
|
|
|
sessionWriter = logWriterFactory.Invoke(Session.AppConfig.ServiceLogFilePath);
|
|
|
|
|
logger.Subscribe(sessionWriter);
|
|
|
|
|
logger.LogLevel = Session.Settings.LogLevel;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
logger.Warn("Could not initialize session writer due to missing configuration data!");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void FinalizeSessionLogging()
|
|
|
|
|
{
|
|
|
|
|
if (sessionWriter != null)
|
|
|
|
|
{
|
|
|
|
|
logger.Unsubscribe(sessionWriter);
|
|
|
|
|
sessionWriter = null;
|
|
|
|
|
}
|
|
|
|
|
}
|
2019-06-06 15:44:03 +02:00
|
|
|
|
}
|
|
|
|
|
}
|