SEBWIN-405: Implemented scaffolding for SEB server operation.
This commit is contained in:
parent
92ab58f988
commit
0edca494b3
17 changed files with 573 additions and 66 deletions
|
@ -119,6 +119,7 @@ namespace SafeExamBrowser.I18n.Contracts
|
||||||
OperationStatus_CloseRuntimeConnection,
|
OperationStatus_CloseRuntimeConnection,
|
||||||
OperationStatus_EmptyClipboard,
|
OperationStatus_EmptyClipboard,
|
||||||
OperationStatus_FinalizeApplications,
|
OperationStatus_FinalizeApplications,
|
||||||
|
OperationStatus_FinalizeServer,
|
||||||
OperationStatus_FinalizeServiceSession,
|
OperationStatus_FinalizeServiceSession,
|
||||||
OperationStatus_FinalizeSystemEvents,
|
OperationStatus_FinalizeSystemEvents,
|
||||||
OperationStatus_InitializeApplications,
|
OperationStatus_InitializeApplications,
|
||||||
|
@ -126,6 +127,7 @@ namespace SafeExamBrowser.I18n.Contracts
|
||||||
OperationStatus_InitializeConfiguration,
|
OperationStatus_InitializeConfiguration,
|
||||||
OperationStatus_InitializeKioskMode,
|
OperationStatus_InitializeKioskMode,
|
||||||
OperationStatus_InitializeRuntimeConnection,
|
OperationStatus_InitializeRuntimeConnection,
|
||||||
|
OperationStatus_InitializeServer,
|
||||||
OperationStatus_InitializeServiceSession,
|
OperationStatus_InitializeServiceSession,
|
||||||
OperationStatus_InitializeSession,
|
OperationStatus_InitializeSession,
|
||||||
OperationStatus_InitializeShell,
|
OperationStatus_InitializeShell,
|
||||||
|
|
|
@ -315,6 +315,9 @@
|
||||||
<Entry key="OperationStatus_FinalizeApplications">
|
<Entry key="OperationStatus_FinalizeApplications">
|
||||||
Beende Applikationen
|
Beende Applikationen
|
||||||
</Entry>
|
</Entry>
|
||||||
|
<Entry key="OperationStatus_FinalizeServer">
|
||||||
|
Finalisiere SEB-Server
|
||||||
|
</Entry>
|
||||||
<Entry key="OperationStatus_FinalizeServiceSession">
|
<Entry key="OperationStatus_FinalizeServiceSession">
|
||||||
Beende Service-Sitzung
|
Beende Service-Sitzung
|
||||||
</Entry>
|
</Entry>
|
||||||
|
@ -336,6 +339,9 @@
|
||||||
<Entry key="OperationStatus_InitializeRuntimeConnection">
|
<Entry key="OperationStatus_InitializeRuntimeConnection">
|
||||||
Initialisiere Verbindung zur Runtime
|
Initialisiere Verbindung zur Runtime
|
||||||
</Entry>
|
</Entry>
|
||||||
|
<Entry key="OperationStatus_InitializeServer">
|
||||||
|
Initialisiere SEB-Server
|
||||||
|
</Entry>
|
||||||
<Entry key="OperationStatus_InitializeServiceSession">
|
<Entry key="OperationStatus_InitializeServiceSession">
|
||||||
Initialisiere Service-Sitzung
|
Initialisiere Service-Sitzung
|
||||||
</Entry>
|
</Entry>
|
||||||
|
|
|
@ -315,6 +315,9 @@
|
||||||
<Entry key="OperationStatus_FinalizeApplications">
|
<Entry key="OperationStatus_FinalizeApplications">
|
||||||
Finalizing applications
|
Finalizing applications
|
||||||
</Entry>
|
</Entry>
|
||||||
|
<Entry key="OperationStatus_FinalizeServer">
|
||||||
|
Finalizing SEB-Server
|
||||||
|
</Entry>
|
||||||
<Entry key="OperationStatus_FinalizeServiceSession">
|
<Entry key="OperationStatus_FinalizeServiceSession">
|
||||||
Finalizing service session
|
Finalizing service session
|
||||||
</Entry>
|
</Entry>
|
||||||
|
@ -336,6 +339,9 @@
|
||||||
<Entry key="OperationStatus_InitializeRuntimeConnection">
|
<Entry key="OperationStatus_InitializeRuntimeConnection">
|
||||||
Initializing runtime connection
|
Initializing runtime connection
|
||||||
</Entry>
|
</Entry>
|
||||||
|
<Entry key="OperationStatus_InitializeServer">
|
||||||
|
Initializing SEB-Server
|
||||||
|
</Entry>
|
||||||
<Entry key="OperationStatus_InitializeServiceSession">
|
<Entry key="OperationStatus_InitializeServiceSession">
|
||||||
Initializing service session
|
Initializing service session
|
||||||
</Entry>
|
</Entry>
|
||||||
|
|
|
@ -26,6 +26,7 @@ using SafeExamBrowser.Logging;
|
||||||
using SafeExamBrowser.Logging.Contracts;
|
using SafeExamBrowser.Logging.Contracts;
|
||||||
using SafeExamBrowser.Runtime.Communication;
|
using SafeExamBrowser.Runtime.Communication;
|
||||||
using SafeExamBrowser.Runtime.Operations;
|
using SafeExamBrowser.Runtime.Operations;
|
||||||
|
using SafeExamBrowser.Server;
|
||||||
using SafeExamBrowser.Settings.Logging;
|
using SafeExamBrowser.Settings.Logging;
|
||||||
using SafeExamBrowser.SystemComponents;
|
using SafeExamBrowser.SystemComponents;
|
||||||
using SafeExamBrowser.SystemComponents.Contracts;
|
using SafeExamBrowser.SystemComponents.Contracts;
|
||||||
|
@ -66,6 +67,7 @@ namespace SafeExamBrowser.Runtime
|
||||||
var proxyFactory = new ProxyFactory(new ProxyObjectFactory(), ModuleLogger(nameof(ProxyFactory)));
|
var proxyFactory = new ProxyFactory(new ProxyObjectFactory(), ModuleLogger(nameof(ProxyFactory)));
|
||||||
var runtimeHost = new RuntimeHost(appConfig.RuntimeAddress, new HostObjectFactory(), ModuleLogger(nameof(RuntimeHost)), FIVE_SECONDS);
|
var runtimeHost = new RuntimeHost(appConfig.RuntimeAddress, new HostObjectFactory(), ModuleLogger(nameof(RuntimeHost)), FIVE_SECONDS);
|
||||||
var runtimeWindow = uiFactory.CreateRuntimeWindow(appConfig);
|
var runtimeWindow = uiFactory.CreateRuntimeWindow(appConfig);
|
||||||
|
var server = new ServerProxy();
|
||||||
var serviceProxy = new ServiceProxy(appConfig.ServiceAddress, new ProxyObjectFactory(), ModuleLogger(nameof(ServiceProxy)), Interlocutor.Runtime);
|
var serviceProxy = new ServiceProxy(appConfig.ServiceAddress, new ProxyObjectFactory(), ModuleLogger(nameof(ServiceProxy)), Interlocutor.Runtime);
|
||||||
var sessionContext = new SessionContext();
|
var sessionContext = new SessionContext();
|
||||||
var splashScreen = uiFactory.CreateSplashScreen(appConfig);
|
var splashScreen = uiFactory.CreateSplashScreen(appConfig);
|
||||||
|
@ -80,7 +82,7 @@ namespace SafeExamBrowser.Runtime
|
||||||
|
|
||||||
sessionOperations.Enqueue(new SessionInitializationOperation(configuration, logger, runtimeHost, sessionContext));
|
sessionOperations.Enqueue(new SessionInitializationOperation(configuration, logger, runtimeHost, sessionContext));
|
||||||
sessionOperations.Enqueue(new ConfigurationOperation(args, configuration, new FileSystem(), new HashAlgorithm(), logger, sessionContext));
|
sessionOperations.Enqueue(new ConfigurationOperation(args, configuration, new FileSystem(), new HashAlgorithm(), logger, sessionContext));
|
||||||
// TODO: sessionOperations.Enqueue(new ServerOperation());
|
sessionOperations.Enqueue(new ServerOperation(args, configuration, logger, sessionContext, server));
|
||||||
sessionOperations.Enqueue(new VirtualMachineOperation(vmDetector, logger, sessionContext));
|
sessionOperations.Enqueue(new VirtualMachineOperation(vmDetector, logger, sessionContext));
|
||||||
sessionOperations.Enqueue(new ServiceOperation(logger, runtimeHost, serviceProxy, sessionContext, THIRTY_SECONDS, userInfo));
|
sessionOperations.Enqueue(new ServiceOperation(logger, runtimeHost, serviceProxy, sessionContext, THIRTY_SECONDS, userInfo));
|
||||||
sessionOperations.Enqueue(new ClientTerminationOperation(logger, processFactory, proxyFactory, runtimeHost, sessionContext, THIRTY_SECONDS));
|
sessionOperations.Enqueue(new ClientTerminationOperation(logger, processFactory, proxyFactory, runtimeHost, sessionContext, THIRTY_SECONDS));
|
||||||
|
@ -108,7 +110,7 @@ namespace SafeExamBrowser.Runtime
|
||||||
}
|
}
|
||||||
|
|
||||||
internal void LogStartupInformation()
|
internal void LogStartupInformation()
|
||||||
{
|
{
|
||||||
logger.Log($"/* {appConfig.ProgramTitle}, Version {appConfig.ProgramInformationalVersion}, Build {appConfig.ProgramBuildVersion}");
|
logger.Log($"/* {appConfig.ProgramTitle}, Version {appConfig.ProgramInformationalVersion}, Build {appConfig.ProgramBuildVersion}");
|
||||||
logger.Log($"/* {appConfig.ProgramCopyright}");
|
logger.Log($"/* {appConfig.ProgramCopyright}");
|
||||||
logger.Log($"/* ");
|
logger.Log($"/* ");
|
||||||
|
|
|
@ -0,0 +1,91 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2020 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.Communication.Contracts.Data;
|
||||||
|
using SafeExamBrowser.Configuration.Contracts;
|
||||||
|
using SafeExamBrowser.Configuration.Contracts.Cryptography;
|
||||||
|
using SafeExamBrowser.Core.Contracts.OperationModel.Events;
|
||||||
|
using SafeExamBrowser.Runtime.Operations.Events;
|
||||||
|
using SafeExamBrowser.Settings;
|
||||||
|
|
||||||
|
namespace SafeExamBrowser.Runtime.Operations
|
||||||
|
{
|
||||||
|
internal abstract class ConfigurationBaseOperation : SessionOperation
|
||||||
|
{
|
||||||
|
protected string[] commandLineArgs;
|
||||||
|
protected IConfigurationRepository configuration;
|
||||||
|
|
||||||
|
protected string AppDataFilePath => Context.Next.AppConfig.AppDataFilePath;
|
||||||
|
protected string ProgramDataFilePath => Context.Next.AppConfig.ProgramDataFilePath;
|
||||||
|
|
||||||
|
public ConfigurationBaseOperation(string[] commandLineArgs, IConfigurationRepository configuration, SessionContext context) : base(context)
|
||||||
|
{
|
||||||
|
this.commandLineArgs = commandLineArgs;
|
||||||
|
this.configuration = configuration;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected abstract void InvokeActionRequired(ActionRequiredEventArgs args);
|
||||||
|
|
||||||
|
protected LoadStatus? TryLoadSettings(Uri uri, UriSource source, out PasswordParameters passwordParams, out AppSettings settings, string currentPassword = default(string))
|
||||||
|
{
|
||||||
|
passwordParams = new PasswordParameters { Password = string.Empty, IsHash = true };
|
||||||
|
|
||||||
|
var status = configuration.TryLoadSettings(uri, out settings, passwordParams);
|
||||||
|
|
||||||
|
if (status == LoadStatus.PasswordNeeded && currentPassword != default(string))
|
||||||
|
{
|
||||||
|
passwordParams.Password = currentPassword;
|
||||||
|
passwordParams.IsHash = true;
|
||||||
|
|
||||||
|
status = configuration.TryLoadSettings(uri, out settings, passwordParams);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int attempts = 0; attempts < 5 && status == LoadStatus.PasswordNeeded; attempts++)
|
||||||
|
{
|
||||||
|
var isLocalConfig = source == UriSource.AppData || source == UriSource.ProgramData;
|
||||||
|
var purpose = isLocalConfig ? PasswordRequestPurpose.LocalSettings : PasswordRequestPurpose.Settings;
|
||||||
|
var success = TryGetPassword(purpose, out var password);
|
||||||
|
|
||||||
|
if (success)
|
||||||
|
{
|
||||||
|
passwordParams.Password = password;
|
||||||
|
passwordParams.IsHash = false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
status = configuration.TryLoadSettings(uri, out settings, passwordParams);
|
||||||
|
}
|
||||||
|
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected bool TryGetPassword(PasswordRequestPurpose purpose, out string password)
|
||||||
|
{
|
||||||
|
var args = new PasswordRequiredEventArgs { Purpose = purpose };
|
||||||
|
|
||||||
|
InvokeActionRequired(args);
|
||||||
|
password = args.Password;
|
||||||
|
|
||||||
|
return args.Success;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected enum UriSource
|
||||||
|
{
|
||||||
|
Undefined,
|
||||||
|
AppData,
|
||||||
|
CommandLine,
|
||||||
|
ProgramData,
|
||||||
|
Reconfiguration,
|
||||||
|
Server
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -21,17 +21,12 @@ using SafeExamBrowser.SystemComponents.Contracts;
|
||||||
|
|
||||||
namespace SafeExamBrowser.Runtime.Operations
|
namespace SafeExamBrowser.Runtime.Operations
|
||||||
{
|
{
|
||||||
internal class ConfigurationOperation : SessionOperation
|
internal class ConfigurationOperation : ConfigurationBaseOperation
|
||||||
{
|
{
|
||||||
private string[] commandLineArgs;
|
|
||||||
private IConfigurationRepository configuration;
|
|
||||||
private IFileSystem fileSystem;
|
private IFileSystem fileSystem;
|
||||||
private IHashAlgorithm hashAlgorithm;
|
private IHashAlgorithm hashAlgorithm;
|
||||||
private ILogger logger;
|
private ILogger logger;
|
||||||
|
|
||||||
private string AppDataFilePath => Context.Next.AppConfig.AppDataFilePath;
|
|
||||||
private string ProgramDataFilePath => Context.Next.AppConfig.ProgramDataFilePath;
|
|
||||||
|
|
||||||
public override event ActionRequiredEventHandler ActionRequired;
|
public override event ActionRequiredEventHandler ActionRequired;
|
||||||
public override event StatusChangedEventHandler StatusChanged;
|
public override event StatusChangedEventHandler StatusChanged;
|
||||||
|
|
||||||
|
@ -41,10 +36,8 @@ namespace SafeExamBrowser.Runtime.Operations
|
||||||
IFileSystem fileSystem,
|
IFileSystem fileSystem,
|
||||||
IHashAlgorithm hashAlgorithm,
|
IHashAlgorithm hashAlgorithm,
|
||||||
ILogger logger,
|
ILogger logger,
|
||||||
SessionContext sessionContext) : base(sessionContext)
|
SessionContext sessionContext) : base(commandLineArgs, configuration, sessionContext)
|
||||||
{
|
{
|
||||||
this.commandLineArgs = commandLineArgs;
|
|
||||||
this.configuration = configuration;
|
|
||||||
this.fileSystem = fileSystem;
|
this.fileSystem = fileSystem;
|
||||||
this.hashAlgorithm = hashAlgorithm;
|
this.hashAlgorithm = hashAlgorithm;
|
||||||
this.logger = logger;
|
this.logger = logger;
|
||||||
|
@ -99,6 +92,11 @@ namespace SafeExamBrowser.Runtime.Operations
|
||||||
return OperationResult.Success;
|
return OperationResult.Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected override void InvokeActionRequired(ActionRequiredEventArgs args)
|
||||||
|
{
|
||||||
|
ActionRequired?.Invoke(args);
|
||||||
|
}
|
||||||
|
|
||||||
private OperationResult LoadDefaultSettings()
|
private OperationResult LoadDefaultSettings()
|
||||||
{
|
{
|
||||||
logger.Info("No valid configuration resource specified and no local client configuration found - loading default settings...");
|
logger.Info("No valid configuration resource specified and no local client configuration found - loading default settings...");
|
||||||
|
@ -232,42 +230,6 @@ namespace SafeExamBrowser.Runtime.Operations
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
private LoadStatus? TryLoadSettings(Uri uri, UriSource source, out PasswordParameters passwordParams, out AppSettings settings, string currentPassword = default(string))
|
|
||||||
{
|
|
||||||
passwordParams = new PasswordParameters { Password = string.Empty, IsHash = true };
|
|
||||||
|
|
||||||
var status = configuration.TryLoadSettings(uri, out settings, passwordParams);
|
|
||||||
|
|
||||||
if (status == LoadStatus.PasswordNeeded && currentPassword != default(string))
|
|
||||||
{
|
|
||||||
passwordParams.Password = currentPassword;
|
|
||||||
passwordParams.IsHash = true;
|
|
||||||
|
|
||||||
status = configuration.TryLoadSettings(uri, out settings, passwordParams);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int attempts = 0; attempts < 5 && status == LoadStatus.PasswordNeeded; attempts++)
|
|
||||||
{
|
|
||||||
var isLocalConfig = source == UriSource.AppData || source == UriSource.ProgramData;
|
|
||||||
var purpose = isLocalConfig ? PasswordRequestPurpose.LocalSettings : PasswordRequestPurpose.Settings;
|
|
||||||
var success = TryGetPassword(purpose, out var password);
|
|
||||||
|
|
||||||
if (success)
|
|
||||||
{
|
|
||||||
passwordParams.Password = password;
|
|
||||||
passwordParams.IsHash = false;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
status = configuration.TryLoadSettings(uri, out settings, passwordParams);
|
|
||||||
}
|
|
||||||
|
|
||||||
return status;
|
|
||||||
}
|
|
||||||
|
|
||||||
private bool? TryConfigureClient(Uri uri, PasswordParameters passwordParams, string currentPassword = default(string))
|
private bool? TryConfigureClient(Uri uri, PasswordParameters passwordParams, string currentPassword = default(string))
|
||||||
{
|
{
|
||||||
var mustAuthenticate = IsRequiredToAuthenticateForClientConfiguration(passwordParams, currentPassword);
|
var mustAuthenticate = IsRequiredToAuthenticateForClientConfiguration(passwordParams, currentPassword);
|
||||||
|
@ -395,16 +357,6 @@ namespace SafeExamBrowser.Runtime.Operations
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool TryGetPassword(PasswordRequestPurpose purpose, out string password)
|
|
||||||
{
|
|
||||||
var args = new PasswordRequiredEventArgs { Purpose = purpose };
|
|
||||||
|
|
||||||
ActionRequired?.Invoke(args);
|
|
||||||
password = args.Password;
|
|
||||||
|
|
||||||
return args.Success;
|
|
||||||
}
|
|
||||||
|
|
||||||
private bool TryInitializeSettingsUri(out Uri uri, out UriSource source)
|
private bool TryInitializeSettingsUri(out Uri uri, out UriSource source)
|
||||||
{
|
{
|
||||||
var isValidUri = false;
|
var isValidUri = false;
|
||||||
|
@ -461,14 +413,5 @@ namespace SafeExamBrowser.Runtime.Operations
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private enum UriSource
|
|
||||||
{
|
|
||||||
Undefined,
|
|
||||||
AppData,
|
|
||||||
CommandLine,
|
|
||||||
ProgramData,
|
|
||||||
Reconfiguration
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,25 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2020 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.Collections.Generic;
|
||||||
|
using SafeExamBrowser.Core.Contracts.OperationModel.Events;
|
||||||
|
using SafeExamBrowser.Server.Contracts;
|
||||||
|
|
||||||
|
namespace SafeExamBrowser.Runtime.Operations.Events
|
||||||
|
{
|
||||||
|
internal class ExamSelectionEventArgs : ActionRequiredEventArgs
|
||||||
|
{
|
||||||
|
internal IEnumerable<Exam> Exams { get; set; }
|
||||||
|
internal Exam SelectedExam { get; set; }
|
||||||
|
|
||||||
|
internal ExamSelectionEventArgs(IEnumerable<Exam> exams)
|
||||||
|
{
|
||||||
|
Exams = exams;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,25 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2020 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.Core.Contracts.OperationModel.Events;
|
||||||
|
|
||||||
|
namespace SafeExamBrowser.Runtime.Operations.Events
|
||||||
|
{
|
||||||
|
internal class ServerFailureEventArgs : ActionRequiredEventArgs
|
||||||
|
{
|
||||||
|
public bool Abort { get; set; }
|
||||||
|
public bool Fallback { get; set; }
|
||||||
|
public string Message { get; set; }
|
||||||
|
public bool Retry { get; set; }
|
||||||
|
|
||||||
|
public ServerFailureEventArgs(string message)
|
||||||
|
{
|
||||||
|
Message = message;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
204
SafeExamBrowser.Runtime/Operations/ServerOperation.cs
Normal file
204
SafeExamBrowser.Runtime/Operations/ServerOperation.cs
Normal file
|
@ -0,0 +1,204 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2020 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 System.Collections.Generic;
|
||||||
|
using SafeExamBrowser.Configuration.Contracts;
|
||||||
|
using SafeExamBrowser.Core.Contracts.OperationModel;
|
||||||
|
using SafeExamBrowser.Core.Contracts.OperationModel.Events;
|
||||||
|
using SafeExamBrowser.I18n.Contracts;
|
||||||
|
using SafeExamBrowser.Logging.Contracts;
|
||||||
|
using SafeExamBrowser.Runtime.Operations.Events;
|
||||||
|
using SafeExamBrowser.Server.Contracts;
|
||||||
|
using SafeExamBrowser.Settings;
|
||||||
|
|
||||||
|
namespace SafeExamBrowser.Runtime.Operations
|
||||||
|
{
|
||||||
|
internal class ServerOperation : ConfigurationBaseOperation
|
||||||
|
{
|
||||||
|
private readonly ILogger logger;
|
||||||
|
private readonly IServerProxy server;
|
||||||
|
|
||||||
|
public override event ActionRequiredEventHandler ActionRequired;
|
||||||
|
public override event StatusChangedEventHandler StatusChanged;
|
||||||
|
|
||||||
|
public ServerOperation(
|
||||||
|
string[] commandLineArgs,
|
||||||
|
IConfigurationRepository configuration,
|
||||||
|
ILogger logger,
|
||||||
|
SessionContext context,
|
||||||
|
IServerProxy server) : base(commandLineArgs, configuration, context)
|
||||||
|
{
|
||||||
|
this.logger = logger;
|
||||||
|
this.server = server;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override OperationResult Perform()
|
||||||
|
{
|
||||||
|
var result = OperationResult.Success;
|
||||||
|
|
||||||
|
if (Context.Next.Settings.SessionMode == SessionMode.Server)
|
||||||
|
{
|
||||||
|
logger.Info("Initializing server...");
|
||||||
|
StatusChanged?.Invoke(TextKey.OperationStatus_InitializeServer);
|
||||||
|
|
||||||
|
var (abort, fallback, success) = TryPerformWithFallback(() => server.Connect(Context.Next.Settings.Server));
|
||||||
|
|
||||||
|
if (success)
|
||||||
|
{
|
||||||
|
(abort, fallback, success) = TryPerformWithFallback(() => server.GetAvailableExams(), out var exams);
|
||||||
|
|
||||||
|
if (success)
|
||||||
|
{
|
||||||
|
var exam = SelectExam(exams);
|
||||||
|
|
||||||
|
(abort, fallback, success) = TryPerformWithFallback(() => server.GetConfigurationFor(exam), out var uri);
|
||||||
|
|
||||||
|
if (success)
|
||||||
|
{
|
||||||
|
var status = TryLoadSettings(uri, UriSource.Server, out _, out var settings);
|
||||||
|
|
||||||
|
if (status == LoadStatus.Success)
|
||||||
|
{
|
||||||
|
Context.Next.Settings = settings;
|
||||||
|
result = OperationResult.Success;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
result = OperationResult.Failed;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (abort)
|
||||||
|
{
|
||||||
|
result = OperationResult.Aborted;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fallback)
|
||||||
|
{
|
||||||
|
result = OperationResult.Success;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override OperationResult Repeat()
|
||||||
|
{
|
||||||
|
var result = Revert();
|
||||||
|
|
||||||
|
if (result == OperationResult.Success)
|
||||||
|
{
|
||||||
|
result = Perform();
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override OperationResult Revert()
|
||||||
|
{
|
||||||
|
var result = OperationResult.Failed;
|
||||||
|
|
||||||
|
if (Context.Current.Settings.SessionMode == SessionMode.Server)
|
||||||
|
{
|
||||||
|
logger.Info("Finalizing server...");
|
||||||
|
StatusChanged?.Invoke(TextKey.OperationStatus_FinalizeServer);
|
||||||
|
|
||||||
|
var disconnect = server.Disconnect();
|
||||||
|
|
||||||
|
if (disconnect.Success)
|
||||||
|
{
|
||||||
|
result = OperationResult.Success;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
result = OperationResult.Failed;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
result = OperationResult.Success;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void InvokeActionRequired(ActionRequiredEventArgs args)
|
||||||
|
{
|
||||||
|
ActionRequired?.Invoke(args);
|
||||||
|
}
|
||||||
|
|
||||||
|
private (bool abort, bool fallback, bool success) TryPerformWithFallback(Func<ServerResponse> request)
|
||||||
|
{
|
||||||
|
var abort = false;
|
||||||
|
var fallback = false;
|
||||||
|
var success = false;
|
||||||
|
|
||||||
|
while (!success)
|
||||||
|
{
|
||||||
|
var response = request();
|
||||||
|
|
||||||
|
success = response.Success;
|
||||||
|
|
||||||
|
if (!success && !Retry(response.Message, out abort, out fallback))
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return (abort, fallback, success);
|
||||||
|
}
|
||||||
|
|
||||||
|
private (bool abort, bool fallback, bool success) TryPerformWithFallback<T>(Func<ServerResponse<T>> request, out T value)
|
||||||
|
{
|
||||||
|
var abort = false;
|
||||||
|
var fallback = false;
|
||||||
|
var success = false;
|
||||||
|
|
||||||
|
value = default(T);
|
||||||
|
|
||||||
|
while (!success)
|
||||||
|
{
|
||||||
|
var response = request();
|
||||||
|
|
||||||
|
success = response.Success;
|
||||||
|
value = response.Value;
|
||||||
|
|
||||||
|
if (!success && !Retry(response.Message, out abort, out fallback))
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return (abort, fallback, success);
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool Retry(string message, out bool abort, out bool fallback)
|
||||||
|
{
|
||||||
|
var args = new ServerFailureEventArgs(message);
|
||||||
|
|
||||||
|
ActionRequired?.Invoke(args);
|
||||||
|
|
||||||
|
abort = args.Abort;
|
||||||
|
fallback = args.Fallback;
|
||||||
|
|
||||||
|
return args.Retry;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Exam SelectExam(IEnumerable<Exam> exams)
|
||||||
|
{
|
||||||
|
var args = new ExamSelectionEventArgs(exams);
|
||||||
|
|
||||||
|
ActionRequired?.Invoke(args);
|
||||||
|
|
||||||
|
return args.SelectedExam;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -384,15 +384,31 @@ namespace SafeExamBrowser.Runtime
|
||||||
case ConfigurationCompletedEventArgs a:
|
case ConfigurationCompletedEventArgs a:
|
||||||
AskIfConfigurationSufficient(a);
|
AskIfConfigurationSufficient(a);
|
||||||
break;
|
break;
|
||||||
|
case ExamSelectionEventArgs a:
|
||||||
|
AskForExamSelection(a);
|
||||||
|
break;
|
||||||
case MessageEventArgs m:
|
case MessageEventArgs m:
|
||||||
ShowMessageBox(m);
|
ShowMessageBox(m);
|
||||||
break;
|
break;
|
||||||
case PasswordRequiredEventArgs p:
|
case PasswordRequiredEventArgs p:
|
||||||
AskForPassword(p);
|
AskForPassword(p);
|
||||||
break;
|
break;
|
||||||
|
case ServerFailureEventArgs a:
|
||||||
|
AskForServerFailureAction(a);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void AskForExamSelection(ExamSelectionEventArgs a)
|
||||||
|
{
|
||||||
|
// TODO: Also implement mechanism to retrieve selection via client!!
|
||||||
|
}
|
||||||
|
|
||||||
|
private void AskForServerFailureAction(ServerFailureEventArgs a)
|
||||||
|
{
|
||||||
|
// TODO: Also implement mechanism to retrieve selection via client!!
|
||||||
|
}
|
||||||
|
|
||||||
private void AskIfConfigurationSufficient(ConfigurationCompletedEventArgs args)
|
private void AskIfConfigurationSufficient(ConfigurationCompletedEventArgs args)
|
||||||
{
|
{
|
||||||
var message = TextKey.MessageBox_ClientConfigurationQuestion;
|
var message = TextKey.MessageBox_ClientConfigurationQuestion;
|
||||||
|
|
|
@ -90,16 +90,20 @@
|
||||||
<Compile Include="App.cs" />
|
<Compile Include="App.cs" />
|
||||||
<Compile Include="Operations\ClientOperation.cs" />
|
<Compile Include="Operations\ClientOperation.cs" />
|
||||||
<Compile Include="Operations\ClientTerminationOperation.cs" />
|
<Compile Include="Operations\ClientTerminationOperation.cs" />
|
||||||
|
<Compile Include="Operations\ConfigurationBaseOperation.cs" />
|
||||||
<Compile Include="Operations\ConfigurationOperation.cs" />
|
<Compile Include="Operations\ConfigurationOperation.cs" />
|
||||||
<Compile Include="Operations\Events\ClientConfigurationErrorMessageArgs.cs" />
|
<Compile Include="Operations\Events\ClientConfigurationErrorMessageArgs.cs" />
|
||||||
<Compile Include="Operations\Events\ConfigurationCompletedEventArgs.cs" />
|
<Compile Include="Operations\Events\ConfigurationCompletedEventArgs.cs" />
|
||||||
|
<Compile Include="Operations\Events\ExamSelectionEventArgs.cs" />
|
||||||
<Compile Include="Operations\Events\InvalidDataMessageArgs.cs" />
|
<Compile Include="Operations\Events\InvalidDataMessageArgs.cs" />
|
||||||
<Compile Include="Operations\Events\InvalidPasswordMessageArgs.cs" />
|
<Compile Include="Operations\Events\InvalidPasswordMessageArgs.cs" />
|
||||||
<Compile Include="Operations\Events\MessageEventArgs.cs" />
|
<Compile Include="Operations\Events\MessageEventArgs.cs" />
|
||||||
<Compile Include="Operations\Events\NotSupportedMessageArgs.cs" />
|
<Compile Include="Operations\Events\NotSupportedMessageArgs.cs" />
|
||||||
<Compile Include="Operations\Events\PasswordRequiredEventArgs.cs" />
|
<Compile Include="Operations\Events\PasswordRequiredEventArgs.cs" />
|
||||||
|
<Compile Include="Operations\Events\ServerFailureEventArgs.cs" />
|
||||||
<Compile Include="Operations\Events\UnexpectedErrorMessageArgs.cs" />
|
<Compile Include="Operations\Events\UnexpectedErrorMessageArgs.cs" />
|
||||||
<Compile Include="Operations\KioskModeOperation.cs" />
|
<Compile Include="Operations\KioskModeOperation.cs" />
|
||||||
|
<Compile Include="Operations\ServerOperation.cs" />
|
||||||
<Compile Include="Operations\ServiceOperation.cs" />
|
<Compile Include="Operations\ServiceOperation.cs" />
|
||||||
<Compile Include="Operations\SessionActivationOperation.cs" />
|
<Compile Include="Operations\SessionActivationOperation.cs" />
|
||||||
<Compile Include="Operations\SessionOperation.cs" />
|
<Compile Include="Operations\SessionOperation.cs" />
|
||||||
|
@ -177,6 +181,14 @@
|
||||||
<Project>{e107026c-2011-4552-a7d8-3a0d37881df6}</Project>
|
<Project>{e107026c-2011-4552-a7d8-3a0d37881df6}</Project>
|
||||||
<Name>SafeExamBrowser.Logging</Name>
|
<Name>SafeExamBrowser.Logging</Name>
|
||||||
</ProjectReference>
|
</ProjectReference>
|
||||||
|
<ProjectReference Include="..\SafeExamBrowser.Server.Contracts\SafeExamBrowser.Server.Contracts.csproj">
|
||||||
|
<Project>{db701e6f-bddc-4cec-b662-335a9dc11809}</Project>
|
||||||
|
<Name>SafeExamBrowser.Server.Contracts</Name>
|
||||||
|
</ProjectReference>
|
||||||
|
<ProjectReference Include="..\SafeExamBrowser.Server\SafeExamBrowser.Server.csproj">
|
||||||
|
<Project>{46edbde0-58b4-4725-9783-0c55c3d49c0c}</Project>
|
||||||
|
<Name>SafeExamBrowser.Server</Name>
|
||||||
|
</ProjectReference>
|
||||||
<ProjectReference Include="..\SafeExamBrowser.Settings\SafeExamBrowser.Settings.csproj">
|
<ProjectReference Include="..\SafeExamBrowser.Settings\SafeExamBrowser.Settings.csproj">
|
||||||
<Project>{30b2d907-5861-4f39-abad-c4abf1b3470e}</Project>
|
<Project>{30b2d907-5861-4f39-abad-c4abf1b3470e}</Project>
|
||||||
<Name>SafeExamBrowser.Settings</Name>
|
<Name>SafeExamBrowser.Settings</Name>
|
||||||
|
|
18
SafeExamBrowser.Server.Contracts/Exam.cs
Normal file
18
SafeExamBrowser.Server.Contracts/Exam.cs
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2020 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/.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace SafeExamBrowser.Server.Contracts
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
///
|
||||||
|
/// </summary>
|
||||||
|
public class Exam
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
45
SafeExamBrowser.Server.Contracts/IServerProxy.cs
Normal file
45
SafeExamBrowser.Server.Contracts/IServerProxy.cs
Normal file
|
@ -0,0 +1,45 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2020 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 System.Collections.Generic;
|
||||||
|
using SafeExamBrowser.Settings.Server;
|
||||||
|
|
||||||
|
namespace SafeExamBrowser.Server.Contracts
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
///
|
||||||
|
/// </summary>
|
||||||
|
public interface IServerProxy
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
///
|
||||||
|
/// </summary>
|
||||||
|
ServerResponse Connect(ServerSettings settings);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
///
|
||||||
|
/// </summary>
|
||||||
|
ServerResponse Disconnect();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
///
|
||||||
|
/// </summary>
|
||||||
|
ServerResponse<IEnumerable<Exam>> GetAvailableExams();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
///
|
||||||
|
/// </summary>
|
||||||
|
ServerResponse<Uri> GetConfigurationFor(Exam exam);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
///
|
||||||
|
/// </summary>
|
||||||
|
ServerResponse SendSessionInfo(string sessionId);
|
||||||
|
}
|
||||||
|
}
|
|
@ -54,7 +54,16 @@
|
||||||
<Reference Include="Microsoft.CSharp" />
|
<Reference Include="Microsoft.CSharp" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
<Compile Include="Exam.cs" />
|
||||||
|
<Compile Include="IServerProxy.cs" />
|
||||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||||
|
<Compile Include="ServerResponse.cs" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\SafeExamBrowser.Settings\SafeExamBrowser.Settings.csproj">
|
||||||
|
<Project>{30b2d907-5861-4f39-abad-c4abf1b3470e}</Project>
|
||||||
|
<Name>SafeExamBrowser.Settings</Name>
|
||||||
|
</ProjectReference>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||||
</Project>
|
</Project>
|
49
SafeExamBrowser.Server.Contracts/ServerResponse.cs
Normal file
49
SafeExamBrowser.Server.Contracts/ServerResponse.cs
Normal file
|
@ -0,0 +1,49 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2020 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/.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace SafeExamBrowser.Server.Contracts
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Defines the result of a communication with a SEB server.
|
||||||
|
/// </summary>
|
||||||
|
public class ServerResponse
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The message retrieved by the server in case the communication failed.
|
||||||
|
/// </summary>
|
||||||
|
public string Message { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Defines whether the communication was successful or not.
|
||||||
|
/// </summary>
|
||||||
|
public bool Success { get; }
|
||||||
|
|
||||||
|
public ServerResponse(bool success, string message = default(string))
|
||||||
|
{
|
||||||
|
Message = message;
|
||||||
|
Success = success;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Defines the result of a communication with a SEB server.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T">The type of the expected response value.</typeparam>
|
||||||
|
public class ServerResponse<T> : ServerResponse
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The response value. Can be <c>null</c> or <c>default(T)</c> in case the communication failed!
|
||||||
|
/// </summary>
|
||||||
|
public T Value { get; }
|
||||||
|
|
||||||
|
public ServerResponse(bool success, T value, string message = default(string)) : base(success, message)
|
||||||
|
{
|
||||||
|
Value = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -55,6 +55,17 @@
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||||
|
<Compile Include="ServerProxy.cs" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\SafeExamBrowser.Server.Contracts\SafeExamBrowser.Server.Contracts.csproj">
|
||||||
|
<Project>{db701e6f-bddc-4cec-b662-335a9dc11809}</Project>
|
||||||
|
<Name>SafeExamBrowser.Server.Contracts</Name>
|
||||||
|
</ProjectReference>
|
||||||
|
<ProjectReference Include="..\SafeExamBrowser.Settings\SafeExamBrowser.Settings.csproj">
|
||||||
|
<Project>{30b2d907-5861-4f39-abad-c4abf1b3470e}</Project>
|
||||||
|
<Name>SafeExamBrowser.Settings</Name>
|
||||||
|
</ProjectReference>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||||
</Project>
|
</Project>
|
43
SafeExamBrowser.Server/ServerProxy.cs
Normal file
43
SafeExamBrowser.Server/ServerProxy.cs
Normal file
|
@ -0,0 +1,43 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2020 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 System.Collections.Generic;
|
||||||
|
using SafeExamBrowser.Server.Contracts;
|
||||||
|
using SafeExamBrowser.Settings.Server;
|
||||||
|
|
||||||
|
namespace SafeExamBrowser.Server
|
||||||
|
{
|
||||||
|
public class ServerProxy : IServerProxy
|
||||||
|
{
|
||||||
|
public ServerResponse Connect(ServerSettings settings)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public ServerResponse Disconnect()
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public ServerResponse<IEnumerable<Exam>> GetAvailableExams()
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public ServerResponse<Uri> GetConfigurationFor(Exam exam)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public ServerResponse SendSessionInfo(string sessionId)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue