Merge pull request #1432 from PepperDash/fix/web-debug-url

Fix/web debug url
This commit is contained in:
erikdred 2026-06-12 17:15:05 -04:00 committed by GitHub
commit a63da82cc3
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 99 additions and 18 deletions

View file

@ -72,6 +72,20 @@ namespace PepperDash.Core
/// </summary> /// </summary>
public bool IsRunning { get => _httpsServer?.IsListening ?? false; } public bool IsRunning { get => _httpsServer?.IsListening ?? false; }
/// <summary>
/// Gets a value indicating whether there are active WebSocket connections.
/// </summary>
public bool HasActiveConnections
{
get
{
if (_httpsServer == null || !_httpsServer.IsListening) return false;
var service = _httpsServer.WebSocketServices[_path];
if (service == null) return false;
return service.Sessions.Count > 0;
}
}
private readonly ITextFormatter _textFormatter; private readonly ITextFormatter _textFormatter;
@ -217,6 +231,8 @@ namespace PepperDash.Core
{ {
Debug.LogInformation("Starting Websocket Server on port: {0}", port); Debug.LogInformation("Starting Websocket Server on port: {0}", port);
Start(port, CertPath, _certificatePassword); Start(port, CertPath, _certificatePassword);
} }

View file

@ -17,7 +17,10 @@ namespace PepperDash.Essentials.Core.Web.RequestHandlers
/// Represents a DebugSessionRequestHandler /// Represents a DebugSessionRequestHandler
/// </summary> /// </summary>
public class DebugSessionRequestHandler : WebApiBaseRequestHandler public class DebugSessionRequestHandler : WebApiBaseRequestHandler
{ {
private CTimer _portForwardTimeoutTimer;
private readonly object _timerLock = new object();
/// <summary> /// <summary>
/// Constructor /// Constructor
/// </summary> /// </summary>
@ -48,6 +51,7 @@ namespace PepperDash.Essentials.Core.Web.RequestHandlers
CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_CURRENT_IP_ADDRESS, 0); CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_CURRENT_IP_ADDRESS, 0);
var port = 0; var port = 0;
string csIp = null;
if (!Debug.WebsocketSink.IsRunning) if (!Debug.WebsocketSink.IsRunning)
{ {
@ -57,15 +61,18 @@ namespace PepperDash.Essentials.Core.Web.RequestHandlers
// Start the WS Server // Start the WS Server
Debug.WebsocketSink.StartServerAndSetPort(port); Debug.WebsocketSink.StartServerAndSetPort(port);
Debug.SetWebSocketMinimumDebugLevel(Serilog.Events.LogEventLevel.Verbose); Debug.SetWebSocketMinimumDebugLevel(Serilog.Events.LogEventLevel.Verbose);
}
// Attempt to forward the port to the CS LAN // Attempt to get the CS LAN IP and forward the port
try try
{
var csAdapterId = CrestronEthernetHelper.GetAdapterdIdForSpecifiedAdapterType(
EthernetAdapterType.EthernetCSAdapter);
csIp = CrestronEthernetHelper.GetEthernetParameter(
CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_CURRENT_IP_ADDRESS, csAdapterId);
if (port > 0)
{ {
var csAdapterId = CrestronEthernetHelper.GetAdapterdIdForSpecifiedAdapterType(
EthernetAdapterType.EthernetCSAdapter);
var csIp = CrestronEthernetHelper.GetEthernetParameter(
CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_CURRENT_IP_ADDRESS, csAdapterId);
var result = CrestronEthernetHelper.AddPortForwarding( var result = CrestronEthernetHelper.AddPortForwarding(
(ushort)port, (ushort)port, csIp, (ushort)port, (ushort)port, csIp,
CrestronEthernetHelper.ePortMapTransport.TCP); CrestronEthernetHelper.ePortMapTransport.TCP);
@ -77,26 +84,29 @@ namespace PepperDash.Essentials.Core.Web.RequestHandlers
else else
{ {
Debug.LogMessage(LogEventLevel.Information, "Port {0} forwarded to CS LAN for debug websocket", port); Debug.LogMessage(LogEventLevel.Information, "Port {0} forwarded to CS LAN for debug websocket", port);
StartPortForwardTimeout(port, csIp);
} }
} }
catch (ArgumentException) }
{ catch (ArgumentException)
Debug.LogMessage(LogEventLevel.Debug, "This processor does not have a CS LAN adapter; skipping port forwarding"); {
} Debug.LogMessage(LogEventLevel.Debug, "This processor does not have a CS LAN adapter; skipping port forwarding");
catch (Exception ex) }
{ catch (Exception ex)
Debug.LogMessage(LogEventLevel.Warning, "Error automatically forwarding debug websocket port to CS LAN: {0}", ex.Message); {
} Debug.LogMessage(LogEventLevel.Warning, "Error automatically forwarding debug websocket port to CS LAN: {0}", ex.Message);
} }
var url = Debug.WebsocketSink.Url; var url = Debug.WebsocketSink.Url;
object data = new var data = new
{ {
url = Debug.WebsocketSink.Url url = Debug.WebsocketSink.Url,
fallbackUrl = csIp != null ? url.Replace(csIp, ip) : null
}; };
Debug.LogMessage(LogEventLevel.Information, "Debug Session URL: {0}", url); Debug.LogMessage(LogEventLevel.Information, "Debug Session URL: {0}", url);
Debug.LogMessage(LogEventLevel.Information, "Fallback Debug Session URL: {0}", data.fallbackUrl);
// Return the port number with the full url of the WS Server // Return the port number with the full url of the WS Server
var res = JsonConvert.SerializeObject(data); var res = JsonConvert.SerializeObject(data);
@ -120,6 +130,8 @@ namespace PepperDash.Essentials.Core.Web.RequestHandlers
/// <param name="context"></param> /// <param name="context"></param>
protected override void HandlePost(HttpCwsContext context) protected override void HandlePost(HttpCwsContext context)
{ {
CancelPortForwardTimeout();
var port = Debug.WebsocketSink.Port; var port = Debug.WebsocketSink.Port;
Debug.WebsocketSink.StopServer(); Debug.WebsocketSink.StopServer();
@ -168,5 +180,55 @@ namespace PepperDash.Essentials.Core.Web.RequestHandlers
Debug.LogMessage(LogEventLevel.Information, "Websocket Debug Session Stopped"); Debug.LogMessage(LogEventLevel.Information, "Websocket Debug Session Stopped");
} }
private void StartPortForwardTimeout(int port, string csIp)
{
lock (_timerLock)
{
_portForwardTimeoutTimer?.Dispose();
_portForwardTimeoutTimer = new CTimer(_ =>
{
if (Debug.WebsocketSink.HasActiveConnections)
{
Debug.LogMessage(LogEventLevel.Debug, "Debug websocket has active connections; keeping port forward");
return;
}
Debug.LogMessage(LogEventLevel.Information, "No debug websocket connection within 30 seconds; removing port forward for port {0}", port);
try
{
var result = CrestronEthernetHelper.RemovePortForwarding(
(ushort)port, (ushort)port, csIp,
CrestronEthernetHelper.ePortMapTransport.TCP);
if (result != CrestronEthernetHelper.PortForwardingUserPatRetCodes.NoErr)
{
Debug.LogMessage(LogEventLevel.Warning, "Error removing port forwarding on timeout: {0}", result);
}
else
{
Debug.LogMessage(LogEventLevel.Information, "Port forwarding for port {0} removed due to timeout", port);
}
}
catch (Exception ex)
{
Debug.LogMessage(LogEventLevel.Warning, "Error removing port forwarding on timeout: {0}", ex.Message);
}
}, 30000);
}
}
/// <summary>
/// Cancels the port forward timeout timer if a session is being explicitly stopped.
/// </summary>
private void CancelPortForwardTimeout()
{
lock (_timerLock)
{
_portForwardTimeoutTimer?.Dispose();
_portForwardTimeoutTimer = null;
}
}
} }
} }

View file

@ -264,6 +264,9 @@ namespace PepperDash.Essentials.AppServer.Messengers
message.Name = _device.Name; message.Name = _device.Name;
message.MessageBasePath = MessagePath;
var token = JToken.FromObject(message); var token = JToken.FromObject(message);
PostStatusMessage(token, MessagePath, clientId); PostStatusMessage(token, MessagePath, clientId);