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();
+ }
+ }
+}