SEBWIN-405: Changed implementation for sending of log events and implemented server quit event.
This commit is contained in:
parent
6997d3a5f5
commit
09fbc6579a
6 changed files with 104 additions and 28 deletions
|
@ -206,7 +206,7 @@ namespace SafeExamBrowser.Client
|
|||
|
||||
if (Server != null)
|
||||
{
|
||||
// TODO
|
||||
Server.TerminationRequested += Server_TerminationRequested;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -240,7 +240,7 @@ namespace SafeExamBrowser.Client
|
|||
|
||||
if (Server != null)
|
||||
{
|
||||
// TODO
|
||||
Server.TerminationRequested -= Server_TerminationRequested;
|
||||
}
|
||||
|
||||
foreach (var activator in context.Activators.OfType<ITerminationActivator>())
|
||||
|
@ -551,6 +551,12 @@ namespace SafeExamBrowser.Client
|
|||
shutdown.Invoke();
|
||||
}
|
||||
|
||||
private void Server_TerminationRequested()
|
||||
{
|
||||
logger.Info("Attempting to shutdown as requested by the server...");
|
||||
TryRequestShutdown();
|
||||
}
|
||||
|
||||
private void Shell_QuitButtonClicked(System.ComponentModel.CancelEventArgs args)
|
||||
{
|
||||
PauseActivators();
|
||||
|
|
|
@ -77,6 +77,7 @@ namespace SafeExamBrowser.Runtime.Operations
|
|||
|
||||
if (status == LoadStatus.Success)
|
||||
{
|
||||
// TODO: Why aren't the server settings and SEB mode correctly set in the exam configuration?
|
||||
var serverSettings = Context.Next.Settings.Server;
|
||||
|
||||
Context.Next.AppConfig.ServerApi = info.Api;
|
||||
|
|
|
@ -0,0 +1,15 @@
|
|||
/*
|
||||
* 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.Events
|
||||
{
|
||||
/// <summary>
|
||||
/// Event handler used to indicate that a termination instruction has been detected.
|
||||
/// </summary>
|
||||
public delegate void TerminationRequestedEventHandler();
|
||||
}
|
|
@ -9,6 +9,7 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using SafeExamBrowser.Server.Contracts.Data;
|
||||
using SafeExamBrowser.Server.Contracts.Events;
|
||||
using SafeExamBrowser.Settings.Server;
|
||||
|
||||
namespace SafeExamBrowser.Server.Contracts
|
||||
|
@ -18,6 +19,11 @@ namespace SafeExamBrowser.Server.Contracts
|
|||
/// </summary>
|
||||
public interface IServerProxy
|
||||
{
|
||||
/// <summary>
|
||||
/// Event fired when the server detects an instruction to terminate SEB.
|
||||
/// </summary>
|
||||
event TerminationRequestedEventHandler TerminationRequested;
|
||||
|
||||
/// <summary>
|
||||
/// Attempts to initialize a connection with the server.
|
||||
/// </summary>
|
||||
|
|
|
@ -56,6 +56,7 @@
|
|||
<ItemGroup>
|
||||
<Compile Include="Data\ConnectionInfo.cs" />
|
||||
<Compile Include="Data\Exam.cs" />
|
||||
<Compile Include="Events\TerminationRequestedEventHandler.cs" />
|
||||
<Compile Include="IServerProxy.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
<Compile Include="Data\ServerResponse.cs" />
|
||||
|
@ -66,5 +67,6 @@
|
|||
<Name>SafeExamBrowser.Settings</Name>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<ItemGroup />
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
</Project>
|
|
@ -14,6 +14,7 @@ using System.Linq;
|
|||
using System.Net.Http;
|
||||
using System.Net.Http.Headers;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using System.Timers;
|
||||
using Newtonsoft.Json;
|
||||
|
@ -22,9 +23,11 @@ using SafeExamBrowser.Configuration.Contracts;
|
|||
using SafeExamBrowser.Logging.Contracts;
|
||||
using SafeExamBrowser.Server.Contracts;
|
||||
using SafeExamBrowser.Server.Contracts.Data;
|
||||
using SafeExamBrowser.Server.Contracts.Events;
|
||||
using SafeExamBrowser.Server.Data;
|
||||
using SafeExamBrowser.Settings.Logging;
|
||||
using SafeExamBrowser.Settings.Server;
|
||||
using Timer = System.Timers.Timer;
|
||||
|
||||
namespace SafeExamBrowser.Server
|
||||
{
|
||||
|
@ -32,6 +35,7 @@ namespace SafeExamBrowser.Server
|
|||
{
|
||||
private ApiVersion1 api;
|
||||
private AppConfig appConfig;
|
||||
private CancellationTokenSource cancellationTokenSource;
|
||||
private string connectionToken;
|
||||
private string examId;
|
||||
private HttpClient httpClient;
|
||||
|
@ -40,12 +44,16 @@ namespace SafeExamBrowser.Server
|
|||
private string oauth2Token;
|
||||
private int pingNumber;
|
||||
private ServerSettings settings;
|
||||
private Task task;
|
||||
private Timer timer;
|
||||
|
||||
public event TerminationRequestedEventHandler TerminationRequested;
|
||||
|
||||
public ServerProxy(AppConfig appConfig, ILogger logger)
|
||||
{
|
||||
this.api = new ApiVersion1();
|
||||
this.appConfig = appConfig;
|
||||
this.cancellationTokenSource = new CancellationTokenSource();
|
||||
this.httpClient = new HttpClient();
|
||||
this.logger = logger;
|
||||
this.logContent = new ConcurrentQueue<ILogContent>();
|
||||
|
@ -244,6 +252,9 @@ namespace SafeExamBrowser.Server
|
|||
|
||||
logger.Subscribe(this);
|
||||
|
||||
task = new Task(SendLog, cancellationTokenSource.Token);
|
||||
task.Start();
|
||||
|
||||
timer.AutoReset = false;
|
||||
timer.Elapsed += Timer_Elapsed;
|
||||
timer.Interval = 1000;
|
||||
|
@ -253,36 +264,23 @@ namespace SafeExamBrowser.Server
|
|||
public void StopConnectivity()
|
||||
{
|
||||
logger.Unsubscribe(this);
|
||||
cancellationTokenSource.Cancel();
|
||||
task.Wait();
|
||||
|
||||
timer.Stop();
|
||||
timer.Elapsed -= Timer_Elapsed;
|
||||
}
|
||||
|
||||
private void Timer_Elapsed(object sender, ElapsedEventArgs args)
|
||||
private void SendLog()
|
||||
{
|
||||
var authorization = ("Authorization", $"Bearer {oauth2Token}");
|
||||
var contentType = "application/json;charset=UTF-8";
|
||||
var token = ("SEBConnectionToken", connectionToken);
|
||||
|
||||
try
|
||||
{
|
||||
var content = $"timestamp={DateTime.Now.Ticks}&ping-number={++pingNumber}";
|
||||
var contentType = "application/x-www-form-urlencoded";
|
||||
var success = TryExecute(HttpMethod.Post, api.PingEndpoint, out var response, content, contentType, authorization, token);
|
||||
logger.Info("Starting to send log items...");
|
||||
|
||||
if (success)
|
||||
while (!cancellationTokenSource.IsCancellationRequested)
|
||||
{
|
||||
// TODO: Fire event if instruction is sent via response!
|
||||
}
|
||||
else
|
||||
{
|
||||
logger.Error($"Failed to send ping: {ToString(response)}");
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
logger.Error("Failed to send ping!", e);
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
if (logContent.TryDequeue(out var c) && c is ILogMessage message)
|
||||
|
@ -293,9 +291,7 @@ namespace SafeExamBrowser.Server
|
|||
["timestamp"] = message.DateTime.Ticks,
|
||||
["text"] = message.Message
|
||||
};
|
||||
|
||||
var content = json.ToString();
|
||||
var contentType = "application/json;charset=UTF-8";
|
||||
// TODO: Why can't we send multiple log messages in one request?
|
||||
var success = TryExecute(HttpMethod.Post, api.LogEndpoint, out var response, content, contentType, authorization, token);
|
||||
}
|
||||
|
@ -304,6 +300,34 @@ namespace SafeExamBrowser.Server
|
|||
{
|
||||
logger.Error("Failed to send log!", e);
|
||||
}
|
||||
}
|
||||
|
||||
logger.Info("Stopped sending log items.");
|
||||
}
|
||||
|
||||
private void Timer_Elapsed(object sender, ElapsedEventArgs args)
|
||||
{
|
||||
try
|
||||
{
|
||||
var authorization = ("Authorization", $"Bearer {oauth2Token}");
|
||||
var content = $"timestamp={DateTime.Now.Ticks}&ping-number={++pingNumber}";
|
||||
var contentType = "application/x-www-form-urlencoded";
|
||||
var token = ("SEBConnectionToken", connectionToken);
|
||||
var success = TryExecute(HttpMethod.Post, api.PingEndpoint, out var response, content, contentType, authorization, token);
|
||||
|
||||
if (success && TryParseInstruction(response.Content, out var instruction) && instruction == "SEB_QUIT")
|
||||
{
|
||||
Task.Run(() => TerminationRequested?.Invoke());
|
||||
}
|
||||
else
|
||||
{
|
||||
logger.Error($"Failed to send ping: {ToString(response)}");
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
logger.Error("Failed to send ping!", e);
|
||||
}
|
||||
|
||||
timer.Start();
|
||||
}
|
||||
|
@ -413,6 +437,24 @@ namespace SafeExamBrowser.Server
|
|||
return exams.Any();
|
||||
}
|
||||
|
||||
private bool TryParseInstruction(HttpContent content, out string instruction)
|
||||
{
|
||||
instruction = default(string);
|
||||
|
||||
try
|
||||
{
|
||||
var json = JsonConvert.DeserializeObject(Extract(content)) as JObject;
|
||||
|
||||
instruction = json["instruction"].Value<string>();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
logger.Error("Failed to parse instruction!", e);
|
||||
}
|
||||
|
||||
return instruction != default(string);
|
||||
}
|
||||
|
||||
private bool TryParseOauth2Token(HttpContent content)
|
||||
{
|
||||
try
|
||||
|
@ -461,8 +503,12 @@ namespace SafeExamBrowser.Server
|
|||
try
|
||||
{
|
||||
response = httpClient.SendAsync(request).GetAwaiter().GetResult();
|
||||
|
||||
if (request.RequestUri.AbsolutePath != api.LogEndpoint && request.RequestUri.AbsolutePath != api.PingEndpoint)
|
||||
{
|
||||
logger.Debug($"Completed request: {request.Method} '{request.RequestUri}' -> {ToString(response)}");
|
||||
}
|
||||
}
|
||||
catch (TaskCanceledException)
|
||||
{
|
||||
logger.Debug($"Request {request.Method} '{request.RequestUri}' did not complete within {settings.RequestTimeout}ms!");
|
||||
|
|
Loading…
Add table
Reference in a new issue