SEBWIN-221: Fixed implementation of session sequence to correctly handle initialization, transition and termination of sessions by introducing the SessionContext.
This commit is contained in:
parent
f4631a1a3d
commit
95ad176047
25 changed files with 551 additions and 375 deletions
|
@ -74,7 +74,7 @@ namespace SafeExamBrowser.Communication.Proxies
|
|||
{
|
||||
if (Ignore)
|
||||
{
|
||||
Logger.Debug($"Skipping {operationName} because the ignore flag is set.");
|
||||
Logger.Debug($"Skipping '{operationName}' operation because the ignore flag is set.");
|
||||
}
|
||||
|
||||
return Ignore;
|
||||
|
|
|
@ -25,86 +25,15 @@ namespace SafeExamBrowser.Configuration
|
|||
|
||||
private AppConfig appConfig;
|
||||
|
||||
public ISessionData CurrentSession { get; private set; }
|
||||
public Settings CurrentSettings { get; private set; }
|
||||
public string ReconfigurationFilePath { get; set; }
|
||||
|
||||
public AppConfig AppConfig
|
||||
{
|
||||
get
|
||||
{
|
||||
if (appConfig == null)
|
||||
{
|
||||
InitializeAppConfig();
|
||||
}
|
||||
|
||||
return appConfig;
|
||||
}
|
||||
}
|
||||
|
||||
public ConfigurationRepository(string executablePath, string programCopyright, string programTitle, string programVersion)
|
||||
{
|
||||
this.executablePath = executablePath ?? throw new ArgumentNullException(nameof(executablePath));
|
||||
this.programCopyright = programCopyright ?? throw new ArgumentNullException(nameof(programCopyright));
|
||||
this.programTitle = programTitle ?? throw new ArgumentNullException(nameof(programTitle));
|
||||
this.programVersion = programVersion ?? throw new ArgumentNullException(nameof(programVersion));
|
||||
this.executablePath = executablePath ?? string.Empty;
|
||||
this.programCopyright = programCopyright ?? string.Empty;
|
||||
this.programTitle = programTitle ?? string.Empty;
|
||||
this.programVersion = programVersion ?? string.Empty;
|
||||
}
|
||||
|
||||
public ClientConfiguration BuildClientConfiguration()
|
||||
{
|
||||
return new ClientConfiguration
|
||||
{
|
||||
AppConfig = AppConfig,
|
||||
SessionId = CurrentSession.Id,
|
||||
Settings = CurrentSettings
|
||||
};
|
||||
}
|
||||
|
||||
public void InitializeSessionConfiguration()
|
||||
{
|
||||
CurrentSession = new SessionData
|
||||
{
|
||||
Id = Guid.NewGuid(),
|
||||
NewDesktop = CurrentSession?.NewDesktop,
|
||||
OriginalDesktop = CurrentSession?.OriginalDesktop,
|
||||
StartupToken = Guid.NewGuid()
|
||||
};
|
||||
|
||||
UpdateAppConfig();
|
||||
}
|
||||
|
||||
public LoadStatus LoadSettings(Uri resource, string settingsPassword = null, string adminPassword = null)
|
||||
{
|
||||
// TODO: Implement loading mechanism
|
||||
|
||||
LoadDefaultSettings();
|
||||
|
||||
return LoadStatus.Success;
|
||||
}
|
||||
|
||||
public void LoadDefaultSettings()
|
||||
{
|
||||
// TODO: Implement default settings
|
||||
|
||||
CurrentSettings = new Settings();
|
||||
|
||||
CurrentSettings.KioskMode = KioskMode.None;
|
||||
CurrentSettings.ServicePolicy = ServicePolicy.Optional;
|
||||
|
||||
CurrentSettings.Browser.StartUrl = "https://www.safeexambrowser.org/testing";
|
||||
CurrentSettings.Browser.AllowAddressBar = true;
|
||||
CurrentSettings.Browser.AllowBackwardNavigation = true;
|
||||
CurrentSettings.Browser.AllowDeveloperConsole = true;
|
||||
CurrentSettings.Browser.AllowForwardNavigation = true;
|
||||
CurrentSettings.Browser.AllowReloading = true;
|
||||
CurrentSettings.Browser.AllowDownloads = true;
|
||||
|
||||
CurrentSettings.Taskbar.AllowApplicationLog = true;
|
||||
CurrentSettings.Taskbar.AllowKeyboardLayout = true;
|
||||
CurrentSettings.Taskbar.AllowWirelessNetwork = true;
|
||||
}
|
||||
|
||||
private void InitializeAppConfig()
|
||||
public AppConfig InitializeAppConfig()
|
||||
{
|
||||
var appDataFolder = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), nameof(SafeExamBrowser));
|
||||
var startTime = DateTime.Now;
|
||||
|
@ -134,12 +63,89 @@ namespace SafeExamBrowser.Configuration
|
|||
appConfig.SebUriScheme = "seb";
|
||||
appConfig.SebUriSchemeSecure = "sebs";
|
||||
appConfig.ServiceAddress = $"{BASE_ADDRESS}/service";
|
||||
|
||||
return appConfig;
|
||||
}
|
||||
|
||||
public ISessionConfiguration InitializeSessionConfiguration()
|
||||
{
|
||||
var configuration = new SessionConfiguration();
|
||||
|
||||
UpdateAppConfig();
|
||||
|
||||
configuration.AppConfig = CloneAppConfig();
|
||||
configuration.Id = Guid.NewGuid();
|
||||
configuration.StartupToken = Guid.NewGuid();
|
||||
|
||||
return configuration;
|
||||
}
|
||||
|
||||
public LoadStatus TryLoadSettings(Uri resource, out Settings settings, string adminPassword = null, string settingsPassword = null)
|
||||
{
|
||||
// TODO: Implement loading mechanism
|
||||
|
||||
settings = LoadDefaultSettings();
|
||||
|
||||
return LoadStatus.Success;
|
||||
}
|
||||
|
||||
public Settings LoadDefaultSettings()
|
||||
{
|
||||
// TODO: Implement default settings
|
||||
|
||||
var settings = new Settings();
|
||||
|
||||
settings.KioskMode = new Random().Next(10) < 5 ? KioskMode.CreateNewDesktop : KioskMode.DisableExplorerShell;
|
||||
settings.ServicePolicy = ServicePolicy.Optional;
|
||||
|
||||
settings.Browser.StartUrl = "https://www.safeexambrowser.org/testing";
|
||||
settings.Browser.AllowAddressBar = true;
|
||||
settings.Browser.AllowBackwardNavigation = true;
|
||||
settings.Browser.AllowDeveloperConsole = true;
|
||||
settings.Browser.AllowForwardNavigation = true;
|
||||
settings.Browser.AllowReloading = true;
|
||||
settings.Browser.AllowDownloads = true;
|
||||
|
||||
settings.Taskbar.AllowApplicationLog = true;
|
||||
settings.Taskbar.AllowKeyboardLayout = true;
|
||||
settings.Taskbar.AllowWirelessNetwork = true;
|
||||
|
||||
return settings;
|
||||
}
|
||||
|
||||
private AppConfig CloneAppConfig()
|
||||
{
|
||||
return new AppConfig
|
||||
{
|
||||
AppDataFolder = appConfig.AppDataFolder,
|
||||
ApplicationStartTime = appConfig.ApplicationStartTime,
|
||||
BrowserCachePath = appConfig.BrowserCachePath,
|
||||
BrowserLogFile = appConfig.BrowserLogFile,
|
||||
ClientAddress = appConfig.ClientAddress,
|
||||
ClientExecutablePath = appConfig.ClientExecutablePath,
|
||||
ClientId = appConfig.ClientId,
|
||||
ClientLogFile = appConfig.ClientLogFile,
|
||||
ConfigurationFileExtension = appConfig.ConfigurationFileExtension,
|
||||
DefaultSettingsFileName = appConfig.DefaultSettingsFileName,
|
||||
DownloadDirectory = appConfig.DownloadDirectory,
|
||||
LogLevel = appConfig.LogLevel,
|
||||
ProgramCopyright = appConfig.ProgramCopyright,
|
||||
ProgramDataFolder = appConfig.ProgramDataFolder,
|
||||
ProgramTitle = appConfig.ProgramTitle,
|
||||
ProgramVersion = appConfig.ProgramVersion,
|
||||
RuntimeAddress = appConfig.RuntimeAddress,
|
||||
RuntimeId = appConfig.RuntimeId,
|
||||
RuntimeLogFile = appConfig.RuntimeLogFile,
|
||||
SebUriScheme = appConfig.SebUriScheme,
|
||||
SebUriSchemeSecure = appConfig.SebUriSchemeSecure,
|
||||
ServiceAddress = appConfig.ServiceAddress
|
||||
};
|
||||
}
|
||||
|
||||
private void UpdateAppConfig()
|
||||
{
|
||||
AppConfig.ClientId = Guid.NewGuid();
|
||||
AppConfig.ClientAddress = $"{BASE_ADDRESS}/client/{Guid.NewGuid()}";
|
||||
appConfig.ClientId = Guid.NewGuid();
|
||||
appConfig.ClientAddress = $"{BASE_ADDRESS}/client/{Guid.NewGuid()}";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,7 +15,7 @@ namespace SafeExamBrowser.Configuration
|
|||
{
|
||||
public bool IsHtmlResource(Uri resource)
|
||||
{
|
||||
// TODO
|
||||
// TODO: Implement resource loader
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -53,9 +53,9 @@
|
|||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="ResourceLoader.cs" />
|
||||
<Compile Include="SessionData.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
<Compile Include="ConfigurationRepository.cs" />
|
||||
<Compile Include="SessionConfiguration.cs" />
|
||||
<Compile Include="SystemInfo.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
|
|
|
@ -7,19 +7,16 @@
|
|||
*/
|
||||
|
||||
using System;
|
||||
using SafeExamBrowser.Contracts.Communication.Proxies;
|
||||
using SafeExamBrowser.Contracts.Configuration;
|
||||
using SafeExamBrowser.Contracts.WindowsApi;
|
||||
using SafeExamBrowser.Contracts.Configuration.Settings;
|
||||
|
||||
namespace SafeExamBrowser.Configuration
|
||||
{
|
||||
public class SessionData : ISessionData
|
||||
internal class SessionConfiguration : ISessionConfiguration
|
||||
{
|
||||
public IClientProxy ClientProxy { get; set; }
|
||||
public IProcess ClientProcess { get; set; }
|
||||
public AppConfig AppConfig { get; set; }
|
||||
public Guid Id { get; set; }
|
||||
public IDesktop NewDesktop { get; set; }
|
||||
public IDesktop OriginalDesktop { get; set; }
|
||||
public Settings Settings { get; set; }
|
||||
public Guid StartupToken { get; set; }
|
||||
}
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
/*
|
||||
* 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.Configuration;
|
||||
|
||||
namespace SafeExamBrowser.Contracts.Communication.Events
|
||||
{
|
||||
/// <summary>
|
||||
/// The event arguments used for the client configuration event fired by the <see cref="Hosts.IRuntimeHost"/>.
|
||||
/// </summary>
|
||||
public class ClientConfigurationEventArgs : CommunicationEventArgs
|
||||
{
|
||||
/// <summary>
|
||||
/// The configuration to be sent to the client.
|
||||
/// </summary>
|
||||
public ClientConfiguration ClientConfiguration { get; set; }
|
||||
}
|
||||
}
|
|
@ -31,6 +31,11 @@ namespace SafeExamBrowser.Contracts.Communication.Hosts
|
|||
/// </summary>
|
||||
event CommunicationEventHandler ClientReady;
|
||||
|
||||
/// <summary>
|
||||
/// Event fired when the client requested its configuration data.
|
||||
/// </summary>
|
||||
event CommunicationEventHandler<ClientConfigurationEventArgs> ClientConfigurationNeeded;
|
||||
|
||||
/// <summary>
|
||||
/// Event fired when the client submitted a password entered by the user.
|
||||
/// </summary>
|
||||
|
|
|
@ -16,46 +16,25 @@ namespace SafeExamBrowser.Contracts.Configuration
|
|||
public interface IConfigurationRepository
|
||||
{
|
||||
/// <summary>
|
||||
/// The global configuration information for the currently running application instance.
|
||||
/// Initializes the global configuration information for the currently running application instance.
|
||||
/// </summary>
|
||||
AppConfig AppConfig { get; }
|
||||
AppConfig InitializeAppConfig();
|
||||
|
||||
/// <summary>
|
||||
/// 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>!
|
||||
/// Initializes all relevant configuration data for a new session.
|
||||
/// </summary>
|
||||
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
|
||||
/// be <c>null</c>!
|
||||
/// </summary>
|
||||
Settings.Settings CurrentSettings { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The path of the settings file to be used when reconfiguring the application.
|
||||
/// </summary>
|
||||
string ReconfigurationFilePath { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Builds a configuration for the client component, given the currently loaded settings, session and runtime information.
|
||||
/// </summary>
|
||||
ClientConfiguration BuildClientConfiguration();
|
||||
|
||||
/// <summary>
|
||||
/// Initializes all relevant data for a new session.
|
||||
/// </summary>
|
||||
void InitializeSessionConfiguration();
|
||||
ISessionConfiguration InitializeSessionConfiguration();
|
||||
|
||||
/// <summary>
|
||||
/// Attempts to load settings from the specified resource, using the optional passwords. Returns a <see cref="LoadStatus"/>
|
||||
/// indicating the result of the operation.
|
||||
/// indicating the result of the operation. As long as the result is not <see cref="LoadStatus.Success"/>, the declared
|
||||
/// <paramref name="settings"/> will be <c>null</c>!
|
||||
/// </summary>
|
||||
LoadStatus LoadSettings(Uri resource, string adminPassword = null, string settingsPassword = null);
|
||||
LoadStatus TryLoadSettings(Uri resource, out Settings.Settings settings, string adminPassword = null, string settingsPassword = null);
|
||||
|
||||
/// <summary>
|
||||
/// Loads the default settings.
|
||||
/// </summary>
|
||||
void LoadDefaultSettings();
|
||||
Settings.Settings LoadDefaultSettings();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,38 @@
|
|||
/*
|
||||
* 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
|
||||
{
|
||||
/// <summary>
|
||||
/// Holds all session-related configuration data.
|
||||
/// </summary>
|
||||
public interface ISessionConfiguration
|
||||
{
|
||||
/// <summary>
|
||||
/// The active application configuration for this session.
|
||||
/// </summary>
|
||||
AppConfig AppConfig { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The unique session identifier.
|
||||
/// </summary>
|
||||
Guid Id { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The settings used for this session.
|
||||
/// </summary>
|
||||
Settings.Settings Settings { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The startup token used by the client and runtime components for initial authentication.
|
||||
/// </summary>
|
||||
Guid StartupToken { get; }
|
||||
}
|
||||
}
|
|
@ -1,50 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2018 ETH Zürich, Educational Development and Technology (LET)
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using SafeExamBrowser.Contracts.Communication.Proxies;
|
||||
using SafeExamBrowser.Contracts.WindowsApi;
|
||||
|
||||
namespace SafeExamBrowser.Contracts.Configuration
|
||||
{
|
||||
/// <summary>
|
||||
/// Holds all session-related configuration and runtime data.
|
||||
/// </summary>
|
||||
public interface ISessionData
|
||||
{
|
||||
/// <summary>
|
||||
/// The communication proxy for the client instance associated to this session.
|
||||
/// </summary>
|
||||
IClientProxy ClientProxy { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The process information of the client instance associated to this session.
|
||||
/// </summary>
|
||||
IProcess ClientProcess { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The unique session identifier.
|
||||
/// </summary>
|
||||
Guid Id { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The new desktop, if <see cref="Settings.KioskMode.CreateNewDesktop"/> is active for this session.
|
||||
/// </summary>
|
||||
IDesktop NewDesktop { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The original desktop, if <see cref="Settings.KioskMode.CreateNewDesktop"/> is active for this session.
|
||||
/// </summary>
|
||||
IDesktop OriginalDesktop { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The startup token used by the client and runtime components for initial authentication.
|
||||
/// </summary>
|
||||
Guid StartupToken { get; }
|
||||
}
|
||||
}
|
|
@ -52,6 +52,7 @@
|
|||
<Reference Include="System.ServiceModel" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="Communication\Events\ClientConfigurationEventArgs.cs" />
|
||||
<Compile Include="Core\Events\InstanceTerminatedEventHandler.cs" />
|
||||
<Compile Include="Core\Events\NameChangedEventHandler.cs" />
|
||||
<Compile Include="Core\IApplicationController.cs" />
|
||||
|
@ -109,7 +110,7 @@
|
|||
<Compile Include="Configuration\IResourceLoader.cs" />
|
||||
<Compile Include="Configuration\LoadStatus.cs" />
|
||||
<Compile Include="Configuration\AppConfig.cs" />
|
||||
<Compile Include="Configuration\ISessionData.cs" />
|
||||
<Compile Include="Configuration\ISessionConfiguration.cs" />
|
||||
<Compile Include="Configuration\Settings\ConfigurationMode.cs" />
|
||||
<Compile Include="Core\INotificationController.cs" />
|
||||
<Compile Include="Core\OperationModel\IOperation.cs" />
|
||||
|
|
|
@ -11,7 +11,6 @@ using SafeExamBrowser.Communication.Hosts;
|
|||
using SafeExamBrowser.Contracts.Communication.Data;
|
||||
using SafeExamBrowser.Contracts.Communication.Events;
|
||||
using SafeExamBrowser.Contracts.Communication.Hosts;
|
||||
using SafeExamBrowser.Contracts.Configuration;
|
||||
using SafeExamBrowser.Contracts.Logging;
|
||||
|
||||
namespace SafeExamBrowser.Runtime.Communication
|
||||
|
@ -19,24 +18,18 @@ namespace SafeExamBrowser.Runtime.Communication
|
|||
internal class RuntimeHost : BaseHost, IRuntimeHost
|
||||
{
|
||||
private bool allowConnection = true;
|
||||
private IConfigurationRepository configuration;
|
||||
|
||||
public Guid StartupToken { private get; set; }
|
||||
|
||||
public event CommunicationEventHandler ClientDisconnected;
|
||||
public event CommunicationEventHandler ClientReady;
|
||||
public event CommunicationEventHandler<ClientConfigurationEventArgs> ClientConfigurationNeeded;
|
||||
public event CommunicationEventHandler<PasswordReplyEventArgs> PasswordReceived;
|
||||
public event CommunicationEventHandler<ReconfigurationEventArgs> ReconfigurationRequested;
|
||||
public event CommunicationEventHandler ShutdownRequested;
|
||||
|
||||
public RuntimeHost(
|
||||
string address,
|
||||
IConfigurationRepository configuration,
|
||||
IHostObjectFactory factory,
|
||||
ILogger logger,
|
||||
int timeout_ms) : base(address, factory, logger, timeout_ms)
|
||||
public RuntimeHost(string address, IHostObjectFactory factory, ILogger logger, int timeout_ms) : base(address, factory, logger, timeout_ms)
|
||||
{
|
||||
this.configuration = configuration;
|
||||
}
|
||||
|
||||
protected override bool OnConnect(Guid? token = null)
|
||||
|
@ -87,8 +80,7 @@ namespace SafeExamBrowser.Runtime.Communication
|
|||
ClientReady?.Invoke();
|
||||
return new SimpleResponse(SimpleResponsePurport.Acknowledged);
|
||||
case SimpleMessagePurport.ConfigurationNeeded:
|
||||
// TODO: Not the job of the host, fire event or alike!
|
||||
return new ConfigurationResponse { Configuration = configuration.BuildClientConfiguration() };
|
||||
return HandleConfigurationRequest();
|
||||
case SimpleMessagePurport.RequestShutdown:
|
||||
ShutdownRequested?.Invoke();
|
||||
return new SimpleResponse(SimpleResponsePurport.Acknowledged);
|
||||
|
@ -96,5 +88,14 @@ namespace SafeExamBrowser.Runtime.Communication
|
|||
|
||||
return new SimpleResponse(SimpleResponsePurport.UnknownMessage);
|
||||
}
|
||||
|
||||
private Response HandleConfigurationRequest()
|
||||
{
|
||||
var args = new ClientConfigurationEventArgs();
|
||||
|
||||
ClientConfigurationNeeded?.Invoke(args);
|
||||
|
||||
return new ConfigurationResponse { Configuration = args.ClientConfiguration };
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -49,7 +49,7 @@ namespace SafeExamBrowser.Runtime
|
|||
var nativeMethods = new NativeMethods();
|
||||
|
||||
logger = new Logger();
|
||||
appConfig = configuration.AppConfig;
|
||||
appConfig = configuration.InitializeAppConfig();
|
||||
systemInfo = new SystemInfo();
|
||||
|
||||
InitializeLogging();
|
||||
|
@ -61,8 +61,9 @@ namespace SafeExamBrowser.Runtime
|
|||
var processFactory = new ProcessFactory(new ModuleLogger(logger, nameof(ProcessFactory)));
|
||||
var proxyFactory = new ProxyFactory(new ProxyObjectFactory(), logger);
|
||||
var resourceLoader = new ResourceLoader();
|
||||
var runtimeHost = new RuntimeHost(appConfig.RuntimeAddress, configuration, new HostObjectFactory(), new ModuleLogger(logger, nameof(RuntimeHost)), FIVE_SECONDS);
|
||||
var runtimeHost = new RuntimeHost(appConfig.RuntimeAddress, new HostObjectFactory(), new ModuleLogger(logger, nameof(RuntimeHost)), FIVE_SECONDS);
|
||||
var serviceProxy = new ServiceProxy(appConfig.ServiceAddress, new ProxyObjectFactory(), new ModuleLogger(logger, nameof(ServiceProxy)));
|
||||
var sessionContext = new SessionContext();
|
||||
var uiFactory = new UserInterfaceFactory(text);
|
||||
|
||||
var bootstrapOperations = new Queue<IOperation>();
|
||||
|
@ -71,18 +72,19 @@ namespace SafeExamBrowser.Runtime
|
|||
bootstrapOperations.Enqueue(new I18nOperation(logger, text, textResource));
|
||||
bootstrapOperations.Enqueue(new CommunicationHostOperation(runtimeHost, logger));
|
||||
|
||||
sessionOperations.Enqueue(new ConfigurationOperation(appConfig, configuration, logger, resourceLoader, args));
|
||||
sessionOperations.Enqueue(new ClientTerminationOperation(configuration, logger, processFactory, proxyFactory, runtimeHost, FIFTEEN_SECONDS));
|
||||
sessionOperations.Enqueue(new KioskModeTerminationOperation(configuration, desktopFactory, explorerShell, logger, processFactory));
|
||||
sessionOperations.Enqueue(new SessionInitializationOperation(configuration, logger, runtimeHost));
|
||||
sessionOperations.Enqueue(new ServiceOperation(configuration, logger, serviceProxy));
|
||||
sessionOperations.Enqueue(new KioskModeOperation(configuration, desktopFactory, explorerShell, logger, processFactory));
|
||||
sessionOperations.Enqueue(new ClientOperation(configuration, logger, processFactory, proxyFactory, runtimeHost, FIFTEEN_SECONDS));
|
||||
sessionOperations.Enqueue(new SessionInitializationOperation(configuration, logger, runtimeHost, sessionContext));
|
||||
sessionOperations.Enqueue(new ConfigurationOperation(args, configuration, logger, resourceLoader, sessionContext));
|
||||
sessionOperations.Enqueue(new ClientTerminationOperation(logger, processFactory, proxyFactory, runtimeHost, sessionContext, FIFTEEN_SECONDS));
|
||||
sessionOperations.Enqueue(new KioskModeTerminationOperation(desktopFactory, explorerShell, logger, processFactory, sessionContext));
|
||||
sessionOperations.Enqueue(new ServiceOperation(logger, serviceProxy, sessionContext));
|
||||
sessionOperations.Enqueue(new KioskModeOperation(desktopFactory, explorerShell, logger, processFactory, sessionContext));
|
||||
sessionOperations.Enqueue(new ClientOperation(logger, processFactory, proxyFactory, runtimeHost, sessionContext, FIFTEEN_SECONDS));
|
||||
sessionOperations.Enqueue(new SessionActivationOperation(logger, sessionContext));
|
||||
|
||||
var bootstrapSequence = new OperationSequence(logger, bootstrapOperations);
|
||||
var sessionSequence = new RepeatableOperationSequence(logger, sessionOperations);
|
||||
|
||||
RuntimeController = new RuntimeController(appConfig, configuration, logger, messageBox, bootstrapSequence, sessionSequence, runtimeHost, serviceProxy, shutdown, text, uiFactory);
|
||||
RuntimeController = new RuntimeController(appConfig, logger, messageBox, bootstrapSequence, sessionSequence, runtimeHost, serviceProxy, sessionContext, shutdown, text, uiFactory);
|
||||
}
|
||||
|
||||
internal void LogStartupInformation()
|
||||
|
@ -103,7 +105,7 @@ namespace SafeExamBrowser.Runtime
|
|||
logger?.Log($"# Application terminated at {DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")}");
|
||||
}
|
||||
|
||||
private ConfigurationRepository BuildConfigurationRepository()
|
||||
private IConfigurationRepository BuildConfigurationRepository()
|
||||
{
|
||||
var executable = Assembly.GetExecutingAssembly();
|
||||
var programCopyright = executable.GetCustomAttribute<AssemblyCopyrightAttribute>().Copyright;
|
||||
|
|
|
@ -10,7 +10,6 @@ using System.Threading;
|
|||
using SafeExamBrowser.Contracts.Communication.Events;
|
||||
using SafeExamBrowser.Contracts.Communication.Hosts;
|
||||
using SafeExamBrowser.Contracts.Communication.Proxies;
|
||||
using SafeExamBrowser.Contracts.Configuration;
|
||||
using SafeExamBrowser.Contracts.Core.OperationModel;
|
||||
using SafeExamBrowser.Contracts.Core.OperationModel.Events;
|
||||
using SafeExamBrowser.Contracts.I18n;
|
||||
|
@ -20,40 +19,38 @@ using SafeExamBrowser.Contracts.WindowsApi.Events;
|
|||
|
||||
namespace SafeExamBrowser.Runtime.Operations
|
||||
{
|
||||
internal class ClientOperation : IRepeatableOperation
|
||||
internal class ClientOperation : SessionOperation
|
||||
{
|
||||
private readonly int timeout_ms;
|
||||
|
||||
private IConfigurationRepository configuration;
|
||||
private ILogger logger;
|
||||
private IProcessFactory processFactory;
|
||||
private IProxyFactory proxyFactory;
|
||||
private IRuntimeHost runtimeHost;
|
||||
|
||||
public event ActionRequiredEventHandler ActionRequired { add { } remove { } }
|
||||
public event StatusChangedEventHandler StatusChanged;
|
||||
|
||||
private IProcess ClientProcess
|
||||
{
|
||||
get { return configuration.CurrentSession.ClientProcess; }
|
||||
set { configuration.CurrentSession.ClientProcess = value; }
|
||||
get { return Context.ClientProcess; }
|
||||
set { Context.ClientProcess = value; }
|
||||
}
|
||||
|
||||
private IClientProxy ClientProxy
|
||||
{
|
||||
get { return configuration.CurrentSession.ClientProxy; }
|
||||
set { configuration.CurrentSession.ClientProxy = value; }
|
||||
get { return Context.ClientProxy; }
|
||||
set { Context.ClientProxy = value; }
|
||||
}
|
||||
|
||||
public override event ActionRequiredEventHandler ActionRequired { add { } remove { } }
|
||||
public override event StatusChangedEventHandler StatusChanged;
|
||||
|
||||
public ClientOperation(
|
||||
IConfigurationRepository configuration,
|
||||
ILogger logger,
|
||||
IProcessFactory processFactory,
|
||||
IProxyFactory proxyFactory,
|
||||
IRuntimeHost runtimeHost,
|
||||
int timeout_ms)
|
||||
SessionContext sessionContext,
|
||||
int timeout_ms) : base(sessionContext)
|
||||
{
|
||||
this.configuration = configuration;
|
||||
this.logger = logger;
|
||||
this.processFactory = processFactory;
|
||||
this.proxyFactory = proxyFactory;
|
||||
|
@ -61,7 +58,7 @@ namespace SafeExamBrowser.Runtime.Operations
|
|||
this.timeout_ms = timeout_ms;
|
||||
}
|
||||
|
||||
public virtual OperationResult Perform()
|
||||
public override OperationResult Perform()
|
||||
{
|
||||
StatusChanged?.Invoke(TextKey.OperationStatus_StartClient);
|
||||
|
||||
|
@ -79,12 +76,12 @@ namespace SafeExamBrowser.Runtime.Operations
|
|||
return success ? OperationResult.Success : OperationResult.Failed;
|
||||
}
|
||||
|
||||
public virtual OperationResult Repeat()
|
||||
public override OperationResult Repeat()
|
||||
{
|
||||
return Perform();
|
||||
}
|
||||
|
||||
public virtual OperationResult Revert()
|
||||
public override OperationResult Revert()
|
||||
{
|
||||
var success = true;
|
||||
|
||||
|
@ -103,10 +100,10 @@ namespace SafeExamBrowser.Runtime.Operations
|
|||
var clientReadyEvent = new AutoResetEvent(false);
|
||||
var clientReadyEventHandler = new CommunicationEventHandler(() => clientReadyEvent.Set());
|
||||
|
||||
var clientExecutable = configuration.AppConfig.ClientExecutablePath;
|
||||
var clientLogFile = $"{'"' + configuration.AppConfig.ClientLogFile + '"'}";
|
||||
var hostUri = configuration.AppConfig.RuntimeAddress;
|
||||
var token = configuration.CurrentSession.StartupToken.ToString("D");
|
||||
var clientExecutable = Context.Next.AppConfig.ClientExecutablePath;
|
||||
var clientLogFile = $"{'"' + Context.Next.AppConfig.ClientLogFile + '"'}";
|
||||
var hostUri = Context.Next.AppConfig.RuntimeAddress;
|
||||
var token = Context.Next.StartupToken.ToString("D");
|
||||
|
||||
logger.Info("Starting new client process...");
|
||||
runtimeHost.ClientReady += clientReadyEventHandler;
|
||||
|
@ -124,9 +121,9 @@ namespace SafeExamBrowser.Runtime.Operations
|
|||
}
|
||||
|
||||
logger.Info("Client has been successfully started and initialized. Creating communication proxy for client host...");
|
||||
ClientProxy = proxyFactory.CreateClientProxy(configuration.AppConfig.ClientAddress);
|
||||
ClientProxy = proxyFactory.CreateClientProxy(Context.Next.AppConfig.ClientAddress);
|
||||
|
||||
if (!ClientProxy.Connect(configuration.CurrentSession.StartupToken))
|
||||
if (!ClientProxy.Connect(Context.Next.StartupToken))
|
||||
{
|
||||
logger.Error("Failed to connect to client!");
|
||||
|
||||
|
|
|
@ -8,22 +8,21 @@
|
|||
|
||||
using SafeExamBrowser.Contracts.Communication.Hosts;
|
||||
using SafeExamBrowser.Contracts.Communication.Proxies;
|
||||
using SafeExamBrowser.Contracts.Configuration;
|
||||
using SafeExamBrowser.Contracts.Core.OperationModel;
|
||||
using SafeExamBrowser.Contracts.Logging;
|
||||
using SafeExamBrowser.Contracts.WindowsApi;
|
||||
|
||||
namespace SafeExamBrowser.Runtime.Operations
|
||||
{
|
||||
internal class ClientTerminationOperation : ClientOperation, IRepeatableOperation
|
||||
internal class ClientTerminationOperation : ClientOperation
|
||||
{
|
||||
public ClientTerminationOperation(
|
||||
IConfigurationRepository configuration,
|
||||
ILogger logger,
|
||||
IProcessFactory processFactory,
|
||||
IProxyFactory proxyFactory,
|
||||
IRuntimeHost runtimeHost,
|
||||
int timeout_ms) : base(configuration, logger, processFactory, proxyFactory, runtimeHost, timeout_ms)
|
||||
SessionContext sessionContext,
|
||||
int timeout_ms) : base(logger, processFactory, proxyFactory, runtimeHost, sessionContext, timeout_ms)
|
||||
{
|
||||
}
|
||||
|
||||
|
|
|
@ -19,32 +19,30 @@ using SafeExamBrowser.Runtime.Operations.Events;
|
|||
|
||||
namespace SafeExamBrowser.Runtime.Operations
|
||||
{
|
||||
internal class ConfigurationOperation : IRepeatableOperation
|
||||
internal class ConfigurationOperation : SessionOperation
|
||||
{
|
||||
private string[] commandLineArgs;
|
||||
private IConfigurationRepository configuration;
|
||||
private ILogger logger;
|
||||
private IResourceLoader resourceLoader;
|
||||
private AppConfig appConfig;
|
||||
private string[] commandLineArgs;
|
||||
|
||||
public event ActionRequiredEventHandler ActionRequired;
|
||||
public event StatusChangedEventHandler StatusChanged;
|
||||
public override event ActionRequiredEventHandler ActionRequired;
|
||||
public override event StatusChangedEventHandler StatusChanged;
|
||||
|
||||
public ConfigurationOperation(
|
||||
AppConfig appConfig,
|
||||
string[] commandLineArgs,
|
||||
IConfigurationRepository configuration,
|
||||
ILogger logger,
|
||||
IResourceLoader resourceLoader,
|
||||
string[] commandLineArgs)
|
||||
SessionContext sessionContext) : base(sessionContext)
|
||||
{
|
||||
this.appConfig = appConfig;
|
||||
this.commandLineArgs = commandLineArgs;
|
||||
this.logger = logger;
|
||||
this.configuration = configuration;
|
||||
this.resourceLoader = resourceLoader;
|
||||
this.commandLineArgs = commandLineArgs;
|
||||
}
|
||||
|
||||
public OperationResult Perform()
|
||||
public override OperationResult Perform()
|
||||
{
|
||||
logger.Info("Initializing application configuration...");
|
||||
StatusChanged?.Invoke(TextKey.OperationStatus_InitializeConfiguration);
|
||||
|
@ -69,12 +67,12 @@ namespace SafeExamBrowser.Runtime.Operations
|
|||
return OperationResult.Success;
|
||||
}
|
||||
|
||||
public OperationResult Repeat()
|
||||
public override OperationResult Repeat()
|
||||
{
|
||||
logger.Info("Initializing new application configuration...");
|
||||
StatusChanged?.Invoke(TextKey.OperationStatus_InitializeConfiguration);
|
||||
|
||||
var isValidUri = TryValidateSettingsUri(configuration.ReconfigurationFilePath, out Uri uri);
|
||||
var isValidUri = TryValidateSettingsUri(Context.ReconfigurationFilePath, out Uri uri);
|
||||
|
||||
if (isValidUri)
|
||||
{
|
||||
|
@ -92,7 +90,7 @@ namespace SafeExamBrowser.Runtime.Operations
|
|||
return OperationResult.Failed;
|
||||
}
|
||||
|
||||
public OperationResult Revert()
|
||||
public override OperationResult Revert()
|
||||
{
|
||||
return OperationResult.Success;
|
||||
}
|
||||
|
@ -101,11 +99,12 @@ namespace SafeExamBrowser.Runtime.Operations
|
|||
{
|
||||
var adminPassword = default(string);
|
||||
var settingsPassword = default(string);
|
||||
var settings = default(Settings);
|
||||
var status = default(LoadStatus);
|
||||
|
||||
for (int adminAttempts = 0, settingsAttempts = 0; adminAttempts < 5 && settingsAttempts < 5;)
|
||||
{
|
||||
status = configuration.LoadSettings(uri, adminPassword, settingsPassword);
|
||||
status = configuration.TryLoadSettings(uri, out settings, adminPassword, settingsPassword);
|
||||
|
||||
if (status == LoadStatus.AdminPasswordNeeded || status == LoadStatus.SettingsPasswordNeeded)
|
||||
{
|
||||
|
@ -132,7 +131,15 @@ namespace SafeExamBrowser.Runtime.Operations
|
|||
HandleInvalidData(ref status, uri);
|
||||
}
|
||||
|
||||
return status == LoadStatus.Success ? OperationResult.Success : OperationResult.Failed;
|
||||
if (status == LoadStatus.Success)
|
||||
{
|
||||
Context.Next.Settings = settings;
|
||||
|
||||
return OperationResult.Success;
|
||||
}
|
||||
|
||||
|
||||
return OperationResult.Failed;
|
||||
}
|
||||
|
||||
private PasswordRequiredEventArgs TryGetPassword(LoadStatus status)
|
||||
|
@ -150,7 +157,7 @@ namespace SafeExamBrowser.Runtime.Operations
|
|||
if (resourceLoader.IsHtmlResource(uri))
|
||||
{
|
||||
configuration.LoadDefaultSettings();
|
||||
configuration.CurrentSettings.Browser.StartUrl = uri.AbsoluteUri;
|
||||
Context.Next.Settings.Browser.StartUrl = uri.AbsoluteUri;
|
||||
logger.Info($"The specified URI '{uri.AbsoluteUri}' appears to point to a HTML resource, setting it as startup URL.");
|
||||
|
||||
status = LoadStatus.Success;
|
||||
|
@ -165,8 +172,8 @@ namespace SafeExamBrowser.Runtime.Operations
|
|||
{
|
||||
var path = string.Empty;
|
||||
var isValidUri = false;
|
||||
var programDataSettings = Path.Combine(appConfig.ProgramDataFolder, appConfig.DefaultSettingsFileName);
|
||||
var appDataSettings = Path.Combine(appConfig.AppDataFolder, appConfig.DefaultSettingsFileName);
|
||||
var programDataSettings = Path.Combine(Context.Next.AppConfig.ProgramDataFolder, Context.Next.AppConfig.DefaultSettingsFileName);
|
||||
var appDataSettings = Path.Combine(Context.Next.AppConfig.AppDataFolder, Context.Next.AppConfig.DefaultSettingsFileName);
|
||||
|
||||
uri = null;
|
||||
|
||||
|
@ -206,7 +213,7 @@ namespace SafeExamBrowser.Runtime.Operations
|
|||
|
||||
private void HandleClientConfiguration(ref OperationResult result)
|
||||
{
|
||||
if (result == OperationResult.Success && configuration.CurrentSettings.ConfigurationMode == ConfigurationMode.ConfigureClient)
|
||||
if (result == OperationResult.Success && Context.Next.Settings.ConfigurationMode == ConfigurationMode.ConfigureClient)
|
||||
{
|
||||
var args = new ConfigurationCompletedEventArgs();
|
||||
|
||||
|
|
|
@ -6,7 +6,6 @@
|
|||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
using SafeExamBrowser.Contracts.Configuration;
|
||||
using SafeExamBrowser.Contracts.Configuration.Settings;
|
||||
using SafeExamBrowser.Contracts.Core.OperationModel;
|
||||
using SafeExamBrowser.Contracts.Core.OperationModel.Events;
|
||||
|
@ -16,52 +15,40 @@ using SafeExamBrowser.Contracts.WindowsApi;
|
|||
|
||||
namespace SafeExamBrowser.Runtime.Operations
|
||||
{
|
||||
internal class KioskModeOperation : IRepeatableOperation
|
||||
internal class KioskModeOperation : SessionOperation
|
||||
{
|
||||
private IConfigurationRepository configuration;
|
||||
private IDesktopFactory desktopFactory;
|
||||
private IExplorerShell explorerShell;
|
||||
private KioskMode kioskMode;
|
||||
private ILogger logger;
|
||||
private IProcessFactory processFactory;
|
||||
protected IDesktopFactory desktopFactory;
|
||||
protected IExplorerShell explorerShell;
|
||||
protected ILogger logger;
|
||||
protected IProcessFactory processFactory;
|
||||
|
||||
public event ActionRequiredEventHandler ActionRequired { add { } remove { } }
|
||||
public event StatusChangedEventHandler StatusChanged;
|
||||
private static IDesktop newDesktop;
|
||||
private static IDesktop originalDesktop;
|
||||
|
||||
private IDesktop NewDesktop
|
||||
{
|
||||
get { return configuration.CurrentSession.NewDesktop; }
|
||||
set { configuration.CurrentSession.NewDesktop = value; }
|
||||
}
|
||||
protected static KioskMode? ActiveMode { get; private set; }
|
||||
|
||||
private IDesktop OriginalDesktop
|
||||
{
|
||||
get { return configuration.CurrentSession.OriginalDesktop; }
|
||||
set { configuration.CurrentSession.OriginalDesktop = value; }
|
||||
}
|
||||
public override event ActionRequiredEventHandler ActionRequired { add { } remove { } }
|
||||
public override event StatusChangedEventHandler StatusChanged;
|
||||
|
||||
public KioskModeOperation(
|
||||
IConfigurationRepository configuration,
|
||||
IDesktopFactory desktopFactory,
|
||||
IExplorerShell explorerShell,
|
||||
ILogger logger,
|
||||
IProcessFactory processFactory)
|
||||
IProcessFactory processFactory,
|
||||
SessionContext sessionContext) : base(sessionContext)
|
||||
{
|
||||
this.configuration = configuration;
|
||||
this.desktopFactory = desktopFactory;
|
||||
this.explorerShell = explorerShell;
|
||||
this.logger = logger;
|
||||
this.processFactory = processFactory;
|
||||
}
|
||||
|
||||
public virtual OperationResult Perform()
|
||||
public override OperationResult Perform()
|
||||
{
|
||||
kioskMode = configuration.CurrentSettings.KioskMode;
|
||||
|
||||
logger.Info($"Initializing kiosk mode '{kioskMode}'...");
|
||||
logger.Info($"Initializing kiosk mode '{Context.Next.Settings.KioskMode}'...");
|
||||
StatusChanged?.Invoke(TextKey.OperationStatus_InitializeKioskMode);
|
||||
|
||||
switch (kioskMode)
|
||||
switch (Context.Next.Settings.KioskMode)
|
||||
{
|
||||
case KioskMode.CreateNewDesktop:
|
||||
CreateNewDesktop();
|
||||
|
@ -71,17 +58,18 @@ namespace SafeExamBrowser.Runtime.Operations
|
|||
break;
|
||||
}
|
||||
|
||||
ActiveMode = Context.Next.Settings.KioskMode;
|
||||
|
||||
return OperationResult.Success;
|
||||
}
|
||||
|
||||
public virtual OperationResult Repeat()
|
||||
public override OperationResult Repeat()
|
||||
{
|
||||
var oldMode = kioskMode;
|
||||
var newMode = configuration.CurrentSettings.KioskMode;
|
||||
var newMode = Context.Next.Settings.KioskMode;
|
||||
|
||||
if (newMode == oldMode)
|
||||
if (ActiveMode == newMode)
|
||||
{
|
||||
logger.Info($"New kiosk mode '{newMode}' is equal to the currently active '{oldMode}', skipping re-initialization...");
|
||||
logger.Info($"New kiosk mode '{newMode}' is already active, skipping initialization...");
|
||||
|
||||
return OperationResult.Success;
|
||||
}
|
||||
|
@ -89,12 +77,12 @@ namespace SafeExamBrowser.Runtime.Operations
|
|||
return Perform();
|
||||
}
|
||||
|
||||
public virtual OperationResult Revert()
|
||||
public override OperationResult Revert()
|
||||
{
|
||||
logger.Info($"Reverting kiosk mode '{kioskMode}'...");
|
||||
logger.Info($"Reverting kiosk mode '{ActiveMode}'...");
|
||||
StatusChanged?.Invoke(TextKey.OperationStatus_RevertKioskMode);
|
||||
|
||||
switch (kioskMode)
|
||||
switch (ActiveMode)
|
||||
{
|
||||
case KioskMode.CreateNewDesktop:
|
||||
CloseNewDesktop();
|
||||
|
@ -109,14 +97,14 @@ namespace SafeExamBrowser.Runtime.Operations
|
|||
|
||||
private void CreateNewDesktop()
|
||||
{
|
||||
OriginalDesktop = desktopFactory.GetCurrent();
|
||||
logger.Info($"Current desktop is {OriginalDesktop}.");
|
||||
originalDesktop = desktopFactory.GetCurrent();
|
||||
logger.Info($"Current desktop is {originalDesktop}.");
|
||||
|
||||
NewDesktop = desktopFactory.CreateNew(nameof(SafeExamBrowser));
|
||||
logger.Info($"Created new desktop {NewDesktop}.");
|
||||
newDesktop = desktopFactory.CreateNew(nameof(SafeExamBrowser));
|
||||
logger.Info($"Created new desktop {newDesktop}.");
|
||||
|
||||
NewDesktop.Activate();
|
||||
processFactory.StartupDesktop = NewDesktop;
|
||||
newDesktop.Activate();
|
||||
processFactory.StartupDesktop = newDesktop;
|
||||
logger.Info("Successfully activated new desktop.");
|
||||
|
||||
explorerShell.Suspend();
|
||||
|
@ -124,21 +112,21 @@ namespace SafeExamBrowser.Runtime.Operations
|
|||
|
||||
private void CloseNewDesktop()
|
||||
{
|
||||
if (OriginalDesktop != null)
|
||||
if (originalDesktop != null)
|
||||
{
|
||||
OriginalDesktop.Activate();
|
||||
processFactory.StartupDesktop = OriginalDesktop;
|
||||
logger.Info($"Switched back to original desktop {OriginalDesktop}.");
|
||||
originalDesktop.Activate();
|
||||
processFactory.StartupDesktop = originalDesktop;
|
||||
logger.Info($"Switched back to original desktop {originalDesktop}.");
|
||||
}
|
||||
else
|
||||
{
|
||||
logger.Warn($"No original desktop found when attempting to close new desktop!");
|
||||
}
|
||||
|
||||
if (NewDesktop != null)
|
||||
if (newDesktop != null)
|
||||
{
|
||||
NewDesktop.Close();
|
||||
logger.Info($"Closed new desktop {NewDesktop}.");
|
||||
newDesktop.Close();
|
||||
logger.Info($"Closed new desktop {newDesktop}.");
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -151,6 +139,9 @@ namespace SafeExamBrowser.Runtime.Operations
|
|||
private void TerminateExplorerShell()
|
||||
{
|
||||
StatusChanged?.Invoke(TextKey.OperationStatus_WaitExplorerTermination);
|
||||
|
||||
// TODO: Hiding all windows must be done here, as the explorer shell is needed to do so!
|
||||
|
||||
explorerShell.Terminate();
|
||||
}
|
||||
|
||||
|
@ -158,6 +149,8 @@ namespace SafeExamBrowser.Runtime.Operations
|
|||
{
|
||||
StatusChanged?.Invoke(TextKey.OperationStatus_WaitExplorerStartup);
|
||||
explorerShell.Start();
|
||||
|
||||
// TODO: Restore all hidden windows!
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,8 +6,6 @@
|
|||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
using SafeExamBrowser.Contracts.Configuration;
|
||||
using SafeExamBrowser.Contracts.Configuration.Settings;
|
||||
using SafeExamBrowser.Contracts.Core.OperationModel;
|
||||
using SafeExamBrowser.Contracts.Logging;
|
||||
using SafeExamBrowser.Contracts.WindowsApi;
|
||||
|
@ -16,36 +14,27 @@ namespace SafeExamBrowser.Runtime.Operations
|
|||
{
|
||||
internal class KioskModeTerminationOperation : KioskModeOperation, IRepeatableOperation
|
||||
{
|
||||
private IConfigurationRepository configuration;
|
||||
private KioskMode kioskMode;
|
||||
private ILogger logger;
|
||||
|
||||
public KioskModeTerminationOperation(
|
||||
IConfigurationRepository configuration,
|
||||
IDesktopFactory desktopFactory,
|
||||
IExplorerShell explorerShell,
|
||||
ILogger logger,
|
||||
IProcessFactory processFactory) : base(configuration, desktopFactory, explorerShell, logger, processFactory)
|
||||
IProcessFactory processFactory,
|
||||
SessionContext sessionContext) : base(desktopFactory, explorerShell, logger, processFactory, sessionContext)
|
||||
{
|
||||
this.configuration = configuration;
|
||||
this.logger = logger;
|
||||
}
|
||||
|
||||
public override OperationResult Perform()
|
||||
{
|
||||
kioskMode = configuration.CurrentSettings.KioskMode;
|
||||
|
||||
return OperationResult.Success;
|
||||
}
|
||||
|
||||
public override OperationResult Repeat()
|
||||
{
|
||||
var oldMode = kioskMode;
|
||||
var newMode = configuration.CurrentSettings.KioskMode;
|
||||
var newMode = Context.Next.Settings.KioskMode;
|
||||
|
||||
if (newMode == oldMode)
|
||||
if (ActiveMode == newMode)
|
||||
{
|
||||
logger.Info($"New kiosk mode '{newMode}' is equal to the currently active '{oldMode}', skipping termination...");
|
||||
logger.Info($"New kiosk mode '{newMode}' is the same as the currently active, skipping termination...");
|
||||
|
||||
return OperationResult.Success;
|
||||
}
|
||||
|
|
|
@ -7,7 +7,6 @@
|
|||
*/
|
||||
|
||||
using SafeExamBrowser.Contracts.Communication.Proxies;
|
||||
using SafeExamBrowser.Contracts.Configuration;
|
||||
using SafeExamBrowser.Contracts.Configuration.Settings;
|
||||
using SafeExamBrowser.Contracts.Core.OperationModel;
|
||||
using SafeExamBrowser.Contracts.Core.OperationModel.Events;
|
||||
|
@ -16,29 +15,27 @@ using SafeExamBrowser.Contracts.Logging;
|
|||
|
||||
namespace SafeExamBrowser.Runtime.Operations
|
||||
{
|
||||
internal class ServiceOperation : IRepeatableOperation
|
||||
internal class ServiceOperation : SessionOperation
|
||||
{
|
||||
private bool connected, mandatory;
|
||||
private IConfigurationRepository configuration;
|
||||
private ILogger logger;
|
||||
private IServiceProxy service;
|
||||
|
||||
public event ActionRequiredEventHandler ActionRequired { add { } remove { } }
|
||||
public event StatusChangedEventHandler StatusChanged;
|
||||
public override event ActionRequiredEventHandler ActionRequired { add { } remove { } }
|
||||
public override event StatusChangedEventHandler StatusChanged;
|
||||
|
||||
public ServiceOperation(IConfigurationRepository configuration, ILogger logger, IServiceProxy service)
|
||||
public ServiceOperation(ILogger logger, IServiceProxy service, SessionContext sessionContext) : base(sessionContext)
|
||||
{
|
||||
this.configuration = configuration;
|
||||
this.service = service;
|
||||
this.logger = logger;
|
||||
this.service = service;
|
||||
}
|
||||
|
||||
public OperationResult Perform()
|
||||
public override OperationResult Perform()
|
||||
{
|
||||
logger.Info($"Initializing service session...");
|
||||
StatusChanged?.Invoke(TextKey.OperationStatus_InitializeServiceSession);
|
||||
|
||||
mandatory = configuration.CurrentSettings.ServicePolicy == ServicePolicy.Mandatory;
|
||||
mandatory = Context.Next.Settings.ServicePolicy == ServicePolicy.Mandatory;
|
||||
connected = service.Connect();
|
||||
|
||||
if (mandatory && !connected)
|
||||
|
@ -59,7 +56,7 @@ namespace SafeExamBrowser.Runtime.Operations
|
|||
return OperationResult.Success;
|
||||
}
|
||||
|
||||
public OperationResult Repeat()
|
||||
public override OperationResult Repeat()
|
||||
{
|
||||
var result = Revert();
|
||||
|
||||
|
@ -71,7 +68,7 @@ namespace SafeExamBrowser.Runtime.Operations
|
|||
return Perform();
|
||||
}
|
||||
|
||||
public OperationResult Revert()
|
||||
public override OperationResult Revert()
|
||||
{
|
||||
logger.Info("Finalizing service session...");
|
||||
StatusChanged?.Invoke(TextKey.OperationStatus_FinalizeServiceSession);
|
||||
|
@ -97,12 +94,12 @@ namespace SafeExamBrowser.Runtime.Operations
|
|||
|
||||
private void StartServiceSession()
|
||||
{
|
||||
service.StartSession(configuration.CurrentSession.Id, configuration.CurrentSettings);
|
||||
service.StartSession(Context.Next.Id, Context.Next.Settings);
|
||||
}
|
||||
|
||||
private void StopServiceSession()
|
||||
{
|
||||
service.StopSession(configuration.CurrentSession.Id);
|
||||
service.StopSession(Context.Current.Id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,63 @@
|
|||
/*
|
||||
* 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.Core.OperationModel;
|
||||
using SafeExamBrowser.Contracts.Core.OperationModel.Events;
|
||||
using SafeExamBrowser.Contracts.Logging;
|
||||
|
||||
namespace SafeExamBrowser.Runtime.Operations
|
||||
{
|
||||
internal class SessionActivationOperation : SessionOperation
|
||||
{
|
||||
private ILogger logger;
|
||||
|
||||
public override event ActionRequiredEventHandler ActionRequired { add { } remove { } }
|
||||
public override event StatusChangedEventHandler StatusChanged { add { } remove { } }
|
||||
|
||||
public SessionActivationOperation(ILogger logger, SessionContext sessionContext) : base(sessionContext)
|
||||
{
|
||||
this.logger = logger;
|
||||
}
|
||||
|
||||
public override OperationResult Perform()
|
||||
{
|
||||
ActivateNewSession();
|
||||
|
||||
return OperationResult.Success;
|
||||
}
|
||||
|
||||
public override OperationResult Repeat()
|
||||
{
|
||||
ActivateNewSession();
|
||||
|
||||
return OperationResult.Success;
|
||||
}
|
||||
|
||||
public override OperationResult Revert()
|
||||
{
|
||||
return OperationResult.Success;
|
||||
}
|
||||
|
||||
private void ActivateNewSession()
|
||||
{
|
||||
var isFirstSession = Context.Current == null;
|
||||
|
||||
if (isFirstSession)
|
||||
{
|
||||
logger.Info($"Successfully activated first session '{Context.Next.Id}'.");
|
||||
}
|
||||
else
|
||||
{
|
||||
logger.Info($"Successfully terminated old session '{Context.Current.Id}' and activated new session '{Context.Next.Id}'.");
|
||||
}
|
||||
|
||||
Context.Current = Context.Next;
|
||||
Context.Next = null;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -15,35 +15,41 @@ using SafeExamBrowser.Contracts.Logging;
|
|||
|
||||
namespace SafeExamBrowser.Runtime.Operations
|
||||
{
|
||||
internal class SessionInitializationOperation : IRepeatableOperation
|
||||
internal class SessionInitializationOperation : SessionOperation
|
||||
{
|
||||
private IConfigurationRepository configuration;
|
||||
private ILogger logger;
|
||||
private IRuntimeHost runtimeHost;
|
||||
|
||||
public event ActionRequiredEventHandler ActionRequired { add { } remove { } }
|
||||
public event StatusChangedEventHandler StatusChanged;
|
||||
public override event ActionRequiredEventHandler ActionRequired { add { } remove { } }
|
||||
public override event StatusChangedEventHandler StatusChanged;
|
||||
|
||||
public SessionInitializationOperation(IConfigurationRepository configuration, ILogger logger, IRuntimeHost runtimeHost)
|
||||
public SessionInitializationOperation(
|
||||
IConfigurationRepository configuration,
|
||||
ILogger logger,
|
||||
IRuntimeHost runtimeHost,
|
||||
SessionContext sessionContext) : base(sessionContext)
|
||||
{
|
||||
this.configuration = configuration;
|
||||
this.logger = logger;
|
||||
this.runtimeHost = runtimeHost;
|
||||
}
|
||||
|
||||
public OperationResult Perform()
|
||||
public override OperationResult Perform()
|
||||
{
|
||||
InitializeSessionConfiguration();
|
||||
|
||||
return OperationResult.Success;
|
||||
}
|
||||
|
||||
public OperationResult Repeat()
|
||||
public override OperationResult Repeat()
|
||||
{
|
||||
return Perform();
|
||||
InitializeSessionConfiguration();
|
||||
|
||||
return OperationResult.Success;
|
||||
}
|
||||
|
||||
public OperationResult Revert()
|
||||
public override OperationResult Revert()
|
||||
{
|
||||
return OperationResult.Success;
|
||||
}
|
||||
|
@ -53,12 +59,12 @@ namespace SafeExamBrowser.Runtime.Operations
|
|||
logger.Info("Initializing new session configuration...");
|
||||
StatusChanged?.Invoke(TextKey.OperationStatus_InitializeSession);
|
||||
|
||||
configuration.InitializeSessionConfiguration();
|
||||
runtimeHost.StartupToken = configuration.CurrentSession.StartupToken;
|
||||
Context.Next = configuration.InitializeSessionConfiguration();
|
||||
runtimeHost.StartupToken = Context.Next.StartupToken;
|
||||
|
||||
logger.Info($" -> Client-ID: {configuration.AppConfig.ClientId}");
|
||||
logger.Info($" -> Runtime-ID: {configuration.AppConfig.RuntimeId}");
|
||||
logger.Info($" -> Session-ID: {configuration.CurrentSession.Id}");
|
||||
logger.Info($" -> Client-ID: {Context.Next.AppConfig.ClientId}");
|
||||
logger.Info($" -> Runtime-ID: {Context.Next.AppConfig.RuntimeId}");
|
||||
logger.Info($" -> Session-ID: {Context.Next.Id}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
25
SafeExamBrowser.Runtime/Operations/SessionOperation.cs
Normal file
25
SafeExamBrowser.Runtime/Operations/SessionOperation.cs
Normal file
|
@ -0,0 +1,25 @@
|
|||
using SafeExamBrowser.Contracts.Core.OperationModel;
|
||||
using SafeExamBrowser.Contracts.Core.OperationModel.Events;
|
||||
|
||||
namespace SafeExamBrowser.Runtime.Operations
|
||||
{
|
||||
/// <summary>
|
||||
/// The base implementation to be used for all operations in the session operation sequence.
|
||||
/// </summary>
|
||||
internal abstract class SessionOperation : IRepeatableOperation
|
||||
{
|
||||
protected SessionContext Context { get; private set; }
|
||||
|
||||
public abstract event ActionRequiredEventHandler ActionRequired;
|
||||
public abstract event StatusChangedEventHandler StatusChanged;
|
||||
|
||||
public SessionOperation(SessionContext sessionContext)
|
||||
{
|
||||
Context = sessionContext;
|
||||
}
|
||||
|
||||
public abstract OperationResult Perform();
|
||||
public abstract OperationResult Repeat();
|
||||
public abstract OperationResult Revert();
|
||||
}
|
||||
}
|
|
@ -28,10 +28,7 @@ namespace SafeExamBrowser.Runtime
|
|||
{
|
||||
internal class RuntimeController : IRuntimeController
|
||||
{
|
||||
private bool sessionRunning;
|
||||
|
||||
private AppConfig appConfig;
|
||||
private IConfigurationRepository configuration;
|
||||
private ILogger logger;
|
||||
private IMessageBox messageBox;
|
||||
private IOperationSequence bootstrapSequence;
|
||||
|
@ -39,32 +36,43 @@ namespace SafeExamBrowser.Runtime
|
|||
private IRuntimeHost runtimeHost;
|
||||
private IRuntimeWindow runtimeWindow;
|
||||
private IServiceProxy service;
|
||||
private SessionContext sessionContext;
|
||||
private ISplashScreen splashScreen;
|
||||
private Action shutdown;
|
||||
private IText text;
|
||||
private IUserInterfaceFactory uiFactory;
|
||||
|
||||
private ISessionConfiguration Session
|
||||
{
|
||||
get { return sessionContext.Current; }
|
||||
}
|
||||
|
||||
private bool SessionIsRunning
|
||||
{
|
||||
get { return Session != null; }
|
||||
}
|
||||
|
||||
public RuntimeController(
|
||||
AppConfig appConfig,
|
||||
IConfigurationRepository configuration,
|
||||
ILogger logger,
|
||||
IMessageBox messageBox,
|
||||
IOperationSequence bootstrapSequence,
|
||||
IRepeatableOperationSequence sessionSequence,
|
||||
IRuntimeHost runtimeHost,
|
||||
IServiceProxy service,
|
||||
SessionContext sessionContext,
|
||||
Action shutdown,
|
||||
IText text,
|
||||
IUserInterfaceFactory uiFactory)
|
||||
{
|
||||
this.appConfig = appConfig;
|
||||
this.configuration = configuration;
|
||||
this.bootstrapSequence = bootstrapSequence;
|
||||
this.logger = logger;
|
||||
this.messageBox = messageBox;
|
||||
this.runtimeHost = runtimeHost;
|
||||
this.sessionSequence = sessionSequence;
|
||||
this.service = service;
|
||||
this.sessionContext = sessionContext;
|
||||
this.shutdown = shutdown;
|
||||
this.text = text;
|
||||
this.uiFactory = uiFactory;
|
||||
|
@ -96,7 +104,7 @@ namespace SafeExamBrowser.Runtime
|
|||
logger.Subscribe(runtimeWindow);
|
||||
splashScreen.Close();
|
||||
|
||||
StartSession(true);
|
||||
StartSession();
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -106,14 +114,14 @@ namespace SafeExamBrowser.Runtime
|
|||
messageBox.Show(TextKey.MessageBox_StartupError, TextKey.MessageBox_StartupErrorTitle, icon: MessageBoxIcon.Error, parent: splashScreen);
|
||||
}
|
||||
|
||||
return initialized && sessionRunning;
|
||||
return initialized && SessionIsRunning;
|
||||
}
|
||||
|
||||
public void Terminate()
|
||||
{
|
||||
DeregisterEvents();
|
||||
|
||||
if (sessionRunning)
|
||||
if (SessionIsRunning)
|
||||
{
|
||||
StopSession();
|
||||
}
|
||||
|
@ -145,51 +153,79 @@ namespace SafeExamBrowser.Runtime
|
|||
splashScreen.Close();
|
||||
}
|
||||
|
||||
private void StartSession(bool initial = false)
|
||||
private void StartSession()
|
||||
{
|
||||
runtimeWindow.Show();
|
||||
runtimeWindow.BringToForeground();
|
||||
runtimeWindow.ShowProgressBar();
|
||||
logger.Info("### --- Session Start Procedure --- ###");
|
||||
|
||||
if (sessionRunning)
|
||||
if (SessionIsRunning)
|
||||
{
|
||||
DeregisterSessionEvents();
|
||||
}
|
||||
|
||||
var result = initial ? sessionSequence.TryPerform() : sessionSequence.TryRepeat();
|
||||
var result = SessionIsRunning ? sessionSequence.TryRepeat() : sessionSequence.TryPerform();
|
||||
|
||||
if (result == OperationResult.Success)
|
||||
{
|
||||
RegisterSessionEvents();
|
||||
|
||||
logger.Info("### --- Session Running --- ###");
|
||||
|
||||
HandleSessionStartSuccess();
|
||||
}
|
||||
else if (result == OperationResult.Failed)
|
||||
{
|
||||
logger.Info("### --- Session Start Failed --- ###");
|
||||
|
||||
HandleSessionStartFailure();
|
||||
}
|
||||
else if (result == OperationResult.Aborted)
|
||||
{
|
||||
logger.Info("### --- Session Start Aborted --- ###");
|
||||
|
||||
HandleSessionStartAbortion();
|
||||
}
|
||||
}
|
||||
|
||||
private void HandleSessionStartSuccess()
|
||||
{
|
||||
RegisterSessionEvents();
|
||||
|
||||
runtimeWindow.HideProgressBar();
|
||||
runtimeWindow.UpdateStatus(TextKey.RuntimeWindow_ApplicationRunning);
|
||||
runtimeWindow.TopMost = Session.Settings.KioskMode != KioskMode.None;
|
||||
|
||||
if (Session.Settings.KioskMode == KioskMode.DisableExplorerShell)
|
||||
{
|
||||
runtimeWindow.Hide();
|
||||
}
|
||||
}
|
||||
|
||||
private void HandleSessionStartFailure()
|
||||
{
|
||||
if (SessionIsRunning)
|
||||
{
|
||||
StopSession();
|
||||
|
||||
messageBox.Show(TextKey.MessageBox_SessionStartError, TextKey.MessageBox_SessionStartErrorTitle, icon: MessageBoxIcon.Error, parent: runtimeWindow);
|
||||
logger.Info("Terminating application...");
|
||||
|
||||
shutdown.Invoke();
|
||||
}
|
||||
}
|
||||
|
||||
private void HandleSessionStartAbortion()
|
||||
{
|
||||
if (SessionIsRunning)
|
||||
{
|
||||
runtimeWindow.HideProgressBar();
|
||||
runtimeWindow.UpdateStatus(TextKey.RuntimeWindow_ApplicationRunning);
|
||||
runtimeWindow.TopMost = configuration.CurrentSettings.KioskMode != KioskMode.None;
|
||||
runtimeWindow.TopMost = Session.Settings.KioskMode != KioskMode.None;
|
||||
|
||||
if (configuration.CurrentSettings.KioskMode == KioskMode.DisableExplorerShell)
|
||||
if (Session.Settings.KioskMode == KioskMode.DisableExplorerShell)
|
||||
{
|
||||
runtimeWindow.Hide();
|
||||
}
|
||||
|
||||
sessionRunning = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
logger.Info($"### --- Session Start {(result == OperationResult.Aborted ? "Aborted" : "Failed")} --- ###");
|
||||
|
||||
if (result == OperationResult.Failed)
|
||||
{
|
||||
// TODO: Find solution for this; maybe manually switch back to original desktop?
|
||||
// messageBox.Show(TextKey.MessageBox_SessionStartError, TextKey.MessageBox_SessionStartErrorTitle, icon: MessageBoxIcon.Error, parent: runtimeWindow);
|
||||
|
||||
if (!initial)
|
||||
{
|
||||
logger.Info("Terminating application...");
|
||||
shutdown.Invoke();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -207,7 +243,6 @@ namespace SafeExamBrowser.Runtime
|
|||
if (success)
|
||||
{
|
||||
logger.Info("### --- Session Terminated --- ###");
|
||||
sessionRunning = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -218,32 +253,34 @@ namespace SafeExamBrowser.Runtime
|
|||
|
||||
private void RegisterEvents()
|
||||
{
|
||||
runtimeHost.ClientConfigurationNeeded += RuntimeHost_ClientConfigurationNeeded;
|
||||
runtimeHost.ReconfigurationRequested += RuntimeHost_ReconfigurationRequested;
|
||||
runtimeHost.ShutdownRequested += RuntimeHost_ShutdownRequested;
|
||||
}
|
||||
|
||||
private void DeregisterEvents()
|
||||
{
|
||||
runtimeHost.ClientConfigurationNeeded -= RuntimeHost_ClientConfigurationNeeded;
|
||||
runtimeHost.ReconfigurationRequested -= RuntimeHost_ReconfigurationRequested;
|
||||
runtimeHost.ShutdownRequested -= RuntimeHost_ShutdownRequested;
|
||||
}
|
||||
|
||||
private void RegisterSessionEvents()
|
||||
{
|
||||
configuration.CurrentSession.ClientProcess.Terminated += ClientProcess_Terminated;
|
||||
configuration.CurrentSession.ClientProxy.ConnectionLost += Client_ConnectionLost;
|
||||
sessionContext.ClientProcess.Terminated += ClientProcess_Terminated;
|
||||
sessionContext.ClientProxy.ConnectionLost += Client_ConnectionLost;
|
||||
}
|
||||
|
||||
private void DeregisterSessionEvents()
|
||||
{
|
||||
if (configuration.CurrentSession.ClientProcess != null)
|
||||
if (sessionContext.ClientProcess != null)
|
||||
{
|
||||
configuration.CurrentSession.ClientProcess.Terminated -= ClientProcess_Terminated;
|
||||
sessionContext.ClientProcess.Terminated -= ClientProcess_Terminated;
|
||||
}
|
||||
|
||||
if (configuration.CurrentSession.ClientProxy != null)
|
||||
if (sessionContext.ClientProxy != null)
|
||||
{
|
||||
configuration.CurrentSession.ClientProxy.ConnectionLost -= Client_ConnectionLost;
|
||||
sessionContext.ClientProxy.ConnectionLost -= Client_ConnectionLost;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -261,7 +298,7 @@ namespace SafeExamBrowser.Runtime
|
|||
{
|
||||
logger.Error($"Client application has unexpectedly terminated with exit code {exitCode}!");
|
||||
|
||||
if (sessionRunning)
|
||||
if (SessionIsRunning)
|
||||
{
|
||||
StopSession();
|
||||
}
|
||||
|
@ -275,7 +312,7 @@ namespace SafeExamBrowser.Runtime
|
|||
{
|
||||
logger.Error("Lost connection to the client application!");
|
||||
|
||||
if (sessionRunning)
|
||||
if (SessionIsRunning)
|
||||
{
|
||||
StopSession();
|
||||
}
|
||||
|
@ -285,21 +322,31 @@ namespace SafeExamBrowser.Runtime
|
|||
shutdown.Invoke();
|
||||
}
|
||||
|
||||
private void RuntimeHost_ClientConfigurationNeeded(ClientConfigurationEventArgs args)
|
||||
{
|
||||
args.ClientConfiguration = new ClientConfiguration
|
||||
{
|
||||
AppConfig = sessionContext.Next.AppConfig,
|
||||
SessionId = sessionContext.Next.Id,
|
||||
Settings = sessionContext.Next.Settings
|
||||
};
|
||||
}
|
||||
|
||||
private void RuntimeHost_ReconfigurationRequested(ReconfigurationEventArgs args)
|
||||
{
|
||||
var mode = configuration.CurrentSettings.ConfigurationMode;
|
||||
var mode = Session.Settings.ConfigurationMode;
|
||||
|
||||
if (mode == ConfigurationMode.ConfigureClient)
|
||||
{
|
||||
logger.Info($"Accepted request for reconfiguration with '{args.ConfigurationPath}'.");
|
||||
configuration.ReconfigurationFilePath = args.ConfigurationPath;
|
||||
sessionContext.ReconfigurationFilePath = args.ConfigurationPath;
|
||||
|
||||
StartSession();
|
||||
}
|
||||
else
|
||||
{
|
||||
logger.Info($"Denied request for reconfiguration with '{args.ConfigurationPath}' due to '{mode}' mode!");
|
||||
configuration.CurrentSession.ClientProxy.InformReconfigurationDenied(args.ConfigurationPath);
|
||||
sessionContext.ClientProxy.InformReconfigurationDenied(args.ConfigurationPath);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -333,8 +380,8 @@ namespace SafeExamBrowser.Runtime
|
|||
|
||||
private void AskForPassword(PasswordRequiredEventArgs args)
|
||||
{
|
||||
var isStartup = configuration.CurrentSession == null;
|
||||
var isRunningOnDefaultDesktop = configuration.CurrentSettings?.KioskMode == KioskMode.DisableExplorerShell;
|
||||
var isStartup = !SessionIsRunning;
|
||||
var isRunningOnDefaultDesktop = SessionIsRunning && Session.Settings.KioskMode == KioskMode.DisableExplorerShell;
|
||||
|
||||
if (isStartup || isRunningOnDefaultDesktop)
|
||||
{
|
||||
|
@ -374,7 +421,7 @@ namespace SafeExamBrowser.Runtime
|
|||
|
||||
runtimeHost.PasswordReceived += responseEventHandler;
|
||||
|
||||
var communication = configuration.CurrentSession.ClientProxy.RequestPassword(args.Purpose, requestId);
|
||||
var communication = sessionContext.ClientProxy.RequestPassword(args.Purpose, requestId);
|
||||
|
||||
if (communication.Success)
|
||||
{
|
||||
|
@ -401,6 +448,9 @@ namespace SafeExamBrowser.Runtime
|
|||
runtimeWindow?.UpdateStatus(status, true);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// TODO: Move to utility in core library and use in client controller!
|
||||
/// </summary>
|
||||
private void MapProgress(IProgressIndicator progressIndicator, ProgressChangedEventArgs args)
|
||||
{
|
||||
if (args.CurrentValue.HasValue)
|
||||
|
|
|
@ -94,6 +94,8 @@
|
|||
<Compile Include="Operations\KioskModeOperation.cs" />
|
||||
<Compile Include="Operations\KioskModeTerminationOperation.cs" />
|
||||
<Compile Include="Operations\ServiceOperation.cs" />
|
||||
<Compile Include="Operations\SessionActivationOperation.cs" />
|
||||
<Compile Include="Operations\SessionOperation.cs" />
|
||||
<Compile Include="Operations\SessionInitializationOperation.cs" />
|
||||
<Compile Include="Communication\ProxyFactory.cs" />
|
||||
<Compile Include="Communication\RuntimeHost.cs" />
|
||||
|
@ -112,6 +114,7 @@
|
|||
<DesignTimeSharedInput>True</DesignTimeSharedInput>
|
||||
</Compile>
|
||||
<Compile Include="RuntimeController.cs" />
|
||||
<Compile Include="SessionContext.cs" />
|
||||
<EmbeddedResource Include="Properties\Resources.resx">
|
||||
<Generator>ResXFileCodeGenerator</Generator>
|
||||
<LastGenOutput>Resources.Designer.cs</LastGenOutput>
|
||||
|
|
45
SafeExamBrowser.Runtime/SessionContext.cs
Normal file
45
SafeExamBrowser.Runtime/SessionContext.cs
Normal file
|
@ -0,0 +1,45 @@
|
|||
/*
|
||||
* 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.Proxies;
|
||||
using SafeExamBrowser.Contracts.Configuration;
|
||||
using SafeExamBrowser.Contracts.WindowsApi;
|
||||
|
||||
namespace SafeExamBrowser.Runtime
|
||||
{
|
||||
/// <summary>
|
||||
/// Holds all configuration and runtime data required for the session handling.
|
||||
/// </summary>
|
||||
internal class SessionContext
|
||||
{
|
||||
/// <summary>
|
||||
/// The currently running client process.
|
||||
/// </summary>
|
||||
public IProcess ClientProcess { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The communication proxy for the currently running client process.
|
||||
/// </summary>
|
||||
public IClientProxy ClientProxy { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The configuration of the currently active session.
|
||||
/// </summary>
|
||||
public ISessionConfiguration Current { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The configuration of the next session to be activated.
|
||||
/// </summary>
|
||||
public ISessionConfiguration Next { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The path of the configuration file to be used for reconfiguration.
|
||||
/// </summary>
|
||||
public string ReconfigurationFilePath { get; set; }
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue