diff --git a/SafeExamBrowser.I18n.Contracts/TextKey.cs b/SafeExamBrowser.I18n.Contracts/TextKey.cs index bfa415d8..ba794121 100644 --- a/SafeExamBrowser.I18n.Contracts/TextKey.cs +++ b/SafeExamBrowser.I18n.Contracts/TextKey.cs @@ -119,6 +119,7 @@ namespace SafeExamBrowser.I18n.Contracts OperationStatus_CloseRuntimeConnection, OperationStatus_EmptyClipboard, OperationStatus_FinalizeApplications, + OperationStatus_FinalizeServer, OperationStatus_FinalizeServiceSession, OperationStatus_FinalizeSystemEvents, OperationStatus_InitializeApplications, @@ -126,6 +127,7 @@ namespace SafeExamBrowser.I18n.Contracts OperationStatus_InitializeConfiguration, OperationStatus_InitializeKioskMode, OperationStatus_InitializeRuntimeConnection, + OperationStatus_InitializeServer, OperationStatus_InitializeServiceSession, OperationStatus_InitializeSession, OperationStatus_InitializeShell, diff --git a/SafeExamBrowser.I18n/Data/de.xml b/SafeExamBrowser.I18n/Data/de.xml index 93120c27..13cb99c5 100644 --- a/SafeExamBrowser.I18n/Data/de.xml +++ b/SafeExamBrowser.I18n/Data/de.xml @@ -315,6 +315,9 @@ Beende Applikationen + + Finalisiere SEB-Server + Beende Service-Sitzung @@ -336,6 +339,9 @@ Initialisiere Verbindung zur Runtime + + Initialisiere SEB-Server + Initialisiere Service-Sitzung diff --git a/SafeExamBrowser.I18n/Data/en.xml b/SafeExamBrowser.I18n/Data/en.xml index f7eee548..913063c0 100644 --- a/SafeExamBrowser.I18n/Data/en.xml +++ b/SafeExamBrowser.I18n/Data/en.xml @@ -315,6 +315,9 @@ Finalizing applications + + Finalizing SEB-Server + Finalizing service session @@ -336,6 +339,9 @@ Initializing runtime connection + + Initializing SEB-Server + Initializing service session diff --git a/SafeExamBrowser.Runtime/CompositionRoot.cs b/SafeExamBrowser.Runtime/CompositionRoot.cs index 87df6690..fa5757a6 100644 --- a/SafeExamBrowser.Runtime/CompositionRoot.cs +++ b/SafeExamBrowser.Runtime/CompositionRoot.cs @@ -26,6 +26,7 @@ using SafeExamBrowser.Logging; using SafeExamBrowser.Logging.Contracts; using SafeExamBrowser.Runtime.Communication; using SafeExamBrowser.Runtime.Operations; +using SafeExamBrowser.Server; using SafeExamBrowser.Settings.Logging; using SafeExamBrowser.SystemComponents; using SafeExamBrowser.SystemComponents.Contracts; @@ -66,6 +67,7 @@ namespace SafeExamBrowser.Runtime var proxyFactory = new ProxyFactory(new ProxyObjectFactory(), ModuleLogger(nameof(ProxyFactory))); var runtimeHost = new RuntimeHost(appConfig.RuntimeAddress, new HostObjectFactory(), ModuleLogger(nameof(RuntimeHost)), FIVE_SECONDS); var runtimeWindow = uiFactory.CreateRuntimeWindow(appConfig); + var server = new ServerProxy(); var serviceProxy = new ServiceProxy(appConfig.ServiceAddress, new ProxyObjectFactory(), ModuleLogger(nameof(ServiceProxy)), Interlocutor.Runtime); var sessionContext = new SessionContext(); var splashScreen = uiFactory.CreateSplashScreen(appConfig); @@ -80,7 +82,7 @@ namespace SafeExamBrowser.Runtime sessionOperations.Enqueue(new SessionInitializationOperation(configuration, logger, runtimeHost, sessionContext)); sessionOperations.Enqueue(new ConfigurationOperation(args, configuration, new FileSystem(), new HashAlgorithm(), logger, sessionContext)); - // TODO: sessionOperations.Enqueue(new ServerOperation()); + sessionOperations.Enqueue(new ServerOperation(args, configuration, logger, sessionContext, server)); sessionOperations.Enqueue(new VirtualMachineOperation(vmDetector, logger, sessionContext)); sessionOperations.Enqueue(new ServiceOperation(logger, runtimeHost, serviceProxy, sessionContext, THIRTY_SECONDS, userInfo)); sessionOperations.Enqueue(new ClientTerminationOperation(logger, processFactory, proxyFactory, runtimeHost, sessionContext, THIRTY_SECONDS)); @@ -108,7 +110,7 @@ namespace SafeExamBrowser.Runtime } internal void LogStartupInformation() - { + { logger.Log($"/* {appConfig.ProgramTitle}, Version {appConfig.ProgramInformationalVersion}, Build {appConfig.ProgramBuildVersion}"); logger.Log($"/* {appConfig.ProgramCopyright}"); logger.Log($"/* "); diff --git a/SafeExamBrowser.Runtime/Operations/ConfigurationBaseOperation.cs b/SafeExamBrowser.Runtime/Operations/ConfigurationBaseOperation.cs new file mode 100644 index 00000000..1468a96e --- /dev/null +++ b/SafeExamBrowser.Runtime/Operations/ConfigurationBaseOperation.cs @@ -0,0 +1,91 @@ +/* + * Copyright (c) 2020 ETH Zürich, Educational Development and Technology (LET) + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +using System; +using SafeExamBrowser.Communication.Contracts.Data; +using SafeExamBrowser.Configuration.Contracts; +using SafeExamBrowser.Configuration.Contracts.Cryptography; +using SafeExamBrowser.Core.Contracts.OperationModel.Events; +using SafeExamBrowser.Runtime.Operations.Events; +using SafeExamBrowser.Settings; + +namespace SafeExamBrowser.Runtime.Operations +{ + internal abstract class ConfigurationBaseOperation : SessionOperation + { + protected string[] commandLineArgs; + protected IConfigurationRepository configuration; + + protected string AppDataFilePath => Context.Next.AppConfig.AppDataFilePath; + protected string ProgramDataFilePath => Context.Next.AppConfig.ProgramDataFilePath; + + public ConfigurationBaseOperation(string[] commandLineArgs, IConfigurationRepository configuration, SessionContext context) : base(context) + { + this.commandLineArgs = commandLineArgs; + this.configuration = configuration; + } + + protected abstract void InvokeActionRequired(ActionRequiredEventArgs args); + + protected LoadStatus? TryLoadSettings(Uri uri, UriSource source, out PasswordParameters passwordParams, out AppSettings settings, string currentPassword = default(string)) + { + passwordParams = new PasswordParameters { Password = string.Empty, IsHash = true }; + + var status = configuration.TryLoadSettings(uri, out settings, passwordParams); + + if (status == LoadStatus.PasswordNeeded && currentPassword != default(string)) + { + passwordParams.Password = currentPassword; + passwordParams.IsHash = true; + + status = configuration.TryLoadSettings(uri, out settings, passwordParams); + } + + for (int attempts = 0; attempts < 5 && status == LoadStatus.PasswordNeeded; attempts++) + { + var isLocalConfig = source == UriSource.AppData || source == UriSource.ProgramData; + var purpose = isLocalConfig ? PasswordRequestPurpose.LocalSettings : PasswordRequestPurpose.Settings; + var success = TryGetPassword(purpose, out var password); + + if (success) + { + passwordParams.Password = password; + passwordParams.IsHash = false; + } + else + { + return null; + } + + status = configuration.TryLoadSettings(uri, out settings, passwordParams); + } + + return status; + } + + protected bool TryGetPassword(PasswordRequestPurpose purpose, out string password) + { + var args = new PasswordRequiredEventArgs { Purpose = purpose }; + + InvokeActionRequired(args); + password = args.Password; + + return args.Success; + } + + protected enum UriSource + { + Undefined, + AppData, + CommandLine, + ProgramData, + Reconfiguration, + Server + } + } +} diff --git a/SafeExamBrowser.Runtime/Operations/ConfigurationOperation.cs b/SafeExamBrowser.Runtime/Operations/ConfigurationOperation.cs index 4068ae96..8e642465 100644 --- a/SafeExamBrowser.Runtime/Operations/ConfigurationOperation.cs +++ b/SafeExamBrowser.Runtime/Operations/ConfigurationOperation.cs @@ -21,17 +21,12 @@ using SafeExamBrowser.SystemComponents.Contracts; namespace SafeExamBrowser.Runtime.Operations { - internal class ConfigurationOperation : SessionOperation + internal class ConfigurationOperation : ConfigurationBaseOperation { - private string[] commandLineArgs; - private IConfigurationRepository configuration; private IFileSystem fileSystem; private IHashAlgorithm hashAlgorithm; private ILogger logger; - private string AppDataFilePath => Context.Next.AppConfig.AppDataFilePath; - private string ProgramDataFilePath => Context.Next.AppConfig.ProgramDataFilePath; - public override event ActionRequiredEventHandler ActionRequired; public override event StatusChangedEventHandler StatusChanged; @@ -41,10 +36,8 @@ namespace SafeExamBrowser.Runtime.Operations IFileSystem fileSystem, IHashAlgorithm hashAlgorithm, ILogger logger, - SessionContext sessionContext) : base(sessionContext) + SessionContext sessionContext) : base(commandLineArgs, configuration, sessionContext) { - this.commandLineArgs = commandLineArgs; - this.configuration = configuration; this.fileSystem = fileSystem; this.hashAlgorithm = hashAlgorithm; this.logger = logger; @@ -99,6 +92,11 @@ namespace SafeExamBrowser.Runtime.Operations return OperationResult.Success; } + protected override void InvokeActionRequired(ActionRequiredEventArgs args) + { + ActionRequired?.Invoke(args); + } + private OperationResult LoadDefaultSettings() { logger.Info("No valid configuration resource specified and no local client configuration found - loading default settings..."); @@ -232,42 +230,6 @@ namespace SafeExamBrowser.Runtime.Operations return result; } - private LoadStatus? TryLoadSettings(Uri uri, UriSource source, out PasswordParameters passwordParams, out AppSettings settings, string currentPassword = default(string)) - { - passwordParams = new PasswordParameters { Password = string.Empty, IsHash = true }; - - var status = configuration.TryLoadSettings(uri, out settings, passwordParams); - - if (status == LoadStatus.PasswordNeeded && currentPassword != default(string)) - { - passwordParams.Password = currentPassword; - passwordParams.IsHash = true; - - status = configuration.TryLoadSettings(uri, out settings, passwordParams); - } - - for (int attempts = 0; attempts < 5 && status == LoadStatus.PasswordNeeded; attempts++) - { - var isLocalConfig = source == UriSource.AppData || source == UriSource.ProgramData; - var purpose = isLocalConfig ? PasswordRequestPurpose.LocalSettings : PasswordRequestPurpose.Settings; - var success = TryGetPassword(purpose, out var password); - - if (success) - { - passwordParams.Password = password; - passwordParams.IsHash = false; - } - else - { - return null; - } - - status = configuration.TryLoadSettings(uri, out settings, passwordParams); - } - - return status; - } - private bool? TryConfigureClient(Uri uri, PasswordParameters passwordParams, string currentPassword = default(string)) { var mustAuthenticate = IsRequiredToAuthenticateForClientConfiguration(passwordParams, currentPassword); @@ -395,16 +357,6 @@ namespace SafeExamBrowser.Runtime.Operations } } - private bool TryGetPassword(PasswordRequestPurpose purpose, out string password) - { - var args = new PasswordRequiredEventArgs { Purpose = purpose }; - - ActionRequired?.Invoke(args); - password = args.Password; - - return args.Success; - } - private bool TryInitializeSettingsUri(out Uri uri, out UriSource source) { var isValidUri = false; @@ -461,14 +413,5 @@ namespace SafeExamBrowser.Runtime.Operations break; } } - - private enum UriSource - { - Undefined, - AppData, - CommandLine, - ProgramData, - Reconfiguration - } } } diff --git a/SafeExamBrowser.Runtime/Operations/Events/ExamSelectionEventArgs.cs b/SafeExamBrowser.Runtime/Operations/Events/ExamSelectionEventArgs.cs new file mode 100644 index 00000000..ef2af434 --- /dev/null +++ b/SafeExamBrowser.Runtime/Operations/Events/ExamSelectionEventArgs.cs @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2020 ETH Zürich, Educational Development and Technology (LET) + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +using System.Collections.Generic; +using SafeExamBrowser.Core.Contracts.OperationModel.Events; +using SafeExamBrowser.Server.Contracts; + +namespace SafeExamBrowser.Runtime.Operations.Events +{ + internal class ExamSelectionEventArgs : ActionRequiredEventArgs + { + internal IEnumerable Exams { get; set; } + internal Exam SelectedExam { get; set; } + + internal ExamSelectionEventArgs(IEnumerable exams) + { + Exams = exams; + } + } +} diff --git a/SafeExamBrowser.Runtime/Operations/Events/ServerFailureEventArgs.cs b/SafeExamBrowser.Runtime/Operations/Events/ServerFailureEventArgs.cs new file mode 100644 index 00000000..3d0178d3 --- /dev/null +++ b/SafeExamBrowser.Runtime/Operations/Events/ServerFailureEventArgs.cs @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2020 ETH Zürich, Educational Development and Technology (LET) + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +using SafeExamBrowser.Core.Contracts.OperationModel.Events; + +namespace SafeExamBrowser.Runtime.Operations.Events +{ + internal class ServerFailureEventArgs : ActionRequiredEventArgs + { + public bool Abort { get; set; } + public bool Fallback { get; set; } + public string Message { get; set; } + public bool Retry { get; set; } + + public ServerFailureEventArgs(string message) + { + Message = message; + } + } +} diff --git a/SafeExamBrowser.Runtime/Operations/ServerOperation.cs b/SafeExamBrowser.Runtime/Operations/ServerOperation.cs new file mode 100644 index 00000000..85f9671c --- /dev/null +++ b/SafeExamBrowser.Runtime/Operations/ServerOperation.cs @@ -0,0 +1,204 @@ +/* + * Copyright (c) 2020 ETH Zürich, Educational Development and Technology (LET) + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +using System; +using System.Collections.Generic; +using SafeExamBrowser.Configuration.Contracts; +using SafeExamBrowser.Core.Contracts.OperationModel; +using SafeExamBrowser.Core.Contracts.OperationModel.Events; +using SafeExamBrowser.I18n.Contracts; +using SafeExamBrowser.Logging.Contracts; +using SafeExamBrowser.Runtime.Operations.Events; +using SafeExamBrowser.Server.Contracts; +using SafeExamBrowser.Settings; + +namespace SafeExamBrowser.Runtime.Operations +{ + internal class ServerOperation : ConfigurationBaseOperation + { + private readonly ILogger logger; + private readonly IServerProxy server; + + public override event ActionRequiredEventHandler ActionRequired; + public override event StatusChangedEventHandler StatusChanged; + + public ServerOperation( + string[] commandLineArgs, + IConfigurationRepository configuration, + ILogger logger, + SessionContext context, + IServerProxy server) : base(commandLineArgs, configuration, context) + { + this.logger = logger; + this.server = server; + } + + public override OperationResult Perform() + { + var result = OperationResult.Success; + + if (Context.Next.Settings.SessionMode == SessionMode.Server) + { + logger.Info("Initializing server..."); + StatusChanged?.Invoke(TextKey.OperationStatus_InitializeServer); + + var (abort, fallback, success) = TryPerformWithFallback(() => server.Connect(Context.Next.Settings.Server)); + + if (success) + { + (abort, fallback, success) = TryPerformWithFallback(() => server.GetAvailableExams(), out var exams); + + if (success) + { + var exam = SelectExam(exams); + + (abort, fallback, success) = TryPerformWithFallback(() => server.GetConfigurationFor(exam), out var uri); + + if (success) + { + var status = TryLoadSettings(uri, UriSource.Server, out _, out var settings); + + if (status == LoadStatus.Success) + { + Context.Next.Settings = settings; + result = OperationResult.Success; + } + else + { + result = OperationResult.Failed; + } + } + } + } + + if (abort) + { + result = OperationResult.Aborted; + } + + if (fallback) + { + result = OperationResult.Success; + } + } + + return result; + } + + public override OperationResult Repeat() + { + var result = Revert(); + + if (result == OperationResult.Success) + { + result = Perform(); + } + + return result; + } + + public override OperationResult Revert() + { + var result = OperationResult.Failed; + + if (Context.Current.Settings.SessionMode == SessionMode.Server) + { + logger.Info("Finalizing server..."); + StatusChanged?.Invoke(TextKey.OperationStatus_FinalizeServer); + + var disconnect = server.Disconnect(); + + if (disconnect.Success) + { + result = OperationResult.Success; + } + else + { + result = OperationResult.Failed; + } + } + else + { + result = OperationResult.Success; + } + + return result; + } + + protected override void InvokeActionRequired(ActionRequiredEventArgs args) + { + ActionRequired?.Invoke(args); + } + + private (bool abort, bool fallback, bool success) TryPerformWithFallback(Func request) + { + var abort = false; + var fallback = false; + var success = false; + + while (!success) + { + var response = request(); + + success = response.Success; + + if (!success && !Retry(response.Message, out abort, out fallback)) + { + break; + } + } + + return (abort, fallback, success); + } + + private (bool abort, bool fallback, bool success) TryPerformWithFallback(Func> request, out T value) + { + var abort = false; + var fallback = false; + var success = false; + + value = default(T); + + while (!success) + { + var response = request(); + + success = response.Success; + value = response.Value; + + if (!success && !Retry(response.Message, out abort, out fallback)) + { + break; + } + } + + return (abort, fallback, success); + } + + private bool Retry(string message, out bool abort, out bool fallback) + { + var args = new ServerFailureEventArgs(message); + + ActionRequired?.Invoke(args); + + abort = args.Abort; + fallback = args.Fallback; + + return args.Retry; + } + + private Exam SelectExam(IEnumerable exams) + { + var args = new ExamSelectionEventArgs(exams); + + ActionRequired?.Invoke(args); + + return args.SelectedExam; + } + } +} diff --git a/SafeExamBrowser.Runtime/RuntimeController.cs b/SafeExamBrowser.Runtime/RuntimeController.cs index 63ecd03b..6691e9da 100644 --- a/SafeExamBrowser.Runtime/RuntimeController.cs +++ b/SafeExamBrowser.Runtime/RuntimeController.cs @@ -384,15 +384,31 @@ namespace SafeExamBrowser.Runtime case ConfigurationCompletedEventArgs a: AskIfConfigurationSufficient(a); break; + case ExamSelectionEventArgs a: + AskForExamSelection(a); + break; case MessageEventArgs m: ShowMessageBox(m); break; case PasswordRequiredEventArgs p: AskForPassword(p); break; + case ServerFailureEventArgs a: + AskForServerFailureAction(a); + break; } } + private void AskForExamSelection(ExamSelectionEventArgs a) + { + // TODO: Also implement mechanism to retrieve selection via client!! + } + + private void AskForServerFailureAction(ServerFailureEventArgs a) + { + // TODO: Also implement mechanism to retrieve selection via client!! + } + private void AskIfConfigurationSufficient(ConfigurationCompletedEventArgs args) { var message = TextKey.MessageBox_ClientConfigurationQuestion; diff --git a/SafeExamBrowser.Runtime/SafeExamBrowser.Runtime.csproj b/SafeExamBrowser.Runtime/SafeExamBrowser.Runtime.csproj index 0542bd86..0e6d4628 100644 --- a/SafeExamBrowser.Runtime/SafeExamBrowser.Runtime.csproj +++ b/SafeExamBrowser.Runtime/SafeExamBrowser.Runtime.csproj @@ -90,16 +90,20 @@ + + + + @@ -177,6 +181,14 @@ {e107026c-2011-4552-a7d8-3a0d37881df6} SafeExamBrowser.Logging + + {db701e6f-bddc-4cec-b662-335a9dc11809} + SafeExamBrowser.Server.Contracts + + + {46edbde0-58b4-4725-9783-0c55c3d49c0c} + SafeExamBrowser.Server + {30b2d907-5861-4f39-abad-c4abf1b3470e} SafeExamBrowser.Settings diff --git a/SafeExamBrowser.Server.Contracts/Exam.cs b/SafeExamBrowser.Server.Contracts/Exam.cs new file mode 100644 index 00000000..0fe5e16c --- /dev/null +++ b/SafeExamBrowser.Server.Contracts/Exam.cs @@ -0,0 +1,18 @@ +/* + * Copyright (c) 2020 ETH Zürich, Educational Development and Technology (LET) + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +namespace SafeExamBrowser.Server.Contracts +{ + /// + /// + /// + public class Exam + { + + } +} diff --git a/SafeExamBrowser.Server.Contracts/IServerProxy.cs b/SafeExamBrowser.Server.Contracts/IServerProxy.cs new file mode 100644 index 00000000..e9108449 --- /dev/null +++ b/SafeExamBrowser.Server.Contracts/IServerProxy.cs @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2020 ETH Zürich, Educational Development and Technology (LET) + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +using System; +using System.Collections.Generic; +using SafeExamBrowser.Settings.Server; + +namespace SafeExamBrowser.Server.Contracts +{ + /// + /// + /// + public interface IServerProxy + { + /// + /// + /// + ServerResponse Connect(ServerSettings settings); + + /// + /// + /// + ServerResponse Disconnect(); + + /// + /// + /// + ServerResponse> GetAvailableExams(); + + /// + /// + /// + ServerResponse GetConfigurationFor(Exam exam); + + /// + /// + /// + ServerResponse SendSessionInfo(string sessionId); + } +} diff --git a/SafeExamBrowser.Server.Contracts/SafeExamBrowser.Server.Contracts.csproj b/SafeExamBrowser.Server.Contracts/SafeExamBrowser.Server.Contracts.csproj index 840a50bc..9cf9979c 100644 --- a/SafeExamBrowser.Server.Contracts/SafeExamBrowser.Server.Contracts.csproj +++ b/SafeExamBrowser.Server.Contracts/SafeExamBrowser.Server.Contracts.csproj @@ -54,7 +54,16 @@ + + + + + + + {30b2d907-5861-4f39-abad-c4abf1b3470e} + SafeExamBrowser.Settings + \ No newline at end of file diff --git a/SafeExamBrowser.Server.Contracts/ServerResponse.cs b/SafeExamBrowser.Server.Contracts/ServerResponse.cs new file mode 100644 index 00000000..6b7fe155 --- /dev/null +++ b/SafeExamBrowser.Server.Contracts/ServerResponse.cs @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2020 ETH Zürich, Educational Development and Technology (LET) + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +namespace SafeExamBrowser.Server.Contracts +{ + /// + /// Defines the result of a communication with a SEB server. + /// + public class ServerResponse + { + /// + /// The message retrieved by the server in case the communication failed. + /// + public string Message { get; } + + /// + /// Defines whether the communication was successful or not. + /// + public bool Success { get; } + + public ServerResponse(bool success, string message = default(string)) + { + Message = message; + Success = success; + } + } + + /// + /// Defines the result of a communication with a SEB server. + /// + /// The type of the expected response value. + public class ServerResponse : ServerResponse + { + /// + /// The response value. Can be null or default(T) in case the communication failed! + /// + public T Value { get; } + + public ServerResponse(bool success, T value, string message = default(string)) : base(success, message) + { + Value = value; + } + } +} diff --git a/SafeExamBrowser.Server/SafeExamBrowser.Server.csproj b/SafeExamBrowser.Server/SafeExamBrowser.Server.csproj index a855638f..75c02513 100644 --- a/SafeExamBrowser.Server/SafeExamBrowser.Server.csproj +++ b/SafeExamBrowser.Server/SafeExamBrowser.Server.csproj @@ -55,6 +55,17 @@ + + + + + {db701e6f-bddc-4cec-b662-335a9dc11809} + SafeExamBrowser.Server.Contracts + + + {30b2d907-5861-4f39-abad-c4abf1b3470e} + SafeExamBrowser.Settings + \ No newline at end of file diff --git a/SafeExamBrowser.Server/ServerProxy.cs b/SafeExamBrowser.Server/ServerProxy.cs new file mode 100644 index 00000000..50f5387e --- /dev/null +++ b/SafeExamBrowser.Server/ServerProxy.cs @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2020 ETH Zürich, Educational Development and Technology (LET) + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +using System; +using System.Collections.Generic; +using SafeExamBrowser.Server.Contracts; +using SafeExamBrowser.Settings.Server; + +namespace SafeExamBrowser.Server +{ + public class ServerProxy : IServerProxy + { + public ServerResponse Connect(ServerSettings settings) + { + throw new NotImplementedException(); + } + + public ServerResponse Disconnect() + { + throw new NotImplementedException(); + } + + public ServerResponse> GetAvailableExams() + { + throw new NotImplementedException(); + } + + public ServerResponse GetConfigurationFor(Exam exam) + { + throw new NotImplementedException(); + } + + public ServerResponse SendSessionInfo(string sessionId) + { + throw new NotImplementedException(); + } + } +}