SEBWIN-219: Implemented draft of communication operation and runtime communication host.

This commit is contained in:
dbuechel 2018-02-06 15:12:11 +01:00
parent c10e141e7f
commit 8cd0659a22
32 changed files with 626 additions and 170 deletions

View file

@ -58,7 +58,7 @@ namespace SafeExamBrowser.Client
browserInfo = new BrowserApplicationInfo();
logger = new Logger();
nativeMethods = new NativeMethods();
settings = new SettingsRepository().LoadDefaults();
settings = new ConfigurationRepository().LoadDefaultSettings();
systemInfo = new SystemInfo();
uiFactory = new UserInterfaceFactory();

View file

@ -0,0 +1,87 @@
/*
* 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 System.IO;
using System.Reflection;
using SafeExamBrowser.Contracts.Configuration;
using SafeExamBrowser.Contracts.Configuration.Settings;
namespace SafeExamBrowser.Configuration
{
public class ConfigurationRepository : IConfigurationRepository
{
private RuntimeInfo runtimeInfo;
public ISettings CurrentSettings { get; private set; }
public IRuntimeInfo RuntimeInfo
{
get
{
if (runtimeInfo == null)
{
InitializeRuntimeInfo();
}
return runtimeInfo;
}
}
public ISettings LoadSettings(Uri path)
{
// TODO
return LoadDefaultSettings();
}
public ISettings LoadDefaultSettings()
{
var settings = new Settings.Settings();
// TODO
settings.ServicePolicy = ServicePolicy.Optional;
CurrentSettings = settings;
return settings;
}
private void InitializeRuntimeInfo()
{
var appDataFolder = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), nameof(SafeExamBrowser));
var baseAddress = "net.pipe://localhost/safeexambrowser";
var clientId = Guid.NewGuid();
var executable = Assembly.GetEntryAssembly();
var runtimeId = Guid.NewGuid();
var startTime = DateTime.Now;
var logFolder = Path.Combine(appDataFolder, "Logs");
var logFilePrefix = startTime.ToString("yyyy-MM-dd\\_HH\\hmm\\mss\\s");
runtimeInfo = new RuntimeInfo
{
ApplicationStartTime = startTime,
AppDataFolder = appDataFolder,
BrowserCachePath = Path.Combine(appDataFolder, "Cache"),
BrowserLogFile = Path.Combine(logFolder, $"{logFilePrefix}_Browser.txt"),
ClientId = Guid.NewGuid(),
ClientAddress = $"{baseAddress}/client/{clientId}",
ClientLogFile = Path.Combine(logFolder, $"{logFilePrefix}_Client.txt"),
DefaultSettingsFileName = "SebClientSettings.seb",
ProgramCopyright = executable.GetCustomAttribute<AssemblyCopyrightAttribute>().Copyright,
ProgramDataFolder = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData), nameof(SafeExamBrowser)),
ProgramTitle = executable.GetCustomAttribute<AssemblyTitleAttribute>().Title,
ProgramVersion = executable.GetCustomAttribute<AssemblyInformationalVersionAttribute>().InformationalVersion,
RuntimeId = Guid.NewGuid(),
RuntimeAddress = $"{baseAddress}/runtime/{runtimeId}",
RuntimeLogFile = Path.Combine(logFolder, $"{logFilePrefix}_Runtime.txt"),
ServiceAddress = $"{baseAddress}/service"
};
}
}
}

View file

@ -18,12 +18,17 @@ namespace SafeExamBrowser.Configuration
public DateTime ApplicationStartTime { get; set; }
public string BrowserCachePath { get; set; }
public string BrowserLogFile { get; set; }
public string ClientAddress { get; set; }
public Guid ClientId { get; set; }
public string ClientLogFile { get; set; }
public string DefaultSettingsFileName { get; set; }
public string ProgramCopyright { get; set; }
public string ProgramDataFolder { get; set; }
public string ProgramTitle { get; set; }
public string ProgramVersion { get; set; }
public string RuntimeAddress { get; set; }
public Guid RuntimeId { get; set; }
public string RuntimeLogFile { get; set; }
public string ServiceAddress { get; set; }
}
}

View file

@ -59,7 +59,7 @@
<Compile Include="Settings\MouseSettings.cs" />
<Compile Include="Settings\Settings.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Settings\SettingsRepository.cs" />
<Compile Include="ConfigurationRepository.cs" />
<Compile Include="SystemInfo.cs" />
<Compile Include="Settings\TaskbarSettings.cs" />
</ItemGroup>

View file

@ -1,37 +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.Configuration.Settings;
namespace SafeExamBrowser.Configuration.Settings
{
public class SettingsRepository : ISettingsRepository
{
public ISettings Current { get; private set; }
public ISettings Load(Uri path)
{
// TODO
return LoadDefaults();
}
public ISettings LoadDefaults()
{
var settings = new Settings();
// TODO
settings.ServicePolicy = ServicePolicy.Optional;
Current = settings;
return settings;
}
}
}

View file

@ -6,6 +6,7 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
namespace SafeExamBrowser.Contracts.Behaviour
{
public interface IRuntimeController

View file

@ -0,0 +1,28 @@
/*
* 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/.
*/
namespace SafeExamBrowser.Contracts.Communication
{
public interface ICommunicationHost
{
/// <summary>
/// Indicates whether the host is running and ready for communication.
/// </summary>
bool IsRunning { get; }
/// <summary>
/// Starts the host and opens it for communication.
/// </summary>
void Start();
/// <summary>
/// Closes and terminates the host.
/// </summary>
void Stop();
}
}

View file

@ -0,0 +1,15 @@
/*
* 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/.
*/
namespace SafeExamBrowser.Contracts.Communication
{
public interface IRuntimeHost : ICommunicationHost
{
}
}

View file

@ -7,26 +7,32 @@
*/
using System;
using SafeExamBrowser.Contracts.Configuration.Settings;
namespace SafeExamBrowser.Contracts.Configuration.Settings
namespace SafeExamBrowser.Contracts.Configuration
{
public interface ISettingsRepository
public interface IConfigurationRepository
{
/// <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>.
/// be <c>null</c>!
/// </summary>
ISettings Current { get; }
ISettings CurrentSettings { get; }
/// <summary>
/// The runtime information for the currently running application instance.
/// </summary>
IRuntimeInfo RuntimeInfo { get; }
/// <summary>
/// Attempts to load settings from the specified path.
/// </summary>
/// <exception cref="System.ArgumentException">Thrown if the given path cannot be resolved to a settings file.</exception>
ISettings Load(Uri path);
/// <exception cref="ArgumentException">Thrown if the given path cannot be resolved to a settings file.</exception>
ISettings LoadSettings(Uri path);
/// <summary>
/// Loads the default settings.
/// </summary>
ISettings LoadDefaults();
ISettings LoadDefaultSettings();
}
}

View file

@ -32,6 +32,22 @@ namespace SafeExamBrowser.Contracts.Configuration
/// </summary>
string BrowserLogFile { get; }
/// <summary>
/// The communication address of the client component.
///
/// TODO: Will need to be updated for each new client instance!
///
/// </summary>
string ClientAddress { get; }
/// <summary>
/// The unique identifier for the currently running client instance.
///
/// TODO: Will need to be updated for each new client instance!
///
/// </summary>
Guid ClientId { get; }
/// <summary>
/// The file path under which the log of the client component is to be stored.
/// </summary>
@ -62,9 +78,24 @@ namespace SafeExamBrowser.Contracts.Configuration
/// </summary>
string ProgramVersion { get; }
/// <summary>
/// The communication address of the runtime component.
/// </summary>
string RuntimeAddress { get; }
/// <summary>
/// The unique identifier for the currently running runtime instance.
/// </summary>
Guid RuntimeId { get; }
/// <summary>
/// The file path under which the log of the runtime component is to be stored.
/// </summary>
string RuntimeLogFile { get; }
/// <summary>
/// The communication address of the service component.
/// </summary>
string ServiceAddress { get; }
}
}

View file

@ -35,12 +35,15 @@ namespace SafeExamBrowser.Contracts.I18n
ProgressIndicator_InitializeTaskbar,
ProgressIndicator_InitializeWindowMonitoring,
ProgressIndicator_InitializeWorkingArea,
ProgressIndicator_RestartCommunicationHost,
ProgressIndicator_RestoreWorkingArea,
ProgressIndicator_RevertKioskMode,
ProgressIndicator_ShutdownProcedure,
ProgressIndicator_StartCommunicationHost,
ProgressIndicator_StartEventHandling,
ProgressIndicator_StartKeyboardInterception,
ProgressIndicator_StartMouseInterception,
ProgressIndicator_StopCommunicationHost,
ProgressIndicator_StopEventHandling,
ProgressIndicator_StopKeyboardInterception,
ProgressIndicator_StopMouseInterception,

View file

@ -58,6 +58,8 @@
<Compile Include="Behaviour\Operations\IOperationSequence.cs" />
<Compile Include="Communication\ICommunication.cs" />
<Compile Include="Communication\IClientProxy.cs" />
<Compile Include="Communication\ICommunicationHost.cs" />
<Compile Include="Communication\IRuntimeHost.cs" />
<Compile Include="Communication\IRuntimeProxy.cs" />
<Compile Include="Communication\IServiceProxy.cs" />
<Compile Include="Communication\Messages\IMessage.cs" />
@ -78,7 +80,7 @@
<Compile Include="Configuration\Settings\IKeyboardSettings.cs" />
<Compile Include="Configuration\Settings\IMouseSettings.cs" />
<Compile Include="Configuration\Settings\ISettings.cs" />
<Compile Include="Configuration\Settings\ISettingsRepository.cs" />
<Compile Include="Configuration\IConfigurationRepository.cs" />
<Compile Include="Configuration\Settings\ITaskbarSettings.cs" />
<Compile Include="Configuration\Settings\KioskMode.cs" />
<Compile Include="Configuration\Settings\ServicePolicy.cs" />

View file

@ -0,0 +1,70 @@
/*
* Copyright (c) 2018 ETH Zürich, Educational Development and Technology (LET)
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Moq;
using SafeExamBrowser.Contracts.Communication;
using SafeExamBrowser.Contracts.Logging;
using SafeExamBrowser.Core.Behaviour.Operations;
namespace SafeExamBrowser.Core.UnitTests.Behaviour.Operations
{
[TestClass]
public class CommunicationOperationTests
{
private Mock<ICommunicationHost> hostMock;
private Mock<ILogger> loggerMock;
private CommunicationOperation sut;
[TestInitialize]
public void Initialize()
{
hostMock = new Mock<ICommunicationHost>();
loggerMock = new Mock<ILogger>();
sut = new CommunicationOperation(hostMock.Object, loggerMock.Object);
}
[TestMethod]
public void MustRestartHostOnRepeat()
{
var order = 0;
var stop = 0;
var start = 0;
hostMock.Setup(h => h.Stop()).Callback(() => stop = ++order);
hostMock.Setup(h => h.Start()).Callback(() => start = ++order);
sut.Repeat();
hostMock.Verify(h => h.Stop(), Times.Once);
hostMock.Verify(h => h.Start(), Times.Once);
Assert.AreEqual(stop, 1);
Assert.AreEqual(start, 2);
}
[TestMethod]
public void MustStartHostOnPerform()
{
sut.Perform();
hostMock.Verify(h => h.Start(), Times.Once);
hostMock.Verify(h => h.Stop(), Times.Never);
}
[TestMethod]
public void MustStopHostOnRevert()
{
sut.Revert();
hostMock.Verify(h => h.Stop(), Times.Once);
hostMock.Verify(h => h.Start(), Times.Never);
}
}
}

View file

@ -28,6 +28,29 @@ namespace SafeExamBrowser.Core.UnitTests.Behaviour.Operations
loggerMock = new Mock<ILogger>();
}
[TestMethod]
public void MustCreateCopyOfOperationQueue()
{
var operationA = new Mock<IOperation>();
var operationB = new Mock<IOperation>();
var operationC = new Mock<IOperation>();
var operations = new Queue<IOperation>();
operations.Enqueue(operationA.Object);
operations.Enqueue(operationB.Object);
operations.Enqueue(operationC.Object);
var sut = new OperationSequence(loggerMock.Object, operations);
operations.Clear();
sut.TryPerform();
operationA.Verify(o => o.Perform(), Times.Once);
operationB.Verify(o => o.Perform(), Times.Once);
operationC.Verify(o => o.Perform(), Times.Once);
}
#region Perform Tests
[TestMethod]

View file

@ -78,6 +78,7 @@
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="Behaviour\Operations\CommunicationOperationTests.cs" />
<Compile Include="Behaviour\Operations\I18nOperationTests.cs" />
<Compile Include="Behaviour\Operations\OperationSequenceTests.cs" />
<Compile Include="I18n\TextTests.cs" />

View file

@ -0,0 +1,59 @@
/*
* Copyright (c) 2018 ETH Zürich, Educational Development and Technology (LET)
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
using SafeExamBrowser.Contracts.Behaviour.Operations;
using SafeExamBrowser.Contracts.Communication;
using SafeExamBrowser.Contracts.I18n;
using SafeExamBrowser.Contracts.Logging;
using SafeExamBrowser.Contracts.UserInterface;
namespace SafeExamBrowser.Core.Behaviour.Operations
{
public class CommunicationOperation : IOperation
{
private ICommunicationHost host;
private ILogger logger;
public bool Abort { get; private set; }
public IProgressIndicator ProgressIndicator { private get; set; }
public CommunicationOperation(ICommunicationHost host, ILogger logger)
{
this.host = host;
this.logger = logger;
}
public void Perform()
{
logger.Info("Starting communication host...");
ProgressIndicator?.UpdateText(TextKey.ProgressIndicator_StartCommunicationHost);
host.Start();
}
public void Repeat()
{
if (!host.IsRunning)
{
logger.Info("Restarting communication host...");
ProgressIndicator?.UpdateText(TextKey.ProgressIndicator_RestartCommunicationHost);
host.Stop();
host.Start();
}
}
public void Revert()
{
logger.Info("Stopping communication host...");
ProgressIndicator?.UpdateText(TextKey.ProgressIndicator_StopCommunicationHost);
host.Stop();
}
}
}

View file

@ -40,7 +40,7 @@ namespace SafeExamBrowser.Core.Behaviour.Operations
if (!success)
{
Revert();
Revert(true);
}
}
catch (Exception e)
@ -74,8 +74,8 @@ namespace SafeExamBrowser.Core.Behaviour.Operations
try
{
Initialize();
success = Revert(false);
Initialize(true);
success = Revert();
}
catch (Exception e)
{
@ -154,7 +154,7 @@ namespace SafeExamBrowser.Core.Behaviour.Operations
return true;
}
private bool Revert(bool regress = true)
private bool Revert(bool regress = false)
{
var success = true;

View file

@ -0,0 +1,91 @@
/*
* 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 System.ServiceModel;
using SafeExamBrowser.Contracts.Communication;
using SafeExamBrowser.Contracts.Communication.Messages;
using SafeExamBrowser.Contracts.Communication.Responses;
using SafeExamBrowser.Contracts.Logging;
namespace SafeExamBrowser.Core.Communication
{
[ServiceBehavior(InstanceContextMode = InstanceContextMode.Single, ConcurrencyMode = ConcurrencyMode.Single)]
public abstract class BaseHost : ICommunication, ICommunicationHost
{
private string address;
private ILogger logger;
private ServiceHost host;
public bool IsRunning
{
get { return host?.State == CommunicationState.Opened; }
}
public BaseHost(string address, ILogger logger)
{
this.address = address;
this.logger = logger;
}
public abstract IConnectResponse Connect(Guid? token = null);
public abstract void Disconnect(IMessage message);
public abstract IResponse Send(IMessage message);
public void Start()
{
host = new ServiceHost(this);
host.AddServiceEndpoint(typeof(ICommunication), new NetNamedPipeBinding(NetNamedPipeSecurityMode.Transport), address);
host.Closed += Host_Closed;
host.Closing += Host_Closing;
host.Faulted += Host_Faulted;
host.Opened += Host_Opened;
host.Opening += Host_Opening;
host.UnknownMessageReceived += Host_UnknownMessageReceived;
host.Open();
logger.Debug($"Successfully started communication host for endpoint '{address}'.");
}
public void Stop()
{
host?.Close();
logger.Debug($"Terminated communication host for endpoint '{address}'.");
}
private void Host_Closed(object sender, EventArgs e)
{
logger.Debug("Communication host has been closed.");
}
private void Host_Closing(object sender, EventArgs e)
{
logger.Debug("Communication host is closing...");
}
private void Host_Faulted(object sender, EventArgs e)
{
logger.Debug("Communication host has faulted!");
}
private void Host_Opened(object sender, EventArgs e)
{
logger.Debug("Communication host has been opened.");
}
private void Host_Opening(object sender, EventArgs e)
{
logger.Debug("Communication host is opening...");
}
private void Host_UnknownMessageReceived(object sender, UnknownMessageReceivedEventArgs e)
{
logger.Debug($"Communication host has received an unknown message: {e?.Message}.");
}
}
}

View file

@ -23,7 +23,7 @@ namespace SafeExamBrowser.Core.Communication
protected Guid? CommunicationToken { get; private set; }
protected ILogger Logger { get; private set; }
public BaseProxy(ILogger logger, string address)
public BaseProxy(string address, ILogger logger)
{
this.address = address;
this.Logger = logger;
@ -34,9 +34,11 @@ namespace SafeExamBrowser.Core.Communication
var endpoint = new EndpointAddress(address);
channel = ChannelFactory<ICommunication>.CreateChannel(new NetNamedPipeBinding(NetNamedPipeSecurityMode.Transport), endpoint);
(channel as ICommunicationObject).Closed += CommunicationHostProxy_Closed;
(channel as ICommunicationObject).Closing += CommunicationHostProxy_Closing;
(channel as ICommunicationObject).Faulted += CommunicationHostProxy_Faulted;
(channel as ICommunicationObject).Closed += BaseProxy_Closed;
(channel as ICommunicationObject).Closing += BaseProxy_Closing;
(channel as ICommunicationObject).Faulted += BaseProxy_Faulted;
(channel as ICommunicationObject).Opened += BaseProxy_Opened;
(channel as ICommunicationObject).Opening += BaseProxy_Opening;
var response = channel.Connect(token);
@ -84,21 +86,31 @@ namespace SafeExamBrowser.Core.Communication
return channel != null && (channel as ICommunicationObject).State == CommunicationState.Opened;
}
private void CommunicationHostProxy_Closed(object sender, EventArgs e)
private void BaseProxy_Closed(object sender, EventArgs e)
{
Logger.Debug("Communication channel has been closed.");
}
private void CommunicationHostProxy_Closing(object sender, EventArgs e)
private void BaseProxy_Closing(object sender, EventArgs e)
{
Logger.Debug("Communication channel is closing.");
Logger.Debug("Communication channel is closing...");
}
private void CommunicationHostProxy_Faulted(object sender, EventArgs e)
private void BaseProxy_Faulted(object sender, EventArgs e)
{
Logger.Debug("Communication channel has faulted!");
}
private void BaseProxy_Opened(object sender, EventArgs e)
{
Logger.Debug("Communication channel has been opened.");
}
private void BaseProxy_Opening(object sender, EventArgs e)
{
Logger.Debug("Communication channel is opening...");
}
private string GetChannelState()
{
return channel == null ? "null" : $"in state '{(channel as ICommunicationObject).State}'";

View file

@ -16,7 +16,7 @@ namespace SafeExamBrowser.Core.Communication
{
public bool Ignore { private get; set; }
public ServiceProxy(ILogger logger, string address) : base(logger, address)
public ServiceProxy(string address, ILogger logger) : base(address, logger)
{
}

View file

@ -60,6 +60,9 @@
<Entry key="ProgressIndicator_InitializeWorkingArea">
Initializing working area
</Entry>
<Entry key="ProgressIndicator_RestartCommunicationHost">
Restarting communication host
</Entry>
<Entry key="ProgressIndicator_RestoreWorkingArea">
Restoring working area
</Entry>
@ -69,6 +72,9 @@
<Entry key="ProgressIndicator_ShutdownProcedure">
Initiating shutdown procedure
</Entry>
<Entry key="ProgressIndicator_StartCommunicationHost">
Starting communication host
</Entry>
<Entry key="ProgressIndicator_StartEventHandling">
Starting event handling
</Entry>
@ -78,6 +84,9 @@
<Entry key="ProgressIndicator_StartMouseInterception">
Starting mouse interception
</Entry>
<Entry key="ProgressIndicator_StopCommunicationHost">
Stopping communication host
</Entry>
<Entry key="ProgressIndicator_StopEventHandling">
Stopping event handling
</Entry>

View file

@ -55,9 +55,11 @@
<Reference Include="System.Xml.Linq" />
</ItemGroup>
<ItemGroup>
<Compile Include="Behaviour\Operations\CommunicationOperation.cs" />
<Compile Include="Behaviour\Operations\I18nOperation.cs" />
<Compile Include="Behaviour\Operations\OperationSequence.cs" />
<Compile Include="Communication\BaseProxy.cs" />
<Compile Include="Communication\BaseHost.cs" />
<Compile Include="Communication\Messages\Message.cs" />
<Compile Include="Communication\ServiceProxy.cs" />
<Compile Include="Logging\DefaultLogFormatter.cs" />

View file

@ -24,7 +24,7 @@ namespace SafeExamBrowser.Runtime.UnitTests.Behaviour.Operations
{
private Mock<ILogger> logger;
private Mock<IRuntimeInfo> info;
private Mock<ISettingsRepository> repository;
private Mock<IConfigurationRepository> repository;
private Mock<ISettings> settings;
private Mock<IText> text;
private Mock<IUserInterfaceFactory> uiFactory;
@ -35,7 +35,7 @@ namespace SafeExamBrowser.Runtime.UnitTests.Behaviour.Operations
{
logger = new Mock<ILogger>();
info = new Mock<IRuntimeInfo>();
repository = new Mock<ISettingsRepository>();
repository = new Mock<IConfigurationRepository>();
settings = new Mock<ISettings>();
text = new Mock<IText>();
uiFactory = new Mock<IUserInterfaceFactory>();
@ -43,24 +43,24 @@ namespace SafeExamBrowser.Runtime.UnitTests.Behaviour.Operations
info.SetupGet(i => i.AppDataFolder).Returns(@"C:\Not\Really\AppData");
info.SetupGet(i => i.DefaultSettingsFileName).Returns("SettingsDummy.txt");
info.SetupGet(i => i.ProgramDataFolder).Returns(@"C:\Not\Really\ProgramData");
repository.Setup(r => r.Load(It.IsAny<Uri>())).Returns(settings.Object);
repository.Setup(r => r.LoadDefaults()).Returns(settings.Object);
repository.Setup(r => r.LoadSettings(It.IsAny<Uri>())).Returns(settings.Object);
repository.Setup(r => r.LoadDefaultSettings()).Returns(settings.Object);
}
[TestMethod]
public void MustNotFailWithoutCommandLineArgs()
{
repository.Setup(r => r.LoadDefaults());
repository.Setup(r => r.LoadDefaultSettings());
sut = new ConfigurationOperation(logger.Object, info.Object, repository.Object, text.Object, uiFactory.Object, null);
sut = new ConfigurationOperation(repository.Object, logger.Object, info.Object, text.Object, uiFactory.Object, null);
sut.Perform();
sut = new ConfigurationOperation(logger.Object, info.Object, repository.Object, text.Object, uiFactory.Object, new string[] { });
sut = new ConfigurationOperation(repository.Object, logger.Object, info.Object, text.Object, uiFactory.Object, new string[] { });
sut.Perform();
repository.Verify(r => r.LoadDefaults(), Times.Exactly(2));
repository.Verify(r => r.LoadDefaultSettings(), Times.Exactly(2));
}
[TestMethod]
@ -68,7 +68,7 @@ namespace SafeExamBrowser.Runtime.UnitTests.Behaviour.Operations
{
var path = @"an/invalid\path.'*%yolo/()";
sut = new ConfigurationOperation(logger.Object, info.Object, repository.Object, text.Object, uiFactory.Object, new [] { "blubb.exe", path });
sut = new ConfigurationOperation(repository.Object, logger.Object, info.Object, text.Object, uiFactory.Object, new [] { "blubb.exe", path });
sut.Perform();
}
@ -82,11 +82,11 @@ namespace SafeExamBrowser.Runtime.UnitTests.Behaviour.Operations
info.SetupGet(r => r.ProgramDataFolder).Returns(location);
info.SetupGet(r => r.AppDataFolder).Returns(location);
sut = new ConfigurationOperation(logger.Object, info.Object, repository.Object, text.Object, uiFactory.Object, new[] { "blubb.exe", path });
sut = new ConfigurationOperation(repository.Object, logger.Object, info.Object, text.Object, uiFactory.Object, new[] { "blubb.exe", path });
sut.Perform();
repository.Verify(r => r.Load(It.Is<Uri>(u => u.Equals(new Uri(path)))), Times.Once);
repository.Verify(r => r.LoadSettings(It.Is<Uri>(u => u.Equals(new Uri(path)))), Times.Once);
}
[TestMethod]
@ -97,11 +97,11 @@ namespace SafeExamBrowser.Runtime.UnitTests.Behaviour.Operations
info.SetupGet(r => r.ProgramDataFolder).Returns(location);
info.SetupGet(r => r.AppDataFolder).Returns($@"{location}\WRONG");
sut = new ConfigurationOperation(logger.Object, info.Object, repository.Object, text.Object, uiFactory.Object, null);
sut = new ConfigurationOperation(repository.Object, logger.Object, info.Object, text.Object, uiFactory.Object, null);
sut.Perform();
repository.Verify(r => r.Load(It.Is<Uri>(u => u.Equals(new Uri(Path.Combine(location, "SettingsDummy.txt"))))), Times.Once);
repository.Verify(r => r.LoadSettings(It.Is<Uri>(u => u.Equals(new Uri(Path.Combine(location, "SettingsDummy.txt"))))), Times.Once);
}
[TestMethod]
@ -111,21 +111,21 @@ namespace SafeExamBrowser.Runtime.UnitTests.Behaviour.Operations
info.SetupGet(r => r.AppDataFolder).Returns(location);
sut = new ConfigurationOperation(logger.Object, info.Object, repository.Object, text.Object, uiFactory.Object, null);
sut = new ConfigurationOperation(repository.Object, logger.Object, info.Object, text.Object, uiFactory.Object, null);
sut.Perform();
repository.Verify(r => r.Load(It.Is<Uri>(u => u.Equals(new Uri(Path.Combine(location, "SettingsDummy.txt"))))), Times.Once);
repository.Verify(r => r.LoadSettings(It.Is<Uri>(u => u.Equals(new Uri(Path.Combine(location, "SettingsDummy.txt"))))), Times.Once);
}
[TestMethod]
public void MustFallbackToDefaultsAsLastPrio()
{
sut = new ConfigurationOperation(logger.Object, info.Object, repository.Object, text.Object, uiFactory.Object, null);
sut = new ConfigurationOperation(repository.Object, logger.Object, info.Object, text.Object, uiFactory.Object, null);
sut.Perform();
repository.Verify(r => r.LoadDefaults(), Times.Once);
repository.Verify(r => r.LoadDefaultSettings(), Times.Once);
}
[TestMethod]
@ -136,7 +136,7 @@ namespace SafeExamBrowser.Runtime.UnitTests.Behaviour.Operations
info.SetupGet(r => r.ProgramDataFolder).Returns(location);
uiFactory.Setup(u => u.Show(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<MessageBoxAction>(), It.IsAny<MessageBoxIcon>())).Returns(MessageBoxResult.Yes);
sut = new ConfigurationOperation(logger.Object, info.Object, repository.Object, text.Object, uiFactory.Object, null);
sut = new ConfigurationOperation(repository.Object, logger.Object, info.Object, text.Object, uiFactory.Object, null);
sut.Perform();
@ -148,7 +148,7 @@ namespace SafeExamBrowser.Runtime.UnitTests.Behaviour.Operations
{
uiFactory.Setup(u => u.Show(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<MessageBoxAction>(), It.IsAny<MessageBoxIcon>())).Returns(MessageBoxResult.No);
sut = new ConfigurationOperation(logger.Object, info.Object, repository.Object, text.Object, uiFactory.Object, null);
sut = new ConfigurationOperation(repository.Object, logger.Object, info.Object, text.Object, uiFactory.Object, null);
sut.Perform();

View file

@ -14,7 +14,7 @@ namespace SafeExamBrowser.Runtime.UnitTests.Behaviour.Operations
public class KioskModeOperationTests
{
[TestMethod]
public void Todo()
public void TODO()
{
Assert.Fail();
}

View file

@ -10,6 +10,7 @@ using System;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Moq;
using SafeExamBrowser.Contracts.Communication;
using SafeExamBrowser.Contracts.Configuration;
using SafeExamBrowser.Contracts.Configuration.Settings;
using SafeExamBrowser.Contracts.I18n;
using SafeExamBrowser.Contracts.Logging;
@ -23,7 +24,7 @@ namespace SafeExamBrowser.Runtime.UnitTests.Behaviour.Operations
{
private Mock<ILogger> logger;
private Mock<IServiceProxy> service;
private Mock<ISettingsRepository> settings;
private Mock<IConfigurationRepository> configuration;
private Mock<IProgressIndicator> progressIndicator;
private Mock<IText> text;
private ServiceOperation sut;
@ -33,23 +34,23 @@ namespace SafeExamBrowser.Runtime.UnitTests.Behaviour.Operations
{
logger = new Mock<ILogger>();
service = new Mock<IServiceProxy>();
settings = new Mock<ISettingsRepository>();
configuration = new Mock<IConfigurationRepository>();
progressIndicator = new Mock<IProgressIndicator>();
text = new Mock<IText>();
sut = new ServiceOperation(logger.Object, service.Object, settings.Object, text.Object);
sut = new ServiceOperation(configuration.Object, logger.Object, service.Object, text.Object);
}
[TestMethod]
public void MustConnectToService()
{
service.Setup(s => s.Connect()).Returns(true);
settings.SetupGet(s => s.Current.ServicePolicy).Returns(ServicePolicy.Mandatory);
configuration.SetupGet(s => s.CurrentSettings.ServicePolicy).Returns(ServicePolicy.Mandatory);
sut.Perform();
service.Setup(s => s.Connect()).Returns(true);
settings.SetupGet(s => s.Current.ServicePolicy).Returns(ServicePolicy.Optional);
configuration.SetupGet(s => s.CurrentSettings.ServicePolicy).Returns(ServicePolicy.Optional);
sut.Perform();
@ -60,22 +61,22 @@ namespace SafeExamBrowser.Runtime.UnitTests.Behaviour.Operations
public void MustNotFailIfServiceNotAvailable()
{
service.Setup(s => s.Connect()).Returns(false);
settings.SetupGet(s => s.Current.ServicePolicy).Returns(ServicePolicy.Mandatory);
configuration.SetupGet(s => s.CurrentSettings.ServicePolicy).Returns(ServicePolicy.Mandatory);
sut.Perform();
service.Setup(s => s.Connect()).Returns(false);
settings.SetupGet(s => s.Current.ServicePolicy).Returns(ServicePolicy.Optional);
configuration.SetupGet(s => s.CurrentSettings.ServicePolicy).Returns(ServicePolicy.Optional);
sut.Perform();
service.Setup(s => s.Connect()).Throws<Exception>();
settings.SetupGet(s => s.Current.ServicePolicy).Returns(ServicePolicy.Mandatory);
configuration.SetupGet(s => s.CurrentSettings.ServicePolicy).Returns(ServicePolicy.Mandatory);
sut.Perform();
service.Setup(s => s.Connect()).Throws<Exception>();
settings.SetupGet(s => s.Current.ServicePolicy).Returns(ServicePolicy.Optional);
configuration.SetupGet(s => s.CurrentSettings.ServicePolicy).Returns(ServicePolicy.Optional);
sut.Perform();
}
@ -84,7 +85,7 @@ namespace SafeExamBrowser.Runtime.UnitTests.Behaviour.Operations
public void MustAbortIfServiceMandatoryAndNotAvailable()
{
service.Setup(s => s.Connect()).Returns(false);
settings.SetupGet(s => s.Current.ServicePolicy).Returns(ServicePolicy.Mandatory);
configuration.SetupGet(s => s.CurrentSettings.ServicePolicy).Returns(ServicePolicy.Mandatory);
sut.Perform();
@ -95,7 +96,7 @@ namespace SafeExamBrowser.Runtime.UnitTests.Behaviour.Operations
public void MustNotAbortIfServiceOptionalAndNotAvailable()
{
service.Setup(s => s.Connect()).Returns(false);
settings.SetupGet(s => s.Current.ServicePolicy).Returns(ServicePolicy.Optional);
configuration.SetupGet(s => s.CurrentSettings.ServicePolicy).Returns(ServicePolicy.Optional);
sut.Perform();
@ -107,13 +108,13 @@ namespace SafeExamBrowser.Runtime.UnitTests.Behaviour.Operations
public void MustDisconnectWhenReverting()
{
service.Setup(s => s.Connect()).Returns(true);
settings.SetupGet(s => s.Current.ServicePolicy).Returns(ServicePolicy.Mandatory);
configuration.SetupGet(s => s.CurrentSettings.ServicePolicy).Returns(ServicePolicy.Mandatory);
sut.Perform();
sut.Revert();
service.Setup(s => s.Connect()).Returns(true);
settings.SetupGet(s => s.Current.ServicePolicy).Returns(ServicePolicy.Optional);
configuration.SetupGet(s => s.CurrentSettings.ServicePolicy).Returns(ServicePolicy.Optional);
sut.Perform();
sut.Revert();
@ -126,7 +127,7 @@ namespace SafeExamBrowser.Runtime.UnitTests.Behaviour.Operations
{
service.Setup(s => s.Connect()).Returns(true);
service.Setup(s => s.Disconnect()).Throws<Exception>();
settings.SetupGet(s => s.Current.ServicePolicy).Returns(ServicePolicy.Optional);
configuration.SetupGet(s => s.CurrentSettings.ServicePolicy).Returns(ServicePolicy.Optional);
sut.Perform();
sut.Revert();
@ -138,25 +139,25 @@ namespace SafeExamBrowser.Runtime.UnitTests.Behaviour.Operations
public void MustNotDisconnnectIfNotAvailable()
{
service.Setup(s => s.Connect()).Returns(false);
settings.SetupGet(s => s.Current.ServicePolicy).Returns(ServicePolicy.Mandatory);
configuration.SetupGet(s => s.CurrentSettings.ServicePolicy).Returns(ServicePolicy.Mandatory);
sut.Perform();
sut.Revert();
service.Setup(s => s.Connect()).Returns(false);
settings.SetupGet(s => s.Current.ServicePolicy).Returns(ServicePolicy.Optional);
configuration.SetupGet(s => s.CurrentSettings.ServicePolicy).Returns(ServicePolicy.Optional);
sut.Perform();
sut.Revert();
service.Setup(s => s.Connect()).Throws<Exception>();
settings.SetupGet(s => s.Current.ServicePolicy).Returns(ServicePolicy.Mandatory);
configuration.SetupGet(s => s.CurrentSettings.ServicePolicy).Returns(ServicePolicy.Mandatory);
sut.Perform();
sut.Revert();
service.Setup(s => s.Connect()).Throws<Exception>();
settings.SetupGet(s => s.Current.ServicePolicy).Returns(ServicePolicy.Optional);
configuration.SetupGet(s => s.CurrentSettings.ServicePolicy).Returns(ServicePolicy.Optional);
sut.Perform();
sut.Revert();

View file

@ -19,9 +19,9 @@ namespace SafeExamBrowser.Runtime.Behaviour.Operations
{
internal class ConfigurationOperation : IOperation
{
private IConfigurationRepository repository;
private ILogger logger;
private IRuntimeInfo runtimeInfo;
private ISettingsRepository repository;
private IText text;
private IUserInterfaceFactory uiFactory;
private string[] commandLineArgs;
@ -30,16 +30,16 @@ namespace SafeExamBrowser.Runtime.Behaviour.Operations
public IProgressIndicator ProgressIndicator { private get; set; }
public ConfigurationOperation(
IConfigurationRepository repository,
ILogger logger,
IRuntimeInfo runtimeInfo,
ISettingsRepository repository,
IText text,
IUserInterfaceFactory uiFactory,
string[] commandLineArgs)
{
this.repository = repository;
this.logger = logger;
this.commandLineArgs = commandLineArgs;
this.repository = repository;
this.runtimeInfo = runtimeInfo;
this.text = text;
this.uiFactory = uiFactory;
@ -56,7 +56,7 @@ namespace SafeExamBrowser.Runtime.Behaviour.Operations
if (isValidUri)
{
logger.Info($"Loading configuration from '{uri.AbsolutePath}'...");
settings = repository.Load(uri);
settings = repository.LoadSettings(uri);
if (settings.ConfigurationMode == ConfigurationMode.ConfigureClient && UserWantsToAbortStartup())
{
@ -67,7 +67,7 @@ namespace SafeExamBrowser.Runtime.Behaviour.Operations
else
{
logger.Info("No valid settings file specified nor found in PROGRAMDATA or APPDATA - loading default settings...");
settings = repository.LoadDefaults();
settings = repository.LoadDefaultSettings();
}
}

View file

@ -7,6 +7,7 @@
*/
using SafeExamBrowser.Contracts.Behaviour.Operations;
using SafeExamBrowser.Contracts.Configuration;
using SafeExamBrowser.Contracts.Configuration.Settings;
using SafeExamBrowser.Contracts.I18n;
using SafeExamBrowser.Contracts.Logging;
@ -17,21 +18,21 @@ namespace SafeExamBrowser.Runtime.Behaviour.Operations
internal class KioskModeOperation : IOperation
{
private ILogger logger;
private ISettingsRepository settingsRepository;
private IConfigurationRepository configuration;
private KioskMode kioskMode;
public bool Abort { get; private set; }
public IProgressIndicator ProgressIndicator { private get; set; }
public KioskModeOperation(ILogger logger, ISettingsRepository settingsRepository)
public KioskModeOperation(ILogger logger, IConfigurationRepository configuration)
{
this.logger = logger;
this.settingsRepository = settingsRepository;
this.configuration = configuration;
}
public void Perform()
{
kioskMode = settingsRepository.Current.KioskMode;
kioskMode = configuration.CurrentSettings.KioskMode;
logger.Info($"Initializing kiosk mode '{kioskMode}'...");
ProgressIndicator?.UpdateText(TextKey.ProgressIndicator_InitializeKioskMode);

View file

@ -9,6 +9,7 @@
using System;
using SafeExamBrowser.Contracts.Behaviour.Operations;
using SafeExamBrowser.Contracts.Communication;
using SafeExamBrowser.Contracts.Configuration;
using SafeExamBrowser.Contracts.Configuration.Settings;
using SafeExamBrowser.Contracts.I18n;
using SafeExamBrowser.Contracts.Logging;
@ -20,19 +21,19 @@ namespace SafeExamBrowser.Runtime.Behaviour.Operations
{
private bool serviceAvailable;
private bool serviceMandatory;
private IConfigurationRepository configuration;
private ILogger logger;
private IServiceProxy service;
private ISettingsRepository settingsRepository;
private IText text;
public bool Abort { get; private set; }
public IProgressIndicator ProgressIndicator { private get; set; }
public ServiceOperation(ILogger logger, IServiceProxy service, ISettingsRepository settingsRepository, IText text)
public ServiceOperation(IConfigurationRepository configuration, ILogger logger, IServiceProxy service, IText text)
{
this.configuration = configuration;
this.service = service;
this.logger = logger;
this.settingsRepository = settingsRepository;
this.text = text;
}
@ -43,7 +44,7 @@ namespace SafeExamBrowser.Runtime.Behaviour.Operations
try
{
serviceMandatory = settingsRepository.Current.ServicePolicy == ServicePolicy.Mandatory;
serviceMandatory = configuration.CurrentSettings.ServicePolicy == ServicePolicy.Mandatory;
serviceAvailable = service.Connect();
}
catch (Exception e)

View file

@ -20,36 +20,41 @@ namespace SafeExamBrowser.Runtime.Behaviour
{
internal class RuntimeController : IRuntimeController
{
private bool initialized;
private IConfigurationRepository configuration;
private ILogger logger;
private IOperationSequence bootstrapSequence;
private IOperationSequence sessionSequence;
private IRuntimeHost runtimeHost;
private IRuntimeInfo runtimeInfo;
private IRuntimeWindow runtimeWindow;
private IServiceProxy serviceProxy;
private ISettingsRepository settingsRepository;
private ISplashScreen splashScreen;
private Action terminationCallback;
private Action shutdown;
private IText text;
private IUserInterfaceFactory uiFactory;
public RuntimeController(
IConfigurationRepository configuration,
ILogger logger,
IOperationSequence bootstrapSequence,
IOperationSequence sessionSequence,
IRuntimeHost runtimeHost,
IRuntimeInfo runtimeInfo,
IServiceProxy serviceProxy,
ISettingsRepository settingsRepository,
Action terminationCallback,
Action shutdown,
IText text,
IUserInterfaceFactory uiFactory)
{
this.configuration = configuration;
this.logger = logger;
this.bootstrapSequence = bootstrapSequence;
this.sessionSequence = sessionSequence;
this.runtimeHost = runtimeHost;
this.runtimeInfo = runtimeInfo;
this.serviceProxy = serviceProxy;
this.settingsRepository = settingsRepository;
this.terminationCallback = terminationCallback;
this.shutdown = shutdown;
this.text = text;
this.uiFactory = uiFactory;
}
@ -58,19 +63,16 @@ namespace SafeExamBrowser.Runtime.Behaviour
{
logger.Info("--- Initiating startup procedure ---");
runtimeWindow = uiFactory.CreateRuntimeWindow(runtimeInfo, text);
splashScreen = uiFactory.CreateSplashScreen(runtimeInfo, text);
splashScreen.Show();
bootstrapSequence.ProgressIndicator = splashScreen;
var success = bootstrapSequence.TryPerform();
initialized = bootstrapSequence.TryPerform();
System.Threading.Thread.Sleep(5000);
if (success)
if (initialized)
{
runtimeWindow = uiFactory.CreateRuntimeWindow(runtimeInfo, text);
logger.Info("--- Application successfully initialized! ---");
logger.Log(string.Empty);
logger.Subscribe(runtimeWindow);
@ -85,17 +87,19 @@ namespace SafeExamBrowser.Runtime.Behaviour
logger.Log(string.Empty);
}
return success;
return initialized;
}
public void Terminate()
{
StopSession();
// TODO: Necessary here? Move to App.cs as private "started" flag if not...
if (!initialized)
{
return;
}
// TODO:
// - Disconnect from service
// - Terminate runtime communication host
// - Revert kiosk mode (or do that when stopping session?)
// TODO: Only if session is running!
StopSession();
logger.Unsubscribe(runtimeWindow);
runtimeWindow?.Close();
@ -104,6 +108,10 @@ namespace SafeExamBrowser.Runtime.Behaviour
logger.Log(string.Empty);
logger.Info("--- Initiating shutdown procedure ---");
// TODO:
// - Disconnect from service
// - Terminate runtime communication host
// - Revert kiosk mode (or do that when stopping session?)
var success = bootstrapSequence.TryRevert();
if (success)
@ -137,25 +145,28 @@ namespace SafeExamBrowser.Runtime.Behaviour
if (success)
{
// TODO
}
else
{
// TODO
}
// TODO: Remove!
System.Threading.Thread.Sleep(5000);
runtimeWindow.HideProgressBar();
runtimeWindow.UpdateText(TextKey.RuntimeWindow_ApplicationRunning);
if (settingsRepository.Current.KioskMode == KioskMode.DisableExplorerShell)
if (configuration.CurrentSettings.KioskMode == KioskMode.DisableExplorerShell)
{
runtimeWindow.Hide();
}
// TODO: Remove!
System.Threading.Thread.Sleep(5000);
terminationCallback.Invoke();
shutdown.Invoke();
}
private void StopSession()
@ -163,12 +174,26 @@ namespace SafeExamBrowser.Runtime.Behaviour
logger.Info("Stopping current session...");
runtimeWindow.Show();
runtimeWindow.BringToForeground();
runtimeWindow.ShowProgressBar();
runtimeWindow.UpdateText(TextKey.RuntimeWindow_StopSession, true);
// TODO:
// - Terminate client (or does it terminate itself?)
// - Finalize session with service
// - Stop event handling and close session
var success = sessionSequence.TryRevert();
// TODO: Remove!
System.Threading.Thread.Sleep(5000);
if (success)
{
// TODO
}
else
{
// TODO
}
}
}
}

View file

@ -0,0 +1,42 @@
/*
* 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;
using SafeExamBrowser.Contracts.Communication.Messages;
using SafeExamBrowser.Contracts.Communication.Responses;
using SafeExamBrowser.Contracts.Logging;
using SafeExamBrowser.Core.Communication;
namespace SafeExamBrowser.Runtime.Communication
{
internal class RuntimeHost : BaseHost, IRuntimeHost
{
public RuntimeHost(string address, ILogger logger) : base(address, logger)
{
}
public override IConnectResponse Connect(Guid? token = null)
{
// TODO
throw new NotImplementedException();
}
public override void Disconnect(IMessage message)
{
// TODO
throw new NotImplementedException();
}
public override IResponse Send(IMessage message)
{
// TODO
throw new NotImplementedException();
}
}
}

View file

@ -8,11 +8,8 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Reflection;
using System.Windows;
using SafeExamBrowser.Configuration;
using SafeExamBrowser.Configuration.Settings;
using SafeExamBrowser.Contracts.Behaviour;
using SafeExamBrowser.Contracts.Behaviour.Operations;
using SafeExamBrowser.Contracts.Configuration;
@ -23,6 +20,7 @@ using SafeExamBrowser.Core.I18n;
using SafeExamBrowser.Core.Logging;
using SafeExamBrowser.Runtime.Behaviour;
using SafeExamBrowser.Runtime.Behaviour.Operations;
using SafeExamBrowser.Runtime.Communication;
using SafeExamBrowser.UserInterface.Classic;
using SafeExamBrowser.WindowsApi;
@ -31,7 +29,7 @@ namespace SafeExamBrowser.Runtime
internal class CompositionRoot
{
private ILogger logger;
private RuntimeInfo runtimeInfo;
private IRuntimeInfo runtimeInfo;
private ISystemInfo systemInfo;
internal IRuntimeController RuntimeController { get; private set; }
@ -42,30 +40,30 @@ namespace SafeExamBrowser.Runtime
var bootstrapOperations = new Queue<IOperation>();
var sessionOperations = new Queue<IOperation>();
var nativeMethods = new NativeMethods();
var settingsRepository = new SettingsRepository();
var configuration = new ConfigurationRepository();
var uiFactory = new UserInterfaceFactory();
logger = new Logger();
runtimeInfo = new RuntimeInfo();
runtimeInfo = configuration.RuntimeInfo;
systemInfo = new SystemInfo();
InitializeRuntimeInfo();
InitializeLogging();
var text = new Text(logger);
var serviceProxy = new ServiceProxy(new ModuleLogger(logger, typeof(ServiceProxy)), "net.pipe://localhost/safeexambrowser/service");
var runtimeHost = new RuntimeHost(runtimeInfo.RuntimeAddress, new ModuleLogger(logger, typeof(RuntimeHost)));
var serviceProxy = new ServiceProxy(runtimeInfo.ServiceAddress, new ModuleLogger(logger, typeof(ServiceProxy)));
bootstrapOperations.Enqueue(new I18nOperation(logger, text));
// TODO: RuntimeHostOperation here (is IBootstrapOperation -> only performed once per runtime!)
bootstrapOperations.Enqueue(new CommunicationOperation(runtimeHost, logger));
sessionOperations.Enqueue(new ConfigurationOperation(logger, runtimeInfo, settingsRepository, text, uiFactory, args));
sessionOperations.Enqueue(new ServiceOperation(logger, serviceProxy, settingsRepository, text));
sessionOperations.Enqueue(new KioskModeOperation(logger, settingsRepository));
sessionOperations.Enqueue(new ConfigurationOperation(configuration, logger, runtimeInfo, text, uiFactory, args));
sessionOperations.Enqueue(new ServiceOperation(configuration, logger, serviceProxy, text));
sessionOperations.Enqueue(new KioskModeOperation(logger, configuration));
var bootstrapSequence = new OperationSequence(logger, bootstrapOperations);
var boostrapSequence = new OperationSequence(logger, bootstrapOperations);
var sessionSequence = new OperationSequence(logger, sessionOperations);
RuntimeController = new RuntimeController(logger, bootstrapSequence, sessionSequence, runtimeInfo, serviceProxy, settingsRepository, Application.Current.Shutdown, text, uiFactory);
RuntimeController = new RuntimeController(configuration, logger, boostrapSequence, sessionSequence, runtimeHost, runtimeInfo, serviceProxy, Application.Current.Shutdown, text, uiFactory);
}
internal void LogStartupInformation()
@ -84,28 +82,7 @@ namespace SafeExamBrowser.Runtime
internal void LogShutdownInformation()
{
logger?.Log($"{Environment.NewLine}# Application terminated at {DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")}");
}
private void InitializeRuntimeInfo()
{
var appDataFolder = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), nameof(SafeExamBrowser));
var executable = Assembly.GetEntryAssembly();
var startTime = DateTime.Now;
var logFolder = Path.Combine(appDataFolder, "Logs");
var logFilePrefix = startTime.ToString("yyyy-MM-dd\\_HH\\hmm\\mss\\s");
runtimeInfo.ApplicationStartTime = startTime;
runtimeInfo.AppDataFolder = appDataFolder;
runtimeInfo.BrowserCachePath = Path.Combine(appDataFolder, "Cache");
runtimeInfo.BrowserLogFile = Path.Combine(logFolder, $"{logFilePrefix}_Browser.txt");
runtimeInfo.ClientLogFile = Path.Combine(logFolder, $"{logFilePrefix}_Client.txt");
runtimeInfo.DefaultSettingsFileName = "SebClientSettings.seb";
runtimeInfo.ProgramCopyright = executable.GetCustomAttribute<AssemblyCopyrightAttribute>().Copyright;
runtimeInfo.ProgramDataFolder = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData), nameof(SafeExamBrowser));
runtimeInfo.ProgramTitle = executable.GetCustomAttribute<AssemblyTitleAttribute>().Title;
runtimeInfo.ProgramVersion = executable.GetCustomAttribute<AssemblyInformationalVersionAttribute>().InformationalVersion;
runtimeInfo.RuntimeLogFile = Path.Combine(logFolder, $"{logFilePrefix}_Runtime.txt");
logger?.Log($"# Application terminated at {DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")}");
}
private void InitializeLogging()

View file

@ -90,6 +90,7 @@
<Compile Include="Behaviour\Operations\ConfigurationOperation.cs" />
<Compile Include="Behaviour\Operations\KioskModeOperation.cs" />
<Compile Include="Behaviour\Operations\ServiceOperation.cs" />
<Compile Include="Communication\RuntimeHost.cs" />
<Compile Include="CompositionRoot.cs" />
<Compile Include="Properties\AssemblyInfo.cs">
<SubType>Code</SubType>