From 7ac34b3473e8fdecc9decb495cb55127d155b859 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Damian=20B=C3=BCchel?= <damian.buechel@let.ethz.ch> Date: Fri, 31 Jul 2020 14:37:12 +0200 Subject: [PATCH] SEBWIN-405: Implemented draft of mechanism to send pings and logs. --- SafeExamBrowser.Browser/BrowserApplication.cs | 1 + .../IServerProxy.cs | 4 +- SafeExamBrowser.Server/ServerProxy.cs | 105 +++++++++++++++++- 3 files changed, 104 insertions(+), 6 deletions(-) diff --git a/SafeExamBrowser.Browser/BrowserApplication.cs b/SafeExamBrowser.Browser/BrowserApplication.cs index b54e907a..f686ed9f 100644 --- a/SafeExamBrowser.Browser/BrowserApplication.cs +++ b/SafeExamBrowser.Browser/BrowserApplication.cs @@ -315,6 +315,7 @@ namespace SafeExamBrowser.Browser private void StopMonitoringCookies() { timer.Stop(); + timer.Elapsed -= Timer_Elapsed; } private string ToScheme(ProxyProtocol protocol) diff --git a/SafeExamBrowser.Server.Contracts/IServerProxy.cs b/SafeExamBrowser.Server.Contracts/IServerProxy.cs index 6f77539e..fc2986f3 100644 --- a/SafeExamBrowser.Server.Contracts/IServerProxy.cs +++ b/SafeExamBrowser.Server.Contracts/IServerProxy.cs @@ -59,12 +59,12 @@ namespace SafeExamBrowser.Server.Contracts ServerResponse SendSessionIdentifier(string identifier); /// <summary> - /// TODO + /// Starts sending ping and log data to the server. /// </summary> void StartConnectivity(); /// <summary> - /// TODO + /// Stops sending ping and log data to the server. /// </summary> void StopConnectivity(); } diff --git a/SafeExamBrowser.Server/ServerProxy.cs b/SafeExamBrowser.Server/ServerProxy.cs index 2449a847..687e31a7 100644 --- a/SafeExamBrowser.Server/ServerProxy.cs +++ b/SafeExamBrowser.Server/ServerProxy.cs @@ -7,6 +7,7 @@ */ using System; +using System.Collections.Concurrent; using System.Collections.Generic; using System.IO; using System.Linq; @@ -14,6 +15,7 @@ using System.Net.Http; using System.Net.Http.Headers; using System.Text; using System.Threading.Tasks; +using System.Timers; using Newtonsoft.Json; using Newtonsoft.Json.Linq; using SafeExamBrowser.Configuration.Contracts; @@ -21,20 +23,24 @@ using SafeExamBrowser.Logging.Contracts; using SafeExamBrowser.Server.Contracts; using SafeExamBrowser.Server.Contracts.Data; using SafeExamBrowser.Server.Data; +using SafeExamBrowser.Settings.Logging; using SafeExamBrowser.Settings.Server; namespace SafeExamBrowser.Server { - public class ServerProxy : IServerProxy + public class ServerProxy : ILogObserver, IServerProxy { private ApiVersion1 api; + private AppConfig appConfig; private string connectionToken; private string examId; private HttpClient httpClient; - private readonly AppConfig appConfig; private ILogger logger; + private ConcurrentQueue<ILogContent> logContent; private string oauth2Token; + private int pingNumber; private ServerSettings settings; + private Timer timer; public ServerProxy(AppConfig appConfig, ILogger logger) { @@ -42,6 +48,8 @@ namespace SafeExamBrowser.Server this.appConfig = appConfig; this.httpClient = new HttpClient(); this.logger = logger; + this.logContent = new ConcurrentQueue<ILogContent>(); + this.timer = new Timer(); } public ServerResponse Connect() @@ -200,6 +208,11 @@ namespace SafeExamBrowser.Server Initialize(settings); } + public void Notify(ILogContent content) + { + logContent.Enqueue(content); + } + public ServerResponse SendSessionIdentifier(string identifier) { var authorization = ("Authorization", $"Bearer {oauth2Token}"); @@ -224,12 +237,79 @@ namespace SafeExamBrowser.Server public void StartConnectivity() { - // TODO: Start sending logs and pings + foreach (var item in logger.GetLog()) + { + logContent.Enqueue(item); + } + + logger.Subscribe(this); + + timer.AutoReset = false; + timer.Elapsed += Timer_Elapsed; + timer.Interval = 1000; + timer.Start(); } public void StopConnectivity() { - // TODO: Stop sending logs and pings + logger.Unsubscribe(this); + + timer.Stop(); + timer.Elapsed -= Timer_Elapsed; + } + + private void Timer_Elapsed(object sender, ElapsedEventArgs args) + { + var authorization = ("Authorization", $"Bearer {oauth2Token}"); + 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); + + if (success) + { + // 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 + { + for (var count = 0; count < 5; count--) + { + if (logContent.TryDequeue(out var c) && c is ILogMessage message) + { + var json = new JObject + { + ["type"] = ToLogType(message.Severity), + ["timestamp"] = message.DateTime.Ticks, + ["text"] = message.Message + }; + + var content = json.ToString(); + var contentType = "application/json;charset=UTF-8"; + // TODO: Logging these requests spams the application log! + // 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); + } + } + } + catch (Exception e) + { + logger.Error("Failed to send log!", e); + } + + timer.Start(); } private bool TryParseApi(HttpContent content) @@ -443,6 +523,23 @@ namespace SafeExamBrowser.Server return reader.ReadToEnd(); } + private string ToLogType(LogLevel severity) + { + switch (severity) + { + case LogLevel.Debug: + return "DEBUG_LOG"; + case LogLevel.Error: + return "ERROR_LOG"; + case LogLevel.Info: + return "INFO_LOG"; + case LogLevel.Warning: + return "WARN_LOG"; + } + + return "UNKNOWN"; + } + private string ToString(HttpResponseMessage response) { return $"{(int?) response?.StatusCode} {response?.StatusCode} {response?.ReasonPhrase}";