diff --git a/SafeExamBrowser.Browser/BrowserApplicationController.cs b/SafeExamBrowser.Browser/BrowserApplicationController.cs index 1d469757..57efa3b8 100644 --- a/SafeExamBrowser.Browser/BrowserApplicationController.cs +++ b/SafeExamBrowser.Browser/BrowserApplicationController.cs @@ -24,6 +24,8 @@ namespace SafeExamBrowser.Browser { public class BrowserApplicationController : IBrowserApplicationController { + private int instanceIdCounter = default(int); + private AppConfig appConfig; private IApplicationButton button; private IList instances; @@ -57,6 +59,8 @@ namespace SafeExamBrowser.Browser var cefSettings = InitializeCefSettings(); var success = Cef.Initialize(cefSettings, true, null); + logger.Info("Initialized CEF."); + if (!success) { throw new Exception("Failed to initialize the browser engine!"); @@ -75,14 +79,20 @@ namespace SafeExamBrowser.Browser { instance.Terminated -= Instance_Terminated; instance.Window.Close(); + + logger.Info($"Terminated browser instance {instance.Id}."); } Cef.Shutdown(); + + logger.Info("Terminated CEF."); } private void CreateNewInstance() { - var instance = new BrowserApplicationInstance(appConfig, settings, text, uiFactory, instances.Count == 0); + var id = new BrowserInstanceIdentifier(++instanceIdCounter); + var isMainInstance = instances.Count == 0; + var instance = new BrowserApplicationInstance(appConfig, settings, id, isMainInstance, text, uiFactory); instance.Initialize(); instance.ConfigurationDownloadRequested += (fileName, args) => ConfigurationDownloadRequested?.Invoke(fileName, args); @@ -91,36 +101,44 @@ namespace SafeExamBrowser.Browser button.RegisterInstance(instance); instances.Add(instance); instance.Window.Show(); + + logger.Info($"Created browser instance {instance.Id}."); } private CefSettings InitializeCefSettings() { + var warning = appConfig.LogLevel == LogLevel.Warning; + var error = appConfig.LogLevel == LogLevel.Error; var cefSettings = new CefSettings { CachePath = appConfig.BrowserCachePath, LogFile = appConfig.BrowserLogFile, - // TODO: Set according to current application LogLevel, but avoid verbose! - LogSeverity = LogSeverity.Info + LogSeverity = error ? LogSeverity.Error : (warning ? LogSeverity.Warning : LogSeverity.Info) }; + logger.Debug($"CEF cache path is '{cefSettings.CachePath}'."); + logger.Debug($"CEF log file is '{cefSettings.LogFile}'."); + logger.Debug($"CEF log severity is '{cefSettings.LogSeverity}'."); + return cefSettings; } - private void Button_OnClick(Guid? instanceId = null) + private void Button_OnClick(InstanceIdentifier id = null) { - if (instanceId.HasValue) - { - instances.FirstOrDefault(i => i.Id == instanceId)?.Window?.BringToForeground(); - } - else + if (id is null) { CreateNewInstance(); } + else + { + instances.FirstOrDefault(i => i.Id == id)?.Window?.BringToForeground(); + } } - private void Instance_Terminated(Guid id) + private void Instance_Terminated(InstanceIdentifier id) { instances.Remove(instances.FirstOrDefault(i => i.Id == id)); + logger.Info($"Browser instance {id} was terminated."); } } } diff --git a/SafeExamBrowser.Browser/BrowserApplicationInstance.cs b/SafeExamBrowser.Browser/BrowserApplicationInstance.cs index 3374ffdf..811a58fd 100644 --- a/SafeExamBrowser.Browser/BrowserApplicationInstance.cs +++ b/SafeExamBrowser.Browser/BrowserApplicationInstance.cs @@ -6,7 +6,6 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -using System; using SafeExamBrowser.Browser.Handlers; using SafeExamBrowser.Contracts.Behaviour; using SafeExamBrowser.Contracts.Behaviour.Events; @@ -30,7 +29,7 @@ namespace SafeExamBrowser.Browser private IText text; private IUserInterfaceFactory uiFactory; - public Guid Id { get; private set; } + public InstanceIdentifier Id { get; private set; } public string Name { get; private set; } public IWindow Window { get { return window; } } @@ -41,11 +40,13 @@ namespace SafeExamBrowser.Browser public BrowserApplicationInstance( AppConfig appConfig, BrowserSettings settings, + InstanceIdentifier id, + bool isMainInstance, IText text, - IUserInterfaceFactory uiFactory, - bool isMainInstance) + IUserInterfaceFactory uiFactory) { this.appConfig = appConfig; + this.Id = id; this.isMainInstance = isMainInstance; this.settings = settings; this.text = text; @@ -56,7 +57,6 @@ namespace SafeExamBrowser.Browser { var downloadHandler = new DownloadHandler(appConfig, settings); - Id = Guid.NewGuid(); downloadHandler.ConfigurationDownloadRequested += (fileName, args) => ConfigurationDownloadRequested?.Invoke(fileName, args); control = new BrowserControl(appConfig, settings, text); diff --git a/SafeExamBrowser.Browser/BrowserInstanceIdentifier.cs b/SafeExamBrowser.Browser/BrowserInstanceIdentifier.cs new file mode 100644 index 00000000..bcc743e2 --- /dev/null +++ b/SafeExamBrowser.Browser/BrowserInstanceIdentifier.cs @@ -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 SafeExamBrowser.Contracts.Behaviour; + +namespace SafeExamBrowser.Browser +{ + internal class BrowserInstanceIdentifier : InstanceIdentifier + { + public int Value { get; private set; } + + public BrowserInstanceIdentifier(int id) + { + Value = id; + } + + public override bool Equals(object other) + { + if (other is BrowserInstanceIdentifier id) + { + return Value == id.Value; + } + + return false; + } + + public override int GetHashCode() + { + return Value.GetHashCode(); + } + + public override string ToString() + { + return $"#{Value}"; + } + } +} diff --git a/SafeExamBrowser.Browser/SafeExamBrowser.Browser.csproj b/SafeExamBrowser.Browser/SafeExamBrowser.Browser.csproj index 8831c9ce..d1af4713 100644 --- a/SafeExamBrowser.Browser/SafeExamBrowser.Browser.csproj +++ b/SafeExamBrowser.Browser/SafeExamBrowser.Browser.csproj @@ -65,6 +65,7 @@ + Component diff --git a/SafeExamBrowser.Client/CompositionRoot.cs b/SafeExamBrowser.Client/CompositionRoot.cs index fa8f0a28..cfe7bdb0 100644 --- a/SafeExamBrowser.Client/CompositionRoot.cs +++ b/SafeExamBrowser.Client/CompositionRoot.cs @@ -155,7 +155,7 @@ namespace SafeExamBrowser.Client private IOperation BuildBrowserOperation() { - var moduleLogger = new ModuleLogger(logger, typeof(BrowserApplicationController)); + var moduleLogger = new ModuleLogger(logger, "BrowserController"); var browserController = new BrowserApplicationController(configuration.AppConfig, configuration.Settings.Browser, moduleLogger, messageBox, text, uiFactory); var browserInfo = new BrowserApplicationInfo(); var operation = new BrowserOperation(browserController, browserInfo, logger, Taskbar, uiFactory); diff --git a/SafeExamBrowser.Configuration/ConfigurationRepository.cs b/SafeExamBrowser.Configuration/ConfigurationRepository.cs index 01a67cb0..6c3bc618 100644 --- a/SafeExamBrowser.Configuration/ConfigurationRepository.cs +++ b/SafeExamBrowser.Configuration/ConfigurationRepository.cs @@ -11,6 +11,7 @@ using System.IO; using System.Reflection; using SafeExamBrowser.Contracts.Configuration; using SafeExamBrowser.Contracts.Configuration.Settings; +using SafeExamBrowser.Contracts.Logging; namespace SafeExamBrowser.Configuration { @@ -81,7 +82,7 @@ namespace SafeExamBrowser.Configuration CurrentSettings = new Settings(); - CurrentSettings.KioskMode = KioskMode.DisableExplorerShell; + CurrentSettings.KioskMode = KioskMode.None; CurrentSettings.ServicePolicy = ServicePolicy.Optional; CurrentSettings.Browser.StartUrl = "https://www.safeexambrowser.org/testing"; @@ -117,6 +118,7 @@ namespace SafeExamBrowser.Configuration appConfig.ConfigurationFileExtension = ".seb"; appConfig.DefaultSettingsFileName = "SebClientSettings.seb"; appConfig.DownloadDirectory = Path.Combine(appDataFolder, "Downloads"); + appConfig.LogLevel = LogLevel.Debug; appConfig.ProgramCopyright = executable.GetCustomAttribute().Copyright; appConfig.ProgramDataFolder = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData), nameof(SafeExamBrowser)); appConfig.ProgramTitle = executable.GetCustomAttribute().Title; diff --git a/SafeExamBrowser.Contracts/Behaviour/Events/InstanceTerminatedEventHandler.cs b/SafeExamBrowser.Contracts/Behaviour/Events/InstanceTerminatedEventHandler.cs index 6828f8f5..ddad6d91 100644 --- a/SafeExamBrowser.Contracts/Behaviour/Events/InstanceTerminatedEventHandler.cs +++ b/SafeExamBrowser.Contracts/Behaviour/Events/InstanceTerminatedEventHandler.cs @@ -6,12 +6,11 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -using System; namespace SafeExamBrowser.Contracts.Behaviour.Events { /// /// Event handler used to indicate that an application instance with a particular ID has terminated. /// - public delegate void InstanceTerminatedEventHandler(Guid id); + public delegate void InstanceTerminatedEventHandler(InstanceIdentifier id); } diff --git a/SafeExamBrowser.Contracts/Behaviour/IApplicationInstance.cs b/SafeExamBrowser.Contracts/Behaviour/IApplicationInstance.cs index 8f4a2c05..668fc4a8 100644 --- a/SafeExamBrowser.Contracts/Behaviour/IApplicationInstance.cs +++ b/SafeExamBrowser.Contracts/Behaviour/IApplicationInstance.cs @@ -6,7 +6,6 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -using System; using SafeExamBrowser.Contracts.Behaviour.Events; using SafeExamBrowser.Contracts.UserInterface.Windows; @@ -20,7 +19,7 @@ namespace SafeExamBrowser.Contracts.Behaviour /// /// The unique identifier for the application instance. /// - Guid Id { get; } + InstanceIdentifier Id { get; } /// /// The name or (document) title of the application instance. diff --git a/SafeExamBrowser.Contracts/Behaviour/InstanceIdentifier.cs b/SafeExamBrowser.Contracts/Behaviour/InstanceIdentifier.cs new file mode 100644 index 00000000..5b23d6c4 --- /dev/null +++ b/SafeExamBrowser.Contracts/Behaviour/InstanceIdentifier.cs @@ -0,0 +1,41 @@ +/* + * 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.Behaviour +{ + /// + /// Defines an identifier which uniquely identifies an in the context of a (third-party) application. + /// + public abstract class InstanceIdentifier + { + /// + /// Determines whether two identifiers are equal (i.e. whether they identify the same ). + /// + public static bool operator ==(InstanceIdentifier a, InstanceIdentifier b) => Equals(a, b); + + /// + /// Determines whether two identifiers are different (i.e. whether they identify different s). + /// + public static bool operator !=(InstanceIdentifier a, InstanceIdentifier b) => !Equals(a, b); + + /// + /// Indicates whether the given object is an for the same . + /// + public abstract override bool Equals(object other); + + /// + /// Returns a hash code for the identifier. + /// + public abstract override int GetHashCode(); + + /// + /// Returns a human-readable string representation of the identifier. + /// + public abstract override string ToString(); + } +} diff --git a/SafeExamBrowser.Contracts/Configuration/AppConfig.cs b/SafeExamBrowser.Contracts/Configuration/AppConfig.cs index 73c81271..62800bbe 100644 --- a/SafeExamBrowser.Contracts/Configuration/AppConfig.cs +++ b/SafeExamBrowser.Contracts/Configuration/AppConfig.cs @@ -7,6 +7,7 @@ */ using System; +using SafeExamBrowser.Contracts.Logging; namespace SafeExamBrowser.Contracts.Configuration { @@ -71,6 +72,11 @@ namespace SafeExamBrowser.Contracts.Configuration /// public string DownloadDirectory { get; set; } + /// + /// The currently active, global log severity threshold. + /// + public LogLevel LogLevel { get; set; } + /// /// The copyright information for the application (i.e. the executing assembly). /// diff --git a/SafeExamBrowser.Contracts/Logging/ILogger.cs b/SafeExamBrowser.Contracts/Logging/ILogger.cs index e832c554..8fd8e44d 100644 --- a/SafeExamBrowser.Contracts/Logging/ILogger.cs +++ b/SafeExamBrowser.Contracts/Logging/ILogger.cs @@ -17,32 +17,32 @@ namespace SafeExamBrowser.Contracts.Logging public interface ILogger { /// - /// Logs the given message with severity DEBUG. + /// Logs the given message with severity . /// /// void Debug(string message); /// - /// Logs the given message with severity INFO. + /// Logs the given message with severity . /// /// void Info(string message); /// - /// Logs the given message with severity WARNING. + /// Logs the given message with severity . /// /// void Warn(string message); /// - /// Logs the given message with severity ERROR. + /// Logs the given message with severity . /// /// void Error(string message); /// - /// Logs the given message with severity ERROR and includes information about - /// the specified exception (i.e. type, message and stacktrace). + /// Logs the given message with severity and includes + /// information about the specified exception (i.e. type, message and stacktrace). /// /// void Error(string message, Exception exception); @@ -60,7 +60,7 @@ namespace SafeExamBrowser.Contracts.Logging void Log(ILogContent content); /// - /// Suscribes an observer to the application log. + /// Subscribes an observer to the application log. /// /// void Subscribe(ILogObserver observer); diff --git a/SafeExamBrowser.Contracts/SafeExamBrowser.Contracts.csproj b/SafeExamBrowser.Contracts/SafeExamBrowser.Contracts.csproj index 1b846b34..4234a881 100644 --- a/SafeExamBrowser.Contracts/SafeExamBrowser.Contracts.csproj +++ b/SafeExamBrowser.Contracts/SafeExamBrowser.Contracts.csproj @@ -55,6 +55,7 @@ + diff --git a/SafeExamBrowser.Contracts/UserInterface/Taskbar/Events/ApplicationButtonClickedEventHandler.cs b/SafeExamBrowser.Contracts/UserInterface/Taskbar/Events/ApplicationButtonClickedEventHandler.cs index dc1cceab..efb3c5f7 100644 --- a/SafeExamBrowser.Contracts/UserInterface/Taskbar/Events/ApplicationButtonClickedEventHandler.cs +++ b/SafeExamBrowser.Contracts/UserInterface/Taskbar/Events/ApplicationButtonClickedEventHandler.cs @@ -6,7 +6,7 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -using System; +using SafeExamBrowser.Contracts.Behaviour; namespace SafeExamBrowser.Contracts.UserInterface.Taskbar.Events { @@ -14,5 +14,5 @@ namespace SafeExamBrowser.Contracts.UserInterface.Taskbar.Events /// Indicates that an has been clicked, optionally specifying the ID of the selected instance (if /// multiple instances of the same application are running). /// - public delegate void ApplicationButtonClickedEventHandler(Guid? instanceId = null); + public delegate void ApplicationButtonClickedEventHandler(InstanceIdentifier id = null); } diff --git a/SafeExamBrowser.Contracts/WindowsApi/IExplorerShell.cs b/SafeExamBrowser.Contracts/WindowsApi/IExplorerShell.cs index 492d2e96..768a1e5b 100644 --- a/SafeExamBrowser.Contracts/WindowsApi/IExplorerShell.cs +++ b/SafeExamBrowser.Contracts/WindowsApi/IExplorerShell.cs @@ -8,6 +8,9 @@ namespace SafeExamBrowser.Contracts.WindowsApi { + /// + /// Defines an abstraction of the Windows explorer shell (i.e. the process controlling the GUI of the operating system). + /// public interface IExplorerShell { /// diff --git a/SafeExamBrowser.Core/Communication/Proxies/BaseProxy.cs b/SafeExamBrowser.Core/Communication/Proxies/BaseProxy.cs index e547d38a..b32ca39d 100644 --- a/SafeExamBrowser.Core/Communication/Proxies/BaseProxy.cs +++ b/SafeExamBrowser.Core/Communication/Proxies/BaseProxy.cs @@ -23,7 +23,7 @@ namespace SafeExamBrowser.Core.Communication.Proxies public abstract class BaseProxy : ICommunicationProxy { private const int ONE_MINUTE = 60000; - private static readonly object @lock = new object(); + private readonly object @lock = new object(); private string address; private IProxyObject proxy; diff --git a/SafeExamBrowser.Core/Logging/LogFileWriter.cs b/SafeExamBrowser.Core/Logging/LogFileWriter.cs index 5d932be8..863ca779 100644 --- a/SafeExamBrowser.Core/Logging/LogFileWriter.cs +++ b/SafeExamBrowser.Core/Logging/LogFileWriter.cs @@ -17,7 +17,7 @@ namespace SafeExamBrowser.Core.Logging /// public class LogFileWriter : ILogObserver { - private static readonly object @lock = new object(); + private readonly object @lock = new object(); private readonly string filePath; private readonly ILogContentFormatter formatter; diff --git a/SafeExamBrowser.Core/Logging/Logger.cs b/SafeExamBrowser.Core/Logging/Logger.cs index 63de193a..c910dc3e 100644 --- a/SafeExamBrowser.Core/Logging/Logger.cs +++ b/SafeExamBrowser.Core/Logging/Logger.cs @@ -20,7 +20,7 @@ namespace SafeExamBrowser.Core.Logging /// public class Logger : ILogger { - private static readonly object @lock = new object(); + private readonly object @lock = new object(); private readonly IList log = new List(); private readonly IList observers = new List(); diff --git a/SafeExamBrowser.Core/Logging/ModuleLogger.cs b/SafeExamBrowser.Core/Logging/ModuleLogger.cs index b48a2d70..d7ba37b0 100644 --- a/SafeExamBrowser.Core/Logging/ModuleLogger.cs +++ b/SafeExamBrowser.Core/Logging/ModuleLogger.cs @@ -18,12 +18,16 @@ namespace SafeExamBrowser.Core.Logging public class ModuleLogger : ILogger { private ILogger logger; - private Type module; + private string moduleInfo; - public ModuleLogger(ILogger logger, Type module) + public ModuleLogger(ILogger logger, string moduleInfo) { this.logger = logger; - this.module = module; + this.moduleInfo = moduleInfo; + } + + public ModuleLogger(ILogger logger, Type module) : this(logger, module.Name) + { } public void Debug(string message) @@ -78,7 +82,7 @@ namespace SafeExamBrowser.Core.Logging private string AppendModuleInfo(string message) { - return $"[{module.Name}] {message}"; + return $"[{moduleInfo}] {message}"; } } } diff --git a/SafeExamBrowser.UserInterface.Classic/Controls/ApplicationButton.xaml.cs b/SafeExamBrowser.UserInterface.Classic/Controls/ApplicationButton.xaml.cs index d469489d..5c13f5a6 100644 --- a/SafeExamBrowser.UserInterface.Classic/Controls/ApplicationButton.xaml.cs +++ b/SafeExamBrowser.UserInterface.Classic/Controls/ApplicationButton.xaml.cs @@ -6,7 +6,6 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -using System; using System.Collections.Generic; using System.Linq; using System.Windows; @@ -90,7 +89,7 @@ namespace SafeExamBrowser.UserInterface.Classic.Controls } } - private void Instance_OnTerminated(Guid id, ApplicationInstanceButton instanceButton) + private void Instance_OnTerminated(InstanceIdentifier id, ApplicationInstanceButton instanceButton) { instances.Remove(instances.FirstOrDefault(i => i.Id == id)); InstanceStackPanel.Children.Remove(instanceButton); diff --git a/SafeExamBrowser.UserInterface.Classic/Controls/ApplicationInstanceButton.xaml.cs b/SafeExamBrowser.UserInterface.Classic/Controls/ApplicationInstanceButton.xaml.cs index 3d685271..1e926a25 100644 --- a/SafeExamBrowser.UserInterface.Classic/Controls/ApplicationInstanceButton.xaml.cs +++ b/SafeExamBrowser.UserInterface.Classic/Controls/ApplicationInstanceButton.xaml.cs @@ -6,23 +6,21 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -using System; using System.Windows; using System.Windows.Controls; using SafeExamBrowser.Contracts.Behaviour; using SafeExamBrowser.Contracts.Configuration; +using SafeExamBrowser.Contracts.UserInterface.Taskbar.Events; using SafeExamBrowser.UserInterface.Classic.Utilities; namespace SafeExamBrowser.UserInterface.Classic.Controls { - internal delegate void InstanceButtonClickedEventHandler(Guid instanceId); - public partial class ApplicationInstanceButton : UserControl { private IApplicationInfo info; private IApplicationInstance instance; - internal event InstanceButtonClickedEventHandler Clicked; + internal event ApplicationButtonClickedEventHandler Clicked; public ApplicationInstanceButton(IApplicationInstance instance, IApplicationInfo info) { diff --git a/SafeExamBrowser.UserInterface.Windows10/Controls/ApplicationButton.xaml.cs b/SafeExamBrowser.UserInterface.Windows10/Controls/ApplicationButton.xaml.cs index 6619da7d..92e2d482 100644 --- a/SafeExamBrowser.UserInterface.Windows10/Controls/ApplicationButton.xaml.cs +++ b/SafeExamBrowser.UserInterface.Windows10/Controls/ApplicationButton.xaml.cs @@ -91,7 +91,7 @@ namespace SafeExamBrowser.UserInterface.Windows10.Controls } } - private void Instance_OnTerminated(Guid id, ApplicationInstanceButton instanceButton) + private void Instance_OnTerminated(InstanceIdentifier id, ApplicationInstanceButton instanceButton) { instances.Remove(instances.FirstOrDefault(i => i.Id == id)); InstanceStackPanel.Children.Remove(instanceButton); diff --git a/SafeExamBrowser.UserInterface.Windows10/Controls/ApplicationInstanceButton.xaml.cs b/SafeExamBrowser.UserInterface.Windows10/Controls/ApplicationInstanceButton.xaml.cs index fd269683..7e654685 100644 --- a/SafeExamBrowser.UserInterface.Windows10/Controls/ApplicationInstanceButton.xaml.cs +++ b/SafeExamBrowser.UserInterface.Windows10/Controls/ApplicationInstanceButton.xaml.cs @@ -6,23 +6,21 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -using System; using System.Windows; using System.Windows.Controls; using SafeExamBrowser.Contracts.Behaviour; using SafeExamBrowser.Contracts.Configuration; +using SafeExamBrowser.Contracts.UserInterface.Taskbar.Events; using SafeExamBrowser.UserInterface.Windows10.Utilities; namespace SafeExamBrowser.UserInterface.Windows10.Controls { - internal delegate void InstanceButtonClickedEventHandler(Guid instanceId); - public partial class ApplicationInstanceButton : UserControl { private IApplicationInfo info; private IApplicationInstance instance; - internal event InstanceButtonClickedEventHandler Clicked; + internal event ApplicationButtonClickedEventHandler Clicked; public ApplicationInstanceButton(IApplicationInstance instance, IApplicationInfo info) {