feat: unique client IDs for direct server

When multiple UI applications were connecting using the same token, the actual websocket connection was getting lost, and could eventually be garbage-collected, leading to odd behavior from the UI. This is due to an existing client getting replaced and a reference to it lost. This has now been remedied, with each client getting a unique instance with a unique client ID.
This commit is contained in:
Andrew Welker
2025-07-10 10:36:47 -05:00
parent 5ff587a8c9
commit 8b098aac2c
12 changed files with 345 additions and 285 deletions

View File

@@ -0,0 +1,74 @@
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
{
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
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");
}
}
#endregion
}
}

View File

@@ -1,4 +1,10 @@
using Crestron.SimplSharp; using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using Crestron.SimplSharp;
using Crestron.SimplSharp.CrestronIO; using Crestron.SimplSharp.CrestronIO;
using Crestron.SimplSharp.Net.Http; using Crestron.SimplSharp.Net.Http;
using Crestron.SimplSharp.WebScripting; using Crestron.SimplSharp.WebScripting;
@@ -30,12 +36,6 @@ using PepperDash.Essentials.RoomBridges;
using PepperDash.Essentials.Services; using PepperDash.Essentials.Services;
using PepperDash.Essentials.WebApiHandlers; using PepperDash.Essentials.WebApiHandlers;
using PepperDash.Essentials.WebSocketServer; using PepperDash.Essentials.WebSocketServer;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using WebSocketSharp; using WebSocketSharp;
namespace PepperDash.Essentials namespace PepperDash.Essentials
@@ -1619,12 +1619,12 @@ Mobile Control Direct Server Information:
Tokens Defined: {0} Tokens Defined: {0}
Clients Connected: {1} Clients Connected: {1}
", ",
_directServer.UiClients.Count, _directServer.UiClientContexts.Count,
_directServer.ConnectedUiClientsCount _directServer.ConnectedUiClientsCount
); );
var clientNo = 1; var clientNo = 1;
foreach (var clientContext in _directServer.UiClients) foreach (var clientContext in _directServer.UiClientContexts)
{ {
var isAlive = false; var isAlive = false;
var duration = "Not Connected"; var duration = "Not Connected";

View File

@@ -1,13 +1,10 @@
using Newtonsoft.Json; using System;
using Newtonsoft.Json;
using Newtonsoft.Json.Converters; using Newtonsoft.Json.Converters;
using PepperDash.Core; using PepperDash.Core;
using PepperDash.Core.Logging;
using PepperDash.Essentials.AppServer.Messengers; using PepperDash.Essentials.AppServer.Messengers;
using PepperDash.Essentials.Core.Queues; using PepperDash.Essentials.Core.Queues;
using PepperDash.Essentials.WebSocketServer;
using Serilog.Events; using Serilog.Events;
using System;
using System.Threading;
using WebSocketSharp; using WebSocketSharp;
namespace PepperDash.Essentials namespace PepperDash.Essentials
@@ -65,66 +62,4 @@ namespace PepperDash.Essentials
#endregion #endregion
} }
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
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");
}
}
#endregion
}
} }

View File

@@ -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 Newtonsoft.Json;
using PepperDash.Core; using PepperDash.Core;
using PepperDash.Core.Web.RequestHandlers; using PepperDash.Core.Web.RequestHandlers;
using PepperDash.Essentials.Core.Config; using PepperDash.Essentials.Core.Config;
using PepperDash.Essentials.WebSocketServer; using PepperDash.Essentials.WebSocketServer;
using System;
using System.Collections.Generic;
using System.Linq;
namespace PepperDash.Essentials.WebApiHandlers namespace PepperDash.Essentials.WebApiHandlers
{ {
@@ -99,13 +99,13 @@ namespace PepperDash.Essentials.WebApiHandlers
public int ServerPort => directServer.Port; public int ServerPort => directServer.Port;
[JsonProperty("tokensDefined")] [JsonProperty("tokensDefined")]
public int TokensDefined => directServer.UiClients.Count; public int TokensDefined => directServer.UiClientContexts.Count;
[JsonProperty("clientsConnected")] [JsonProperty("clientsConnected")]
public int ClientsConnected => directServer.ConnectedUiClientsCount; public int ClientsConnected => directServer.ConnectedUiClientsCount;
[JsonProperty("clients")] [JsonProperty("clients")]
public List<MobileControlDirectClient> Clients => directServer.UiClients.Select((c, i) => { return new MobileControlDirectClient(c, i, directServer.UserAppUrlPrefix); }).ToList(); public List<MobileControlDirectClient> Clients => directServer.UiClientContexts.Select((c, i) => { return new MobileControlDirectClient(c, i, directServer.UserAppUrlPrefix); }).ToList();
public MobileControlDirectServer(MobileControlWebsocketServer server) public MobileControlDirectServer(MobileControlWebsocketServer server)
{ {

View File

@@ -90,7 +90,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 var response = new ClientResponse
{ {
@@ -131,7 +131,7 @@ namespace PepperDash.Essentials.WebApiHandlers
return; return;
} }
server.UiClients.Remove(request.Token); server.UiClientContexts.Remove(request.Token);
server.UpdateSecret(); server.UpdateSecret();

View File

@@ -0,0 +1,39 @@
using System;
using Newtonsoft.Json;
namespace PepperDash.Essentials.WebSocketServer
{
/// <summary>
/// Represents the structure of the join response
/// </summary>
public class JoinResponse
{
[JsonProperty("clientId")]
public string ClientId { get; set; }
[JsonProperty("roomKey")]
public string RoomKey { get; set; }
[JsonProperty("systemUUid")]
public string SystemUuid { get; set; }
[JsonProperty("roomUUid")]
public string RoomUuid { get; set; }
[JsonProperty("config")]
public object Config { get; set; }
[JsonProperty("codeExpires")]
public DateTime CodeExpires { get; set; }
[JsonProperty("userCode")]
public string UserCode { get; set; }
[JsonProperty("userAppUrl")]
public string UserAppUrl { get; set; }
[JsonProperty("enableDebug")]
public bool EnableDebug { get; set; }
}
}

View File

@@ -0,0 +1,22 @@
using Independentsoft.Exchange;
namespace PepperDash.Essentials.WebSocketServer
{
/// <summary>
/// Represents a join token with the associated properties
/// </summary>
public class JoinToken
{
public string Code { get; set; }
public string RoomKey { get; set; }
public string Uuid { get; set; }
public string TouchpanelKey { get; set; } = "";
public string Token { get; set; } = null;
public string Id { get; set; }
}
}

View File

@@ -1,4 +1,10 @@
using Crestron.SimplSharp; using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net.Http;
using System.Text;
using Crestron.SimplSharp;
using Crestron.SimplSharp.WebScripting; using Crestron.SimplSharp.WebScripting;
using Newtonsoft.Json; using Newtonsoft.Json;
using PepperDash.Core; using PepperDash.Core;
@@ -9,12 +15,6 @@ using PepperDash.Essentials.Core.Web;
using PepperDash.Essentials.RoomBridges; using PepperDash.Essentials.RoomBridges;
using PepperDash.Essentials.WebApiHandlers; using PepperDash.Essentials.WebApiHandlers;
using Serilog.Events; using Serilog.Events;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net.Http;
using System.Text;
using WebSocketSharp; using WebSocketSharp;
using WebSocketSharp.Net; using WebSocketSharp.Net;
using WebSocketSharp.Server; using WebSocketSharp.Server;
@@ -24,6 +24,7 @@ namespace PepperDash.Essentials.WebSocketServer
{ {
public class MobileControlWebsocketServer : EssentialsDevice public class MobileControlWebsocketServer : EssentialsDevice
{ {
private int nextClientId = 0;
private readonly string userAppPath = Global.FilePathPrefix + "mcUserApp" + Global.DirectorySeparator; private readonly string userAppPath = Global.FilePathPrefix + "mcUserApp" + Global.DirectorySeparator;
private readonly string localConfigFolderName = "_local-config"; private readonly string localConfigFolderName = "_local-config";
@@ -40,7 +41,9 @@ namespace PepperDash.Essentials.WebSocketServer
public HttpServer Server => _server; public HttpServer Server => _server;
public Dictionary<string, UiClientContext> UiClients { get; private set; } public Dictionary<string, UiClientContext> UiClientContexts { get; private set; }
public Dictionary<string, UiClient> UiClients { get; private set; } = new Dictionary<string, UiClient>();
private readonly MobileControlSystemController _parent; private readonly MobileControlSystemController _parent;
@@ -104,7 +107,7 @@ namespace PepperDash.Essentials.WebSocketServer
{ {
var count = 0; var count = 0;
foreach (var client in UiClients) foreach (var client in UiClientContexts)
{ {
if (client.Value.Client != null && client.Value.Client.Context.WebSocket.IsAlive) if (client.Value.Client != null && client.Value.Client.Context.WebSocket.IsAlive)
{ {
@@ -173,7 +176,7 @@ namespace PepperDash.Essentials.WebSocketServer
} }
UiClients = new Dictionary<string, UiClientContext>(); UiClientContexts = new Dictionary<string, UiClientContext>();
//_joinTokens = new Dictionary<string, JoinToken>(); //_joinTokens = new Dictionary<string, JoinToken>();
@@ -472,45 +475,39 @@ namespace PepperDash.Essentials.WebSocketServer
Debug.LogMessage(LogEventLevel.Information, "Adding token: {0} for room: {1}", this, token.Key, token.Value.RoomKey); Debug.LogMessage(LogEventLevel.Information, "Adding token: {0} for room: {1}", this, token.Key, token.Value.RoomKey);
if (UiClients == null) if (UiClientContexts == null)
{ {
Debug.LogMessage(LogEventLevel.Warning, "UiClients is null", this); Debug.LogMessage(LogEventLevel.Warning, "UiClients is null", this);
UiClients = new Dictionary<string, UiClientContext>(); UiClientContexts = new Dictionary<string, UiClientContext>();
} }
UiClients.Add(token.Key, new UiClientContext(token.Value)); UiClientContexts.Add(token.Key, new UiClientContext(token.Value));
} }
} }
if (UiClients.Count > 0) if (UiClientContexts.Count > 0)
{ {
Debug.LogMessage(LogEventLevel.Information, "Restored {uiClientCount} UiClients from secrets data", this, UiClients.Count); Debug.LogMessage(LogEventLevel.Information, "Restored {uiClientCount} UiClients from secrets data", this, UiClientContexts.Count);
foreach (var client in UiClients) foreach (var client in UiClientContexts)
{ {
var key = client.Key; var key = client.Key;
var path = _wsPath + key; var path = _wsPath + key;
var roomKey = client.Value.Token.RoomKey; var roomKey = client.Value.Token.RoomKey;
var token = client.Value.Token;
var bridge = _parent.GetRoomBridge(roomKey);
if (bridge == null)
{
this.LogWarning("No bridge found for room key: {0}", this, roomKey);
continue;
}
_server.AddWebSocketService(path, () => _server.AddWebSocketService(path, () =>
{ {
var c = new UiClient(); return InitializeUiClient(token, bridge);
Debug.LogMessage(LogEventLevel.Debug, "Constructing UiClient with id: {key}", this, key);
c.Controller = _parent;
c.RoomKey = roomKey;
UiClients[key].SetClient(c);
return c;
}); });
//_server.WebSocketServices.AddService<UiClient>(path, (c) =>
//{
// Debug.Console(2, this, "Constructing UiClient with id: {0}", key);
// c.Controller = _parent;
// c.RoomKey = roomKey;
// UiClients[key].SetClient(c);
//});
} }
} }
} }
@@ -519,7 +516,7 @@ namespace PepperDash.Essentials.WebSocketServer
Debug.LogMessage(LogEventLevel.Warning, "No secret found"); Debug.LogMessage(LogEventLevel.Warning, "No secret found");
} }
Debug.LogMessage(LogEventLevel.Debug, "{uiClientCount} UiClients restored from secrets data", this, UiClients.Count); Debug.LogMessage(LogEventLevel.Debug, "{uiClientCount} UiClients restored from secrets data", this, UiClientContexts.Count);
} }
catch (Exception ex) catch (Exception ex)
{ {
@@ -543,7 +540,7 @@ namespace PepperDash.Essentials.WebSocketServer
_secret.Tokens.Clear(); _secret.Tokens.Clear();
foreach (var uiClientContext in UiClients) foreach (var uiClientContext in UiClientContexts)
{ {
_secret.Tokens.Add(uiClientContext.Key, uiClientContext.Value.Token); _secret.Tokens.Add(uiClientContext.Key, uiClientContext.Value.Token);
} }
@@ -636,24 +633,50 @@ namespace PepperDash.Essentials.WebSocketServer
} }
} }
private UiClient InitializeUiClient(JoinToken token, MobileControlBridgeBase bridge)
{
Debug.LogMessage(LogEventLevel.Verbose, "Constructing UiClient with id: {0}", this, token.Id);
var c = new UiClient(token.Id)
{
Controller = _parent,
RoomKey = bridge.RoomKey
};
UiClients.Add(c.ClientId, c);
// reset client ID in token for next use
token.Id = null;
c.Context.WebSocket.OnClose += (sender, e) =>
{
if (UiClients.ContainsKey(c.ClientId))
{
UiClients.Remove(c.ClientId);
}
};
return c;
}
public (string, string) GenerateClientToken(MobileControlBridgeBase bridge, string touchPanelKey = "") public (string, string) GenerateClientToken(MobileControlBridgeBase bridge, string touchPanelKey = "")
{ {
var key = Guid.NewGuid().ToString(); var key = Guid.NewGuid().ToString();
var token = new JoinToken { Code = bridge.UserCode, RoomKey = bridge.RoomKey, Uuid = _parent.SystemUuid, TouchpanelKey = touchPanelKey }; 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; var path = _wsPath + key;
_server.AddWebSocketService(path, () => _server.AddWebSocketService(path, () =>
{ {
var c = new UiClient(); if (string.IsNullOrEmpty(token.Id))
Debug.LogMessage(LogEventLevel.Verbose, "Constructing UiClient with id: {0}", this, key); {
c.Controller = _parent; token.Id = nextClientId++.ToString();
c.RoomKey = bridge.RoomKey; }
UiClients[key].SetClient(c);
return c; return InitializeUiClient(token, bridge);
}); });
Debug.LogMessage(LogEventLevel.Information, "Added new WebSocket UiClient service at path: {path}", this, path); Debug.LogMessage(LogEventLevel.Information, "Added new WebSocket UiClient service at path: {path}", this, path);
@@ -683,7 +706,7 @@ namespace PepperDash.Essentials.WebSocketServer
return; return;
} }
foreach (var client in UiClients) foreach (var client in UiClientContexts)
{ {
if (client.Value.Client != null && client.Value.Client.Context.WebSocket.IsAlive) if (client.Value.Client != null && client.Value.Client.Context.WebSocket.IsAlive)
{ {
@@ -701,7 +724,7 @@ namespace PepperDash.Essentials.WebSocketServer
} }
} }
UiClients.Clear(); UiClientContexts.Clear();
UpdateSecret(); UpdateSecret();
} }
@@ -720,9 +743,9 @@ namespace PepperDash.Essentials.WebSocketServer
var key = s; 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) if (uiClientContext.Client != null && uiClientContext.Client.Context.WebSocket.IsAlive)
{ {
@@ -732,7 +755,7 @@ namespace PepperDash.Essentials.WebSocketServer
var path = _wsPath + key; var path = _wsPath + key;
if (_server.RemoveWebSocketService(path)) if (_server.RemoveWebSocketService(path))
{ {
UiClients.Remove(key); UiClientContexts.Remove(key);
UpdateSecret(); UpdateSecret();
@@ -756,9 +779,9 @@ namespace PepperDash.Essentials.WebSocketServer
{ {
CrestronConsole.ConsoleCommandResponse("Mobile Control UI Client Info:\r"); 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)); CrestronConsole.ConsoleCommandResponse(string.Format("RoomKey: {0} Token: {1}\r", client.Value.Token.RoomKey, client.Key));
} }
@@ -768,7 +791,7 @@ namespace PepperDash.Essentials.WebSocketServer
{ {
if (programEventType == eProgramStatusEventType.Stopping) 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) if (client.Client != null && client.Client.Context.WebSocket.IsAlive)
{ {
@@ -907,7 +930,7 @@ namespace PepperDash.Essentials.WebSocketServer
this.LogVerbose("Join Room Request with token: {token}", token); this.LogVerbose("Join Room Request with token: {token}", token);
if (UiClients.TryGetValue(token, out UiClientContext clientContext)) if (UiClientContexts.TryGetValue(token, out UiClientContext clientContext))
{ {
var bridge = _parent.GetRoomBridge(clientContext.Token.RoomKey); var bridge = _parent.GetRoomBridge(clientContext.Token.RoomKey);
@@ -916,10 +939,12 @@ namespace PepperDash.Essentials.WebSocketServer
res.StatusCode = 200; res.StatusCode = 200;
res.ContentType = "application/json"; res.ContentType = "application/json";
clientContext.Token.Id = nextClientId++.ToString();
// Construct the response object // Construct the response object
JoinResponse jRes = new JoinResponse JoinResponse jRes = new JoinResponse
{ {
ClientId = token, ClientId = clientContext.Token.Id,
RoomKey = bridge.RoomKey, RoomKey = bridge.RoomKey,
SystemUuid = _parent.SystemUuid, SystemUuid = _parent.SystemUuid,
RoomUuid = _parent.SystemUuid, RoomUuid = _parent.SystemUuid,
@@ -1137,12 +1162,14 @@ namespace PepperDash.Essentials.WebSocketServer
/// <param name="message"></param> /// <param name="message"></param>
public void SendMessageToAllClients(string message) 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);
} }
} }
@@ -1153,129 +1180,25 @@ namespace PepperDash.Essentials.WebSocketServer
/// <param name="message"></param> /// <param name="message"></param>
public void SendMessageToClient(object clientId, string message) public void SendMessageToClient(object clientId, string message)
{ {
if (clientId == null) if (clientId == null || !(clientId is string))
{ {
return; return;
} }
if (UiClients.TryGetValue((string)clientId, out UiClientContext clientContext)) if (!UiClients.TryGetValue((string)clientId, out UiClient client))
{
if (clientContext.Client != null)
{
var socket = clientContext.Client.Context.WebSocket;
if (socket.IsAlive)
{
socket.Send(message);
}
}
}
else
{ {
this.LogWarning("Unable to find client with ID: {clientId}", clientId); this.LogWarning("Unable to find client with ID: {clientId}", clientId);
} return;
}
} }
/// <summary> var socket = client.Context.WebSocket;
/// Class to describe the server version info
/// </summary> if (!socket.IsAlive)
public class Version
{ {
[JsonProperty("serverVersion")] return;
public string ServerVersion { get; set; } }
socket.Send(message);
[JsonProperty("serverIsRunningOnProcessorHardware")]
public bool ServerIsRunningOnProcessorHardware { get; private set; }
public Version()
{
ServerIsRunningOnProcessorHardware = true;
} }
} }
/// <summary>
/// Represents an instance of a UiClient and the associated Token
/// </summary>
public class UiClientContext
{
public UiClient Client { get; private set; }
public JoinToken Token { get; private set; }
public UiClientContext(JoinToken token)
{
Token = token;
}
public void SetClient(UiClient client)
{
Client = client;
}
}
/// <summary>
/// Represents the data structure for the grant code and UiClient tokens to be stored in the secrets manager
/// </summary>
public class ServerTokenSecrets
{
public string GrantCode { get; set; }
public Dictionary<string, JoinToken> Tokens { get; set; }
public ServerTokenSecrets(string grantCode)
{
GrantCode = grantCode;
Tokens = new Dictionary<string, JoinToken>();
}
}
/// <summary>
/// Represents a join token with the associated properties
/// </summary>
public class JoinToken
{
public string Code { get; set; }
public string RoomKey { get; set; }
public string Uuid { get; set; }
public string TouchpanelKey { get; set; } = "";
public string Token { get; set; } = null;
}
/// <summary>
/// Represents the structure of the join response
/// </summary>
public class JoinResponse
{
[JsonProperty("clientId")]
public string ClientId { get; set; }
[JsonProperty("roomKey")]
public string RoomKey { get; set; }
[JsonProperty("systemUUid")]
public string SystemUuid { get; set; }
[JsonProperty("roomUUid")]
public string RoomUuid { get; set; }
[JsonProperty("config")]
public object Config { get; set; }
[JsonProperty("codeExpires")]
public DateTime CodeExpires { get; set; }
[JsonProperty("userCode")]
public string UserCode { get; set; }
[JsonProperty("userAppUrl")]
public string UserAppUrl { get; set; }
[JsonProperty("enableDebug")]
public bool EnableDebug { get; set; }
}
} }

View File

@@ -0,0 +1,21 @@
using System.Collections.Generic;
namespace PepperDash.Essentials.WebSocketServer
{
/// <summary>
/// Represents the data structure for the grant code and UiClient tokens to be stored in the secrets manager
/// </summary>
public class ServerTokenSecrets
{
public string GrantCode { get; set; }
public Dictionary<string, JoinToken> Tokens { get; set; }
public ServerTokenSecrets(string grantCode)
{
GrantCode = grantCode;
Tokens = new Dictionary<string, JoinToken>();
}
}
}

View File

@@ -1,11 +1,11 @@
using Newtonsoft.Json; using System;
using System.Text.RegularExpressions;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq; using Newtonsoft.Json.Linq;
using PepperDash.Core; using PepperDash.Core;
using PepperDash.Essentials.AppServer.Messengers; using PepperDash.Essentials.AppServer.Messengers;
using PepperDash.Essentials.RoomBridges; using PepperDash.Essentials.RoomBridges;
using Serilog.Events; using Serilog.Events;
using System;
using System.Text.RegularExpressions;
using WebSocketSharp; using WebSocketSharp;
using WebSocketSharp.Server; using WebSocketSharp.Server;
using ErrorEventArgs = WebSocketSharp.ErrorEventArgs; using ErrorEventArgs = WebSocketSharp.ErrorEventArgs;
@@ -22,7 +22,10 @@ namespace PepperDash.Essentials.WebSocketServer
public string RoomKey { get; set; } public string RoomKey { get; set; }
private string _clientId; public string ClientId
{
get; private set;
}
private DateTime _connectionTime; private DateTime _connectionTime;
@@ -41,9 +44,9 @@ namespace PepperDash.Essentials.WebSocketServer
} }
} }
public UiClient() public UiClient(string clientId)
{ {
ClientId = clientId;
} }
protected override void OnOpen() protected override void OnOpen()
@@ -61,8 +64,7 @@ namespace PepperDash.Essentials.WebSocketServer
return; return;
} }
var clientId = match.Groups[1].Value; var clientId = ClientId;
_clientId = clientId;
if (Controller == null) if (Controller == null)
{ {
@@ -96,7 +98,7 @@ namespace PepperDash.Essentials.WebSocketServer
private void Bridge_UserCodeChanged(object sender, EventArgs e) private void Bridge_UserCodeChanged(object sender, EventArgs e)
{ {
SendUserCodeToClient((MobileControlEssentialsRoomBridge)sender, _clientId); SendUserCodeToClient((MobileControlEssentialsRoomBridge)sender, ClientId);
} }
private void SendUserCodeToClient(MobileControlBridgeBase bridge, string clientId) private void SendUserCodeToClient(MobileControlBridgeBase bridge, string clientId)

View File

@@ -0,0 +1,22 @@
namespace PepperDash.Essentials.WebSocketServer
{
/// <summary>
/// Represents an instance of a UiClient and the associated Token
/// </summary>
public class UiClientContext
{
public UiClient Client { get; private set; }
public JoinToken Token { get; private set; }
public UiClientContext(JoinToken token)
{
Token = token;
}
public void SetClient(UiClient client)
{
Client = client;
}
}
}

View File

@@ -0,0 +1,22 @@
using Newtonsoft.Json;
namespace PepperDash.Essentials.WebSocketServer
{
/// <summary>
/// Class to describe the server version info
/// </summary>
public class Version
{
[JsonProperty("serverVersion")]
public string ServerVersion { get; set; }
[JsonProperty("serverIsRunningOnProcessorHardware")]
public bool ServerIsRunningOnProcessorHardware { get; private set; }
public Version()
{
ServerIsRunningOnProcessorHardware = true;
}
}
}