|
|
|
|
@@ -1,22 +1,19 @@
|
|
|
|
|
using Org.BouncyCastle.Crypto.Prng;
|
|
|
|
|
using PepperDash.Core;
|
|
|
|
|
using PepperDash.Core;
|
|
|
|
|
using PepperDash.Essentials.Core.Config;
|
|
|
|
|
using System;
|
|
|
|
|
using System.Collections;
|
|
|
|
|
using System.Collections.Generic;
|
|
|
|
|
using System.Linq;
|
|
|
|
|
using System.Reflection;
|
|
|
|
|
|
|
|
|
|
namespace PepperDash.Essentials.Core.Routing
|
|
|
|
|
{
|
|
|
|
|
public class RoutingFeedbackManager:EssentialsDevice
|
|
|
|
|
{
|
|
|
|
|
public RoutingFeedbackManager(string key, string name): base(key, name)
|
|
|
|
|
{
|
|
|
|
|
AddPostActivationAction(SubscribeForMidpointFeedback);
|
|
|
|
|
AddPostActivationAction(SubscribeForSinkFeedback);
|
|
|
|
|
{
|
|
|
|
|
AddPreActivationAction(SubscribeForMidpointFeedback);
|
|
|
|
|
AddPreActivationAction(SubscribeForSinkFeedback);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private void SubscribeForMidpointFeedback()
|
|
|
|
|
{
|
|
|
|
|
var midpointDevices = DeviceManager.AllDevices.OfType<IRoutingWithFeedback>();
|
|
|
|
|
@@ -39,11 +36,18 @@ namespace PepperDash.Essentials.Core.Routing
|
|
|
|
|
|
|
|
|
|
private void HandleMidpointUpdate(IRoutingWithFeedback midpoint, RouteSwitchDescriptor newRoute)
|
|
|
|
|
{
|
|
|
|
|
var devices = DeviceManager.AllDevices.OfType<IRoutingSinkWithSwitching>();
|
|
|
|
|
|
|
|
|
|
foreach(var device in devices)
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
UpdateDestination(device, device.CurrentInputPort);
|
|
|
|
|
var devices = DeviceManager.AllDevices.OfType<IRoutingSinkWithSwitching>();
|
|
|
|
|
|
|
|
|
|
foreach (var device in devices)
|
|
|
|
|
{
|
|
|
|
|
UpdateDestination(device, device.CurrentInputPort);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
catch (Exception ex)
|
|
|
|
|
{
|
|
|
|
|
Debug.LogMessage(ex, "Error handling midpoint update from {midpointKey}:{Exception}", this, midpoint.Key, ex);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@@ -60,30 +64,68 @@ namespace PepperDash.Essentials.Core.Routing
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void UpdateDestination(IRoutingSinkWithSwitching destination, RoutingInputPort inputPort)
|
|
|
|
|
{
|
|
|
|
|
var tieLines = TieLineCollection.Default;
|
|
|
|
|
{
|
|
|
|
|
Debug.LogMessage(Serilog.Events.LogEventLevel.Verbose, "Updating destination {destination} with inputPort {inputPort}", this,destination?.Key, inputPort?.Key);
|
|
|
|
|
|
|
|
|
|
var firstTieLine = tieLines.FirstOrDefault(tl => tl.DestinationPort.Key == inputPort.Key);
|
|
|
|
|
|
|
|
|
|
if (firstTieLine == null)
|
|
|
|
|
if(inputPort == null)
|
|
|
|
|
{
|
|
|
|
|
Debug.LogMessage(Serilog.Events.LogEventLevel.Information, "No tieline found for inputPort {inputPort}. Clearing current source", this, inputPort);
|
|
|
|
|
Debug.LogMessage(Serilog.Events.LogEventLevel.Warning, "Destination {destination} has not reported an input port yet", this,destination.Key);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
destination.CurrentSourceInfo = null;
|
|
|
|
|
destination.CurrentSourceInfoKey = string.Empty;
|
|
|
|
|
TieLine firstTieLine;
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
var tieLines = TieLineCollection.Default;
|
|
|
|
|
|
|
|
|
|
firstTieLine = tieLines.FirstOrDefault(tl => tl.DestinationPort.Key == inputPort.Key && tl.DestinationPort.ParentDevice.Key == inputPort.ParentDevice.Key);
|
|
|
|
|
|
|
|
|
|
if (firstTieLine == null)
|
|
|
|
|
{
|
|
|
|
|
Debug.LogMessage(Serilog.Events.LogEventLevel.Information, "No tieline found for inputPort {inputPort}. Clearing current source", this, inputPort);
|
|
|
|
|
|
|
|
|
|
var tempSourceListItem = new SourceListItem
|
|
|
|
|
{
|
|
|
|
|
SourceKey = "$transient",
|
|
|
|
|
Name = inputPort.Key,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
destination.CurrentSourceInfo = tempSourceListItem; ;
|
|
|
|
|
destination.CurrentSourceInfoKey = "$transient";
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
} catch (Exception ex)
|
|
|
|
|
{
|
|
|
|
|
Debug.LogMessage(ex, "Error getting first tieline: {Exception}", this, ex);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Debug.LogMessage(Serilog.Events.LogEventLevel.Verbose, "Getting source for first TieLine {tieLine}", this, firstTieLine);
|
|
|
|
|
|
|
|
|
|
var sourceTieLine = GetRootTieLine(firstTieLine);
|
|
|
|
|
|
|
|
|
|
if (sourceTieLine == null)
|
|
|
|
|
TieLine sourceTieLine;
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
Debug.LogMessage(Serilog.Events.LogEventLevel.Information, "No route found to source for inputPort {inputPort}. Clearing current source", this, inputPort);
|
|
|
|
|
sourceTieLine = GetRootTieLine(firstTieLine);
|
|
|
|
|
|
|
|
|
|
destination.CurrentSourceInfo = null;
|
|
|
|
|
destination.CurrentSourceInfoKey = string.Empty;
|
|
|
|
|
if (sourceTieLine == null)
|
|
|
|
|
{
|
|
|
|
|
Debug.LogMessage(Serilog.Events.LogEventLevel.Information, "No route found to source for inputPort {inputPort}. Clearing current source", this, inputPort);
|
|
|
|
|
|
|
|
|
|
var tempSourceListItem = new SourceListItem
|
|
|
|
|
{
|
|
|
|
|
SourceKey = "$transient",
|
|
|
|
|
Name = "None",
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
destination.CurrentSourceInfo = tempSourceListItem;
|
|
|
|
|
destination.CurrentSourceInfoKey = string.Empty;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
} catch(Exception ex)
|
|
|
|
|
{
|
|
|
|
|
Debug.LogMessage(ex, "Error getting sourceTieLine: {Exception}", this, ex);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Debug.LogMessage(Serilog.Events.LogEventLevel.Verbose, "Found root TieLine {tieLine}", this, sourceTieLine);
|
|
|
|
|
@@ -136,10 +178,16 @@ namespace PepperDash.Essentials.Core.Routing
|
|
|
|
|
|
|
|
|
|
if (source == null)
|
|
|
|
|
{
|
|
|
|
|
Debug.LogMessage(Serilog.Events.LogEventLevel.Information, "No source found for device {key}. Clearing current source on {destination}", this, sourceTieLine.SourcePort.ParentDevice.Key, destination);
|
|
|
|
|
Debug.LogMessage(Serilog.Events.LogEventLevel.Information, "No source found for device {key}. Creating transient source for {destination}", this, sourceTieLine.SourcePort.ParentDevice.Key, destination);
|
|
|
|
|
|
|
|
|
|
destination.CurrentSourceInfo = null;
|
|
|
|
|
destination.CurrentSourceInfoKey = string.Empty;
|
|
|
|
|
var tempSourceListItem = new SourceListItem
|
|
|
|
|
{
|
|
|
|
|
SourceKey = "$transient",
|
|
|
|
|
Name = sourceTieLine.SourcePort.Key,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
destination.CurrentSourceInfo = tempSourceListItem; ;
|
|
|
|
|
destination.CurrentSourceInfoKey = "$transient";
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@@ -152,43 +200,67 @@ namespace PepperDash.Essentials.Core.Routing
|
|
|
|
|
private TieLine GetRootTieLine(TieLine tieLine)
|
|
|
|
|
{
|
|
|
|
|
TieLine nextTieLine = null;
|
|
|
|
|
|
|
|
|
|
if(tieLine.SourcePort.ParentDevice is IRoutingWithFeedback midpoint)
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
Debug.LogMessage(Serilog.Events.LogEventLevel.Verbose, "TieLine Source device is midpoint", this);
|
|
|
|
|
Debug.LogMessage(Serilog.Events.LogEventLevel.Verbose, "**Following tieLine {tieLine}**", this, tieLine);
|
|
|
|
|
|
|
|
|
|
var currentRoute = midpoint.CurrentRoutes.FirstOrDefault(route => route.OutputPort.Key == tieLine.SourcePort.Key);
|
|
|
|
|
|
|
|
|
|
if(currentRoute == null)
|
|
|
|
|
if (tieLine.SourcePort.ParentDevice is IRoutingWithFeedback midpoint)
|
|
|
|
|
{
|
|
|
|
|
Debug.LogMessage(Serilog.Events.LogEventLevel.Information, "No route through midpoint {midpoint} for outputPort {outputPort}", this, midpoint.Key, tieLine.SourcePort);
|
|
|
|
|
return null;
|
|
|
|
|
Debug.LogMessage(Serilog.Events.LogEventLevel.Verbose, "TieLine Source device {sourceDevice} is midpoint", this, midpoint);
|
|
|
|
|
|
|
|
|
|
if(midpoint.CurrentRoutes == null || midpoint.CurrentRoutes.Count == 0)
|
|
|
|
|
{
|
|
|
|
|
Debug.LogMessage(Serilog.Events.LogEventLevel.Information, "Midpoint {midpointKey} has no routes",this, midpoint.Key);
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var currentRoute = midpoint.CurrentRoutes.FirstOrDefault(route => {
|
|
|
|
|
Debug.LogMessage(Serilog.Events.LogEventLevel.Verbose, "Checking {route} against {tieLine}", this, route, tieLine);
|
|
|
|
|
|
|
|
|
|
return route.OutputPort.Key == tieLine.SourcePort.Key && route.OutputPort.ParentDevice.Key == tieLine.SourcePort.ParentDevice.Key;
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
if (currentRoute == null)
|
|
|
|
|
{
|
|
|
|
|
Debug.LogMessage(Serilog.Events.LogEventLevel.Information, "No route through midpoint {midpoint} for outputPort {outputPort}", this, midpoint.Key, tieLine.SourcePort);
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Debug.LogMessage(Serilog.Events.LogEventLevel.Verbose, "Found currentRoute {currentRoute} through {midpoint}", this, currentRoute, midpoint);
|
|
|
|
|
|
|
|
|
|
nextTieLine = TieLineCollection.Default.FirstOrDefault(tl => {
|
|
|
|
|
Debug.LogMessage(Serilog.Events.LogEventLevel.Verbose, "Checking {route} against {tieLine}", tl.DestinationPort.Key, currentRoute.InputPort.Key);
|
|
|
|
|
return tl.DestinationPort.Key == currentRoute.InputPort.Key && tl.DestinationPort.ParentDevice.Key == currentRoute.InputPort.ParentDevice.Key; });
|
|
|
|
|
|
|
|
|
|
if (nextTieLine != null)
|
|
|
|
|
{
|
|
|
|
|
Debug.LogMessage(Serilog.Events.LogEventLevel.Verbose, "Found next tieLine {tieLine}. Walking the chain", this, nextTieLine);
|
|
|
|
|
return GetRootTieLine(nextTieLine);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Debug.LogMessage(Serilog.Events.LogEventLevel.Verbose, "Found root tieLine {tieLine}", this,nextTieLine);
|
|
|
|
|
return nextTieLine;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
nextTieLine = TieLineCollection.Default.FirstOrDefault(tl => tl.DestinationPort.Key == currentRoute.InputPort.Key);
|
|
|
|
|
Debug.LogMessage(Serilog.Events.LogEventLevel.Verbose, "TieLIne Source Device {sourceDeviceKey} is IRoutingSource: {isIRoutingSource}", this, tieLine.SourcePort.ParentDevice.Key, tieLine.SourcePort.ParentDevice is IRoutingSource);
|
|
|
|
|
Debug.LogMessage(Serilog.Events.LogEventLevel.Verbose, "TieLine Source Device interfaces: {typeFullName}:{interfaces}", this, tieLine.SourcePort.ParentDevice.GetType().FullName, tieLine.SourcePort.ParentDevice.GetType().GetInterfaces().Select(i => i.Name));
|
|
|
|
|
|
|
|
|
|
if(tieLine != null)
|
|
|
|
|
if (tieLine.SourcePort.ParentDevice is IRoutingSource || tieLine.SourcePort.ParentDevice is IRoutingOutputs) //end of the chain
|
|
|
|
|
{
|
|
|
|
|
Debug.LogMessage(Serilog.Events.LogEventLevel.Verbose, "Found root: {tieLine}", this, tieLine);
|
|
|
|
|
return tieLine;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
nextTieLine = TieLineCollection.Default.FirstOrDefault(tl => tl.DestinationPort.Key == tieLine.SourcePort.Key && tl.DestinationPort.ParentDevice.Key == tieLine.SourcePort.ParentDevice.Key );
|
|
|
|
|
|
|
|
|
|
if (nextTieLine != null)
|
|
|
|
|
{
|
|
|
|
|
return GetRootTieLine(nextTieLine);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return tieLine;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Debug.LogMessage(Serilog.Events.LogEventLevel.Verbose, "TieLIne Source Device {sourceDeviceKey} is IRoutingSource: {isIRoutingSource}", this,tieLine.SourcePort.ParentDevice.Key, tieLine.SourcePort.ParentDevice is IRoutingSource);
|
|
|
|
|
Debug.LogMessage(Serilog.Events.LogEventLevel.Verbose, "TieLine Source Device interfaces: {typeFullName}:{interfaces}",this, tieLine.SourcePort.ParentDevice.GetType().FullName, tieLine.SourcePort.ParentDevice.GetType().GetInterfaces().Select(i => i.Name));
|
|
|
|
|
|
|
|
|
|
if(tieLine.SourcePort.ParentDevice is IRoutingSource || tieLine.SourcePort.ParentDevice is IRoutingOutputs) //end of the chain
|
|
|
|
|
} catch (Exception ex)
|
|
|
|
|
{
|
|
|
|
|
Debug.LogMessage(Serilog.Events.LogEventLevel.Verbose, "Found root: {tieLine}", this, tieLine);
|
|
|
|
|
return tieLine;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
nextTieLine = TieLineCollection.Default.FirstOrDefault(tl => tl.SourcePort.Key == tieLine.SourcePort.Key);
|
|
|
|
|
|
|
|
|
|
if(nextTieLine != null)
|
|
|
|
|
{
|
|
|
|
|
return GetRootTieLine(nextTieLine);
|
|
|
|
|
Debug.LogMessage(ex, "Error walking tieLines: {Exception}", this, ex);
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return null;
|
|
|
|
|
|