SEBWIN-219: Found better solution for session operation sequence (got rid of session controller and sequence start resp. end operations).
This commit is contained in:
		
							parent
							
								
									e750f870c0
								
							
						
					
					
						commit
						6efa7bed81
					
				
					 15 changed files with 270 additions and 246 deletions
				
			
		|  | @ -43,14 +43,14 @@ namespace SafeExamBrowser.Contracts.I18n | |||
| 		Notification_AboutTooltip, | ||||
| 		Notification_LogTooltip, | ||||
| 		ProgressIndicator_CloseRuntimeConnection, | ||||
| 		ProgressIndicator_CloseServiceConnection, | ||||
| 		ProgressIndicator_EmptyClipboard, | ||||
| 		ProgressIndicator_FinalizeServiceSession, | ||||
| 		ProgressIndicator_InitializeBrowser, | ||||
| 		ProgressIndicator_InitializeConfiguration, | ||||
| 		ProgressIndicator_InitializeKioskMode, | ||||
| 		ProgressIndicator_InitializeProcessMonitoring, | ||||
| 		ProgressIndicator_InitializeRuntimeConnection, | ||||
| 		ProgressIndicator_InitializeServiceConnection, | ||||
| 		ProgressIndicator_InitializeServiceSession, | ||||
| 		ProgressIndicator_InitializeTaskbar, | ||||
| 		ProgressIndicator_InitializeWindowMonitoring, | ||||
| 		ProgressIndicator_InitializeWorkingArea, | ||||
|  | @ -58,17 +58,18 @@ namespace SafeExamBrowser.Contracts.I18n | |||
| 		ProgressIndicator_RestoreWorkingArea, | ||||
| 		ProgressIndicator_RevertKioskMode, | ||||
| 		ProgressIndicator_ShutdownProcedure, | ||||
| 		ProgressIndicator_StartClient, | ||||
| 		ProgressIndicator_StartCommunicationHost, | ||||
| 		ProgressIndicator_StartEventHandling, | ||||
| 		ProgressIndicator_StartKeyboardInterception, | ||||
| 		ProgressIndicator_StartMouseInterception, | ||||
| 		ProgressIndicator_StartSession, | ||||
| 		ProgressIndicator_InitializeSession, | ||||
| 		ProgressIndicator_StopClient, | ||||
| 		ProgressIndicator_StopCommunicationHost, | ||||
| 		ProgressIndicator_StopEventHandling, | ||||
| 		ProgressIndicator_StopKeyboardInterception, | ||||
| 		ProgressIndicator_StopMouseInterception, | ||||
| 		ProgressIndicator_StopProcessMonitoring, | ||||
| 		ProgressIndicator_StopSession, | ||||
| 		ProgressIndicator_StopWindowMonitoring, | ||||
| 		ProgressIndicator_TerminateBrowser, | ||||
| 		ProgressIndicator_TerminateTaskbar, | ||||
|  |  | |||
|  | @ -81,12 +81,12 @@ | |||
|   <Entry key="ProgressIndicator_CloseRuntimeConnection"> | ||||
|     Closing runtime connection | ||||
|   </Entry> | ||||
|   <Entry key="ProgressIndicator_CloseServiceConnection"> | ||||
|     Closing service connection | ||||
|   </Entry> | ||||
|   <Entry key="ProgressIndicator_EmptyClipboard"> | ||||
|     Emptying clipboard | ||||
|   </Entry> | ||||
|   <Entry key="ProgressIndicator_FinalizeServiceSession"> | ||||
|     Finalizing service session | ||||
|   </Entry> | ||||
|   <Entry key="ProgressIndicator_InitializeBrowser"> | ||||
|     Initializing browser | ||||
|   </Entry> | ||||
|  | @ -102,8 +102,11 @@ | |||
|   <Entry key="ProgressIndicator_InitializeRuntimeConnection"> | ||||
|     Initializing runtime connection | ||||
|   </Entry> | ||||
|   <Entry key="ProgressIndicator_InitializeServiceConnection"> | ||||
|     Initializing service connection | ||||
|   <Entry key="ProgressIndicator_InitializeServiceSession"> | ||||
|     Initializing service session | ||||
|   </Entry> | ||||
|   <Entry key="ProgressIndicator_InitializeSession"> | ||||
|     Initializing new session | ||||
|   </Entry> | ||||
|   <Entry key="ProgressIndicator_InitializeTaskbar"> | ||||
|     Initializing taskbar | ||||
|  | @ -126,6 +129,9 @@ | |||
|   <Entry key="ProgressIndicator_ShutdownProcedure"> | ||||
|     Initiating shutdown procedure | ||||
|   </Entry> | ||||
|   <Entry key="ProgressIndicator_StartClient"> | ||||
|     Starting client | ||||
|   </Entry> | ||||
|   <Entry key="ProgressIndicator_StartCommunicationHost"> | ||||
|     Starting communication host | ||||
|   </Entry> | ||||
|  | @ -138,8 +144,8 @@ | |||
|   <Entry key="ProgressIndicator_StartMouseInterception"> | ||||
|     Starting mouse interception | ||||
|   </Entry> | ||||
|   <Entry key="ProgressIndicator_StartSession"> | ||||
|     Starting new session | ||||
|   <Entry key="ProgressIndicator_StopClient"> | ||||
|     Stopping client | ||||
|   </Entry> | ||||
|   <Entry key="ProgressIndicator_StopCommunicationHost"> | ||||
|     Stopping communication host | ||||
|  | @ -156,9 +162,6 @@ | |||
|   <Entry key="ProgressIndicator_StopProcessMonitoring"> | ||||
|     Stopping process monitoring | ||||
|   </Entry> | ||||
|   <Entry key="ProgressIndicator_StopSession"> | ||||
|     Stopping current session | ||||
|   </Entry> | ||||
|   <Entry key="ProgressIndicator_StopWindowMonitoring"> | ||||
|     Stopping window monitoring | ||||
|   </Entry> | ||||
|  |  | |||
|  | @ -28,7 +28,7 @@ namespace SafeExamBrowser.Runtime.UnitTests.Behaviour.Operations | |||
| 		private Mock<IConfigurationRepository> configuration; | ||||
| 		private Mock<IProgressIndicator> progressIndicator; | ||||
| 		private Mock<IText> text; | ||||
| 		private ServiceConnectionOperation sut; | ||||
| 		private ServiceOperation sut; | ||||
| 
 | ||||
| 		[TestInitialize] | ||||
| 		public void Initialize() | ||||
|  | @ -39,7 +39,7 @@ namespace SafeExamBrowser.Runtime.UnitTests.Behaviour.Operations | |||
| 			progressIndicator = new Mock<IProgressIndicator>(); | ||||
| 			text = new Mock<IText>(); | ||||
| 
 | ||||
| 			sut = new ServiceConnectionOperation(configuration.Object, logger.Object, service.Object, text.Object); | ||||
| 			sut = new ServiceOperation(configuration.Object, logger.Object, service.Object, text.Object); | ||||
| 		} | ||||
| 
 | ||||
| 		[TestMethod] | ||||
|  |  | |||
|  | @ -1,22 +0,0 @@ | |||
| /* | ||||
|  * Copyright (c) 2018 ETH Zürich, Educational Development and Technology (LET) | ||||
|  *  | ||||
|  * This Source Code Form is subject to the terms of the Mozilla Public | ||||
|  * License, v. 2.0. If a copy of the MPL was not distributed with this | ||||
|  * file, You can obtain one at http://mozilla.org/MPL/2.0/. | ||||
|  */ | ||||
| 
 | ||||
| using Microsoft.VisualStudio.TestTools.UnitTesting; | ||||
| 
 | ||||
| namespace SafeExamBrowser.Runtime.UnitTests.Behaviour.Operations | ||||
| { | ||||
| 	[TestClass] | ||||
| 	public class SessionSequenceOperationTests | ||||
| 	{ | ||||
| 		[TestMethod] | ||||
| 		public void TODO() | ||||
| 		{ | ||||
| 			Assert.Fail(); | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | @ -83,7 +83,6 @@ | |||
|     <Compile Include="Behaviour\Operations\ConfigurationOperationTests.cs" /> | ||||
|     <Compile Include="Behaviour\Operations\KioskModeOperationTests.cs" /> | ||||
|     <Compile Include="Behaviour\Operations\ServiceConnectionOperationTests.cs" /> | ||||
|     <Compile Include="Behaviour\Operations\SessionSequenceOperationTests.cs" /> | ||||
|     <Compile Include="Behaviour\RuntimeControllerTests.cs" /> | ||||
|     <Compile Include="Communication\RuntimeHostTests.cs" /> | ||||
|     <Compile Include="Properties\AssemblyInfo.cs" /> | ||||
|  |  | |||
|  | @ -17,104 +17,69 @@ using SafeExamBrowser.Contracts.Logging; | |||
| using SafeExamBrowser.Contracts.UserInterface; | ||||
| using SafeExamBrowser.Contracts.WindowsApi; | ||||
| 
 | ||||
| namespace SafeExamBrowser.Runtime.Behaviour | ||||
| namespace SafeExamBrowser.Runtime.Behaviour.Operations | ||||
| { | ||||
| 	internal class SessionController | ||||
| 	internal class ClientOperation : IOperation | ||||
| 	{ | ||||
| 		private const int TEN_SECONDS = 10000; | ||||
| 
 | ||||
| 		private bool sessionRunning; | ||||
| 		private IConfigurationRepository configuration; | ||||
| 		private ILogger logger; | ||||
| 		private IProcessFactory processFactory; | ||||
| 		private IProxyFactory proxyFactory; | ||||
| 		private IRuntimeHost runtimeHost; | ||||
| 		private IServiceProxy service; | ||||
| 		protected IConfigurationRepository configuration; | ||||
| 		protected ILogger logger; | ||||
| 		protected IProcessFactory processFactory; | ||||
| 		protected IProxyFactory proxyFactory; | ||||
| 		protected IRuntimeHost runtimeHost; | ||||
| 
 | ||||
| 		internal IProgressIndicator ProgressIndicator { private get; set; } | ||||
| 		protected static IProcess ClientProcess { get; private set; } | ||||
| 		protected static IClientProxy ClientProxy { get; private set; } | ||||
| 		public IProgressIndicator ProgressIndicator { protected get; set; } | ||||
| 
 | ||||
| 		internal SessionController( | ||||
| 		public ClientOperation( | ||||
| 			IConfigurationRepository configuration, | ||||
| 			ILogger logger, | ||||
| 			IProcessFactory processFactory, | ||||
| 			IProxyFactory proxyFactory, | ||||
| 			IRuntimeHost runtimeHost, | ||||
| 			IServiceProxy service) | ||||
| 			IRuntimeHost runtimeHost) | ||||
| 		{ | ||||
| 			this.configuration = configuration; | ||||
| 			this.logger = logger; | ||||
| 			this.processFactory = processFactory; | ||||
| 			this.proxyFactory = proxyFactory; | ||||
| 			this.runtimeHost = runtimeHost; | ||||
| 			this.service = service; | ||||
| 		} | ||||
| 
 | ||||
| 		internal OperationResult StartSession() | ||||
| 		public virtual OperationResult Perform() | ||||
| 		{ | ||||
| 			logger.Info("Starting new session..."); | ||||
| 			ProgressIndicator?.UpdateText(TextKey.ProgressIndicator_StartSession, true); | ||||
| 			ProgressIndicator?.UpdateText(TextKey.ProgressIndicator_StartClient, true); | ||||
| 
 | ||||
| 			InitializeSessionConfiguration(); | ||||
| 			StartServiceSession(); | ||||
| 			sessionRunning = TryStartClient(); | ||||
| 			var success = TryStartClient(); | ||||
| 
 | ||||
| 			if (!sessionRunning) | ||||
| 			if (success) | ||||
| 			{ | ||||
| 				logger.Info($"Failed to start new session! Reverting service session and aborting procedure..."); | ||||
| 				service.StopSession(configuration.CurrentSession.Id); | ||||
| 
 | ||||
| 				return OperationResult.Failed; | ||||
| 				logger.Info($"Successfully started new client instance."); | ||||
| 			} | ||||
| 
 | ||||
| 			logger.Info($"Successfully started new session."); | ||||
| 
 | ||||
| 			return OperationResult.Success; | ||||
| 		} | ||||
| 
 | ||||
| 		internal OperationResult StopSession() | ||||
| 			else | ||||
| 			{ | ||||
| 			if (sessionRunning) | ||||
| 				logger.Error($"Failed to start new client instance! Aborting procedure..."); | ||||
| 			} | ||||
| 
 | ||||
| 			return success ? OperationResult.Success : OperationResult.Failed; | ||||
| 		} | ||||
| 
 | ||||
| 		public virtual OperationResult Repeat() | ||||
| 		{ | ||||
| 				logger.Info($"Stopping session with identifier '{configuration.CurrentSession.Id}'..."); | ||||
| 				ProgressIndicator?.UpdateText(TextKey.ProgressIndicator_StopSession, true); | ||||
| 			return Perform(); | ||||
| 		} | ||||
| 
 | ||||
| 				StopServiceSession(); | ||||
| 
 | ||||
| 				if (!configuration.CurrentSession.ClientProcess.HasTerminated) | ||||
| 		public virtual void Revert() | ||||
| 		{ | ||||
| 					StopClient(); | ||||
| 				} | ||||
| 
 | ||||
| 				sessionRunning = false; | ||||
| 				logger.Info($"Successfully stopped session."); | ||||
| 			} | ||||
| 
 | ||||
| 			return OperationResult.Success; | ||||
| 		} | ||||
| 
 | ||||
| 		private void InitializeSessionConfiguration() | ||||
| 			if (ClientProcess != null && !ClientProcess.HasTerminated) | ||||
| 			{ | ||||
| 			configuration.InitializeSessionConfiguration(); | ||||
| 			runtimeHost.StartupToken = configuration.CurrentSession.StartupToken; | ||||
| 
 | ||||
| 			logger.Info($" -> Client-ID: {configuration.RuntimeInfo.ClientId}"); | ||||
| 			logger.Info($" -> Runtime-ID: {configuration.RuntimeInfo.RuntimeId} (as reference, does not change)"); | ||||
| 			logger.Info($" -> Session-ID: {configuration.CurrentSession.Id}"); | ||||
| 				ProgressIndicator?.UpdateText(TextKey.ProgressIndicator_StopClient, true); | ||||
| 				TryStopClient(); | ||||
| 			} | ||||
| 		} | ||||
| 
 | ||||
| 		private void StartServiceSession() | ||||
| 		{ | ||||
| 			logger.Info("Initializing service session..."); | ||||
| 			service.StartSession(configuration.CurrentSession.Id, configuration.CurrentSettings); | ||||
| 		} | ||||
| 
 | ||||
| 		private void StopServiceSession() | ||||
| 		{ | ||||
| 			logger.Info("Stopping service session..."); | ||||
| 			service.StopSession(configuration.CurrentSession.Id); | ||||
| 		} | ||||
| 
 | ||||
| 		private bool TryStartClient() | ||||
| 		protected bool TryStartClient() | ||||
| 		{ | ||||
| 			var clientReady = false; | ||||
| 			var clientReadyEvent = new AutoResetEvent(false); | ||||
|  | @ -126,7 +91,7 @@ namespace SafeExamBrowser.Runtime.Behaviour | |||
| 
 | ||||
| 			logger.Info("Starting new client process..."); | ||||
| 			runtimeHost.ClientReady += clientReadyEventHandler; | ||||
| 			configuration.CurrentSession.ClientProcess = processFactory.StartNew(clientExecutable, clientLogFile, hostUri, token); | ||||
| 			ClientProcess = processFactory.StartNew(clientExecutable, clientLogFile, hostUri, token); | ||||
| 
 | ||||
| 			logger.Info("Waiting for client to complete initialization..."); | ||||
| 			clientReady = clientReadyEvent.WaitOne(TEN_SECONDS); | ||||
|  | @ -140,20 +105,20 @@ namespace SafeExamBrowser.Runtime.Behaviour | |||
| 			} | ||||
| 
 | ||||
| 			logger.Info("Client has been successfully started and initialized. Creating communication proxy for client host..."); | ||||
| 			configuration.CurrentSession.ClientProxy = proxyFactory.CreateClientProxy(configuration.RuntimeInfo.ClientAddress); | ||||
| 			ClientProxy = proxyFactory.CreateClientProxy(configuration.RuntimeInfo.ClientAddress); | ||||
| 
 | ||||
| 			if (!configuration.CurrentSession.ClientProxy.Connect(configuration.CurrentSession.StartupToken)) | ||||
| 			if (!ClientProxy.Connect(configuration.CurrentSession.StartupToken)) | ||||
| 			{ | ||||
| 				logger.Error("Failed to connect to client!"); | ||||
| 
 | ||||
| 				return false; | ||||
| 			} | ||||
| 
 | ||||
| 			logger.Info("Connection with client has been established."); | ||||
| 			logger.Info("Connection with client has been established. Requesting authentication..."); | ||||
| 
 | ||||
| 			var response = configuration.CurrentSession.ClientProxy.RequestAuthentication(); | ||||
| 			var response = ClientProxy.RequestAuthentication(); | ||||
| 
 | ||||
| 			if (configuration.CurrentSession.ClientProcess.Id != response?.ProcessId) | ||||
| 			if (ClientProcess.Id != response?.ProcessId) | ||||
| 			{ | ||||
| 				logger.Error("Failed to verify client integrity!"); | ||||
| 
 | ||||
|  | @ -162,11 +127,16 @@ namespace SafeExamBrowser.Runtime.Behaviour | |||
| 
 | ||||
| 			logger.Info("Authentication of client has been successful, client is ready to operate."); | ||||
| 
 | ||||
| 			configuration.CurrentSession.ClientProcess = ClientProcess; | ||||
| 			configuration.CurrentSession.ClientProxy = ClientProxy; | ||||
| 
 | ||||
| 			return true; | ||||
| 		} | ||||
| 
 | ||||
| 		private void StopClient() | ||||
| 		protected bool TryStopClient() | ||||
| 		{ | ||||
| 			var success = false; | ||||
| 
 | ||||
| 			var disconnected = false; | ||||
| 			var disconnectedEvent = new AutoResetEvent(false); | ||||
| 			var disconnectedEventHandler = new CommunicationEventHandler(() => disconnectedEvent.Set()); | ||||
|  | @ -176,13 +146,13 @@ namespace SafeExamBrowser.Runtime.Behaviour | |||
| 			var terminatedEventHandler = new ProcessTerminatedEventHandler((_) => terminatedEvent.Set()); | ||||
| 
 | ||||
| 			runtimeHost.ClientDisconnected += disconnectedEventHandler; | ||||
| 			configuration.CurrentSession.ClientProcess.Terminated += terminatedEventHandler; | ||||
| 			ClientProcess.Terminated += terminatedEventHandler; | ||||
| 
 | ||||
| 			logger.Info("Instructing client to initiate shutdown procedure."); | ||||
| 			configuration.CurrentSession.ClientProxy.InitiateShutdown(); | ||||
| 			ClientProxy.InitiateShutdown(); | ||||
| 
 | ||||
| 			logger.Info("Disconnecting from client communication host."); | ||||
| 			configuration.CurrentSession.ClientProxy.Disconnect(); | ||||
| 			ClientProxy.Disconnect(); | ||||
| 
 | ||||
| 			logger.Info("Waiting for client to disconnect from runtime communication host..."); | ||||
| 			disconnected = disconnectedEvent.WaitOne(TEN_SECONDS); | ||||
|  | @ -201,20 +171,29 @@ namespace SafeExamBrowser.Runtime.Behaviour | |||
| 			} | ||||
| 
 | ||||
| 			runtimeHost.ClientDisconnected -= disconnectedEventHandler; | ||||
| 			configuration.CurrentSession.ClientProcess.Terminated -= terminatedEventHandler; | ||||
| 			ClientProcess.Terminated -= terminatedEventHandler; | ||||
| 
 | ||||
| 			if (disconnected && terminated) | ||||
| 			{ | ||||
| 				logger.Info("Client has been successfully terminated."); | ||||
| 				success = true; | ||||
| 			} | ||||
| 			else | ||||
| 			{ | ||||
| 				logger.Warn("Attempting to kill client process since graceful termination failed!"); | ||||
| 				KillClient(); | ||||
| 			} | ||||
| 				success = TryKillClient(); | ||||
| 			} | ||||
| 
 | ||||
| 		private void KillClient(int attempt = 0) | ||||
| 			if (success) | ||||
| 			{ | ||||
| 				configuration.CurrentSession.ClientProcess = null; | ||||
| 				configuration.CurrentSession.ClientProxy = null; | ||||
| 			} | ||||
| 
 | ||||
| 			return success; | ||||
| 		} | ||||
| 
 | ||||
| 		protected bool TryKillClient(int attempt = 0) | ||||
| 		{ | ||||
| 			const int MAX_ATTEMPTS = 5; | ||||
| 
 | ||||
|  | @ -222,20 +201,23 @@ namespace SafeExamBrowser.Runtime.Behaviour | |||
| 			{ | ||||
| 				logger.Error($"Failed to kill client process within {MAX_ATTEMPTS} attempts!"); | ||||
| 
 | ||||
| 				return; | ||||
| 				return false; | ||||
| 			} | ||||
| 
 | ||||
| 			logger.Info($"Killing client process with ID = {configuration.CurrentSession.ClientProcess.Id}."); | ||||
| 			configuration.CurrentSession.ClientProcess.Kill(); | ||||
| 			logger.Info($"Killing client process with ID = {ClientProcess.Id}."); | ||||
| 			ClientProcess.Kill(); | ||||
| 
 | ||||
| 			if (configuration.CurrentSession.ClientProcess.HasTerminated) | ||||
| 			if (ClientProcess.HasTerminated) | ||||
| 			{ | ||||
| 				logger.Info("Client process has terminated."); | ||||
| 
 | ||||
| 				return true; | ||||
| 			} | ||||
| 			else | ||||
| 			{ | ||||
| 				logger.Warn("Failed to kill client process. Trying again..."); | ||||
| 				KillClient(attempt++); | ||||
| 
 | ||||
| 				return TryKillClient(attempt++); | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
|  | @ -0,0 +1,53 @@ | |||
| /* | ||||
|  * 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.OperationModel; | ||||
| using SafeExamBrowser.Contracts.Communication.Hosts; | ||||
| using SafeExamBrowser.Contracts.Communication.Proxies; | ||||
| using SafeExamBrowser.Contracts.Configuration; | ||||
| using SafeExamBrowser.Contracts.I18n; | ||||
| using SafeExamBrowser.Contracts.Logging; | ||||
| using SafeExamBrowser.Contracts.WindowsApi; | ||||
| 
 | ||||
| namespace SafeExamBrowser.Runtime.Behaviour.Operations | ||||
| { | ||||
| 	internal class ClientTerminationOperation : ClientOperation | ||||
| 	{ | ||||
| 		public ClientTerminationOperation( | ||||
| 			IConfigurationRepository configuration, | ||||
| 			ILogger logger, | ||||
| 			IProcessFactory processFactory, | ||||
| 			IProxyFactory proxyFactory, | ||||
| 			IRuntimeHost runtimeHost) : base(configuration, logger, processFactory, proxyFactory, runtimeHost) | ||||
| 		{ | ||||
| 		} | ||||
| 
 | ||||
| 		public override OperationResult Perform() | ||||
| 		{ | ||||
| 			return OperationResult.Success; | ||||
| 		} | ||||
| 
 | ||||
| 		public override OperationResult Repeat() | ||||
| 		{ | ||||
| 			var success = true; | ||||
| 
 | ||||
| 			if (ClientProcess != null && !ClientProcess.HasTerminated) | ||||
| 			{ | ||||
| 				ProgressIndicator?.UpdateText(TextKey.ProgressIndicator_StopClient, true); | ||||
| 				success = TryStopClient(); | ||||
| 			} | ||||
| 
 | ||||
| 			return success ? OperationResult.Success : OperationResult.Failed; | ||||
| 		} | ||||
| 
 | ||||
| 		public override void Revert() | ||||
| 		{ | ||||
| 			// Nothing to do here... | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | @ -23,8 +23,8 @@ namespace SafeExamBrowser.Runtime.Behaviour.Operations | |||
| 		private IConfigurationRepository repository; | ||||
| 		private ILogger logger; | ||||
| 		private IMessageBox messageBox; | ||||
| 		private RuntimeInfo runtimeInfo; | ||||
| 		private IText text; | ||||
| 		private RuntimeInfo runtimeInfo; | ||||
| 		private string[] commandLineArgs; | ||||
| 
 | ||||
| 		public IProgressIndicator ProgressIndicator { private get; set; } | ||||
|  | @ -50,30 +50,23 @@ namespace SafeExamBrowser.Runtime.Behaviour.Operations | |||
| 			logger.Info("Initializing application configuration..."); | ||||
| 			ProgressIndicator?.UpdateText(TextKey.ProgressIndicator_InitializeConfiguration); | ||||
| 
 | ||||
| 			Settings settings; | ||||
| 			var isValidUri = TryGetSettingsUri(out Uri uri); | ||||
| 
 | ||||
| 			if (isValidUri) | ||||
| 			{ | ||||
| 				logger.Info($"Loading configuration from '{uri.AbsolutePath}'..."); | ||||
| 				settings = repository.LoadSettings(uri); | ||||
| 
 | ||||
| 				if (settings.ConfigurationMode == ConfigurationMode.ConfigureClient) | ||||
| 				{ | ||||
| 					var abort = IsConfigurationSufficient(); | ||||
| 
 | ||||
| 					logger.Info($"The user chose to {(abort ? "abort" : "continue")} after successful client configuration."); | ||||
| 				var abort = LoadSettings(uri); | ||||
| 
 | ||||
| 				if (abort) | ||||
| 				{ | ||||
| 					return OperationResult.Aborted; | ||||
| 				} | ||||
| 			} | ||||
| 			} | ||||
| 			else | ||||
| 			{ | ||||
| 				logger.Info("No valid settings file specified nor found in PROGRAMDATA or APPDATA - loading default settings..."); | ||||
| 				settings = repository.LoadDefaultSettings(); | ||||
| 				repository.LoadDefaultSettings(); | ||||
| 			} | ||||
| 
 | ||||
| 			return OperationResult.Success; | ||||
|  | @ -126,6 +119,21 @@ namespace SafeExamBrowser.Runtime.Behaviour.Operations | |||
| 			return isValidUri; | ||||
| 		} | ||||
| 
 | ||||
| 		private bool LoadSettings(Uri uri) | ||||
| 		{ | ||||
| 			var abort = false; | ||||
| 			var settings = repository.LoadSettings(uri); | ||||
| 
 | ||||
| 			if (settings.ConfigurationMode == ConfigurationMode.ConfigureClient) | ||||
| 			{ | ||||
| 				abort = IsConfigurationSufficient(); | ||||
| 
 | ||||
| 				logger.Info($"The user chose to {(abort ? "abort" : "continue")} after successful client configuration."); | ||||
| 			} | ||||
| 
 | ||||
| 			return abort; | ||||
| 		} | ||||
| 
 | ||||
| 		private bool IsConfigurationSufficient() | ||||
| 		{ | ||||
| 			var message = text.Get(TextKey.MessageBox_ClientConfigurationQuestion); | ||||
|  |  | |||
|  | @ -17,7 +17,7 @@ using SafeExamBrowser.Contracts.UserInterface; | |||
| 
 | ||||
| namespace SafeExamBrowser.Runtime.Behaviour.Operations | ||||
| { | ||||
| 	internal class ServiceConnectionOperation : IOperation | ||||
| 	internal class ServiceOperation : IOperation | ||||
| 	{ | ||||
| 		private bool connected, mandatory; | ||||
| 		private IConfigurationRepository configuration; | ||||
|  | @ -27,7 +27,7 @@ namespace SafeExamBrowser.Runtime.Behaviour.Operations | |||
| 
 | ||||
| 		public IProgressIndicator ProgressIndicator { private get; set; } | ||||
| 
 | ||||
| 		public ServiceConnectionOperation(IConfigurationRepository configuration, ILogger logger, IServiceProxy service, IText text) | ||||
| 		public ServiceOperation(IConfigurationRepository configuration, ILogger logger, IServiceProxy service, IText text) | ||||
| 		{ | ||||
| 			this.configuration = configuration; | ||||
| 			this.service = service; | ||||
|  | @ -37,8 +37,8 @@ namespace SafeExamBrowser.Runtime.Behaviour.Operations | |||
| 
 | ||||
| 		public OperationResult Perform() | ||||
| 		{ | ||||
| 			logger.Info($"Initializing service connection..."); | ||||
| 			ProgressIndicator?.UpdateText(TextKey.ProgressIndicator_InitializeServiceConnection); | ||||
| 			logger.Info($"Initializing service session..."); | ||||
| 			ProgressIndicator?.UpdateText(TextKey.ProgressIndicator_InitializeServiceSession); | ||||
| 
 | ||||
| 			try | ||||
| 			{ | ||||
|  | @ -60,23 +60,35 @@ namespace SafeExamBrowser.Runtime.Behaviour.Operations | |||
| 			service.Ignore = !connected; | ||||
| 			logger.Info($"The service is {(mandatory ? "mandatory" : "optional")} and {(connected ? "available." : "not available. All service-related operations will be ignored!")}"); | ||||
| 
 | ||||
| 			if (connected) | ||||
| 			{ | ||||
| 				StartServiceSession(); | ||||
| 			} | ||||
| 
 | ||||
| 			return OperationResult.Success; | ||||
| 		} | ||||
| 
 | ||||
| 		public OperationResult Repeat() | ||||
| 		{ | ||||
| 			// TODO: Re-check if mandatory, if so, try to connect (if not connected) - otherwise, no action required (except maybe logging of status?) | ||||
| 			if (connected) | ||||
| 			{ | ||||
| 				StopServiceSession(); | ||||
| 				StartServiceSession(); | ||||
| 			} | ||||
| 
 | ||||
| 			return OperationResult.Success; | ||||
| 		} | ||||
| 
 | ||||
| 		public void Revert() | ||||
| 		{ | ||||
| 			logger.Info("Closing service connection..."); | ||||
| 			ProgressIndicator?.UpdateText(TextKey.ProgressIndicator_CloseServiceConnection); | ||||
| 			logger.Info("Finalizing service session..."); | ||||
| 			ProgressIndicator?.UpdateText(TextKey.ProgressIndicator_FinalizeServiceSession); | ||||
| 
 | ||||
| 			if (connected) | ||||
| 			{ | ||||
| 				StopServiceSession(); | ||||
| 
 | ||||
| 				try | ||||
| 				{ | ||||
| 					service.Disconnect(); | ||||
|  | @ -88,6 +100,16 @@ namespace SafeExamBrowser.Runtime.Behaviour.Operations | |||
| 			} | ||||
| 		} | ||||
| 
 | ||||
| 		private void StartServiceSession() | ||||
| 		{ | ||||
| 			service.StartSession(configuration.CurrentSession.Id, configuration.CurrentSettings); | ||||
| 		} | ||||
| 
 | ||||
| 		private void StopServiceSession() | ||||
| 		{ | ||||
| 			service.StopSession(configuration.CurrentSession.Id); | ||||
| 		} | ||||
| 
 | ||||
| 		private void LogException(Exception e) | ||||
| 		{ | ||||
| 			var message = "Failed to connect to the service component!"; | ||||
|  | @ -0,0 +1,65 @@ | |||
| /* | ||||
|  * 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.OperationModel; | ||||
| using SafeExamBrowser.Contracts.Communication.Hosts; | ||||
| using SafeExamBrowser.Contracts.Configuration; | ||||
| using SafeExamBrowser.Contracts.I18n; | ||||
| using SafeExamBrowser.Contracts.Logging; | ||||
| using SafeExamBrowser.Contracts.UserInterface; | ||||
| 
 | ||||
| namespace SafeExamBrowser.Runtime.Behaviour.Operations | ||||
| { | ||||
| 	internal class SessionInitializationOperation : IOperation | ||||
| 	{ | ||||
| 		private IConfigurationRepository configuration; | ||||
| 		private ILogger logger; | ||||
| 		private IRuntimeHost runtimeHost; | ||||
| 
 | ||||
| 		public IProgressIndicator ProgressIndicator { private get; set; } | ||||
| 
 | ||||
| 		public SessionInitializationOperation(IConfigurationRepository configuration, ILogger logger, IRuntimeHost runtimeHost) | ||||
| 		{ | ||||
| 			this.configuration = configuration; | ||||
| 			this.logger = logger; | ||||
| 			this.runtimeHost = runtimeHost; | ||||
| 		} | ||||
| 
 | ||||
| 		public OperationResult Perform() | ||||
| 		{ | ||||
| 			InitializeSessionConfiguration(); | ||||
| 
 | ||||
| 			return OperationResult.Success; | ||||
| 		} | ||||
| 
 | ||||
| 		public OperationResult Repeat() | ||||
| 		{ | ||||
| 			InitializeSessionConfiguration(); | ||||
| 
 | ||||
| 			return OperationResult.Success; | ||||
| 		} | ||||
| 
 | ||||
| 		public void Revert() | ||||
| 		{ | ||||
| 			// Nothing to do here... | ||||
| 		} | ||||
| 
 | ||||
| 		private void InitializeSessionConfiguration() | ||||
| 		{ | ||||
| 			logger.Info("Initializing new session configuration..."); | ||||
| 			ProgressIndicator?.UpdateText(TextKey.ProgressIndicator_InitializeSession, true); | ||||
| 
 | ||||
| 			configuration.InitializeSessionConfiguration(); | ||||
| 			runtimeHost.StartupToken = configuration.CurrentSession.StartupToken; | ||||
| 
 | ||||
| 			logger.Info($" -> Client-ID: {configuration.RuntimeInfo.ClientId}"); | ||||
| 			logger.Info($" -> Runtime-ID: {configuration.RuntimeInfo.RuntimeId} (as reference, does not change)"); | ||||
| 			logger.Info($" -> Session-ID: {configuration.CurrentSession.Id}"); | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | @ -1,45 +0,0 @@ | |||
| /* | ||||
|  * Copyright (c) 2018 ETH Zürich, Educational Development and Technology (LET) | ||||
|  * | ||||
|  * This Source Code Form is subject to the terms of the Mozilla Public | ||||
|  * License, v. 2.0. If a copy of the MPL was not distributed with this | ||||
|  * file, You can obtain one at http://mozilla.org/MPL/2.0/. | ||||
|  */ | ||||
| 
 | ||||
| using SafeExamBrowser.Contracts.Behaviour.OperationModel; | ||||
| using SafeExamBrowser.Contracts.UserInterface; | ||||
| 
 | ||||
| namespace SafeExamBrowser.Runtime.Behaviour.Operations | ||||
| { | ||||
| 	internal class SessionSequenceEndOperation : IOperation | ||||
| 	{ | ||||
| 		private SessionController controller; | ||||
| 
 | ||||
| 		public IProgressIndicator ProgressIndicator { private get; set; } | ||||
| 
 | ||||
| 		public SessionSequenceEndOperation(SessionController controller) | ||||
| 		{ | ||||
| 			this.controller = controller; | ||||
| 		} | ||||
| 
 | ||||
| 		public OperationResult Perform() | ||||
| 		{ | ||||
| 			controller.ProgressIndicator = ProgressIndicator; | ||||
| 
 | ||||
| 			return controller.StartSession(); | ||||
| 		} | ||||
| 
 | ||||
| 		public OperationResult Repeat() | ||||
| 		{ | ||||
| 			controller.ProgressIndicator = ProgressIndicator; | ||||
| 
 | ||||
| 			return controller.StartSession(); | ||||
| 		} | ||||
| 
 | ||||
| 		public void Revert() | ||||
| 		{ | ||||
| 			controller.ProgressIndicator = ProgressIndicator; | ||||
| 			controller.StopSession(); | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | @ -1,42 +0,0 @@ | |||
| /* | ||||
|  * Copyright (c) 2018 ETH Zürich, Educational Development and Technology (LET) | ||||
|  * | ||||
|  * This Source Code Form is subject to the terms of the Mozilla Public | ||||
|  * License, v. 2.0. If a copy of the MPL was not distributed with this | ||||
|  * file, You can obtain one at http://mozilla.org/MPL/2.0/. | ||||
|  */ | ||||
| 
 | ||||
| using SafeExamBrowser.Contracts.Behaviour.OperationModel; | ||||
| using SafeExamBrowser.Contracts.UserInterface; | ||||
| 
 | ||||
| namespace SafeExamBrowser.Runtime.Behaviour.Operations | ||||
| { | ||||
| 	internal class SessionSequenceStartOperation : IOperation | ||||
| 	{ | ||||
| 		private SessionController controller; | ||||
| 
 | ||||
| 		public IProgressIndicator ProgressIndicator { private get; set; } | ||||
| 
 | ||||
| 		public SessionSequenceStartOperation(SessionController controller) | ||||
| 		{ | ||||
| 			this.controller = controller; | ||||
| 		} | ||||
| 
 | ||||
| 		public OperationResult Perform() | ||||
| 		{ | ||||
| 			return OperationResult.Success; | ||||
| 		} | ||||
| 
 | ||||
| 		public OperationResult Repeat() | ||||
| 		{ | ||||
| 			controller.ProgressIndicator = ProgressIndicator; | ||||
| 
 | ||||
| 			return controller.StopSession(); | ||||
| 		} | ||||
| 
 | ||||
| 		public void Revert() | ||||
| 		{ | ||||
| 			// Nothing to do here... | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | @ -209,18 +209,18 @@ namespace SafeExamBrowser.Runtime.Behaviour | |||
| 			runtimeHost.ShutdownRequested += RuntimeHost_ShutdownRequested; | ||||
| 		} | ||||
| 
 | ||||
| 		private void RegisterSessionEvents() | ||||
| 		{ | ||||
| 			configuration.CurrentSession.ClientProcess.Terminated += ClientProcess_Terminated; | ||||
| 			configuration.CurrentSession.ClientProxy.ConnectionLost += Client_ConnectionLost; | ||||
| 		} | ||||
| 
 | ||||
| 		private void DeregisterEvents() | ||||
| 		{ | ||||
| 			runtimeHost.ReconfigurationRequested -= RuntimeHost_ReconfigurationRequested; | ||||
| 			runtimeHost.ShutdownRequested -= RuntimeHost_ShutdownRequested; | ||||
| 		} | ||||
| 
 | ||||
| 		private void RegisterSessionEvents() | ||||
| 		{ | ||||
| 			configuration.CurrentSession.ClientProcess.Terminated += ClientProcess_Terminated; | ||||
| 			configuration.CurrentSession.ClientProxy.ConnectionLost += Client_ConnectionLost; | ||||
| 		} | ||||
| 
 | ||||
| 		private void DeregisterSessionEvents() | ||||
| 		{ | ||||
| 			configuration.CurrentSession.ClientProcess.Terminated -= ClientProcess_Terminated; | ||||
|  |  | |||
|  | @ -54,7 +54,6 @@ namespace SafeExamBrowser.Runtime | |||
| 			var proxyFactory = new ProxyFactory(new ProxyObjectFactory(), logger); | ||||
| 			var runtimeHost = new RuntimeHost(runtimeInfo.RuntimeAddress, configuration, new HostObjectFactory(), new ModuleLogger(logger, typeof(RuntimeHost))); | ||||
| 			var serviceProxy = new ServiceProxy(runtimeInfo.ServiceAddress, new ProxyObjectFactory(), new ModuleLogger(logger, typeof(ServiceProxy))); | ||||
| 			var sessionController = new SessionController(configuration, logger, processFactory, proxyFactory, runtimeHost, serviceProxy); | ||||
| 
 | ||||
| 			var bootstrapOperations = new Queue<IOperation>(); | ||||
| 			var sessionOperations = new Queue<IOperation>(); | ||||
|  | @ -62,16 +61,17 @@ namespace SafeExamBrowser.Runtime | |||
| 			bootstrapOperations.Enqueue(new I18nOperation(logger, text)); | ||||
| 			bootstrapOperations.Enqueue(new CommunicationOperation(runtimeHost, logger)); | ||||
| 
 | ||||
| 			sessionOperations.Enqueue(new SessionSequenceStartOperation(sessionController)); | ||||
| 			sessionOperations.Enqueue(new ConfigurationOperation(configuration, logger, messageBox, runtimeInfo, text, args)); | ||||
| 			sessionOperations.Enqueue(new ServiceConnectionOperation(configuration, logger, serviceProxy, text)); | ||||
| 			sessionOperations.Enqueue(new SessionInitializationOperation(configuration, logger, runtimeHost)); | ||||
| 			sessionOperations.Enqueue(new ServiceOperation(configuration, logger, serviceProxy, text)); | ||||
| 			sessionOperations.Enqueue(new ClientTerminationOperation(configuration, logger, processFactory, proxyFactory, runtimeHost)); | ||||
| 			sessionOperations.Enqueue(new KioskModeOperation(logger, configuration)); | ||||
| 			sessionOperations.Enqueue(new SessionSequenceEndOperation(sessionController)); | ||||
| 			sessionOperations.Enqueue(new ClientOperation(configuration, logger, processFactory, proxyFactory, runtimeHost)); | ||||
| 
 | ||||
| 			var boostrapSequence = new OperationSequence(logger, bootstrapOperations); | ||||
| 			var bootstrapSequence = new OperationSequence(logger, bootstrapOperations); | ||||
| 			var sessionSequence = new OperationSequence(logger, sessionOperations); | ||||
| 
 | ||||
| 			RuntimeController = new RuntimeController(configuration, logger, messageBox, boostrapSequence, sessionSequence, runtimeHost,  runtimeInfo, serviceProxy, shutdown, uiFactory); | ||||
| 			RuntimeController = new RuntimeController(configuration, logger, messageBox, bootstrapSequence, sessionSequence, runtimeHost,  runtimeInfo, serviceProxy, shutdown, uiFactory); | ||||
| 		} | ||||
| 
 | ||||
| 		internal void LogStartupInformation() | ||||
|  |  | |||
|  | @ -87,12 +87,12 @@ | |||
|   </ItemGroup> | ||||
|   <ItemGroup> | ||||
|     <Compile Include="App.cs" /> | ||||
|     <Compile Include="Behaviour\Operations\ClientOperation.cs" /> | ||||
|     <Compile Include="Behaviour\Operations\ClientTerminationOperation.cs" /> | ||||
|     <Compile Include="Behaviour\Operations\ConfigurationOperation.cs" /> | ||||
|     <Compile Include="Behaviour\Operations\KioskModeOperation.cs" /> | ||||
|     <Compile Include="Behaviour\Operations\ServiceConnectionOperation.cs" /> | ||||
|     <Compile Include="Behaviour\Operations\SessionSequenceEndOperation.cs" /> | ||||
|     <Compile Include="Behaviour\SessionController.cs" /> | ||||
|     <Compile Include="Behaviour\Operations\SessionSequenceStartOperation.cs" /> | ||||
|     <Compile Include="Behaviour\Operations\ServiceOperation.cs" /> | ||||
|     <Compile Include="Behaviour\Operations\SessionInitializationOperation.cs" /> | ||||
|     <Compile Include="Communication\ProxyFactory.cs" /> | ||||
|     <Compile Include="Communication\RuntimeHost.cs" /> | ||||
|     <Compile Include="CompositionRoot.cs" /> | ||||
|  |  | |||
		Loading…
	
	Add table
		
		Reference in a new issue
	
	 dbuechel
						dbuechel