SEBWIN-405: Implemented loading of server exam configuration.
This commit is contained in:
		
							parent
							
								
									7915d4dff9
								
							
						
					
					
						commit
						ef13cfe9c5
					
				
					 4 changed files with 96 additions and 20 deletions
				
			
		|  | @ -63,11 +63,12 @@ namespace SafeExamBrowser.Runtime | ||||||
| 			var uiFactory = new UserInterfaceFactory(text); | 			var uiFactory = new UserInterfaceFactory(text); | ||||||
| 			var desktopFactory = new DesktopFactory(ModuleLogger(nameof(DesktopFactory))); | 			var desktopFactory = new DesktopFactory(ModuleLogger(nameof(DesktopFactory))); | ||||||
| 			var explorerShell = new ExplorerShell(ModuleLogger(nameof(ExplorerShell)), nativeMethods); | 			var explorerShell = new ExplorerShell(ModuleLogger(nameof(ExplorerShell)), nativeMethods); | ||||||
|  | 			var fileSystem = new FileSystem(); | ||||||
| 			var processFactory = new ProcessFactory(ModuleLogger(nameof(ProcessFactory))); | 			var processFactory = new ProcessFactory(ModuleLogger(nameof(ProcessFactory))); | ||||||
| 			var proxyFactory = new ProxyFactory(new ProxyObjectFactory(), ModuleLogger(nameof(ProxyFactory))); | 			var proxyFactory = new ProxyFactory(new ProxyObjectFactory(), ModuleLogger(nameof(ProxyFactory))); | ||||||
| 			var runtimeHost = new RuntimeHost(appConfig.RuntimeAddress, new HostObjectFactory(), ModuleLogger(nameof(RuntimeHost)), FIVE_SECONDS); | 			var runtimeHost = new RuntimeHost(appConfig.RuntimeAddress, new HostObjectFactory(), ModuleLogger(nameof(RuntimeHost)), FIVE_SECONDS); | ||||||
| 			var runtimeWindow = uiFactory.CreateRuntimeWindow(appConfig); | 			var runtimeWindow = uiFactory.CreateRuntimeWindow(appConfig); | ||||||
| 			var server = new ServerProxy(ModuleLogger(nameof(ServerProxy))); | 			var server = new ServerProxy(appConfig, ModuleLogger(nameof(ServerProxy))); | ||||||
| 			var serviceProxy = new ServiceProxy(appConfig.ServiceAddress, new ProxyObjectFactory(), ModuleLogger(nameof(ServiceProxy)), Interlocutor.Runtime); | 			var serviceProxy = new ServiceProxy(appConfig.ServiceAddress, new ProxyObjectFactory(), ModuleLogger(nameof(ServiceProxy)), Interlocutor.Runtime); | ||||||
| 			var sessionContext = new SessionContext(); | 			var sessionContext = new SessionContext(); | ||||||
| 			var splashScreen = uiFactory.CreateSplashScreen(appConfig); | 			var splashScreen = uiFactory.CreateSplashScreen(appConfig); | ||||||
|  | @ -82,7 +83,7 @@ namespace SafeExamBrowser.Runtime | ||||||
| 
 | 
 | ||||||
| 			sessionOperations.Enqueue(new SessionInitializationOperation(configuration, logger, runtimeHost, sessionContext)); | 			sessionOperations.Enqueue(new SessionInitializationOperation(configuration, logger, runtimeHost, sessionContext)); | ||||||
| 			sessionOperations.Enqueue(new ConfigurationOperation(args, configuration, new FileSystem(), new HashAlgorithm(), logger, sessionContext)); | 			sessionOperations.Enqueue(new ConfigurationOperation(args, configuration, new FileSystem(), new HashAlgorithm(), logger, sessionContext)); | ||||||
| 			sessionOperations.Enqueue(new ServerOperation(args, configuration, logger, sessionContext, server)); | 			sessionOperations.Enqueue(new ServerOperation(args, configuration, fileSystem, logger, sessionContext, server)); | ||||||
| 			sessionOperations.Enqueue(new VirtualMachineOperation(vmDetector, logger, sessionContext)); | 			sessionOperations.Enqueue(new VirtualMachineOperation(vmDetector, logger, sessionContext)); | ||||||
| 			sessionOperations.Enqueue(new ServiceOperation(logger, runtimeHost, serviceProxy, sessionContext, THIRTY_SECONDS, userInfo)); | 			sessionOperations.Enqueue(new ServiceOperation(logger, runtimeHost, serviceProxy, sessionContext, THIRTY_SECONDS, userInfo)); | ||||||
| 			sessionOperations.Enqueue(new ClientTerminationOperation(logger, processFactory, proxyFactory, runtimeHost, sessionContext, THIRTY_SECONDS)); | 			sessionOperations.Enqueue(new ClientTerminationOperation(logger, processFactory, proxyFactory, runtimeHost, sessionContext, THIRTY_SECONDS)); | ||||||
|  |  | ||||||
|  | @ -16,11 +16,13 @@ using SafeExamBrowser.Logging.Contracts; | ||||||
| using SafeExamBrowser.Runtime.Operations.Events; | using SafeExamBrowser.Runtime.Operations.Events; | ||||||
| using SafeExamBrowser.Server.Contracts; | using SafeExamBrowser.Server.Contracts; | ||||||
| using SafeExamBrowser.Settings; | using SafeExamBrowser.Settings; | ||||||
|  | using SafeExamBrowser.SystemComponents.Contracts; | ||||||
| 
 | 
 | ||||||
| namespace SafeExamBrowser.Runtime.Operations | namespace SafeExamBrowser.Runtime.Operations | ||||||
| { | { | ||||||
| 	internal class ServerOperation : ConfigurationBaseOperation | 	internal class ServerOperation : ConfigurationBaseOperation | ||||||
| 	{ | 	{ | ||||||
|  | 		private readonly IFileSystem fileSystem; | ||||||
| 		private readonly ILogger logger; | 		private readonly ILogger logger; | ||||||
| 		private readonly IServerProxy server; | 		private readonly IServerProxy server; | ||||||
| 
 | 
 | ||||||
|  | @ -30,10 +32,12 @@ namespace SafeExamBrowser.Runtime.Operations | ||||||
| 		public ServerOperation( | 		public ServerOperation( | ||||||
| 			string[] commandLineArgs, | 			string[] commandLineArgs, | ||||||
| 			IConfigurationRepository configuration, | 			IConfigurationRepository configuration, | ||||||
|  | 			IFileSystem fileSystem, | ||||||
| 			ILogger logger, | 			ILogger logger, | ||||||
| 			SessionContext context, | 			SessionContext context, | ||||||
| 			IServerProxy server) : base(commandLineArgs, configuration, context) | 			IServerProxy server) : base(commandLineArgs, configuration, context) | ||||||
| 		{ | 		{ | ||||||
|  | 			this.fileSystem = fileSystem; | ||||||
| 			this.logger = logger; | 			this.logger = logger; | ||||||
| 			this.server = server; | 			this.server = server; | ||||||
| 		} | 		} | ||||||
|  | @ -67,6 +71,8 @@ namespace SafeExamBrowser.Runtime.Operations | ||||||
| 							{ | 							{ | ||||||
| 								var status = TryLoadSettings(uri, UriSource.Server, out _, out var settings); | 								var status = TryLoadSettings(uri, UriSource.Server, out _, out var settings); | ||||||
| 
 | 
 | ||||||
|  | 								fileSystem.Delete(uri.LocalPath); | ||||||
|  | 
 | ||||||
| 								if (status == LoadStatus.Success) | 								if (status == LoadStatus.Success) | ||||||
| 								{ | 								{ | ||||||
| 									Context.Next.Settings = settings; | 									Context.Next.Settings = settings; | ||||||
|  |  | ||||||
|  | @ -63,6 +63,10 @@ | ||||||
|     <Compile Include="ServerProxy.cs" /> |     <Compile Include="ServerProxy.cs" /> | ||||||
|   </ItemGroup> |   </ItemGroup> | ||||||
|   <ItemGroup> |   <ItemGroup> | ||||||
|  |     <ProjectReference Include="..\SafeExamBrowser.Configuration.Contracts\SafeExamBrowser.Configuration.Contracts.csproj"> | ||||||
|  |       <Project>{7d74555e-63e1-4c46-bd0a-8580552368c8}</Project> | ||||||
|  |       <Name>SafeExamBrowser.Configuration.Contracts</Name> | ||||||
|  |     </ProjectReference> | ||||||
|     <ProjectReference Include="..\SafeExamBrowser.Logging.Contracts\SafeExamBrowser.Logging.Contracts.csproj"> |     <ProjectReference Include="..\SafeExamBrowser.Logging.Contracts\SafeExamBrowser.Logging.Contracts.csproj"> | ||||||
|       <Project>{64ea30fb-11d4-436a-9c2b-88566285363e}</Project> |       <Project>{64ea30fb-11d4-436a-9c2b-88566285363e}</Project> | ||||||
|       <Name>SafeExamBrowser.Logging.Contracts</Name> |       <Name>SafeExamBrowser.Logging.Contracts</Name> | ||||||
|  |  | ||||||
|  | @ -16,6 +16,7 @@ using System.Text; | ||||||
| using System.Threading.Tasks; | using System.Threading.Tasks; | ||||||
| using Newtonsoft.Json; | using Newtonsoft.Json; | ||||||
| using Newtonsoft.Json.Linq; | using Newtonsoft.Json.Linq; | ||||||
|  | using SafeExamBrowser.Configuration.Contracts; | ||||||
| using SafeExamBrowser.Logging.Contracts; | using SafeExamBrowser.Logging.Contracts; | ||||||
| using SafeExamBrowser.Server.Contracts; | using SafeExamBrowser.Server.Contracts; | ||||||
| using SafeExamBrowser.Server.Data; | using SafeExamBrowser.Server.Data; | ||||||
|  | @ -28,13 +29,15 @@ namespace SafeExamBrowser.Server | ||||||
| 		private ApiVersion1 api; | 		private ApiVersion1 api; | ||||||
| 		private string connectionToken; | 		private string connectionToken; | ||||||
| 		private HttpClient httpClient; | 		private HttpClient httpClient; | ||||||
|  | 		private readonly AppConfig appConfig; | ||||||
| 		private ILogger logger; | 		private ILogger logger; | ||||||
| 		private string oauth2Token; | 		private string oauth2Token; | ||||||
| 		private ServerSettings settings; | 		private ServerSettings settings; | ||||||
| 
 | 
 | ||||||
| 		public ServerProxy(ILogger logger) | 		public ServerProxy(AppConfig appConfig, ILogger logger) | ||||||
| 		{ | 		{ | ||||||
| 			this.api = new ApiVersion1(); | 			this.api = new ApiVersion1(); | ||||||
|  | 			this.appConfig = appConfig; | ||||||
| 			this.httpClient = new HttpClient(); | 			this.httpClient = new HttpClient(); | ||||||
| 			this.logger = logger; | 			this.logger = logger; | ||||||
| 		} | 		} | ||||||
|  | @ -75,7 +78,7 @@ namespace SafeExamBrowser.Server | ||||||
| 
 | 
 | ||||||
| 		public ServerResponse Disconnect() | 		public ServerResponse Disconnect() | ||||||
| 		{ | 		{ | ||||||
| 			return new ServerResponse(false, "Some error message here"); | 			return new ServerResponse(false, "TODO!"); | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		public ServerResponse<IEnumerable<Exam>> GetAvailableExams() | 		public ServerResponse<IEnumerable<Exam>> GetAvailableExams() | ||||||
|  | @ -83,13 +86,19 @@ namespace SafeExamBrowser.Server | ||||||
| 			var authorization = ("Authorization", $"Bearer {oauth2Token}"); | 			var authorization = ("Authorization", $"Bearer {oauth2Token}"); | ||||||
| 			var content = $"institutionId={settings.Institution}"; | 			var content = $"institutionId={settings.Institution}"; | ||||||
| 			var contentType = "application/x-www-form-urlencoded"; | 			var contentType = "application/x-www-form-urlencoded"; | ||||||
|  | 			var exams = default(IList<Exam>); | ||||||
| 
 | 
 | ||||||
| 			var success = TryExecute(HttpMethod.Post, api.HandshakeEndpoint, out var response, content, contentType, authorization); | 			var success = TryExecute(HttpMethod.Post, api.HandshakeEndpoint, out var response, content, contentType, authorization); | ||||||
| 			var message = ToString(response); | 			var message = ToString(response); | ||||||
| 			var hasToken = TryParseConnectionToken(response); |  | ||||||
| 			var hasExams = TryParseExams(response.Content, out var exams); |  | ||||||
| 
 | 
 | ||||||
| 			if (success && hasExams && hasToken) | 			if (success) | ||||||
|  | 			{ | ||||||
|  | 				var hasExams = TryParseExams(response.Content, out exams); | ||||||
|  | 				var hasToken = TryParseConnectionToken(response); | ||||||
|  | 
 | ||||||
|  | 				success = hasExams && hasToken; | ||||||
|  | 
 | ||||||
|  | 				if (success) | ||||||
| 				{ | 				{ | ||||||
| 					logger.Info("Successfully retrieved connection token and available exams."); | 					logger.Info("Successfully retrieved connection token and available exams."); | ||||||
| 				} | 				} | ||||||
|  | @ -101,19 +110,45 @@ namespace SafeExamBrowser.Server | ||||||
| 				{ | 				{ | ||||||
| 					logger.Error("Failed to retrieve connection token!"); | 					logger.Error("Failed to retrieve connection token!"); | ||||||
| 				} | 				} | ||||||
|  | 			} | ||||||
| 			else | 			else | ||||||
| 			{ | 			{ | ||||||
| 				logger.Error("Failed to load connection token and available exams!"); | 				logger.Error("Failed to load connection token and available exams!"); | ||||||
| 			} | 			} | ||||||
| 
 | 
 | ||||||
| 			return new ServerResponse<IEnumerable<Exam>>(hasExams && hasToken, exams, message); | 			return new ServerResponse<IEnumerable<Exam>>(success, exams, message); | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		public ServerResponse<Uri> GetConfigurationFor(Exam exam) | 		public ServerResponse<Uri> GetConfigurationFor(Exam exam) | ||||||
| 		{ | 		{ | ||||||
| 			// 4. Send exam ID | 			var authorization = ("Authorization", $"Bearer {oauth2Token}"); | ||||||
|  | 			var token = ("SEBConnectionToken", connectionToken); | ||||||
|  | 			var uri = default(Uri); | ||||||
| 
 | 
 | ||||||
| 			return new ServerResponse<Uri>(false, default(Uri), "Some error message here"); | 			var success = TryExecute(HttpMethod.Get, $"{api.ConfigurationEndpoint}?examId={exam.Id}", out var response, default(string), default(string), authorization, token); | ||||||
|  | 			var message = ToString(response); | ||||||
|  | 
 | ||||||
|  | 			if (success) | ||||||
|  | 			{ | ||||||
|  | 				logger.Info("Successfully retrieved exam configuration."); | ||||||
|  | 
 | ||||||
|  | 				success = TrySaveFile(response.Content, out uri); | ||||||
|  | 
 | ||||||
|  | 				if (success) | ||||||
|  | 				{ | ||||||
|  | 					logger.Info($"Successfully saved exam configuration as '{uri}'."); | ||||||
|  | 				} | ||||||
|  | 				else | ||||||
|  | 				{ | ||||||
|  | 					logger.Error("Failed to save exam configuration!"); | ||||||
|  | 				} | ||||||
|  | 			} | ||||||
|  | 			else | ||||||
|  | 			{ | ||||||
|  | 				logger.Error("Failed to retrieve exam configuration!"); | ||||||
|  | 			} | ||||||
|  | 
 | ||||||
|  | 			return new ServerResponse<Uri>(success, uri, message); | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		public void Initialize(ServerSettings settings) | 		public void Initialize(ServerSettings settings) | ||||||
|  | @ -129,7 +164,7 @@ namespace SafeExamBrowser.Server | ||||||
| 
 | 
 | ||||||
| 		public ServerResponse SendSessionInfo(string sessionId) | 		public ServerResponse SendSessionInfo(string sessionId) | ||||||
| 		{ | 		{ | ||||||
| 			return new ServerResponse(false, "Some error message here"); | 			return new ServerResponse(false, "TODO!"); | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		private bool TryParseApi(HttpContent content) | 		private bool TryParseApi(HttpContent content) | ||||||
|  | @ -301,6 +336,36 @@ namespace SafeExamBrowser.Server | ||||||
| 			return response != default(HttpResponseMessage) && response.IsSuccessStatusCode; | 			return response != default(HttpResponseMessage) && response.IsSuccessStatusCode; | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
|  | 		private bool TrySaveFile(HttpContent content, out Uri uri) | ||||||
|  | 		{ | ||||||
|  | 			uri = new Uri(Path.Combine(appConfig.TemporaryDirectory, $"ServerExam{appConfig.ConfigurationFileExtension}")); | ||||||
|  | 
 | ||||||
|  | 			try | ||||||
|  | 			{ | ||||||
|  | 				var task = Task.Run(async () => | ||||||
|  | 				{ | ||||||
|  | 					return await content.ReadAsStreamAsync(); | ||||||
|  | 				}); | ||||||
|  | 
 | ||||||
|  | 				using (var data = task.GetAwaiter().GetResult()) | ||||||
|  | 				using (var file = new FileStream(uri.LocalPath, FileMode.Create)) | ||||||
|  | 				{ | ||||||
|  | 					data.Seek(0, SeekOrigin.Begin); | ||||||
|  | 					data.CopyTo(file); | ||||||
|  | 					data.Flush(); | ||||||
|  | 					file.Flush(); | ||||||
|  | 				} | ||||||
|  | 
 | ||||||
|  | 				return true; | ||||||
|  | 			} | ||||||
|  | 			catch (Exception e) | ||||||
|  | 			{ | ||||||
|  | 				logger.Error($"Failed to save file '{uri.LocalPath}'!", e); | ||||||
|  | 			} | ||||||
|  | 
 | ||||||
|  | 			return false; | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
| 		private string Extract(HttpContent content) | 		private string Extract(HttpContent content) | ||||||
| 		{ | 		{ | ||||||
| 			var task = Task.Run(async () => | 			var task = Task.Run(async () => | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		
		Reference in a new issue
	
	 Damian Büchel
						Damian Büchel