diff --git a/src/Directory.Build.props b/src/Directory.Build.props index 235fee48..ab9f2732 100644 --- a/src/Directory.Build.props +++ b/src/Directory.Build.props @@ -1,6 +1,6 @@ - 2.42.1-local + 2.36.6-local $(Version) PepperDash Technology PepperDash Technology diff --git a/src/PepperDash.Core/Comm/GenericSshClient.cs b/src/PepperDash.Core/Comm/GenericSshClient.cs index 546a2a67..df44ab51 100644 --- a/src/PepperDash.Core/Comm/GenericSshClient.cs +++ b/src/PepperDash.Core/Comm/GenericSshClient.cs @@ -151,8 +151,6 @@ namespace PepperDash.Core // Thread-safety lock for state changes private readonly object _stateLock = new object(); - private volatile bool _isProgramStopping; - private bool disconnectLogged = false; /// @@ -209,9 +207,11 @@ namespace PepperDash.Core { if (programEventType == eProgramStatusEventType.Stopping) { - _isProgramStopping = true; - this.LogDebug("Program stopping. Closing connection"); - Disconnect(); + if (client != null) + { + this.LogDebug("Program stopping. Closing connection"); + Disconnect(); + } } } @@ -228,12 +228,6 @@ namespace PepperDash.Core return; } - if (_isProgramStopping) - { - this.LogDebug("Skipping connect because program is stopping"); - return; - } - ConnectEnabled = true; try @@ -293,7 +287,13 @@ namespace PepperDash.Core } catch (SshConnectionException e) { - var ie = e.InnerException; // The details are inside, when present - remote can close the connection with no inner exception at all + var ie = e.InnerException; // The details are inside!! + + if (ie is SocketException) + { + this.LogError("CONNECTION failure: Cannot reach host"); + this.LogVerbose(ie, "Exception details: "); + } if (ie is System.Net.Sockets.SocketException socketException) { @@ -301,20 +301,20 @@ namespace PepperDash.Core Hostname, Port); this.LogVerbose(socketException, "SocketException details: "); } - else if (ie is SshAuthenticationException) + if (ie is SshAuthenticationException) { this.LogError("Authentication failure for username {userName}", Username); this.LogVerbose(ie, "AuthenticationException details: "); } else { - this.LogError("Error on connect: {error}", ie?.Message ?? e.Message); - this.LogVerbose(ie ?? e, "Exception details: "); + this.LogError("Error on connect: {error}", ie.Message); + this.LogVerbose(ie, "Exception details: "); } disconnectLogged = true; KillClient(SocketStatus.SOCKET_STATUS_CONNECT_FAILED); - if (AutoReconnect && ConnectEnabled && !_isProgramStopping) + if (AutoReconnect) { this.LogDebug("Checking autoreconnect: {autoReconnect}, {autoReconnectInterval}ms", AutoReconnect, AutoReconnectIntervalMs); StartReconnectTimer(); @@ -326,7 +326,7 @@ namespace PepperDash.Core disconnectLogged = true; KillClient(SocketStatus.SOCKET_STATUS_CONNECT_FAILED); - if (AutoReconnect && ConnectEnabled && !_isProgramStopping) + if (AutoReconnect) { this.LogDebug("Checking autoreconnect: {0}, {1}ms", AutoReconnect, AutoReconnectIntervalMs); StartReconnectTimer(); @@ -338,7 +338,7 @@ namespace PepperDash.Core this.LogVerbose(e, "Exception details: "); disconnectLogged = true; KillClient(SocketStatus.SOCKET_STATUS_CONNECT_FAILED); - if (AutoReconnect && ConnectEnabled && !_isProgramStopping) + if (AutoReconnect) { this.LogDebug("Checking autoreconnect: {0}, {1}ms", AutoReconnect, AutoReconnectIntervalMs); StartReconnectTimer(); @@ -473,7 +473,7 @@ namespace PepperDash.Core { connectLock.Release(); } - if (AutoReconnect && ConnectEnabled && !_isProgramStopping) + if (AutoReconnect && ConnectEnabled) { this.LogDebug("Checking autoreconnect: {0}, {1}ms", AutoReconnect, AutoReconnectIntervalMs); StartReconnectTimer(); @@ -516,10 +516,7 @@ namespace PepperDash.Core this.LogError("ObjectDisposedException sending '{message}'. Restarting connection...", text.Trim()); KillClient(SocketStatus.SOCKET_STATUS_CONNECT_FAILED); - if (AutoReconnect && ConnectEnabled && !_isProgramStopping) - { - StartReconnectTimer(); - } + StartReconnectTimer(); } catch (Exception ex) { @@ -552,10 +549,7 @@ namespace PepperDash.Core this.LogException(ex, "ObjectDisposedException sending {message}", ComTextHelper.GetEscapedText(bytes)); KillClient(SocketStatus.SOCKET_STATUS_CONNECT_FAILED); - if (AutoReconnect && ConnectEnabled && !_isProgramStopping) - { - StartReconnectTimer(); - } + StartReconnectTimer(); } catch (Exception ex) { diff --git a/src/PepperDash.Core/PepperDash.Core.csproj b/src/PepperDash.Core/PepperDash.Core.csproj index 747aefb6..daa5c6da 100644 --- a/src/PepperDash.Core/PepperDash.Core.csproj +++ b/src/PepperDash.Core/PepperDash.Core.csproj @@ -43,7 +43,7 @@ - + diff --git a/src/PepperDash.Essentials.Core/Comm and IR/CecPortController.cs b/src/PepperDash.Essentials.Core/Comm and IR/CecPortController.cs index a5aa0d13..298bbc9b 100644 --- a/src/PepperDash.Essentials.Core/Comm and IR/CecPortController.cs +++ b/src/PepperDash.Essentials.Core/Comm and IR/CecPortController.cs @@ -39,8 +39,6 @@ namespace PepperDash.Essentials.Core ICec Port; - bool _cecSubscribed; - /// /// Constructor /// @@ -56,7 +54,7 @@ namespace PepperDash.Essentials.Core { Port = postActivationFunc(config); - TryEnsureCecSubscription(); + Port.StreamCec.CecChange += StreamCec_CecChange; }); } @@ -70,29 +68,7 @@ namespace PepperDash.Essentials.Core { Port = port; - TryEnsureCecSubscription(); - } - - /// - /// Subscribes to the CEC change event once is available. - /// Safe to call repeatedly; the subscription is only wired a single time. - /// If StreamCec is null during construction, this is retried when send methods invoke - /// this method later. - /// - void TryEnsureCecSubscription() - { - if (_cecSubscribed) - return; - - if (Port?.StreamCec == null) - { - Debug.LogMessage(LogEventLevel.Warning, this, "StreamCec is not available; CEC feedback is deferred until the device is ready"); - return; - } - Port.StreamCec.CecChange += new CecChangeEventHandler(StreamCec_CecChange); - _cecSubscribed = true; - Debug.LogMessage(LogEventLevel.Information, this, "Subscribed to CEC feedback"); } void StreamCec_CecChange(Cec cecDevice, CecEventArgs args) @@ -128,9 +104,8 @@ namespace PepperDash.Essentials.Core /// public void SendText(string text) { - if (Port?.StreamCec == null) + if (Port == null) return; - TryEnsureCecSubscription(); this.PrintSentText(text); Port.StreamCec.Send.StringValue = text; } @@ -140,9 +115,8 @@ namespace PepperDash.Essentials.Core /// public void SendBytes(byte[] bytes) { - if (Port?.StreamCec == null) + if (Port == null) return; - TryEnsureCecSubscription(); var text = Encoding.GetEncoding(28591).GetString(bytes, 0, bytes.Length); this.PrintSentBytes(bytes); Debug.LogMessage(LogEventLevel.Information, this, "Sending {0} bytes: '{1}'", bytes.Length, ComTextHelper.GetEscapedText(bytes)); diff --git a/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/IHasWirelessSharing.cs b/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/IHasWirelessSharing.cs deleted file mode 100644 index 6cd3835e..00000000 --- a/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/IHasWirelessSharing.cs +++ /dev/null @@ -1,48 +0,0 @@ -using System; - -namespace PepperDash.Essentials.Core.DeviceTypeInterfaces -{ - /// - /// Defines the contract for a wireless presentation endpoint that reports whether a wireless - /// sharing session is currently active. Implemented by platforms such as Crestron AirMedia, - /// Mersive Solstice, Barco ClickShare, Miracast/Teams receivers, etc. Allows consumers (e.g. - /// room plugins) to react to wireless sharing activity without taking a dependency on any - /// concrete device implementation. - /// - /// - /// This refers specifically to wireless screen/device mirroring, as distinct from in-call - /// content sharing on a video conference. - /// - public interface IHasWirelessSharing - { - /// - /// Reports whether a wireless sharing session is currently active (content is being presented). - /// - BoolFeedback IsSharingFeedback { get; } - - /// - /// Raised when wireless sharing starts or stops. The event args carry the new sharing state. - /// - event EventHandler SharingChanged; - } - - /// - /// Event arguments describing a change in wireless sharing state. - /// - public class WirelessSharingEventArgs : EventArgs - { - /// - /// True if a wireless sharing session is active (content is being presented), false otherwise. - /// - public bool IsSharing { get; private set; } - - /// - /// Creates a new . - /// - /// True if a wireless sharing session is active, false otherwise. - public WirelessSharingEventArgs(bool isSharing) - { - IsSharing = isSharing; - } - } -} diff --git a/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/INetworkSwitchControl.cs b/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/INetworkSwitchControl.cs deleted file mode 100644 index 6c6e5598..00000000 --- a/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/INetworkSwitchControl.cs +++ /dev/null @@ -1,122 +0,0 @@ -using System; - -namespace PepperDash.Essentials.Core.DeviceTypeInterfaces -{ - /// - /// Interface for network switches that support VLAN assignment on individual ports. - /// - public interface INetworkSwitchVlanManager - { - /// - /// Returns the current access VLAN ID configured on the port. - /// Return -1 when the value is unavailable (e.g. the switch has not been polled yet - /// or the implementation does not support VLAN queries). - /// - /// Switch port identifier - /// VLAN ID or -1 when unavailable - int GetPortCurrentVlan(string port); - - /// - /// Changes the access VLAN of a single switch port. - /// The implementation is responsible for entering/exiting privileged/config mode. - /// - /// Switch port identifier (e.g. "1/0/3" for Netgear, "gi1/0/3" for Cisco) - /// Target VLAN ID (1-4093) - void SetPortVlan(string port, uint vlanId); - } - - /// - /// Interface for network switches that support Power over Ethernet (PoE) control on individual ports. - /// - public interface INetworkSwitchPoeManager - { - /// - /// Enables or disables PoE power delivery on a single switch port. - /// The implementation is responsible for entering/exiting privileged/config mode. - /// - /// Switch port identifier - /// True to enable PoE; false to disable PoE - void SetPortPoeState(string port, bool enabled); - } - - /// - /// Standardized interface for network switch devices that support per-port PoE control - /// and VLAN assignment. - /// - public interface INetworkSwitchPoeVlanManager : INetworkSwitchVlanManager, INetworkSwitchPoeManager - { - /// - /// Event that is raised when the state of a switch port changes, such as a VLAN change or PoE state change. - /// - event EventHandler PortStateChanged; - - } - - /// - /// Event arguments for port state changes on a network switch, such as VLAN changes or PoE state changes. - /// - public class NetworkSwitchPortEventArgs : EventArgs - { - /// - /// The identifier of the port that changed state (e.g. "1/0/3" for Netgear, "gi1/0/3" for Cisco). - /// - public string Port { get; private set; } - - /// - /// The type of event that occurred on the port (e.g. VLAN change, PoE enabled/disabled). - /// - public NetworkSwitchPortEventType EventType { get; private set; } - - /// - /// Constructor for NetworkSwitchPortEventArgs - /// - /// The identifier of the port that changed state - /// The type of event that occurred on the port - public NetworkSwitchPortEventArgs(string port, NetworkSwitchPortEventType eventType) - { - Port = port; - EventType = eventType; - } - } - - /// - /// Enumeration of network switch port state change event types (e.g. VLAN changes or PoE state changes). - /// - public enum NetworkSwitchPortEventType - { - /// - /// Indicates that the type of event is unknown or cannot be determined. - /// - Unknown, - - /// - /// Indicates that a VLAN change is in progress on the port, either through a call to SetPortVlan or an external change detected by polling. - /// - VlanChangeInProgress, - - /// - /// Indicates that the access VLAN on a port has changed, either through a successful call to SetPortVlan or an external change detected by polling. - /// - VlanChanged, - - /// - /// Indicates that PoE is being disabled on the port, either through a call to SetPortPoeState or an external change detected by polling. - /// - PoeDisableInProgress, - - /// - /// Indicates that PoE has been disabled on the port, either through a successful call to SetPortPoeState or an external change detected by polling. - /// - PoEDisabled, - - /// - /// Indicates that PoE is being enabled on the port, either through a call to SetPortPoeState or an external change detected by polling. - /// - PoeEnableInProgress, - - /// - /// Indicates that PoE has been enabled on the port, either through a successful call to SetPortPoeState or an external change detected by polling. - /// - PoEEnabled - } -} diff --git a/src/PepperDash.Essentials.Core/Devices/IHasDspPresetSave.cs b/src/PepperDash.Essentials.Core/Devices/IHasDspPresetSave.cs deleted file mode 100644 index c628129e..00000000 --- a/src/PepperDash.Essentials.Core/Devices/IHasDspPresetSave.cs +++ /dev/null @@ -1,14 +0,0 @@ -namespace PepperDash.Essentials.Core -{ - /// - /// Defines the contract for IHasDspPresetSave - /// - public interface IHasDspPresetSave : IDspPresets - { - /// - /// Saves the preset by key - /// - /// key of preset to save - void SavePreset(string key); - } -} \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/PepperDash.Essentials.Core.csproj b/src/PepperDash.Essentials.Core/PepperDash.Essentials.Core.csproj index b7f333bd..251ba316 100644 --- a/src/PepperDash.Essentials.Core/PepperDash.Essentials.Core.csproj +++ b/src/PepperDash.Essentials.Core/PepperDash.Essentials.Core.csproj @@ -25,7 +25,7 @@ bin\$(Configuration)\PepperDash_Essentials_Core.xml - + diff --git a/src/PepperDash.Essentials.Core/Routing/Extensions.cs b/src/PepperDash.Essentials.Core/Routing/Extensions.cs index 303a0194..9b9c458e 100644 --- a/src/PepperDash.Essentials.Core/Routing/Extensions.cs +++ b/src/PepperDash.Essentials.Core/Routing/Extensions.cs @@ -343,14 +343,12 @@ namespace PepperDash.Essentials.Core IndexTieLines(); } - var sinks = DeviceManager.AllDevices.OfType() - .Where(d => !(d is IRoutingInputsOutputs)).ToList(); - var sources = DeviceManager.AllDevices.OfType() - .Where(d => !(d is IRoutingInputsOutputs)).ToList(); + var sinks = DeviceManager.AllDevices.OfType(); + var sources = DeviceManager.AllDevices.OfType(); - foreach (var sink in sinks) + foreach (var sink in sinks.Where(d => !(d is IRoutingInputsOutputs))) { - foreach (var source in sources) + foreach (var source in sources.Where(d => !(d is IRoutingInputsOutputs))) { foreach (var inputPort in sink.InputPorts) { @@ -375,10 +373,6 @@ namespace PepperDash.Essentials.Core continue; } - Debug.LogVerbose("Route mapped: {source} -> {sink} via {input}/{output}, type {type}", - source.Key, sink.Key, - inputPort.Key, outputPort.Key, audioOrSingleRoute.SignalType); - // Add to the appropriate collection(s) based on signal type // Note: A single route descriptor with combined flags (e.g., AudioVideo) will be added once per matching signal type if (audioOrSingleRoute.SignalType.HasFlag(eRoutingSignalType.Audio)) @@ -410,10 +404,6 @@ namespace PepperDash.Essentials.Core continue; } - Debug.LogVerbose("Video route mapped: {source} -> {sink} via {input}/{output}", - source.Key, sink.Key, - inputPort.Key, outputPort.Key); - RouteDescriptors[eRoutingSignalType.Video].AddRouteDescriptor(videoRoute); } } @@ -619,12 +609,10 @@ namespace PepperDash.Essentials.Core // No direct tie? Run back out on the inputs' attached devices... // Only the ones that are routing devices - var midpointTieLines = destinationTieLines - .Where(t => t.SourcePort.ParentDevice is IRoutingInputsOutputs) - .ToList(); + var midpointTieLines = destinationTieLines.Where(t => t.SourcePort.ParentDevice is IRoutingInputsOutputs); + + Debug.LogVerbose(destination, "Found {tieLineCount} tie lines to walk for {destinationKey}", midpointTieLines.Count(), destination.Key); - Debug.LogVerbose(destination, "Found {tieLineCount} tie lines to walk for {destinationKey}", midpointTieLines.Count, destination.Key); - //Create a list for tracking already checked devices to avoid loops, if it doesn't already exist from previous iteration if (alreadyCheckedDevices == null) alreadyCheckedDevices = new List(); diff --git a/src/PepperDash.Essentials.Core/Web/RequestHandlers/GetFeedbacksForDeviceRequestHandler.cs b/src/PepperDash.Essentials.Core/Web/RequestHandlers/GetFeedbacksForDeviceRequestHandler.cs index 9831fa91..ca9eeb81 100644 --- a/src/PepperDash.Essentials.Core/Web/RequestHandlers/GetFeedbacksForDeviceRequestHandler.cs +++ b/src/PepperDash.Essentials.Core/Web/RequestHandlers/GetFeedbacksForDeviceRequestHandler.cs @@ -1,14 +1,13 @@ -using System; -using System.Linq; +using System.Linq; using Crestron.SimplSharp.WebScripting; using Newtonsoft.Json; using PepperDash.Core.Web.RequestHandlers; namespace PepperDash.Essentials.Core.Web.RequestHandlers { - /// - /// Represents a GetFeedbacksForDeviceRequestHandler - /// + /// + /// Represents a GetFeedbacksForDeviceRequestHandler + /// public class GetFeedbacksForDeviceRequestHandler : WebApiBaseRequestHandler { /// @@ -77,7 +76,7 @@ namespace PepperDash.Essentials.Core.Web.RequestHandlers Value = feedback.IntValue }; - var stringFeedback = + var stringFeedback = from feedback in device.Feedbacks.OfType() where !string.IsNullOrEmpty(feedback.Key) select new diff --git a/src/PepperDash.Essentials.Devices.Common/Displays/ScreenLiftController.cs b/src/PepperDash.Essentials.Devices.Common/Displays/ScreenLiftController.cs index d542f52a..80c1f8ee 100644 --- a/src/PepperDash.Essentials.Devices.Common/Displays/ScreenLiftController.cs +++ b/src/PepperDash.Essentials.Devices.Common/Displays/ScreenLiftController.cs @@ -152,15 +152,6 @@ namespace PepperDash.Essentials.Devices.Common.Shades private void IsCoolingDownFeedback_OutputChange(object sender, FeedbackEventArgs e) { - if (Config.DisableAutoRaiseOnPowerOff) - { - this.LogDebug( - "Auto-raise on power-off disabled for {type}; leaving position unchanged (manual control only)", - Type - ); - return; - } - if ( !DisplayDevice.IsCoolingDownFeedback.BoolValue && Type == eScreenLiftControlType.lift @@ -183,15 +174,6 @@ namespace PepperDash.Essentials.Devices.Common.Shades { if (DisplayDevice.IsWarmingUpFeedback.BoolValue) { - if (Config.DisableAutoLowerOnPowerOn) - { - this.LogDebug( - "Auto-lower on power-on disabled for {type}; leaving position unchanged (manual control only)", - Type - ); - return; - } - Lower(); } } diff --git a/src/PepperDash.Essentials.Devices.Common/Displays/ScreenLiftControllerConfigProperties.cs b/src/PepperDash.Essentials.Devices.Common/Displays/ScreenLiftControllerConfigProperties.cs index 88113a08..1c4f9906 100644 --- a/src/PepperDash.Essentials.Devices.Common/Displays/ScreenLiftControllerConfigProperties.cs +++ b/src/PepperDash.Essentials.Devices.Common/Displays/ScreenLiftControllerConfigProperties.cs @@ -41,23 +41,5 @@ namespace PepperDash.Essentials.Devices.Common.Shades /// [JsonProperty("muteOnScreenUp")] public bool MuteOnScreenUp { get; set; } - - /// - /// When true, this controller does NOT automatically lower when its assigned display powers on - /// (warms up). Manual Raise/Lower still work, and the power-off auto-raise is unaffected. Intended - /// for a projector screen that must not auto-drop in a public space for safety, while the projector - /// lift (a separate controller) can still drop automatically. - /// - [JsonProperty("disableAutoLowerOnPowerOn")] - public bool DisableAutoLowerOnPowerOn { get; set; } - - /// - /// When true, this controller does NOT automatically raise when its assigned display powers off - /// (cools down). Manual Raise/Lower still work, and the power-on auto-lower is unaffected. The - /// companion to ; together they make a controller fully - /// manual while leaving other controllers (e.g. the lift) on their default automatic behavior. - /// - [JsonProperty("disableAutoRaiseOnPowerOff")] - public bool DisableAutoRaiseOnPowerOff { get; set; } } } diff --git a/src/PepperDash.Essentials.Devices.Common/PepperDash.Essentials.Devices.Common.csproj b/src/PepperDash.Essentials.Devices.Common/PepperDash.Essentials.Devices.Common.csproj index 317fa2d3..7be4372d 100644 --- a/src/PepperDash.Essentials.Devices.Common/PepperDash.Essentials.Devices.Common.csproj +++ b/src/PepperDash.Essentials.Devices.Common/PepperDash.Essentials.Devices.Common.csproj @@ -29,6 +29,6 @@ - + \ No newline at end of file diff --git a/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/DeviceMessageBase.cs b/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/DeviceMessageBase.cs index 0198df2f..54a6ec36 100644 --- a/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/DeviceMessageBase.cs +++ b/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/DeviceMessageBase.cs @@ -10,7 +10,7 @@ namespace PepperDash.Essentials.AppServer.Messengers /// /// The device key /// - [JsonProperty("key", NullValueHandling = NullValueHandling.Ignore)] + [JsonProperty("key")] /// /// Gets or sets the Key /// @@ -19,19 +19,19 @@ namespace PepperDash.Essentials.AppServer.Messengers /// /// The device name /// - [JsonProperty("name", NullValueHandling = NullValueHandling.Ignore)] + [JsonProperty("name")] public string Name { get; set; } /// /// The type of the message class /// - [JsonProperty("messageType", NullValueHandling = NullValueHandling.Ignore)] + [JsonProperty("messageType")] public string MessageType => GetType().Name; /// /// Gets or sets the MessageBasePath /// - [JsonProperty("messageBasePath", NullValueHandling = NullValueHandling.Ignore)] + [JsonProperty("messageBasePath")] public string MessageBasePath { get; set; } } diff --git a/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/DeviceStateMessageBase.cs b/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/DeviceStateMessageBase.cs index c5c0ab65..a5df51a8 100644 --- a/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/DeviceStateMessageBase.cs +++ b/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/DeviceStateMessageBase.cs @@ -12,8 +12,7 @@ namespace PepperDash.Essentials.AppServer.Messengers /// /// The interfaces implmented by the device sending the messsage /// - [JsonProperty("interfaces", NullValueHandling = NullValueHandling.Ignore)] - [Obsolete("Interfaces are no longer supported and will be removed in a future release. Interfaces for all devices are now retrieved via the /joinroom endpoint in the MobileControlWebsocketServer")] + [JsonProperty("interfaces")] public List Interfaces { get; private set; } /// diff --git a/src/PepperDash.Essentials.MobileControl.Messengers/PepperDash.Essentials.MobileControl.Messengers.csproj b/src/PepperDash.Essentials.MobileControl.Messengers/PepperDash.Essentials.MobileControl.Messengers.csproj index a9223061..d13d1a09 100644 --- a/src/PepperDash.Essentials.MobileControl.Messengers/PepperDash.Essentials.MobileControl.Messengers.csproj +++ b/src/PepperDash.Essentials.MobileControl.Messengers/PepperDash.Essentials.MobileControl.Messengers.csproj @@ -33,7 +33,7 @@ - + diff --git a/src/PepperDash.Essentials.MobileControl/PepperDash.Essentials.MobileControl.csproj b/src/PepperDash.Essentials.MobileControl/PepperDash.Essentials.MobileControl.csproj index b0e2dd9f..235e0899 100644 --- a/src/PepperDash.Essentials.MobileControl/PepperDash.Essentials.MobileControl.csproj +++ b/src/PepperDash.Essentials.MobileControl/PepperDash.Essentials.MobileControl.csproj @@ -38,7 +38,7 @@ - + diff --git a/src/PepperDash.Essentials.MobileControl/Touchpanel/MobileControlTouchpanelController.cs b/src/PepperDash.Essentials.MobileControl/Touchpanel/MobileControlTouchpanelController.cs index 262cb34e..5830782d 100644 --- a/src/PepperDash.Essentials.MobileControl/Touchpanel/MobileControlTouchpanelController.cs +++ b/src/PepperDash.Essentials.MobileControl/Touchpanel/MobileControlTouchpanelController.cs @@ -25,28 +25,11 @@ namespace PepperDash.Essentials.Touchpanel /// Mobile Control touchpanel controller that provides app control, Zoom integration, /// and mobile control functionality for Crestron touchpanels. /// - public class MobileControlTouchpanelController : TouchpanelBase, IHasFeedback, ITswAppControl, ITswZoomControl, IDeviceInfoProvider, IMobileControlCrestronTouchpanelController, ITheme, ICommunicationMonitor + public class MobileControlTouchpanelController : TouchpanelBase, IHasFeedback, ITswAppControl, ITswZoomControl, IDeviceInfoProvider, IMobileControlCrestronTouchpanelController, ITheme { private readonly MobileControlTouchpanelProperties localConfig; private IMobileControlRoomMessenger _bridge; - /// - /// Gets the CommunicationMonitor tracking the panel's online/offline state - /// - public StatusMonitorBase CommunicationMonitor { get; private set; } - - private sealed class NullCommunicationMonitor : StatusMonitorBase - { - public NullCommunicationMonitor(IKeyed parent) : base(parent, 120000, 300000) - { - Status = MonitorStatus.InError; - Message = "Panel is not initialized"; - } - - public override void Start() { } - public override void Stop() { } - } - private string _appUrl; /// @@ -145,11 +128,6 @@ namespace PepperDash.Essentials.Touchpanel { localConfig = config; - if (panel != null) - { - CommunicationMonitor = new CrestronGenericBaseCommunicationMonitor(this, panel, 120000, 300000); - } - AddPostActivationAction(SubscribeForMobileControlUpdates); ThemeFeedback = new StringFeedback($"{Key}-theme", () => Theme); @@ -388,8 +366,6 @@ namespace PepperDash.Essentials.Touchpanel /// public override bool CustomActivate() { - CommunicationMonitor?.Start(); - var appMessenger = new ITswAppControlMessenger($"appControlMessenger-{Key}", $"/device/{Key}", this); var zoomMessenger = new ITswZoomControlMessenger($"zoomControlMessenger-{Key}", $"/device/{Key}", this); @@ -417,17 +393,6 @@ namespace PepperDash.Essentials.Touchpanel return base.CustomActivate(); } - /// - /// Stops the CommunicationMonitor on deactivation. - /// - /// True if deactivation was successful; otherwise, false. - public override bool Deactivate() - { - CommunicationMonitor?.Stop(); - - return base.Deactivate(); - } - /// /// Handles device extender signal changes for system reserved signals. /// @@ -554,8 +519,15 @@ namespace PepperDash.Essentials.Touchpanel return false; }) ? csIpAddress.ToString() : processorIp; - // replace the host but preserve whatever scheme (http/https) is already present in the URL - var updatedUrl = Regex.Replace(url, @"^(https?)://[^:/]+", $"$1://{ip}"); + var match = Regex.Match(url, @"^http://([^:/]+):\d+/mc/app\?token=.+$"); + if (match.Success) + { + string ipa = match.Groups[1].Value; + // ip will be "192.168.1.100" + } + + // replace ipa with ip but leave the rest of the string intact + var updatedUrl = Regex.Replace(url, @"^http://[^:/]+", $"http://{ip}"); this.LogVerbose("Updated URL: {updatedUrl}", updatedUrl); @@ -768,7 +740,7 @@ namespace PepperDash.Essentials.Touchpanel /// public MobileControlTouchpanelControllerFactory() { - TypeNames = new List() { "mccrestronapp", "mctsw550", "mctsw750", "mctsw1050", "mctsw560", "mctsw760", "mctsw1060", "mctsw570", "mctsw770", "mcts770", "mctsw1070", "mcts1070", "mctsw1080", "mcts1080", "mcxpanel", "mcdge1000" }; + TypeNames = new List() { "mccrestronapp", "mctsw550", "mctsw750", "mctsw1050", "mctsw560", "mctsw760", "mctsw1060", "mctsw570", "mctsw770", "mcts770", "mctsw1070", "mcts1070", "mcxpanel", "mcdge1000" }; MinimumEssentialsFrameworkVersion = "2.0.0"; factories = new Dictionary> @@ -793,8 +765,6 @@ namespace PepperDash.Essentials.Touchpanel {"ts770", (id, controlSystem, projectName) => new Ts770(id, controlSystem)}, {"tsw1070", (id, controlSystem, projectName) => new Tsw1070(id, controlSystem)}, {"ts1070", (id, controlSystem, projectName) => new Ts1070(id, controlSystem)}, - {"tsw1080", (id, controlSystem, projectName) => new Tsw1080(id, controlSystem)}, - {"ts1080", (id, controlSystem, projectName) => new Ts1080(id, controlSystem)}, {"dge1000", (id, controlSystem, projectName) => new Dge1000(id, controlSystem)} }; } diff --git a/src/PepperDash.Essentials.MobileControl/WebSocketServer/MobileControlWebsocketServer.cs b/src/PepperDash.Essentials.MobileControl/WebSocketServer/MobileControlWebsocketServer.cs index c96dc116..1c9ed37a 100644 --- a/src/PepperDash.Essentials.MobileControl/WebSocketServer/MobileControlWebsocketServer.cs +++ b/src/PepperDash.Essentials.MobileControl/WebSocketServer/MobileControlWebsocketServer.cs @@ -127,16 +127,6 @@ namespace PepperDash.Essentials.WebSocketServer /// public int Port { get; private set; } - /// - /// Gets the HTTP scheme to use for generated URLs, based on whether the direct server is configured as secure - /// - private string HttpScheme => _parent.Config.DirectServer.Secure ? "https" : "http"; - - /// - /// Gets the WebSocket scheme to use for generated URLs, based on whether the direct server is configured as secure - /// - private string WsScheme => _parent.Config.DirectServer.Secure ? "wss" : "ws"; - /// /// Gets the user app URL prefix /// @@ -144,8 +134,7 @@ namespace PepperDash.Essentials.WebSocketServer { get { - return string.Format("{0}://{1}:{2}{3}?token=", - HttpScheme, + return string.Format("http://{0}:{1}{2}?token=", CrestronEthernetHelper.GetEthernetParameter(CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_CURRENT_IP_ADDRESS, 0), Port, _userAppBaseHref); @@ -284,7 +273,7 @@ namespace PepperDash.Essentials.WebSocketServer { base.Initialize(); - _server = new HttpServer(Port, _parent.Config.DirectServer.Secure); + _server = new HttpServer(Port, false); _server.OnGet += Server_OnGet; @@ -302,7 +291,7 @@ namespace PepperDash.Essentials.WebSocketServer { ClientCertificateRequired = false, CheckCertificateRevocation = false, - EnabledSslProtocols = SslProtocols.Tls12 + EnabledSslProtocols = SslProtocols.Tls12 | SslProtocols.Tls11 }; } @@ -414,11 +403,11 @@ namespace PepperDash.Essentials.WebSocketServer ip = csIpAddress.ToString(); } - var appUrl = $"{HttpScheme}://{ip}:{Port}/mc/app?token={touchpanel.Key}"; + var appUrl = $"http://{ip}:{_parent.Config.DirectServer.Port}/mc/app?token={touchpanel.Key}"; this.LogVerbose("Sending URL {appUrl} to touchpanel {touchpanelKey}", appUrl, touchpanel.Touchpanel.Key); - touchpanel.Touchpanel.SetAppUrl(appUrl); + touchpanel.Touchpanel.SetAppUrl($"http://{ip}:{_parent.Config.DirectServer.Port}/mc/app?token={touchpanel.Key}"); } } @@ -498,7 +487,7 @@ namespace PepperDash.Essentials.WebSocketServer { var config = new MobileControlApplicationConfig { - ApiPath = string.Format("{0}://{1}:{2}/mc/api", HttpScheme, processorIp, Port), + 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, @@ -1109,7 +1098,6 @@ namespace PepperDash.Essentials.WebSocketServer res.StatusCode = 200; res.Close(); - // remote log collector has no dedicated secure flag; keep it on http regardless of DirectServer.Secure var logRequest = new HttpRequestMessage(HttpMethod.Post, $"http://{_parent.Config.DirectServer.Logging.Host}:{_parent.Config.DirectServer.Logging.Port}/logs") { Content = new StringContent(body, Encoding.UTF8, "application/json"), @@ -1162,11 +1150,6 @@ namespace PepperDash.Essentials.WebSocketServer var qp = req.QueryString; var token = qp["token"]; - // Each join mints a single-use clientId; the panel webview must never replay a cached - // response, or it reconnects forever with an already-consumed id (1008 loop). - res.Headers.Add("Cache-Control", "no-store"); - res.Headers.Add("Pragma", "no-cache"); - this.LogVerbose("Join Room Request with token: {token}", token); byte[] body; @@ -1230,7 +1213,8 @@ namespace PepperDash.Essentials.WebSocketServer this.LogVerbose("Assigning ClientId: {clientId} for token: {token} at {timestamp}", clientId, token, now); // Construct WebSocket URL with clientId query parameter - var wsUrl = $"{WsScheme}://{CrestronEthernetHelper.GetEthernetParameter(CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_CURRENT_IP_ADDRESS, 0)}:{Port}{_wsPath}{token}?clientId={clientId}"; + var wsProtocol = "ws"; + var wsUrl = $"{wsProtocol}://{CrestronEthernetHelper.GetEthernetParameter(CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_CURRENT_IP_ADDRESS, 0)}:{Port}{_wsPath}{token}?clientId={clientId}"; // Construct the response object JoinResponse jRes = new JoinResponse @@ -1242,8 +1226,7 @@ namespace PepperDash.Essentials.WebSocketServer Config = _parent.GetConfigWithPluginVersion(), CodeExpires = new DateTime().AddYears(1), UserCode = bridge.UserCode, - UserAppUrl = string.Format("{0}://{1}:{2}/mc/app", - HttpScheme, + UserAppUrl = string.Format("http://{0}:{1}/mc/app", CrestronEthernetHelper.GetEthernetParameter(CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_CURRENT_IP_ADDRESS, 0), Port), WebSocketUrl = wsUrl, @@ -1268,8 +1251,6 @@ namespace PepperDash.Essentials.WebSocketServer { res.StatusCode = 200; res.ContentType = "application/json"; - res.Headers.Add("Cache-Control", "no-store"); - res.Headers.Add("Pragma", "no-cache"); var version = new Version() { ServerVersion = _parent.GetConfigWithPluginVersion().RuntimeInfo.PluginVersion }; var message = JsonConvert.SerializeObject(version); this.LogVerbose("{message}", message); diff --git a/src/PepperDash.Essentials/PepperDash.Essentials.csproj b/src/PepperDash.Essentials/PepperDash.Essentials.csproj index cb83bf84..20a42ffd 100644 --- a/src/PepperDash.Essentials/PepperDash.Essentials.csproj +++ b/src/PepperDash.Essentials/PepperDash.Essentials.csproj @@ -48,7 +48,7 @@ - +