diff --git a/.github/workflows/add-issues-to-project.yml b/.github/workflows/add-issues-to-project.yml new file mode 100644 index 00000000..8811c0cc --- /dev/null +++ b/.github/workflows/add-issues-to-project.yml @@ -0,0 +1,37 @@ +name: Add bugs to bugs project + +on: + issues: + types: + - opened + - labeled + +jobs: + check-secret: + runs-on: ubuntu-latest + outputs: + my-key: ${{ steps.my-key.outputs.defined }} + steps: + - id: my-key + if: "${{ env.MY_KEY != '' }}" + run: echo "::set-output name=defined::true" + env: + MY_KEY: ${{ secrets.PROJECT_URL }} + throw-error: + name: Check + runs-on: ubuntu-latest + needs: [check-secret] + if: needs.check-secret.outputs.my-key != 'true' + steps: + - run: echo "The Project URL Repo Secret is empty" + add-to-project: + name: Add issue to project + runs-on: ubuntu-latest + needs: [check-secret] + if: needs.check-secret.outputs.my-key == 'true' + steps: + - uses: actions/add-to-project@main + with: + project-url: ${{ secrets.PROJECT_URL }} + github-token: ${{ secrets.GH_PROJECTS_PASSWORD }} + diff --git a/PepperDashEssentials/ControlSystem.cs b/PepperDashEssentials/ControlSystem.cs index 296065b5..dc4ac3a3 100644 --- a/PepperDashEssentials/ControlSystem.cs +++ b/PepperDashEssentials/ControlSystem.cs @@ -13,6 +13,7 @@ using PepperDash.Essentials.Core; using PepperDash.Essentials.Core.Bridges; using PepperDash.Essentials.Core.Config; using PepperDash.Essentials.Core.Fusion; +using PepperDash.Essentials.Core.Web; using PepperDash.Essentials.Devices.Common; using PepperDash.Essentials.DM; using PepperDash.Essentials.Fusion; @@ -357,6 +358,7 @@ namespace PepperDash.Essentials // Build the processor wrapper class DeviceManager.AddDevice(new PepperDash.Essentials.Core.Devices.CrestronProcessor("processor")); + DeviceManager.AddDevice(new EssemtialsWebApi("essentialsWebApi","Essentials Web API")); // Add global System Monitor device if (CrestronEnvironment.DevicePlatform == eDevicePlatform.Appliance) diff --git a/PepperDashEssentials/Room/Types/EssentialsTechRoom.cs b/PepperDashEssentials/Room/Types/EssentialsTechRoom.cs index b97ef9c4..65cc52fa 100644 --- a/PepperDashEssentials/Room/Types/EssentialsTechRoom.cs +++ b/PepperDashEssentials/Room/Types/EssentialsTechRoom.cs @@ -272,7 +272,7 @@ namespace PepperDash.Essentials { Debug.Console(2, this, @"Attempting to run action: -DeviceKey: {0} +Key: {0} MethodName: {1} Params: {2}" , a.DeviceKey, a.MethodName, a.Params); diff --git a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Bridges/BridgeBase.cs b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Bridges/BridgeBase.cs index 11b8f4ff..cb937235 100644 --- a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Bridges/BridgeBase.cs +++ b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Bridges/BridgeBase.cs @@ -109,7 +109,7 @@ namespace PepperDash.Essentials.Core.Bridges { public EiscApiPropertiesConfig PropertiesConfig { get; private set; } - protected Dictionary JoinMaps { get; private set; } + public Dictionary JoinMaps { get; private set; } public BasicTriList Eisc { get; private set; } diff --git a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Bridges/JoinMaps/IAnalogInputJoinMap.cs b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Bridges/JoinMaps/IAnalogInputJoinMap.cs new file mode 100644 index 00000000..eaf70f3a --- /dev/null +++ b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Bridges/JoinMaps/IAnalogInputJoinMap.cs @@ -0,0 +1,34 @@ +using System; + +namespace PepperDash.Essentials.Core.Bridges +{ + public class IAnalogInputJoinMap : JoinMapBaseAdvanced + { + + [JoinName("InputValue")] + public JoinDataComplete InputValue = new JoinDataComplete(new JoinData { JoinNumber = 1, JoinSpan = 1 }, + new JoinMetadata { Description = "Input Value", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Analog }); + [JoinName("MinimumChange")] + public JoinDataComplete MinimumChange = new JoinDataComplete(new JoinData { JoinNumber = 2, JoinSpan = 1 }, + new JoinMetadata { Description = "Minimum voltage change required to reflect a change", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Analog }); + + /// + /// Constructor to use when instantiating this Join Map without inheriting from it + /// + /// Join this join map will start at + public IAnalogInputJoinMap(uint joinStart) + : this(joinStart, typeof(IAnalogInputJoinMap)) + { + } + + /// + /// Constructor to use when extending this Join map + /// + /// Join this join map will start at + /// Type of the child join map + protected IAnalogInputJoinMap(uint joinStart, Type type) + : base(joinStart, type) + { + } + } +} \ No newline at end of file diff --git a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Bridges/JoinMaps/IDigitalInputJoinMap.cs b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Bridges/JoinMaps/IDigitalInputJoinMap.cs index 82c09e54..83e6cdab 100644 --- a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Bridges/JoinMaps/IDigitalInputJoinMap.cs +++ b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Bridges/JoinMaps/IDigitalInputJoinMap.cs @@ -7,7 +7,7 @@ namespace PepperDash.Essentials.Core.Bridges [JoinName("InputState")] public JoinDataComplete InputState = new JoinDataComplete(new JoinData { JoinNumber = 1, JoinSpan = 1 }, - new JoinMetadata { Description = "Room Email Url", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); + new JoinMetadata { Description = "Input State", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); /// /// Constructor to use when instantiating this Join Map without inheriting from it diff --git a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Comm and IR/CommFactory.cs b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Comm and IR/CommFactory.cs index 8a5efe47..9667b5b9 100644 --- a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Comm and IR/CommFactory.cs +++ b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Comm and IR/CommFactory.cs @@ -183,6 +183,8 @@ namespace PepperDash.Essentials.Core [JsonConverter(typeof(ComSpecJsonConverter))] public ComPort.ComPortSpec ComParams { get; set; } + public string RoomId { get; set; } + public string CresnetId { get; set; } /// diff --git a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Crestron IO/IOPortConfig.cs b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Crestron IO/IOPortConfig.cs index 09061ff2..5fbe10e1 100644 --- a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Crestron IO/IOPortConfig.cs +++ b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Crestron IO/IOPortConfig.cs @@ -15,5 +15,7 @@ namespace PepperDash.Essentials.Core.CrestronIO public uint PortNumber { get; set; } [JsonProperty("disablePullUpResistor")] public bool DisablePullUpResistor { get; set; } + [JsonProperty("minimumChange")] + public int MinimumChange { get; set; } } } \ No newline at end of file diff --git a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Crestron IO/Inputs/GenericVersiportAnalogInputDevice.cs b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Crestron IO/Inputs/GenericVersiportAnalogInputDevice.cs new file mode 100644 index 00000000..70be2f6f --- /dev/null +++ b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Crestron IO/Inputs/GenericVersiportAnalogInputDevice.cs @@ -0,0 +1,208 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using Crestron.SimplSharp; +using Crestron.SimplSharpPro; +using Crestron.SimplSharpPro.DeviceSupport; + +using PepperDash.Core; +using PepperDash.Essentials.Core.Config; +using PepperDash.Essentials.Core.Bridges; + + +using Newtonsoft.Json; + +namespace PepperDash.Essentials.Core.CrestronIO +{ + /// + /// Represents a generic digital input deviced tied to a versiport + /// + public class GenericVersiportAnalogInputDevice : EssentialsBridgeableDevice, IAnalogInput + { + public Versiport InputPort { get; private set; } + + public IntFeedback InputValueFeedback { get; private set; } + public IntFeedback InputMinimumChangeFeedback { get; private set; } + + Func InputValueFeedbackFunc + { + get + { + return () => InputPort.AnalogIn; + } + } + + Func InputMinimumChangeFeedbackFunc + { + get { return () => InputPort.AnalogMinChange; } + } + + public GenericVersiportAnalogInputDevice(string key, string name, Func postActivationFunc, IOPortConfig config) : + base(key, name) + { + InputValueFeedback = new IntFeedback(InputValueFeedbackFunc); + InputMinimumChangeFeedback = new IntFeedback(InputMinimumChangeFeedbackFunc); + + AddPostActivationAction(() => + { + InputPort = postActivationFunc(config); + + InputPort.Register(); + + InputPort.SetVersiportConfiguration(eVersiportConfiguration.AnalogInput); + InputPort.AnalogMinChange = (ushort)(config.MinimumChange > 0 ? config.MinimumChange : 655); + if (config.DisablePullUpResistor) + InputPort.DisablePullUpResistor = true; + + InputPort.VersiportChange += InputPort_VersiportChange; + + Debug.Console(1, this, "Created GenericVersiportAnalogInputDevice on port '{0}'. DisablePullUpResistor: '{1}'", config.PortNumber, InputPort.DisablePullUpResistor); + + }); + + } + + /// + /// Set minimum voltage change for device to update voltage changed method + /// + /// valid values range from 0 - 65535, representing the full 100% range of the processor voltage source. Check processor documentation for details + public void SetMinimumChange(ushort value) + { + InputPort.AnalogMinChange = value; + } + + void InputPort_VersiportChange(Versiport port, VersiportEventArgs args) + { + Debug.Console(1, this, "Versiport change: {0}", args.Event); + + if(args.Event == eVersiportEvent.AnalogInChange) + InputValueFeedback.FireUpdate(); + if (args.Event == eVersiportEvent.AnalogMinChangeChange) + InputMinimumChangeFeedback.FireUpdate(); + } + + + #region Bridge Linking + + public override void LinkToApi(BasicTriList trilist, uint joinStart, string joinMapKey, EiscApiAdvanced bridge) + { + var joinMap = new IAnalogInputJoinMap(joinStart); + + var joinMapSerialized = JoinMapHelper.GetSerializedJoinMapForDevice(joinMapKey); + + if (!string.IsNullOrEmpty(joinMapSerialized)) + joinMap = JsonConvert.DeserializeObject(joinMapSerialized); + + if (bridge != null) + { + bridge.AddJoinMap(Key, joinMap); + } + else + { + Debug.Console(0, this, "Please update config to use 'eiscapiadvanced' to get all join map features for this device."); + } + + try + { + Debug.Console(1, this, "Linking to Trilist '{0}'", trilist.ID.ToString("X")); + + // Link feedback for input state + InputValueFeedback.LinkInputSig(trilist.UShortInput[joinMap.InputValue.JoinNumber]); + InputMinimumChangeFeedback.LinkInputSig(trilist.UShortInput[joinMap.MinimumChange.JoinNumber]); + trilist.SetUShortSigAction(joinMap.MinimumChange.JoinNumber, SetMinimumChange); + + } + catch (Exception e) + { + Debug.Console(1, this, "Unable to link device '{0}'. Input is null", Key); + Debug.Console(1, this, "Error: {0}", e); + } + + trilist.OnlineStatusChange += (d, args) => + { + if (!args.DeviceOnLine) return; + InputValueFeedback.FireUpdate(); + InputMinimumChangeFeedback.FireUpdate(); + }; + + } + + void trilist_OnlineStatusChange(GenericBase currentDevice, OnlineOfflineEventArgs args) + { + throw new NotImplementedException(); + } + + #endregion + + + public static Versiport GetVersiportDigitalInput(IOPortConfig dc) + { + + IIOPorts ioPortDevice; + + if (dc.PortDeviceKey.Equals("processor")) + { + if (!Global.ControlSystem.SupportsVersiport) + { + Debug.Console(0, "GetVersiportAnalogInput: Processor does not support Versiports"); + return null; + } + ioPortDevice = Global.ControlSystem; + } + else + { + var ioPortDev = DeviceManager.GetDeviceForKey(dc.PortDeviceKey) as IIOPorts; + if (ioPortDev == null) + { + Debug.Console(0, "GetVersiportAnalogInput: Device {0} is not a valid device", dc.PortDeviceKey); + return null; + } + ioPortDevice = ioPortDev; + } + if (ioPortDevice == null) + { + Debug.Console(0, "GetVersiportAnalogInput: Device '0' is not a valid IIOPorts Device", dc.PortDeviceKey); + return null; + } + + if (dc.PortNumber > ioPortDevice.NumberOfVersiPorts) + { + Debug.Console(0, "GetVersiportAnalogInput: Device {0} does not contain a port {1}", dc.PortDeviceKey, dc.PortNumber); + return null; + } + if(!ioPortDevice.VersiPorts[dc.PortNumber].SupportsAnalogInput) + { + Debug.Console(0, "GetVersiportAnalogInput: Device {0} does not support AnalogInput on port {1}", dc.PortDeviceKey, dc.PortNumber); + return null; + } + + + return ioPortDevice.VersiPorts[dc.PortNumber]; + + + } + } + + + public class GenericVersiportAbalogInputDeviceFactory : EssentialsDeviceFactory + { + public GenericVersiportAbalogInputDeviceFactory() + { + TypeNames = new List() { "versiportanaloginput" }; + } + + public override EssentialsDevice BuildDevice(DeviceConfig dc) + { + Debug.Console(1, "Factory Attempting to create new Generic Versiport Device"); + + var props = JsonConvert.DeserializeObject(dc.Properties.ToString()); + + if (props == null) return null; + + var portDevice = new GenericVersiportAnalogInputDevice(dc.Key, dc.Name, GenericVersiportAnalogInputDevice.GetVersiportDigitalInput, props); + + return portDevice; + } + } +} \ No newline at end of file diff --git a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Crestron IO/Inputs/IAnalogInput.cs b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Crestron IO/Inputs/IAnalogInput.cs new file mode 100644 index 00000000..44af9954 --- /dev/null +++ b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Crestron IO/Inputs/IAnalogInput.cs @@ -0,0 +1,14 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using Crestron.SimplSharp; +using PepperDash.Essentials.Core; + +namespace PepperDash.Essentials.Core.CrestronIO +{ + public interface IAnalogInput + { + IntFeedback InputValueFeedback { get; } + } +} \ No newline at end of file diff --git a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Crestron IO/Outputs/GenericVersiportOutputDevice.cs b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Crestron IO/Outputs/GenericVersiportOutputDevice.cs index 77037845..2d1ae9c4 100644 --- a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Crestron IO/Outputs/GenericVersiportOutputDevice.cs +++ b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Crestron IO/Outputs/GenericVersiportOutputDevice.cs @@ -42,18 +42,19 @@ namespace PepperDash.Essentials.Core.CrestronIO OutputPort = postActivationFunc(config); OutputPort.Register(); + + if (!OutputPort.SupportsDigitalOutput) { Debug.Console(0, this, "Device does not support configuration as a Digital Output"); return; } + OutputPort.SetVersiportConfiguration(eVersiportConfiguration.DigitalOutput); + + OutputPort.VersiportChange += OutputPort_VersiportChange; - - - Debug.Console(1, this, "Created GenericVersiportDigitalOutputDevice on port '{0}'.", config.PortNumber); - }); } @@ -72,7 +73,18 @@ namespace PepperDash.Essentials.Core.CrestronIO /// value to set the output to public void SetOutput(bool state) { - OutputPort.DigitalOut = state; + if (OutputPort.SupportsDigitalOutput) + { + Debug.Console(0, this, "Passed the Check"); + + OutputPort.DigitalOut = state; + + } + else + { + Debug.Console(0, this, "Versiport does not support Digital Output Mode"); + } + } #region Bridge Linking @@ -115,40 +127,40 @@ namespace PepperDash.Essentials.Core.CrestronIO public static Versiport GetVersiportDigitalOutput(IOPortConfig dc) { - - IIOPorts ioPortDevice; - if (dc.PortDeviceKey.Equals("processor")) - { - if (!Global.ControlSystem.SupportsVersiport) + IIOPorts ioPortDevice; + + if (dc.PortDeviceKey.Equals("processor")) { - Debug.Console(0, "GetVersiportDigitalOuptut: Processor does not support Versiports"); + if (!Global.ControlSystem.SupportsVersiport) + { + Debug.Console(0, "GetVersiportDigitalOuptut: Processor does not support Versiports"); + return null; + } + ioPortDevice = Global.ControlSystem; + } + else + { + var ioPortDev = DeviceManager.GetDeviceForKey(dc.PortDeviceKey) as IIOPorts; + if (ioPortDev == null) + { + Debug.Console(0, "GetVersiportDigitalOuptut: Device {0} is not a valid device", dc.PortDeviceKey); + return null; + } + ioPortDevice = ioPortDev; + } + if (ioPortDevice == null) + { + Debug.Console(0, "GetVersiportDigitalOuptut: Device '0' is not a valid IOPorts Device", dc.PortDeviceKey); return null; } - ioPortDevice = Global.ControlSystem; - } - else - { - var ioPortDev = DeviceManager.GetDeviceForKey(dc.PortDeviceKey) as IIOPorts; - if (ioPortDev == null) + + if (dc.PortNumber > ioPortDevice.NumberOfVersiPorts) { - Debug.Console(0, "GetVersiportDigitalOuptut: Device {0} is not a valid device", dc.PortDeviceKey); - return null; + Debug.Console(0, "GetVersiportDigitalOuptut: Device {0} does not contain a port {1}", dc.PortDeviceKey, dc.PortNumber); } - ioPortDevice = ioPortDev; - } - if (ioPortDevice == null) - { - Debug.Console(0, "GetVersiportDigitalOuptut: Device '0' is not a valid IIOPorts Device", dc.PortDeviceKey); - return null; - } - - if (dc.PortNumber > ioPortDevice.NumberOfVersiPorts) - { - Debug.Console(0, "GetVersiportDigitalOuptut: Device {0} does not contain a port {1}", dc.PortDeviceKey, dc.PortNumber); - } - - return ioPortDevice.VersiPorts[dc.PortNumber]; + var port = ioPortDevice.VersiPorts[dc.PortNumber]; + return port; } } diff --git a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Factory/DeviceFactory.cs b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Factory/DeviceFactory.cs index ebdc87b1..bad3e531 100644 --- a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Factory/DeviceFactory.cs +++ b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Factory/DeviceFactory.cs @@ -204,5 +204,17 @@ namespace PepperDash.Essentials.Core Description: {2}", type.Key, cType, description); } } + + /// + /// Returns the device factory dictionary + /// + /// + /// + public static Dictionary GetDeviceFactoryDictionary(string filter) + { + return string.IsNullOrEmpty(filter) + ? FactoryMethods + : FactoryMethods.Where(k => k.Key.Contains(filter)).ToDictionary(k => k.Key, k => k.Value); + } } } \ No newline at end of file diff --git a/essentials-framework/Essentials Core/PepperDashEssentialsBase/JoinMaps/JoinMapBase.cs b/essentials-framework/Essentials Core/PepperDashEssentialsBase/JoinMaps/JoinMapBase.cs index 6ffb16cc..8f484121 100644 --- a/essentials-framework/Essentials Core/PepperDashEssentialsBase/JoinMaps/JoinMapBase.cs +++ b/essentials-framework/Essentials Core/PepperDashEssentialsBase/JoinMaps/JoinMapBase.cs @@ -1,9 +1,7 @@ using System; using System.Collections.Generic; -using System.Data; using System.Globalization; using System.Linq; -using System.Runtime.InteropServices; using System.Text; using Crestron.SimplSharp.Reflection; using Crestron.SimplSharp.CrestronIO; @@ -236,25 +234,45 @@ namespace PepperDash.Essentials.Core /// public void PrintJoinMapInfo() { - Debug.Console(0, "{0}:\n", GetType().Name); + var sb = JoinmapStringBuilder(); + + CrestronConsole.ConsoleCommandResponse(sb.ToString()); + } + + private StringBuilder JoinmapStringBuilder() + { + var sb = new StringBuilder(); // Get the joins of each type and print them - Debug.Console(0, "Digitals:"); - var digitals = Joins.Where(j => (j.Value.Metadata.JoinType & eJoinType.Digital) == eJoinType.Digital).ToDictionary(j => j.Key, j => j.Value); - Debug.Console(2, "Found {0} Digital Joins", digitals.Count); - PrintJoinList(GetSortedJoins(digitals)); + sb.AppendLine(String.Format("# {0}", GetType().Name)); + sb.AppendLine(); + sb.AppendLine("## Digitals"); + sb.AppendLine(); + // Get the joins of each type and print them + var digitals = + Joins.Where(j => (j.Value.Metadata.JoinType & eJoinType.Digital) == eJoinType.Digital) + .ToDictionary(j => j.Key, j => j.Value); + var digitalSb = AppendJoinList(GetSortedJoins(digitals)); + digitalSb.AppendLine("## Analogs"); + digitalSb.AppendLine(); - Debug.Console(0, "Analogs:"); - var analogs = Joins.Where(j => (j.Value.Metadata.JoinType & eJoinType.Analog) == eJoinType.Analog).ToDictionary(j => j.Key, j => j.Value); - Debug.Console(2, "Found {0} Analog Joins", analogs.Count); - PrintJoinList(GetSortedJoins(analogs)); + var analogs = + Joins.Where(j => (j.Value.Metadata.JoinType & eJoinType.Analog) == eJoinType.Analog) + .ToDictionary(j => j.Key, j => j.Value); + var analogSb = AppendJoinList(GetSortedJoins(analogs)); + analogSb.AppendLine("## Serials"); + analogSb.AppendLine(); - Debug.Console(0, "Serials:"); - var serials = Joins.Where(j => (j.Value.Metadata.JoinType & eJoinType.Serial) == eJoinType.Serial).ToDictionary(j => j.Key, j => j.Value); - Debug.Console(2, "Found {0} Serial Joins", serials.Count); - PrintJoinList(GetSortedJoins(serials)); + var serials = + Joins.Where(j => (j.Value.Metadata.JoinType & eJoinType.Serial) == eJoinType.Serial) + .ToDictionary(j => j.Key, j => j.Value); + var serialSb = AppendJoinList(GetSortedJoins(serials)); + sb.EnsureCapacity(sb.Length + digitalSb.Length + analogSb.Length + serialSb.Length); + sb.Append(digitalSb).Append(analogSb).Append(serialSb); + return sb; } + /// /// Prints the join information to console /// @@ -264,35 +282,9 @@ namespace PepperDash.Essentials.Core Debug.Console(0, "{0}:\n", pluginType); - var sb = new StringBuilder(); - sb.AppendLine(String.Format("# {0}", GetType().Name)); - sb.AppendLine(String.Format("Generated from '{0}' on bridge '{1}'", deviceKey, bridgeKey)); - sb.AppendLine(); - sb.AppendLine("## Digitals"); - // Get the joins of each type and print them - var digitals = Joins.Where(j => (j.Value.Metadata.JoinType & eJoinType.Digital) == eJoinType.Digital).ToDictionary(j => j.Key, j => j.Value); - Debug.Console(2, "Found {0} Digital Joins", digitals.Count); - var digitalSb = AppendJoinList(GetSortedJoins(digitals)); - digitalSb.AppendLine("## Analogs"); - digitalSb.AppendLine(); - Debug.Console(0, "Analogs:"); - var analogs = Joins.Where(j => (j.Value.Metadata.JoinType & eJoinType.Analog) == eJoinType.Analog).ToDictionary(j => j.Key, j => j.Value); - Debug.Console(2, "Found {0} Analog Joins", analogs.Count); - var analogSb = AppendJoinList(GetSortedJoins(analogs)); - analogSb.AppendLine("## Serials"); - analogSb.AppendLine(); - - Debug.Console(0, "Serials:"); - var serials = Joins.Where(j => (j.Value.Metadata.JoinType & eJoinType.Serial) == eJoinType.Serial).ToDictionary(j => j.Key, j => j.Value); - Debug.Console(2, "Found {0} Serial Joins", serials.Count); - var serialSb = AppendJoinList(GetSortedJoins(serials)); - - sb.EnsureCapacity(sb.Length + digitalSb.Length + analogSb.Length + serialSb.Length); - sb.Append(digitalSb).Append(analogSb).Append(serialSb); - - WriteJoinmapMarkdown(sb, pluginType, bridgeKey, deviceKey); + WriteJoinmapMarkdown(JoinmapStringBuilder(), pluginType, bridgeKey, deviceKey); } @@ -313,7 +305,7 @@ namespace PepperDash.Essentials.Core /// /// /// - List> GetSortedJoins(Dictionary joins) + static List> GetSortedJoins(Dictionary joins) { var sortedJoins = joins.ToList(); @@ -322,7 +314,7 @@ namespace PepperDash.Essentials.Core return sortedJoins; } - void PrintJoinList(List> joins) + void PrintJoinList(IEnumerable> joins) { foreach (var join in joins) { @@ -579,7 +571,7 @@ namespace PepperDash.Essentials.Core var errorKey = string.Empty; foreach (var item in dataArray) { - if (item.Value.TrimEnd() == placeholder) ; + if (item.Value.TrimEnd() == placeholder) continue; errorKey = item.Key; break; } diff --git a/essentials-framework/Essentials Core/PepperDashEssentialsBase/PepperDash_Essentials_Core.csproj b/essentials-framework/Essentials Core/PepperDashEssentialsBase/PepperDash_Essentials_Core.csproj index 2cf2928c..c8ecbde6 100644 --- a/essentials-framework/Essentials Core/PepperDashEssentialsBase/PepperDash_Essentials_Core.csproj +++ b/essentials-framework/Essentials Core/PepperDashEssentialsBase/PepperDash_Essentials_Core.csproj @@ -92,6 +92,10 @@ ..\..\..\..\..\..\..\..\..\ProgramData\Crestron\SDK\SimplSharpCustomAttributesInterface.dll False + + False + ..\..\..\..\..\..\ProgramData\Crestron\SDK\SimplSharpCWSHelperInterface.dll + False ..\..\..\..\..\..\..\..\..\ProgramData\Crestron\SDK\SimplSharpHelperInterface.dll @@ -123,6 +127,7 @@ + @@ -182,8 +187,10 @@ + + @@ -193,6 +200,24 @@ + + + + + + + + + + + + + + + + + + diff --git a/essentials-framework/Essentials Core/PepperDashEssentialsBase/PepperDash_Essentials_Core.csproj.DotSettings b/essentials-framework/Essentials Core/PepperDashEssentialsBase/PepperDash_Essentials_Core.csproj.DotSettings new file mode 100644 index 00000000..cb991a69 --- /dev/null +++ b/essentials-framework/Essentials Core/PepperDashEssentialsBase/PepperDash_Essentials_Core.csproj.DotSettings @@ -0,0 +1,3 @@ + + True + False \ No newline at end of file diff --git a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Routing/IRoutingInputsExtensions.cs b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Routing/IRoutingInputsExtensions.cs index d371c2d6..4cd0d4ff 100644 --- a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Routing/IRoutingInputsExtensions.cs +++ b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Routing/IRoutingInputsExtensions.cs @@ -1,425 +1,425 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using Crestron.SimplSharp; -using Crestron.SimplSharpPro; -using Crestron.SimplSharpPro.DM; - -using PepperDash.Core; - - -namespace PepperDash.Essentials.Core -{ - public class RouteRequest - { - public IRoutingSink Destination {get; set;} - public IRoutingOutputs Source {get; set;} - public eRoutingSignalType SignalType {get; set;} - - public void HandleCooldown(object sender, FeedbackEventArgs args) - { - var coolingDevice = sender as IWarmingCooling; - - if(args.BoolValue == false) - { - Destination.ReleaseAndMakeRoute(Source, SignalType); - - if(sender == null) return; - - coolingDevice.IsCoolingDownFeedback.OutputChange -= HandleCooldown; - } - } - } - - /// - /// Extensions added to any IRoutingInputs classes to provide discovery-based routing - /// on those destinations. - /// - public static class IRoutingInputsExtensions - { - private static Dictionary RouteRequests = new Dictionary(); - /// - /// Gets any existing RouteDescriptor for a destination, clears it using ReleaseRoute - /// and then attempts a new Route and if sucessful, stores that RouteDescriptor - /// in RouteDescriptorCollection.DefaultCollection - /// - public static void ReleaseAndMakeRoute(this IRoutingSink destination, IRoutingOutputs source, eRoutingSignalType signalType) - { - var routeRequest = new RouteRequest { - Destination = destination, - Source = source, - SignalType = signalType - }; - - var coolingDevice = destination as IWarmingCooling; - - RouteRequest existingRouteRequest; - - //We already have a route request for this device, and it's a cooling device and is cooling - if (RouteRequests.TryGetValue(destination.Key, out existingRouteRequest) && coolingDevice != null && coolingDevice.IsCoolingDownFeedback.BoolValue == true) - { - coolingDevice.IsCoolingDownFeedback.OutputChange -= existingRouteRequest.HandleCooldown; - - coolingDevice.IsCoolingDownFeedback.OutputChange += routeRequest.HandleCooldown; - +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using Crestron.SimplSharp; +using Crestron.SimplSharpPro; +using Crestron.SimplSharpPro.DM; + +using PepperDash.Core; + + +namespace PepperDash.Essentials.Core +{ + public class RouteRequest + { + public IRoutingSink Destination {get; set;} + public IRoutingOutputs Source {get; set;} + public eRoutingSignalType SignalType {get; set;} + + public void HandleCooldown(object sender, FeedbackEventArgs args) + { + var coolingDevice = sender as IWarmingCooling; + + if(args.BoolValue == false) + { + Destination.ReleaseAndMakeRoute(Source, SignalType); + + if(sender == null) return; + + coolingDevice.IsCoolingDownFeedback.OutputChange -= HandleCooldown; + } + } + } + + /// + /// Extensions added to any IRoutingInputs classes to provide discovery-based routing + /// on those destinations. + /// + public static class IRoutingInputsExtensions + { + private static Dictionary RouteRequests = new Dictionary(); + /// + /// Gets any existing RouteDescriptor for a destination, clears it using ReleaseRoute + /// and then attempts a new Route and if sucessful, stores that RouteDescriptor + /// in RouteDescriptorCollection.DefaultCollection + /// + public static void ReleaseAndMakeRoute(this IRoutingSink destination, IRoutingOutputs source, eRoutingSignalType signalType) + { + var routeRequest = new RouteRequest { + Destination = destination, + Source = source, + SignalType = signalType + }; + + var coolingDevice = destination as IWarmingCooling; + + RouteRequest existingRouteRequest; + + //We already have a route request for this device, and it's a cooling device and is cooling + if (RouteRequests.TryGetValue(destination.Key, out existingRouteRequest) && coolingDevice != null && coolingDevice.IsCoolingDownFeedback.BoolValue == true) + { + coolingDevice.IsCoolingDownFeedback.OutputChange -= existingRouteRequest.HandleCooldown; + + coolingDevice.IsCoolingDownFeedback.OutputChange += routeRequest.HandleCooldown; + RouteRequests[destination.Key] = routeRequest; - Debug.Console(2, "******************************************************** Device: {0} is cooling down and already has a routing request stored. Storing new route request to route to source key: {1}", destination.Key, routeRequest.Source.Key); - - return; - } - - //New Request - if (coolingDevice != null && coolingDevice.IsCoolingDownFeedback.BoolValue == true) - { - coolingDevice.IsCoolingDownFeedback.OutputChange -= routeRequest.HandleCooldown; - - coolingDevice.IsCoolingDownFeedback.OutputChange += routeRequest.HandleCooldown; - + Debug.Console(2, "******************************************************** Device: {0} is cooling down and already has a routing request stored. Storing new route request to route to source key: {1}", destination.Key, routeRequest.Source.Key); + + return; + } + + //New Request + if (coolingDevice != null && coolingDevice.IsCoolingDownFeedback.BoolValue == true) + { + coolingDevice.IsCoolingDownFeedback.OutputChange -= routeRequest.HandleCooldown; + + coolingDevice.IsCoolingDownFeedback.OutputChange += routeRequest.HandleCooldown; + RouteRequests.Add(destination.Key, routeRequest); Debug.Console(2, "******************************************************** Device: {0} is cooling down. Storing route request to route to source key: {1}", destination.Key, routeRequest.Source.Key); - return; - } - - if (RouteRequests.ContainsKey(destination.Key) && coolingDevice != null && coolingDevice.IsCoolingDownFeedback.BoolValue == false) - { + return; + } + + if (RouteRequests.ContainsKey(destination.Key) && coolingDevice != null && coolingDevice.IsCoolingDownFeedback.BoolValue == false) + { RouteRequests.Remove(destination.Key); Debug.Console(2, "******************************************************** Device: {0} is NOT cooling down. Removing stored route request and routing to source key: {1}", destination.Key, routeRequest.Source.Key); - } - - destination.ReleaseRoute(); - - RunRouteRequest(routeRequest); - } - - public static void RunRouteRequest(RouteRequest request) - { - if (request.Source == null) return; - var newRoute = request.Destination.GetRouteToSource(request.Source, request.SignalType); - if (newRoute == null) return; - RouteDescriptorCollection.DefaultCollection.AddRouteDescriptor(newRoute); - Debug.Console(2, request.Destination, "Executing full route"); - newRoute.ExecuteRoutes(); - } - - /// - /// Will release the existing route on the destination, if it is found in - /// RouteDescriptorCollection.DefaultCollection - /// - /// - public static void ReleaseRoute(this IRoutingSink destination) - { - RouteRequest existingRequest; - - if (RouteRequests.TryGetValue(destination.Key, out existingRequest) && destination is IWarmingCooling) - { - var coolingDevice = destination as IWarmingCooling; - - coolingDevice.IsCoolingDownFeedback.OutputChange -= existingRequest.HandleCooldown; - } - - RouteRequests.Remove(destination.Key); - - var current = RouteDescriptorCollection.DefaultCollection.RemoveRouteDescriptor(destination); - if (current != null) - { - Debug.Console(1, destination, "Releasing current route: {0}", current.Source.Key); - current.ReleaseRoutes(); - } - } - - /// - /// 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 GetRouteToSource(this IRoutingSink destination, IRoutingOutputs source, eRoutingSignalType signalType) - { - var routeDescr = new RouteDescriptor(source, destination, signalType); - // if it's a single signal type, find the route - if ((signalType & (eRoutingSignalType.Audio & eRoutingSignalType.Video)) == (eRoutingSignalType.Audio & eRoutingSignalType.Video)) - { - Debug.Console(1, destination, "Attempting to build source route from {0}", source.Key); - if (!destination.GetRouteToSource(source, null, null, signalType, 0, routeDescr)) - routeDescr = null; - } - // otherwise, audioVideo needs to be handled as two steps. - else - { - Debug.Console(1, destination, "Attempting to build audio and video routes from {0}", source.Key); - var audioSuccess = destination.GetRouteToSource(source, null, null, eRoutingSignalType.Audio, 0, routeDescr); - if (!audioSuccess) - Debug.Console(1, destination, "Cannot find audio route to {0}", source.Key); - var videoSuccess = destination.GetRouteToSource(source, null, null, eRoutingSignalType.Video, 0, routeDescr); - if (!videoSuccess) - Debug.Console(1, destination, "Cannot find video route to {0}", source.Key); - if (!audioSuccess && !videoSuccess) - routeDescr = null; - } - - //Debug.Console(1, destination, "Route{0} discovered", routeDescr == null ? " NOT" : ""); - return routeDescr; - } - - /// - /// 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 - /// hoping to find the source. - /// - /// - /// - /// The RoutingOutputPort whose link is being checked for a route - /// Prevents Devices from being twice-checked - /// This recursive function should not be called with AudioVideo - /// Just an informational counter - /// The RouteDescriptor being populated as the route is discovered - /// true if source is hit - static bool GetRouteToSource(this IRoutingInputs destination, IRoutingOutputs source, - RoutingOutputPort outputPortToUse, List alreadyCheckedDevices, - eRoutingSignalType signalType, int cycle, RouteDescriptor routeTable) - { - cycle++; - Debug.Console(2, "GetRouteToSource: {0} {1}--> {2}", cycle, source.Key, destination.Key); - - RoutingInputPort goodInputPort = null; - var destDevInputTies = TieLineCollection.Default.Where(t => - t.DestinationPort.ParentDevice == destination && (t.Type == signalType || (t.Type & (eRoutingSignalType.Audio | eRoutingSignalType.Video)) == (eRoutingSignalType.Audio | eRoutingSignalType.Video))); - - // find a direct tie - var directTie = destDevInputTies.FirstOrDefault( - t => t.DestinationPort.ParentDevice == destination - && t.SourcePort.ParentDevice == source); - if (directTie != null) // Found a tie directly to the source - { - goodInputPort = directTie.DestinationPort; - } - else // no direct-connect. Walk back devices. - { - Debug.Console(2, destination, "is not directly connected to {0}. Walking down tie lines", source.Key); - - // No direct tie? Run back out on the inputs' attached devices... - // Only the ones that are routing devices - var attachedMidpoints = destDevInputTies.Where(t => t.SourcePort.ParentDevice is IRoutingInputsOutputs); - - //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(); - alreadyCheckedDevices.Add(destination as IRoutingInputsOutputs); - - foreach (var inputTieToTry in attachedMidpoints) - { - var upstreamDeviceOutputPort = inputTieToTry.SourcePort; - var upstreamRoutingDevice = upstreamDeviceOutputPort.ParentDevice as IRoutingInputsOutputs; - Debug.Console(2, destination, "Trying to find route on {0}", upstreamRoutingDevice.Key); - - // Check if this previous device has already been walked - if (alreadyCheckedDevices.Contains(upstreamRoutingDevice)) - { - Debug.Console(2, destination, "Skipping input {0} on {1}, this was already checked", upstreamRoutingDevice.Key, destination.Key); - continue; - } - // haven't seen this device yet. Do it. Pass the output port to the next - // level to enable switching on success - var upstreamRoutingSuccess = upstreamRoutingDevice.GetRouteToSource(source, upstreamDeviceOutputPort, - alreadyCheckedDevices, signalType, cycle, routeTable); - if (upstreamRoutingSuccess) - { - Debug.Console(2, destination, "Upstream device route found"); - goodInputPort = inputTieToTry.DestinationPort; - break; // Stop looping the inputs in this cycle - } - } - } - - // we have a route on corresponding inputPort. *** Do the route *** - if (goodInputPort != null) - { - //Debug.Console(2, destination, "adding RouteDescriptor"); - if (outputPortToUse == null) - { - // it's a sink device - routeTable.Routes.Add(new RouteSwitchDescriptor(goodInputPort)); - } - else if (destination is IRouting) - { - routeTable.Routes.Add(new RouteSwitchDescriptor (outputPortToUse, goodInputPort)); - } - else // device is merely IRoutingInputOutputs - Debug.Console(2, destination, " No routing. Passthrough device"); - //Debug.Console(2, destination, "Exiting cycle {0}", cycle); - return true; - } - - Debug.Console(2, destination, "No route found to {0}", source.Key); - return false; - } - } - - - - - - // MOVE MOVE MOVE MOVE MOVE MOVE MOVE MOVE MOVE MOVE MOVE MOVE MOVE MOVE MOVE MOVE MOVE MOVE MOVE MOVE MOVE - - - /// - /// A collection of RouteDescriptors - typically the static DefaultCollection is used - /// - public class RouteDescriptorCollection - { - public static RouteDescriptorCollection DefaultCollection - { - get - { - if (_DefaultCollection == null) - _DefaultCollection = new RouteDescriptorCollection(); - return _DefaultCollection; - } - } - static RouteDescriptorCollection _DefaultCollection; - - List RouteDescriptors = new List(); - - /// - /// Adds a RouteDescriptor to the list. If an existing RouteDescriptor for the - /// destination exists already, it will not be added - in order to preserve - /// proper route releasing. - /// - /// - public void AddRouteDescriptor(RouteDescriptor descriptor) - { - if (RouteDescriptors.Any(t => t.Destination == descriptor.Destination)) - { - Debug.Console(1, descriptor.Destination, - "Route to [{0}] already exists in global routes table", descriptor.Source.Key); - return; - } - RouteDescriptors.Add(descriptor); - } - - /// - /// Gets the RouteDescriptor for a destination - /// - /// null if no RouteDescriptor for a destination exists - public RouteDescriptor GetRouteDescriptorForDestination(IRoutingInputs destination) - { - return RouteDescriptors.FirstOrDefault(rd => rd.Destination == destination); - } - - /// - /// Returns the RouteDescriptor for a given destination AND removes it from collection. - /// Returns null if no route with the provided destination exists. - /// - public RouteDescriptor RemoveRouteDescriptor(IRoutingInputs destination) - { - var descr = GetRouteDescriptorForDestination(destination); - if (descr != null) - RouteDescriptors.Remove(descr); - return descr; - } - } - - /// - /// Represents an collection of individual route steps between Source and Destination - /// - public class RouteDescriptor - { - public IRoutingInputs Destination { get; private set; } - public IRoutingOutputs Source { get; private set; } - public eRoutingSignalType SignalType { get; private set; } - public List Routes { get; private set; } - - - public RouteDescriptor(IRoutingOutputs source, IRoutingInputs destination, eRoutingSignalType signalType) - { - Destination = destination; - Source = source; - SignalType = signalType; - Routes = new List(); - } - - /// - /// Executes all routes described in this collection. Typically called via - /// extension method IRoutingInputs.ReleaseAndMakeRoute() - /// - public void ExecuteRoutes() - { - foreach (var route in Routes) - { - Debug.Console(2, "ExecuteRoutes: {0}", route.ToString()); - if (route.SwitchingDevice is IRoutingSink) - { - var device = route.SwitchingDevice as IRoutingSinkWithSwitching; - if (device == null) - continue; - - device.ExecuteSwitch(route.InputPort.Selector); - } - else if (route.SwitchingDevice is IRouting) - { - (route.SwitchingDevice as IRouting).ExecuteSwitch(route.InputPort.Selector, route.OutputPort.Selector, SignalType); - route.OutputPort.InUseTracker.AddUser(Destination, "destination-" + SignalType); - Debug.Console(2, "Output port {0} routing. Count={1}", route.OutputPort.Key, route.OutputPort.InUseTracker.InUseCountFeedback.UShortValue); - } - } - } - - /// - /// Releases all routes in this collection. Typically called via - /// extension method IRoutingInputs.ReleaseAndMakeRoute() - /// - public void ReleaseRoutes() - { - foreach (var route in Routes) - { - if (route.SwitchingDevice is IRouting) - { - // Pull the route from the port. Whatever is watching the output's in use tracker is - // responsible for responding appropriately. - route.OutputPort.InUseTracker.RemoveUser(Destination, "destination-" + SignalType); - Debug.Console(2, "Port {0} releasing. Count={1}", route.OutputPort.Key, route.OutputPort.InUseTracker.InUseCountFeedback.UShortValue); - } - } - } - - public override string ToString() - { - var routesText = Routes.Select(r => r.ToString()).ToArray(); - return string.Format("Route table from {0} to {1}:\r{2}", Source.Key, Destination.Key, string.Join("\r", routesText)); - } - } - - /// - /// Represents an individual link for a route - /// - public class RouteSwitchDescriptor - { - public IRoutingInputs SwitchingDevice { get { return InputPort.ParentDevice; } } - public RoutingOutputPort OutputPort { get; set; } - public RoutingInputPort InputPort { get; set; } - - public RouteSwitchDescriptor(RoutingInputPort inputPort) - { - InputPort = inputPort; - } - - public RouteSwitchDescriptor(RoutingOutputPort outputPort, RoutingInputPort inputPort) - { - InputPort = inputPort; - OutputPort = outputPort; - } - - public override string ToString() - { - if(SwitchingDevice is IRouting) - return string.Format("{0} switches output '{1}' to input '{2}'", SwitchingDevice.Key, OutputPort.Selector, InputPort.Selector); - else - return string.Format("{0} switches to input '{1}'", SwitchingDevice.Key, InputPort.Selector); - - } - } + } + + destination.ReleaseRoute(); + + RunRouteRequest(routeRequest); + } + + public static void RunRouteRequest(RouteRequest request) + { + if (request.Source == null) return; + var newRoute = request.Destination.GetRouteToSource(request.Source, request.SignalType); + if (newRoute == null) return; + RouteDescriptorCollection.DefaultCollection.AddRouteDescriptor(newRoute); + Debug.Console(2, request.Destination, "Executing full route"); + newRoute.ExecuteRoutes(); + } + + /// + /// Will release the existing route on the destination, if it is found in + /// RouteDescriptorCollection.DefaultCollection + /// + /// + public static void ReleaseRoute(this IRoutingSink destination) + { + RouteRequest existingRequest; + + if (RouteRequests.TryGetValue(destination.Key, out existingRequest) && destination is IWarmingCooling) + { + var coolingDevice = destination as IWarmingCooling; + + coolingDevice.IsCoolingDownFeedback.OutputChange -= existingRequest.HandleCooldown; + } + + RouteRequests.Remove(destination.Key); + + var current = RouteDescriptorCollection.DefaultCollection.RemoveRouteDescriptor(destination); + if (current != null) + { + Debug.Console(1, destination, "Releasing current route: {0}", current.Source.Key); + current.ReleaseRoutes(); + } + } + + /// + /// 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 GetRouteToSource(this IRoutingSink destination, IRoutingOutputs source, eRoutingSignalType signalType) + { + var routeDescr = new RouteDescriptor(source, destination, signalType); + // if it's a single signal type, find the route + if ((signalType & (eRoutingSignalType.Audio & eRoutingSignalType.Video)) == (eRoutingSignalType.Audio & eRoutingSignalType.Video)) + { + Debug.Console(1, destination, "Attempting to build source route from {0}", source.Key); + if (!destination.GetRouteToSource(source, null, null, signalType, 0, routeDescr)) + routeDescr = null; + } + // otherwise, audioVideo needs to be handled as two steps. + else + { + Debug.Console(1, destination, "Attempting to build audio and video routes from {0}", source.Key); + var audioSuccess = destination.GetRouteToSource(source, null, null, eRoutingSignalType.Audio, 0, routeDescr); + if (!audioSuccess) + Debug.Console(1, destination, "Cannot find audio route to {0}", source.Key); + var videoSuccess = destination.GetRouteToSource(source, null, null, eRoutingSignalType.Video, 0, routeDescr); + if (!videoSuccess) + Debug.Console(1, destination, "Cannot find video route to {0}", source.Key); + if (!audioSuccess && !videoSuccess) + routeDescr = null; + } + + //Debug.Console(1, destination, "Route{0} discovered", routeDescr == null ? " NOT" : ""); + return routeDescr; + } + + /// + /// 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 + /// hoping to find the source. + /// + /// + /// + /// The RoutingOutputPort whose link is being checked for a route + /// Prevents Devices from being twice-checked + /// This recursive function should not be called with AudioVideo + /// Just an informational counter + /// The RouteDescriptor being populated as the route is discovered + /// true if source is hit + static bool GetRouteToSource(this IRoutingInputs destination, IRoutingOutputs source, + RoutingOutputPort outputPortToUse, List alreadyCheckedDevices, + eRoutingSignalType signalType, int cycle, RouteDescriptor routeTable) + { + cycle++; + Debug.Console(2, "GetRouteToSource: {0} {1}--> {2}", cycle, source.Key, destination.Key); + + RoutingInputPort goodInputPort = null; + var destDevInputTies = TieLineCollection.Default.Where(t => + t.DestinationPort.ParentDevice == destination && (t.Type == signalType || (t.Type & (eRoutingSignalType.Audio | eRoutingSignalType.Video)) == (eRoutingSignalType.Audio | eRoutingSignalType.Video))); + + // find a direct tie + var directTie = destDevInputTies.FirstOrDefault( + t => t.DestinationPort.ParentDevice == destination + && t.SourcePort.ParentDevice == source); + if (directTie != null) // Found a tie directly to the source + { + goodInputPort = directTie.DestinationPort; + } + else // no direct-connect. Walk back devices. + { + Debug.Console(2, destination, "is not directly connected to {0}. Walking down tie lines", source.Key); + + // No direct tie? Run back out on the inputs' attached devices... + // Only the ones that are routing devices + var attachedMidpoints = destDevInputTies.Where(t => t.SourcePort.ParentDevice is IRoutingInputsOutputs); + + //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(); + alreadyCheckedDevices.Add(destination as IRoutingInputsOutputs); + + foreach (var inputTieToTry in attachedMidpoints) + { + var upstreamDeviceOutputPort = inputTieToTry.SourcePort; + var upstreamRoutingDevice = upstreamDeviceOutputPort.ParentDevice as IRoutingInputsOutputs; + Debug.Console(2, destination, "Trying to find route on {0}", upstreamRoutingDevice.Key); + + // Check if this previous device has already been walked + if (alreadyCheckedDevices.Contains(upstreamRoutingDevice)) + { + Debug.Console(2, destination, "Skipping input {0} on {1}, this was already checked", upstreamRoutingDevice.Key, destination.Key); + continue; + } + // haven't seen this device yet. Do it. Pass the output port to the next + // level to enable switching on success + var upstreamRoutingSuccess = upstreamRoutingDevice.GetRouteToSource(source, upstreamDeviceOutputPort, + alreadyCheckedDevices, signalType, cycle, routeTable); + if (upstreamRoutingSuccess) + { + Debug.Console(2, destination, "Upstream device route found"); + goodInputPort = inputTieToTry.DestinationPort; + break; // Stop looping the inputs in this cycle + } + } + } + + // we have a route on corresponding inputPort. *** Do the route *** + if (goodInputPort != null) + { + //Debug.Console(2, destination, "adding RouteDescriptor"); + if (outputPortToUse == null) + { + // it's a sink device + routeTable.Routes.Add(new RouteSwitchDescriptor(goodInputPort)); + } + else if (destination is IRouting) + { + routeTable.Routes.Add(new RouteSwitchDescriptor (outputPortToUse, goodInputPort)); + } + else // device is merely IRoutingInputOutputs + Debug.Console(2, destination, " No routing. Passthrough device"); + //Debug.Console(2, destination, "Exiting cycle {0}", cycle); + return true; + } + + Debug.Console(2, destination, "No route found to {0}", source.Key); + return false; + } + } + + + + + + // MOVE MOVE MOVE MOVE MOVE MOVE MOVE MOVE MOVE MOVE MOVE MOVE MOVE MOVE MOVE MOVE MOVE MOVE MOVE MOVE MOVE + + + /// + /// A collection of RouteDescriptors - typically the static DefaultCollection is used + /// + public class RouteDescriptorCollection + { + public static RouteDescriptorCollection DefaultCollection + { + get + { + if (_DefaultCollection == null) + _DefaultCollection = new RouteDescriptorCollection(); + return _DefaultCollection; + } + } + static RouteDescriptorCollection _DefaultCollection; + + List RouteDescriptors = new List(); + + /// + /// Adds a RouteDescriptor to the list. If an existing RouteDescriptor for the + /// destination exists already, it will not be added - in order to preserve + /// proper route releasing. + /// + /// + public void AddRouteDescriptor(RouteDescriptor descriptor) + { + if (RouteDescriptors.Any(t => t.Destination == descriptor.Destination)) + { + Debug.Console(1, descriptor.Destination, + "Route to [{0}] already exists in global routes table", descriptor.Source.Key); + return; + } + RouteDescriptors.Add(descriptor); + } + + /// + /// Gets the RouteDescriptor for a destination + /// + /// null if no RouteDescriptor for a destination exists + public RouteDescriptor GetRouteDescriptorForDestination(IRoutingInputs destination) + { + return RouteDescriptors.FirstOrDefault(rd => rd.Destination == destination); + } + + /// + /// Returns the RouteDescriptor for a given destination AND removes it from collection. + /// Returns null if no route with the provided destination exists. + /// + public RouteDescriptor RemoveRouteDescriptor(IRoutingInputs destination) + { + var descr = GetRouteDescriptorForDestination(destination); + if (descr != null) + RouteDescriptors.Remove(descr); + return descr; + } + } + + /// + /// Represents an collection of individual route steps between Source and Destination + /// + public class RouteDescriptor + { + public IRoutingInputs Destination { get; private set; } + public IRoutingOutputs Source { get; private set; } + public eRoutingSignalType SignalType { get; private set; } + public List Routes { get; private set; } + + + public RouteDescriptor(IRoutingOutputs source, IRoutingInputs destination, eRoutingSignalType signalType) + { + Destination = destination; + Source = source; + SignalType = signalType; + Routes = new List(); + } + + /// + /// Executes all routes described in this collection. Typically called via + /// extension method IRoutingInputs.ReleaseAndMakeRoute() + /// + public void ExecuteRoutes() + { + foreach (var route in Routes) + { + Debug.Console(2, "ExecuteRoutes: {0}", route.ToString()); + if (route.SwitchingDevice is IRoutingSink) + { + var device = route.SwitchingDevice as IRoutingSinkWithSwitching; + if (device == null) + continue; + + device.ExecuteSwitch(route.InputPort.Selector); + } + else if (route.SwitchingDevice is IRouting) + { + (route.SwitchingDevice as IRouting).ExecuteSwitch(route.InputPort.Selector, route.OutputPort.Selector, SignalType); + route.OutputPort.InUseTracker.AddUser(Destination, "destination-" + SignalType); + Debug.Console(2, "Output port {0} routing. Count={1}", route.OutputPort.Key, route.OutputPort.InUseTracker.InUseCountFeedback.UShortValue); + } + } + } + + /// + /// Releases all routes in this collection. Typically called via + /// extension method IRoutingInputs.ReleaseAndMakeRoute() + /// + public void ReleaseRoutes() + { + foreach (var route in Routes) + { + if (route.SwitchingDevice is IRouting) + { + // Pull the route from the port. Whatever is watching the output's in use tracker is + // responsible for responding appropriately. + route.OutputPort.InUseTracker.RemoveUser(Destination, "destination-" + SignalType); + Debug.Console(2, "Port {0} releasing. Count={1}", route.OutputPort.Key, route.OutputPort.InUseTracker.InUseCountFeedback.UShortValue); + } + } + } + + public override string ToString() + { + var routesText = Routes.Select(r => r.ToString()).ToArray(); + return string.Format("Route table from {0} to {1}:\r{2}", Source.Key, Destination.Key, string.Join("\r", routesText)); + } + } + + /// + /// Represents an individual link for a route + /// + public class RouteSwitchDescriptor + { + public IRoutingInputs SwitchingDevice { get { return InputPort.ParentDevice; } } + public RoutingOutputPort OutputPort { get; set; } + public RoutingInputPort InputPort { get; set; } + + public RouteSwitchDescriptor(RoutingInputPort inputPort) + { + InputPort = inputPort; + } + + public RouteSwitchDescriptor(RoutingOutputPort outputPort, RoutingInputPort inputPort) + { + InputPort = inputPort; + OutputPort = outputPort; + } + + public override string ToString() + { + if(SwitchingDevice is IRouting) + return string.Format("{0} switches output '{1}' to input '{2}'", SwitchingDevice.Key, OutputPort.Selector, InputPort.Selector); + else + return string.Format("{0} switches to input '{1}'", SwitchingDevice.Key, InputPort.Selector); + + } + } } \ No newline at end of file diff --git a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Web/EssemtialsWebApi.cs b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Web/EssemtialsWebApi.cs new file mode 100644 index 00000000..973b303b --- /dev/null +++ b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Web/EssemtialsWebApi.cs @@ -0,0 +1,242 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using Crestron.SimplSharp; +using Crestron.SimplSharp.WebScripting; +using Crestron.SimplSharpPro.Diagnostics; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; +using PepperDash.Core; +using PepperDash.Core.Web; +using PepperDash.Essentials.Core.Web.RequestHandlers; + +namespace PepperDash.Essentials.Core.Web +{ + public class EssemtialsWebApi : EssentialsDevice + { + private readonly WebApiServer _server; + + /// + /// http(s)://{ipaddress}/cws/{basePath} + /// http(s)://{ipaddress}/VirtualControl/Rooms/{roomId}/cws/{basePath} + /// + private readonly string _defaultBasePath = + CrestronEnvironment.DevicePlatform == eDevicePlatform.Appliance ? string.Format("/app{0:00}/api", InitialParametersClass.ApplicationNumber) : "/api"; + + // TODO [ ] Reset debug levels to proper value Trace = 0, Info = 1, Verbose = 2 + private const int DebugTrace = 0; + private const int DebugInfo = 0; + private const int DebugVerbose = 0; + + /// + /// CWS base path + /// + public string BasePath { get; private set; } + + /// + /// Tracks if CWS is registered + /// + public bool IsRegistered + { + get { return _server.IsRegistered; } + } + + /// + /// Constructor + /// + /// + /// + public EssemtialsWebApi(string key, string name) + : this(key, name, null) + { + } + + /// + /// Constructor + /// + /// + /// + /// + public EssemtialsWebApi(string key, string name, EssentialsWebApiPropertiesConfig config) + : base(key, name) + { + Key = key; + + if (config == null) + BasePath = _defaultBasePath; + else + BasePath = string.IsNullOrEmpty(config.BasePath) ? _defaultBasePath : config.BasePath; + + _server = new WebApiServer(Key, Name, BasePath); + } + + /// + /// Custom activate, add routes + /// + /// + public override bool CustomActivate() + { + var routes = new List + { + new HttpCwsRoute("reportversions") + { + Name = "ReportVersions", + RouteHandler = new ReportVersionsRequestHandler() + }, + new HttpCwsRoute("appdebug") + { + Name = "AppDebug", + RouteHandler = new AppDebugRequestHandler() + }, + new HttpCwsRoute("devlist") + { + Name = "DevList", + RouteHandler = new DevListRequestHandler() + }, + new HttpCwsRoute("devprops") + { + Name = "DevProps", + RouteHandler = new DevPropsRequestHandler() + }, + //new HttpCwsRoute("devprops/{key}") + //{ + // Name = "DevProps", + // RouteHandler = new DevPropsRequestHandler() + //}, + new HttpCwsRoute("devjson") + { + Name = "DevJson", + RouteHandler = new DevJsonRequestHandler() + }, + new HttpCwsRoute("setdevicestreamdebug") + { + Name = "SetDeviceStreamDebug", + RouteHandler = new SetDeviceStreamDebugRequestHandler() + }, + //new HttpCwsRoute("setdevicestreamdebug/{deviceKey}/{state}") + //{ + // Name = "SetDeviceStreamDebug", + // RouteHandler = new SetDeviceStreamDebugRequestHandler() + //}, + new HttpCwsRoute("disableallstreamdebug") + { + Name = "DisableAllStreamDebug", + RouteHandler = new DisableAllStreamDebugRequestHandler() + }, + new HttpCwsRoute("showconfig") + { + Name = "ShowConfig", + RouteHandler = new ShowConfigRequestHandler() + }, + new HttpCwsRoute("gettypes") + { + Name = "GetTypes", + RouteHandler = new GetTypesRequestHandler() + }, + new HttpCwsRoute("gettypes/{filter}") + { + Name = "GetTypesByFilter", + RouteHandler = new GetTypesByFilterRequestHandler() + }, + new HttpCwsRoute("getjoinmap/{bridgeKey}") + { + Name = "GetJoinMapsForBridgeKey", + RouteHandler = new GetJoinMapForBridgeKeyRequestHandler() + }, + new HttpCwsRoute("getjoinmap/{bridgeKey}/{deviceKey}") + { + Name = "GetJoinMapsForDeviceKey", + RouteHandler = new GetJoinMapForDeviceKeyRequestHandler() + }, + new HttpCwsRoute("feedbacks/{deviceKey}") + { + Name = "GetFeedbacksForDeviceKey", + RouteHandler = new GetFeedbacksForDeviceRequestHandler() + } + }; + + foreach (var route in routes.Where(route => route != null)) + { + var r = route; + _server.AddRoute(r); + } + + return base.CustomActivate(); + } + + /// + /// Initializes the CWS class + /// + public override void Initialize() + { + // If running on an appliance + if (CrestronEnvironment.DevicePlatform == eDevicePlatform.Appliance) + { + /* + RMC4> + WEBSERVER [ON | OFF | TIMEOUT | MAXSESSIONSPERUSER ] + WEBSERVER [TIMEOUT] will display current session timeout value + WEBSERVER MAXSESSIONSPERUSER will display current max web sessions per user + WEBSERVER ALLOWSHAREDSESSION will display whether 'samesite = none' would be set on cookies + No parameter - displays current setting + */ + var response = string.Empty; + CrestronConsole.SendControlSystemCommand("webserver", ref response); + if (response.Contains("OFF")) return; + + var is4Series = eCrestronSeries.Series4 == (Global.ProcessorSeries & eCrestronSeries.Series4); + Debug.Console(DebugTrace, Debug.ErrorLogLevel.Notice, "Starting Essentials Web API on {0} Appliance", is4Series ? "4-series" : "3-series"); + + _server.Start(); + + GetPaths(); + + return; + } + + // Automatically start CWS when running on a server (Linux OS, Virtual Control) + Debug.Console(DebugTrace, Debug.ErrorLogLevel.Notice, "Starting Essentials Web API on Virtual Control Server"); + + _server.Start(); + + GetPaths(); + } + + /// + /// Print the available pahts + /// + /// + /// http(s)://{ipaddress}/cws/{basePath} + /// http(s)://{ipaddress}/VirtualControl/Rooms/{roomId}/cws/{basePath} + /// + public void GetPaths() + { + Debug.Console(DebugTrace, this, "{0}", new String('-', 50)); + + var currentIp = CrestronEthernetHelper.GetEthernetParameter( + CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_CURRENT_IP_ADDRESS, 0); + + var hostname = CrestronEthernetHelper.GetEthernetParameter( + CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_HOSTNAME, 0); + + var path = CrestronEnvironment.DevicePlatform == eDevicePlatform.Server + ? string.Format("http(s)://{0}/VirtualControl/Rooms/{1}/cws{2}", hostname, InitialParametersClass.RoomId, BasePath) + : string.Format("http(s)://{0}/cws{1}", currentIp, BasePath); + + Debug.Console(DebugTrace, this, "Server:{0}", path); + + var routeCollection = _server.GetRouteCollection(); + if (routeCollection == null) + { + Debug.Console(DebugTrace, this, "Server route collection is null"); + return; + } + Debug.Console(DebugTrace, this, "Configured Routes:"); + foreach (var route in routeCollection) + { + Debug.Console(DebugTrace, this, "{0}: {1}/{2}", route.Name, path, route.Url); + } + Debug.Console(DebugTrace, this, "{0}", new String('-', 50)); + } + } +} \ No newline at end of file diff --git a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Web/EssentialsWebApiFactory.cs b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Web/EssentialsWebApiFactory.cs new file mode 100644 index 00000000..51361c2c --- /dev/null +++ b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Web/EssentialsWebApiFactory.cs @@ -0,0 +1,25 @@ +using System.Collections.Generic; +using PepperDash.Core; +using PepperDash.Essentials.Core.Config; + +namespace PepperDash.Essentials.Core.Web +{ + public class EssentialsWebApiFactory : EssentialsDeviceFactory + { + public EssentialsWebApiFactory() + { + TypeNames = new List { "EssentialsWebApi" }; + } + + public override EssentialsDevice BuildDevice(DeviceConfig dc) + { + Debug.Console(1, "Factory Attempting to create new Essentials Web API Server"); + + var props = dc.Properties.ToObject(); + if (props != null) return new EssemtialsWebApi(dc.Key, dc.Name, props); + + Debug.Console(1, "Factory failed to create new Essentials Web API Server"); + return null; + } + } +} \ No newline at end of file diff --git a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Web/EssentialsWebApiHelpers.cs b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Web/EssentialsWebApiHelpers.cs new file mode 100644 index 00000000..4830edb4 --- /dev/null +++ b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Web/EssentialsWebApiHelpers.cs @@ -0,0 +1,87 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using Crestron.SimplSharp.WebScripting; +using PepperDash.Core; + +namespace PepperDash.Essentials.Core.Web +{ + public class EssentialsWebApiHelpers + { + public static string GetRequestBody(HttpCwsRequest request) + { + var bytes = new Byte[request.ContentLength]; + + request.InputStream.Read(bytes, 0, request.ContentLength); + + return Encoding.UTF8.GetString(bytes, 0, bytes.Length); + } + + public static object MapToAssemblyObject(LoadedAssembly assembly) + { + return new + { + Name = assembly.Name, + Version = assembly.Version + }; + } + + public static object MapToDeviceListObject(IKeyed device) + { + return new + { + Key = device.Key, + Name = (device is IKeyName) + ? (device as IKeyName).Name + : "---" + }; + } + + public static object MapJoinToObject(string key, JoinMapBaseAdvanced join) + { + var kp = new KeyValuePair(key, join); + + return MapJoinToObject(kp); + } + + public static object MapJoinToObject(KeyValuePair join) + { + return new + { + DeviceKey = join.Key, + Joins = join.Value.Joins.Select(j => MapJoinDataCompleteToObject(j)) + }; + } + + public static object MapJoinDataCompleteToObject(KeyValuePair joinData) + { + return new + { + Signal = joinData.Key, + Description = joinData.Value.Metadata.Description, + JoinNumber = joinData.Value.JoinNumber, + JoinSpan = joinData.Value.JoinSpan, + JoinType = joinData.Value.Metadata.JoinType.ToString(), + JoinCapabilities = joinData.Value.Metadata.JoinCapabilities.ToString() + }; + } + + public static object MapDeviceTypeToObject(string key, DeviceFactoryWrapper device) + { + var kp = new KeyValuePair(key, device); + + return MapDeviceTypeToObject(kp); + } + + public static object MapDeviceTypeToObject(KeyValuePair device) + { + return new + { + Type = device.Key, + Description = device.Value.Description, + CType = device.Value.CType == null ? "---": device.Value.CType.ToString() + }; + } + } +} \ No newline at end of file diff --git a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Web/EssentialsWebApiPropertiesConfig.cs b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Web/EssentialsWebApiPropertiesConfig.cs new file mode 100644 index 00000000..a57e1ce9 --- /dev/null +++ b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Web/EssentialsWebApiPropertiesConfig.cs @@ -0,0 +1,10 @@ +using Newtonsoft.Json; + +namespace PepperDash.Essentials.Core.Web +{ + public class EssentialsWebApiPropertiesConfig + { + [JsonProperty("basePath")] + public string BasePath { get; set; } + } +} \ No newline at end of file diff --git a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Web/RequestHandlers/AppDebugRequestHandler.cs b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Web/RequestHandlers/AppDebugRequestHandler.cs new file mode 100644 index 00000000..f80f9f7f --- /dev/null +++ b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Web/RequestHandlers/AppDebugRequestHandler.cs @@ -0,0 +1,150 @@ +using System; +using System.Text; +using Crestron.SimplSharp.WebScripting; +using Newtonsoft.Json; +using PepperDash.Core; +using PepperDash.Core.Web.RequestHandlers; + +namespace PepperDash.Essentials.Core.Web.RequestHandlers +{ + public class AppDebugRequestHandler : WebApiBaseRequestHandler + { + /// + /// Handles CONNECT method requests + /// + /// + protected override void HandleConnect(HttpCwsContext context) + { + context.Response.StatusCode = 501; + context.Response.StatusDescription = "Not Implemented"; + context.Response.End(); + } + + /// + /// Handles DELETE method requests + /// + /// + protected override void HandleDelete(HttpCwsContext context) + { + context.Response.StatusCode = 501; + context.Response.StatusDescription = "Not Implemented"; + context.Response.End(); + } + + /// + /// Handles GET method requests + /// + /// + protected override void HandleGet(HttpCwsContext context) + { + var appDebug = new AppDebug {Level = Debug.Level}; + + var body = JsonConvert.SerializeObject(appDebug, Formatting.Indented); + + context.Response.StatusCode = 200; + context.Response.StatusDescription = "OK"; + context.Response.Write(body, false); + context.Response.End(); + } + + /// + /// Handles HEAD method requests + /// + /// + protected override void HandleHead(HttpCwsContext context) + { + context.Response.StatusCode = 501; + context.Response.StatusDescription = "Not Implemented"; + context.Response.End(); + } + + /// + /// Handles OPTIONS method requests + /// + /// + protected override void HandleOptions(HttpCwsContext context) + { + context.Response.StatusCode = 501; + context.Response.StatusDescription = "Not Implemented"; + context.Response.End(); + } + + /// + /// Handles PATCH method requests + /// + /// + protected override void HandlePatch(HttpCwsContext context) + { + context.Response.StatusCode = 501; + context.Response.StatusDescription = "Not Implemented"; + context.Response.End(); + } + + /// + /// Handles POST method requests + /// + /// + protected override void HandlePost(HttpCwsContext context) + { + if (context.Request.ContentLength < 0) + { + context.Response.StatusCode = 400; + context.Response.StatusDescription = "Bad Request"; + context.Response.End(); + + return; + } + + var data = EssentialsWebApiHelpers.GetRequestBody(context.Request); + if (string.IsNullOrEmpty(data)) + { + context.Response.StatusCode = 400; + context.Response.StatusDescription = "Bad Request"; + context.Response.End(); + + return; + } + + var appDebug = new AppDebug(); + var requestBody = JsonConvert.DeserializeAnonymousType(data, appDebug); + + Debug.SetDebugLevel(requestBody.Level); + + appDebug.Level = Debug.Level; + var responseBody = JsonConvert.SerializeObject(appDebug, Formatting.Indented); + + context.Response.StatusCode = 200; + context.Response.StatusDescription = "OK"; + context.Response.Write(responseBody, false); + context.Response.End(); + } + + /// + /// Handles PUT method requests + /// + /// + protected override void HandlePut(HttpCwsContext context) + { + context.Response.StatusCode = 501; + context.Response.StatusDescription = "Not Implemented"; + context.Response.End(); + } + + /// + /// Handles TRACE method requests + /// + /// + protected override void HandleTrace(HttpCwsContext context) + { + context.Response.StatusCode = 501; + context.Response.StatusDescription = "Not Implemented"; + context.Response.End(); + } + } + + public class AppDebug + { + [JsonProperty("level", NullValueHandling = NullValueHandling.Ignore)] + public int Level { get; set; } + } +} \ No newline at end of file diff --git a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Web/RequestHandlers/DefaultRequestHandler.cs b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Web/RequestHandlers/DefaultRequestHandler.cs new file mode 100644 index 00000000..4ffa500a --- /dev/null +++ b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Web/RequestHandlers/DefaultRequestHandler.cs @@ -0,0 +1,107 @@ +using Crestron.SimplSharp.WebScripting; +using PepperDash.Core.Web.RequestHandlers; + +namespace PepperDash.Essentials.Core.Web.RequestHandlers +{ + public class DefaultRequestHandler : WebApiBaseRequestHandler + { + /// + /// Handles CONNECT method requests + /// + /// + protected override void HandleConnect(HttpCwsContext context) + { + context.Response.StatusCode = 418; + context.Response.StatusDescription = "I'm a teapot"; + context.Response.End(); + } + + /// + /// Handles DELETE method requests + /// + /// + protected override void HandleDelete(HttpCwsContext context) + { + context.Response.StatusCode = 418; + context.Response.StatusDescription = "I'm a teapot"; + context.Response.End(); + } + + /// + /// Handles GET method requests + /// + /// + protected override void HandleGet(HttpCwsContext context) + { + context.Response.StatusCode = 418; + context.Response.StatusDescription = "I'm a teapot"; + context.Response.End(); + } + + /// + /// Handles HEAD method requests + /// + /// + protected override void HandleHead(HttpCwsContext context) + { + context.Response.StatusCode = 418; + context.Response.StatusDescription = "I'm a teapot"; + context.Response.End(); + } + + /// + /// Handles OPTIONS method requests + /// + /// + protected override void HandleOptions(HttpCwsContext context) + { + context.Response.StatusCode = 418; + context.Response.StatusDescription = "I'm a teapot"; + context.Response.End(); + } + + /// + /// Handles PATCH method requests + /// + /// + protected override void HandlePatch(HttpCwsContext context) + { + context.Response.StatusCode = 418; + context.Response.StatusDescription = "I'm a teapot"; + context.Response.End(); + } + + /// + /// Handles POST method requests + /// + /// + protected override void HandlePost(HttpCwsContext context) + { + context.Response.StatusCode = 418; + context.Response.StatusDescription = "I'm a teapot"; + context.Response.End(); + } + + /// + /// Handles PUT method requests + /// + /// + protected override void HandlePut(HttpCwsContext context) + { + context.Response.StatusCode = 418; + context.Response.StatusDescription = "I'm a teapot"; + context.Response.End(); + } + + /// + /// Handles TRACE method requests + /// + /// + protected override void HandleTrace(HttpCwsContext context) + { + context.Response.StatusCode = 418; + context.Response.StatusDescription = "I'm a teapot"; + context.Response.End(); + } + } +} \ No newline at end of file diff --git a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Web/RequestHandlers/DevJsonRequestHandler.cs b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Web/RequestHandlers/DevJsonRequestHandler.cs new file mode 100644 index 00000000..6080465b --- /dev/null +++ b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Web/RequestHandlers/DevJsonRequestHandler.cs @@ -0,0 +1,139 @@ +using System; +using System.Text; +using Crestron.SimplSharp.WebScripting; +using PepperDash.Core.Web.RequestHandlers; + +namespace PepperDash.Essentials.Core.Web.RequestHandlers +{ + public class DevJsonRequestHandler : WebApiBaseRequestHandler + { + /// + /// Handles CONNECT method requests + /// + /// + protected override void HandleConnect(HttpCwsContext context) + { + context.Response.StatusCode = 501; + context.Response.StatusDescription = "Not Implemented"; + context.Response.End(); + } + + /// + /// Handles DELETE method requests + /// + /// + protected override void HandleDelete(HttpCwsContext context) + { + context.Response.StatusCode = 501; + context.Response.StatusDescription = "Not Implemented"; + context.Response.End(); + } + + /// + /// Handles GET method requests + /// + /// + protected override void HandleGet(HttpCwsContext context) + { + context.Response.StatusCode = 501; + context.Response.StatusDescription = "Not Implemented"; + context.Response.End(); + } + + /// + /// Handles HEAD method requests + /// + /// + protected override void HandleHead(HttpCwsContext context) + { + context.Response.StatusCode = 501; + context.Response.StatusDescription = "Not Implemented"; + context.Response.End(); + } + + /// + /// Handles OPTIONS method requests + /// + /// + protected override void HandleOptions(HttpCwsContext context) + { + context.Response.StatusCode = 501; + context.Response.StatusDescription = "Not Implemented"; + context.Response.End(); + } + + /// + /// Handles PATCH method requests + /// + /// + protected override void HandlePatch(HttpCwsContext context) + { + context.Response.StatusCode = 501; + context.Response.StatusDescription = "Not Implemented"; + context.Response.End(); + } + + /// + /// Handles POST method requests + /// + /// + protected override void HandlePost(HttpCwsContext context) + { + if (context.Request.ContentLength < 0) + { + context.Response.StatusCode = 400; + context.Response.StatusDescription = "Bad Request"; + context.Response.End(); + + return; + } + + var data = EssentialsWebApiHelpers.GetRequestBody(context.Request); + if (string.IsNullOrEmpty(data)) + { + context.Response.StatusCode = 400; + context.Response.StatusDescription = "Bad Request"; + context.Response.End(); + + return; + } + + try + { + DeviceJsonApi.DoDeviceActionWithJson(data); + + context.Response.StatusCode = 200; + context.Response.StatusDescription = "OK"; + context.Response.End(); + } + catch (Exception ex) + { + context.Response.StatusCode = 400; + context.Response.StatusDescription = "Bad Request"; + context.Response.End(); + } + } + + /// + /// Handles PUT method requests + /// + /// + protected override void HandlePut(HttpCwsContext context) + { + context.Response.StatusCode = 501; + context.Response.StatusDescription = "Not Implemented"; + context.Response.End(); + } + + /// + /// Handles TRACE method requests + /// + /// + protected override void HandleTrace(HttpCwsContext context) + { + context.Response.StatusCode = 501; + context.Response.StatusDescription = "Not Implemented"; + context.Response.End(); + } + } +} \ No newline at end of file diff --git a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Web/RequestHandlers/DevListRequestHandler.cs b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Web/RequestHandlers/DevListRequestHandler.cs new file mode 100644 index 00000000..c34542e2 --- /dev/null +++ b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Web/RequestHandlers/DevListRequestHandler.cs @@ -0,0 +1,128 @@ +using System.Linq; +using Crestron.SimplSharp.WebScripting; +using Newtonsoft.Json; +using PepperDash.Core.Web.RequestHandlers; + +namespace PepperDash.Essentials.Core.Web.RequestHandlers +{ + public class DevListRequestHandler : WebApiBaseRequestHandler + { + /// + /// Handles CONNECT method requests + /// + /// + protected override void HandleConnect(HttpCwsContext context) + { + context.Response.StatusCode = 501; + context.Response.StatusDescription = "Not Implemented"; + context.Response.End(); + } + + /// + /// Handles DELETE method requests + /// + /// + protected override void HandleDelete(HttpCwsContext context) + { + context.Response.StatusCode = 501; + context.Response.StatusDescription = "Not Implemented"; + context.Response.End(); + } + + /// + /// Handles GET method requests + /// + /// + protected override void HandleGet(HttpCwsContext context) + { + var allDevices = DeviceManager.AllDevices; + if (allDevices == null) + { + context.Response.StatusCode = 404; + context.Response.StatusDescription = "Not Found"; + context.Response.End(); + + return; + } + + allDevices.Sort((a, b) => System.String.Compare(a.Key, b.Key, System.StringComparison.Ordinal)); + + var deviceList = allDevices.Select(d => EssentialsWebApiHelpers.MapToDeviceListObject(d)).ToList(); + + var js = JsonConvert.SerializeObject(deviceList, Formatting.Indented); + + context.Response.StatusCode = 200; + context.Response.StatusDescription = "OK"; + context.Response.ContentType = "application/json"; + context.Response.ContentEncoding = System.Text.Encoding.UTF8; + context.Response.Write(js, false); + context.Response.End(); + } + + /// + /// Handles HEAD method requests + /// + /// + protected override void HandleHead(HttpCwsContext context) + { + context.Response.StatusCode = 501; + context.Response.StatusDescription = "Not Implemented"; + context.Response.End(); + } + + /// + /// Handles OPTIONS method requests + /// + /// + protected override void HandleOptions(HttpCwsContext context) + { + context.Response.StatusCode = 501; + context.Response.StatusDescription = "Not Implemented"; + context.Response.End(); + } + + /// + /// Handles PATCH method requests + /// + /// + protected override void HandlePatch(HttpCwsContext context) + { + context.Response.StatusCode = 501; + context.Response.StatusDescription = "Not Implemented"; + context.Response.End(); + } + + /// + /// Handles POST method requests + /// + /// + protected override void HandlePost(HttpCwsContext context) + { + context.Response.StatusCode = 501; + context.Response.StatusDescription = "Not Implemented"; + context.Response.End(); + } + + /// + /// Handles PUT method requests + /// + /// + protected override void HandlePut(HttpCwsContext context) + { + context.Response.StatusCode = 501; + context.Response.StatusDescription = "Not Implemented"; + context.Response.End(); + } + + /// + /// Handles TRACE method requests + /// + /// + protected override void HandleTrace(HttpCwsContext context) + { + context.Response.StatusCode = 501; + context.Response.StatusDescription = "Not Implemented"; + context.Response.End(); + } + } +} \ No newline at end of file diff --git a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Web/RequestHandlers/DevPropsRequestHandler.cs b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Web/RequestHandlers/DevPropsRequestHandler.cs new file mode 100644 index 00000000..b7dcc511 --- /dev/null +++ b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Web/RequestHandlers/DevPropsRequestHandler.cs @@ -0,0 +1,154 @@ +using System; +using System.Text; +using Crestron.SimplSharp.WebScripting; +using Newtonsoft.Json; +using PepperDash.Core.Web.RequestHandlers; + +namespace PepperDash.Essentials.Core.Web.RequestHandlers +{ + public class DevPropsRequestHandler : WebApiBaseRequestHandler + { + /// + /// Handles CONNECT method requests + /// + /// + protected override void HandleConnect(HttpCwsContext context) + { + context.Response.StatusCode = 501; + context.Response.StatusDescription = "Not Implemented"; + context.Response.End(); + } + + /// + /// Handles DELETE method requests + /// + /// + protected override void HandleDelete(HttpCwsContext context) + { + context.Response.StatusCode = 501; + context.Response.StatusDescription = "Not Implemented"; + context.Response.End(); + } + + /// + /// Handles GET method requests + /// + /// + protected override void HandleGet(HttpCwsContext context) + { + context.Response.StatusCode = 501; + context.Response.StatusDescription = "Not Implemented"; + context.Response.End(); + } + + /// + /// Handles HEAD method requests + /// + /// + protected override void HandleHead(HttpCwsContext context) + { + context.Response.StatusCode = 501; + context.Response.StatusDescription = "Not Implemented"; + context.Response.End(); + } + + /// + /// Handles OPTIONS method requests + /// + /// + protected override void HandleOptions(HttpCwsContext context) + { + context.Response.StatusCode = 501; + context.Response.StatusDescription = "Not Implemented"; + context.Response.End(); + } + + /// + /// Handles PATCH method requests + /// + /// + protected override void HandlePatch(HttpCwsContext context) + { + context.Response.StatusCode = 501; + context.Response.StatusDescription = "Not Implemented"; + context.Response.End(); + } + + /// + /// Handles POST method requests + /// + /// + protected override void HandlePost(HttpCwsContext context) + { + if (context.Request.ContentLength < 0) + { + context.Response.StatusCode = 400; + context.Response.StatusDescription = "Bad Request"; + context.Response.End(); + + return; + } + + var data = EssentialsWebApiHelpers.GetRequestBody(context.Request); + if (string.IsNullOrEmpty(data)) + { + context.Response.StatusCode = 400; + context.Response.StatusDescription = "Bad Request"; + context.Response.End(); + + return; + } + + var o = new DeviceActionWrapper(); + var body = JsonConvert.DeserializeAnonymousType(data, o); + + if (string.IsNullOrEmpty(body.DeviceKey)) + { + context.Response.StatusCode = 400; + context.Response.StatusDescription = "Bad Request"; + context.Response.End(); + + return; + } + + var deviceProps = DeviceJsonApi.GetProperties(body.DeviceKey); + if (deviceProps == null || deviceProps.ToLower().Contains("no device")) + { + context.Response.StatusCode = 404; + context.Response.StatusDescription = "Not Found"; + context.Response.End(); + + return; + } + + context.Response.StatusCode = 200; + context.Response.StatusDescription = "OK"; + context.Response.ContentType = "application/json"; + context.Response.ContentEncoding = Encoding.UTF8; + context.Response.Write(deviceProps, false); + context.Response.End(); + } + + /// + /// Handles PUT method requests + /// + /// + protected override void HandlePut(HttpCwsContext context) + { + context.Response.StatusCode = 501; + context.Response.StatusDescription = "Not Implemented"; + context.Response.End(); + } + + /// + /// Handles TRACE method requests + /// + /// + protected override void HandleTrace(HttpCwsContext context) + { + context.Response.StatusCode = 501; + context.Response.StatusDescription = "Not Implemented"; + context.Response.End(); + } + } +} \ No newline at end of file diff --git a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Web/RequestHandlers/DisableAllStreamDebugRequestHandler.cs b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Web/RequestHandlers/DisableAllStreamDebugRequestHandler.cs new file mode 100644 index 00000000..8cfc7315 --- /dev/null +++ b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Web/RequestHandlers/DisableAllStreamDebugRequestHandler.cs @@ -0,0 +1,109 @@ +using Crestron.SimplSharp.WebScripting; +using PepperDash.Core.Web.RequestHandlers; + +namespace PepperDash.Essentials.Core.Web.RequestHandlers +{ + public class DisableAllStreamDebugRequestHandler : WebApiBaseRequestHandler + { + /// + /// Handles CONNECT method requests + /// + /// + protected override void HandleConnect(HttpCwsContext context) + { + context.Response.StatusCode = 501; + context.Response.StatusDescription = "Not Implemented"; + context.Response.End(); + } + + /// + /// Handles DELETE method requests + /// + /// + protected override void HandleDelete(HttpCwsContext context) + { + context.Response.StatusCode = 501; + context.Response.StatusDescription = "Not Implemented"; + context.Response.End(); + } + + /// + /// Handles GET method requests + /// + /// + protected override void HandleGet(HttpCwsContext context) + { + context.Response.StatusCode = 501; + context.Response.StatusDescription = "Not Implemented"; + context.Response.End(); + } + + /// + /// Handles HEAD method requests + /// + /// + protected override void HandleHead(HttpCwsContext context) + { + context.Response.StatusCode = 501; + context.Response.StatusDescription = "Not Implemented"; + context.Response.End(); + } + + /// + /// Handles OPTIONS method requests + /// + /// + protected override void HandleOptions(HttpCwsContext context) + { + context.Response.StatusCode = 501; + context.Response.StatusDescription = "Not Implemented"; + context.Response.End(); + } + + /// + /// Handles PATCH method requests + /// + /// + protected override void HandlePatch(HttpCwsContext context) + { + context.Response.StatusCode = 501; + context.Response.StatusDescription = "Not Implemented"; + context.Response.End(); + } + + /// + /// Handles POST method requests + /// + /// + protected override void HandlePost(HttpCwsContext context) + { + DeviceManager.DisableAllDeviceStreamDebugging(); + + context.Response.StatusCode = 200; + context.Response.StatusDescription = "OK"; + context.Response.End(); + } + + /// + /// Handles PUT method requests + /// + /// + protected override void HandlePut(HttpCwsContext context) + { + context.Response.StatusCode = 501; + context.Response.StatusDescription = "Not Implemented"; + context.Response.End(); + } + + /// + /// Handles TRACE method requests + /// + /// + protected override void HandleTrace(HttpCwsContext context) + { + context.Response.StatusCode = 501; + context.Response.StatusDescription = "Not Implemented"; + context.Response.End(); + } + } +} \ No newline at end of file diff --git a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Web/RequestHandlers/GetFeedbacksForDeviceRequestHandler.cs b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Web/RequestHandlers/GetFeedbacksForDeviceRequestHandler.cs new file mode 100644 index 00000000..2f892f2b --- /dev/null +++ b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Web/RequestHandlers/GetFeedbacksForDeviceRequestHandler.cs @@ -0,0 +1,179 @@ +using System.Linq; +using Crestron.SimplSharp.WebScripting; +using Newtonsoft.Json; +using PepperDash.Core.Web.RequestHandlers; + +namespace PepperDash.Essentials.Core.Web.RequestHandlers +{ + public class GetFeedbacksForDeviceRequestHandler : WebApiBaseRequestHandler + { + /// + /// Handles CONNECT method requests + /// + /// + protected override void HandleConnect(HttpCwsContext context) + { + context.Response.StatusCode = 501; + context.Response.StatusDescription = "Not Implemented"; + context.Response.End(); + } + + /// + /// Handles DELETE method requests + /// + /// + protected override void HandleDelete(HttpCwsContext context) + { + context.Response.StatusCode = 501; + context.Response.StatusDescription = "Not Implemented"; + context.Response.End(); + } + + /// + /// Handles GET method requests + /// + /// + protected override void HandleGet(HttpCwsContext context) + { + var routeData = context.Request.RouteData; + if (routeData == null) + { + context.Response.StatusCode = 400; + context.Response.StatusDescription = "Bad Request"; + context.Response.End(); + + return; + } + + object deviceObj; + if (!routeData.Values.TryGetValue("deviceKey", out deviceObj)) + { + context.Response.StatusCode = 400; + context.Response.StatusDescription = "Bad Request"; + context.Response.End(); + + return; + } + + + var device = DeviceManager.GetDeviceForKey(deviceObj.ToString()) as IHasFeedback; + if (device == null) + { + context.Response.StatusCode = 404; + context.Response.StatusDescription = "Not Found"; + context.Response.End(); + + return; + } + + var boolFeedback = + from feedback in device.Feedbacks.OfType() + where !string.IsNullOrEmpty(feedback.Key) + select new + { + FeedbackKey = feedback.Key, + Value = feedback.BoolValue + }; + + var intFeedback = + from feedback in device.Feedbacks.OfType() + where !string.IsNullOrEmpty(feedback.Key) + select new + { + FeedbackKey = feedback.Key, + Value = feedback.IntValue + }; + + var stringFeedback = + from feedback in device.Feedbacks.OfType() + where !string.IsNullOrEmpty(feedback.Key) + select new + { + FeedbackKey = feedback.Key, + Value = feedback.StringValue ?? string.Empty + }; + + var responseObj = new + { + BoolValues = boolFeedback, + IntValues = intFeedback, + SerialValues = stringFeedback + }; + + var js = JsonConvert.SerializeObject(responseObj, Formatting.Indented); + + context.Response.StatusCode = 200; + context.Response.StatusDescription = "OK"; + context.Response.ContentType = "application/json"; + context.Response.ContentEncoding = System.Text.Encoding.UTF8; + context.Response.Write(js, false); + context.Response.End(); + } + + /// + /// Handles HEAD method requests + /// + /// + protected override void HandleHead(HttpCwsContext context) + { + context.Response.StatusCode = 501; + context.Response.StatusDescription = "Not Implemented"; + context.Response.End(); + } + + /// + /// Handles OPTIONS method requests + /// + /// + protected override void HandleOptions(HttpCwsContext context) + { + context.Response.StatusCode = 501; + context.Response.StatusDescription = "Not Implemented"; + context.Response.End(); + } + + /// + /// Handles PATCH method requests + /// + /// + protected override void HandlePatch(HttpCwsContext context) + { + context.Response.StatusCode = 501; + context.Response.StatusDescription = "Not Implemented"; + context.Response.End(); + } + + /// + /// Handles POST method requests + /// + /// + protected override void HandlePost(HttpCwsContext context) + { + context.Response.StatusCode = 501; + context.Response.StatusDescription = "Not Implemented"; + context.Response.End(); + } + + /// + /// Handles PUT method requests + /// + /// + protected override void HandlePut(HttpCwsContext context) + { + context.Response.StatusCode = 501; + context.Response.StatusDescription = "Not Implemented"; + context.Response.End(); + } + + /// + /// Handles TRACE method requests + /// + /// + protected override void HandleTrace(HttpCwsContext context) + { + context.Response.StatusCode = 501; + context.Response.StatusDescription = "Not Implemented"; + context.Response.End(); + } + } +} \ No newline at end of file diff --git a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Web/RequestHandlers/GetJoinMapForBridgeKeyRequestHandler.cs b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Web/RequestHandlers/GetJoinMapForBridgeKeyRequestHandler.cs new file mode 100644 index 00000000..d037b9e6 --- /dev/null +++ b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Web/RequestHandlers/GetJoinMapForBridgeKeyRequestHandler.cs @@ -0,0 +1,157 @@ +using System.Linq; +using Crestron.SimplSharp.WebScripting; +using Newtonsoft.Json; +using PepperDash.Core.Web.RequestHandlers; +using PepperDash.Essentials.Core.Bridges; + +namespace PepperDash.Essentials.Core.Web.RequestHandlers +{ + public class GetJoinMapForBridgeKeyRequestHandler : WebApiBaseRequestHandler + { + /// + /// Handles CONNECT method requests + /// + /// + protected override void HandleConnect(HttpCwsContext context) + { + context.Response.StatusCode = 501; + context.Response.StatusDescription = "Not Implemented"; + context.Response.End(); + } + + /// + /// Handles DELETE method requests + /// + /// + protected override void HandleDelete(HttpCwsContext context) + { + context.Response.StatusCode = 501; + context.Response.StatusDescription = "Not Implemented"; + context.Response.End(); + } + + /// + /// Handles GET method requests + /// + /// + protected override void HandleGet(HttpCwsContext context) + { + var routeData = context.Request.RouteData; + if (routeData == null) + { + context.Response.StatusCode = 400; + context.Response.StatusDescription = "Bad Request"; + context.Response.End(); + + return; + } + + object bridgeObj; + if (!routeData.Values.TryGetValue("bridgeKey", out bridgeObj)) + { + context.Response.StatusCode = 400; + context.Response.StatusDescription = "Bad Request"; + context.Response.End(); + + return; + } + + var bridge = DeviceManager.GetDeviceForKey(bridgeObj.ToString()) as EiscApiAdvanced; + if (bridge == null) + { + context.Response.StatusCode = 400; + context.Response.StatusDescription = "Bad Request"; + context.Response.End(); + + return; + } + + var joinMap = bridge.JoinMaps.Select(j => EssentialsWebApiHelpers.MapJoinToObject(j)).ToList(); + if (joinMap == null) + { + context.Response.StatusCode = 404; + context.Response.StatusDescription = "Not Found"; + context.Response.End(); + + return; + } + + var js = JsonConvert.SerializeObject(joinMap, Formatting.Indented); + + context.Response.StatusCode = 200; + context.Response.StatusDescription = "OK"; + context.Response.ContentType = "application/json"; + context.Response.ContentEncoding = System.Text.Encoding.UTF8; + context.Response.Write(js, false); + context.Response.End(); + } + + /// + /// Handles HEAD method requests + /// + /// + protected override void HandleHead(HttpCwsContext context) + { + context.Response.StatusCode = 501; + context.Response.StatusDescription = "Not Implemented"; + context.Response.End(); + } + + /// + /// Handles OPTIONS method requests + /// + /// + protected override void HandleOptions(HttpCwsContext context) + { + context.Response.StatusCode = 501; + context.Response.StatusDescription = "Not Implemented"; + context.Response.End(); + } + + /// + /// Handles PATCH method requests + /// + /// + protected override void HandlePatch(HttpCwsContext context) + { + context.Response.StatusCode = 501; + context.Response.StatusDescription = "Not Implemented"; + context.Response.End(); + } + + /// + /// Handles POST method requests + /// + /// + protected override void HandlePost(HttpCwsContext context) + { + context.Response.StatusCode = 501; + context.Response.StatusDescription = "Not Implemented"; + context.Response.End(); + } + + /// + /// Handles PUT method requests + /// + /// + protected override void HandlePut(HttpCwsContext context) + { + context.Response.StatusCode = 501; + context.Response.StatusDescription = "Not Implemented"; + context.Response.End(); + } + + /// + /// Handles TRACE method requests + /// + /// + protected override void HandleTrace(HttpCwsContext context) + { + context.Response.StatusCode = 501; + context.Response.StatusDescription = "Not Implemented"; + context.Response.End(); + } + + + } +} \ No newline at end of file diff --git a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Web/RequestHandlers/GetJoinMapForDeviceKeyRequestHandler.cs b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Web/RequestHandlers/GetJoinMapForDeviceKeyRequestHandler.cs new file mode 100644 index 00000000..63ca47a0 --- /dev/null +++ b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Web/RequestHandlers/GetJoinMapForDeviceKeyRequestHandler.cs @@ -0,0 +1,172 @@ +using Crestron.SimplSharp.WebScripting; +using Newtonsoft.Json; +using PepperDash.Core.Web.RequestHandlers; +using PepperDash.Essentials.Core.Bridges; + +namespace PepperDash.Essentials.Core.Web.RequestHandlers +{ + public class GetJoinMapForDeviceKeyRequestHandler : WebApiBaseRequestHandler + { + /// + /// Handles CONNECT method requests + /// + /// + protected override void HandleConnect(HttpCwsContext context) + { + context.Response.StatusCode = 501; + context.Response.StatusDescription = "Not Implemented"; + context.Response.End(); + } + + /// + /// Handles DELETE method requests + /// + /// + protected override void HandleDelete(HttpCwsContext context) + { + context.Response.StatusCode = 501; + context.Response.StatusDescription = "Not Implemented"; + context.Response.End(); + } + + /// + /// Handles GET method requests + /// + /// + protected override void HandleGet(HttpCwsContext context) + { + var routeData = context.Request.RouteData; + if (routeData == null) + { + context.Response.StatusCode = 400; + context.Response.StatusDescription = "Bad Request"; + context.Response.End(); + + return; + } + + object bridgeObj; + if (!routeData.Values.TryGetValue("bridgeKey", out bridgeObj)) + { + context.Response.StatusCode = 400; + context.Response.StatusDescription = "Bad Request"; + context.Response.End(); + + return; + } + + object deviceObj; + if (!routeData.Values.TryGetValue("deviceKey", out deviceObj)) + { + context.Response.StatusCode = 400; + context.Response.StatusDescription = "Bad Request"; + context.Response.End(); + + return; + } + + var bridge = DeviceManager.GetDeviceForKey(bridgeObj.ToString()) as EiscApiAdvanced; + if (bridge == null) + { + context.Response.StatusCode = 404; + context.Response.StatusDescription = "Not Found"; + context.Response.End(); + + return; + } + + JoinMapBaseAdvanced deviceJoinMap; + if (!bridge.JoinMaps.TryGetValue(deviceObj.ToString(), out deviceJoinMap)) + { + context.Response.StatusCode = 500; + context.Response.StatusDescription = "Internal Server Error"; + context.Response.End(); + + return; + } + + var joinMap = EssentialsWebApiHelpers.MapJoinToObject(deviceObj.ToString(), deviceJoinMap); + var js = JsonConvert.SerializeObject(joinMap, Formatting.Indented, new JsonSerializerSettings + { + ReferenceLoopHandling = ReferenceLoopHandling.Ignore, + NullValueHandling = NullValueHandling.Ignore, + MissingMemberHandling = MissingMemberHandling.Ignore, + DefaultValueHandling = DefaultValueHandling.Ignore, + TypeNameHandling = TypeNameHandling.None + }); + + context.Response.StatusCode = 200; + context.Response.StatusDescription = "OK"; + context.Response.ContentType = "application/json"; + context.Response.ContentEncoding = System.Text.Encoding.UTF8; + context.Response.Write(js, false); + context.Response.End(); + } + + /// + /// Handles HEAD method requests + /// + /// + protected override void HandleHead(HttpCwsContext context) + { + context.Response.StatusCode = 501; + context.Response.StatusDescription = "Not Implemented"; + context.Response.End(); + } + + /// + /// Handles OPTIONS method requests + /// + /// + protected override void HandleOptions(HttpCwsContext context) + { + context.Response.StatusCode = 501; + context.Response.StatusDescription = "Not Implemented"; + context.Response.End(); + } + + /// + /// Handles PATCH method requests + /// + /// + protected override void HandlePatch(HttpCwsContext context) + { + context.Response.StatusCode = 501; + context.Response.StatusDescription = "Not Implemented"; + context.Response.End(); + } + + /// + /// Handles POST method requests + /// + /// + protected override void HandlePost(HttpCwsContext context) + { + context.Response.StatusCode = 501; + context.Response.StatusDescription = "Not Implemented"; + context.Response.End(); + } + + /// + /// Handles PUT method requests + /// + /// + protected override void HandlePut(HttpCwsContext context) + { + context.Response.StatusCode = 501; + context.Response.StatusDescription = "Not Implemented"; + context.Response.End(); + } + + /// + /// Handles TRACE method requests + /// + /// + protected override void HandleTrace(HttpCwsContext context) + { + context.Response.StatusCode = 501; + context.Response.StatusDescription = "Not Implemented"; + context.Response.End(); + } + } +} \ No newline at end of file diff --git a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Web/RequestHandlers/GetTypesByFilterRequestHandler.cs b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Web/RequestHandlers/GetTypesByFilterRequestHandler.cs new file mode 100644 index 00000000..be7347fb --- /dev/null +++ b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Web/RequestHandlers/GetTypesByFilterRequestHandler.cs @@ -0,0 +1,145 @@ +using System.Linq; +using Crestron.SimplSharp.WebScripting; +using Newtonsoft.Json; +using PepperDash.Core.Web.RequestHandlers; + +namespace PepperDash.Essentials.Core.Web.RequestHandlers +{ + public class GetTypesByFilterRequestHandler : WebApiBaseRequestHandler + { + /// + /// Handles CONNECT method requests + /// + /// + protected override void HandleConnect(HttpCwsContext context) + { + context.Response.StatusCode = 501; + context.Response.StatusDescription = "Not Implemented"; + context.Response.End(); + } + + /// + /// Handles DELETE method requests + /// + /// + protected override void HandleDelete(HttpCwsContext context) + { + context.Response.StatusCode = 501; + context.Response.StatusDescription = "Not Implemented"; + context.Response.End(); + } + + /// + /// Handles GET method requests + /// + /// + protected override void HandleGet(HttpCwsContext context) + { + var routeData = context.Request.RouteData; + if (routeData == null) + { + context.Response.StatusCode = 400; + context.Response.StatusDescription = "Bad Request"; + context.Response.End(); + + return; + } + + object filterObj; + if (!routeData.Values.TryGetValue("filter", out filterObj)) + { + context.Response.StatusCode = 400; + context.Response.StatusDescription = "Bad Request"; + context.Response.End(); + + return; + } + + var deviceFactory = DeviceFactory.GetDeviceFactoryDictionary(filterObj.ToString()); + if (deviceFactory == null) + { + context.Response.StatusCode = 404; + context.Response.StatusDescription = "Not Found"; + context.Response.End(); + + return; + } + + var deviceTypes = deviceFactory.Select(t => EssentialsWebApiHelpers.MapDeviceTypeToObject(t)).ToList(); + var js = JsonConvert.SerializeObject(deviceTypes, Formatting.Indented); + + context.Response.StatusCode = 200; + context.Response.StatusDescription = "OK"; + context.Response.ContentType = "application/json"; + context.Response.ContentEncoding = System.Text.Encoding.UTF8; + context.Response.Write(js, false); + context.Response.End(); + } + + /// + /// Handles HEAD method requests + /// + /// + protected override void HandleHead(HttpCwsContext context) + { + context.Response.StatusCode = 501; + context.Response.StatusDescription = "Not Implemented"; + context.Response.End(); + } + + /// + /// Handles OPTIONS method requests + /// + /// + protected override void HandleOptions(HttpCwsContext context) + { + context.Response.StatusCode = 501; + context.Response.StatusDescription = "Not Implemented"; + context.Response.End(); + } + + /// + /// Handles PATCH method requests + /// + /// + protected override void HandlePatch(HttpCwsContext context) + { + context.Response.StatusCode = 501; + context.Response.StatusDescription = "Not Implemented"; + context.Response.End(); + } + + /// + /// Handles POST method requests + /// + /// + protected override void HandlePost(HttpCwsContext context) + { + context.Response.StatusCode = 501; + context.Response.StatusDescription = "Not Implemented"; + context.Response.End(); + } + + /// + /// Handles PUT method requests + /// + /// + protected override void HandlePut(HttpCwsContext context) + { + context.Response.StatusCode = 501; + context.Response.StatusDescription = "Not Implemented"; + context.Response.End(); + } + + /// + /// Handles TRACE method requests + /// + /// + protected override void HandleTrace(HttpCwsContext context) + { + context.Response.StatusCode = 501; + context.Response.StatusDescription = "Not Implemented"; + context.Response.End(); + } + } +} \ No newline at end of file diff --git a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Web/RequestHandlers/GetTypesRequestHandler.cs b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Web/RequestHandlers/GetTypesRequestHandler.cs new file mode 100644 index 00000000..f2630063 --- /dev/null +++ b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Web/RequestHandlers/GetTypesRequestHandler.cs @@ -0,0 +1,135 @@ +using System.Linq; +using Crestron.SimplSharp.WebScripting; +using Newtonsoft.Json; +using PepperDash.Core.Web.RequestHandlers; + +namespace PepperDash.Essentials.Core.Web.RequestHandlers +{ + public class GetTypesRequestHandler : WebApiBaseRequestHandler + { + /// + /// Handles CONNECT method requests + /// + /// + protected override void HandleConnect(HttpCwsContext context) + { + context.Response.StatusCode = 501; + context.Response.StatusDescription = "Not Implemented"; + context.Response.End(); + } + + /// + /// Handles DELETE method requests + /// + /// + protected override void HandleDelete(HttpCwsContext context) + { + context.Response.StatusCode = 501; + context.Response.StatusDescription = "Not Implemented"; + context.Response.End(); + } + + /// + /// Handles GET method requests + /// + /// + protected override void HandleGet(HttpCwsContext context) + { + var routeData = context.Request.RouteData; + if (routeData == null) + { + context.Response.StatusCode = 400; + context.Response.StatusDescription = "Bad Request"; + context.Response.End(); + + return; + } + + var deviceFactory = DeviceFactory.GetDeviceFactoryDictionary(null); + if (deviceFactory == null) + { + context.Response.StatusCode = 404; + context.Response.StatusDescription = "Not Found"; + context.Response.End(); + + return; + } + + var deviceTypes = deviceFactory.Select(t => EssentialsWebApiHelpers.MapDeviceTypeToObject(t)).ToList(); + var js = JsonConvert.SerializeObject(deviceTypes, Formatting.Indented); + + context.Response.StatusCode = 200; + context.Response.StatusDescription = "OK"; + context.Response.ContentType = "application/json"; + context.Response.ContentEncoding = System.Text.Encoding.UTF8; + context.Response.Write(js, false); + context.Response.End(); + } + + /// + /// Handles HEAD method requests + /// + /// + protected override void HandleHead(HttpCwsContext context) + { + context.Response.StatusCode = 501; + context.Response.StatusDescription = "Not Implemented"; + context.Response.End(); + } + + /// + /// Handles OPTIONS method requests + /// + /// + protected override void HandleOptions(HttpCwsContext context) + { + context.Response.StatusCode = 501; + context.Response.StatusDescription = "Not Implemented"; + context.Response.End(); + } + + /// + /// Handles PATCH method requests + /// + /// + protected override void HandlePatch(HttpCwsContext context) + { + context.Response.StatusCode = 501; + context.Response.StatusDescription = "Not Implemented"; + context.Response.End(); + } + + /// + /// Handles POST method requests + /// + /// + protected override void HandlePost(HttpCwsContext context) + { + context.Response.StatusCode = 501; + context.Response.StatusDescription = "Not Implemented"; + context.Response.End(); + } + + /// + /// Handles PUT method requests + /// + /// + protected override void HandlePut(HttpCwsContext context) + { + context.Response.StatusCode = 501; + context.Response.StatusDescription = "Not Implemented"; + context.Response.End(); + } + + /// + /// Handles TRACE method requests + /// + /// + protected override void HandleTrace(HttpCwsContext context) + { + context.Response.StatusCode = 501; + context.Response.StatusDescription = "Not Implemented"; + context.Response.End(); + } + } +} \ No newline at end of file diff --git a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Web/RequestHandlers/ReportVersionsRequestHandler.cs b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Web/RequestHandlers/ReportVersionsRequestHandler.cs new file mode 100644 index 00000000..6ba3cb7a --- /dev/null +++ b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Web/RequestHandlers/ReportVersionsRequestHandler.cs @@ -0,0 +1,126 @@ +using System.Linq; +using Crestron.SimplSharp.WebScripting; +using Newtonsoft.Json; +using PepperDash.Core.Web.RequestHandlers; + +namespace PepperDash.Essentials.Core.Web.RequestHandlers +{ + public class ReportVersionsRequestHandler : WebApiBaseRequestHandler + { + /// + /// Handles CONNECT method requests + /// + /// + protected override void HandleConnect(HttpCwsContext context) + { + context.Response.StatusCode = 501; + context.Response.StatusDescription = "Not Implemented"; + context.Response.End(); + } + + /// + /// Handles DELETE method requests + /// + /// + protected override void HandleDelete(HttpCwsContext context) + { + context.Response.StatusCode = 501; + context.Response.StatusDescription = "Not Implemented"; + context.Response.End(); + } + + /// + /// Handles GET method requests + /// + /// + protected override void HandleGet(HttpCwsContext context) + { + var loadAssemblies = PluginLoader.LoadedAssemblies; + if (loadAssemblies == null) + { + context.Response.StatusCode = 500; + context.Response.StatusDescription = "Internal Server Error"; + context.Response.End(); + + return; + } + + var assemblies = loadAssemblies.Select(a => EssentialsWebApiHelpers.MapToAssemblyObject(a)).ToList(); + + var js = JsonConvert.SerializeObject(assemblies, Formatting.Indented); + + context.Response.StatusCode = 200; + context.Response.StatusDescription = "OK"; + context.Response.ContentType = "application/json"; + context.Response.ContentEncoding = System.Text.Encoding.UTF8; + context.Response.Write(js, false); + context.Response.End(); + } + + /// + /// Handles HEAD method requests + /// + /// + protected override void HandleHead(HttpCwsContext context) + { + context.Response.StatusCode = 501; + context.Response.StatusDescription = "Not Implemented"; + context.Response.End(); + } + + /// + /// Handles OPTIONS method requests + /// + /// + protected override void HandleOptions(HttpCwsContext context) + { + context.Response.StatusCode = 501; + context.Response.StatusDescription = "Not Implemented"; + context.Response.End(); + } + + /// + /// Handles PATCH method requests + /// + /// + protected override void HandlePatch(HttpCwsContext context) + { + context.Response.StatusCode = 501; + context.Response.StatusDescription = "Not Implemented"; + context.Response.End(); + } + + /// + /// Handles POST method requests + /// + /// + protected override void HandlePost(HttpCwsContext context) + { + context.Response.StatusCode = 501; + context.Response.StatusDescription = "Not Implemented"; + context.Response.End(); + } + + /// + /// Handles PUT method requests + /// + /// + protected override void HandlePut(HttpCwsContext context) + { + context.Response.StatusCode = 501; + context.Response.StatusDescription = "Not Implemented"; + context.Response.End(); + } + + /// + /// Handles TRACE method requests + /// + /// + protected override void HandleTrace(HttpCwsContext context) + { + context.Response.StatusCode = 501; + context.Response.StatusDescription = "Not Implemented"; + context.Response.End(); + } + } +} \ No newline at end of file diff --git a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Web/RequestHandlers/SetDeviceStreamDebugRequestHandler.cs b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Web/RequestHandlers/SetDeviceStreamDebugRequestHandler.cs new file mode 100644 index 00000000..bb7cc12f --- /dev/null +++ b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Web/RequestHandlers/SetDeviceStreamDebugRequestHandler.cs @@ -0,0 +1,212 @@ +using System; +using Crestron.SimplSharp.WebScripting; +using Newtonsoft.Json; +using PepperDash.Core; +using PepperDash.Core.Web.RequestHandlers; + +namespace PepperDash.Essentials.Core.Web.RequestHandlers +{ + public class SetDeviceStreamDebugRequestHandler : WebApiBaseRequestHandler + { + /// + /// Handles CONNECT method requests + /// + /// + protected override void HandleConnect(HttpCwsContext context) + { + context.Response.StatusCode = 501; + context.Response.StatusDescription = "Not Implemented"; + context.Response.End(); + } + + /// + /// Handles DELETE method requests + /// + /// + protected override void HandleDelete(HttpCwsContext context) + { + context.Response.StatusCode = 501; + context.Response.StatusDescription = "Not Implemented"; + context.Response.End(); + } + + /// + /// Handles GET method requests + /// + /// + protected override void HandleGet(HttpCwsContext context) + { + context.Response.StatusCode = 501; + context.Response.StatusDescription = "Not Implemented"; + context.Response.End(); + } + + /// + /// Handles HEAD method requests + /// + /// + protected override void HandleHead(HttpCwsContext context) + { + context.Response.StatusCode = 501; + context.Response.StatusDescription = "Not Implemented"; + context.Response.End(); + } + + /// + /// Handles OPTIONS method requests + /// + /// + protected override void HandleOptions(HttpCwsContext context) + { + context.Response.StatusCode = 501; + context.Response.StatusDescription = "Not Implemented"; + context.Response.End(); + } + + /// + /// Handles PATCH method requests + /// + /// + protected override void HandlePatch(HttpCwsContext context) + { + context.Response.StatusCode = 501; + context.Response.StatusDescription = "Not Implemented"; + context.Response.End(); + } + + /// + /// Handles POST method requests + /// + /// + protected override void HandlePost(HttpCwsContext context) + { + if (context.Request.ContentLength < 0) + { + context.Response.StatusCode = 400; + context.Response.StatusDescription = "Bad Request"; + context.Response.End(); + + return; + } + + var data = EssentialsWebApiHelpers.GetRequestBody(context.Request); + if (data == null) + { + context.Response.StatusCode = 500; + context.Response.StatusDescription = "Internal Server Error"; + context.Response.End(); + + return; + } + + var config = new SetDeviceStreamDebugConfig(); + var body = JsonConvert.DeserializeAnonymousType(data, config); + if (body == null) + { + context.Response.StatusCode = 500; + context.Response.StatusDescription = "Internal Server Error"; + context.Response.End(); + + return; + } + + if (string.IsNullOrEmpty(body.DeviceKey) || string.IsNullOrEmpty(body.Setting)) + { + context.Response.StatusCode = 400; + context.Response.StatusDescription = "Bad Request"; + context.Response.End(); + + return; + } + + var device = DeviceManager.GetDeviceForKey(body.DeviceKey) as IStreamDebugging; + if (device == null) + { + context.Response.StatusCode = 404; + context.Response.StatusDescription = "Not Found"; + context.Response.End(); + + return; + } + + eStreamDebuggingSetting debugSetting; + try + { + debugSetting = (eStreamDebuggingSetting) Enum.Parse(typeof (eStreamDebuggingSetting), body.Setting, true); + } + catch (Exception ex) + { + context.Response.StatusCode = 500; + context.Response.StatusDescription = "Internal Server Error"; + context.Response.End(); + + return; + } + + try + { + var mins = Convert.ToUInt32(body.Timeout); + if (mins > 0) + { + device.StreamDebugging.SetDebuggingWithSpecificTimeout(debugSetting, mins); + } + else + { + device.StreamDebugging.SetDebuggingWithDefaultTimeout(debugSetting); + } + + context.Response.StatusCode = 200; + context.Response.StatusDescription = "OK"; + context.Response.End(); + } + catch (Exception ex) + { + context.Response.StatusCode = 500; + context.Response.StatusDescription = "Internal Server Error"; + context.Response.End(); + } + } + + /// + /// Handles PUT method requests + /// + /// + protected override void HandlePut(HttpCwsContext context) + { + context.Response.StatusCode = 501; + context.Response.StatusDescription = "Not Implemented"; + context.Response.End(); + } + + /// + /// Handles TRACE method requests + /// + /// + protected override void HandleTrace(HttpCwsContext context) + { + context.Response.StatusCode = 501; + context.Response.StatusDescription = "Not Implemented"; + context.Response.End(); + } + } + + + public class SetDeviceStreamDebugConfig + { + [JsonProperty("deviceKey", NullValueHandling = NullValueHandling.Include)] + public string DeviceKey { get; set; } + + [JsonProperty("setting", NullValueHandling = NullValueHandling.Include)] + public string Setting { get; set; } + + [JsonProperty("timeout")] + public int Timeout { get; set; } + + public SetDeviceStreamDebugConfig() + { + DeviceKey = null; + Setting = null; + Timeout = 15; + } + } +} \ No newline at end of file diff --git a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Web/RequestHandlers/ShowConfigRequestHandler.cs b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Web/RequestHandlers/ShowConfigRequestHandler.cs new file mode 100644 index 00000000..4dded8b5 --- /dev/null +++ b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Web/RequestHandlers/ShowConfigRequestHandler.cs @@ -0,0 +1,114 @@ +using Crestron.SimplSharp.WebScripting; +using Newtonsoft.Json; +using PepperDash.Core.Web.RequestHandlers; +using PepperDash.Essentials.Core.Config; + +namespace PepperDash.Essentials.Core.Web.RequestHandlers +{ + public class ShowConfigRequestHandler : WebApiBaseRequestHandler + { + /// + /// Handles CONNECT method requests + /// + /// + protected override void HandleConnect(HttpCwsContext context) + { + context.Response.StatusCode = 501; + context.Response.StatusDescription = "Not Implemented"; + context.Response.End(); + } + + /// + /// Handles DELETE method requests + /// + /// + protected override void HandleDelete(HttpCwsContext context) + { + context.Response.StatusCode = 501; + context.Response.StatusDescription = "Not Implemented"; + context.Response.End(); + } + + /// + /// Handles GET method requests + /// + /// + protected override void HandleGet(HttpCwsContext context) + { + var config = JsonConvert.SerializeObject(ConfigReader.ConfigObject, Formatting.Indented); + + context.Response.StatusCode = 200; + context.Response.StatusDescription = "OK"; + context.Response.ContentType = "application/json"; + context.Response.ContentEncoding = System.Text.Encoding.UTF8; + context.Response.Write(config, false); + context.Response.End(); + } + + /// + /// Handles HEAD method requests + /// + /// + protected override void HandleHead(HttpCwsContext context) + { + context.Response.StatusCode = 501; + context.Response.StatusDescription = "Not Implemented"; + context.Response.End(); + } + + /// + /// Handles OPTIONS method requests + /// + /// + protected override void HandleOptions(HttpCwsContext context) + { + context.Response.StatusCode = 501; + context.Response.StatusDescription = "Not Implemented"; + context.Response.End(); + } + + /// + /// Handles PATCH method requests + /// + /// + protected override void HandlePatch(HttpCwsContext context) + { + context.Response.StatusCode = 501; + context.Response.StatusDescription = "Not Implemented"; + context.Response.End(); + } + + /// + /// Handles POST method requests + /// + /// + protected override void HandlePost(HttpCwsContext context) + { + context.Response.StatusCode = 501; + context.Response.StatusDescription = "Not Implemented"; + context.Response.End(); + } + + /// + /// Handles PUT method requests + /// + /// + protected override void HandlePut(HttpCwsContext context) + { + context.Response.StatusCode = 501; + context.Response.StatusDescription = "Not Implemented"; + context.Response.End(); + } + + /// + /// Handles TRACE method requests + /// + /// + protected override void HandleTrace(HttpCwsContext context) + { + context.Response.StatusCode = 501; + context.Response.StatusDescription = "Not Implemented"; + context.Response.End(); + } + } +} \ No newline at end of file diff --git a/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/VideoCodecBase.cs b/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/VideoCodecBase.cs index 19c61b9f..c0048a68 100644 --- a/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/VideoCodecBase.cs +++ b/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/VideoCodecBase.cs @@ -1004,7 +1004,9 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec if (codec.DirectoryRoot != null) { - trilist.SetUshort(joinMap.DirectoryRowCount.JoinNumber, (ushort)codec.DirectoryRoot.CurrentDirectoryResults.Count); + var contactsCount = codec.DirectoryRoot.CurrentDirectoryResults.Where(c => c.ParentFolderId.Equals("root")).ToList().Count; + trilist.SetUshort(joinMap.DirectoryRowCount.JoinNumber, (ushort)contactsCount); + Debug.Console(2, this, ">>> contactsCount: {0}", contactsCount); var clearBytes = XSigHelpers.ClearOutputs(); @@ -1020,7 +1022,13 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec codec.DirectoryResultReturned += (sender, args) => { - trilist.SetUshort(joinMap.DirectoryRowCount.JoinNumber, (ushort)args.Directory.CurrentDirectoryResults.Count); + var isRoot = codec.CurrentDirectoryResultIsNotDirectoryRoot.BoolValue == false; + var argsCount = isRoot + ? args.Directory.CurrentDirectoryResults.Where(a => a.ParentFolderId.Equals("root")).ToList().Count + : args.Directory.CurrentDirectoryResults.Count; + + trilist.SetUshort(joinMap.DirectoryRowCount.JoinNumber, (ushort)argsCount); + Debug.Console(2, this, ">>> argsCount: {0}", argsCount); var clearBytes = XSigHelpers.ClearOutputs(); @@ -1184,46 +1192,47 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec return GetXSigString(tokenArray); } - private string UpdateDirectoryXSig(CodecDirectory directory, bool isRoot) - { - var xSigMaxIndex = 1023; - var tokenArray = new XSigToken[directory.CurrentDirectoryResults.Count > xSigMaxIndex - ? xSigMaxIndex - : directory.CurrentDirectoryResults.Count]; + private string UpdateDirectoryXSig(CodecDirectory directory, bool isRoot) + { + var xSigMaxIndex = 1023; + var tokenArray = new XSigToken[directory.CurrentDirectoryResults.Count > xSigMaxIndex + ? xSigMaxIndex + : directory.CurrentDirectoryResults.Count]; - Debug.Console(2, this, "IsRoot: {0}, Directory Count: {1}, TokenArray.Length: {2}", isRoot, - directory.CurrentDirectoryResults.Count, tokenArray.Length); + Debug.Console(2, this, "IsRoot: {0}, Directory Count: {1}, TokenArray.Length: {2}", isRoot, directory.CurrentDirectoryResults.Count, tokenArray.Length); - var contacts = directory.CurrentDirectoryResults.Count > xSigMaxIndex - ? directory.CurrentDirectoryResults.Take(xSigMaxIndex) - : directory.CurrentDirectoryResults; + var contacts = directory.CurrentDirectoryResults.Count > xSigMaxIndex + ? directory.CurrentDirectoryResults.Take(xSigMaxIndex) + : directory.CurrentDirectoryResults; - var counterIndex = 1; - foreach (var entry in contacts) - { - var arrayIndex = counterIndex - 1; - var entryIndex = counterIndex; + var contactsToDisplay = isRoot + ? contacts.Where(c => c.ParentFolderId == "root") + : contacts.Where(c => c.ParentFolderId != "root"); - Debug.Console(2, this, "Entry{2:0000} Name: {0}, Folder ID: {1}", entry.Name, entry.FolderId, entryIndex); + var counterIndex = 1; + foreach (var entry in contactsToDisplay) + { + var arrayIndex = counterIndex - 1; + var entryIndex = counterIndex; - if (entry is DirectoryFolder && entry.ParentFolderId == "root") - { - tokenArray[arrayIndex] = new XSigSerialToken(entryIndex, String.Format("[+] {0}", entry.Name)); + Debug.Console(2, this, "Entry{2:0000} Name: {0}, Folder ID: {1}, Type: {3}, ParentFolderId: {4}", + entry.Name, entry.FolderId, entryIndex, entry.GetType().GetCType().FullName, entry.ParentFolderId); - counterIndex++; - counterIndex++; + if (entry is DirectoryFolder) + { + tokenArray[arrayIndex] = new XSigSerialToken(entryIndex, String.Format("[+] {0}", entry.Name)); - continue; - } + counterIndex++; - tokenArray[arrayIndex] = new XSigSerialToken(entryIndex, entry.Name); + continue; + } - counterIndex++; - } - - return GetXSigString(tokenArray); + tokenArray[arrayIndex] = new XSigSerialToken(entryIndex, entry.Name); + counterIndex++; + } + return GetXSigString(tokenArray); } private void LinkVideoCodecCallControlsToApi(BasicTriList trilist, VideoCodecControllerJoinMap joinMap) diff --git a/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/ZoomRoom/ResponseObjects.cs b/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/ZoomRoom/ResponseObjects.cs index 0075b657..79a5395d 100644 --- a/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/ZoomRoom/ResponseObjects.cs +++ b/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/ZoomRoom/ResponseObjects.cs @@ -303,11 +303,19 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.ZoomRoom { var contact = new InvitableDirectoryContact { Name = c.ScreenName, ContactId = c.Jid }; - contact.ContactMethods.Add(new ContactMethod() { Number = c.Jid, Device = eContactMethodDevice.Video, CallType = eContactMethodCallType.Video, ContactMethodId = c.Jid }); + contact.ContactMethods.Add(new ContactMethod() + { + Number = c.Jid, + Device = eContactMethodDevice.Video, + CallType = eContactMethodCallType.Video, + ContactMethodId = c.Jid + }); if (folders.Count > 0) { - contact.ParentFolderId = c.IsZoomRoom ? "rooms" : "contacts"; + contact.ParentFolderId = c.IsZoomRoom + ? roomFolder.FolderId // "rooms" + : contactFolder.FolderId; // "contacts" } contacts.Add(contact); diff --git a/packages.config b/packages.config index ffea92a5..ea9f8e18 100644 --- a/packages.config +++ b/packages.config @@ -1,3 +1,3 @@ - + \ No newline at end of file