SEBWIN-219: Implemented draft of session mechanism.

This commit is contained in:
dbuechel 2018-02-08 13:32:48 +01:00
parent 001c262158
commit 66e9078a4c
21 changed files with 334 additions and 59 deletions

View file

@ -18,6 +18,7 @@ namespace SafeExamBrowser.Configuration
{
private RuntimeInfo runtimeInfo;
public ISessionData CurrentSessionData { get; private set; }
public ISettings CurrentSettings { get; private set; }
public IRuntimeInfo RuntimeInfo
@ -33,6 +34,17 @@ namespace SafeExamBrowser.Configuration
}
}
public ISessionData InitializeSessionData()
{
var sessionData = new SessionData();
sessionData.Id = Guid.NewGuid();
CurrentSessionData = sessionData;
return sessionData;
}
public ISettings LoadSettings(Uri path)
{
// TODO

View file

@ -54,6 +54,7 @@
</ItemGroup>
<ItemGroup>
<Compile Include="RuntimeInfo.cs" />
<Compile Include="SessionData.cs" />
<Compile Include="Settings\BrowserSettings.cs" />
<Compile Include="Settings\KeyboardSettings.cs" />
<Compile Include="Settings\MouseSettings.cs" />

View file

@ -0,0 +1,19 @@
/*
* 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 System;
using SafeExamBrowser.Contracts.Configuration;
namespace SafeExamBrowser.Configuration
{
[Serializable]
public class SessionData : ISessionData
{
public Guid Id { get; set; }
}
}

View file

@ -12,6 +12,14 @@ namespace SafeExamBrowser.Contracts.Communication
{
public interface IClientProxy
{
/// <summary>
/// Tries to connect to the client host.
/// </summary>
bool Connect(Guid token);
/// <summary>
/// Disconnects from the client host.
/// </summary>
void Disconnect();
}
}

View file

@ -6,6 +6,9 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
using System;
using SafeExamBrowser.Contracts.Configuration.Settings;
namespace SafeExamBrowser.Contracts.Communication
{
public interface IServiceProxy
@ -25,5 +28,15 @@ namespace SafeExamBrowser.Contracts.Communication
/// Disconnects from the service host.
/// </summary>
void Disconnect();
/// <summary>
/// Instructs the service to start a new session according to the given parameters.
/// </summary>
void StartSession(Guid sessionId, ISettings settings);
/// <summary>
/// Instructs the service to stop the specified session.
/// </summary>
void StopSession(Guid sessionId);
}
}

View file

@ -13,6 +13,12 @@ namespace SafeExamBrowser.Contracts.Configuration
{
public interface IConfigurationRepository
{
/// <summary>
/// Retrieves the current session data, i.e. the last ones which were initialized. If no session has been initialized yet, this
/// property will be <c>null</c>!
/// </summary>
ISessionData CurrentSessionData { get; }
/// <summary>
/// Retrieves the current settings, i.e. the last ones which were loaded. If no settings have been loaded yet, this property will
/// be <c>null</c>!
@ -24,6 +30,11 @@ namespace SafeExamBrowser.Contracts.Configuration
/// </summary>
IRuntimeInfo RuntimeInfo { get; }
/// <summary>
/// Initializes all relevant data for a new session.
/// </summary>
ISessionData InitializeSessionData();
/// <summary>
/// Attempts to load settings from the specified path.
/// </summary>

View file

@ -0,0 +1,20 @@
/*
* 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 System;
namespace SafeExamBrowser.Contracts.Configuration
{
public interface ISessionData
{
/// <summary>
/// The unique session identifier.
/// </summary>
Guid Id { get; }
}
}

View file

@ -45,19 +45,19 @@ namespace SafeExamBrowser.Contracts.I18n
ProgressIndicator_StartEventHandling,
ProgressIndicator_StartKeyboardInterception,
ProgressIndicator_StartMouseInterception,
ProgressIndicator_StartSession,
ProgressIndicator_StopCommunicationHost,
ProgressIndicator_StopEventHandling,
ProgressIndicator_StopKeyboardInterception,
ProgressIndicator_StopMouseInterception,
ProgressIndicator_StopProcessMonitoring,
ProgressIndicator_StopSession,
ProgressIndicator_StopWindowMonitoring,
ProgressIndicator_TerminateBrowser,
ProgressIndicator_TerminateTaskbar,
ProgressIndicator_WaitExplorerStartup,
ProgressIndicator_WaitExplorerTermination,
RuntimeWindow_ApplicationRunning,
RuntimeWindow_StartSession,
RuntimeWindow_StopSession,
SystemControl_BatteryCharged,
SystemControl_BatteryCharging,
SystemControl_BatteryChargeCriticalWarning,

View file

@ -66,6 +66,7 @@
<Compile Include="Communication\Responses\IResponse.cs" />
<Compile Include="Communication\Responses\IConnectResponse.cs" />
<Compile Include="Configuration\IRuntimeInfo.cs" />
<Compile Include="Configuration\ISessionData.cs" />
<Compile Include="Configuration\Settings\ConfigurationMode.cs" />
<Compile Include="Behaviour\INotificationController.cs" />
<Compile Include="Behaviour\Operations\IOperation.cs" />

View file

@ -33,9 +33,38 @@ namespace SafeExamBrowser.Core.Communication
this.logger = logger;
}
public abstract IConnectResponse Connect(Guid? token = null);
public abstract void Disconnect(IMessage message);
public abstract IResponse Send(IMessage message);
protected abstract IConnectResponse OnConnect(Guid? token);
protected abstract void OnDisconnect(IMessage message);
protected abstract IResponse OnReceive(IMessage message);
public IConnectResponse Connect(Guid? token = null)
{
logger.Debug($"Received connection request with token '{token}'.");
var response = OnConnect(token);
logger.Debug($"{(response.ConnectionEstablished ? "Accepted" : "Denied")} connection request.");
return response;
}
public void Disconnect(IMessage message)
{
logger.Debug($"Received disconnection request with message '{message}'.");
OnDisconnect(message);
}
public IResponse Send(IMessage message)
{
logger.Debug($"Received message '{message}'.");
var response = OnReceive(message);
logger.Debug($"Sending response '{response}'.");
return response;
}
public void Start()
{

View file

@ -6,7 +6,9 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
using System;
using SafeExamBrowser.Contracts.Communication;
using SafeExamBrowser.Contracts.Configuration.Settings;
using SafeExamBrowser.Contracts.Logging;
using SafeExamBrowser.Core.Communication.Messages;
@ -22,22 +24,48 @@ namespace SafeExamBrowser.Core.Communication
public bool Connect()
{
if (!IgnoreOperation(nameof(Connect)))
if (IgnoreOperation(nameof(Connect)))
{
return base.Connect().ConnectionEstablished;
return false;
}
return false;
return base.Connect().ConnectionEstablished;
}
public void Disconnect()
{
if (!IgnoreOperation(nameof(Disconnect)))
if (IgnoreOperation(nameof(Disconnect)))
{
FailIfNotConnected(nameof(Disconnect));
Disconnect(new Message { CommunicationToken = CommunicationToken.Value });
return;
}
FailIfNotConnected(nameof(Disconnect));
Disconnect(new Message { CommunicationToken = CommunicationToken.Value });
}
public void StartSession(Guid sessionId, ISettings settings)
{
if (IgnoreOperation(nameof(StartSession)))
{
return;
}
FailIfNotConnected(nameof(StartSession));
// TODO: Send(new StartSessionMessage { Id = sessionId, Settings = settings });
}
public void StopSession(Guid sessionId)
{
if (IgnoreOperation(nameof(StopSession)))
{
return;
}
FailIfNotConnected(nameof(StopSession));
// TODO
}
private bool IgnoreOperation(string operationName)

View file

@ -90,6 +90,9 @@
<Entry key="ProgressIndicator_StartMouseInterception">
Starting mouse interception
</Entry>
<Entry key="ProgressIndicator_StartSession">
Starting new session
</Entry>
<Entry key="ProgressIndicator_StopCommunicationHost">
Stopping communication host
</Entry>
@ -105,6 +108,9 @@
<Entry key="ProgressIndicator_StopProcessMonitoring">
Stopping process monitoring
</Entry>
<Entry key="ProgressIndicator_StopSession">
Stopping current session
</Entry>
<Entry key="ProgressIndicator_StopWindowMonitoring">
Stopping window monitoring
</Entry>
@ -123,12 +129,6 @@
<Entry key="RuntimeWindow_ApplicationRunning">
The application is running.
</Entry>
<Entry key="RuntimeWindow_StartSession">
Starting new session
</Entry>
<Entry key="RuntimeWindow_StopSession">
Stopping current session
</Entry>
<Entry key="SystemControl_BatteryCharging">
Plugged in, charging... (%%CHARGE%%%)
</Entry>

View file

@ -74,6 +74,7 @@ namespace SafeExamBrowser.Runtime.Behaviour.Operations
public void Repeat()
{
// TODO: How will the new settings be retrieved? Uri passed to the repository? If yes, how does the Uri get here?!
// -> IDEA: Use configuration repository as container?
}
public void Revert()

View file

@ -0,0 +1,36 @@
/*
* 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.Communication;
using SafeExamBrowser.Contracts.Configuration;
using SafeExamBrowser.Contracts.Logging;
namespace SafeExamBrowser.Runtime.Behaviour.Operations
{
internal class SessionSequenceEndOperation : SessionSequenceOperation
{
public SessionSequenceEndOperation(IConfigurationRepository configuration, ILogger logger, IServiceProxy serviceProxy) : base(configuration, logger, serviceProxy)
{
}
public override void Perform()
{
StartSession();
}
public override void Repeat()
{
StartSession();
}
public override void Revert()
{
StopSession();
}
}
}

View file

@ -0,0 +1,76 @@
/*
* 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.Operations;
using SafeExamBrowser.Contracts.Communication;
using SafeExamBrowser.Contracts.Configuration;
using SafeExamBrowser.Contracts.I18n;
using SafeExamBrowser.Contracts.Logging;
using SafeExamBrowser.Contracts.UserInterface;
namespace SafeExamBrowser.Runtime.Behaviour.Operations
{
internal abstract class SessionSequenceOperation : IOperation
{
private bool sessionInitialized;
private IConfigurationRepository configuration;
private ILogger logger;
private IServiceProxy serviceProxy;
private ISessionData sessionData;
public bool Abort { get; private set; }
public IProgressIndicator ProgressIndicator { private get; set; }
public SessionSequenceOperation(IConfigurationRepository configuration, ILogger logger, IServiceProxy serviceProxy)
{
this.configuration = configuration;
this.logger = logger;
this.serviceProxy = serviceProxy;
}
public abstract void Perform();
public abstract void Repeat();
public abstract void Revert();
protected void StartSession()
{
logger.Info("Starting new session...");
ProgressIndicator?.UpdateText(TextKey.ProgressIndicator_StartSession, true);
sessionData = configuration.InitializeSessionData();
serviceProxy.StartSession(sessionData.Id, configuration.CurrentSettings);
// TODO:
// - Create and connect to client
// - Verify session integrity and start event handling -> in runtime controller?
System.Threading.Thread.Sleep(5000);
sessionInitialized = true;
logger.Info($"Successfully started new session with identifier '{sessionData.Id}'.");
}
protected void StopSession()
{
if (sessionInitialized)
{
logger.Info($"Stopping session with identifier '{sessionData.Id}'...");
ProgressIndicator?.UpdateText(TextKey.ProgressIndicator_StopSession, true);
serviceProxy.StopSession(sessionData.Id);
// TODO:
// - Terminate client (or does it terminate itself?)
// - Stop event handling and verify session termination -> in runtime controller?
System.Threading.Thread.Sleep(5000);
sessionInitialized = false;
logger.Info($"Successfully stopped session with identifier '{sessionData.Id}'.");
}
}
}
}

View file

@ -0,0 +1,36 @@
/*
* 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.Communication;
using SafeExamBrowser.Contracts.Configuration;
using SafeExamBrowser.Contracts.Logging;
namespace SafeExamBrowser.Runtime.Behaviour.Operations
{
internal class SessionSequenceStartOperation : SessionSequenceOperation
{
public SessionSequenceStartOperation(IConfigurationRepository configuration, ILogger logger, IServiceProxy serviceProxy) : base(configuration, logger, serviceProxy)
{
}
public override void Perform()
{
// Nothing to do here...
}
public override void Repeat()
{
StopSession();
}
public override void Revert()
{
// Nothing to do here...
}
}
}

View file

@ -20,7 +20,7 @@ namespace SafeExamBrowser.Runtime.Behaviour
{
internal class RuntimeController : IRuntimeController
{
private bool initialized;
private bool sessionRunning;
private IConfigurationRepository configuration;
private ILogger logger;
@ -68,7 +68,7 @@ namespace SafeExamBrowser.Runtime.Behaviour
splashScreen.Show();
initialized = bootstrapSequence.TryPerform();
var initialized = bootstrapSequence.TryPerform();
if (initialized)
{
@ -86,20 +86,16 @@ namespace SafeExamBrowser.Runtime.Behaviour
logger.Log(string.Empty);
}
return initialized;
return initialized && sessionRunning;
}
public void Terminate()
{
// TODO: Necessary here? Move to App.cs as private "started" flag if not...
if (!initialized)
if (sessionRunning)
{
return;
StopSession();
}
// TODO: Only if session is running!
StopSession();
logger.Unsubscribe(runtimeWindow);
runtimeWindow?.Close();
splashScreen?.Show();
@ -129,23 +125,12 @@ namespace SafeExamBrowser.Runtime.Behaviour
private void StartSession(bool initial = false)
{
logger.Info("Starting new session...");
runtimeWindow.UpdateText(TextKey.RuntimeWindow_StartSession, true);
runtimeWindow.Show();
var success = initial ? sessionSequence.TryPerform() : sessionSequence.TryRepeat();
sessionRunning = initial ? sessionSequence.TryPerform() : sessionSequence.TryRepeat();
if (success)
if (sessionRunning)
{
// TODO:
// - Initialize session data
// - Create and connect to client
// - Initialize session with service
// - Verify session integrity and start event handling
runtimeWindow.HideProgressBar();
runtimeWindow.UpdateText(TextKey.RuntimeWindow_ApplicationRunning);
@ -157,34 +142,27 @@ namespace SafeExamBrowser.Runtime.Behaviour
else
{
uiFactory.Show(TextKey.MessageBox_SessionStartError, TextKey.MessageBox_SessionStartErrorTitle, icon: MessageBoxIcon.Error);
logger.Info($"Failed to start new session. Terminating application...");
if (initial)
if (!initial)
{
initialized = false;
}
else
{
shutdown();
shutdown.Invoke();
}
}
}
private void StopSession()
{
logger.Info("Stopping current session...");
runtimeWindow.Show();
runtimeWindow.BringToForeground();
runtimeWindow.ShowProgressBar();
runtimeWindow.UpdateText(TextKey.RuntimeWindow_StopSession, true);
// TODO:
// - Terminate client (or does it terminate itself?)
// - Finalize session with service
// - Stop event handling and close session
var success = sessionSequence.TryRevert();
if (success)
{
sessionRunning = false;
// TODO
}
else

View file

@ -21,19 +21,19 @@ namespace SafeExamBrowser.Runtime.Communication
{
}
public override IConnectResponse Connect(Guid? token = null)
protected override IConnectResponse OnConnect(Guid? token = null)
{
// TODO
throw new NotImplementedException();
}
public override void Disconnect(IMessage message)
protected override void OnDisconnect(IMessage message)
{
// TODO
throw new NotImplementedException();
}
public override IResponse Send(IMessage message)
protected override IResponse OnReceive(IMessage message)
{
// TODO
throw new NotImplementedException();

View file

@ -37,10 +37,8 @@ namespace SafeExamBrowser.Runtime
internal void BuildObjectGraph()
{
var args = Environment.GetCommandLineArgs();
var bootstrapOperations = new Queue<IOperation>();
var sessionOperations = new Queue<IOperation>();
var nativeMethods = new NativeMethods();
var configuration = new ConfigurationRepository();
var nativeMethods = new NativeMethods();
logger = new Logger();
runtimeInfo = configuration.RuntimeInfo;
@ -53,12 +51,17 @@ namespace SafeExamBrowser.Runtime
var runtimeHost = new RuntimeHost(runtimeInfo.RuntimeAddress, new ModuleLogger(logger, typeof(RuntimeHost)));
var serviceProxy = new ServiceProxy(runtimeInfo.ServiceAddress, new ModuleLogger(logger, typeof(ServiceProxy)));
var bootstrapOperations = new Queue<IOperation>();
var sessionOperations = new Queue<IOperation>();
bootstrapOperations.Enqueue(new I18nOperation(logger, text));
bootstrapOperations.Enqueue(new CommunicationOperation(runtimeHost, logger));
sessionOperations.Enqueue(new SessionSequenceStartOperation(configuration, logger, serviceProxy));
sessionOperations.Enqueue(new ConfigurationOperation(configuration, logger, runtimeInfo, text, uiFactory, args));
sessionOperations.Enqueue(new ServiceOperation(configuration, logger, serviceProxy, text));
sessionOperations.Enqueue(new KioskModeOperation(logger, configuration));
sessionOperations.Enqueue(new SessionSequenceEndOperation(configuration, logger, serviceProxy));
var boostrapSequence = new OperationSequence(logger, bootstrapOperations);
var sessionSequence = new OperationSequence(logger, sessionOperations);

View file

@ -90,6 +90,9 @@
<Compile Include="Behaviour\Operations\ConfigurationOperation.cs" />
<Compile Include="Behaviour\Operations\KioskModeOperation.cs" />
<Compile Include="Behaviour\Operations\ServiceOperation.cs" />
<Compile Include="Behaviour\Operations\SessionSequenceEndOperation.cs" />
<Compile Include="Behaviour\Operations\SessionSequenceOperation.cs" />
<Compile Include="Behaviour\Operations\SessionSequenceStartOperation.cs" />
<Compile Include="Communication\RuntimeHost.cs" />
<Compile Include="CompositionRoot.cs" />
<Compile Include="Properties\AssemblyInfo.cs">

View file

@ -52,7 +52,7 @@
<s:Double x:Key="{x:Static SystemParameters.HorizontalScrollBarHeightKey}">5</s:Double>
<s:Double x:Key="{x:Static SystemParameters.VerticalScrollBarWidthKey}">5</s:Double>
</ScrollViewer.Resources>
<TextBox x:Name="LogTextBlock" Background="Transparent" BorderThickness="0" FontFamily="Courier New" Foreground="Black" IsReadOnly="True" />
<TextBox x:Name="LogTextBlock" Background="Transparent" BorderThickness="0" FontFamily="Courier New" FontSize="10" Foreground="Black" IsReadOnly="True" />
</ScrollViewer>
</Border>
</Grid>