diff --git a/src/PepperDash.Essentials.MobileControl/WebSocketServer/MobileControlWebsocketServer.cs b/src/PepperDash.Essentials.MobileControl/WebSocketServer/MobileControlWebsocketServer.cs
index cd75dcb7..4e6d74e4 100644
--- a/src/PepperDash.Essentials.MobileControl/WebSocketServer/MobileControlWebsocketServer.cs
+++ b/src/PepperDash.Essentials.MobileControl/WebSocketServer/MobileControlWebsocketServer.cs
@@ -1,10 +1,8 @@
using Crestron.SimplSharp;
using Crestron.SimplSharp.WebScripting;
using Newtonsoft.Json;
-using Newtonsoft.Json.Linq;
using PepperDash.Core;
using PepperDash.Core.Logging;
-using PepperDash.Essentials.AppServer.Messengers;
using PepperDash.Essentials.Core;
using PepperDash.Essentials.Core.DeviceTypeInterfaces;
using PepperDash.Essentials.Core.Web;
@@ -17,145 +15,13 @@ using System.IO;
using System.Linq;
using System.Net.Http;
using System.Text;
-using System.Text.RegularExpressions;
using WebSocketSharp;
using WebSocketSharp.Net;
using WebSocketSharp.Server;
-using ErrorEventArgs = WebSocketSharp.ErrorEventArgs;
namespace PepperDash.Essentials.WebSocketServer
{
- ///
- /// Represents the behaviour to associate with a UiClient for WebSocket communication
- ///
- public class UiClient : WebSocketBehavior
- {
- public MobileControlSystemController Controller { get; set; }
-
- public string RoomKey { get; set; }
-
- private string _clientId;
-
- private DateTime _connectionTime;
-
- public TimeSpan ConnectedDuration
- {
- get
- {
- if (Context.WebSocket.IsAlive)
- {
- return DateTime.Now - _connectionTime;
- }
- else
- {
- return new TimeSpan(0);
- }
- }
- }
-
- public UiClient()
- {
-
- }
-
- protected override void OnOpen()
- {
- base.OnOpen();
-
- var url = Context.WebSocket.Url;
- Debug.LogMessage(LogEventLevel.Verbose, "New WebSocket Connection from: {0}", null, 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)
- {
- Debug.LogMessage(LogEventLevel.Verbose, "WebSocket UiClient Controller is null");
- _connectionTime = DateTime.Now;
- }
-
- var clientJoinedMessage = new MobileControlMessage
- {
- Type = "/system/clientJoined",
- Content = JToken.FromObject(new
- {
- clientId,
- roomKey = RoomKey,
- })
- };
-
- Controller.HandleClientMessage(JsonConvert.SerializeObject(clientJoinedMessage));
-
- var bridge = Controller.GetRoomBridge(RoomKey);
-
- if (bridge == null) return;
-
- SendUserCodeToClient(bridge, clientId);
-
- bridge.UserCodeChanged -= Bridge_UserCodeChanged;
- bridge.UserCodeChanged += Bridge_UserCodeChanged;
-
- // TODO: Future: Check token to see if there's already an open session using that token and reject/close the session
- }
-
- private void Bridge_UserCodeChanged(object sender, EventArgs e)
- {
- SendUserCodeToClient((MobileControlEssentialsRoomBridge)sender, _clientId);
- }
-
- private void SendUserCodeToClient(MobileControlBridgeBase bridge, string clientId)
- {
- var content = new
- {
- userCode = bridge.UserCode,
- qrUrl = bridge.QrCodeUrl,
- };
-
- var message = new MobileControlMessage
- {
- Type = "/system/userCodeChanged",
- ClientId = clientId,
- Content = JToken.FromObject(content)
- };
-
- Controller.SendMessageObjectToDirectClient(message);
- }
-
- protected override void OnMessage(MessageEventArgs e)
- {
- base.OnMessage(e);
-
- if (e.IsText && e.Data.Length > 0 && Controller != null)
- {
- // Forward the message to the controller to be put on the receive queue
- Controller.HandleClientMessage(e.Data);
- }
- }
-
- protected override void OnClose(CloseEventArgs e)
- {
- base.OnClose(e);
-
- Debug.LogMessage(LogEventLevel.Verbose, "WebSocket UiClient Closing: {0} reason: {1}", null, e.Code, e.Reason);
- }
-
- protected override void OnError(ErrorEventArgs e)
- {
- base.OnError(e);
-
- Debug.LogMessage(LogEventLevel.Verbose, "WebSocket UiClient Error: {exception} message: {message}", e.Exception, e.Message);
- }
- }
-
public class MobileControlWebsocketServer : EssentialsDevice
{
private readonly string userAppPath = Global.FilePathPrefix + "mcUserApp" + Global.DirectorySeparator;
@@ -163,6 +29,7 @@ namespace PepperDash.Essentials.WebSocketServer
private readonly string localConfigFolderName = "_local-config";
private readonly string appConfigFileName = "_config.local.json";
+ private readonly string appConfigCsFileName = "_config.cs.json";
///
/// Where the key is the join token and the value is the room key
@@ -191,6 +58,50 @@ namespace PepperDash.Essentials.WebSocketServer
}
}
+ private string lanIpAddress => CrestronEthernetHelper.GetEthernetParameter(CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_CURRENT_IP_ADDRESS, CrestronEthernetHelper.GetAdapterdIdForSpecifiedAdapterType(EthernetAdapterType.EthernetLANAdapter));
+
+ private string csIpAddress
+ {
+ get
+ {
+ short csAdapterId = -1;
+
+ try
+ {
+ CrestronEthernetHelper.GetAdapterdIdForSpecifiedAdapterType(EthernetAdapterType.EthernetCSAdapter);
+ }
+ catch (ArgumentException)
+ {
+ return "";
+ }
+
+ return CrestronEthernetHelper.GetEthernetParameter(CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_CURRENT_IP_ADDRESS, csAdapterId);
+ }
+ }
+
+ private string csSubnet
+ {
+ get
+ {
+ short csAdapterId = -1;
+
+ try
+ {
+ CrestronEthernetHelper.GetAdapterdIdForSpecifiedAdapterType(EthernetAdapterType.EthernetCSAdapter);
+ }
+ catch (ArgumentException)
+ {
+ return "";
+ }
+
+ var subnetMask = CrestronEthernetHelper.GetEthernetParameter(CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_CURRENT_IP_MASK, csAdapterId);
+
+ this.LogDebug("cs subnet mask: {subnetMask}", subnetMask);
+
+ return subnetMask;
+ }
+ }
+
///
/// The path for the WebSocket messaging
///
@@ -209,7 +120,7 @@ namespace PepperDash.Essentials.WebSocketServer
private string _userAppBaseHref = "/mc/app";
///
- /// The prot the server will run on
+ /// The port the server will run on
///
public int Port { get; private set; }
@@ -251,6 +162,8 @@ namespace PepperDash.Essentials.WebSocketServer
// Set the default port to be 50000 plus the slot number of the program
Port = 50000 + (int)Global.ControlSystem.ProgramNumber;
+ this.LogDebug("CS Subnet: {csSubnet}", csSubnet);
+
if (customPort != 0)
{
Port = customPort;
@@ -462,11 +375,45 @@ namespace PepperDash.Essentials.WebSocketServer
if (!Directory.Exists($"{userAppPath}{localConfigFolderName}"))
{
Directory.CreateDirectory($"{userAppPath}{localConfigFolderName}");
- }
+ }
using (var sw = new StreamWriter(File.Open($"{userAppPath}{localConfigFolderName}{Global.DirectorySeparator}{appConfigFileName}", FileMode.Create, FileAccess.ReadWrite)))
+ {
+ // Write the LAN application configuration file. Used when a request comes in for the application config from the LAN
+ var lanAdapterId = CrestronEthernetHelper.GetAdapterdIdForSpecifiedAdapterType(EthernetAdapterType.EthernetLANAdapter);
+
+ var processorIp = CrestronEthernetHelper.GetEthernetParameter(CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_CURRENT_IP_ADDRESS, lanAdapterId);
+
+ var config = GetApplicationConfig(processorIp);
+
+ var contents = JsonConvert.SerializeObject(config, Formatting.Indented);
+
+ sw.Write(contents);
+ }
+
+ short csAdapterId;
+ try
+ {
+ csAdapterId = CrestronEthernetHelper.GetAdapterdIdForSpecifiedAdapterType(EthernetAdapterType.EthernetCSAdapter);
+ }
+ catch (ArgumentException)
{
- var config = GetApplicationConfig();
+ this.LogDebug("This processor does not have a CS LAN");
+ return;
+ }
+
+ if(csAdapterId == -1)
+ {
+ this.LogDebug("CS LAN Adapter not found");
+ return;
+ }
+
+ using (var sw = new StreamWriter(File.Open($"{userAppPath}{localConfigFolderName}{Global.DirectorySeparator}{appConfigCsFileName}", FileMode.Create, FileAccess.ReadWrite)))
+ {
+ // Write the CS application configuration file. Used when a request comes in for the application config from the CS
+ var processorIp = CrestronEthernetHelper.GetEthernetParameter(CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_CURRENT_IP_ADDRESS, csAdapterId);
+
+ var config = GetApplicationConfig(processorIp);
var contents = JsonConvert.SerializeObject(config, Formatting.Indented);
@@ -474,74 +421,41 @@ namespace PepperDash.Essentials.WebSocketServer
}
}
- private MobileControlApplicationConfig GetApplicationConfig()
- {
- MobileControlApplicationConfig config = null;
-
- var lanAdapterId = CrestronEthernetHelper.GetAdapterdIdForSpecifiedAdapterType(EthernetAdapterType.EthernetLANAdapter);
-
- var processorIp = CrestronEthernetHelper.GetEthernetParameter(CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_CURRENT_IP_ADDRESS, lanAdapterId);
-
+ private MobileControlApplicationConfig GetApplicationConfig(string processorIp)
+ {
try
{
- if (_parent.Config.ApplicationConfig == null)
+ var config = new MobileControlApplicationConfig
{
- config = new MobileControlApplicationConfig
+ ApiPath = string.Format("http://{0}:{1}/mc/api", processorIp, _parent.Config.DirectServer.Port),
+ GatewayAppPath = "",
+ LogoPath = _parent.Config.ApplicationConfig?.LogoPath ?? "logo/logo.png",
+ EnableDev = _parent.Config.ApplicationConfig?.EnableDev ?? false,
+ IconSet = _parent.Config.ApplicationConfig?.IconSet ?? MCIconSet.GOOGLE,
+ LoginMode = _parent.Config.ApplicationConfig?.LoginMode ?? "room-list",
+ Modes = _parent.Config.ApplicationConfig?.Modes ?? new Dictionary
{
- ApiPath = string.Format("http://{0}:{1}/mc/api", processorIp, _parent.Config.DirectServer.Port),
- GatewayAppPath = "",
- LogoPath = "logo/logo.png",
- EnableDev = false,
- IconSet = MCIconSet.GOOGLE,
- LoginMode = "room-list",
- Modes = new Dictionary
{
- {
- "room-list",
- new McMode{
- ListPageText= "Please select your room",
- LoginHelpText = "Please select your room from the list, then enter the code shown on the display.",
- PasscodePageText = "Please enter the code shown on this room's display"
- }
+ "room-list",
+ new McMode {
+ ListPageText = "Please select your room",
+ LoginHelpText = "Please select your room from the list, then enter the code shown on the display.",
+ PasscodePageText = "Please enter the code shown on this room's display"
}
- },
- Logging = _parent.Config.DirectServer.Logging.EnableRemoteLogging,
- };
- }
- else
- {
- config = new MobileControlApplicationConfig
- {
- ApiPath = string.Format("http://{0}:{1}/mc/api", processorIp, _parent.Config.DirectServer.Port),
- GatewayAppPath = "",
- LogoPath = _parent.Config.ApplicationConfig.LogoPath ?? "logo/logo.png",
- EnableDev = _parent.Config.ApplicationConfig.EnableDev ?? false,
- IconSet = _parent.Config.ApplicationConfig.IconSet ?? MCIconSet.GOOGLE,
- LoginMode = _parent.Config.ApplicationConfig.LoginMode ?? "room-list",
- Modes = _parent.Config.ApplicationConfig.Modes ?? new Dictionary
- {
- {
- "room-list",
- new McMode {
- ListPageText = "Please select your room",
- LoginHelpText = "Please select your room from the list, then enter the code shown on the display.",
- PasscodePageText = "Please enter the code shown on this room's display"
- }
- }
- },
- Logging = _parent.Config.ApplicationConfig.Logging,
- PartnerMetadata = _parent.Config.ApplicationConfig.PartnerMetadata ?? new List()
- };
- }
+ }
+ },
+ Logging = _parent.Config.ApplicationConfig?.Logging ?? false,
+ PartnerMetadata = _parent.Config.ApplicationConfig?.PartnerMetadata ?? new List()
+ };
+
+ return config;
}
catch (Exception ex)
{
- Debug.LogMessage(ex, "Error getting application configuration", this);
+ this.LogError(ex, "Error getting application configuration");
- Debug.LogMessage(LogEventLevel.Verbose, "Config Object: {config} from {parentConfig}", this, config, _parent.Config);
- }
-
- return config;
+ return null;
+ }
}
///
@@ -1207,6 +1121,8 @@ namespace PepperDash.Essentials.WebSocketServer
this.LogVerbose("Attempting to serve file: {filePath}", filePath);
+
+
byte[] contents;
if (File.Exists(filePath))
{
diff --git a/src/PepperDash.Essentials.MobileControl/WebSocketServer/UiClient.cs b/src/PepperDash.Essentials.MobileControl/WebSocketServer/UiClient.cs
new file mode 100644
index 00000000..eb1cf7a1
--- /dev/null
+++ b/src/PepperDash.Essentials.MobileControl/WebSocketServer/UiClient.cs
@@ -0,0 +1,145 @@
+using Newtonsoft.Json;
+using Newtonsoft.Json.Linq;
+using PepperDash.Core;
+using PepperDash.Essentials.AppServer.Messengers;
+using PepperDash.Essentials.RoomBridges;
+using Serilog.Events;
+using System;
+using System.Text.RegularExpressions;
+using WebSocketSharp;
+using WebSocketSharp.Server;
+using ErrorEventArgs = WebSocketSharp.ErrorEventArgs;
+
+
+namespace PepperDash.Essentials.WebSocketServer
+{
+ ///
+ /// Represents the behaviour to associate with a UiClient for WebSocket communication
+ ///
+ public class UiClient : WebSocketBehavior
+ {
+ public MobileControlSystemController Controller { get; set; }
+
+ public string RoomKey { get; set; }
+
+ private string _clientId;
+
+ private DateTime _connectionTime;
+
+ public TimeSpan ConnectedDuration
+ {
+ get
+ {
+ if (Context.WebSocket.IsAlive)
+ {
+ return DateTime.Now - _connectionTime;
+ }
+ else
+ {
+ return new TimeSpan(0);
+ }
+ }
+ }
+
+ public UiClient()
+ {
+
+ }
+
+ protected override void OnOpen()
+ {
+ base.OnOpen();
+
+ var url = Context.WebSocket.Url;
+ Debug.LogMessage(LogEventLevel.Verbose, "New WebSocket Connection from: {0}", null, 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)
+ {
+ Debug.LogMessage(LogEventLevel.Verbose, "WebSocket UiClient Controller is null");
+ _connectionTime = DateTime.Now;
+ }
+
+ var clientJoinedMessage = new MobileControlMessage
+ {
+ Type = "/system/clientJoined",
+ Content = JToken.FromObject(new
+ {
+ clientId,
+ roomKey = RoomKey,
+ })
+ };
+
+ Controller.HandleClientMessage(JsonConvert.SerializeObject(clientJoinedMessage));
+
+ var bridge = Controller.GetRoomBridge(RoomKey);
+
+ if (bridge == null) return;
+
+ SendUserCodeToClient(bridge, clientId);
+
+ bridge.UserCodeChanged -= Bridge_UserCodeChanged;
+ bridge.UserCodeChanged += Bridge_UserCodeChanged;
+
+ // TODO: Future: Check token to see if there's already an open session using that token and reject/close the session
+ }
+
+ private void Bridge_UserCodeChanged(object sender, EventArgs e)
+ {
+ SendUserCodeToClient((MobileControlEssentialsRoomBridge)sender, _clientId);
+ }
+
+ private void SendUserCodeToClient(MobileControlBridgeBase bridge, string clientId)
+ {
+ var content = new
+ {
+ userCode = bridge.UserCode,
+ qrUrl = bridge.QrCodeUrl,
+ };
+
+ var message = new MobileControlMessage
+ {
+ Type = "/system/userCodeChanged",
+ ClientId = clientId,
+ Content = JToken.FromObject(content)
+ };
+
+ Controller.SendMessageObjectToDirectClient(message);
+ }
+
+ protected override void OnMessage(MessageEventArgs e)
+ {
+ base.OnMessage(e);
+
+ if (e.IsText && e.Data.Length > 0 && Controller != null)
+ {
+ // Forward the message to the controller to be put on the receive queue
+ Controller.HandleClientMessage(e.Data);
+ }
+ }
+
+ protected override void OnClose(CloseEventArgs e)
+ {
+ base.OnClose(e);
+
+ Debug.LogMessage(LogEventLevel.Verbose, "WebSocket UiClient Closing: {0} reason: {1}", null, e.Code, e.Reason);
+ }
+
+ protected override void OnError(ErrorEventArgs e)
+ {
+ base.OnError(e);
+
+ Debug.LogMessage(LogEventLevel.Verbose, "WebSocket UiClient Error: {exception} message: {message}", e.Exception, e.Message);
+ }
+ }
+}