SEBWIN-219: Finished basic implementation of reconfiguration mechanism.
This commit is contained in:
parent
5bd1d9dea4
commit
993329bd71
27 changed files with 259 additions and 98 deletions
|
@ -13,8 +13,10 @@ using System.Linq;
|
|||
using CefSharp;
|
||||
using SafeExamBrowser.Browser.Handlers;
|
||||
using SafeExamBrowser.Contracts.Behaviour;
|
||||
using SafeExamBrowser.Contracts.Communication;
|
||||
using SafeExamBrowser.Contracts.Configuration;
|
||||
using SafeExamBrowser.Contracts.I18n;
|
||||
using SafeExamBrowser.Contracts.Logging;
|
||||
using SafeExamBrowser.Contracts.UserInterface;
|
||||
using SafeExamBrowser.Contracts.UserInterface.Taskbar;
|
||||
using BrowserSettings = SafeExamBrowser.Contracts.Configuration.Settings.BrowserSettings;
|
||||
|
@ -26,6 +28,8 @@ namespace SafeExamBrowser.Browser
|
|||
private IApplicationButton button;
|
||||
private IList<IApplicationInstance> instances = new List<IApplicationInstance>();
|
||||
private BrowserSettings settings;
|
||||
private ILogger logger;
|
||||
private IRuntimeProxy runtime;
|
||||
private RuntimeInfo runtimeInfo;
|
||||
private IUserInterfaceFactory uiFactory;
|
||||
private IText text;
|
||||
|
@ -33,9 +37,13 @@ namespace SafeExamBrowser.Browser
|
|||
public BrowserApplicationController(
|
||||
BrowserSettings settings,
|
||||
RuntimeInfo runtimeInfo,
|
||||
ILogger logger,
|
||||
IRuntimeProxy runtime,
|
||||
IText text,
|
||||
IUserInterfaceFactory uiFactory)
|
||||
{
|
||||
this.logger = logger;
|
||||
this.runtime = runtime;
|
||||
this.runtimeInfo = runtimeInfo;
|
||||
this.settings = settings;
|
||||
this.text = text;
|
||||
|
@ -112,15 +120,32 @@ namespace SafeExamBrowser.Browser
|
|||
|
||||
private void Instance_ConfigurationDetected(string url, CancelEventArgs args)
|
||||
{
|
||||
// TODO:
|
||||
// 1. Ask whether reconfiguration should be attempted
|
||||
// 2. Contact runtime and ask whether configuration valid and reconfiguration allowed
|
||||
// - If yes, do nothing and wait for shutdown command
|
||||
// - If no, show message box and NAVIGATE TO PREVIOUS PAGE -> but how?
|
||||
var result = uiFactory.Show(TextKey.MessageBox_ReconfigurationQuestion, TextKey.MessageBox_ReconfigurationQuestionTitle, MessageBoxAction.YesNo, MessageBoxIcon.Question);
|
||||
var reconfigure = result == MessageBoxResult.Yes;
|
||||
var allowed = false;
|
||||
|
||||
var result = uiFactory.Show(TextKey.MessageBox_ReconfigureQuestion, TextKey.MessageBox_ReconfigureQuestionTitle, MessageBoxAction.YesNo, MessageBoxIcon.Question);
|
||||
logger.Info($"Detected configuration request for '{url}'. The user chose to {(reconfigure ? "start" : "abort")} the reconfiguration.");
|
||||
|
||||
args.Cancel = result == MessageBoxResult.No;
|
||||
if (reconfigure)
|
||||
{
|
||||
try
|
||||
{
|
||||
allowed = runtime.RequestReconfiguration(url);
|
||||
logger.Info($"The runtime {(allowed ? "accepted" : "denied")} the reconfiguration request.");
|
||||
|
||||
if (!allowed)
|
||||
{
|
||||
uiFactory.Show(TextKey.MessageBox_ReconfigurationDenied, TextKey.MessageBox_ReconfigurationDeniedTitle);
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
logger.Error("Failed to communicate the reconfiguration request to the runtime!", e);
|
||||
uiFactory.Show(TextKey.MessageBox_ReconfigurationError, TextKey.MessageBox_ReconfigurationErrorTitle, icon: MessageBoxIcon.Error);
|
||||
}
|
||||
}
|
||||
|
||||
args.Cancel = !allowed;
|
||||
}
|
||||
|
||||
private void Instance_Terminated(Guid id)
|
||||
|
|
|
@ -17,7 +17,7 @@ namespace SafeExamBrowser.Browser.Handlers
|
|||
{
|
||||
public IResourceHandler Create(IBrowser browser, IFrame frame, string schemeName, IRequest request)
|
||||
{
|
||||
var page = "<html><body style=\"height: 90%; display: flex; align-items: center; justify-content: center\"><progress /></body></html>";
|
||||
var page = @"<html><body style=""height: 90%; display: flex; align-items: center; justify-content: center""><progress /></body></html>";
|
||||
var handler = ResourceHandler.FromString(page);
|
||||
|
||||
return handler;
|
||||
|
|
|
@ -48,6 +48,7 @@ namespace SafeExamBrowser.Client
|
|||
private IClientHost clientHost;
|
||||
private ILogger logger;
|
||||
private INativeMethods nativeMethods;
|
||||
private IRuntimeProxy runtimeProxy;
|
||||
private ISystemInfo systemInfo;
|
||||
private IText text;
|
||||
private IUserInterfaceFactory uiFactory;
|
||||
|
@ -68,8 +69,8 @@ namespace SafeExamBrowser.Client
|
|||
|
||||
text = new Text(logger);
|
||||
uiFactory = new UserInterfaceFactory(text);
|
||||
runtimeProxy = new RuntimeProxy(runtimeHostUri, new ModuleLogger(logger, typeof(RuntimeProxy)));
|
||||
|
||||
var runtimeProxy = new RuntimeProxy(runtimeHostUri, new ModuleLogger(logger, typeof(RuntimeProxy)));
|
||||
var displayMonitor = new DisplayMonitor(new ModuleLogger(logger, typeof(DisplayMonitor)), nativeMethods);
|
||||
var processMonitor = new ProcessMonitor(new ModuleLogger(logger, typeof(ProcessMonitor)), nativeMethods);
|
||||
var windowMonitor = new WindowMonitor(new ModuleLogger(logger, typeof(WindowMonitor)), nativeMethods);
|
||||
|
@ -143,7 +144,8 @@ namespace SafeExamBrowser.Client
|
|||
|
||||
private IOperation BuildBrowserOperation()
|
||||
{
|
||||
var browserController = new BrowserApplicationController(configuration.Settings.Browser, configuration.RuntimeInfo, text, uiFactory);
|
||||
var moduleLogger = new ModuleLogger(logger, typeof(BrowserApplicationController));
|
||||
var browserController = new BrowserApplicationController(configuration.Settings.Browser, configuration.RuntimeInfo, moduleLogger, runtimeProxy, text, uiFactory);
|
||||
var browserInfo = new BrowserApplicationInfo();
|
||||
var operation = new BrowserOperation(browserController, browserInfo, logger, Taskbar, uiFactory);
|
||||
|
||||
|
|
|
@ -18,8 +18,9 @@ namespace SafeExamBrowser.Configuration
|
|||
{
|
||||
private RuntimeInfo runtimeInfo;
|
||||
|
||||
public ISession CurrentSession { get; private set; }
|
||||
public ISessionData CurrentSession { get; private set; }
|
||||
public Settings CurrentSettings { get; private set; }
|
||||
public string ReconfigurationUrl { get; set; }
|
||||
|
||||
public RuntimeInfo RuntimeInfo
|
||||
{
|
||||
|
@ -34,9 +35,9 @@ namespace SafeExamBrowser.Configuration
|
|||
}
|
||||
}
|
||||
|
||||
public ISession InitializeSession()
|
||||
public ISessionData InitializeSessionData()
|
||||
{
|
||||
var session = new Session
|
||||
var session = new SessionData
|
||||
{
|
||||
Id = Guid.NewGuid(),
|
||||
StartupToken = Guid.NewGuid()
|
||||
|
|
|
@ -53,7 +53,7 @@
|
|||
<Reference Include="Microsoft.CSharp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="Session.cs" />
|
||||
<Compile Include="SessionData.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
<Compile Include="ConfigurationRepository.cs" />
|
||||
<Compile Include="SystemInfo.cs" />
|
||||
|
|
|
@ -12,7 +12,7 @@ using SafeExamBrowser.Contracts.WindowsApi;
|
|||
|
||||
namespace SafeExamBrowser.Configuration
|
||||
{
|
||||
public class Session : ISession
|
||||
public class SessionData : ISessionData
|
||||
{
|
||||
public IProcess ClientProcess { get; set; }
|
||||
public Guid Id { get; set; }
|
|
@ -18,10 +18,12 @@ namespace SafeExamBrowser.Contracts.Communication
|
|||
/// Defines the API for all communication between the three application components (runtime, service and client).
|
||||
/// </summary>
|
||||
[ServiceContract(SessionMode = SessionMode.Required)]
|
||||
[ServiceKnownType(typeof(SimpleMessage))]
|
||||
[ServiceKnownType(typeof(AuthenticationResponse))]
|
||||
[ServiceKnownType(typeof(ConfigurationResponse))]
|
||||
[ServiceKnownType(typeof(ClientConfiguration))]
|
||||
[ServiceKnownType(typeof(ConfigurationResponse))]
|
||||
[ServiceKnownType(typeof(ReconfigurationMessage))]
|
||||
[ServiceKnownType(typeof(ReconfigurationResponse))]
|
||||
[ServiceKnownType(typeof(SimpleMessage))]
|
||||
[ServiceKnownType(typeof(SimpleResponse))]
|
||||
public interface ICommunication
|
||||
{
|
||||
|
|
|
@ -30,6 +30,11 @@ namespace SafeExamBrowser.Contracts.Communication
|
|||
/// </summary>
|
||||
event CommunicationEventHandler ClientReady;
|
||||
|
||||
/// <summary>
|
||||
/// Event fired when the client detected a reconfiguration request.
|
||||
/// </summary>
|
||||
event CommunicationEventHandler ReconfigurationRequested;
|
||||
|
||||
/// <summary>
|
||||
/// Event fired when the client requests to shut down the application.
|
||||
/// </summary>
|
||||
|
|
|
@ -32,5 +32,12 @@ namespace SafeExamBrowser.Contracts.Communication
|
|||
/// </summary>
|
||||
/// <exception cref="System.ServiceModel.*">If the communication failed.</exception>
|
||||
void RequestShutdown();
|
||||
|
||||
/// <summary>
|
||||
/// Requests the runtime to reconfigure the application with the configuration from the given location. Returns <c>true</c> if
|
||||
/// the runtime accepted the request, otherwise <c>false</c>.
|
||||
/// </summary>
|
||||
/// <exception cref="System.ServiceModel.*">If the communication failed.</exception>
|
||||
bool RequestReconfiguration(string url);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,29 @@
|
|||
/*
|
||||
* 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.Communication.Messages
|
||||
{
|
||||
/// <summary>
|
||||
/// This message is transmitted to the runtime to request that the application be reconfigured.
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
public class ReconfigurationMessage : Message
|
||||
{
|
||||
/// <summary>
|
||||
/// The locator of the new configuration to be used.
|
||||
/// </summary>
|
||||
public string ConfigurationUrl { get; private set; }
|
||||
|
||||
public ReconfigurationMessage(string url)
|
||||
{
|
||||
ConfigurationUrl = url;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,24 @@
|
|||
/*
|
||||
* 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.Communication.Responses
|
||||
{
|
||||
/// <summary>
|
||||
/// The response to a <see cref="Messages.ReconfigurationMessage"/>.
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
public class ReconfigurationResponse : Response
|
||||
{
|
||||
/// <summary>
|
||||
/// Indicates whether the reconfiguration request has been accepted.
|
||||
/// </summary>
|
||||
public bool Accepted { get; set; }
|
||||
}
|
||||
}
|
|
@ -16,10 +16,10 @@ namespace SafeExamBrowser.Contracts.Configuration
|
|||
public interface IConfigurationRepository
|
||||
{
|
||||
/// <summary>
|
||||
/// Retrieves the current session, i.e. the last one which was initialized. If no session has been initialized yet, this
|
||||
/// Retrieves the current session data, i.e. the last one which was initialized. If no session has been initialized yet, this
|
||||
/// property will be <c>null</c>!
|
||||
/// </summary>
|
||||
ISession CurrentSession { get; }
|
||||
ISessionData CurrentSession { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Retrieves the current settings, i.e. the last ones which were loaded. If no settings have been loaded yet, this property will
|
||||
|
@ -27,6 +27,11 @@ namespace SafeExamBrowser.Contracts.Configuration
|
|||
/// </summary>
|
||||
Settings.Settings CurrentSettings { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The locator of the configuration to be used when reconfiguring the application.
|
||||
/// </summary>
|
||||
string ReconfigurationUrl { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The runtime information for the currently running application instance.
|
||||
/// </summary>
|
||||
|
@ -40,7 +45,7 @@ namespace SafeExamBrowser.Contracts.Configuration
|
|||
/// <summary>
|
||||
/// Initializes all relevant data for a new session.
|
||||
/// </summary>
|
||||
ISession InitializeSession();
|
||||
ISessionData InitializeSessionData();
|
||||
|
||||
/// <summary>
|
||||
/// Attempts to load settings from the specified path.
|
||||
|
|
|
@ -14,7 +14,7 @@ namespace SafeExamBrowser.Contracts.Configuration
|
|||
/// <summary>
|
||||
/// Defines all session-related (configuration) data.
|
||||
/// </summary>
|
||||
public interface ISession
|
||||
public interface ISessionData
|
||||
{
|
||||
/// <summary>
|
||||
/// The process information of the client instance associated to this session.
|
|
@ -18,14 +18,18 @@ namespace SafeExamBrowser.Contracts.I18n
|
|||
LogWindow_Title,
|
||||
MessageBox_ApplicationError,
|
||||
MessageBox_ApplicationErrorTitle,
|
||||
MessageBox_ConfigureClientSuccess,
|
||||
MessageBox_ConfigureClientSuccessTitle,
|
||||
MessageBox_ClientConfigurationQuestion,
|
||||
MessageBox_ClientConfigurationQuestionTitle,
|
||||
MessageBox_Quit,
|
||||
MessageBox_QuitTitle,
|
||||
MessageBox_QuitError,
|
||||
MessageBox_QuitErrorTitle,
|
||||
MessageBox_ReconfigureQuestion,
|
||||
MessageBox_ReconfigureQuestionTitle,
|
||||
MessageBox_ReconfigurationDenied,
|
||||
MessageBox_ReconfigurationDeniedTitle,
|
||||
MessageBox_ReconfigurationError,
|
||||
MessageBox_ReconfigurationErrorTitle,
|
||||
MessageBox_ReconfigurationQuestion,
|
||||
MessageBox_ReconfigurationQuestionTitle,
|
||||
MessageBox_SessionStartError,
|
||||
MessageBox_SessionStartErrorTitle,
|
||||
MessageBox_SessionStopError,
|
||||
|
|
|
@ -67,18 +67,20 @@
|
|||
<Compile Include="Communication\IServiceProxy.cs" />
|
||||
<Compile Include="Communication\Messages\Message.cs" />
|
||||
<Compile Include="Communication\Messages\DisconnectionMessage.cs" />
|
||||
<Compile Include="Communication\Messages\ReconfigurationMessage.cs" />
|
||||
<Compile Include="Communication\Messages\SimpleMessagePurport.cs" />
|
||||
<Compile Include="Communication\Messages\SimpleMessage.cs" />
|
||||
<Compile Include="Communication\Responses\AuthenticationResponse.cs" />
|
||||
<Compile Include="Communication\Responses\ConfigurationResponse.cs" />
|
||||
<Compile Include="Communication\Responses\ConnectionResponse.cs" />
|
||||
<Compile Include="Communication\Responses\DisconnectionResponse.cs" />
|
||||
<Compile Include="Communication\Responses\ReconfigurationResponse.cs" />
|
||||
<Compile Include="Communication\Responses\Response.cs" />
|
||||
<Compile Include="Communication\Responses\SimpleResponsePurport.cs" />
|
||||
<Compile Include="Communication\Responses\SimpleResponse.cs" />
|
||||
<Compile Include="Configuration\ClientConfiguration.cs" />
|
||||
<Compile Include="Configuration\RuntimeInfo.cs" />
|
||||
<Compile Include="Configuration\ISession.cs" />
|
||||
<Compile Include="Configuration\ISessionData.cs" />
|
||||
<Compile Include="Configuration\Settings\ConfigurationMode.cs" />
|
||||
<Compile Include="Behaviour\INotificationController.cs" />
|
||||
<Compile Include="Behaviour\OperationModel\IOperation.cs" />
|
||||
|
|
|
@ -26,7 +26,6 @@ namespace SafeExamBrowser.Core.Communication
|
|||
private readonly object @lock = new object();
|
||||
|
||||
private string address;
|
||||
private ILogger logger;
|
||||
private ServiceHost host;
|
||||
private Thread hostThread;
|
||||
|
||||
|
@ -47,7 +46,7 @@ namespace SafeExamBrowser.Core.Communication
|
|||
public BaseHost(string address, ILogger logger)
|
||||
{
|
||||
this.address = address;
|
||||
this.logger = logger;
|
||||
this.Logger = logger;
|
||||
}
|
||||
|
||||
protected abstract bool OnConnect(Guid? token);
|
||||
|
@ -59,7 +58,7 @@ namespace SafeExamBrowser.Core.Communication
|
|||
{
|
||||
lock (@lock)
|
||||
{
|
||||
logger.Debug($"Received connection request with authentication token '{token}'.");
|
||||
Logger.Debug($"Received connection request with authentication token '{token}'.");
|
||||
|
||||
var response = new ConnectionResponse();
|
||||
var connected = OnConnect(token);
|
||||
|
@ -70,7 +69,7 @@ namespace SafeExamBrowser.Core.Communication
|
|||
response.ConnectionEstablished = true;
|
||||
}
|
||||
|
||||
logger.Debug($"{(connected ? "Accepted" : "Denied")} connection request.");
|
||||
Logger.Debug($"{(connected ? "Accepted" : "Denied")} connection request.");
|
||||
|
||||
return response;
|
||||
}
|
||||
|
@ -82,7 +81,7 @@ namespace SafeExamBrowser.Core.Communication
|
|||
{
|
||||
var response = new DisconnectionResponse();
|
||||
|
||||
logger.Debug($"Received disconnection request with message '{ToString(message)}'.");
|
||||
Logger.Debug($"Received disconnection request with message '{ToString(message)}'.");
|
||||
|
||||
if (IsAuthorized(message?.CommunicationToken))
|
||||
{
|
||||
|
@ -118,7 +117,7 @@ namespace SafeExamBrowser.Core.Communication
|
|||
}
|
||||
}
|
||||
|
||||
logger.Debug($"Received message '{ToString(message)}', sending response '{ToString(response)}'.");
|
||||
Logger.Debug($"Received message '{ToString(message)}', sending response '{ToString(response)}'.");
|
||||
|
||||
return response;
|
||||
}
|
||||
|
@ -153,7 +152,7 @@ namespace SafeExamBrowser.Core.Communication
|
|||
|
||||
if (success)
|
||||
{
|
||||
logger.Debug($"Terminated communication host for endpoint '{address}'.");
|
||||
Logger.Debug($"Terminated communication host for endpoint '{address}'.");
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -183,7 +182,7 @@ namespace SafeExamBrowser.Core.Communication
|
|||
host.UnknownMessageReceived += Host_UnknownMessageReceived;
|
||||
host.Open();
|
||||
|
||||
logger.Debug($"Successfully started communication host for endpoint '{address}'.");
|
||||
Logger.Debug($"Successfully started communication host for endpoint '{address}'.");
|
||||
|
||||
startedEvent.Set();
|
||||
}
|
||||
|
@ -215,32 +214,32 @@ namespace SafeExamBrowser.Core.Communication
|
|||
|
||||
private void Host_Closed(object sender, EventArgs e)
|
||||
{
|
||||
logger.Debug("Communication host has been closed.");
|
||||
Logger.Debug("Communication host has been closed.");
|
||||
}
|
||||
|
||||
private void Host_Closing(object sender, EventArgs e)
|
||||
{
|
||||
logger.Debug("Communication host is closing...");
|
||||
Logger.Debug("Communication host is closing...");
|
||||
}
|
||||
|
||||
private void Host_Faulted(object sender, EventArgs e)
|
||||
{
|
||||
logger.Error("Communication host has faulted!");
|
||||
Logger.Error("Communication host has faulted!");
|
||||
}
|
||||
|
||||
private void Host_Opened(object sender, EventArgs e)
|
||||
{
|
||||
logger.Debug("Communication host has been opened.");
|
||||
Logger.Debug("Communication host has been opened.");
|
||||
}
|
||||
|
||||
private void Host_Opening(object sender, EventArgs e)
|
||||
{
|
||||
logger.Debug("Communication host is opening...");
|
||||
Logger.Debug("Communication host is opening...");
|
||||
}
|
||||
|
||||
private void Host_UnknownMessageReceived(object sender, UnknownMessageReceivedEventArgs e)
|
||||
{
|
||||
logger.Warn($"Communication host has received an unknown message: {e?.Message}.");
|
||||
Logger.Warn($"Communication host has received an unknown message: {e?.Message}.");
|
||||
}
|
||||
|
||||
private string ToString(Message message)
|
||||
|
|
|
@ -51,7 +51,7 @@ namespace SafeExamBrowser.Core.Communication
|
|||
(channel as ICommunicationObject).Opened += BaseProxy_Opened;
|
||||
(channel as ICommunicationObject).Opening += BaseProxy_Opening;
|
||||
|
||||
Logger.Debug($"Trying to connect to endpoint {address}{(token.HasValue ? $" with authentication token '{token}'" : string.Empty)}...");
|
||||
Logger.Debug($"Trying to connect to endpoint '{address}'{(token.HasValue ? $" with authentication token '{token}'" : string.Empty)}...");
|
||||
|
||||
var response = channel.Connect(token);
|
||||
|
||||
|
@ -125,7 +125,6 @@ namespace SafeExamBrowser.Core.Communication
|
|||
private void BaseProxy_Faulted(object sender, EventArgs e)
|
||||
{
|
||||
Logger.Error("Communication channel has faulted!");
|
||||
ConnectionLost?.Invoke();
|
||||
}
|
||||
|
||||
private void BaseProxy_Opened(object sender, EventArgs e)
|
||||
|
|
|
@ -46,6 +46,18 @@ namespace SafeExamBrowser.Core.Communication
|
|||
}
|
||||
}
|
||||
|
||||
public bool RequestReconfiguration(string url)
|
||||
{
|
||||
var response = Send(new ReconfigurationMessage(url));
|
||||
|
||||
if (response is ReconfigurationResponse reconfiguration)
|
||||
{
|
||||
return reconfiguration.Accepted;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public void RequestShutdown()
|
||||
{
|
||||
var response = Send(SimpleMessagePurport.RequestShutdown);
|
||||
|
|
|
@ -12,10 +12,10 @@
|
|||
<Entry key="MessageBox_ApplicationErrorTitle">
|
||||
Application Error
|
||||
</Entry>
|
||||
<Entry key="MessageBox_ConfigureClientSuccess">
|
||||
<Entry key="MessageBox_ClientConfigurationQuestion">
|
||||
The client configuration has been saved and will be used when you start the application the next time. Do you want to quit for now?
|
||||
</Entry>
|
||||
<Entry key="MessageBox_ConfigureClientSuccessTitle">
|
||||
<Entry key="MessageBox_ClientConfigurationQuestionTitle">
|
||||
Configuration Successful
|
||||
</Entry>
|
||||
<Entry key="MessageBox_Quit">
|
||||
|
@ -25,15 +25,27 @@
|
|||
Quit?
|
||||
</Entry>
|
||||
<Entry key="MessageBox_QuitError">
|
||||
The client failed to communicate the shutdown request to the runtime! Please try again...
|
||||
The client failed to communicate the shutdown request to the runtime!
|
||||
</Entry>
|
||||
<Entry key="MessageBox_QuitErrorTitle">
|
||||
Quit Error
|
||||
</Entry>
|
||||
<Entry key="MessageBox_ReconfigureQuestion">
|
||||
<Entry key="MessageBox_ReconfigurationDenied">
|
||||
You are not allowed to reconfigure the application.
|
||||
</Entry>
|
||||
<Entry key="MessageBox_ReconfigurationDeniedTitle">
|
||||
Reconfiguration Denied
|
||||
</Entry>
|
||||
<Entry key="MessageBox_ReconfigurationError">
|
||||
The client failed to communicate the reconfiguration request to the runtime!
|
||||
</Entry>
|
||||
<Entry key="MessageBox_ReconfigurationErrorTitle">
|
||||
Reconfiguration Error
|
||||
</Entry>
|
||||
<Entry key="MessageBox_ReconfigurationQuestion">
|
||||
Would you like to reconfigure the application?
|
||||
</Entry>
|
||||
<Entry key="MessageBox_ReconfigureQuestionTitle">
|
||||
<Entry key="MessageBox_ReconfigurationQuestionTitle">
|
||||
Configuration Detected
|
||||
</Entry>
|
||||
<Entry key="MessageBox_SessionStartError">
|
||||
|
|
|
@ -127,8 +127,8 @@ namespace SafeExamBrowser.Runtime.Behaviour.Operations
|
|||
|
||||
private bool IsConfigurationSufficient()
|
||||
{
|
||||
var message = text.Get(TextKey.MessageBox_ConfigureClientSuccess);
|
||||
var title = text.Get(TextKey.MessageBox_ConfigureClientSuccessTitle);
|
||||
var message = text.Get(TextKey.MessageBox_ClientConfigurationQuestion);
|
||||
var title = text.Get(TextKey.MessageBox_ClientConfigurationQuestionTitle);
|
||||
var abort = uiFactory.Show(message, title, MessageBoxAction.YesNo, MessageBoxIcon.Question);
|
||||
|
||||
return abort == MessageBoxResult.Yes;
|
||||
|
|
|
@ -7,38 +7,39 @@
|
|||
*/
|
||||
|
||||
using SafeExamBrowser.Contracts.Behaviour.OperationModel;
|
||||
using SafeExamBrowser.Contracts.Communication;
|
||||
using SafeExamBrowser.Contracts.Configuration;
|
||||
using SafeExamBrowser.Contracts.Logging;
|
||||
using SafeExamBrowser.Contracts.WindowsApi;
|
||||
using SafeExamBrowser.Contracts.UserInterface;
|
||||
|
||||
namespace SafeExamBrowser.Runtime.Behaviour.Operations
|
||||
{
|
||||
internal class SessionSequenceEndOperation : SessionSequenceOperation
|
||||
internal class SessionSequenceEndOperation : IOperation
|
||||
{
|
||||
public SessionSequenceEndOperation(
|
||||
IClientProxy client,
|
||||
IConfigurationRepository configuration,
|
||||
ILogger logger,
|
||||
IProcessFactory processFactory,
|
||||
IRuntimeHost runtimeHost,
|
||||
IServiceProxy service) : base(client, configuration, logger, processFactory, runtimeHost, service)
|
||||
private SessionController controller;
|
||||
|
||||
public IProgressIndicator ProgressIndicator { private get; set; }
|
||||
|
||||
public SessionSequenceEndOperation(SessionController controller)
|
||||
{
|
||||
this.controller = controller;
|
||||
}
|
||||
|
||||
public override OperationResult Perform()
|
||||
public OperationResult Perform()
|
||||
{
|
||||
return StartSession();
|
||||
controller.ProgressIndicator = ProgressIndicator;
|
||||
|
||||
return controller.StartSession();
|
||||
}
|
||||
|
||||
public override OperationResult Repeat()
|
||||
public OperationResult Repeat()
|
||||
{
|
||||
return StartSession();
|
||||
controller.ProgressIndicator = ProgressIndicator;
|
||||
|
||||
return controller.StartSession();
|
||||
}
|
||||
|
||||
public override void Revert()
|
||||
public void Revert()
|
||||
{
|
||||
StopSession();
|
||||
controller.ProgressIndicator = ProgressIndicator;
|
||||
controller.StopSession();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,36 +7,34 @@
|
|||
*/
|
||||
|
||||
using SafeExamBrowser.Contracts.Behaviour.OperationModel;
|
||||
using SafeExamBrowser.Contracts.Communication;
|
||||
using SafeExamBrowser.Contracts.Configuration;
|
||||
using SafeExamBrowser.Contracts.Logging;
|
||||
using SafeExamBrowser.Contracts.WindowsApi;
|
||||
using SafeExamBrowser.Contracts.UserInterface;
|
||||
|
||||
namespace SafeExamBrowser.Runtime.Behaviour.Operations
|
||||
{
|
||||
internal class SessionSequenceStartOperation : SessionSequenceOperation
|
||||
internal class SessionSequenceStartOperation : IOperation
|
||||
{
|
||||
public SessionSequenceStartOperation(
|
||||
IClientProxy client,
|
||||
IConfigurationRepository configuration,
|
||||
ILogger logger,
|
||||
IProcessFactory processFactory,
|
||||
IRuntimeHost runtimeHost,
|
||||
IServiceProxy service) : base(client, configuration, logger, processFactory, runtimeHost, service)
|
||||
private SessionController controller;
|
||||
|
||||
public IProgressIndicator ProgressIndicator { private get; set; }
|
||||
|
||||
public SessionSequenceStartOperation(SessionController controller)
|
||||
{
|
||||
this.controller = controller;
|
||||
}
|
||||
|
||||
public override OperationResult Perform()
|
||||
public OperationResult Perform()
|
||||
{
|
||||
return OperationResult.Success;
|
||||
}
|
||||
|
||||
public override OperationResult Repeat()
|
||||
public OperationResult Repeat()
|
||||
{
|
||||
return StopSession();
|
||||
controller.ProgressIndicator = ProgressIndicator;
|
||||
|
||||
return controller.StopSession();
|
||||
}
|
||||
|
||||
public override void Revert()
|
||||
public void Revert()
|
||||
{
|
||||
// Nothing to do here...
|
||||
}
|
||||
|
|
|
@ -134,6 +134,7 @@ namespace SafeExamBrowser.Runtime.Behaviour
|
|||
{
|
||||
runtimeWindow.Show();
|
||||
runtimeWindow.BringToForeground();
|
||||
runtimeWindow.ShowProgressBar();
|
||||
logger.Info(">>>--- Initiating session procedure ---<<<");
|
||||
|
||||
if (sessionRunning)
|
||||
|
@ -170,6 +171,7 @@ namespace SafeExamBrowser.Runtime.Behaviour
|
|||
|
||||
if (!initial)
|
||||
{
|
||||
logger.Info("Terminating application...");
|
||||
shutdown.Invoke();
|
||||
}
|
||||
}
|
||||
|
@ -201,6 +203,7 @@ namespace SafeExamBrowser.Runtime.Behaviour
|
|||
private void RegisterEvents()
|
||||
{
|
||||
client.ConnectionLost += Client_ConnectionLost;
|
||||
runtimeHost.ReconfigurationRequested += RuntimeHost_ReconfigurationRequested;
|
||||
runtimeHost.ShutdownRequested += RuntimeHost_ShutdownRequested;
|
||||
}
|
||||
|
||||
|
@ -212,6 +215,7 @@ namespace SafeExamBrowser.Runtime.Behaviour
|
|||
private void DeregisterEvents()
|
||||
{
|
||||
client.ConnectionLost -= Client_ConnectionLost;
|
||||
runtimeHost.ReconfigurationRequested -= RuntimeHost_ReconfigurationRequested;
|
||||
runtimeHost.ShutdownRequested -= RuntimeHost_ShutdownRequested;
|
||||
}
|
||||
|
||||
|
@ -238,6 +242,12 @@ namespace SafeExamBrowser.Runtime.Behaviour
|
|||
shutdown.Invoke();
|
||||
}
|
||||
|
||||
private void RuntimeHost_ReconfigurationRequested()
|
||||
{
|
||||
logger.Info($"Starting reconfiguration...");
|
||||
StartSession();
|
||||
}
|
||||
|
||||
private void RuntimeHost_ShutdownRequested()
|
||||
{
|
||||
logger.Info("Received shutdown request from the client application.");
|
||||
|
|
|
@ -15,9 +15,9 @@ using SafeExamBrowser.Contracts.Logging;
|
|||
using SafeExamBrowser.Contracts.UserInterface;
|
||||
using SafeExamBrowser.Contracts.WindowsApi;
|
||||
|
||||
namespace SafeExamBrowser.Runtime.Behaviour.Operations
|
||||
namespace SafeExamBrowser.Runtime.Behaviour
|
||||
{
|
||||
internal abstract class SessionSequenceOperation : IOperation
|
||||
internal class SessionController
|
||||
{
|
||||
private const int TEN_SECONDS = 10000;
|
||||
|
||||
|
@ -28,11 +28,11 @@ namespace SafeExamBrowser.Runtime.Behaviour.Operations
|
|||
private IProcessFactory processFactory;
|
||||
private IRuntimeHost runtimeHost;
|
||||
private IServiceProxy service;
|
||||
private ISession session;
|
||||
private ISessionData session;
|
||||
|
||||
public IProgressIndicator ProgressIndicator { private get; set; }
|
||||
internal IProgressIndicator ProgressIndicator { private get; set; }
|
||||
|
||||
public SessionSequenceOperation(
|
||||
internal SessionController(
|
||||
IClientProxy client,
|
||||
IConfigurationRepository configuration,
|
||||
ILogger logger,
|
||||
|
@ -48,16 +48,12 @@ namespace SafeExamBrowser.Runtime.Behaviour.Operations
|
|||
this.service = service;
|
||||
}
|
||||
|
||||
public abstract OperationResult Perform();
|
||||
public abstract OperationResult Repeat();
|
||||
public abstract void Revert();
|
||||
|
||||
protected OperationResult StartSession()
|
||||
internal OperationResult StartSession()
|
||||
{
|
||||
logger.Info("Starting new session...");
|
||||
ProgressIndicator?.UpdateText(TextKey.ProgressIndicator_StartSession, true);
|
||||
|
||||
session = configuration.InitializeSession();
|
||||
session = configuration.InitializeSessionData();
|
||||
runtimeHost.StartupToken = session.StartupToken;
|
||||
|
||||
logger.Info("Initializing service session...");
|
||||
|
@ -78,7 +74,7 @@ namespace SafeExamBrowser.Runtime.Behaviour.Operations
|
|||
return OperationResult.Success;
|
||||
}
|
||||
|
||||
protected OperationResult StopSession()
|
||||
internal OperationResult StopSession()
|
||||
{
|
||||
if (sessionRunning)
|
||||
{
|
|
@ -7,10 +7,12 @@
|
|||
*/
|
||||
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using SafeExamBrowser.Contracts.Communication;
|
||||
using SafeExamBrowser.Contracts.Communication.Messages;
|
||||
using SafeExamBrowser.Contracts.Communication.Responses;
|
||||
using SafeExamBrowser.Contracts.Configuration;
|
||||
using SafeExamBrowser.Contracts.Configuration.Settings;
|
||||
using SafeExamBrowser.Contracts.Logging;
|
||||
using SafeExamBrowser.Core.Communication;
|
||||
|
||||
|
@ -25,6 +27,7 @@ namespace SafeExamBrowser.Runtime.Communication
|
|||
|
||||
public event CommunicationEventHandler ClientDisconnected;
|
||||
public event CommunicationEventHandler ClientReady;
|
||||
public event CommunicationEventHandler ReconfigurationRequested;
|
||||
public event CommunicationEventHandler ShutdownRequested;
|
||||
|
||||
public RuntimeHost(string address, IConfigurationRepository configuration, ILogger logger) : base(address, logger)
|
||||
|
@ -48,10 +51,17 @@ namespace SafeExamBrowser.Runtime.Communication
|
|||
protected override void OnDisconnect()
|
||||
{
|
||||
ClientDisconnected?.Invoke();
|
||||
allowConnection = true;
|
||||
}
|
||||
|
||||
protected override Response OnReceive(Message message)
|
||||
{
|
||||
switch (message)
|
||||
{
|
||||
case ReconfigurationMessage reconfigurationMessage:
|
||||
return Handle(reconfigurationMessage);
|
||||
}
|
||||
|
||||
return new SimpleResponse(SimpleResponsePurport.UnknownMessage);
|
||||
}
|
||||
|
||||
|
@ -71,5 +81,22 @@ namespace SafeExamBrowser.Runtime.Communication
|
|||
|
||||
return new SimpleResponse(SimpleResponsePurport.UnknownMessage);
|
||||
}
|
||||
|
||||
private Response Handle(ReconfigurationMessage message)
|
||||
{
|
||||
var isExam = configuration.CurrentSettings.ConfigurationMode == ConfigurationMode.Exam;
|
||||
var isValidUri = Uri.TryCreate(message.ConfigurationUrl, UriKind.Absolute, out _);
|
||||
var allowed = !isExam && isValidUri;
|
||||
|
||||
Logger.Info($"Received reconfiguration request for '{message.ConfigurationUrl}', {(allowed ? "accepted" : "denied")} it.");
|
||||
|
||||
if (allowed)
|
||||
{
|
||||
configuration.ReconfigurationUrl = message.ConfigurationUrl;
|
||||
Task.Run(() => ReconfigurationRequested?.Invoke());
|
||||
}
|
||||
|
||||
return new ReconfigurationResponse { Accepted = allowed };
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -52,6 +52,7 @@ namespace SafeExamBrowser.Runtime
|
|||
var clientProxy = new ClientProxy(runtimeInfo.ClientAddress, new ModuleLogger(logger, typeof(ClientProxy)));
|
||||
var runtimeHost = new RuntimeHost(runtimeInfo.RuntimeAddress, configuration, new ModuleLogger(logger, typeof(RuntimeHost)));
|
||||
var serviceProxy = new ServiceProxy(runtimeInfo.ServiceAddress, new ModuleLogger(logger, typeof(ServiceProxy)));
|
||||
var sessionController = new SessionController(clientProxy, configuration, logger, processFactory, runtimeHost, serviceProxy);
|
||||
|
||||
var bootstrapOperations = new Queue<IOperation>();
|
||||
var sessionOperations = new Queue<IOperation>();
|
||||
|
@ -59,11 +60,11 @@ namespace SafeExamBrowser.Runtime
|
|||
bootstrapOperations.Enqueue(new I18nOperation(logger, text));
|
||||
bootstrapOperations.Enqueue(new CommunicationOperation(runtimeHost, logger));
|
||||
|
||||
sessionOperations.Enqueue(new SessionSequenceStartOperation(clientProxy, configuration, logger, processFactory, runtimeHost, serviceProxy));
|
||||
sessionOperations.Enqueue(new SessionSequenceStartOperation(sessionController));
|
||||
sessionOperations.Enqueue(new ConfigurationOperation(configuration, logger, runtimeInfo, text, uiFactory, args));
|
||||
sessionOperations.Enqueue(new ServiceConnectionOperation(configuration, logger, serviceProxy, text));
|
||||
sessionOperations.Enqueue(new KioskModeOperation(logger, configuration));
|
||||
sessionOperations.Enqueue(new SessionSequenceEndOperation(clientProxy, configuration, logger, processFactory, runtimeHost, serviceProxy));
|
||||
sessionOperations.Enqueue(new SessionSequenceEndOperation(sessionController));
|
||||
|
||||
var boostrapSequence = new OperationSequence(logger, bootstrapOperations);
|
||||
var sessionSequence = new OperationSequence(logger, sessionOperations);
|
||||
|
|
|
@ -91,7 +91,7 @@
|
|||
<Compile Include="Behaviour\Operations\KioskModeOperation.cs" />
|
||||
<Compile Include="Behaviour\Operations\ServiceConnectionOperation.cs" />
|
||||
<Compile Include="Behaviour\Operations\SessionSequenceEndOperation.cs" />
|
||||
<Compile Include="Behaviour\Operations\SessionSequenceOperation.cs" />
|
||||
<Compile Include="Behaviour\SessionController.cs" />
|
||||
<Compile Include="Behaviour\Operations\SessionSequenceStartOperation.cs" />
|
||||
<Compile Include="Communication\RuntimeHost.cs" />
|
||||
<Compile Include="CompositionRoot.cs" />
|
||||
|
|
Loading…
Reference in a new issue