diff --git a/SafeExamBrowser.Client/CompositionRoot.cs b/SafeExamBrowser.Client/CompositionRoot.cs
index 600ce9b0..9557e9b0 100644
--- a/SafeExamBrowser.Client/CompositionRoot.cs
+++ b/SafeExamBrowser.Client/CompositionRoot.cs
@@ -37,6 +37,8 @@ using SafeExamBrowser.Settings.UserInterface;
using SafeExamBrowser.SystemComponents;
using SafeExamBrowser.SystemComponents.Audio;
using SafeExamBrowser.SystemComponents.Contracts;
+using SafeExamBrowser.SystemComponents.Contracts.PowerSupply;
+using SafeExamBrowser.SystemComponents.Contracts.WirelessNetwork;
using SafeExamBrowser.SystemComponents.Keyboard;
using SafeExamBrowser.SystemComponents.PowerSupply;
using SafeExamBrowser.SystemComponents.WirelessNetwork;
@@ -68,12 +70,14 @@ namespace SafeExamBrowser.Client
private ILogger logger;
private IMessageBox messageBox;
private INativeMethods nativeMethods;
+ private IPowerSupply powerSupply;
private IRuntimeProxy runtimeProxy;
private ISystemInfo systemInfo;
private ITaskbar taskbar;
private ITaskview taskview;
private IText text;
private IUserInterfaceFactory uiFactory;
+ private IWirelessAdapter wirelessAdapter;
internal ClientController ClientController { get; private set; }
@@ -89,10 +93,12 @@ namespace SafeExamBrowser.Client
actionCenter = uiFactory.CreateActionCenter();
messageBox = BuildMessageBox();
nativeMethods = new NativeMethods();
+ powerSupply = new PowerSupply(ModuleLogger(nameof(PowerSupply)));
runtimeProxy = new RuntimeProxy(runtimeHostUri, new ProxyObjectFactory(), ModuleLogger(nameof(RuntimeProxy)), Interlocutor.Client);
systemInfo = new SystemInfo();
taskbar = uiFactory.CreateTaskbar(ModuleLogger("Taskbar"));
taskview = uiFactory.CreateTaskview();
+ wirelessAdapter = new WirelessAdapter(ModuleLogger(nameof(WirelessAdapter)));
var processFactory = new ProcessFactory(ModuleLogger(nameof(ProcessFactory)));
var applicationMonitor = new ApplicationMonitor(TWO_SECONDS, ModuleLogger(nameof(ApplicationMonitor)), nativeMethods, processFactory);
@@ -241,7 +247,7 @@ namespace SafeExamBrowser.Client
private IOperation BuildServerOperation()
{
- var server = new ServerProxy(context.AppConfig, ModuleLogger(nameof(ServerProxy)));
+ var server = new ServerProxy(context.AppConfig, ModuleLogger(nameof(ServerProxy)), powerSupply, wirelessAdapter);
var operation = new ServerOperation(actionCenter, context, logger, server, taskbar);
context.Server = server;
@@ -257,8 +263,6 @@ namespace SafeExamBrowser.Client
var keyboard = new Keyboard(ModuleLogger(nameof(Keyboard)));
var logInfo = new LogNotificationInfo(text);
var logController = new LogNotificationController(logger, uiFactory);
- var powerSupply = new PowerSupply(ModuleLogger(nameof(PowerSupply)));
- var wirelessAdapter = new WirelessAdapter(ModuleLogger(nameof(WirelessAdapter)));
var operation = new ShellOperation(
actionCenter,
audio,
diff --git a/SafeExamBrowser.Server/SafeExamBrowser.Server.csproj b/SafeExamBrowser.Server/SafeExamBrowser.Server.csproj
index 22fc33de..00c2b6a8 100644
--- a/SafeExamBrowser.Server/SafeExamBrowser.Server.csproj
+++ b/SafeExamBrowser.Server/SafeExamBrowser.Server.csproj
@@ -79,6 +79,10 @@
{30b2d907-5861-4f39-abad-c4abf1b3470e}
SafeExamBrowser.Settings
+
+ {903129c6-e236-493b-9ad6-c6a57f647a3a}
+ SafeExamBrowser.SystemComponents.Contracts
+
diff --git a/SafeExamBrowser.Server/ServerProxy.cs b/SafeExamBrowser.Server/ServerProxy.cs
index e93a348d..5b89c8f4 100644
--- a/SafeExamBrowser.Server/ServerProxy.cs
+++ b/SafeExamBrowser.Server/ServerProxy.cs
@@ -27,6 +27,8 @@ using SafeExamBrowser.Server.Contracts.Events;
using SafeExamBrowser.Server.Data;
using SafeExamBrowser.Settings.Logging;
using SafeExamBrowser.Settings.Server;
+using SafeExamBrowser.SystemComponents.Contracts.PowerSupply;
+using SafeExamBrowser.SystemComponents.Contracts.WirelessNetwork;
using Timer = System.Timers.Timer;
namespace SafeExamBrowser.Server
@@ -43,21 +45,29 @@ namespace SafeExamBrowser.Server
private ConcurrentQueue logContent;
private string oauth2Token;
private int pingNumber;
+ private IPowerSupply powerSupply;
private ServerSettings settings;
private Task task;
private Timer timer;
+ private IWirelessAdapter wirelessAdapter;
public event TerminationRequestedEventHandler TerminationRequested;
- public ServerProxy(AppConfig appConfig, ILogger logger)
+ public ServerProxy(
+ AppConfig appConfig,
+ ILogger logger,
+ IPowerSupply powerSupply = default(IPowerSupply),
+ IWirelessAdapter wirelessAdapter = default(IWirelessAdapter))
{
this.api = new ApiVersion1();
this.appConfig = appConfig;
this.cancellationTokenSource = new CancellationTokenSource();
this.httpClient = new HttpClient();
- this.logger = logger;
this.logContent = new ConcurrentQueue();
+ this.logger = logger;
+ this.powerSupply = powerSupply;
this.timer = new Timer();
+ this.wirelessAdapter = wirelessAdapter;
}
public ServerResponse Connect()
@@ -252,31 +262,40 @@ namespace SafeExamBrowser.Server
}
logger.Subscribe(this);
-
task = new Task(SendLog, cancellationTokenSource.Token);
task.Start();
-
logger.Info("Started sending log items.");
timer.AutoReset = false;
timer.Elapsed += Timer_Elapsed;
timer.Interval = 1000;
timer.Start();
-
logger.Info("Starting sending pings.");
+
+ if (powerSupply != default(IPowerSupply) && wirelessAdapter != default(IWirelessAdapter))
+ {
+ powerSupply.StatusChanged += PowerSupply_StatusChanged;
+ wirelessAdapter.NetworksChanged += WirelessAdapter_NetworksChanged;
+ logger.Info("Started monitoring system components.");
+ }
}
public void StopConnectivity()
{
+ if (powerSupply != default(IPowerSupply) && wirelessAdapter != default(IWirelessAdapter))
+ {
+ powerSupply.StatusChanged -= PowerSupply_StatusChanged;
+ wirelessAdapter.NetworksChanged -= WirelessAdapter_NetworksChanged;
+ logger.Info("Stopped monitoring system components.");
+ }
+
logger.Unsubscribe(this);
cancellationTokenSource.Cancel();
task?.Wait();
-
logger.Info("Stopped sending log items.");
timer.Stop();
timer.Elapsed -= Timer_Elapsed;
-
logger.Info("Stopped sending pings.");
}
@@ -299,7 +318,8 @@ namespace SafeExamBrowser.Server
["text"] = message.Message
};
var content = json.ToString();
- var success = TryExecute(HttpMethod.Post, api.LogEndpoint, out var response, content, contentType, authorization, token);
+
+ TryExecute(HttpMethod.Post, api.LogEndpoint, out var response, content, contentType, authorization, token);
}
}
catch (Exception e)
@@ -309,6 +329,32 @@ namespace SafeExamBrowser.Server
}
}
+ private void PowerSupply_StatusChanged(IPowerSupplyStatus status)
+ {
+ try
+ {
+ var authorization = ("Authorization", $"Bearer {oauth2Token}");
+ var chargeInfo = $"{status.BatteryChargeStatus} at {Convert.ToInt32(status.BatteryCharge * 100)}%";
+ var contentType = "application/json;charset=UTF-8";
+ var gridInfo = $"{(status.IsOnline ? "connected to" : "disconnected from")} the power grid";
+ var token = ("SEBConnectionToken", connectionToken);
+ var json = new JObject
+ {
+ ["type"] = ToLogType(LogLevel.Info),
+ ["timestamp"] = ToUnixTimestamp(DateTime.Now),
+ ["text"] = $" {chargeInfo}, {status.BatteryTimeRemaining} remaining, {gridInfo}",
+ ["numericValue"] = Convert.ToInt32(status.BatteryCharge * 100)
+ };
+ var content = json.ToString();
+
+ TryExecute(HttpMethod.Post, api.LogEndpoint, out var response, content, contentType, authorization, token);
+ }
+ catch (Exception e)
+ {
+ logger.Error("Failed to send power supply status!", e);
+ }
+ }
+
private void Timer_Elapsed(object sender, ElapsedEventArgs args)
{
try
@@ -344,6 +390,34 @@ namespace SafeExamBrowser.Server
timer.Start();
}
+ private void WirelessAdapter_NetworksChanged()
+ {
+ try
+ {
+ var authorization = ("Authorization", $"Bearer {oauth2Token}");
+ var contentType = "application/json;charset=UTF-8";
+ var network = wirelessAdapter.GetNetworks().FirstOrDefault(n => n.Status == WirelessNetworkStatus.Connected);
+ var token = ("SEBConnectionToken", connectionToken);
+ var json = new JObject { ["type"] = ToLogType(LogLevel.Info), ["timestamp"] = ToUnixTimestamp(DateTime.Now) };
+
+ if (network != default(IWirelessNetwork))
+ {
+ json["text"] = $" {network.Name}: {network.Status}, {network.SignalStrength}%";
+ json["numericValue"] = network.SignalStrength;
+ }
+ else
+ {
+ json["text"] = " not connected";
+ }
+
+ TryExecute(HttpMethod.Post, api.LogEndpoint, out var response, json.ToString(), contentType, authorization, token);
+ }
+ catch (Exception e)
+ {
+ logger.Error("Failed to send wireless status!", e);
+ }
+ }
+
private bool TryParseApi(HttpContent content)
{
var success = false;
@@ -384,7 +458,7 @@ namespace SafeExamBrowser.Server
success = true;
}
-
+
if (!success)
{
logger.Error("The selected SEB server instance does not support the required API version!");