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);
///
- /// TODO
+ /// Starts sending ping and log data to the server.
///
void StartConnectivity();
///
- /// TODO
+ /// Stops sending ping and log data to the server.
///
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 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();
+ 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}";