diff --git a/src/PepperDash.Essentials.MobileControl/MessageToClients.cs b/src/PepperDash.Essentials.MobileControl/MessageToClients.cs
new file mode 100644
index 00000000..e1aa5eb5
--- /dev/null
+++ b/src/PepperDash.Essentials.MobileControl/MessageToClients.cs
@@ -0,0 +1,90 @@
+using System;
+using System.Threading;
+using Newtonsoft.Json;
+using Newtonsoft.Json.Converters;
+using PepperDash.Core;
+using PepperDash.Core.Logging;
+using PepperDash.Essentials.AppServer.Messengers;
+using PepperDash.Essentials.Core.Queues;
+using PepperDash.Essentials.WebSocketServer;
+using Serilog.Events;
+
+namespace PepperDash.Essentials
+{
+ ///
+ /// Represents a MessageToClients
+ ///
+ public class MessageToClients : IQueueMessage
+ {
+ private readonly MobileControlWebsocketServer _server;
+ private readonly object msgToSend;
+
+ ///
+ /// Message to send to Direct Server Clients
+ ///
+ /// message object to send
+ /// WebSocket server instance
+ public MessageToClients(object msg, MobileControlWebsocketServer server)
+ {
+ _server = server;
+ msgToSend = msg;
+ }
+
+ ///
+ /// Message to send to Direct Server Clients
+ ///
+ /// message object to send
+ /// WebSocket server instance
+ public MessageToClients(DeviceStateMessageBase msg, MobileControlWebsocketServer server)
+ {
+ _server = server;
+ msgToSend = msg;
+ }
+
+ #region Implementation of IQueueMessage
+
+ ///
+ /// Dispatch method
+ ///
+ public void Dispatch()
+ {
+ try
+ {
+ if (_server == null)
+ {
+ Debug.LogMessage(LogEventLevel.Warning, "Cannot send message. Server is null");
+ return;
+ }
+
+ var message = JsonConvert.SerializeObject(msgToSend, Formatting.None,
+ new JsonSerializerSettings { NullValueHandling = NullValueHandling.Ignore, Converters = { new IsoDateTimeConverter() } });
+
+ var clientSpecificMessage = msgToSend as MobileControlMessage;
+ if (clientSpecificMessage.ClientId != null)
+ {
+ var clientId = clientSpecificMessage.ClientId;
+
+ _server.LogVerbose("Message TX To client {clientId}: {message}", clientId, message);
+
+ _server.SendMessageToClient(clientId, message);
+
+ return;
+ }
+
+ _server.SendMessageToAllClients(message);
+
+ _server.LogVerbose("Message TX To all clients: {message}", message);
+ }
+ catch (ThreadAbortException)
+ {
+ //Swallowing this exception, as it occurs on shutdown and there's no need to print out a scary stack trace
+ }
+ catch (Exception ex)
+ {
+ Debug.LogMessage(ex, "Caught an exception in the Transmit Processor");
+ }
+ }
+ #endregion
+ }
+
+}
\ No newline at end of file
diff --git a/src/PepperDash.Essentials.MobileControl/MobileControlSystemController.cs b/src/PepperDash.Essentials.MobileControl/MobileControlSystemController.cs
index d6a40ede..0b320185 100644
--- a/src/PepperDash.Essentials.MobileControl/MobileControlSystemController.cs
+++ b/src/PepperDash.Essentials.MobileControl/MobileControlSystemController.cs
@@ -1382,33 +1382,13 @@ namespace PepperDash.Essentials
{
Log =
{
- Output = (data, message) =>
- {
- switch (data.Level)
- {
- case LogLevel.Trace:
- this.LogVerbose(data.Message);
- break;
- case LogLevel.Debug:
- this.LogDebug(data.Message);
- break;
- case LogLevel.Info:
- this.LogInformation(data.Message);
- break;
- case LogLevel.Warn:
- this.LogWarning(data.Message);
- break;
- case LogLevel.Error:
- this.LogError(data.Message);
- break;
- case LogLevel.Fatal:
- this.LogFatal(data.Message);
- break;
- }
- }
+ Output = (data, message) => Utilities.ConvertWebsocketLog(data, message, this)
}
};
+ // setting to trace to let level be controlled by appdebug
+ _wsClient2.Log.Level = LogLevel.Trace;
+
_wsClient2.SslConfiguration.EnabledSslProtocols =
System.Security.Authentication.SslProtocols.Tls11
| System.Security.Authentication.SslProtocols.Tls12;
diff --git a/src/PepperDash.Essentials.MobileControl/TransmitMessage.cs b/src/PepperDash.Essentials.MobileControl/TransmitMessage.cs
index 38f7944f..06595a9d 100644
--- a/src/PepperDash.Essentials.MobileControl/TransmitMessage.cs
+++ b/src/PepperDash.Essentials.MobileControl/TransmitMessage.cs
@@ -1,13 +1,9 @@
-using Newtonsoft.Json;
+using System;
+using Newtonsoft.Json;
using Newtonsoft.Json.Converters;
using PepperDash.Core;
-using PepperDash.Core.Logging;
using PepperDash.Essentials.AppServer.Messengers;
using PepperDash.Essentials.Core.Queues;
-using PepperDash.Essentials.WebSocketServer;
-using Serilog.Events;
-using System;
-using System.Threading;
using WebSocketSharp;
namespace PepperDash.Essentials
@@ -20,12 +16,22 @@ namespace PepperDash.Essentials
private readonly WebSocket _ws;
private readonly object msgToSend;
+ ///
+ /// Initialize a message to send
+ ///
+ /// message object to send
+ /// WebSocket instance
public TransmitMessage(object msg, WebSocket ws)
{
_ws = ws;
msgToSend = msg;
}
+ ///
+ /// Initialize a message to send
+ ///
+ /// message object to send
+ /// WebSocket instance
public TransmitMessage(DeviceStateMessageBase msg, WebSocket ws)
{
_ws = ws;
@@ -43,13 +49,13 @@ namespace PepperDash.Essentials
{
if (_ws == null)
{
- Debug.LogMessage(LogEventLevel.Warning, "Cannot send message. Websocket client is null");
+ Debug.LogWarning("Cannot send message. Websocket client is null");
return;
}
if (!_ws.IsAlive)
{
- Debug.LogMessage(LogEventLevel.Warning, "Cannot send message. Websocket client is not connected");
+ Debug.LogWarning("Cannot send message. Websocket client is not connected");
return;
}
@@ -57,83 +63,14 @@ namespace PepperDash.Essentials
var message = JsonConvert.SerializeObject(msgToSend, Formatting.None,
new JsonSerializerSettings { NullValueHandling = NullValueHandling.Ignore, Converters = { new IsoDateTimeConverter() } });
- Debug.LogMessage(LogEventLevel.Verbose, "Message TX: {0}", null, message);
+ Debug.LogVerbose("Message TX: {0}", message);
_ws.Send(message);
-
-
}
catch (Exception ex)
{
- Debug.LogMessage(ex, "Caught an exception in the Transmit Processor");
- }
- }
- #endregion
- }
-
-
-
- ///
- /// Represents a MessageToClients
- ///
- public class MessageToClients : IQueueMessage
- {
- private readonly MobileControlWebsocketServer _server;
- private readonly object msgToSend;
-
- public MessageToClients(object msg, MobileControlWebsocketServer server)
- {
- _server = server;
- msgToSend = msg;
- }
-
- public MessageToClients(DeviceStateMessageBase msg, MobileControlWebsocketServer server)
- {
- _server = server;
- msgToSend = msg;
- }
-
- #region Implementation of IQueueMessage
-
- ///
- /// Dispatch method
- ///
- public void Dispatch()
- {
- try
- {
- if (_server == null)
- {
- Debug.LogMessage(LogEventLevel.Warning, "Cannot send message. Server is null");
- return;
- }
-
- var message = JsonConvert.SerializeObject(msgToSend, Formatting.None,
- new JsonSerializerSettings { NullValueHandling = NullValueHandling.Ignore, Converters = { new IsoDateTimeConverter() } });
-
- var clientSpecificMessage = msgToSend as MobileControlMessage;
- if (clientSpecificMessage.ClientId != null)
- {
- var clientId = clientSpecificMessage.ClientId;
-
- _server.LogVerbose("Message TX To client {clientId} Message: {message}", clientId, message);
-
- _server.SendMessageToClient(clientId, message);
-
- return;
- }
-
- _server.SendMessageToAllClients(message);
-
- _server.LogVerbose("Message TX To all clients: {message}", message);
- }
- catch (ThreadAbortException)
- {
- //Swallowing this exception, as it occurs on shutdown and there's no need to print out a scary stack trace
- }
- catch (Exception ex)
- {
- Debug.LogMessage(ex, "Caught an exception in the Transmit Processor");
+ Debug.LogError("Caught an exception in the Transmit Processor: {message}", ex.Message);
+ Debug.LogDebug(ex, "Stack Trace: ");
}
}
#endregion
diff --git a/src/PepperDash.Essentials.MobileControl/Utilities.cs b/src/PepperDash.Essentials.MobileControl/Utilities.cs
new file mode 100644
index 00000000..83ebc5bc
--- /dev/null
+++ b/src/PepperDash.Essentials.MobileControl/Utilities.cs
@@ -0,0 +1,97 @@
+using PepperDash.Core;
+using PepperDash.Core.Logging;
+using WebSocketSharp;
+
+namespace PepperDash.Essentials
+{
+ ///
+ /// Utility functions for logging and other common tasks.
+ ///
+ public static class Utilities
+ {
+ private static int nextClientId = 0;
+
+ ///
+ /// Get
+ ///
+ ///
+ public static int GetNextClientId()
+ {
+ nextClientId++;
+ return nextClientId;
+ }
+ ///
+ /// Converts a WebSocketServer LogData object to Essentials logging calls.
+ ///
+ /// The LogData object to convert.
+ /// The log message.
+ /// The device associated with the log message.
+ public static void ConvertWebsocketLog(LogData data, string message, IKeyed device = null)
+ {
+
+ switch (data.Level)
+ {
+ case LogLevel.Trace:
+ if (device == null)
+ {
+ Debug.LogVerbose(message);
+ }
+ else
+ {
+ device.LogVerbose(message);
+ }
+ break;
+ case LogLevel.Debug:
+ if (device == null)
+ {
+ Debug.LogDebug(message);
+ }
+ else
+ {
+ device.LogDebug(message);
+ }
+ break;
+ case LogLevel.Info:
+ if (device == null)
+ {
+ Debug.LogInformation(message);
+ }
+ else
+ {
+ device.LogInformation(message);
+ }
+ break;
+ case LogLevel.Warn:
+ if (device == null)
+ {
+ Debug.LogWarning(message);
+ }
+ else
+ {
+ device.LogWarning(message);
+ }
+ break;
+ case LogLevel.Error:
+ if (device == null)
+ {
+ Debug.LogError(message);
+ }
+ else
+ {
+ device.LogError(message);
+ }
+ break;
+ case LogLevel.Fatal:
+ if (device == null)
+ {
+ Debug.LogFatal(message);
+ }
+ else
+ {
+ device.LogFatal(message);
+ }
+ break;
+ }
+ }
+ }
+}
diff --git a/src/PepperDash.Essentials.MobileControl/WebApiHandlers/MobileInfoHandler.cs b/src/PepperDash.Essentials.MobileControl/WebApiHandlers/MobileInfoHandler.cs
index d123dbcd..588d3861 100644
--- a/src/PepperDash.Essentials.MobileControl/WebApiHandlers/MobileInfoHandler.cs
+++ b/src/PepperDash.Essentials.MobileControl/WebApiHandlers/MobileInfoHandler.cs
@@ -1,12 +1,12 @@
-using Crestron.SimplSharp.WebScripting;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using Crestron.SimplSharp.WebScripting;
using Newtonsoft.Json;
using PepperDash.Core;
using PepperDash.Core.Web.RequestHandlers;
using PepperDash.Essentials.Core.Config;
using PepperDash.Essentials.WebSocketServer;
-using System;
-using System.Collections.Generic;
-using System.Linq;
namespace PepperDash.Essentials.WebApiHandlers
{
@@ -111,13 +111,13 @@ namespace PepperDash.Essentials.WebApiHandlers
public int ServerPort => directServer.Port;
[JsonProperty("tokensDefined")]
- public int TokensDefined => directServer.UiClients.Count;
+ public int TokensDefined => directServer.UiClientContexts.Count;
[JsonProperty("clientsConnected")]
public int ClientsConnected => directServer.ConnectedUiClientsCount;
[JsonProperty("clients")]
- public List Clients => directServer.UiClients.Select((c, i) => { return new MobileControlDirectClient(c, i, directServer.UserAppUrlPrefix); }).ToList();
+ public List Clients => directServer.UiClientContexts.Select((c, i) => { return new MobileControlDirectClient(c, i, directServer.UserAppUrlPrefix); }).ToList();
public MobileControlDirectServer(MobileControlWebsocketServer server)
{
diff --git a/src/PepperDash.Essentials.MobileControl/WebApiHandlers/UiClientHandler.cs b/src/PepperDash.Essentials.MobileControl/WebApiHandlers/UiClientHandler.cs
index e45fcc39..23b79d93 100644
--- a/src/PepperDash.Essentials.MobileControl/WebApiHandlers/UiClientHandler.cs
+++ b/src/PepperDash.Essentials.MobileControl/WebApiHandlers/UiClientHandler.cs
@@ -93,7 +93,7 @@ namespace PepperDash.Essentials.WebApiHandlers
- if (!server.UiClients.TryGetValue(request.Token, out UiClientContext clientContext))
+ if (!server.UiClientContexts.TryGetValue(request.Token, out UiClientContext clientContext))
{
var response = new ClientResponse
{
@@ -134,7 +134,7 @@ namespace PepperDash.Essentials.WebApiHandlers
return;
}
- server.UiClients.Remove(request.Token);
+ server.UiClientContexts.Remove(request.Token);
server.UpdateSecret();
diff --git a/src/PepperDash.Essentials.MobileControl/WebSocketServer/ConnectionClosedEventArgs.cs b/src/PepperDash.Essentials.MobileControl/WebSocketServer/ConnectionClosedEventArgs.cs
new file mode 100644
index 00000000..6d877d07
--- /dev/null
+++ b/src/PepperDash.Essentials.MobileControl/WebSocketServer/ConnectionClosedEventArgs.cs
@@ -0,0 +1,24 @@
+using System;
+
+namespace PepperDash.Essentials.WebSocketServer
+{
+ ///
+ /// Event Args for ConnectionClosed event
+ ///
+ public class ConnectionClosedEventArgs : EventArgs
+ {
+ ///
+ /// Client ID that is being closed
+ ///
+ public string ClientId { get; private set; }
+
+ ///
+ /// Initalize an instance of the class.
+ ///
+ /// client that's closing
+ public ConnectionClosedEventArgs(string clientId)
+ {
+ ClientId = clientId;
+ }
+ }
+}
diff --git a/src/PepperDash.Essentials.MobileControl/WebSocketServer/JoinToken.cs b/src/PepperDash.Essentials.MobileControl/WebSocketServer/JoinToken.cs
index b3ea3c7c..7352dc6f 100644
--- a/src/PepperDash.Essentials.MobileControl/WebSocketServer/JoinToken.cs
+++ b/src/PepperDash.Essentials.MobileControl/WebSocketServer/JoinToken.cs
@@ -5,6 +5,10 @@ namespace PepperDash.Essentials.WebSocketServer
///
public class JoinToken
{
+ ///
+ /// Unique client ID for a client that is joining
+ ///
+ public string Id { get; set; }
///
/// Gets or sets the Code
///
diff --git a/src/PepperDash.Essentials.MobileControl/WebSocketServer/MobileControlWebsocketServer.cs b/src/PepperDash.Essentials.MobileControl/WebSocketServer/MobileControlWebsocketServer.cs
index d15185b0..0b0390aa 100644
--- a/src/PepperDash.Essentials.MobileControl/WebSocketServer/MobileControlWebsocketServer.cs
+++ b/src/PepperDash.Essentials.MobileControl/WebSocketServer/MobileControlWebsocketServer.cs
@@ -10,6 +10,7 @@ using System.Text;
using Crestron.SimplSharp;
using Crestron.SimplSharp.WebScripting;
using Newtonsoft.Json;
+using Org.BouncyCastle.Crypto.Prng;
using PepperDash.Core;
using PepperDash.Core.Logging;
using PepperDash.Essentials.Core;
@@ -56,7 +57,9 @@ namespace PepperDash.Essentials.WebSocketServer
///
/// Gets the collection of UI client contexts
///
- public Dictionary UiClients { get; private set; }
+ public Dictionary UiClientContexts { get; private set; }
+
+ private readonly Dictionary uiClients = new Dictionary();
private readonly MobileControlSystemController _parent;
@@ -129,7 +132,7 @@ namespace PepperDash.Essentials.WebSocketServer
{
var count = 0;
- foreach (var client in UiClients)
+ foreach (var client in UiClientContexts)
{
if (client.Value.Client != null && client.Value.Client.Context.WebSocket.IsAlive)
{
@@ -202,7 +205,7 @@ namespace PepperDash.Essentials.WebSocketServer
}
- UiClients = new Dictionary();
+ UiClientContexts = new Dictionary();
//_joinTokens = new Dictionary();
@@ -278,29 +281,20 @@ namespace PepperDash.Essentials.WebSocketServer
}
_server.Log.Output = (data, message) =>
+ {
+ switch (data.Level)
{
- switch (data.Level)
- {
- case LogLevel.Trace:
- this.LogVerbose(data.Message);
- break;
- case LogLevel.Debug:
- this.LogDebug(data.Message);
- break;
- case LogLevel.Info:
- this.LogInformation(data.Message);
- break;
- case LogLevel.Warn:
- this.LogWarning(data.Message);
- break;
- case LogLevel.Error:
- this.LogError(data.Message);
- break;
- case LogLevel.Fatal:
- this.LogFatal(data.Message);
- break;
- }
- };
+ case LogLevel.Trace: this.LogVerbose(message); break;
+ case LogLevel.Debug: this.LogDebug(message); break;
+ case LogLevel.Info: this.LogInformation(message); break;
+ case LogLevel.Warn: this.LogWarning(message); break;
+ case LogLevel.Error: this.LogError(message); break;
+ case LogLevel.Fatal: this.LogFatal(message); break;
+ }
+ };
+
+ // setting to trace to allow logging level to be controlled by appdebug
+ _server.Log.Level = LogLevel.Trace;
CrestronEnvironment.ProgramStatusEventHandler += CrestronEnvironment_ProgramStatusEventHandler;
@@ -554,20 +548,20 @@ namespace PepperDash.Essentials.WebSocketServer
this.LogInformation("Adding token: {key} for room: {roomKey}", token.Key, token.Value.RoomKey);
- if (UiClients == null)
+ if (UiClientContexts == null)
{
- UiClients = new Dictionary();
+ UiClientContexts = new Dictionary();
}
- UiClients.Add(token.Key, new UiClientContext(token.Value));
+ UiClientContexts.Add(token.Key, new UiClientContext(token.Value));
}
}
- if (UiClients.Count > 0)
+ if (UiClientContexts.Count > 0)
{
- this.LogInformation("Restored {uiClientCount} UiClients from secrets data", UiClients.Count);
+ this.LogInformation("Restored {uiClientCount} UiClients from secrets data", UiClientContexts.Count);
- foreach (var client in UiClients)
+ foreach (var client in UiClientContexts)
{
var key = client.Key;
var path = _wsPath + key;
@@ -575,13 +569,8 @@ namespace PepperDash.Essentials.WebSocketServer
_server.AddWebSocketService(path, () =>
{
- var c = new UiClient($"uiclient-{key}-{roomKey}");
- this.LogDebug("Constructing UiClient with id: {key}", key);
-
- c.Controller = _parent;
- c.RoomKey = roomKey;
- UiClients[key].SetClient(c);
- return c;
+ this.LogInformation("Building a UiClient with ID {id}", client.Value.Token.Id);
+ return BuildUiClient(roomKey, client.Value.Token, key);
});
}
}
@@ -591,7 +580,7 @@ namespace PepperDash.Essentials.WebSocketServer
this.LogWarning("No secret found");
}
- this.LogDebug("{uiClientCount} UiClients restored from secrets data", UiClients.Count);
+ this.LogDebug("{uiClientCount} UiClients restored from secrets data", UiClientContexts.Count);
}
catch (Exception ex)
{
@@ -616,7 +605,7 @@ namespace PepperDash.Essentials.WebSocketServer
_secret.Tokens.Clear();
- foreach (var uiClientContext in UiClients)
+ foreach (var uiClientContext in UiClientContexts)
{
_secret.Tokens.Add(uiClientContext.Key, uiClientContext.Value.Token);
}
@@ -725,21 +714,17 @@ namespace PepperDash.Essentials.WebSocketServer
var token = new JoinToken { Code = bridge.UserCode, RoomKey = bridge.RoomKey, Uuid = _parent.SystemUuid, TouchpanelKey = touchPanelKey };
- UiClients.Add(key, new UiClientContext(token));
+ UiClientContexts.Add(key, new UiClientContext(token));
var path = _wsPath + key;
_server.AddWebSocketService(path, () =>
{
- var c = new UiClient($"uiclient-{key}-{bridge.RoomKey}");
- this.LogVerbose("Constructing UiClient with id: {key}", key);
- c.Controller = _parent;
- c.RoomKey = bridge.RoomKey;
- UiClients[key].SetClient(c);
- return c;
+ this.LogInformation("Building a UiClient with ID {id}", token.Id);
+ return BuildUiClient(bridge.RoomKey, token, key);
});
- this.LogInformation("Added new WebSocket UiClient service at path: {path}", path);
+ this.LogInformation("Added new WebSocket UiClient for path: {path}", path);
this.LogInformation("Token: {@token}", token);
this.LogVerbose("{serviceCount} websocket services present", _server.WebSocketServices.Count);
@@ -749,6 +734,44 @@ namespace PepperDash.Essentials.WebSocketServer
return (key, path);
}
+ private UiClient BuildUiClient(string roomKey, JoinToken token, string key)
+ {
+ var c = new UiClient($"uiclient-{key}-{roomKey}-{token.Id}", token.Id);
+ this.LogInformation("Constructing UiClient with key {key} and ID {id}", key, token.Id);
+ c.Controller = _parent;
+ c.RoomKey = roomKey;
+
+ if (uiClients.ContainsKey(token.Id))
+ {
+ this.LogWarning("removing client with duplicate id {id}", token.Id);
+ uiClients.Remove(token.Id);
+ }
+ uiClients.Add(token.Id, c);
+ // UiClients[key].SetClient(c);
+ c.ConnectionClosed += (o, a) => uiClients.Remove(a.ClientId);
+ token.Id = null;
+ return c;
+ }
+
+ ///
+ /// Prints out the session data for each path
+ ///
+ public void PrintSessionData()
+ {
+ foreach (var path in _server.WebSocketServices.Paths)
+ {
+ this.LogInformation("Path: {path}", path);
+ this.LogInformation(" Session Count: {sessionCount}", _server.WebSocketServices[path].Sessions.Count);
+ this.LogInformation(" Active Session Count: {activeSessionCount}", _server.WebSocketServices[path].Sessions.ActiveIDs.Count());
+ this.LogInformation(" Inactive Session Count: {inactiveSessionCount}", _server.WebSocketServices[path].Sessions.InactiveIDs.Count());
+ this.LogInformation(" Active Clients:");
+ foreach (var session in _server.WebSocketServices[path].Sessions.IDs)
+ {
+ this.LogInformation(" Client ID: {id}", (_server.WebSocketServices[path].Sessions[session] as UiClient)?.Id);
+ }
+ }
+ }
+
///
/// Removes all clients from the server
///
@@ -766,7 +789,7 @@ namespace PepperDash.Essentials.WebSocketServer
return;
}
- foreach (var client in UiClients)
+ foreach (var client in UiClientContexts)
{
if (client.Value.Client != null && client.Value.Client.Context.WebSocket.IsAlive)
{
@@ -784,7 +807,7 @@ namespace PepperDash.Essentials.WebSocketServer
}
}
- UiClients.Clear();
+ UiClientContexts.Clear();
UpdateSecret();
}
@@ -803,9 +826,9 @@ namespace PepperDash.Essentials.WebSocketServer
var key = s;
- if (UiClients.ContainsKey(key))
+ if (UiClientContexts.ContainsKey(key))
{
- var uiClientContext = UiClients[key];
+ var uiClientContext = UiClientContexts[key];
if (uiClientContext.Client != null && uiClientContext.Client.Context.WebSocket.IsAlive)
{
@@ -815,7 +838,7 @@ namespace PepperDash.Essentials.WebSocketServer
var path = _wsPath + key;
if (_server.RemoveWebSocketService(path))
{
- UiClients.Remove(key);
+ UiClientContexts.Remove(key);
UpdateSecret();
@@ -839,9 +862,9 @@ namespace PepperDash.Essentials.WebSocketServer
{
CrestronConsole.ConsoleCommandResponse("Mobile Control UI Client Info:\r");
- CrestronConsole.ConsoleCommandResponse(string.Format("{0} clients found:\r", UiClients.Count));
+ CrestronConsole.ConsoleCommandResponse(string.Format("{0} clients found:\r", UiClientContexts.Count));
- foreach (var client in UiClients)
+ foreach (var client in UiClientContexts)
{
CrestronConsole.ConsoleCommandResponse(string.Format("RoomKey: {0} Token: {1}\r", client.Value.Token.RoomKey, client.Key));
}
@@ -851,7 +874,7 @@ namespace PepperDash.Essentials.WebSocketServer
{
if (programEventType == eProgramStatusEventType.Stopping)
{
- foreach (var client in UiClients.Values)
+ foreach (var client in UiClientContexts.Values)
{
if (client.Client != null && client.Client.Context.WebSocket.IsAlive)
{
@@ -990,77 +1013,81 @@ namespace PepperDash.Essentials.WebSocketServer
this.LogVerbose("Join Room Request with token: {token}", token);
+ byte[] body;
- if (UiClients.TryGetValue(token, out UiClientContext clientContext))
- {
- var bridge = _parent.GetRoomBridge(clientContext.Token.RoomKey);
-
- if (bridge != null)
- {
- res.StatusCode = 200;
- res.ContentType = "application/json";
-
- var devices = DeviceManager.GetDevices();
- Dictionary deviceInterfaces = new Dictionary();
-
- foreach (var device in devices)
- {
- var interfaces = device?.GetType().GetInterfaces().Select((i) => i.Name).ToList() ?? new List();
- deviceInterfaces.Add(device.Key, new DeviceInterfaceInfo
- {
- Key = device.Key,
- Name = device is IKeyName ? (device as IKeyName).Name : "",
- Interfaces = interfaces
- });
- }
-
- // Construct the response object
- JoinResponse jRes = new JoinResponse
- {
- ClientId = token,
- RoomKey = bridge.RoomKey,
- SystemUuid = _parent.SystemUuid,
- RoomUuid = _parent.SystemUuid,
- Config = _parent.GetConfigWithPluginVersion(),
- CodeExpires = new DateTime().AddYears(1),
- UserCode = bridge.UserCode,
- UserAppUrl = string.Format("http://{0}:{1}/mc/app",
- CrestronEthernetHelper.GetEthernetParameter(CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_CURRENT_IP_ADDRESS, 0),
- Port),
- EnableDebug = false,
- DeviceInterfaceSupport = deviceInterfaces
- };
-
- // Serialize to JSON and convert to Byte[]
- var json = JsonConvert.SerializeObject(jRes);
- var body = Encoding.UTF8.GetBytes(json);
- res.ContentLength64 = body.LongLength;
-
- // Send the response
- res.Close(body, true);
- }
- else
- {
- var message = string.Format("Unable to find bridge with key: {0}", clientContext.Token.RoomKey);
- res.StatusCode = 404;
- res.ContentType = "application/json";
- this.LogVerbose("{message}", message);
- var body = Encoding.UTF8.GetBytes(message);
- res.ContentLength64 = body.LongLength;
- res.Close(body, true);
-
- }
- }
- else
+ if (!UiClientContexts.TryGetValue(token, out UiClientContext clientContext))
{
var message = "Token invalid or has expired";
res.StatusCode = 401;
res.ContentType = "application/json";
this.LogVerbose("{message}", message);
- var body = Encoding.UTF8.GetBytes(message);
+ body = Encoding.UTF8.GetBytes(message);
res.ContentLength64 = body.LongLength;
res.Close(body, true);
+ return;
}
+
+ var bridge = _parent.GetRoomBridge(clientContext.Token.RoomKey);
+
+ if (bridge == null)
+ {
+ var message = string.Format("Unable to find bridge with key: {0}", clientContext.Token.RoomKey);
+ res.StatusCode = 404;
+ res.ContentType = "application/json";
+ this.LogVerbose("{message}", message);
+ body = Encoding.UTF8.GetBytes(message);
+ res.ContentLength64 = body.LongLength;
+ res.Close(body, true);
+ return;
+ }
+
+ res.StatusCode = 200;
+ res.ContentType = "application/json";
+
+ var devices = DeviceManager.GetDevices();
+ Dictionary deviceInterfaces = new Dictionary();
+
+ foreach (var device in devices)
+ {
+ var interfaces = device?.GetType().GetInterfaces().Select((i) => i.Name).ToList() ?? new List();
+
+ deviceInterfaces.Add(device.Key, new DeviceInterfaceInfo
+ {
+ Key = device.Key,
+ Name = (device as IKeyName)?.Name ?? "",
+ Interfaces = interfaces
+ });
+ }
+
+ var clientId = $"{Utilities.GetNextClientId()}";
+ clientContext.Token.Id = clientId;
+
+ this.LogVerbose("Assigning ClientId: {clientId}", clientId);
+
+ // Construct the response object
+ JoinResponse jRes = new JoinResponse
+ {
+ ClientId = clientId,
+ RoomKey = bridge.RoomKey,
+ SystemUuid = _parent.SystemUuid,
+ RoomUuid = _parent.SystemUuid,
+ Config = _parent.GetConfigWithPluginVersion(),
+ CodeExpires = new DateTime().AddYears(1),
+ UserCode = bridge.UserCode,
+ UserAppUrl = string.Format("http://{0}:{1}/mc/app",
+ CrestronEthernetHelper.GetEthernetParameter(CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_CURRENT_IP_ADDRESS, 0),
+ Port),
+ EnableDebug = false,
+ DeviceInterfaceSupport = deviceInterfaces
+ };
+
+ // Serialize to JSON and convert to Byte[]
+ var json = JsonConvert.SerializeObject(jRes);
+ body = Encoding.UTF8.GetBytes(json);
+ res.ContentLength64 = body.LongLength;
+
+ // Send the response
+ res.Close(body, true);
}
///
@@ -1242,12 +1269,14 @@ namespace PepperDash.Essentials.WebSocketServer
///
public void SendMessageToAllClients(string message)
{
- foreach (var clientContext in UiClients.Values)
+ foreach (var client in uiClients.Values)
{
- if (clientContext.Client != null && clientContext.Client.Context.WebSocket.IsAlive)
+ if (!client.Context.WebSocket.IsAlive)
{
- clientContext.Client.Context.WebSocket.Send(message);
+ continue;
}
+
+ client.Context.WebSocket.Send(message);
}
}
@@ -1266,17 +1295,16 @@ namespace PepperDash.Essentials.WebSocketServer
return;
}
- if (UiClients.TryGetValue((string)clientId, out UiClientContext clientContext))
+ if (uiClients.TryGetValue((string)clientId, out var client))
{
- if (clientContext.Client != null)
- {
- var socket = clientContext.Client.Context.WebSocket;
+ var socket = client.Context.WebSocket;
- if (socket.IsAlive)
- {
- socket.Send(message);
- }
+ if (!socket.IsAlive)
+ {
+ this.LogError("Unable to send message to client {id}. Client is disconnected: {message}", clientId, message);
+ return;
}
+ socket.Send(message);
}
else
{
diff --git a/src/PepperDash.Essentials.MobileControl/WebSocketServer/UiClient.cs b/src/PepperDash.Essentials.MobileControl/WebSocketServer/UiClient.cs
index 3cdd183b..79becd33 100644
--- a/src/PepperDash.Essentials.MobileControl/WebSocketServer/UiClient.cs
+++ b/src/PepperDash.Essentials.MobileControl/WebSocketServer/UiClient.cs
@@ -64,9 +64,11 @@ namespace PepperDash.Essentials.WebSocketServer
/// Initializes a new instance of the UiClient class with the specified key
///
/// The unique key to identify this client
- public UiClient(string key)
+ /// The client ID used by the client for this connection
+ public UiClient(string key, string id)
{
Key = key;
+ Id = id;
}
///
@@ -74,19 +76,33 @@ namespace PepperDash.Essentials.WebSocketServer
{
base.OnOpen();
- var url = Context.WebSocket.Url;
- this.LogInformation("New WebSocket Connection from: {url}", url);
+ Log.Output = (data, message) => Utilities.ConvertWebsocketLog(data, message);
+ Log.Level = LogLevel.Trace;
- var match = Regex.Match(url.AbsoluteUri, "(?:ws|wss):\\/\\/.*(?:\\/mc\\/api\\/ui\\/join\\/)(.*)");
-
- if (!match.Success)
+ try
{
- _connectionTime = DateTime.Now;
- return;
+ this.LogDebug("Current session count on open {count}", Sessions.Count);
+ this.LogDebug("Current WebsocketServiceCount on open: {count}", Controller.DirectServer.WebsocketServiceCount);
+ }
+ catch (Exception ex)
+ {
+ this.LogError("Error getting service count: {message}", ex.Message);
+ this.LogDebug(ex, "Stack Trace: ");
}
- var clientId = match.Groups[1].Value;
- _clientId = clientId;
+ // var url = Context.WebSocket.Url;
+ // this.LogInformation("New WebSocket Connection from: {url}", url);
+
+ // var match = Regex.Match(url.AbsoluteUri, "(?:ws|wss):\\/\\/.*(?:\\/mc\\/api\\/ui\\/join\\/)(.*)");
+
+ // if (!match.Success)
+ // {
+ // _connectionTime = DateTime.Now;
+ // return;
+ // }
+
+ // var clientId = match.Groups[1].Value;
+ // _clientId = clientId;
if (Controller == null)
{
@@ -99,7 +115,7 @@ namespace PepperDash.Essentials.WebSocketServer
Type = "/system/clientJoined",
Content = JToken.FromObject(new
{
- clientId,
+ clientId = Id,
roomKey = RoomKey,
})
};
@@ -110,7 +126,7 @@ namespace PepperDash.Essentials.WebSocketServer
if (bridge == null) return;
- SendUserCodeToClient(bridge, clientId);
+ SendUserCodeToClient(bridge, Id);
bridge.UserCodeChanged -= Bridge_UserCodeChanged;
bridge.UserCodeChanged += Bridge_UserCodeChanged;
@@ -168,17 +184,30 @@ namespace PepperDash.Essentials.WebSocketServer
{
base.OnClose(e);
+ try
+ {
+ this.LogDebug("Current session count on close {count}", Sessions.Count);
+ this.LogDebug("Current WebsocketServiceCount on close: {count}", Controller.DirectServer.WebsocketServiceCount);
+ }
+ catch (Exception ex)
+ {
+ this.LogError("Error getting service count: {message}", ex.Message);
+ this.LogDebug(ex, "Stack Trace: ");
+ }
+
this.LogInformation("WebSocket UiClient Closing: {code} reason: {reason}", e.Code, e.Reason);
foreach (var messenger in Controller.Messengers)
{
- messenger.Value.UnsubscribeClient(_clientId);
+ messenger.Value.UnsubscribeClient(Id);
}
foreach (var messenger in Controller.DefaultMessengers)
{
- messenger.Value.UnsubscribeClient(_clientId);
+ messenger.Value.UnsubscribeClient(Id);
}
+
+ ConnectionClosed?.Invoke(this, new ConnectionClosedEventArgs(Id));
}
///