mirror of
https://github.com/PepperDash/Essentials.git
synced 2026-08-31 19:08:29 +00:00
wip: fixing stuff
This commit is contained in:
parent
e7c3fcbbd9
commit
ee44ff1d5f
2 changed files with 256 additions and 195 deletions
|
|
@ -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
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents the behaviour to associate with a UiClient for WebSocket communication
|
||||
/// </summary>
|
||||
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";
|
||||
|
||||
/// <summary>
|
||||
/// 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;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The path for the WebSocket messaging
|
||||
/// </summary>
|
||||
|
|
@ -209,7 +120,7 @@ namespace PepperDash.Essentials.WebSocketServer
|
|||
private string _userAppBaseHref = "/mc/app";
|
||||
|
||||
/// <summary>
|
||||
/// The prot the server will run on
|
||||
/// The port the server will run on
|
||||
/// </summary>
|
||||
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;
|
||||
|
|
@ -466,7 +379,41 @@ namespace PepperDash.Essentials.WebSocketServer
|
|||
|
||||
using (var sw = new StreamWriter(File.Open($"{userAppPath}{localConfigFolderName}{Global.DirectorySeparator}{appConfigFileName}", FileMode.Create, FileAccess.ReadWrite)))
|
||||
{
|
||||
var config = GetApplicationConfig();
|
||||
// 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)
|
||||
{
|
||||
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,51 +421,19 @@ namespace PepperDash.Essentials.WebSocketServer
|
|||
}
|
||||
}
|
||||
|
||||
private MobileControlApplicationConfig GetApplicationConfig()
|
||||
private MobileControlApplicationConfig GetApplicationConfig(string processorIp)
|
||||
{
|
||||
MobileControlApplicationConfig config = null;
|
||||
|
||||
var lanAdapterId = CrestronEthernetHelper.GetAdapterdIdForSpecifiedAdapterType(EthernetAdapterType.EthernetLANAdapter);
|
||||
|
||||
var processorIp = CrestronEthernetHelper.GetEthernetParameter(CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_CURRENT_IP_ADDRESS, lanAdapterId);
|
||||
|
||||
try
|
||||
{
|
||||
if (_parent.Config.ApplicationConfig == null)
|
||||
{
|
||||
config = new MobileControlApplicationConfig
|
||||
var config = new MobileControlApplicationConfig
|
||||
{
|
||||
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<string, McMode>
|
||||
{
|
||||
{
|
||||
"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<string, McMode>
|
||||
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<string, McMode>
|
||||
{
|
||||
{
|
||||
"room-list",
|
||||
|
|
@ -529,19 +444,18 @@ namespace PepperDash.Essentials.WebSocketServer
|
|||
}
|
||||
}
|
||||
},
|
||||
Logging = _parent.Config.ApplicationConfig.Logging,
|
||||
PartnerMetadata = _parent.Config.ApplicationConfig.PartnerMetadata ?? new List<MobileControlPartnerMetadata>()
|
||||
Logging = _parent.Config.ApplicationConfig?.Logging ?? false,
|
||||
PartnerMetadata = _parent.Config.ApplicationConfig?.PartnerMetadata ?? new List<MobileControlPartnerMetadata>()
|
||||
};
|
||||
}
|
||||
|
||||
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 null;
|
||||
}
|
||||
|
||||
return config;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
@ -1207,6 +1121,8 @@ namespace PepperDash.Essentials.WebSocketServer
|
|||
|
||||
this.LogVerbose("Attempting to serve file: {filePath}", filePath);
|
||||
|
||||
|
||||
|
||||
byte[] contents;
|
||||
if (File.Exists(filePath))
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents the behaviour to associate with a UiClient for WebSocket communication
|
||||
/// </summary>
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue