SEBWIN-219: Started defining & implementing communication contracts and functionality.
This commit is contained in:
parent
f321496815
commit
c56b4a0251
23 changed files with 405 additions and 106 deletions
|
@ -13,19 +13,22 @@ namespace SafeExamBrowser.Configuration.Settings
|
||||||
{
|
{
|
||||||
public class SettingsRepository : ISettingsRepository
|
public class SettingsRepository : ISettingsRepository
|
||||||
{
|
{
|
||||||
|
public ISettings Current { get; private set; }
|
||||||
|
|
||||||
public ISettings Load(Uri path)
|
public ISettings Load(Uri path)
|
||||||
{
|
{
|
||||||
// TODO
|
// TODO
|
||||||
|
|
||||||
return LoadDefaults();
|
return LoadDefaults();
|
||||||
}
|
}
|
||||||
|
|
||||||
public ISettings LoadDefaults()
|
public ISettings LoadDefaults()
|
||||||
{
|
{
|
||||||
var settings = new Settings();
|
Current = new Settings();
|
||||||
|
|
||||||
// TODO
|
// TODO
|
||||||
|
|
||||||
return settings;
|
return Current;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,39 @@
|
||||||
|
/*
|
||||||
|
* 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.Messages;
|
||||||
|
using SafeExamBrowser.Contracts.Communication.Responses;
|
||||||
|
|
||||||
|
namespace SafeExamBrowser.Contracts.Communication
|
||||||
|
{
|
||||||
|
[ServiceContract(SessionMode = SessionMode.Required)]
|
||||||
|
public interface ICommunicationHost
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Initiates a connection to the host and must thus be called before any other opertion. To authenticate itself to the host, the
|
||||||
|
/// client can specify a security token. If the connection request was successful, a new session will be created by the host and
|
||||||
|
/// the client will subsequently be allowed to start communicating with the host.
|
||||||
|
/// </summary>
|
||||||
|
[OperationContract(IsInitiating = true)]
|
||||||
|
IConnectResponse Connect(Guid? token = null);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Closes the connection to the host and instructs it to terminate the communication session.
|
||||||
|
/// </summary>
|
||||||
|
[OperationContract(IsInitiating = false, IsTerminating = true)]
|
||||||
|
void Disconnect(IMessage message);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Sends a message to the host, optionally returning a response. If no response is expected, <c>null</c> will be returned.
|
||||||
|
/// </summary>
|
||||||
|
[OperationContract(IsInitiating = false)]
|
||||||
|
IResponse Send(IMessage message);
|
||||||
|
}
|
||||||
|
}
|
21
SafeExamBrowser.Contracts/Communication/Messages/IMessage.cs
Normal file
21
SafeExamBrowser.Contracts/Communication/Messages/IMessage.cs
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
/*
|
||||||
|
* 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.Runtime.Serialization;
|
||||||
|
|
||||||
|
namespace SafeExamBrowser.Contracts.Communication.Messages
|
||||||
|
{
|
||||||
|
public interface IMessage : ISerializable
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The communication token needed for authentication with the host.
|
||||||
|
/// </summary>
|
||||||
|
Guid CommunicationToken { get; }
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,25 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2018 ETH Zürich, Educational Development and Technology (LET)
|
||||||
|
*
|
||||||
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
|
*/
|
||||||
|
|
||||||
|
using System;
|
||||||
|
|
||||||
|
namespace SafeExamBrowser.Contracts.Communication.Responses
|
||||||
|
{
|
||||||
|
public interface IConnectResponse : IResponse
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The communication token needed for authentication with the host. Is <c>null</c> if a connection was refused.
|
||||||
|
/// </summary>
|
||||||
|
Guid? CommunicationToken { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Indicates whether the host has accepted the connection request.
|
||||||
|
/// </summary>
|
||||||
|
bool ConnectionEstablished { get; }
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,16 @@
|
||||||
|
/*
|
||||||
|
* 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.Runtime.Serialization;
|
||||||
|
|
||||||
|
namespace SafeExamBrowser.Contracts.Communication.Responses
|
||||||
|
{
|
||||||
|
public interface IResponse : ISerializable
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
|
@ -12,6 +12,12 @@ namespace SafeExamBrowser.Contracts.Configuration.Settings
|
||||||
{
|
{
|
||||||
public interface ISettingsRepository
|
public interface ISettingsRepository
|
||||||
{
|
{
|
||||||
|
/// <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>
|
||||||
|
ISettings Current { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Attempts to load settings from the specified path.
|
/// Attempts to load settings from the specified path.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
|
@ -13,6 +13,12 @@ namespace SafeExamBrowser.Contracts.Logging
|
||||||
{
|
{
|
||||||
public interface ILogger
|
public interface ILogger
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Logs the given message with severity <b>DEBUG</b>.
|
||||||
|
/// </summary>
|
||||||
|
/// <exception cref="ArgumentNullException" />
|
||||||
|
void Debug(string message);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Logs the given message with severity <b>INFO</b>.
|
/// Logs the given message with severity <b>INFO</b>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
|
@ -13,8 +13,9 @@ namespace SafeExamBrowser.Contracts.Logging
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public enum LogLevel
|
public enum LogLevel
|
||||||
{
|
{
|
||||||
Info = 1,
|
Debug = 1,
|
||||||
Warning = 2,
|
Info = 2,
|
||||||
Error = 3
|
Warning = 3,
|
||||||
|
Error = 4
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,17 +6,10 @@
|
||||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
using SafeExamBrowser.Contracts.Configuration.Settings;
|
|
||||||
|
|
||||||
namespace SafeExamBrowser.Contracts.Runtime
|
namespace SafeExamBrowser.Contracts.Runtime
|
||||||
{
|
{
|
||||||
public interface IRuntimeController
|
public interface IRuntimeController
|
||||||
{
|
{
|
||||||
/// <summary>
|
|
||||||
/// Allows to specify the application settings to be used during runtime.
|
|
||||||
/// </summary>
|
|
||||||
ISettings Settings { set; }
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Wires up and starts the application event handling.
|
/// Wires up and starts the application event handling.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
|
@ -50,9 +50,14 @@
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Reference Include="System" />
|
<Reference Include="System" />
|
||||||
<Reference Include="Microsoft.CSharp" />
|
<Reference Include="Microsoft.CSharp" />
|
||||||
|
<Reference Include="System.ServiceModel" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Compile Include="Behaviour\IApplicationController.cs" />
|
<Compile Include="Behaviour\IApplicationController.cs" />
|
||||||
|
<Compile Include="Communication\ICommunicationHost.cs" />
|
||||||
|
<Compile Include="Communication\Messages\IMessage.cs" />
|
||||||
|
<Compile Include="Communication\Responses\IResponse.cs" />
|
||||||
|
<Compile Include="Communication\Responses\IConnectResponse.cs" />
|
||||||
<Compile Include="Configuration\IRuntimeInfo.cs" />
|
<Compile Include="Configuration\IRuntimeInfo.cs" />
|
||||||
<Compile Include="Configuration\Settings\ConfigurationMode.cs" />
|
<Compile Include="Configuration\Settings\ConfigurationMode.cs" />
|
||||||
<Compile Include="Runtime\IRuntimeController.cs" />
|
<Compile Include="Runtime\IRuntimeController.cs" />
|
||||||
|
|
|
@ -22,6 +22,7 @@ namespace SafeExamBrowser.Core.UnitTests.Logging
|
||||||
public void MustAddMessagesToLog()
|
public void MustAddMessagesToLog()
|
||||||
{
|
{
|
||||||
var sut = new Logger();
|
var sut = new Logger();
|
||||||
|
var debug = "I'm a debug message";
|
||||||
var info = "I'm an info message";
|
var info = "I'm an info message";
|
||||||
var warn = "I'm a warning!";
|
var warn = "I'm a warning!";
|
||||||
var error = "I AM AN ERROR!!";
|
var error = "I AM AN ERROR!!";
|
||||||
|
@ -30,6 +31,7 @@ namespace SafeExamBrowser.Core.UnitTests.Logging
|
||||||
var message = "I'm a simple text message";
|
var message = "I'm a simple text message";
|
||||||
var content = new LogText("I'm some raw log text...");
|
var content = new LogText("I'm some raw log text...");
|
||||||
|
|
||||||
|
sut.Debug(debug);
|
||||||
sut.Info(info);
|
sut.Info(info);
|
||||||
sut.Warn(warn);
|
sut.Warn(warn);
|
||||||
sut.Error(error);
|
sut.Error(error);
|
||||||
|
@ -39,34 +41,39 @@ namespace SafeExamBrowser.Core.UnitTests.Logging
|
||||||
|
|
||||||
var log = sut.GetLog();
|
var log = sut.GetLog();
|
||||||
|
|
||||||
Assert.IsTrue(log.Count == 7);
|
Assert.IsTrue(log.Count == 8);
|
||||||
|
|
||||||
Assert.IsTrue(info.Equals((log[0] as ILogMessage).Message));
|
Assert.IsTrue(debug.Equals((log[0] as ILogMessage).Message));
|
||||||
Assert.IsTrue((log[0] as ILogMessage).Severity == LogLevel.Info);
|
Assert.IsTrue((log[0] as ILogMessage).Severity == LogLevel.Debug);
|
||||||
|
|
||||||
Assert.IsTrue(warn.Equals((log[1] as ILogMessage).Message));
|
Assert.IsTrue(info.Equals((log[1] as ILogMessage).Message));
|
||||||
Assert.IsTrue((log[1] as ILogMessage).Severity == LogLevel.Warning);
|
Assert.IsTrue((log[1] as ILogMessage).Severity == LogLevel.Info);
|
||||||
|
|
||||||
Assert.IsTrue(error.Equals((log[2] as ILogMessage).Message));
|
Assert.IsTrue(warn.Equals((log[2] as ILogMessage).Message));
|
||||||
Assert.IsTrue((log[2] as ILogMessage).Severity == LogLevel.Error);
|
Assert.IsTrue((log[2] as ILogMessage).Severity == LogLevel.Warning);
|
||||||
|
|
||||||
Assert.IsTrue(error.Equals((log[3] as ILogMessage).Message));
|
Assert.IsTrue(error.Equals((log[3] as ILogMessage).Message));
|
||||||
Assert.IsTrue((log[3] as ILogMessage).Severity == LogLevel.Error);
|
Assert.IsTrue((log[3] as ILogMessage).Severity == LogLevel.Error);
|
||||||
Assert.IsTrue((log[4] as ILogText).Text.Contains(exceptionMessage));
|
|
||||||
|
|
||||||
Assert.IsTrue(message.Equals((log[5] as ILogText).Text));
|
Assert.IsTrue(error.Equals((log[4] as ILogMessage).Message));
|
||||||
|
Assert.IsTrue((log[4] as ILogMessage).Severity == LogLevel.Error);
|
||||||
|
Assert.IsTrue((log[5] as ILogText).Text.Contains(exceptionMessage));
|
||||||
|
|
||||||
Assert.IsTrue(content.Text.Equals((log[6] as ILogText).Text));
|
Assert.IsTrue(message.Equals((log[6] as ILogText).Text));
|
||||||
|
|
||||||
|
Assert.IsTrue(content.Text.Equals((log[7] as ILogText).Text));
|
||||||
}
|
}
|
||||||
|
|
||||||
[TestMethod]
|
[TestMethod]
|
||||||
public void MustReturnCopyOfLog()
|
public void MustReturnCopyOfLog()
|
||||||
{
|
{
|
||||||
var sut = new Logger();
|
var sut = new Logger();
|
||||||
|
var debug = "I'm a debug message";
|
||||||
var info = "I'm an info message";
|
var info = "I'm an info message";
|
||||||
var warn = "I'm a warning!";
|
var warn = "I'm a warning!";
|
||||||
var error = "I AM AN ERROR!!";
|
var error = "I AM AN ERROR!!";
|
||||||
|
|
||||||
|
sut.Debug(debug);
|
||||||
sut.Info(info);
|
sut.Info(info);
|
||||||
sut.Warn(warn);
|
sut.Warn(warn);
|
||||||
sut.Error(error);
|
sut.Error(error);
|
||||||
|
@ -87,6 +94,7 @@ namespace SafeExamBrowser.Core.UnitTests.Logging
|
||||||
{
|
{
|
||||||
var sut = new Logger();
|
var sut = new Logger();
|
||||||
|
|
||||||
|
Assert.ThrowsException<ArgumentNullException>(() => sut.Debug(null));
|
||||||
Assert.ThrowsException<ArgumentNullException>(() => sut.Info(null));
|
Assert.ThrowsException<ArgumentNullException>(() => sut.Info(null));
|
||||||
Assert.ThrowsException<ArgumentNullException>(() => sut.Warn(null));
|
Assert.ThrowsException<ArgumentNullException>(() => sut.Warn(null));
|
||||||
Assert.ThrowsException<ArgumentNullException>(() => sut.Error(null));
|
Assert.ThrowsException<ArgumentNullException>(() => sut.Error(null));
|
||||||
|
|
106
SafeExamBrowser.Core/Communication/CommunicationHostProxy.cs
Normal file
106
SafeExamBrowser.Core/Communication/CommunicationHostProxy.cs
Normal file
|
@ -0,0 +1,106 @@
|
||||||
|
/*
|
||||||
|
* 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
|
||||||
|
{
|
||||||
|
public class CommunicationHostProxy : ICommunicationHost
|
||||||
|
{
|
||||||
|
private string address;
|
||||||
|
private ILogger logger;
|
||||||
|
private ICommunicationHost channel;
|
||||||
|
|
||||||
|
public CommunicationHostProxy(ILogger logger, string address)
|
||||||
|
{
|
||||||
|
this.address = address;
|
||||||
|
this.logger = logger;
|
||||||
|
}
|
||||||
|
|
||||||
|
public IConnectResponse Connect(Guid? token = null)
|
||||||
|
{
|
||||||
|
var endpoint = new EndpointAddress(address);
|
||||||
|
|
||||||
|
channel = ChannelFactory<ICommunicationHost>.CreateChannel(new NetNamedPipeBinding(NetNamedPipeSecurityMode.Transport), endpoint);
|
||||||
|
(channel as ICommunicationObject).Closed += CommunicationHostProxy_Closed;
|
||||||
|
(channel as ICommunicationObject).Closing += CommunicationHostProxy_Closing;
|
||||||
|
(channel as ICommunicationObject).Faulted += CommunicationHostProxy_Faulted;
|
||||||
|
|
||||||
|
var response = channel.Connect(token);
|
||||||
|
|
||||||
|
logger.Debug($"Tried to connect to {address}, connection was {(response.ConnectionEstablished ? "established" : "refused")}.");
|
||||||
|
|
||||||
|
return response;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Disconnect(IMessage message)
|
||||||
|
{
|
||||||
|
if (ChannelIsReady())
|
||||||
|
{
|
||||||
|
channel.Disconnect(message);
|
||||||
|
logger.Debug($"Disconnected from {address}, transmitting {ToString(message)}.");
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new CommunicationException($"Tried to disconnect from host, but channel was {GetChannelState()}!");
|
||||||
|
}
|
||||||
|
|
||||||
|
public IResponse Send(IMessage message)
|
||||||
|
{
|
||||||
|
if (ChannelIsReady())
|
||||||
|
{
|
||||||
|
var response = channel.Send(message);
|
||||||
|
|
||||||
|
logger.Debug($"Sent {ToString(message)}, got {ToString(response)}.");
|
||||||
|
|
||||||
|
return response;
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new CommunicationException($"Tried to send {ToString(message)}, but channel was {GetChannelState()}!");
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool ChannelIsReady()
|
||||||
|
{
|
||||||
|
return channel != null && (channel as ICommunicationObject).State == CommunicationState.Opened;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void CommunicationHostProxy_Closed(object sender, EventArgs e)
|
||||||
|
{
|
||||||
|
logger.Debug("Communication channel has been closed.");
|
||||||
|
}
|
||||||
|
|
||||||
|
private void CommunicationHostProxy_Closing(object sender, EventArgs e)
|
||||||
|
{
|
||||||
|
logger.Debug("Communication channel is closing.");
|
||||||
|
}
|
||||||
|
|
||||||
|
private void CommunicationHostProxy_Faulted(object sender, EventArgs e)
|
||||||
|
{
|
||||||
|
logger.Error("Communication channel has faulted!");
|
||||||
|
}
|
||||||
|
|
||||||
|
private string GetChannelState()
|
||||||
|
{
|
||||||
|
return channel == null ? "null" : $"in state '{(channel as ICommunicationObject).State}'";
|
||||||
|
}
|
||||||
|
|
||||||
|
private string ToString(IMessage message)
|
||||||
|
{
|
||||||
|
return message != null ? $"message of type '{message.GetType()}'" : "no message";
|
||||||
|
}
|
||||||
|
|
||||||
|
private string ToString(IResponse response)
|
||||||
|
{
|
||||||
|
return response != null ? $"response of type '{response.GetType()}'" : "no response";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -21,6 +21,16 @@ namespace SafeExamBrowser.Core.Logging
|
||||||
private readonly IList<ILogContent> log = new List<ILogContent>();
|
private readonly IList<ILogContent> log = new List<ILogContent>();
|
||||||
private readonly IList<ILogObserver> observers = new List<ILogObserver>();
|
private readonly IList<ILogObserver> observers = new List<ILogObserver>();
|
||||||
|
|
||||||
|
public void Debug(string message)
|
||||||
|
{
|
||||||
|
if (message == null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(message));
|
||||||
|
}
|
||||||
|
|
||||||
|
Add(LogLevel.Debug, message);
|
||||||
|
}
|
||||||
|
|
||||||
public void Info(string message)
|
public void Info(string message)
|
||||||
{
|
{
|
||||||
if (message == null)
|
if (message == null)
|
||||||
|
|
|
@ -27,6 +27,11 @@ namespace SafeExamBrowser.Core.Logging
|
||||||
this.module = module;
|
this.module = module;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void Debug(string message)
|
||||||
|
{
|
||||||
|
logger.Debug(AppendModuleInfo(message));
|
||||||
|
}
|
||||||
|
|
||||||
public void Error(string message)
|
public void Error(string message)
|
||||||
{
|
{
|
||||||
logger.Error(AppendModuleInfo(message));
|
logger.Error(AppendModuleInfo(message));
|
||||||
|
|
|
@ -50,6 +50,7 @@
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Reference Include="System" />
|
<Reference Include="System" />
|
||||||
<Reference Include="Microsoft.CSharp" />
|
<Reference Include="Microsoft.CSharp" />
|
||||||
|
<Reference Include="System.ServiceModel" />
|
||||||
<Reference Include="System.Xml" />
|
<Reference Include="System.Xml" />
|
||||||
<Reference Include="System.Xml.Linq" />
|
<Reference Include="System.Xml.Linq" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
@ -57,6 +58,7 @@
|
||||||
<Compile Include="Behaviour\Operations\I18nOperation.cs" />
|
<Compile Include="Behaviour\Operations\I18nOperation.cs" />
|
||||||
<Compile Include="Behaviour\ShutdownController.cs" />
|
<Compile Include="Behaviour\ShutdownController.cs" />
|
||||||
<Compile Include="Behaviour\StartupController.cs" />
|
<Compile Include="Behaviour\StartupController.cs" />
|
||||||
|
<Compile Include="Communication\CommunicationHostProxy.cs" />
|
||||||
<Compile Include="Logging\DefaultLogFormatter.cs" />
|
<Compile Include="Logging\DefaultLogFormatter.cs" />
|
||||||
<Compile Include="Logging\LogFileWriter.cs" />
|
<Compile Include="Logging\LogFileWriter.cs" />
|
||||||
<Compile Include="Logging\LogMessage.cs" />
|
<Compile Include="Logging\LogMessage.cs" />
|
||||||
|
|
|
@ -14,7 +14,6 @@ using SafeExamBrowser.Contracts.Configuration;
|
||||||
using SafeExamBrowser.Contracts.Configuration.Settings;
|
using SafeExamBrowser.Contracts.Configuration.Settings;
|
||||||
using SafeExamBrowser.Contracts.I18n;
|
using SafeExamBrowser.Contracts.I18n;
|
||||||
using SafeExamBrowser.Contracts.Logging;
|
using SafeExamBrowser.Contracts.Logging;
|
||||||
using SafeExamBrowser.Contracts.Runtime;
|
|
||||||
using SafeExamBrowser.Contracts.UserInterface;
|
using SafeExamBrowser.Contracts.UserInterface;
|
||||||
using SafeExamBrowser.Runtime.Behaviour.Operations;
|
using SafeExamBrowser.Runtime.Behaviour.Operations;
|
||||||
|
|
||||||
|
@ -24,7 +23,6 @@ namespace SafeExamBrowser.Runtime.UnitTests.Behaviour.Operations
|
||||||
public class ConfigurationOperationTests
|
public class ConfigurationOperationTests
|
||||||
{
|
{
|
||||||
private Mock<ILogger> logger;
|
private Mock<ILogger> logger;
|
||||||
private Mock<IRuntimeController> controller;
|
|
||||||
private Mock<IRuntimeInfo> info;
|
private Mock<IRuntimeInfo> info;
|
||||||
private Mock<ISettingsRepository> repository;
|
private Mock<ISettingsRepository> repository;
|
||||||
private Mock<ISettings> settings;
|
private Mock<ISettings> settings;
|
||||||
|
@ -37,7 +35,6 @@ namespace SafeExamBrowser.Runtime.UnitTests.Behaviour.Operations
|
||||||
public void Initialize()
|
public void Initialize()
|
||||||
{
|
{
|
||||||
logger = new Mock<ILogger>();
|
logger = new Mock<ILogger>();
|
||||||
controller = new Mock<IRuntimeController>();
|
|
||||||
info = new Mock<IRuntimeInfo>();
|
info = new Mock<IRuntimeInfo>();
|
||||||
repository = new Mock<ISettingsRepository>();
|
repository = new Mock<ISettingsRepository>();
|
||||||
settings = new Mock<ISettings>();
|
settings = new Mock<ISettings>();
|
||||||
|
@ -55,23 +52,23 @@ namespace SafeExamBrowser.Runtime.UnitTests.Behaviour.Operations
|
||||||
[TestMethod]
|
[TestMethod]
|
||||||
public void MustNotFailWithoutCommandLineArgs()
|
public void MustNotFailWithoutCommandLineArgs()
|
||||||
{
|
{
|
||||||
controller.SetupSet(c => c.Settings = It.IsAny<ISettings>());
|
repository.Setup(r => r.LoadDefaults());
|
||||||
|
|
||||||
sut = new ConfigurationOperation(logger.Object, controller.Object, info.Object, repository.Object, text.Object, uiFactory.Object, null)
|
sut = new ConfigurationOperation(logger.Object, info.Object, repository.Object, text.Object, uiFactory.Object, null)
|
||||||
{
|
{
|
||||||
SplashScreen = splashScreen.Object
|
SplashScreen = splashScreen.Object
|
||||||
};
|
};
|
||||||
|
|
||||||
sut.Perform();
|
sut.Perform();
|
||||||
|
|
||||||
sut = new ConfigurationOperation(logger.Object, controller.Object, info.Object, repository.Object, text.Object, uiFactory.Object, new string[] { })
|
sut = new ConfigurationOperation(logger.Object, info.Object, repository.Object, text.Object, uiFactory.Object, new string[] { })
|
||||||
{
|
{
|
||||||
SplashScreen = splashScreen.Object
|
SplashScreen = splashScreen.Object
|
||||||
};
|
};
|
||||||
|
|
||||||
sut.Perform();
|
sut.Perform();
|
||||||
|
|
||||||
controller.VerifySet(c => c.Settings = It.IsAny<ISettings>(), Times.Exactly(2));
|
repository.Verify(r => r.LoadDefaults(), Times.Exactly(2));
|
||||||
}
|
}
|
||||||
|
|
||||||
[TestMethod]
|
[TestMethod]
|
||||||
|
@ -79,7 +76,7 @@ namespace SafeExamBrowser.Runtime.UnitTests.Behaviour.Operations
|
||||||
{
|
{
|
||||||
var path = @"an/invalid\path.'*%yolo/()";
|
var path = @"an/invalid\path.'*%yolo/()";
|
||||||
|
|
||||||
sut = new ConfigurationOperation(logger.Object, controller.Object, info.Object, repository.Object, text.Object, uiFactory.Object, new [] { "blubb.exe", path })
|
sut = new ConfigurationOperation(logger.Object, info.Object, repository.Object, text.Object, uiFactory.Object, new [] { "blubb.exe", path })
|
||||||
{
|
{
|
||||||
SplashScreen = splashScreen.Object
|
SplashScreen = splashScreen.Object
|
||||||
};
|
};
|
||||||
|
@ -96,14 +93,13 @@ namespace SafeExamBrowser.Runtime.UnitTests.Behaviour.Operations
|
||||||
info.SetupGet(r => r.ProgramDataFolder).Returns(location);
|
info.SetupGet(r => r.ProgramDataFolder).Returns(location);
|
||||||
info.SetupGet(r => r.AppDataFolder).Returns(location);
|
info.SetupGet(r => r.AppDataFolder).Returns(location);
|
||||||
|
|
||||||
sut = new ConfigurationOperation(logger.Object, controller.Object, info.Object, repository.Object, text.Object, uiFactory.Object, new[] { "blubb.exe", path })
|
sut = new ConfigurationOperation(logger.Object, info.Object, repository.Object, text.Object, uiFactory.Object, new[] { "blubb.exe", path })
|
||||||
{
|
{
|
||||||
SplashScreen = splashScreen.Object
|
SplashScreen = splashScreen.Object
|
||||||
};
|
};
|
||||||
|
|
||||||
sut.Perform();
|
sut.Perform();
|
||||||
|
|
||||||
controller.VerifySet(c => c.Settings = It.IsAny<ISettings>(), Times.Once);
|
|
||||||
repository.Verify(r => r.Load(It.Is<Uri>(u => u.Equals(new Uri(path)))), Times.Once);
|
repository.Verify(r => r.Load(It.Is<Uri>(u => u.Equals(new Uri(path)))), Times.Once);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -115,14 +111,13 @@ namespace SafeExamBrowser.Runtime.UnitTests.Behaviour.Operations
|
||||||
info.SetupGet(r => r.ProgramDataFolder).Returns(location);
|
info.SetupGet(r => r.ProgramDataFolder).Returns(location);
|
||||||
info.SetupGet(r => r.AppDataFolder).Returns($@"{location}\WRONG");
|
info.SetupGet(r => r.AppDataFolder).Returns($@"{location}\WRONG");
|
||||||
|
|
||||||
sut = new ConfigurationOperation(logger.Object, controller.Object, info.Object, repository.Object, text.Object, uiFactory.Object, null)
|
sut = new ConfigurationOperation(logger.Object, info.Object, repository.Object, text.Object, uiFactory.Object, null)
|
||||||
{
|
{
|
||||||
SplashScreen = splashScreen.Object
|
SplashScreen = splashScreen.Object
|
||||||
};
|
};
|
||||||
|
|
||||||
sut.Perform();
|
sut.Perform();
|
||||||
|
|
||||||
controller.VerifySet(c => c.Settings = It.IsAny<ISettings>(), Times.Once);
|
|
||||||
repository.Verify(r => r.Load(It.Is<Uri>(u => u.Equals(new Uri(Path.Combine(location, "SettingsDummy.txt"))))), Times.Once);
|
repository.Verify(r => r.Load(It.Is<Uri>(u => u.Equals(new Uri(Path.Combine(location, "SettingsDummy.txt"))))), Times.Once);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -133,28 +128,26 @@ namespace SafeExamBrowser.Runtime.UnitTests.Behaviour.Operations
|
||||||
|
|
||||||
info.SetupGet(r => r.AppDataFolder).Returns(location);
|
info.SetupGet(r => r.AppDataFolder).Returns(location);
|
||||||
|
|
||||||
sut = new ConfigurationOperation(logger.Object, controller.Object, info.Object, repository.Object, text.Object, uiFactory.Object, null)
|
sut = new ConfigurationOperation(logger.Object, info.Object, repository.Object, text.Object, uiFactory.Object, null)
|
||||||
{
|
{
|
||||||
SplashScreen = splashScreen.Object
|
SplashScreen = splashScreen.Object
|
||||||
};
|
};
|
||||||
|
|
||||||
sut.Perform();
|
sut.Perform();
|
||||||
|
|
||||||
controller.VerifySet(c => c.Settings = It.IsAny<ISettings>(), Times.Once);
|
|
||||||
repository.Verify(r => r.Load(It.Is<Uri>(u => u.Equals(new Uri(Path.Combine(location, "SettingsDummy.txt"))))), Times.Once);
|
repository.Verify(r => r.Load(It.Is<Uri>(u => u.Equals(new Uri(Path.Combine(location, "SettingsDummy.txt"))))), Times.Once);
|
||||||
}
|
}
|
||||||
|
|
||||||
[TestMethod]
|
[TestMethod]
|
||||||
public void MustFallbackToDefaultsAsLastPrio()
|
public void MustFallbackToDefaultsAsLastPrio()
|
||||||
{
|
{
|
||||||
sut = new ConfigurationOperation(logger.Object, controller.Object, info.Object, repository.Object, text.Object, uiFactory.Object, null)
|
sut = new ConfigurationOperation(logger.Object, info.Object, repository.Object, text.Object, uiFactory.Object, null)
|
||||||
{
|
{
|
||||||
SplashScreen = splashScreen.Object
|
SplashScreen = splashScreen.Object
|
||||||
};
|
};
|
||||||
|
|
||||||
sut.Perform();
|
sut.Perform();
|
||||||
|
|
||||||
controller.VerifySet(c => c.Settings = It.IsAny<ISettings>(), Times.Once);
|
|
||||||
repository.Verify(r => r.LoadDefaults(), Times.Once);
|
repository.Verify(r => r.LoadDefaults(), Times.Once);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -166,7 +159,7 @@ namespace SafeExamBrowser.Runtime.UnitTests.Behaviour.Operations
|
||||||
info.SetupGet(r => r.ProgramDataFolder).Returns(location);
|
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);
|
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, controller.Object, info.Object, repository.Object, text.Object, uiFactory.Object, null)
|
sut = new ConfigurationOperation(logger.Object, info.Object, repository.Object, text.Object, uiFactory.Object, null)
|
||||||
{
|
{
|
||||||
SplashScreen = splashScreen.Object
|
SplashScreen = splashScreen.Object
|
||||||
};
|
};
|
||||||
|
@ -181,7 +174,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);
|
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, controller.Object, info.Object, repository.Object, text.Object, uiFactory.Object, null)
|
sut = new ConfigurationOperation(logger.Object, info.Object, repository.Object, text.Object, uiFactory.Object, null)
|
||||||
{
|
{
|
||||||
SplashScreen = splashScreen.Object
|
SplashScreen = splashScreen.Object
|
||||||
};
|
};
|
||||||
|
|
|
@ -0,0 +1,22 @@
|
||||||
|
/*
|
||||||
|
* 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;
|
||||||
|
|
||||||
|
namespace SafeExamBrowser.Runtime.UnitTests.Behaviour.Operations
|
||||||
|
{
|
||||||
|
[TestClass]
|
||||||
|
public class ServiceOperationTests
|
||||||
|
{
|
||||||
|
[TestMethod]
|
||||||
|
public void Test()
|
||||||
|
{
|
||||||
|
// TODO
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -82,6 +82,7 @@
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Compile Include="Behaviour\Operations\ConfigurationOperationTests.cs" />
|
<Compile Include="Behaviour\Operations\ConfigurationOperationTests.cs" />
|
||||||
<Compile Include="Behaviour\Operations\RuntimeControllerOperationTests.cs" />
|
<Compile Include="Behaviour\Operations\RuntimeControllerOperationTests.cs" />
|
||||||
|
<Compile Include="Behaviour\Operations\ServiceOperationTests.cs" />
|
||||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|
|
@ -60,7 +60,7 @@ namespace SafeExamBrowser.Runtime
|
||||||
base.OnStartup(e);
|
base.OnStartup(e);
|
||||||
|
|
||||||
instances.BuildObjectGraph();
|
instances.BuildObjectGraph();
|
||||||
LogStartupInformation();
|
instances.LogStartupInformation();
|
||||||
|
|
||||||
var success = instances.StartupController.TryInitializeApplication(instances.StartupOperations);
|
var success = instances.StartupController.TryInitializeApplication(instances.StartupOperations);
|
||||||
|
|
||||||
|
@ -79,27 +79,11 @@ namespace SafeExamBrowser.Runtime
|
||||||
|
|
||||||
protected override void OnExit(ExitEventArgs e)
|
protected override void OnExit(ExitEventArgs e)
|
||||||
{
|
{
|
||||||
instances.Logger?.Log($"{Environment.NewLine}# Application terminated at {DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")}");
|
instances.LogShutdownInformation();
|
||||||
|
|
||||||
base.OnExit(e);
|
base.OnExit(e);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void LogStartupInformation()
|
|
||||||
{
|
|
||||||
var runtimeInfo = instances.RuntimeInfo;
|
|
||||||
var logger = instances.Logger;
|
|
||||||
var titleLine = $"/* {runtimeInfo.ProgramTitle}, Version {runtimeInfo.ProgramVersion}{Environment.NewLine}";
|
|
||||||
var copyrightLine = $"/* {runtimeInfo.ProgramCopyright}{Environment.NewLine}";
|
|
||||||
var emptyLine = $"/* {Environment.NewLine}";
|
|
||||||
var githubLine = $"/* Please visit https://github.com/SafeExamBrowser for more information.";
|
|
||||||
|
|
||||||
logger.Log($"{titleLine}{copyrightLine}{emptyLine}{githubLine}");
|
|
||||||
logger.Log(string.Empty);
|
|
||||||
logger.Log($"# Application started at {runtimeInfo.ApplicationStartTime.ToString("yyyy-MM-dd HH:mm:ss.fff")}");
|
|
||||||
logger.Log($"# Running on {instances.SystemInfo.OperatingSystemInfo}");
|
|
||||||
logger.Log(string.Empty);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void MainWindow_Closing(object sender, CancelEventArgs e)
|
private void MainWindow_Closing(object sender, CancelEventArgs e)
|
||||||
{
|
{
|
||||||
var operations = new Queue<IOperation>(instances.StartupOperations.Reverse());
|
var operations = new Queue<IOperation>(instances.StartupOperations.Reverse());
|
||||||
|
|
|
@ -13,7 +13,6 @@ using SafeExamBrowser.Contracts.Configuration;
|
||||||
using SafeExamBrowser.Contracts.Configuration.Settings;
|
using SafeExamBrowser.Contracts.Configuration.Settings;
|
||||||
using SafeExamBrowser.Contracts.I18n;
|
using SafeExamBrowser.Contracts.I18n;
|
||||||
using SafeExamBrowser.Contracts.Logging;
|
using SafeExamBrowser.Contracts.Logging;
|
||||||
using SafeExamBrowser.Contracts.Runtime;
|
|
||||||
using SafeExamBrowser.Contracts.UserInterface;
|
using SafeExamBrowser.Contracts.UserInterface;
|
||||||
|
|
||||||
namespace SafeExamBrowser.Runtime.Behaviour.Operations
|
namespace SafeExamBrowser.Runtime.Behaviour.Operations
|
||||||
|
@ -21,7 +20,6 @@ namespace SafeExamBrowser.Runtime.Behaviour.Operations
|
||||||
internal class ConfigurationOperation : IOperation
|
internal class ConfigurationOperation : IOperation
|
||||||
{
|
{
|
||||||
private ILogger logger;
|
private ILogger logger;
|
||||||
private IRuntimeController controller;
|
|
||||||
private IRuntimeInfo runtimeInfo;
|
private IRuntimeInfo runtimeInfo;
|
||||||
private ISettingsRepository repository;
|
private ISettingsRepository repository;
|
||||||
private IText text;
|
private IText text;
|
||||||
|
@ -33,7 +31,6 @@ namespace SafeExamBrowser.Runtime.Behaviour.Operations
|
||||||
|
|
||||||
public ConfigurationOperation(
|
public ConfigurationOperation(
|
||||||
ILogger logger,
|
ILogger logger,
|
||||||
IRuntimeController controller,
|
|
||||||
IRuntimeInfo runtimeInfo,
|
IRuntimeInfo runtimeInfo,
|
||||||
ISettingsRepository repository,
|
ISettingsRepository repository,
|
||||||
IText text,
|
IText text,
|
||||||
|
@ -41,7 +38,6 @@ namespace SafeExamBrowser.Runtime.Behaviour.Operations
|
||||||
string[] commandLineArgs)
|
string[] commandLineArgs)
|
||||||
{
|
{
|
||||||
this.logger = logger;
|
this.logger = logger;
|
||||||
this.controller = controller;
|
|
||||||
this.commandLineArgs = commandLineArgs;
|
this.commandLineArgs = commandLineArgs;
|
||||||
this.repository = repository;
|
this.repository = repository;
|
||||||
this.runtimeInfo = runtimeInfo;
|
this.runtimeInfo = runtimeInfo;
|
||||||
|
@ -62,11 +58,10 @@ namespace SafeExamBrowser.Runtime.Behaviour.Operations
|
||||||
logger.Info($"Loading configuration from '{uri.AbsolutePath}'...");
|
logger.Info($"Loading configuration from '{uri.AbsolutePath}'...");
|
||||||
settings = repository.Load(uri);
|
settings = repository.Load(uri);
|
||||||
|
|
||||||
if (settings.ConfigurationMode == ConfigurationMode.ConfigureClient && Abort())
|
if (settings.ConfigurationMode == ConfigurationMode.ConfigureClient && UserWantsToAbortStartup())
|
||||||
{
|
{
|
||||||
AbortStartup = true;
|
AbortStartup = true;
|
||||||
|
logger.Info($"The user chose to {(AbortStartup ? "abort" : "continue")} the application startup after successful client configuration.");
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -74,8 +69,6 @@ namespace SafeExamBrowser.Runtime.Behaviour.Operations
|
||||||
logger.Info("No valid settings file specified nor found in PROGRAMDATA or APPDATA - loading default settings...");
|
logger.Info("No valid settings file specified nor found in PROGRAMDATA or APPDATA - loading default settings...");
|
||||||
settings = repository.LoadDefaults();
|
settings = repository.LoadDefaults();
|
||||||
}
|
}
|
||||||
|
|
||||||
controller.Settings = settings;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Revert()
|
public void Revert()
|
||||||
|
@ -116,23 +109,13 @@ namespace SafeExamBrowser.Runtime.Behaviour.Operations
|
||||||
return isValidUri;
|
return isValidUri;
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool Abort()
|
private bool UserWantsToAbortStartup()
|
||||||
{
|
{
|
||||||
var message = text.Get(TextKey.MessageBox_ConfigureClientSuccess);
|
var message = text.Get(TextKey.MessageBox_ConfigureClientSuccess);
|
||||||
var title = text.Get(TextKey.MessageBox_ConfigureClientSuccessTitle);
|
var title = text.Get(TextKey.MessageBox_ConfigureClientSuccessTitle);
|
||||||
var quitDialogResult = uiFactory.Show(message, title, MessageBoxAction.YesNo, MessageBoxIcon.Question);
|
var abort = uiFactory.Show(message, title, MessageBoxAction.YesNo, MessageBoxIcon.Question);
|
||||||
var abort = quitDialogResult == MessageBoxResult.Yes;
|
|
||||||
|
|
||||||
if (abort)
|
return abort == MessageBoxResult.Yes;
|
||||||
{
|
|
||||||
logger.Info("The user chose to terminate the application after successful client configuration.");
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
logger.Info("The user chose to continue starting up the application after successful client configuration.");
|
|
||||||
}
|
|
||||||
|
|
||||||
return abort;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,46 @@
|
||||||
|
/*
|
||||||
|
* 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;
|
||||||
|
using SafeExamBrowser.Contracts.Communication;
|
||||||
|
using SafeExamBrowser.Contracts.Configuration.Settings;
|
||||||
|
using SafeExamBrowser.Contracts.Logging;
|
||||||
|
using SafeExamBrowser.Contracts.UserInterface;
|
||||||
|
|
||||||
|
namespace SafeExamBrowser.Runtime.Behaviour.Operations
|
||||||
|
{
|
||||||
|
internal class ServiceOperation : IOperation
|
||||||
|
{
|
||||||
|
private ICommunicationHost serviceHost;
|
||||||
|
private ILogger logger;
|
||||||
|
private ISettingsRepository settingsRepository;
|
||||||
|
|
||||||
|
public bool AbortStartup { get; private set; }
|
||||||
|
public ISplashScreen SplashScreen { private get; set; }
|
||||||
|
|
||||||
|
public ServiceOperation(ICommunicationHost serviceHost, ILogger logger, ISettingsRepository settingsRepository)
|
||||||
|
{
|
||||||
|
this.serviceHost = serviceHost;
|
||||||
|
this.logger = logger;
|
||||||
|
this.settingsRepository = settingsRepository;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Perform()
|
||||||
|
{
|
||||||
|
logger.Info("Initializing service connection...");
|
||||||
|
// SplashScreen.UpdateText(...)
|
||||||
|
|
||||||
|
// TODO
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Revert()
|
||||||
|
{
|
||||||
|
// TODO
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -17,6 +17,7 @@ using SafeExamBrowser.Contracts.Configuration;
|
||||||
using SafeExamBrowser.Contracts.Logging;
|
using SafeExamBrowser.Contracts.Logging;
|
||||||
using SafeExamBrowser.Core.Behaviour;
|
using SafeExamBrowser.Core.Behaviour;
|
||||||
using SafeExamBrowser.Core.Behaviour.Operations;
|
using SafeExamBrowser.Core.Behaviour.Operations;
|
||||||
|
using SafeExamBrowser.Core.Communication;
|
||||||
using SafeExamBrowser.Core.I18n;
|
using SafeExamBrowser.Core.I18n;
|
||||||
using SafeExamBrowser.Core.Logging;
|
using SafeExamBrowser.Core.Logging;
|
||||||
using SafeExamBrowser.Runtime.Behaviour;
|
using SafeExamBrowser.Runtime.Behaviour;
|
||||||
|
@ -28,11 +29,12 @@ namespace SafeExamBrowser.Runtime
|
||||||
{
|
{
|
||||||
internal class CompositionRoot
|
internal class CompositionRoot
|
||||||
{
|
{
|
||||||
internal ILogger Logger { get; private set; }
|
private ILogger logger;
|
||||||
internal RuntimeInfo RuntimeInfo { get; private set; }
|
private RuntimeInfo runtimeInfo;
|
||||||
|
private ISystemInfo systemInfo;
|
||||||
|
|
||||||
internal IShutdownController ShutdownController { get; private set; }
|
internal IShutdownController ShutdownController { get; private set; }
|
||||||
internal IStartupController StartupController { get; private set; }
|
internal IStartupController StartupController { get; private set; }
|
||||||
internal ISystemInfo SystemInfo { get; private set; }
|
|
||||||
internal Queue<IOperation> StartupOperations { get; private set; }
|
internal Queue<IOperation> StartupOperations { get; private set; }
|
||||||
|
|
||||||
internal void BuildObjectGraph()
|
internal void BuildObjectGraph()
|
||||||
|
@ -42,24 +44,45 @@ namespace SafeExamBrowser.Runtime
|
||||||
var settingsRepository = new SettingsRepository();
|
var settingsRepository = new SettingsRepository();
|
||||||
var uiFactory = new UserInterfaceFactory();
|
var uiFactory = new UserInterfaceFactory();
|
||||||
|
|
||||||
Logger = new Logger();
|
logger = new Logger();
|
||||||
RuntimeInfo = new RuntimeInfo();
|
runtimeInfo = new RuntimeInfo();
|
||||||
SystemInfo = new SystemInfo();
|
systemInfo = new SystemInfo();
|
||||||
|
|
||||||
InitializeRuntimeInfo();
|
InitializeRuntimeInfo();
|
||||||
InitializeLogging();
|
InitializeLogging();
|
||||||
|
|
||||||
var text = new Text(Logger);
|
var text = new Text(logger);
|
||||||
var runtimeController = new RuntimeController(new ModuleLogger(Logger, typeof(RuntimeController)));
|
var runtimeController = new RuntimeController(new ModuleLogger(logger, typeof(RuntimeController)));
|
||||||
|
var serviceProxy = new CommunicationHostProxy(new ModuleLogger(logger, typeof(CommunicationHostProxy)), "net.pipe://localhost/safeexambrowser/service");
|
||||||
|
|
||||||
ShutdownController = new ShutdownController(Logger, RuntimeInfo, text, uiFactory);
|
ShutdownController = new ShutdownController(logger, runtimeInfo, text, uiFactory);
|
||||||
StartupController = new StartupController(Logger, RuntimeInfo, SystemInfo, text, uiFactory);
|
StartupController = new StartupController(logger, runtimeInfo, systemInfo, text, uiFactory);
|
||||||
|
|
||||||
StartupOperations = new Queue<IOperation>();
|
StartupOperations = new Queue<IOperation>();
|
||||||
StartupOperations.Enqueue(new I18nOperation(Logger, text));
|
StartupOperations.Enqueue(new I18nOperation(logger, text));
|
||||||
StartupOperations.Enqueue(new ConfigurationOperation(Logger, runtimeController, RuntimeInfo, settingsRepository, text, uiFactory, args));
|
StartupOperations.Enqueue(new ConfigurationOperation(logger, runtimeInfo, settingsRepository, text, uiFactory, args));
|
||||||
|
StartupOperations.Enqueue(new ServiceOperation(serviceProxy, logger, settingsRepository));
|
||||||
//StartupOperations.Enqueue(new KioskModeOperation());
|
//StartupOperations.Enqueue(new KioskModeOperation());
|
||||||
StartupOperations.Enqueue(new RuntimeControllerOperation(runtimeController, Logger));
|
StartupOperations.Enqueue(new RuntimeControllerOperation(runtimeController, logger));
|
||||||
|
}
|
||||||
|
|
||||||
|
internal void LogStartupInformation()
|
||||||
|
{
|
||||||
|
var titleLine = $"/* {runtimeInfo.ProgramTitle}, Version {runtimeInfo.ProgramVersion}{Environment.NewLine}";
|
||||||
|
var copyrightLine = $"/* {runtimeInfo.ProgramCopyright}{Environment.NewLine}";
|
||||||
|
var emptyLine = $"/* {Environment.NewLine}";
|
||||||
|
var githubLine = $"/* Please visit https://www.github.com/SafeExamBrowser for more information.";
|
||||||
|
|
||||||
|
logger.Log($"{titleLine}{copyrightLine}{emptyLine}{githubLine}");
|
||||||
|
logger.Log(string.Empty);
|
||||||
|
logger.Log($"# Application started at {runtimeInfo.ApplicationStartTime.ToString("yyyy-MM-dd HH:mm:ss.fff")}");
|
||||||
|
logger.Log($"# Running on {systemInfo.OperatingSystemInfo}");
|
||||||
|
logger.Log(string.Empty);
|
||||||
|
}
|
||||||
|
|
||||||
|
internal void LogShutdownInformation()
|
||||||
|
{
|
||||||
|
logger?.Log($"{Environment.NewLine}# Application terminated at {DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")}");
|
||||||
}
|
}
|
||||||
|
|
||||||
private void InitializeRuntimeInfo()
|
private void InitializeRuntimeInfo()
|
||||||
|
@ -70,25 +93,25 @@ namespace SafeExamBrowser.Runtime
|
||||||
var logFolder = Path.Combine(appDataFolder, "Logs");
|
var logFolder = Path.Combine(appDataFolder, "Logs");
|
||||||
var logFilePrefix = startTime.ToString("yyyy-MM-dd\\_HH\\hmm\\mss\\s");
|
var logFilePrefix = startTime.ToString("yyyy-MM-dd\\_HH\\hmm\\mss\\s");
|
||||||
|
|
||||||
RuntimeInfo.ApplicationStartTime = startTime;
|
runtimeInfo.ApplicationStartTime = startTime;
|
||||||
RuntimeInfo.AppDataFolder = appDataFolder;
|
runtimeInfo.AppDataFolder = appDataFolder;
|
||||||
RuntimeInfo.BrowserCachePath = Path.Combine(appDataFolder, "Cache");
|
runtimeInfo.BrowserCachePath = Path.Combine(appDataFolder, "Cache");
|
||||||
RuntimeInfo.BrowserLogFile = Path.Combine(logFolder, $"{logFilePrefix}_Browser.txt");
|
runtimeInfo.BrowserLogFile = Path.Combine(logFolder, $"{logFilePrefix}_Browser.txt");
|
||||||
RuntimeInfo.ClientLogFile = Path.Combine(logFolder, $"{logFilePrefix}_Client.txt");
|
runtimeInfo.ClientLogFile = Path.Combine(logFolder, $"{logFilePrefix}_Client.txt");
|
||||||
RuntimeInfo.DefaultSettingsFileName = "SebClientSettings.seb";
|
runtimeInfo.DefaultSettingsFileName = "SebClientSettings.seb";
|
||||||
RuntimeInfo.ProgramCopyright = executable.GetCustomAttribute<AssemblyCopyrightAttribute>().Copyright;
|
runtimeInfo.ProgramCopyright = executable.GetCustomAttribute<AssemblyCopyrightAttribute>().Copyright;
|
||||||
RuntimeInfo.ProgramDataFolder = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData), nameof(SafeExamBrowser));
|
runtimeInfo.ProgramDataFolder = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData), nameof(SafeExamBrowser));
|
||||||
RuntimeInfo.ProgramTitle = executable.GetCustomAttribute<AssemblyTitleAttribute>().Title;
|
runtimeInfo.ProgramTitle = executable.GetCustomAttribute<AssemblyTitleAttribute>().Title;
|
||||||
RuntimeInfo.ProgramVersion = executable.GetCustomAttribute<AssemblyInformationalVersionAttribute>().InformationalVersion;
|
runtimeInfo.ProgramVersion = executable.GetCustomAttribute<AssemblyInformationalVersionAttribute>().InformationalVersion;
|
||||||
RuntimeInfo.RuntimeLogFile = Path.Combine(logFolder, $"{logFilePrefix}_Runtime.txt");
|
runtimeInfo.RuntimeLogFile = Path.Combine(logFolder, $"{logFilePrefix}_Runtime.txt");
|
||||||
}
|
}
|
||||||
|
|
||||||
private void InitializeLogging()
|
private void InitializeLogging()
|
||||||
{
|
{
|
||||||
var logFileWriter = new LogFileWriter(new DefaultLogFormatter(), RuntimeInfo.RuntimeLogFile);
|
var logFileWriter = new LogFileWriter(new DefaultLogFormatter(), runtimeInfo.RuntimeLogFile);
|
||||||
|
|
||||||
logFileWriter.Initialize();
|
logFileWriter.Initialize();
|
||||||
Logger.Subscribe(logFileWriter);
|
logger.Subscribe(logFileWriter);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -89,6 +89,7 @@
|
||||||
<Compile Include="App.cs" />
|
<Compile Include="App.cs" />
|
||||||
<Compile Include="Behaviour\Operations\ConfigurationOperation.cs" />
|
<Compile Include="Behaviour\Operations\ConfigurationOperation.cs" />
|
||||||
<Compile Include="Behaviour\Operations\RuntimeControllerOperation.cs" />
|
<Compile Include="Behaviour\Operations\RuntimeControllerOperation.cs" />
|
||||||
|
<Compile Include="Behaviour\Operations\ServiceOperation.cs" />
|
||||||
<Compile Include="CompositionRoot.cs" />
|
<Compile Include="CompositionRoot.cs" />
|
||||||
<Compile Include="Properties\AssemblyInfo.cs">
|
<Compile Include="Properties\AssemblyInfo.cs">
|
||||||
<SubType>Code</SubType>
|
<SubType>Code</SubType>
|
||||||
|
|
Loading…
Reference in a new issue