SEBWIN-219: Found better solution for session operation sequence (got rid of session controller and sequence start resp. end operations).

This commit is contained in:
dbuechel 2018-03-21 10:23:15 +01:00
parent e750f870c0
commit 6efa7bed81
15 changed files with 270 additions and 246 deletions

View file

@ -43,14 +43,14 @@ namespace SafeExamBrowser.Contracts.I18n
Notification_AboutTooltip, Notification_AboutTooltip,
Notification_LogTooltip, Notification_LogTooltip,
ProgressIndicator_CloseRuntimeConnection, ProgressIndicator_CloseRuntimeConnection,
ProgressIndicator_CloseServiceConnection,
ProgressIndicator_EmptyClipboard, ProgressIndicator_EmptyClipboard,
ProgressIndicator_FinalizeServiceSession,
ProgressIndicator_InitializeBrowser, ProgressIndicator_InitializeBrowser,
ProgressIndicator_InitializeConfiguration, ProgressIndicator_InitializeConfiguration,
ProgressIndicator_InitializeKioskMode, ProgressIndicator_InitializeKioskMode,
ProgressIndicator_InitializeProcessMonitoring, ProgressIndicator_InitializeProcessMonitoring,
ProgressIndicator_InitializeRuntimeConnection, ProgressIndicator_InitializeRuntimeConnection,
ProgressIndicator_InitializeServiceConnection, ProgressIndicator_InitializeServiceSession,
ProgressIndicator_InitializeTaskbar, ProgressIndicator_InitializeTaskbar,
ProgressIndicator_InitializeWindowMonitoring, ProgressIndicator_InitializeWindowMonitoring,
ProgressIndicator_InitializeWorkingArea, ProgressIndicator_InitializeWorkingArea,
@ -58,17 +58,18 @@ namespace SafeExamBrowser.Contracts.I18n
ProgressIndicator_RestoreWorkingArea, ProgressIndicator_RestoreWorkingArea,
ProgressIndicator_RevertKioskMode, ProgressIndicator_RevertKioskMode,
ProgressIndicator_ShutdownProcedure, ProgressIndicator_ShutdownProcedure,
ProgressIndicator_StartClient,
ProgressIndicator_StartCommunicationHost, ProgressIndicator_StartCommunicationHost,
ProgressIndicator_StartEventHandling, ProgressIndicator_StartEventHandling,
ProgressIndicator_StartKeyboardInterception, ProgressIndicator_StartKeyboardInterception,
ProgressIndicator_StartMouseInterception, ProgressIndicator_StartMouseInterception,
ProgressIndicator_StartSession, ProgressIndicator_InitializeSession,
ProgressIndicator_StopClient,
ProgressIndicator_StopCommunicationHost, ProgressIndicator_StopCommunicationHost,
ProgressIndicator_StopEventHandling, ProgressIndicator_StopEventHandling,
ProgressIndicator_StopKeyboardInterception, ProgressIndicator_StopKeyboardInterception,
ProgressIndicator_StopMouseInterception, ProgressIndicator_StopMouseInterception,
ProgressIndicator_StopProcessMonitoring, ProgressIndicator_StopProcessMonitoring,
ProgressIndicator_StopSession,
ProgressIndicator_StopWindowMonitoring, ProgressIndicator_StopWindowMonitoring,
ProgressIndicator_TerminateBrowser, ProgressIndicator_TerminateBrowser,
ProgressIndicator_TerminateTaskbar, ProgressIndicator_TerminateTaskbar,

View file

@ -81,12 +81,12 @@
<Entry key="ProgressIndicator_CloseRuntimeConnection"> <Entry key="ProgressIndicator_CloseRuntimeConnection">
Closing runtime connection Closing runtime connection
</Entry> </Entry>
<Entry key="ProgressIndicator_CloseServiceConnection">
Closing service connection
</Entry>
<Entry key="ProgressIndicator_EmptyClipboard"> <Entry key="ProgressIndicator_EmptyClipboard">
Emptying clipboard Emptying clipboard
</Entry> </Entry>
<Entry key="ProgressIndicator_FinalizeServiceSession">
Finalizing service session
</Entry>
<Entry key="ProgressIndicator_InitializeBrowser"> <Entry key="ProgressIndicator_InitializeBrowser">
Initializing browser Initializing browser
</Entry> </Entry>
@ -102,8 +102,11 @@
<Entry key="ProgressIndicator_InitializeRuntimeConnection"> <Entry key="ProgressIndicator_InitializeRuntimeConnection">
Initializing runtime connection Initializing runtime connection
</Entry> </Entry>
<Entry key="ProgressIndicator_InitializeServiceConnection"> <Entry key="ProgressIndicator_InitializeServiceSession">
Initializing service connection Initializing service session
</Entry>
<Entry key="ProgressIndicator_InitializeSession">
Initializing new session
</Entry> </Entry>
<Entry key="ProgressIndicator_InitializeTaskbar"> <Entry key="ProgressIndicator_InitializeTaskbar">
Initializing taskbar Initializing taskbar
@ -126,6 +129,9 @@
<Entry key="ProgressIndicator_ShutdownProcedure"> <Entry key="ProgressIndicator_ShutdownProcedure">
Initiating shutdown procedure Initiating shutdown procedure
</Entry> </Entry>
<Entry key="ProgressIndicator_StartClient">
Starting client
</Entry>
<Entry key="ProgressIndicator_StartCommunicationHost"> <Entry key="ProgressIndicator_StartCommunicationHost">
Starting communication host Starting communication host
</Entry> </Entry>
@ -138,8 +144,8 @@
<Entry key="ProgressIndicator_StartMouseInterception"> <Entry key="ProgressIndicator_StartMouseInterception">
Starting mouse interception Starting mouse interception
</Entry> </Entry>
<Entry key="ProgressIndicator_StartSession"> <Entry key="ProgressIndicator_StopClient">
Starting new session Stopping client
</Entry> </Entry>
<Entry key="ProgressIndicator_StopCommunicationHost"> <Entry key="ProgressIndicator_StopCommunicationHost">
Stopping communication host Stopping communication host
@ -156,9 +162,6 @@
<Entry key="ProgressIndicator_StopProcessMonitoring"> <Entry key="ProgressIndicator_StopProcessMonitoring">
Stopping process monitoring Stopping process monitoring
</Entry> </Entry>
<Entry key="ProgressIndicator_StopSession">
Stopping current session
</Entry>
<Entry key="ProgressIndicator_StopWindowMonitoring"> <Entry key="ProgressIndicator_StopWindowMonitoring">
Stopping window monitoring Stopping window monitoring
</Entry> </Entry>

View file

@ -28,7 +28,7 @@ namespace SafeExamBrowser.Runtime.UnitTests.Behaviour.Operations
private Mock<IConfigurationRepository> configuration; private Mock<IConfigurationRepository> configuration;
private Mock<IProgressIndicator> progressIndicator; private Mock<IProgressIndicator> progressIndicator;
private Mock<IText> text; private Mock<IText> text;
private ServiceConnectionOperation sut; private ServiceOperation sut;
[TestInitialize] [TestInitialize]
public void Initialize() public void Initialize()
@ -39,7 +39,7 @@ namespace SafeExamBrowser.Runtime.UnitTests.Behaviour.Operations
progressIndicator = new Mock<IProgressIndicator>(); progressIndicator = new Mock<IProgressIndicator>();
text = new Mock<IText>(); text = new Mock<IText>();
sut = new ServiceConnectionOperation(configuration.Object, logger.Object, service.Object, text.Object); sut = new ServiceOperation(configuration.Object, logger.Object, service.Object, text.Object);
} }
[TestMethod] [TestMethod]

View file

@ -1,22 +0,0 @@
/*
* Copyright (c) 2018 ETH Zürich, Educational Development and Technology (LET)
*
* 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 Microsoft.VisualStudio.TestTools.UnitTesting;
namespace SafeExamBrowser.Runtime.UnitTests.Behaviour.Operations
{
[TestClass]
public class SessionSequenceOperationTests
{
[TestMethod]
public void TODO()
{
Assert.Fail();
}
}
}

View file

@ -83,7 +83,6 @@
<Compile Include="Behaviour\Operations\ConfigurationOperationTests.cs" /> <Compile Include="Behaviour\Operations\ConfigurationOperationTests.cs" />
<Compile Include="Behaviour\Operations\KioskModeOperationTests.cs" /> <Compile Include="Behaviour\Operations\KioskModeOperationTests.cs" />
<Compile Include="Behaviour\Operations\ServiceConnectionOperationTests.cs" /> <Compile Include="Behaviour\Operations\ServiceConnectionOperationTests.cs" />
<Compile Include="Behaviour\Operations\SessionSequenceOperationTests.cs" />
<Compile Include="Behaviour\RuntimeControllerTests.cs" /> <Compile Include="Behaviour\RuntimeControllerTests.cs" />
<Compile Include="Communication\RuntimeHostTests.cs" /> <Compile Include="Communication\RuntimeHostTests.cs" />
<Compile Include="Properties\AssemblyInfo.cs" /> <Compile Include="Properties\AssemblyInfo.cs" />

View file

@ -17,104 +17,69 @@ using SafeExamBrowser.Contracts.Logging;
using SafeExamBrowser.Contracts.UserInterface; using SafeExamBrowser.Contracts.UserInterface;
using SafeExamBrowser.Contracts.WindowsApi; using SafeExamBrowser.Contracts.WindowsApi;
namespace SafeExamBrowser.Runtime.Behaviour namespace SafeExamBrowser.Runtime.Behaviour.Operations
{ {
internal class SessionController internal class ClientOperation : IOperation
{ {
private const int TEN_SECONDS = 10000; private const int TEN_SECONDS = 10000;
private bool sessionRunning; protected IConfigurationRepository configuration;
private IConfigurationRepository configuration; protected ILogger logger;
private ILogger logger; protected IProcessFactory processFactory;
private IProcessFactory processFactory; protected IProxyFactory proxyFactory;
private IProxyFactory proxyFactory; protected IRuntimeHost runtimeHost;
private IRuntimeHost runtimeHost;
private IServiceProxy service;
internal IProgressIndicator ProgressIndicator { private get; set; } protected static IProcess ClientProcess { get; private set; }
protected static IClientProxy ClientProxy { get; private set; }
public IProgressIndicator ProgressIndicator { protected get; set; }
internal SessionController( public ClientOperation(
IConfigurationRepository configuration, IConfigurationRepository configuration,
ILogger logger, ILogger logger,
IProcessFactory processFactory, IProcessFactory processFactory,
IProxyFactory proxyFactory, IProxyFactory proxyFactory,
IRuntimeHost runtimeHost, IRuntimeHost runtimeHost)
IServiceProxy service)
{ {
this.configuration = configuration; this.configuration = configuration;
this.logger = logger; this.logger = logger;
this.processFactory = processFactory; this.processFactory = processFactory;
this.proxyFactory = proxyFactory; this.proxyFactory = proxyFactory;
this.runtimeHost = runtimeHost; this.runtimeHost = runtimeHost;
this.service = service;
} }
internal OperationResult StartSession() public virtual OperationResult Perform()
{ {
logger.Info("Starting new session..."); ProgressIndicator?.UpdateText(TextKey.ProgressIndicator_StartClient, true);
ProgressIndicator?.UpdateText(TextKey.ProgressIndicator_StartSession, true);
InitializeSessionConfiguration(); var success = TryStartClient();
StartServiceSession();
sessionRunning = TryStartClient();
if (!sessionRunning) if (success)
{ {
logger.Info($"Failed to start new session! Reverting service session and aborting procedure..."); logger.Info($"Successfully started new client instance.");
service.StopSession(configuration.CurrentSession.Id); }
else
return OperationResult.Failed; {
logger.Error($"Failed to start new client instance! Aborting procedure...");
} }
logger.Info($"Successfully started new session."); return success ? OperationResult.Success : OperationResult.Failed;
return OperationResult.Success;
} }
internal OperationResult StopSession() public virtual OperationResult Repeat()
{ {
if (sessionRunning) return Perform();
}
public virtual void Revert()
{
if (ClientProcess != null && !ClientProcess.HasTerminated)
{ {
logger.Info($"Stopping session with identifier '{configuration.CurrentSession.Id}'..."); ProgressIndicator?.UpdateText(TextKey.ProgressIndicator_StopClient, true);
ProgressIndicator?.UpdateText(TextKey.ProgressIndicator_StopSession, true); TryStopClient();
StopServiceSession();
if (!configuration.CurrentSession.ClientProcess.HasTerminated)
{
StopClient();
}
sessionRunning = false;
logger.Info($"Successfully stopped session.");
} }
return OperationResult.Success;
} }
private void InitializeSessionConfiguration() protected bool TryStartClient()
{
configuration.InitializeSessionConfiguration();
runtimeHost.StartupToken = configuration.CurrentSession.StartupToken;
logger.Info($" -> Client-ID: {configuration.RuntimeInfo.ClientId}");
logger.Info($" -> Runtime-ID: {configuration.RuntimeInfo.RuntimeId} (as reference, does not change)");
logger.Info($" -> Session-ID: {configuration.CurrentSession.Id}");
}
private void StartServiceSession()
{
logger.Info("Initializing service session...");
service.StartSession(configuration.CurrentSession.Id, configuration.CurrentSettings);
}
private void StopServiceSession()
{
logger.Info("Stopping service session...");
service.StopSession(configuration.CurrentSession.Id);
}
private bool TryStartClient()
{ {
var clientReady = false; var clientReady = false;
var clientReadyEvent = new AutoResetEvent(false); var clientReadyEvent = new AutoResetEvent(false);
@ -126,7 +91,7 @@ namespace SafeExamBrowser.Runtime.Behaviour
logger.Info("Starting new client process..."); logger.Info("Starting new client process...");
runtimeHost.ClientReady += clientReadyEventHandler; runtimeHost.ClientReady += clientReadyEventHandler;
configuration.CurrentSession.ClientProcess = processFactory.StartNew(clientExecutable, clientLogFile, hostUri, token); ClientProcess = processFactory.StartNew(clientExecutable, clientLogFile, hostUri, token);
logger.Info("Waiting for client to complete initialization..."); logger.Info("Waiting for client to complete initialization...");
clientReady = clientReadyEvent.WaitOne(TEN_SECONDS); clientReady = clientReadyEvent.WaitOne(TEN_SECONDS);
@ -140,20 +105,20 @@ namespace SafeExamBrowser.Runtime.Behaviour
} }
logger.Info("Client has been successfully started and initialized. Creating communication proxy for client host..."); logger.Info("Client has been successfully started and initialized. Creating communication proxy for client host...");
configuration.CurrentSession.ClientProxy = proxyFactory.CreateClientProxy(configuration.RuntimeInfo.ClientAddress); ClientProxy = proxyFactory.CreateClientProxy(configuration.RuntimeInfo.ClientAddress);
if (!configuration.CurrentSession.ClientProxy.Connect(configuration.CurrentSession.StartupToken)) if (!ClientProxy.Connect(configuration.CurrentSession.StartupToken))
{ {
logger.Error("Failed to connect to client!"); logger.Error("Failed to connect to client!");
return false; return false;
} }
logger.Info("Connection with client has been established."); logger.Info("Connection with client has been established. Requesting authentication...");
var response = configuration.CurrentSession.ClientProxy.RequestAuthentication(); var response = ClientProxy.RequestAuthentication();
if (configuration.CurrentSession.ClientProcess.Id != response?.ProcessId) if (ClientProcess.Id != response?.ProcessId)
{ {
logger.Error("Failed to verify client integrity!"); logger.Error("Failed to verify client integrity!");
@ -162,11 +127,16 @@ namespace SafeExamBrowser.Runtime.Behaviour
logger.Info("Authentication of client has been successful, client is ready to operate."); logger.Info("Authentication of client has been successful, client is ready to operate.");
configuration.CurrentSession.ClientProcess = ClientProcess;
configuration.CurrentSession.ClientProxy = ClientProxy;
return true; return true;
} }
private void StopClient() protected bool TryStopClient()
{ {
var success = false;
var disconnected = false; var disconnected = false;
var disconnectedEvent = new AutoResetEvent(false); var disconnectedEvent = new AutoResetEvent(false);
var disconnectedEventHandler = new CommunicationEventHandler(() => disconnectedEvent.Set()); var disconnectedEventHandler = new CommunicationEventHandler(() => disconnectedEvent.Set());
@ -176,13 +146,13 @@ namespace SafeExamBrowser.Runtime.Behaviour
var terminatedEventHandler = new ProcessTerminatedEventHandler((_) => terminatedEvent.Set()); var terminatedEventHandler = new ProcessTerminatedEventHandler((_) => terminatedEvent.Set());
runtimeHost.ClientDisconnected += disconnectedEventHandler; runtimeHost.ClientDisconnected += disconnectedEventHandler;
configuration.CurrentSession.ClientProcess.Terminated += terminatedEventHandler; ClientProcess.Terminated += terminatedEventHandler;
logger.Info("Instructing client to initiate shutdown procedure."); logger.Info("Instructing client to initiate shutdown procedure.");
configuration.CurrentSession.ClientProxy.InitiateShutdown(); ClientProxy.InitiateShutdown();
logger.Info("Disconnecting from client communication host."); logger.Info("Disconnecting from client communication host.");
configuration.CurrentSession.ClientProxy.Disconnect(); ClientProxy.Disconnect();
logger.Info("Waiting for client to disconnect from runtime communication host..."); logger.Info("Waiting for client to disconnect from runtime communication host...");
disconnected = disconnectedEvent.WaitOne(TEN_SECONDS); disconnected = disconnectedEvent.WaitOne(TEN_SECONDS);
@ -201,20 +171,29 @@ namespace SafeExamBrowser.Runtime.Behaviour
} }
runtimeHost.ClientDisconnected -= disconnectedEventHandler; runtimeHost.ClientDisconnected -= disconnectedEventHandler;
configuration.CurrentSession.ClientProcess.Terminated -= terminatedEventHandler; ClientProcess.Terminated -= terminatedEventHandler;
if (disconnected && terminated) if (disconnected && terminated)
{ {
logger.Info("Client has been successfully terminated."); logger.Info("Client has been successfully terminated.");
success = true;
} }
else else
{ {
logger.Warn("Attempting to kill client process since graceful termination failed!"); logger.Warn("Attempting to kill client process since graceful termination failed!");
KillClient(); success = TryKillClient();
} }
if (success)
{
configuration.CurrentSession.ClientProcess = null;
configuration.CurrentSession.ClientProxy = null;
}
return success;
} }
private void KillClient(int attempt = 0) protected bool TryKillClient(int attempt = 0)
{ {
const int MAX_ATTEMPTS = 5; const int MAX_ATTEMPTS = 5;
@ -222,20 +201,23 @@ namespace SafeExamBrowser.Runtime.Behaviour
{ {
logger.Error($"Failed to kill client process within {MAX_ATTEMPTS} attempts!"); logger.Error($"Failed to kill client process within {MAX_ATTEMPTS} attempts!");
return; return false;
} }
logger.Info($"Killing client process with ID = {configuration.CurrentSession.ClientProcess.Id}."); logger.Info($"Killing client process with ID = {ClientProcess.Id}.");
configuration.CurrentSession.ClientProcess.Kill(); ClientProcess.Kill();
if (configuration.CurrentSession.ClientProcess.HasTerminated) if (ClientProcess.HasTerminated)
{ {
logger.Info("Client process has terminated."); logger.Info("Client process has terminated.");
return true;
} }
else else
{ {
logger.Warn("Failed to kill client process. Trying again..."); logger.Warn("Failed to kill client process. Trying again...");
KillClient(attempt++);
return TryKillClient(attempt++);
} }
} }
} }

View file

@ -0,0 +1,53 @@
/*
* Copyright (c) 2018 ETH Zürich, Educational Development and Technology (LET)
*
* 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.Contracts.Behaviour.OperationModel;
using SafeExamBrowser.Contracts.Communication.Hosts;
using SafeExamBrowser.Contracts.Communication.Proxies;
using SafeExamBrowser.Contracts.Configuration;
using SafeExamBrowser.Contracts.I18n;
using SafeExamBrowser.Contracts.Logging;
using SafeExamBrowser.Contracts.WindowsApi;
namespace SafeExamBrowser.Runtime.Behaviour.Operations
{
internal class ClientTerminationOperation : ClientOperation
{
public ClientTerminationOperation(
IConfigurationRepository configuration,
ILogger logger,
IProcessFactory processFactory,
IProxyFactory proxyFactory,
IRuntimeHost runtimeHost) : base(configuration, logger, processFactory, proxyFactory, runtimeHost)
{
}
public override OperationResult Perform()
{
return OperationResult.Success;
}
public override OperationResult Repeat()
{
var success = true;
if (ClientProcess != null && !ClientProcess.HasTerminated)
{
ProgressIndicator?.UpdateText(TextKey.ProgressIndicator_StopClient, true);
success = TryStopClient();
}
return success ? OperationResult.Success : OperationResult.Failed;
}
public override void Revert()
{
// Nothing to do here...
}
}
}

View file

@ -23,8 +23,8 @@ namespace SafeExamBrowser.Runtime.Behaviour.Operations
private IConfigurationRepository repository; private IConfigurationRepository repository;
private ILogger logger; private ILogger logger;
private IMessageBox messageBox; private IMessageBox messageBox;
private RuntimeInfo runtimeInfo;
private IText text; private IText text;
private RuntimeInfo runtimeInfo;
private string[] commandLineArgs; private string[] commandLineArgs;
public IProgressIndicator ProgressIndicator { private get; set; } public IProgressIndicator ProgressIndicator { private get; set; }
@ -50,30 +50,23 @@ namespace SafeExamBrowser.Runtime.Behaviour.Operations
logger.Info("Initializing application configuration..."); logger.Info("Initializing application configuration...");
ProgressIndicator?.UpdateText(TextKey.ProgressIndicator_InitializeConfiguration); ProgressIndicator?.UpdateText(TextKey.ProgressIndicator_InitializeConfiguration);
Settings settings;
var isValidUri = TryGetSettingsUri(out Uri uri); var isValidUri = TryGetSettingsUri(out Uri uri);
if (isValidUri) if (isValidUri)
{ {
logger.Info($"Loading configuration from '{uri.AbsolutePath}'..."); logger.Info($"Loading configuration from '{uri.AbsolutePath}'...");
settings = repository.LoadSettings(uri);
if (settings.ConfigurationMode == ConfigurationMode.ConfigureClient) var abort = LoadSettings(uri);
if (abort)
{ {
var abort = IsConfigurationSufficient(); return OperationResult.Aborted;
logger.Info($"The user chose to {(abort ? "abort" : "continue")} after successful client configuration.");
if (abort)
{
return OperationResult.Aborted;
}
} }
} }
else else
{ {
logger.Info("No valid settings file specified nor found in PROGRAMDATA or APPDATA - loading default settings..."); logger.Info("No valid settings file specified nor found in PROGRAMDATA or APPDATA - loading default settings...");
settings = repository.LoadDefaultSettings(); repository.LoadDefaultSettings();
} }
return OperationResult.Success; return OperationResult.Success;
@ -126,6 +119,21 @@ namespace SafeExamBrowser.Runtime.Behaviour.Operations
return isValidUri; return isValidUri;
} }
private bool LoadSettings(Uri uri)
{
var abort = false;
var settings = repository.LoadSettings(uri);
if (settings.ConfigurationMode == ConfigurationMode.ConfigureClient)
{
abort = IsConfigurationSufficient();
logger.Info($"The user chose to {(abort ? "abort" : "continue")} after successful client configuration.");
}
return abort;
}
private bool IsConfigurationSufficient() private bool IsConfigurationSufficient()
{ {
var message = text.Get(TextKey.MessageBox_ClientConfigurationQuestion); var message = text.Get(TextKey.MessageBox_ClientConfigurationQuestion);

View file

@ -17,7 +17,7 @@ using SafeExamBrowser.Contracts.UserInterface;
namespace SafeExamBrowser.Runtime.Behaviour.Operations namespace SafeExamBrowser.Runtime.Behaviour.Operations
{ {
internal class ServiceConnectionOperation : IOperation internal class ServiceOperation : IOperation
{ {
private bool connected, mandatory; private bool connected, mandatory;
private IConfigurationRepository configuration; private IConfigurationRepository configuration;
@ -27,7 +27,7 @@ namespace SafeExamBrowser.Runtime.Behaviour.Operations
public IProgressIndicator ProgressIndicator { private get; set; } public IProgressIndicator ProgressIndicator { private get; set; }
public ServiceConnectionOperation(IConfigurationRepository configuration, ILogger logger, IServiceProxy service, IText text) public ServiceOperation(IConfigurationRepository configuration, ILogger logger, IServiceProxy service, IText text)
{ {
this.configuration = configuration; this.configuration = configuration;
this.service = service; this.service = service;
@ -37,8 +37,8 @@ namespace SafeExamBrowser.Runtime.Behaviour.Operations
public OperationResult Perform() public OperationResult Perform()
{ {
logger.Info($"Initializing service connection..."); logger.Info($"Initializing service session...");
ProgressIndicator?.UpdateText(TextKey.ProgressIndicator_InitializeServiceConnection); ProgressIndicator?.UpdateText(TextKey.ProgressIndicator_InitializeServiceSession);
try try
{ {
@ -60,23 +60,35 @@ namespace SafeExamBrowser.Runtime.Behaviour.Operations
service.Ignore = !connected; service.Ignore = !connected;
logger.Info($"The service is {(mandatory ? "mandatory" : "optional")} and {(connected ? "available." : "not available. All service-related operations will be ignored!")}"); logger.Info($"The service is {(mandatory ? "mandatory" : "optional")} and {(connected ? "available." : "not available. All service-related operations will be ignored!")}");
if (connected)
{
StartServiceSession();
}
return OperationResult.Success; return OperationResult.Success;
} }
public OperationResult Repeat() public OperationResult Repeat()
{ {
// TODO: Re-check if mandatory, if so, try to connect (if not connected) - otherwise, no action required (except maybe logging of status?) // TODO: Re-check if mandatory, if so, try to connect (if not connected) - otherwise, no action required (except maybe logging of status?)
if (connected)
{
StopServiceSession();
StartServiceSession();
}
return OperationResult.Success; return OperationResult.Success;
} }
public void Revert() public void Revert()
{ {
logger.Info("Closing service connection..."); logger.Info("Finalizing service session...");
ProgressIndicator?.UpdateText(TextKey.ProgressIndicator_CloseServiceConnection); ProgressIndicator?.UpdateText(TextKey.ProgressIndicator_FinalizeServiceSession);
if (connected) if (connected)
{ {
StopServiceSession();
try try
{ {
service.Disconnect(); service.Disconnect();
@ -88,6 +100,16 @@ namespace SafeExamBrowser.Runtime.Behaviour.Operations
} }
} }
private void StartServiceSession()
{
service.StartSession(configuration.CurrentSession.Id, configuration.CurrentSettings);
}
private void StopServiceSession()
{
service.StopSession(configuration.CurrentSession.Id);
}
private void LogException(Exception e) private void LogException(Exception e)
{ {
var message = "Failed to connect to the service component!"; var message = "Failed to connect to the service component!";

View file

@ -0,0 +1,65 @@
/*
* Copyright (c) 2018 ETH Zürich, Educational Development and Technology (LET)
*
* 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.Contracts.Behaviour.OperationModel;
using SafeExamBrowser.Contracts.Communication.Hosts;
using SafeExamBrowser.Contracts.Configuration;
using SafeExamBrowser.Contracts.I18n;
using SafeExamBrowser.Contracts.Logging;
using SafeExamBrowser.Contracts.UserInterface;
namespace SafeExamBrowser.Runtime.Behaviour.Operations
{
internal class SessionInitializationOperation : IOperation
{
private IConfigurationRepository configuration;
private ILogger logger;
private IRuntimeHost runtimeHost;
public IProgressIndicator ProgressIndicator { private get; set; }
public SessionInitializationOperation(IConfigurationRepository configuration, ILogger logger, IRuntimeHost runtimeHost)
{
this.configuration = configuration;
this.logger = logger;
this.runtimeHost = runtimeHost;
}
public OperationResult Perform()
{
InitializeSessionConfiguration();
return OperationResult.Success;
}
public OperationResult Repeat()
{
InitializeSessionConfiguration();
return OperationResult.Success;
}
public void Revert()
{
// Nothing to do here...
}
private void InitializeSessionConfiguration()
{
logger.Info("Initializing new session configuration...");
ProgressIndicator?.UpdateText(TextKey.ProgressIndicator_InitializeSession, true);
configuration.InitializeSessionConfiguration();
runtimeHost.StartupToken = configuration.CurrentSession.StartupToken;
logger.Info($" -> Client-ID: {configuration.RuntimeInfo.ClientId}");
logger.Info($" -> Runtime-ID: {configuration.RuntimeInfo.RuntimeId} (as reference, does not change)");
logger.Info($" -> Session-ID: {configuration.CurrentSession.Id}");
}
}
}

View file

@ -1,45 +0,0 @@
/*
* Copyright (c) 2018 ETH Zürich, Educational Development and Technology (LET)
*
* 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.Contracts.Behaviour.OperationModel;
using SafeExamBrowser.Contracts.UserInterface;
namespace SafeExamBrowser.Runtime.Behaviour.Operations
{
internal class SessionSequenceEndOperation : IOperation
{
private SessionController controller;
public IProgressIndicator ProgressIndicator { private get; set; }
public SessionSequenceEndOperation(SessionController controller)
{
this.controller = controller;
}
public OperationResult Perform()
{
controller.ProgressIndicator = ProgressIndicator;
return controller.StartSession();
}
public OperationResult Repeat()
{
controller.ProgressIndicator = ProgressIndicator;
return controller.StartSession();
}
public void Revert()
{
controller.ProgressIndicator = ProgressIndicator;
controller.StopSession();
}
}
}

View file

@ -1,42 +0,0 @@
/*
* Copyright (c) 2018 ETH Zürich, Educational Development and Technology (LET)
*
* 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.Contracts.Behaviour.OperationModel;
using SafeExamBrowser.Contracts.UserInterface;
namespace SafeExamBrowser.Runtime.Behaviour.Operations
{
internal class SessionSequenceStartOperation : IOperation
{
private SessionController controller;
public IProgressIndicator ProgressIndicator { private get; set; }
public SessionSequenceStartOperation(SessionController controller)
{
this.controller = controller;
}
public OperationResult Perform()
{
return OperationResult.Success;
}
public OperationResult Repeat()
{
controller.ProgressIndicator = ProgressIndicator;
return controller.StopSession();
}
public void Revert()
{
// Nothing to do here...
}
}
}

View file

@ -209,18 +209,18 @@ namespace SafeExamBrowser.Runtime.Behaviour
runtimeHost.ShutdownRequested += RuntimeHost_ShutdownRequested; runtimeHost.ShutdownRequested += RuntimeHost_ShutdownRequested;
} }
private void RegisterSessionEvents()
{
configuration.CurrentSession.ClientProcess.Terminated += ClientProcess_Terminated;
configuration.CurrentSession.ClientProxy.ConnectionLost += Client_ConnectionLost;
}
private void DeregisterEvents() private void DeregisterEvents()
{ {
runtimeHost.ReconfigurationRequested -= RuntimeHost_ReconfigurationRequested; runtimeHost.ReconfigurationRequested -= RuntimeHost_ReconfigurationRequested;
runtimeHost.ShutdownRequested -= RuntimeHost_ShutdownRequested; runtimeHost.ShutdownRequested -= RuntimeHost_ShutdownRequested;
} }
private void RegisterSessionEvents()
{
configuration.CurrentSession.ClientProcess.Terminated += ClientProcess_Terminated;
configuration.CurrentSession.ClientProxy.ConnectionLost += Client_ConnectionLost;
}
private void DeregisterSessionEvents() private void DeregisterSessionEvents()
{ {
configuration.CurrentSession.ClientProcess.Terminated -= ClientProcess_Terminated; configuration.CurrentSession.ClientProcess.Terminated -= ClientProcess_Terminated;

View file

@ -54,7 +54,6 @@ namespace SafeExamBrowser.Runtime
var proxyFactory = new ProxyFactory(new ProxyObjectFactory(), logger); var proxyFactory = new ProxyFactory(new ProxyObjectFactory(), logger);
var runtimeHost = new RuntimeHost(runtimeInfo.RuntimeAddress, configuration, new HostObjectFactory(), new ModuleLogger(logger, typeof(RuntimeHost))); var runtimeHost = new RuntimeHost(runtimeInfo.RuntimeAddress, configuration, new HostObjectFactory(), new ModuleLogger(logger, typeof(RuntimeHost)));
var serviceProxy = new ServiceProxy(runtimeInfo.ServiceAddress, new ProxyObjectFactory(), new ModuleLogger(logger, typeof(ServiceProxy))); var serviceProxy = new ServiceProxy(runtimeInfo.ServiceAddress, new ProxyObjectFactory(), new ModuleLogger(logger, typeof(ServiceProxy)));
var sessionController = new SessionController(configuration, logger, processFactory, proxyFactory, runtimeHost, serviceProxy);
var bootstrapOperations = new Queue<IOperation>(); var bootstrapOperations = new Queue<IOperation>();
var sessionOperations = new Queue<IOperation>(); var sessionOperations = new Queue<IOperation>();
@ -62,16 +61,17 @@ namespace SafeExamBrowser.Runtime
bootstrapOperations.Enqueue(new I18nOperation(logger, text)); bootstrapOperations.Enqueue(new I18nOperation(logger, text));
bootstrapOperations.Enqueue(new CommunicationOperation(runtimeHost, logger)); bootstrapOperations.Enqueue(new CommunicationOperation(runtimeHost, logger));
sessionOperations.Enqueue(new SessionSequenceStartOperation(sessionController));
sessionOperations.Enqueue(new ConfigurationOperation(configuration, logger, messageBox, runtimeInfo, text, args)); sessionOperations.Enqueue(new ConfigurationOperation(configuration, logger, messageBox, runtimeInfo, text, args));
sessionOperations.Enqueue(new ServiceConnectionOperation(configuration, logger, serviceProxy, text)); sessionOperations.Enqueue(new SessionInitializationOperation(configuration, logger, runtimeHost));
sessionOperations.Enqueue(new ServiceOperation(configuration, logger, serviceProxy, text));
sessionOperations.Enqueue(new ClientTerminationOperation(configuration, logger, processFactory, proxyFactory, runtimeHost));
sessionOperations.Enqueue(new KioskModeOperation(logger, configuration)); sessionOperations.Enqueue(new KioskModeOperation(logger, configuration));
sessionOperations.Enqueue(new SessionSequenceEndOperation(sessionController)); sessionOperations.Enqueue(new ClientOperation(configuration, logger, processFactory, proxyFactory, runtimeHost));
var boostrapSequence = new OperationSequence(logger, bootstrapOperations); var bootstrapSequence = new OperationSequence(logger, bootstrapOperations);
var sessionSequence = new OperationSequence(logger, sessionOperations); var sessionSequence = new OperationSequence(logger, sessionOperations);
RuntimeController = new RuntimeController(configuration, logger, messageBox, boostrapSequence, sessionSequence, runtimeHost, runtimeInfo, serviceProxy, shutdown, uiFactory); RuntimeController = new RuntimeController(configuration, logger, messageBox, bootstrapSequence, sessionSequence, runtimeHost, runtimeInfo, serviceProxy, shutdown, uiFactory);
} }
internal void LogStartupInformation() internal void LogStartupInformation()

View file

@ -87,12 +87,12 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Compile Include="App.cs" /> <Compile Include="App.cs" />
<Compile Include="Behaviour\Operations\ClientOperation.cs" />
<Compile Include="Behaviour\Operations\ClientTerminationOperation.cs" />
<Compile Include="Behaviour\Operations\ConfigurationOperation.cs" /> <Compile Include="Behaviour\Operations\ConfigurationOperation.cs" />
<Compile Include="Behaviour\Operations\KioskModeOperation.cs" /> <Compile Include="Behaviour\Operations\KioskModeOperation.cs" />
<Compile Include="Behaviour\Operations\ServiceConnectionOperation.cs" /> <Compile Include="Behaviour\Operations\ServiceOperation.cs" />
<Compile Include="Behaviour\Operations\SessionSequenceEndOperation.cs" /> <Compile Include="Behaviour\Operations\SessionInitializationOperation.cs" />
<Compile Include="Behaviour\SessionController.cs" />
<Compile Include="Behaviour\Operations\SessionSequenceStartOperation.cs" />
<Compile Include="Communication\ProxyFactory.cs" /> <Compile Include="Communication\ProxyFactory.cs" />
<Compile Include="Communication\RuntimeHost.cs" /> <Compile Include="Communication\RuntimeHost.cs" />
<Compile Include="CompositionRoot.cs" /> <Compile Include="CompositionRoot.cs" />