feat: get it working

This commit is contained in:
Andrew Welker
2024-05-14 10:23:01 -05:00
parent 888f1b3888
commit 4bf026601f
12 changed files with 216 additions and 92 deletions

View File

@@ -22,10 +22,10 @@
public override string ToString() public override string ToString()
{ {
if(SwitchingDevice is IRouting) if (SwitchingDevice is IRouting)
return string.Format("{0} switches output '{1}' to input '{2}'", SwitchingDevice.Key, OutputPort.Selector, InputPort.Selector); return $"{SwitchingDevice?.Key} switches output {OutputPort.Key} to input {InputPort.Key}";
else else
return string.Format("{0} switches to input '{1}'", SwitchingDevice.Key, InputPort.Selector); return $"{SwitchingDevice.Key} switches to input {InputPort.Key}";
} }
} }

View File

@@ -1,22 +1,19 @@
using Org.BouncyCastle.Crypto.Prng; using PepperDash.Core;
using PepperDash.Core;
using PepperDash.Essentials.Core.Config; using PepperDash.Essentials.Core.Config;
using System; using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Reflection;
namespace PepperDash.Essentials.Core.Routing namespace PepperDash.Essentials.Core.Routing
{ {
public class RoutingFeedbackManager:EssentialsDevice public class RoutingFeedbackManager:EssentialsDevice
{ {
public RoutingFeedbackManager(string key, string name): base(key, name) public RoutingFeedbackManager(string key, string name): base(key, name)
{ {
AddPostActivationAction(SubscribeForMidpointFeedback); AddPreActivationAction(SubscribeForMidpointFeedback);
AddPostActivationAction(SubscribeForSinkFeedback); AddPreActivationAction(SubscribeForSinkFeedback);
} }
private void SubscribeForMidpointFeedback() private void SubscribeForMidpointFeedback()
{ {
var midpointDevices = DeviceManager.AllDevices.OfType<IRoutingWithFeedback>(); var midpointDevices = DeviceManager.AllDevices.OfType<IRoutingWithFeedback>();
@@ -39,11 +36,18 @@ namespace PepperDash.Essentials.Core.Routing
private void HandleMidpointUpdate(IRoutingWithFeedback midpoint, RouteSwitchDescriptor newRoute) private void HandleMidpointUpdate(IRoutingWithFeedback midpoint, RouteSwitchDescriptor newRoute)
{ {
var devices = DeviceManager.AllDevices.OfType<IRoutingSinkWithSwitching>(); try
foreach(var device in devices)
{ {
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) 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(inputPort == null)
if (firstTieLine == 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; TieLine firstTieLine;
destination.CurrentSourceInfoKey = string.Empty; 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; return;
} }
Debug.LogMessage(Serilog.Events.LogEventLevel.Verbose, "Getting source for first TieLine {tieLine}", this, firstTieLine); Debug.LogMessage(Serilog.Events.LogEventLevel.Verbose, "Getting source for first TieLine {tieLine}", this, firstTieLine);
var sourceTieLine = GetRootTieLine(firstTieLine); TieLine sourceTieLine;
try
if (sourceTieLine == null)
{ {
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; if (sourceTieLine == null)
destination.CurrentSourceInfoKey = string.Empty; {
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); Debug.LogMessage(Serilog.Events.LogEventLevel.Verbose, "Found root TieLine {tieLine}", this, sourceTieLine);
@@ -136,10 +178,16 @@ namespace PepperDash.Essentials.Core.Routing
if (source == null) 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; var tempSourceListItem = new SourceListItem
destination.CurrentSourceInfoKey = string.Empty; {
SourceKey = "$transient",
Name = sourceTieLine.SourcePort.Key,
};
destination.CurrentSourceInfo = tempSourceListItem; ;
destination.CurrentSourceInfoKey = "$transient";
return; return;
} }
@@ -152,43 +200,67 @@ namespace PepperDash.Essentials.Core.Routing
private TieLine GetRootTieLine(TieLine tieLine) private TieLine GetRootTieLine(TieLine tieLine)
{ {
TieLine nextTieLine = null; TieLine nextTieLine = null;
try
if(tieLine.SourcePort.ParentDevice is IRoutingWithFeedback midpoint)
{ {
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 (tieLine.SourcePort.ParentDevice is IRoutingWithFeedback midpoint)
if(currentRoute == null)
{ {
Debug.LogMessage(Serilog.Events.LogEventLevel.Information, "No route through midpoint {midpoint} for outputPort {outputPort}", this, midpoint.Key, tieLine.SourcePort); Debug.LogMessage(Serilog.Events.LogEventLevel.Verbose, "TieLine Source device {sourceDevice} is midpoint", this, midpoint);
return null;
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 GetRootTieLine(nextTieLine);
} }
} catch (Exception ex)
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
{ {
Debug.LogMessage(Serilog.Events.LogEventLevel.Verbose, "Found root: {tieLine}", this, tieLine); Debug.LogMessage(ex, "Error walking tieLines: {Exception}", this, ex);
return tieLine; return null;
}
nextTieLine = TieLineCollection.Default.FirstOrDefault(tl => tl.SourcePort.Key == tieLine.SourcePort.Key);
if(nextTieLine != null)
{
return GetRootTieLine(nextTieLine);
} }
return null; return null;

View File

@@ -38,7 +38,12 @@ namespace PepperDash.Essentials.Core
throw new ArgumentNullException(nameof(parent)); throw new ArgumentNullException(nameof(parent));
ParentDevice = parent; ParentDevice = parent;
} }
}
public override string ToString()
{
return $"{ParentDevice.Key}|{Key}|{Type}|{ConnectionType}";
}
}
/*/// <summary> /*/// <summary>
/// Basic RoutingInput with no statuses. /// Basic RoutingInput with no statuses.

View File

@@ -34,7 +34,7 @@ namespace PepperDash.Essentials.Core
public override string ToString() public override string ToString()
{ {
return ParentDevice.Key + ":" + Key; return $"{ParentDevice.Key}|{Key}|{Type}|{ConnectionType}";
} }
} }

View File

@@ -23,8 +23,8 @@ namespace PepperDash.Essentials.Core
ConnectionType = connType; ConnectionType = connType;
Selector = selector; Selector = selector;
IsInternal = isInternal; IsInternal = isInternal;
} }
} }
/*public abstract class RoutingPort<TSelector>:IKeyed /*public abstract class RoutingPort<TSelector>:IKeyed
{ {

View File

@@ -2,6 +2,7 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
using Newtonsoft.Json;
using Crestron.SimplSharp; using Crestron.SimplSharp;
using Crestron.SimplSharpPro; using Crestron.SimplSharpPro;
using Crestron.SimplSharpPro.DM; using Crestron.SimplSharpPro.DM;
@@ -93,19 +94,21 @@ namespace PepperDash.Essentials.Core
} }
} }
//******************************************************************************** //********************************************************************************
public class TieLineCollection : List<TieLine> public class TieLineCollection : List<TieLine>
{ {
public static TieLineCollection Default public static TieLineCollection Default
{ {
get get
{ {
if (_Default == null) if (_Default == null)
_Default = new TieLineCollection(); _Default = new TieLineCollection();
return _Default; return _Default;
} }
} }
[JsonIgnore]
static TieLineCollection _Default; static TieLineCollection _Default;
} }
} }

View File

@@ -163,6 +163,11 @@ namespace PepperDash.Essentials.Core.Web
{ {
Name = "Load Config", Name = "Load Config",
RouteHandler = new LoadConfigRequestHandler() RouteHandler = new LoadConfigRequestHandler()
},
new HttpCwsRoute("getTielines")
{
Name = "Get TieLines",
RouteHandler = new GetTieLinesRequestHandler()
} }
}; };
@@ -233,32 +238,32 @@ namespace PepperDash.Essentials.Core.Web
/// </example> /// </example>
public void GetPaths() public void GetPaths()
{ {
Debug.LogMessage(LogEventLevel.Verbose, this, "{0}", new String('-', 50)); Debug.LogMessage(LogEventLevel.Information, this, new string('-', 50));
var currentIp = CrestronEthernetHelper.GetEthernetParameter( var currentIp = CrestronEthernetHelper.GetEthernetParameter(
CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_CURRENT_IP_ADDRESS, 0); CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_CURRENT_IP_ADDRESS, 0);
var hostname = CrestronEthernetHelper.GetEthernetParameter( var hostname = CrestronEthernetHelper.GetEthernetParameter(
CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_HOSTNAME, 0); CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_HOSTNAME, 0);
var path = CrestronEnvironment.DevicePlatform == eDevicePlatform.Server
? $"http(s)://{hostname}/VirtualControl/Rooms/{InitialParametersClass.RoomId}/cws{BasePath}"
: $"http(s)://{currentIp}/cws{BasePath}";
var path = CrestronEnvironment.DevicePlatform == eDevicePlatform.Server Debug.LogMessage(LogEventLevel.Information, this, "Server:{path:l}", path);
? string.Format("http(s)://{0}/VirtualControl/Rooms/{1}/cws{2}", hostname, InitialParametersClass.RoomId, BasePath)
: string.Format("http(s)://{0}/cws{1}", currentIp, BasePath);
Debug.LogMessage(LogEventLevel.Verbose, this, "Server:{0}", path);
var routeCollection = _server.GetRouteCollection(); var routeCollection = _server.GetRouteCollection();
if (routeCollection == null) if (routeCollection == null)
{ {
Debug.LogMessage(LogEventLevel.Verbose, this, "Server route collection is null"); Debug.LogMessage(LogEventLevel.Information, this, "Server route collection is null");
return; return;
} }
Debug.LogMessage(LogEventLevel.Verbose, this, "Configured Routes:"); Debug.LogMessage(LogEventLevel.Information, this, "Configured Routes:");
foreach (var route in routeCollection) foreach (var route in routeCollection)
{ {
Debug.LogMessage(LogEventLevel.Verbose, this, "{0}: {1}/{2}", route.Name, path, route.Url); Debug.LogMessage(LogEventLevel.Information, this, "{routeName:l}: {routePath:l}/{routeUrl:l}", route.Name, path, route.Url);
} }
Debug.LogMessage(LogEventLevel.Verbose, this, "{0}", new String('-', 50)); Debug.LogMessage(LogEventLevel.Information, this, new string('-', 50));
} }
} }
} }

View File

@@ -1,5 +1,6 @@
using System; using System;
using Crestron.SimplSharp.WebScripting; using Crestron.SimplSharp.WebScripting;
using Newtonsoft.Json;
using PepperDash.Core; using PepperDash.Core;
using PepperDash.Core.Web.RequestHandlers; using PepperDash.Core.Web.RequestHandlers;
using Serilog.Events; using Serilog.Events;
@@ -28,7 +29,7 @@ namespace PepperDash.Essentials.Core.Web.RequestHandlers
if (context.Request.ContentLength < 0) if (context.Request.ContentLength < 0)
{ {
context.Response.StatusCode = 400; context.Response.StatusCode = 400;
context.Response.StatusDescription = "Bad Request"; context.Response.StatusDescription = "Bad Request: no body";
context.Response.End(); context.Response.End();
return; return;
@@ -38,7 +39,7 @@ namespace PepperDash.Essentials.Core.Web.RequestHandlers
if (string.IsNullOrEmpty(data)) if (string.IsNullOrEmpty(data))
{ {
context.Response.StatusCode = 400; context.Response.StatusCode = 400;
context.Response.StatusDescription = "Bad Request"; context.Response.StatusDescription = "Bad Request: no body";
context.Response.End(); context.Response.End();
return; return;
@@ -46,6 +47,7 @@ namespace PepperDash.Essentials.Core.Web.RequestHandlers
try try
{ {
var daw = JsonConvert.DeserializeObject<DeviceActionWrapper>(data);
DeviceJsonApi.DoDeviceActionWithJson(data); DeviceJsonApi.DoDeviceActionWithJson(data);
context.Response.StatusCode = 200; context.Response.StatusCode = 200;
@@ -54,12 +56,11 @@ namespace PepperDash.Essentials.Core.Web.RequestHandlers
} }
catch (Exception ex) catch (Exception ex)
{ {
Debug.LogMessage(LogEventLevel.Error, "Exception Message: {0}", ex.Message); Debug.LogMessage(ex, "Error handling device command: {Exception}");
Debug.LogMessage(LogEventLevel.Verbose, "Exception Stack Trace: {0}", ex.StackTrace);
if(ex.InnerException != null) Debug.LogMessage(LogEventLevel.Error, "Exception Inner: {0}", ex.InnerException);
context.Response.StatusCode = 400; context.Response.StatusCode = 400;
context.Response.StatusDescription = "Bad Request"; context.Response.StatusDescription = "Bad Request";
context.Response.Write(JsonConvert.SerializeObject(new { error = ex.Message }), false);
context.Response.End(); context.Response.End();
} }
} }

View File

@@ -1,6 +1,7 @@
using System.Text; using System.Text;
using Crestron.SimplSharp.WebScripting; using Crestron.SimplSharp.WebScripting;
using Newtonsoft.Json; using Newtonsoft.Json;
using PepperDash.Core;
using PepperDash.Core.Web.RequestHandlers; using PepperDash.Core.Web.RequestHandlers;
namespace PepperDash.Essentials.Core.Web.RequestHandlers namespace PepperDash.Essentials.Core.Web.RequestHandlers
@@ -25,6 +26,7 @@ namespace PepperDash.Essentials.Core.Web.RequestHandlers
protected override void HandleGet(HttpCwsContext context) protected override void HandleGet(HttpCwsContext context)
{ {
var routeData = context.Request.RouteData; var routeData = context.Request.RouteData;
Debug.LogMessage(Serilog.Events.LogEventLevel.Debug, "Getting DevMethods: {@routeData}", routeData);
if (routeData == null) if (routeData == null)
{ {
context.Response.StatusCode = 400; context.Response.StatusCode = 400;

View File

@@ -0,0 +1,34 @@
using Crestron.SimplSharp.WebScripting;
using Newtonsoft.Json;
using PepperDash.Core.Web.RequestHandlers;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace PepperDash.Essentials.Core.Web.RequestHandlers
{
public class GetTieLinesRequestHandler:WebApiBaseRequestHandler
{
public GetTieLinesRequestHandler() : base(true) { }
protected override void HandleGet(HttpCwsContext context)
{
var tieLineString = JsonConvert.SerializeObject(TieLineCollection.Default.Select((tl) => new {
sourceKey = tl.SourcePort.ParentDevice.Key,
sourcePort = tl.SourcePort.Key,
destinationKey = tl.DestinationPort.ParentDevice.Key,
destinationPort = tl.DestinationPort.Key
}));
context.Response.StatusCode = 200;
context.Response.StatusDescription = "OK";
context.Response.ContentType = "application/json";
context.Response.ContentEncoding = Encoding.UTF8;
context.Response.Write(tieLineString, false);
context.Response.End();
}
}
}

View File

@@ -171,7 +171,7 @@ namespace PepperDash.Essentials.Devices.Common.Displays
CurrentInputPort = inputPort; CurrentInputPort = inputPort;
} catch (Exception ex) } catch (Exception ex)
{ {
Debug.LogMessage(ex, "Error making switch: {Exception}", this); Debug.LogMessage(ex, "Error making switch: {Exception}", this, ex);
} }
} }

View File

@@ -92,6 +92,8 @@ namespace PepperDash.Essentials
private void StartSystem(object preventInitialization) private void StartSystem(object preventInitialization)
{ {
Debug.SetErrorLogMinimumDebugLevel(Serilog.Events.LogEventLevel.Verbose);
DeterminePlatform(); DeterminePlatform();
if (Debug.DoNotLoadConfigOnNextBoot) if (Debug.DoNotLoadConfigOnNextBoot)