From 34f59f14107c626e77726457211f4802c3a3f834 Mon Sep 17 00:00:00 2001 From: Andrew Welker Date: Wed, 19 Feb 2025 11:06:56 -0600 Subject: [PATCH 1/7] fix: move ReleaseRoute & RunRouteRequests to use a queue --- .../Routing/Extensions.cs | 32 ++++++++------- .../Routing/RouteRequestQueueItem.cs | 39 +++++++++++++++++++ 2 files changed, 58 insertions(+), 13 deletions(-) create mode 100644 src/PepperDash.Essentials.Core/Routing/RouteRequestQueueItem.cs diff --git a/src/PepperDash.Essentials.Core/Routing/Extensions.cs b/src/PepperDash.Essentials.Core/Routing/Extensions.cs index ee885abf..e3ba0a74 100644 --- a/src/PepperDash.Essentials.Core/Routing/Extensions.cs +++ b/src/PepperDash.Essentials.Core/Routing/Extensions.cs @@ -1,4 +1,6 @@ -using Serilog.Events; +using PepperDash.Essentials.Core.Queues; +using PepperDash.Essentials.Core.Routing; +using Serilog.Events; using System; using System.Collections.Generic; using System.Diagnostics; @@ -17,6 +19,8 @@ namespace PepperDash.Essentials.Core { private static readonly Dictionary RouteRequests = new Dictionary(); + private static readonly GenericQueue routeRequestQueue = new GenericQueue("routingQueue"); + /// /// Gets any existing RouteDescriptor for a destination, clears it using ReleaseRoute /// and then attempts a new Route and if sucessful, stores that RouteDescriptor @@ -33,6 +37,15 @@ namespace PepperDash.Essentials.Core ReleaseAndMakeRoute(destination, source, signalType, inputPort, outputPort); } + public static void ReleaseRoute(this IRoutingInputs destination) + { + routeRequestQueue.Enqueue(new ReleaseRouteQueueItem(ReleaseRouteInternal, destination, string.Empty)); + } + + public static void ReleaseRoute(this IRoutingInputs destination, string inputPortKey) + { + routeRequestQueue.Enqueue(new ReleaseRouteQueueItem(ReleaseRouteInternal, destination, inputPortKey)); + } public static void RemoveRouteRequestForDestination(string destinationKey) { @@ -59,9 +72,7 @@ namespace PepperDash.Essentials.Core Source = source, SourcePort = sourcePort, SignalType = signalType - }; - - + }; var coolingDevice = destination as IWarmingCooling; @@ -101,9 +112,9 @@ namespace PepperDash.Essentials.Core Debug.LogMessage(LogEventLevel.Information, "Device: {destination} is NOT cooling down. Removing stored route request and routing to source key: {sourceKey}", null, destination.Key, routeRequest.Source.Key); } - destination.ReleaseRoute(destinationPort?.Key ?? string.Empty); + routeRequestQueue.Enqueue(new ReleaseRouteQueueItem(ReleaseRouteInternal, destination,destinationPort?.Key ?? string.Empty)); - RunRouteRequest(routeRequest); + routeRequestQueue.Enqueue(new RouteRequestQueueItem(RunRouteRequest, routeRequest)); } private static void RunRouteRequest(RouteRequest request) @@ -133,19 +144,14 @@ namespace PepperDash.Essentials.Core { Debug.LogMessage(ex, "Exception Running Route Request {request}", null, request); } - } - - public static void ReleaseRoute(this IRoutingInputs destination) - { - ReleaseRoute(destination, string.Empty); - } + } /// /// Will release the existing route on the destination, if it is found in /// RouteDescriptorCollection.DefaultCollection /// /// - public static void ReleaseRoute(this IRoutingInputs destination, string inputPortKey) + private static void ReleaseRouteInternal(IRoutingInputs destination, string inputPortKey) { try { diff --git a/src/PepperDash.Essentials.Core/Routing/RouteRequestQueueItem.cs b/src/PepperDash.Essentials.Core/Routing/RouteRequestQueueItem.cs new file mode 100644 index 00000000..3c923eb6 --- /dev/null +++ b/src/PepperDash.Essentials.Core/Routing/RouteRequestQueueItem.cs @@ -0,0 +1,39 @@ +using PepperDash.Essentials.Core.Queues; +using System; + +namespace PepperDash.Essentials.Core.Routing +{ + public class RouteRequestQueueItem : IQueueMessage + { + private readonly Action action; + private readonly RouteRequest routeRequest; + + public RouteRequestQueueItem(Action routeAction, RouteRequest request) + { + action = routeAction; + routeRequest = request; + } + + public void Dispatch() + { + action(routeRequest); + } + } + + public class ReleaseRouteQueueItem: IQueueMessage + { + private readonly Action action; + private readonly IRoutingInputs destination; + private readonly string inputPortKey; + + public ReleaseRouteQueueItem(Action action, IRoutingInputs destination, string inputPortKey) + { + this.action = action; + this.destination = destination; + this.inputPortKey = inputPortKey; + } + + public void Dispatch() { + action(destination, inputPortKey); + } +} From d53a5607e21f91c465669aa2461b0aad3c21e0a4 Mon Sep 17 00:00:00 2001 From: Andrew Welker Date: Wed, 19 Feb 2025 11:07:41 -0600 Subject: [PATCH 2/7] chore: reorg methos in routing Extensions class --- .../Routing/Extensions.cs | 124 +++++++++--------- 1 file changed, 62 insertions(+), 62 deletions(-) diff --git a/src/PepperDash.Essentials.Core/Routing/Extensions.cs b/src/PepperDash.Essentials.Core/Routing/Extensions.cs index e3ba0a74..ae85b1de 100644 --- a/src/PepperDash.Essentials.Core/Routing/Extensions.cs +++ b/src/PepperDash.Essentials.Core/Routing/Extensions.cs @@ -58,6 +58,68 @@ namespace PepperDash.Essentials.Core Debug.LogMessage(LogEventLevel.Information, messageTemplate, null, destinationKey); } + /// + /// Builds a RouteDescriptor that contains the steps necessary to make a route between devices. + /// Routes of type AudioVideo will be built as two separate routes, audio and video. If + /// a route is discovered, a new RouteDescriptor is returned. If one or both parts + /// of an audio/video route are discovered a route descriptor is returned. If no route is + /// discovered, then null is returned + /// + public static (RouteDescriptor, RouteDescriptor) GetRouteToSource(this IRoutingInputs destination, IRoutingOutputs source, eRoutingSignalType signalType, RoutingInputPort destinationPort, RoutingOutputPort sourcePort) + { + // if it's a single signal type, find the route + if (!signalType.HasFlag(eRoutingSignalType.AudioVideo)) + { + var singleTypeRouteDescriptor = new RouteDescriptor(source, destination, destinationPort, signalType); + Debug.LogMessage(LogEventLevel.Debug, "Attempting to build source route from {sourceKey} of type {type}", destination, source.Key, signalType); + + if (!destination.GetRouteToSource(source, null, null, signalType, 0, singleTypeRouteDescriptor, destinationPort, sourcePort)) + singleTypeRouteDescriptor = null; + + var routes = singleTypeRouteDescriptor?.Routes ?? new List(); + foreach (var route in routes) + { + Debug.LogMessage(LogEventLevel.Verbose, "Route for device: {route}", destination, route.ToString()); + } + + return (singleTypeRouteDescriptor, null); + } + // otherwise, audioVideo needs to be handled as two steps. + + Debug.LogMessage(LogEventLevel.Debug, "Attempting to build source route from {sourceKey} of type {type}", destination, source.Key); + + var audioRouteDescriptor = new RouteDescriptor(source, destination, destinationPort, eRoutingSignalType.Audio); + + var audioSuccess = destination.GetRouteToSource(source, null, null, eRoutingSignalType.Audio, 0, audioRouteDescriptor, destinationPort, sourcePort); + + if (!audioSuccess) + Debug.LogMessage(LogEventLevel.Debug, "Cannot find audio route to {0}", destination, source.Key); + + var videoRouteDescriptor = new RouteDescriptor(source, destination, destinationPort, eRoutingSignalType.Video); + + var videoSuccess = destination.GetRouteToSource(source, null, null, eRoutingSignalType.Video, 0, videoRouteDescriptor, destinationPort, sourcePort); + + if (!videoSuccess) + Debug.LogMessage(LogEventLevel.Debug, "Cannot find video route to {0}", destination, source.Key); + + foreach (var route in audioRouteDescriptor.Routes) + { + Debug.LogMessage(LogEventLevel.Verbose, "Audio route for device: {route}", destination, route.ToString()); + } + + foreach (var route in videoRouteDescriptor.Routes) + { + Debug.LogMessage(LogEventLevel.Verbose, "Video route for device: {route}", destination, route.ToString()); + } + + + if (!audioSuccess && !videoSuccess) + return (null, null); + + + return (audioRouteDescriptor, videoRouteDescriptor); + } + private static void ReleaseAndMakeRoute(IRoutingInputs destination, IRoutingOutputs source, eRoutingSignalType signalType, RoutingInputPort destinationPort = null, RoutingOutputPort sourcePort = null) { if (destination == null) throw new ArgumentNullException(nameof(destination)); @@ -178,68 +240,6 @@ namespace PepperDash.Essentials.Core } } - /// - /// Builds a RouteDescriptor that contains the steps necessary to make a route between devices. - /// Routes of type AudioVideo will be built as two separate routes, audio and video. If - /// a route is discovered, a new RouteDescriptor is returned. If one or both parts - /// of an audio/video route are discovered a route descriptor is returned. If no route is - /// discovered, then null is returned - /// - public static (RouteDescriptor, RouteDescriptor) GetRouteToSource(this IRoutingInputs destination, IRoutingOutputs source, eRoutingSignalType signalType, RoutingInputPort destinationPort, RoutingOutputPort sourcePort) - { - // if it's a single signal type, find the route - if (!signalType.HasFlag(eRoutingSignalType.AudioVideo)) - { - var singleTypeRouteDescriptor = new RouteDescriptor(source, destination, destinationPort, signalType); - Debug.LogMessage(LogEventLevel.Debug, "Attempting to build source route from {sourceKey} of type {type}", destination, source.Key, signalType); - - if (!destination.GetRouteToSource(source, null, null, signalType, 0, singleTypeRouteDescriptor, destinationPort, sourcePort)) - singleTypeRouteDescriptor = null; - - var routes = singleTypeRouteDescriptor?.Routes ?? new List(); - foreach (var route in routes) - { - Debug.LogMessage(LogEventLevel.Verbose, "Route for device: {route}", destination, route.ToString()); - } - - return (singleTypeRouteDescriptor, null); - } - // otherwise, audioVideo needs to be handled as two steps. - - Debug.LogMessage(LogEventLevel.Debug, "Attempting to build source route from {sourceKey} of type {type}", destination, source.Key); - - var audioRouteDescriptor = new RouteDescriptor(source, destination, destinationPort, eRoutingSignalType.Audio); - - var audioSuccess = destination.GetRouteToSource(source, null, null, eRoutingSignalType.Audio, 0, audioRouteDescriptor, destinationPort, sourcePort); - - if (!audioSuccess) - Debug.LogMessage(LogEventLevel.Debug, "Cannot find audio route to {0}", destination, source.Key); - - var videoRouteDescriptor = new RouteDescriptor(source, destination, destinationPort, eRoutingSignalType.Video); - - var videoSuccess = destination.GetRouteToSource(source, null, null, eRoutingSignalType.Video, 0, videoRouteDescriptor, destinationPort, sourcePort); - - if (!videoSuccess) - Debug.LogMessage(LogEventLevel.Debug, "Cannot find video route to {0}", destination, source.Key); - - foreach (var route in audioRouteDescriptor.Routes) - { - Debug.LogMessage(LogEventLevel.Verbose, "Audio route for device: {route}", destination, route.ToString()); - } - - foreach (var route in videoRouteDescriptor.Routes) - { - Debug.LogMessage(LogEventLevel.Verbose, "Video route for device: {route}", destination, route.ToString()); - } - - - if (!audioSuccess && !videoSuccess) - return (null, null); - - - return (audioRouteDescriptor, videoRouteDescriptor); - } - /// /// The recursive part of this. Will stop on each device, search its inputs for the /// desired source and if not found, invoke this function for the each input port From 66cb592c70ad2da38f26272503f467a3b1ced63c Mon Sep 17 00:00:00 2001 From: Andrew Welker Date: Wed, 19 Feb 2025 11:10:35 -0600 Subject: [PATCH 3/7] chore: add missing curly brace --- .../Routing/RouteRequestQueueItem.cs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/PepperDash.Essentials.Core/Routing/RouteRequestQueueItem.cs b/src/PepperDash.Essentials.Core/Routing/RouteRequestQueueItem.cs index 3c923eb6..f1848b8b 100644 --- a/src/PepperDash.Essentials.Core/Routing/RouteRequestQueueItem.cs +++ b/src/PepperDash.Essentials.Core/Routing/RouteRequestQueueItem.cs @@ -20,7 +20,7 @@ namespace PepperDash.Essentials.Core.Routing } } - public class ReleaseRouteQueueItem: IQueueMessage + public class ReleaseRouteQueueItem : IQueueMessage { private readonly Action action; private readonly IRoutingInputs destination; @@ -33,7 +33,9 @@ namespace PepperDash.Essentials.Core.Routing this.inputPortKey = inputPortKey; } - public void Dispatch() { + public void Dispatch() + { action(destination, inputPortKey); } + } } From a055d06bc62e0d311ed48d7f11d008fc321beb03 Mon Sep 17 00:00:00 2001 From: Andrew Welker Date: Wed, 19 Feb 2025 11:18:00 -0600 Subject: [PATCH 4/7] chore: add some logging for route queue processing --- src/PepperDash.Essentials.Core/Routing/RouteRequest.cs | 5 +++++ .../Routing/RouteRequestQueueItem.cs | 6 +++++- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/src/PepperDash.Essentials.Core/Routing/RouteRequest.cs b/src/PepperDash.Essentials.Core/Routing/RouteRequest.cs index bd8a42d2..19d8655b 100644 --- a/src/PepperDash.Essentials.Core/Routing/RouteRequest.cs +++ b/src/PepperDash.Essentials.Core/Routing/RouteRequest.cs @@ -38,5 +38,10 @@ namespace PepperDash.Essentials.Core Debug.LogMessage(ex, "Exception handling cooldown", Destination); } } + + public override string ToString() + { + return $"Route {Source?.Key ?? "No Source Device"}:{SourcePort?.Key ?? "auto"} to {Destination?.Key ?? "No Destination Device"}:{DestinationPort?.Key ?? "auto"}"; + } } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Routing/RouteRequestQueueItem.cs b/src/PepperDash.Essentials.Core/Routing/RouteRequestQueueItem.cs index f1848b8b..05681991 100644 --- a/src/PepperDash.Essentials.Core/Routing/RouteRequestQueueItem.cs +++ b/src/PepperDash.Essentials.Core/Routing/RouteRequestQueueItem.cs @@ -1,5 +1,7 @@ -using PepperDash.Essentials.Core.Queues; +using PepperDash.Core; +using PepperDash.Essentials.Core.Queues; using System; +using Serilog.Events; namespace PepperDash.Essentials.Core.Routing { @@ -16,6 +18,7 @@ namespace PepperDash.Essentials.Core.Routing public void Dispatch() { + Debug.LogMessage(LogEventLevel.Information, "Dispatching route request {routeRequest}", null, routeRequest); action(routeRequest); } } @@ -35,6 +38,7 @@ namespace PepperDash.Essentials.Core.Routing public void Dispatch() { + Debug.LogMessage(LogEventLevel.Information, "Dispatching release route request for {destination}:{inputPortKey}", null, destination?.Key ?? "no destination", string.IsNullOrEmpty(inputPortKey) ? "auto" : inputPortKey); action(destination, inputPortKey); } } From e0058d8cfed7de4da5fcacee17366d383440d685 Mon Sep 17 00:00:00 2001 From: Andrew Welker Date: Wed, 19 Feb 2025 13:24:52 -0600 Subject: [PATCH 5/7] chore: update PD Core to 2.0.0-alpha-450 Updated to Renci for SSH --- .../PepperDash.Essentials.Core.csproj | 2 +- .../PepperDash.Essentials.Devices.Common.csproj | 2 +- src/PepperDash.Essentials/PepperDash.Essentials.csproj | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/PepperDash.Essentials.Core/PepperDash.Essentials.Core.csproj b/src/PepperDash.Essentials.Core/PepperDash.Essentials.Core.csproj index c074651a..ce073f06 100644 --- a/src/PepperDash.Essentials.Core/PepperDash.Essentials.Core.csproj +++ b/src/PepperDash.Essentials.Core/PepperDash.Essentials.Core.csproj @@ -26,7 +26,7 @@ - + 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 69f6d24e..8809e44d 100644 --- a/src/PepperDash.Essentials.Devices.Common/PepperDash.Essentials.Devices.Common.csproj +++ b/src/PepperDash.Essentials.Devices.Common/PepperDash.Essentials.Devices.Common.csproj @@ -30,6 +30,6 @@ - + \ No newline at end of file diff --git a/src/PepperDash.Essentials/PepperDash.Essentials.csproj b/src/PepperDash.Essentials/PepperDash.Essentials.csproj index d64846e5..0175df79 100644 --- a/src/PepperDash.Essentials/PepperDash.Essentials.csproj +++ b/src/PepperDash.Essentials/PepperDash.Essentials.csproj @@ -49,7 +49,7 @@ - + From 316867caf81066c23e6dd176018182ea10b59426 Mon Sep 17 00:00:00 2001 From: Andrew Welker Date: Wed, 19 Feb 2025 16:49:22 -0600 Subject: [PATCH 6/7] chore: update to PD Core 2.0.0-alpha-451 Catch the `SshOperationTimeoutException` and handle it differently. --- .../PepperDash.Essentials.Core.csproj | 2 +- .../PepperDash.Essentials.Devices.Common.csproj | 2 +- src/PepperDash.Essentials/PepperDash.Essentials.csproj | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/PepperDash.Essentials.Core/PepperDash.Essentials.Core.csproj b/src/PepperDash.Essentials.Core/PepperDash.Essentials.Core.csproj index ce073f06..900bfc23 100644 --- a/src/PepperDash.Essentials.Core/PepperDash.Essentials.Core.csproj +++ b/src/PepperDash.Essentials.Core/PepperDash.Essentials.Core.csproj @@ -26,7 +26,7 @@ - + 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 8809e44d..d87662fb 100644 --- a/src/PepperDash.Essentials.Devices.Common/PepperDash.Essentials.Devices.Common.csproj +++ b/src/PepperDash.Essentials.Devices.Common/PepperDash.Essentials.Devices.Common.csproj @@ -30,6 +30,6 @@ - + \ No newline at end of file diff --git a/src/PepperDash.Essentials/PepperDash.Essentials.csproj b/src/PepperDash.Essentials/PepperDash.Essentials.csproj index 0175df79..68cdf106 100644 --- a/src/PepperDash.Essentials/PepperDash.Essentials.csproj +++ b/src/PepperDash.Essentials/PepperDash.Essentials.csproj @@ -49,7 +49,7 @@ - + From 27072e34753ad5987df26ba1a74d698da4864088 Mon Sep 17 00:00:00 2001 From: Andrew Welker Date: Wed, 19 Feb 2025 17:10:18 -0600 Subject: [PATCH 7/7] fix: #1213 remove key from GenericSoftCodec routing port keys --- .../SoftCodec/GenericSoftCodec.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/PepperDash.Essentials.Devices.Common/SoftCodec/GenericSoftCodec.cs b/src/PepperDash.Essentials.Devices.Common/SoftCodec/GenericSoftCodec.cs index f623c539..7fdad9b4 100644 --- a/src/PepperDash.Essentials.Devices.Common/SoftCodec/GenericSoftCodec.cs +++ b/src/PepperDash.Essentials.Devices.Common/SoftCodec/GenericSoftCodec.cs @@ -28,14 +28,14 @@ namespace PepperDash.Essentials.Devices.Common.SoftCodec for(var i = 1; i <= props.OutputCount; i++) { - var outputPort = new RoutingOutputPort($"{Key}-output{i}", eRoutingSignalType.AudioVideo, eRoutingPortConnectionType.Hdmi, null, this); + var outputPort = new RoutingOutputPort($"output{i}", eRoutingSignalType.AudioVideo, eRoutingPortConnectionType.Hdmi, null, this); OutputPorts.Add(outputPort); } for(var i = 1; i<= props.ContentInputCount; i++) { - var inputPort = new RoutingInputPort($"{Key}-contentInput{i}", eRoutingSignalType.AudioVideo, eRoutingPortConnectionType.Hdmi, $"contentInput{i}", this); + var inputPort = new RoutingInputPort($"contentInput{i}", eRoutingSignalType.AudioVideo, eRoutingPortConnectionType.Hdmi, $"contentInput{i}", this); InputPorts.Add(inputPort); } @@ -47,7 +47,7 @@ namespace PepperDash.Essentials.Devices.Common.SoftCodec for(var i = 1; i <=props.CameraInputCount; i++) { - var cameraPort = new RoutingInputPort($"{Key}-cameraInput{i}", eRoutingSignalType.Video, eRoutingPortConnectionType.Hdmi, $"cameraInput{i}", this); + var cameraPort = new RoutingInputPort($"cameraInput{i}", eRoutingSignalType.Video, eRoutingPortConnectionType.Hdmi, $"cameraInput{i}", this); InputPorts.Add(cameraPort); }