mirror of
https://github.com/PepperDash/Essentials.git
synced 2026-02-09 01:35:02 +00:00
feat: modify factory loading
Updating IDeviceFactory to resolve [FEATURE]-Refactor Plugin loading mechanism #1065. This change should be backwards-compatible with existing plugins that use the EssentialsPluginDeviceFactory<T> class, as the interfaces are implemented by the various base classes. In addition, the correct assembly name is now printed when a type is loaded.
This commit is contained in:
@@ -8,500 +8,507 @@ using System.Linq;
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
|
||||
namespace PepperDash.Essentials.Core
|
||||
namespace PepperDash.Essentials.Core;
|
||||
|
||||
public static class DeviceManager
|
||||
{
|
||||
public static class DeviceManager
|
||||
public static event EventHandler<EventArgs> AllDevicesActivated;
|
||||
public static event EventHandler<EventArgs> AllDevicesRegistered;
|
||||
public static event EventHandler<EventArgs> AllDevicesInitialized;
|
||||
|
||||
private static readonly CCriticalSection DeviceCriticalSection = new CCriticalSection();
|
||||
|
||||
//public static List<Device> Devices { get { return _Devices; } }
|
||||
//static List<Device> _Devices = new List<Device>();
|
||||
|
||||
private static readonly Dictionary<string, IKeyed> Devices = new Dictionary<string, IKeyed>(StringComparer.OrdinalIgnoreCase);
|
||||
|
||||
/// <summary>
|
||||
/// Returns a copy of all the devices in a list
|
||||
/// </summary>
|
||||
public static List<IKeyed> AllDevices => [.. Devices.Values];
|
||||
|
||||
public static bool AddDeviceEnabled;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes the control system by enabling device management and registering console commands.
|
||||
/// </summary>
|
||||
/// <remarks>This method sets up the control system for device management by enabling the addition of
|
||||
/// devices and registering a series of console commands for interacting with devices. These commands allow
|
||||
/// operators to list device statuses, feedbacks, and managed devices, as well as perform actions such as
|
||||
/// simulating communication, debugging device streams, and accessing device properties and methods.</remarks>
|
||||
/// <param name="cs">The <see cref="CrestronControlSystem"/> instance representing the control system to initialize.</param>
|
||||
public static void Initialize(CrestronControlSystem cs)
|
||||
{
|
||||
public static event EventHandler<EventArgs> AllDevicesActivated;
|
||||
public static event EventHandler<EventArgs> AllDevicesRegistered;
|
||||
public static event EventHandler<EventArgs> AllDevicesInitialized;
|
||||
AddDeviceEnabled = true;
|
||||
|
||||
private static readonly CCriticalSection DeviceCriticalSection = new CCriticalSection();
|
||||
private static readonly CEvent AllowAddDevicesCEvent = new CEvent(false, true);
|
||||
CrestronConsole.AddNewConsoleCommand(ListDeviceCommStatuses, "devcommstatus", "Lists the communication status of all devices",
|
||||
ConsoleAccessLevelEnum.AccessOperator);
|
||||
CrestronConsole.AddNewConsoleCommand(ListDeviceFeedbacks, "devfb", "Lists current feedbacks",
|
||||
ConsoleAccessLevelEnum.AccessOperator);
|
||||
CrestronConsole.AddNewConsoleCommand(ListDevices, "devlist", "Lists current managed devices",
|
||||
ConsoleAccessLevelEnum.AccessOperator);
|
||||
CrestronConsole.AddNewConsoleCommand(DeviceJsonApi.DoDeviceActionWithJson, "devjson", "",
|
||||
ConsoleAccessLevelEnum.AccessOperator);
|
||||
CrestronConsole.AddNewConsoleCommand(s => CrestronConsole.ConsoleCommandResponse(DeviceJsonApi.GetProperties(s)), "devprops", "", ConsoleAccessLevelEnum.AccessOperator);
|
||||
CrestronConsole.AddNewConsoleCommand(s => CrestronConsole.ConsoleCommandResponse(DeviceJsonApi.GetMethods(s)), "devmethods", "", ConsoleAccessLevelEnum.AccessOperator);
|
||||
CrestronConsole.AddNewConsoleCommand(s => CrestronConsole.ConsoleCommandResponse(DeviceJsonApi.GetApiMethods(s)), "apimethods", "", ConsoleAccessLevelEnum.AccessOperator);
|
||||
CrestronConsole.AddNewConsoleCommand(SimulateComReceiveOnDevice, "devsimreceive",
|
||||
"Simulates incoming data on a com device", ConsoleAccessLevelEnum.AccessOperator);
|
||||
|
||||
//public static List<Device> Devices { get { return _Devices; } }
|
||||
//static List<Device> _Devices = new List<Device>();
|
||||
CrestronConsole.AddNewConsoleCommand(SetDeviceStreamDebugging, "setdevicestreamdebug", "set comm debug [deviceKey] [off/rx/tx/both] ([minutes])", ConsoleAccessLevelEnum.AccessOperator);
|
||||
CrestronConsole.AddNewConsoleCommand(s => DisableAllDeviceStreamDebugging(), "disableallstreamdebug", "disables stream debugging on all devices", ConsoleAccessLevelEnum.AccessOperator);
|
||||
}
|
||||
|
||||
private static readonly Dictionary<string, IKeyed> Devices = new Dictionary<string, IKeyed>(StringComparer.OrdinalIgnoreCase);
|
||||
|
||||
/// <summary>
|
||||
/// Returns a copy of all the devices in a list
|
||||
/// </summary>
|
||||
public static List<IKeyed> AllDevices { get { return new List<IKeyed>(Devices.Values); } }
|
||||
|
||||
public static bool AddDeviceEnabled;
|
||||
|
||||
public static void Initialize(CrestronControlSystem cs)
|
||||
/// <summary>
|
||||
/// Calls activate steps on all Device class items
|
||||
/// </summary>
|
||||
public static void ActivateAll()
|
||||
{
|
||||
try
|
||||
{
|
||||
AddDeviceEnabled = true;
|
||||
CrestronConsole.AddNewConsoleCommand(ListDeviceCommStatuses, "devcommstatus", "Lists the communication status of all devices",
|
||||
ConsoleAccessLevelEnum.AccessOperator);
|
||||
CrestronConsole.AddNewConsoleCommand(ListDeviceFeedbacks, "devfb", "Lists current feedbacks",
|
||||
ConsoleAccessLevelEnum.AccessOperator);
|
||||
CrestronConsole.AddNewConsoleCommand(ListDevices, "devlist", "Lists current managed devices",
|
||||
ConsoleAccessLevelEnum.AccessOperator);
|
||||
CrestronConsole.AddNewConsoleCommand(DeviceJsonApi.DoDeviceActionWithJson, "devjson", "",
|
||||
ConsoleAccessLevelEnum.AccessOperator);
|
||||
CrestronConsole.AddNewConsoleCommand(s => CrestronConsole.ConsoleCommandResponse(DeviceJsonApi.GetProperties(s)), "devprops", "", ConsoleAccessLevelEnum.AccessOperator);
|
||||
CrestronConsole.AddNewConsoleCommand(s => CrestronConsole.ConsoleCommandResponse(DeviceJsonApi.GetMethods(s)), "devmethods", "", ConsoleAccessLevelEnum.AccessOperator);
|
||||
CrestronConsole.AddNewConsoleCommand(s => CrestronConsole.ConsoleCommandResponse(DeviceJsonApi.GetApiMethods(s)), "apimethods", "", ConsoleAccessLevelEnum.AccessOperator);
|
||||
CrestronConsole.AddNewConsoleCommand(SimulateComReceiveOnDevice, "devsimreceive",
|
||||
"Simulates incoming data on a com device", ConsoleAccessLevelEnum.AccessOperator);
|
||||
OnAllDevicesRegistered();
|
||||
|
||||
CrestronConsole.AddNewConsoleCommand(SetDeviceStreamDebugging, "setdevicestreamdebug", "set comm debug [deviceKey] [off/rx/tx/both] ([minutes])", ConsoleAccessLevelEnum.AccessOperator);
|
||||
CrestronConsole.AddNewConsoleCommand(s => DisableAllDeviceStreamDebugging(), "disableallstreamdebug", "disables stream debugging on all devices", ConsoleAccessLevelEnum.AccessOperator);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Calls activate steps on all Device class items
|
||||
/// </summary>
|
||||
public static void ActivateAll()
|
||||
{
|
||||
try
|
||||
{
|
||||
OnAllDevicesRegistered();
|
||||
|
||||
DeviceCriticalSection.Enter();
|
||||
AddDeviceEnabled = false;
|
||||
// PreActivate all devices
|
||||
Debug.LogMessage(LogEventLevel.Information, "****PreActivation starting...****");
|
||||
foreach (var d in Devices.Values)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (d is Device)
|
||||
(d as Device).PreActivate();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Debug.LogMessage(LogEventLevel.Information, d, "ERROR: Device {1} PreActivation failure: {0}", e.Message, d.Key);
|
||||
Debug.LogMessage(LogEventLevel.Debug, d, "Stack Trace: {0}", e.StackTrace);
|
||||
}
|
||||
}
|
||||
Debug.LogMessage(LogEventLevel.Information, "****PreActivation complete****");
|
||||
Debug.LogMessage(LogEventLevel.Information, "****Activation starting...****");
|
||||
|
||||
// Activate all devices
|
||||
foreach (var d in Devices.Values)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (d is Device)
|
||||
(d as Device).Activate();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Debug.LogMessage(LogEventLevel.Information, d, "ERROR: Device {1} Activation failure: {0}", e.Message, d.Key);
|
||||
Debug.LogMessage(LogEventLevel.Debug, d, "Stack Trace: {0}", e.StackTrace);
|
||||
}
|
||||
}
|
||||
|
||||
Debug.LogMessage(LogEventLevel.Information, "****Activation complete****");
|
||||
Debug.LogMessage(LogEventLevel.Information, "****PostActivation starting...****");
|
||||
|
||||
// PostActivate all devices
|
||||
foreach (var d in Devices.Values)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (d is Device)
|
||||
(d as Device).PostActivate();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Debug.LogMessage(LogEventLevel.Information, d, "ERROR: Device {1} PostActivation failure: {0}", e.Message, d.Key);
|
||||
Debug.LogMessage(LogEventLevel.Debug, d, "Stack Trace: {0}", e.StackTrace);
|
||||
}
|
||||
}
|
||||
|
||||
Debug.LogMessage(LogEventLevel.Information, "****PostActivation complete****");
|
||||
|
||||
OnAllDevicesActivated();
|
||||
}
|
||||
finally
|
||||
{
|
||||
DeviceCriticalSection.Leave();
|
||||
}
|
||||
}
|
||||
|
||||
private static void DeviceManager_Initialized(object sender, EventArgs e)
|
||||
{
|
||||
var allInitialized = Devices.Values.OfType<EssentialsDevice>().All(d => d.IsInitialized);
|
||||
|
||||
if (allInitialized)
|
||||
{
|
||||
Debug.LogMessage(LogEventLevel.Information, "****All Devices Initalized****");
|
||||
|
||||
OnAllDevicesInitialized();
|
||||
}
|
||||
}
|
||||
|
||||
private static void OnAllDevicesActivated()
|
||||
{
|
||||
var handler = AllDevicesActivated;
|
||||
if (handler != null)
|
||||
{
|
||||
handler(null, new EventArgs());
|
||||
}
|
||||
}
|
||||
|
||||
private static void OnAllDevicesRegistered()
|
||||
{
|
||||
var handler = AllDevicesRegistered;
|
||||
if (handler != null)
|
||||
{
|
||||
handler(null, new EventArgs());
|
||||
}
|
||||
}
|
||||
|
||||
private static void OnAllDevicesInitialized()
|
||||
{
|
||||
var handler = AllDevicesInitialized;
|
||||
if (handler != null)
|
||||
{
|
||||
handler(null, new EventArgs());
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Calls activate on all Device class items
|
||||
/// </summary>
|
||||
public static void DeactivateAll()
|
||||
{
|
||||
try
|
||||
{
|
||||
DeviceCriticalSection.Enter();
|
||||
foreach (var d in Devices.Values.OfType<Device>())
|
||||
{
|
||||
d.Deactivate();
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
DeviceCriticalSection.Leave();
|
||||
}
|
||||
}
|
||||
|
||||
//static void ListMethods(string devKey)
|
||||
//{
|
||||
// var dev = GetDeviceForKey(devKey);
|
||||
// if(dev != null)
|
||||
// {
|
||||
// var type = dev.GetType().GetType();
|
||||
// var methods = type.GetMethods(BindingFlags.Public|BindingFlags.Instance);
|
||||
// var sb = new StringBuilder();
|
||||
// sb.AppendLine(string.Format("{2} methods on [{0}] ({1}):", dev.Key, type.Name, methods.Length));
|
||||
// foreach (var m in methods)
|
||||
// {
|
||||
// sb.Append(string.Format("{0}(", m.Name));
|
||||
// var pars = m.GetParameters();
|
||||
// foreach (var p in pars)
|
||||
// sb.Append(string.Format("({1}){0} ", p.Name, p.ParameterType.Name));
|
||||
// sb.AppendLine(")");
|
||||
// }
|
||||
// CrestronConsole.ConsoleCommandResponse(sb.ToString());
|
||||
// }
|
||||
//}
|
||||
|
||||
private static void ListDevices(string s)
|
||||
{
|
||||
Debug.LogMessage(LogEventLevel.Information, "{0} Devices registered with Device Manager:", Devices.Count);
|
||||
var sorted = Devices.Values.ToList();
|
||||
sorted.Sort((a, b) => a.Key.CompareTo(b.Key));
|
||||
|
||||
foreach (var d in sorted)
|
||||
{
|
||||
var name = d is IKeyName ? (d as IKeyName).Name : "---";
|
||||
Debug.LogMessage(LogEventLevel.Information, " [{0}] {1}", d.Key, name);
|
||||
}
|
||||
}
|
||||
|
||||
private static void ListDeviceFeedbacks(string devKey)
|
||||
{
|
||||
var dev = GetDeviceForKey(devKey);
|
||||
if (dev == null)
|
||||
{
|
||||
Debug.LogMessage(LogEventLevel.Information, "Device '{0}' not found", devKey);
|
||||
return;
|
||||
}
|
||||
if (!(dev is IHasFeedback statusDev))
|
||||
{
|
||||
Debug.LogMessage(LogEventLevel.Information, "Device '{0}' does not have visible feedbacks", devKey);
|
||||
return;
|
||||
}
|
||||
statusDev.DumpFeedbacksToConsole(true);
|
||||
}
|
||||
|
||||
//static void ListDeviceCommands(string devKey)
|
||||
//{
|
||||
// var dev = GetDeviceForKey(devKey);
|
||||
// if (dev == null)
|
||||
// {
|
||||
// Debug.LogMessage(LogEventLevel.Information, "Device '{0}' not found", devKey);
|
||||
// return;
|
||||
// }
|
||||
// Debug.LogMessage(LogEventLevel.Information, "This needs to be reworked. Stay tuned.", devKey);
|
||||
//}
|
||||
|
||||
private static void ListDeviceCommStatuses(string input)
|
||||
{
|
||||
|
||||
foreach (var dev in Devices.Values.OfType<ICommunicationMonitor>())
|
||||
{
|
||||
CrestronConsole.ConsoleCommandResponse($"{dev}: {dev.CommunicationMonitor.Status}\r\n");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//static void DoDeviceCommand(string command)
|
||||
//{
|
||||
// Debug.LogMessage(LogEventLevel.Information, "Not yet implemented. Stay tuned");
|
||||
//}
|
||||
|
||||
public static void AddDevice(IKeyed newDev)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (!DeviceCriticalSection.TryEnter())
|
||||
{
|
||||
Debug.LogMessage(LogEventLevel.Information, "Currently unable to add devices to Device Manager. Please try again");
|
||||
return;
|
||||
}
|
||||
// Check for device with same key
|
||||
//var existingDevice = _Devices.FirstOrDefault(d => d.Key.Equals(newDev.Key, StringComparison.OrdinalIgnoreCase));
|
||||
////// If it exists, remove or warn??
|
||||
//if (existingDevice != null)
|
||||
|
||||
if (!AddDeviceEnabled)
|
||||
{
|
||||
Debug.LogMessage(LogEventLevel.Information, "All devices have been activated. Adding new devices is not allowed.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (Devices.ContainsKey(newDev.Key))
|
||||
{
|
||||
Debug.LogMessage(LogEventLevel.Information, newDev, "WARNING: A device with this key already exists. Not added to manager");
|
||||
return;
|
||||
}
|
||||
Devices.Add(newDev.Key, newDev);
|
||||
//if (!(_Devices.Contains(newDev)))
|
||||
// _Devices.Add(newDev);
|
||||
|
||||
if (newDev is EssentialsDevice essentialsDev)
|
||||
essentialsDev.Initialized += DeviceManager_Initialized;
|
||||
}
|
||||
finally
|
||||
{
|
||||
DeviceCriticalSection.Leave();
|
||||
}
|
||||
}
|
||||
|
||||
public static void AddDevice(IEnumerable<IKeyed> devicesToAdd)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (!DeviceCriticalSection.TryEnter())
|
||||
{
|
||||
Debug.LogMessage(LogEventLevel.Information,
|
||||
"Currently unable to add devices to Device Manager. Please try again");
|
||||
return;
|
||||
}
|
||||
if (!AddDeviceEnabled)
|
||||
{
|
||||
Debug.LogMessage(LogEventLevel.Information,
|
||||
"All devices have been activated. Adding new devices is not allowed.");
|
||||
return;
|
||||
}
|
||||
|
||||
foreach (var dev in devicesToAdd)
|
||||
{
|
||||
try
|
||||
{
|
||||
Devices.Add(dev.Key, dev);
|
||||
}
|
||||
catch (ArgumentException ex)
|
||||
{
|
||||
Debug.LogMessage(LogEventLevel.Information, "Error adding device with key {0} to Device Manager: {1}\r\nStack Trace: {2}",
|
||||
dev.Key, ex.Message, ex.StackTrace);
|
||||
}
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
DeviceCriticalSection.Leave();
|
||||
}
|
||||
}
|
||||
|
||||
public static void RemoveDevice(IKeyed newDev)
|
||||
{
|
||||
try
|
||||
{
|
||||
DeviceCriticalSection.Enter();
|
||||
if (newDev == null)
|
||||
return;
|
||||
if (Devices.ContainsKey(newDev.Key))
|
||||
Devices.Remove(newDev.Key);
|
||||
//if (_Devices.Contains(newDev))
|
||||
// _Devices.Remove(newDev);
|
||||
else
|
||||
Debug.LogMessage(LogEventLevel.Information, "Device manager: Device '{0}' does not exist in manager. Cannot remove", newDev.Key);
|
||||
}
|
||||
finally
|
||||
{
|
||||
DeviceCriticalSection.Leave();
|
||||
}
|
||||
}
|
||||
|
||||
public static IEnumerable<string> GetDeviceKeys()
|
||||
{
|
||||
//return _Devices.Select(d => d.Key).ToList();
|
||||
return Devices.Keys;
|
||||
}
|
||||
|
||||
public static IEnumerable<IKeyed> GetDevices()
|
||||
{
|
||||
//return _Devices.Select(d => d.Key).ToList();
|
||||
return Devices.Values;
|
||||
}
|
||||
|
||||
public static IKeyed GetDeviceForKey(string key)
|
||||
{
|
||||
//return _Devices.FirstOrDefault(d => d.Key.Equals(key, StringComparison.OrdinalIgnoreCase));
|
||||
if (key != null && Devices.ContainsKey(key))
|
||||
return Devices[key];
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Console handler that simulates com port data receive
|
||||
/// </summary>
|
||||
/// <param name="s"></param>
|
||||
public static void SimulateComReceiveOnDevice(string s)
|
||||
{
|
||||
// devcomsim:1 xyzabc
|
||||
var match = Regex.Match(s, @"(\S*)\s*(.*)");
|
||||
if (match.Groups.Count < 3)
|
||||
{
|
||||
CrestronConsole.ConsoleCommandResponse(" Format: devsimreceive:P <device key> <string to send>");
|
||||
return;
|
||||
}
|
||||
//Debug.LogMessage(LogEventLevel.Verbose, "**** {0} - {1} ****", match.Groups[1].Value, match.Groups[2].Value);
|
||||
|
||||
if (!(GetDeviceForKey(match.Groups[1].Value) is ComPortController com))
|
||||
{
|
||||
CrestronConsole.ConsoleCommandResponse("'{0}' is not a comm port device", match.Groups[1].Value);
|
||||
return;
|
||||
}
|
||||
com.SimulateReceive(match.Groups[2].Value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Prints a list of routing inputs and outputs by device key.
|
||||
/// </summary>
|
||||
/// <param name="s">Device key from which to report data</param>
|
||||
public static void GetRoutingPorts(string s)
|
||||
{
|
||||
var device = GetDeviceForKey(s);
|
||||
|
||||
if (device == null) return;
|
||||
var inputPorts = ((device as IRoutingInputs) != null) ? (device as IRoutingInputs).InputPorts : null;
|
||||
var outputPorts = ((device as IRoutingOutputs) != null) ? (device as IRoutingOutputs).OutputPorts : null;
|
||||
if (inputPorts != null)
|
||||
{
|
||||
CrestronConsole.ConsoleCommandResponse("Device {0} has {1} Input Ports:{2}", s, inputPorts.Count, CrestronEnvironment.NewLine);
|
||||
foreach (var routingInputPort in inputPorts)
|
||||
{
|
||||
CrestronConsole.ConsoleCommandResponse("{0}{1}", routingInputPort.Key, CrestronEnvironment.NewLine);
|
||||
}
|
||||
}
|
||||
if (outputPorts == null) return;
|
||||
CrestronConsole.ConsoleCommandResponse("Device {0} has {1} Output Ports:{2}", s, outputPorts.Count, CrestronEnvironment.NewLine);
|
||||
foreach (var routingOutputPort in outputPorts)
|
||||
{
|
||||
CrestronConsole.ConsoleCommandResponse("{0}{1}", routingOutputPort.Key, CrestronEnvironment.NewLine);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Attempts to set the debug level of a device
|
||||
/// </summary>
|
||||
/// <param name="s"></param>
|
||||
public static void SetDeviceStreamDebugging(string s)
|
||||
{
|
||||
if (String.IsNullOrEmpty(s) || s.Contains("?"))
|
||||
{
|
||||
CrestronConsole.ConsoleCommandResponse(
|
||||
@"SETDEVICESTREAMDEBUG [{deviceKey}] [OFF |TX | RX | BOTH] [timeOutInMinutes]
|
||||
{deviceKey} [OFF | TX | RX | BOTH] - Device to set stream debugging on, and which setting to use
|
||||
timeOutInMinutes - Set timeout for stream debugging. Default is 30 minutes");
|
||||
return;
|
||||
}
|
||||
|
||||
var args = s.Split(' ');
|
||||
|
||||
var deviceKey = args[0];
|
||||
var setting = args[1];
|
||||
|
||||
var timeout = String.Empty;
|
||||
|
||||
if (args.Length >= 3)
|
||||
{
|
||||
timeout = args[2];
|
||||
}
|
||||
|
||||
|
||||
if (!(GetDeviceForKey(deviceKey) is IStreamDebugging device))
|
||||
{
|
||||
CrestronConsole.ConsoleCommandResponse("Unable to get device with key: {0}", deviceKey);
|
||||
return;
|
||||
}
|
||||
|
||||
eStreamDebuggingSetting debugSetting;
|
||||
|
||||
try
|
||||
{
|
||||
debugSetting = (eStreamDebuggingSetting)Enum.Parse(typeof(eStreamDebuggingSetting), setting, true);
|
||||
}
|
||||
catch
|
||||
{
|
||||
CrestronConsole.ConsoleCommandResponse("Unable to convert setting value. Please use off/rx/tx/both");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(timeout))
|
||||
DeviceCriticalSection.Enter();
|
||||
AddDeviceEnabled = false;
|
||||
// PreActivate all devices
|
||||
Debug.LogMessage(LogEventLevel.Information, "****PreActivation starting...****");
|
||||
foreach (var d in Devices.Values)
|
||||
{
|
||||
try
|
||||
{
|
||||
var min = Convert.ToUInt32(timeout);
|
||||
|
||||
device.StreamDebugging.SetDebuggingWithSpecificTimeout(debugSetting, min);
|
||||
CrestronConsole.ConsoleCommandResponse("Device: '{0}' debug level set to {1} for {2} minutes", deviceKey, debugSetting, min);
|
||||
|
||||
{
|
||||
if (d is Device)
|
||||
(d as Device).PreActivate();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
CrestronConsole.ConsoleCommandResponse("Unable to convert minutes or settings value. Please use an integer value for minutes. Error: {0}", e);
|
||||
Debug.LogMessage(LogEventLevel.Information, d, "ERROR: Device {1} PreActivation failure: {0}", e.Message, d.Key);
|
||||
Debug.LogMessage(LogEventLevel.Debug, d, "Stack Trace: {0}", e.StackTrace);
|
||||
}
|
||||
}
|
||||
else
|
||||
Debug.LogMessage(LogEventLevel.Information, "****PreActivation complete****");
|
||||
Debug.LogMessage(LogEventLevel.Information, "****Activation starting...****");
|
||||
|
||||
// Activate all devices
|
||||
foreach (var d in Devices.Values)
|
||||
{
|
||||
device.StreamDebugging.SetDebuggingWithDefaultTimeout(debugSetting);
|
||||
CrestronConsole.ConsoleCommandResponse("Device: '{0}' debug level set to {1} for default time (30 minutes)", deviceKey, debugSetting);
|
||||
try
|
||||
{
|
||||
if (d is Device)
|
||||
(d as Device).Activate();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Debug.LogMessage(LogEventLevel.Information, d, "ERROR: Device {1} Activation failure: {0}", e.Message, d.Key);
|
||||
Debug.LogMessage(LogEventLevel.Debug, d, "Stack Trace: {0}", e.StackTrace);
|
||||
}
|
||||
}
|
||||
|
||||
Debug.LogMessage(LogEventLevel.Information, "****Activation complete****");
|
||||
Debug.LogMessage(LogEventLevel.Information, "****PostActivation starting...****");
|
||||
|
||||
// PostActivate all devices
|
||||
foreach (var d in Devices.Values)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (d is Device)
|
||||
(d as Device).PostActivate();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Debug.LogMessage(LogEventLevel.Information, d, "ERROR: Device {1} PostActivation failure: {0}", e.Message, d.Key);
|
||||
Debug.LogMessage(LogEventLevel.Debug, d, "Stack Trace: {0}", e.StackTrace);
|
||||
}
|
||||
}
|
||||
|
||||
Debug.LogMessage(LogEventLevel.Information, "****PostActivation complete****");
|
||||
|
||||
OnAllDevicesActivated();
|
||||
}
|
||||
finally
|
||||
{
|
||||
DeviceCriticalSection.Leave();
|
||||
}
|
||||
}
|
||||
|
||||
private static void DeviceManager_Initialized(object sender, EventArgs e)
|
||||
{
|
||||
var allInitialized = Devices.Values.OfType<EssentialsDevice>().All(d => d.IsInitialized);
|
||||
|
||||
if (allInitialized)
|
||||
{
|
||||
Debug.LogMessage(LogEventLevel.Information, "****All Devices Initalized****");
|
||||
|
||||
OnAllDevicesInitialized();
|
||||
}
|
||||
}
|
||||
|
||||
private static void OnAllDevicesActivated()
|
||||
{
|
||||
var handler = AllDevicesActivated;
|
||||
if (handler != null)
|
||||
{
|
||||
handler(null, new EventArgs());
|
||||
}
|
||||
}
|
||||
|
||||
private static void OnAllDevicesRegistered()
|
||||
{
|
||||
var handler = AllDevicesRegistered;
|
||||
if (handler != null)
|
||||
{
|
||||
handler(null, new EventArgs());
|
||||
}
|
||||
}
|
||||
|
||||
private static void OnAllDevicesInitialized()
|
||||
{
|
||||
var handler = AllDevicesInitialized;
|
||||
if (handler != null)
|
||||
{
|
||||
handler(null, new EventArgs());
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Calls activate on all Device class items
|
||||
/// </summary>
|
||||
public static void DeactivateAll()
|
||||
{
|
||||
try
|
||||
{
|
||||
DeviceCriticalSection.Enter();
|
||||
foreach (var d in Devices.Values.OfType<Device>())
|
||||
{
|
||||
d.Deactivate();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets stream debugging settings to off for all devices
|
||||
/// </summary>
|
||||
public static void DisableAllDeviceStreamDebugging()
|
||||
finally
|
||||
{
|
||||
foreach (var device in AllDevices)
|
||||
DeviceCriticalSection.Leave();
|
||||
}
|
||||
}
|
||||
|
||||
//static void ListMethods(string devKey)
|
||||
//{
|
||||
// var dev = GetDeviceForKey(devKey);
|
||||
// if(dev != null)
|
||||
// {
|
||||
// var type = dev.GetType().GetType();
|
||||
// var methods = type.GetMethods(BindingFlags.Public|BindingFlags.Instance);
|
||||
// var sb = new StringBuilder();
|
||||
// sb.AppendLine(string.Format("{2} methods on [{0}] ({1}):", dev.Key, type.Name, methods.Length));
|
||||
// foreach (var m in methods)
|
||||
// {
|
||||
// sb.Append(string.Format("{0}(", m.Name));
|
||||
// var pars = m.GetParameters();
|
||||
// foreach (var p in pars)
|
||||
// sb.Append(string.Format("({1}){0} ", p.Name, p.ParameterType.Name));
|
||||
// sb.AppendLine(")");
|
||||
// }
|
||||
// CrestronConsole.ConsoleCommandResponse(sb.ToString());
|
||||
// }
|
||||
//}
|
||||
|
||||
private static void ListDevices(string s)
|
||||
{
|
||||
Debug.LogMessage(LogEventLevel.Information, "{0} Devices registered with Device Manager:", Devices.Count);
|
||||
var sorted = Devices.Values.ToList();
|
||||
sorted.Sort((a, b) => a.Key.CompareTo(b.Key));
|
||||
|
||||
foreach (var d in sorted)
|
||||
{
|
||||
var name = d is IKeyName ? (d as IKeyName).Name : "---";
|
||||
Debug.LogMessage(LogEventLevel.Information, " [{0}] {1}", d.Key, name);
|
||||
}
|
||||
}
|
||||
|
||||
private static void ListDeviceFeedbacks(string devKey)
|
||||
{
|
||||
var dev = GetDeviceForKey(devKey);
|
||||
if (dev == null)
|
||||
{
|
||||
Debug.LogMessage(LogEventLevel.Information, "Device '{0}' not found", devKey);
|
||||
return;
|
||||
}
|
||||
if (!(dev is IHasFeedback statusDev))
|
||||
{
|
||||
Debug.LogMessage(LogEventLevel.Information, "Device '{0}' does not have visible feedbacks", devKey);
|
||||
return;
|
||||
}
|
||||
statusDev.DumpFeedbacksToConsole(true);
|
||||
}
|
||||
|
||||
//static void ListDeviceCommands(string devKey)
|
||||
//{
|
||||
// var dev = GetDeviceForKey(devKey);
|
||||
// if (dev == null)
|
||||
// {
|
||||
// Debug.LogMessage(LogEventLevel.Information, "Device '{0}' not found", devKey);
|
||||
// return;
|
||||
// }
|
||||
// Debug.LogMessage(LogEventLevel.Information, "This needs to be reworked. Stay tuned.", devKey);
|
||||
//}
|
||||
|
||||
private static void ListDeviceCommStatuses(string input)
|
||||
{
|
||||
|
||||
foreach (var dev in Devices.Values.OfType<ICommunicationMonitor>())
|
||||
{
|
||||
CrestronConsole.ConsoleCommandResponse($"{dev}: {dev.CommunicationMonitor.Status}\r\n");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//static void DoDeviceCommand(string command)
|
||||
//{
|
||||
// Debug.LogMessage(LogEventLevel.Information, "Not yet implemented. Stay tuned");
|
||||
//}
|
||||
|
||||
public static void AddDevice(IKeyed newDev)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (!DeviceCriticalSection.TryEnter())
|
||||
{
|
||||
if (device is IStreamDebugging streamDevice)
|
||||
Debug.LogMessage(LogEventLevel.Information, "Currently unable to add devices to Device Manager. Please try again");
|
||||
return;
|
||||
}
|
||||
// Check for device with same key
|
||||
//var existingDevice = _Devices.FirstOrDefault(d => d.Key.Equals(newDev.Key, StringComparison.OrdinalIgnoreCase));
|
||||
////// If it exists, remove or warn??
|
||||
//if (existingDevice != null)
|
||||
|
||||
if (!AddDeviceEnabled)
|
||||
{
|
||||
Debug.LogMessage(LogEventLevel.Information, "All devices have been activated. Adding new devices is not allowed.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (Devices.ContainsKey(newDev.Key))
|
||||
{
|
||||
Debug.LogMessage(LogEventLevel.Information, newDev, "WARNING: A device with this key already exists. Not added to manager");
|
||||
return;
|
||||
}
|
||||
Devices.Add(newDev.Key, newDev);
|
||||
//if (!(_Devices.Contains(newDev)))
|
||||
// _Devices.Add(newDev);
|
||||
|
||||
if (newDev is EssentialsDevice essentialsDev)
|
||||
essentialsDev.Initialized += DeviceManager_Initialized;
|
||||
}
|
||||
finally
|
||||
{
|
||||
DeviceCriticalSection.Leave();
|
||||
}
|
||||
}
|
||||
|
||||
public static void AddDevice(IEnumerable<IKeyed> devicesToAdd)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (!DeviceCriticalSection.TryEnter())
|
||||
{
|
||||
Debug.LogMessage(LogEventLevel.Information,
|
||||
"Currently unable to add devices to Device Manager. Please try again");
|
||||
return;
|
||||
}
|
||||
if (!AddDeviceEnabled)
|
||||
{
|
||||
Debug.LogMessage(LogEventLevel.Information,
|
||||
"All devices have been activated. Adding new devices is not allowed.");
|
||||
return;
|
||||
}
|
||||
|
||||
foreach (var dev in devicesToAdd)
|
||||
{
|
||||
try
|
||||
{
|
||||
streamDevice.StreamDebugging.SetDebuggingWithDefaultTimeout(eStreamDebuggingSetting.Off);
|
||||
Devices.Add(dev.Key, dev);
|
||||
}
|
||||
catch (ArgumentException ex)
|
||||
{
|
||||
Debug.LogMessage(LogEventLevel.Information, "Error adding device with key {0} to Device Manager: {1}\r\nStack Trace: {2}",
|
||||
dev.Key, ex.Message, ex.StackTrace);
|
||||
}
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
DeviceCriticalSection.Leave();
|
||||
}
|
||||
}
|
||||
|
||||
public static void RemoveDevice(IKeyed newDev)
|
||||
{
|
||||
try
|
||||
{
|
||||
DeviceCriticalSection.Enter();
|
||||
if (newDev == null)
|
||||
return;
|
||||
if (Devices.ContainsKey(newDev.Key))
|
||||
Devices.Remove(newDev.Key);
|
||||
//if (_Devices.Contains(newDev))
|
||||
// _Devices.Remove(newDev);
|
||||
else
|
||||
Debug.LogMessage(LogEventLevel.Information, "Device manager: Device '{0}' does not exist in manager. Cannot remove", newDev.Key);
|
||||
}
|
||||
finally
|
||||
{
|
||||
DeviceCriticalSection.Leave();
|
||||
}
|
||||
}
|
||||
|
||||
public static IEnumerable<string> GetDeviceKeys()
|
||||
{
|
||||
//return _Devices.Select(d => d.Key).ToList();
|
||||
return Devices.Keys;
|
||||
}
|
||||
|
||||
public static IEnumerable<IKeyed> GetDevices()
|
||||
{
|
||||
//return _Devices.Select(d => d.Key).ToList();
|
||||
return Devices.Values;
|
||||
}
|
||||
|
||||
public static IKeyed GetDeviceForKey(string key)
|
||||
{
|
||||
//return _Devices.FirstOrDefault(d => d.Key.Equals(key, StringComparison.OrdinalIgnoreCase));
|
||||
if (key != null && Devices.ContainsKey(key))
|
||||
return Devices[key];
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Console handler that simulates com port data receive
|
||||
/// </summary>
|
||||
/// <param name="s"></param>
|
||||
public static void SimulateComReceiveOnDevice(string s)
|
||||
{
|
||||
// devcomsim:1 xyzabc
|
||||
var match = Regex.Match(s, @"(\S*)\s*(.*)");
|
||||
if (match.Groups.Count < 3)
|
||||
{
|
||||
CrestronConsole.ConsoleCommandResponse(" Format: devsimreceive:P <device key> <string to send>");
|
||||
return;
|
||||
}
|
||||
//Debug.LogMessage(LogEventLevel.Verbose, "**** {0} - {1} ****", match.Groups[1].Value, match.Groups[2].Value);
|
||||
|
||||
if (!(GetDeviceForKey(match.Groups[1].Value) is ComPortController com))
|
||||
{
|
||||
CrestronConsole.ConsoleCommandResponse("'{0}' is not a comm port device", match.Groups[1].Value);
|
||||
return;
|
||||
}
|
||||
com.SimulateReceive(match.Groups[2].Value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Prints a list of routing inputs and outputs by device key.
|
||||
/// </summary>
|
||||
/// <param name="s">Device key from which to report data</param>
|
||||
public static void GetRoutingPorts(string s)
|
||||
{
|
||||
var device = GetDeviceForKey(s);
|
||||
|
||||
if (device == null) return;
|
||||
var inputPorts = ((device as IRoutingInputs) != null) ? (device as IRoutingInputs).InputPorts : null;
|
||||
var outputPorts = ((device as IRoutingOutputs) != null) ? (device as IRoutingOutputs).OutputPorts : null;
|
||||
if (inputPorts != null)
|
||||
{
|
||||
CrestronConsole.ConsoleCommandResponse("Device {0} has {1} Input Ports:{2}", s, inputPorts.Count, CrestronEnvironment.NewLine);
|
||||
foreach (var routingInputPort in inputPorts)
|
||||
{
|
||||
CrestronConsole.ConsoleCommandResponse("{0}{1}", routingInputPort.Key, CrestronEnvironment.NewLine);
|
||||
}
|
||||
}
|
||||
if (outputPorts == null) return;
|
||||
CrestronConsole.ConsoleCommandResponse("Device {0} has {1} Output Ports:{2}", s, outputPorts.Count, CrestronEnvironment.NewLine);
|
||||
foreach (var routingOutputPort in outputPorts)
|
||||
{
|
||||
CrestronConsole.ConsoleCommandResponse("{0}{1}", routingOutputPort.Key, CrestronEnvironment.NewLine);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Attempts to set the debug level of a device
|
||||
/// </summary>
|
||||
/// <param name="s"></param>
|
||||
public static void SetDeviceStreamDebugging(string s)
|
||||
{
|
||||
if (String.IsNullOrEmpty(s) || s.Contains("?"))
|
||||
{
|
||||
CrestronConsole.ConsoleCommandResponse(
|
||||
@"SETDEVICESTREAMDEBUG [{deviceKey}] [OFF |TX | RX | BOTH] [timeOutInMinutes]
|
||||
{deviceKey} [OFF | TX | RX | BOTH] - Device to set stream debugging on, and which setting to use
|
||||
timeOutInMinutes - Set timeout for stream debugging. Default is 30 minutes");
|
||||
return;
|
||||
}
|
||||
|
||||
var args = s.Split(' ');
|
||||
|
||||
var deviceKey = args[0];
|
||||
var setting = args[1];
|
||||
|
||||
var timeout = String.Empty;
|
||||
|
||||
if (args.Length >= 3)
|
||||
{
|
||||
timeout = args[2];
|
||||
}
|
||||
|
||||
|
||||
if (!(GetDeviceForKey(deviceKey) is IStreamDebugging device))
|
||||
{
|
||||
CrestronConsole.ConsoleCommandResponse("Unable to get device with key: {0}", deviceKey);
|
||||
return;
|
||||
}
|
||||
|
||||
eStreamDebuggingSetting debugSetting;
|
||||
|
||||
try
|
||||
{
|
||||
debugSetting = (eStreamDebuggingSetting)Enum.Parse(typeof(eStreamDebuggingSetting), setting, true);
|
||||
}
|
||||
catch
|
||||
{
|
||||
CrestronConsole.ConsoleCommandResponse("Unable to convert setting value. Please use off/rx/tx/both");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(timeout))
|
||||
{
|
||||
try
|
||||
{
|
||||
var min = Convert.ToUInt32(timeout);
|
||||
|
||||
device.StreamDebugging.SetDebuggingWithSpecificTimeout(debugSetting, min);
|
||||
CrestronConsole.ConsoleCommandResponse("Device: '{0}' debug level set to {1} for {2} minutes", deviceKey, debugSetting, min);
|
||||
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
CrestronConsole.ConsoleCommandResponse("Unable to convert minutes or settings value. Please use an integer value for minutes. Error: {0}", e);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
device.StreamDebugging.SetDebuggingWithDefaultTimeout(debugSetting);
|
||||
CrestronConsole.ConsoleCommandResponse("Device: '{0}' debug level set to {1} for default time (30 minutes)", deviceKey, debugSetting);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets stream debugging settings to off for all devices
|
||||
/// </summary>
|
||||
public static void DisableAllDeviceStreamDebugging()
|
||||
{
|
||||
foreach (var device in AllDevices)
|
||||
{
|
||||
if (device is IStreamDebugging streamDevice)
|
||||
{
|
||||
streamDevice.StreamDebugging.SetDebuggingWithDefaultTimeout(eStreamDebuggingSetting.Off);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,190 +9,300 @@ using Serilog.Events;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.IO;
|
||||
|
||||
namespace PepperDash.Essentials.Core
|
||||
namespace PepperDash.Essentials.Core;
|
||||
|
||||
/// <summary>
|
||||
/// Represents a wrapper for a device factory, encapsulating the type of device, a description, and a factory method
|
||||
/// for creating device instances.
|
||||
/// </summary>
|
||||
/// <remarks>This class is designed to provide a convenient way to store and manage metadata and factory methods
|
||||
/// for creating devices based on a given configuration.</remarks>
|
||||
public class DeviceFactoryWrapper
|
||||
{
|
||||
public class DeviceFactoryWrapper
|
||||
{
|
||||
public Type Type { get; set; }
|
||||
public string Description { get; set; }
|
||||
public Func<DeviceConfig, IKeyed> FactoryMethod { get; set; }
|
||||
/// <summary>
|
||||
/// Gets or sets the type associated with the current instance.
|
||||
/// </summary>
|
||||
public Type Type { get; set; }
|
||||
|
||||
public DeviceFactoryWrapper()
|
||||
{
|
||||
Type = null;
|
||||
Description = "Not Available";
|
||||
}
|
||||
/// <summary>
|
||||
/// Gets or sets the description associated with the object.
|
||||
/// </summary>
|
||||
public string Description { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the factory method used to create an <see cref="IKeyed"/> instance based on the provided <see
|
||||
/// cref="DeviceConfig"/>.
|
||||
/// </summary>
|
||||
/// <remarks>The factory method allows customization of how <see cref="IKeyed"/> instances are created for
|
||||
/// specific <see cref="DeviceConfig"/> inputs. Ensure the delegate is not null before invoking it.</remarks>
|
||||
public Func<DeviceConfig, IKeyed> FactoryMethod { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="DeviceFactoryWrapper"/> class with default values.
|
||||
/// </summary>
|
||||
/// <remarks>The <see cref="Type"/> property is initialized to <see langword="null"/>, and the <see
|
||||
/// cref="Description"/> property is set to "Not Available".</remarks>
|
||||
public DeviceFactoryWrapper()
|
||||
{
|
||||
Type = null;
|
||||
Description = "Not Available";
|
||||
}
|
||||
}
|
||||
|
||||
public class DeviceFactory
|
||||
{
|
||||
public DeviceFactory()
|
||||
{
|
||||
var assy = Assembly.GetExecutingAssembly();
|
||||
PluginLoader.SetEssentialsAssembly(assy.GetName().Name, assy);
|
||||
/// <summary>
|
||||
/// Provides functionality for managing and registering device factories, including loading plugin-based factories and
|
||||
/// retrieving devices based on their configuration.
|
||||
/// </summary>
|
||||
/// <remarks>The <see cref="DeviceFactory"/> class is responsible for discovering and registering device factories
|
||||
/// from plugins, as well as providing methods to retrieve devices based on their configuration. It maintains a
|
||||
/// collection of factory methods that are keyed by device type names, allowing for extensibility through plugins. This
|
||||
/// class also handles metadata retrieval and secret management for device configurations.</remarks>
|
||||
public class DeviceFactory
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="DeviceFactory"/> class and loads all available device factories
|
||||
/// from the current assembly.
|
||||
/// </summary>
|
||||
/// <remarks>This constructor scans the executing assembly for types that implement the <see
|
||||
/// cref="IDeviceFactory"/> interface and are not abstract or interfaces. For each valid type, an instance is
|
||||
/// created and passed to the <c>LoadDeviceFactories</c> method for further processing. If a type cannot be
|
||||
/// instantiated, an informational log message is generated, and the process continues with the remaining
|
||||
/// types.</remarks>
|
||||
public DeviceFactory()
|
||||
{
|
||||
var programAssemblies = Directory.GetFiles(InitialParametersClass.ProgramDirectory.ToString(), "*.dll");
|
||||
|
||||
var types = assy.GetTypes().Where(ct => typeof(IDeviceFactory).IsAssignableFrom(ct) && !ct.IsInterface && !ct.IsAbstract);
|
||||
|
||||
if (types != null)
|
||||
{
|
||||
foreach (var type in types)
|
||||
{
|
||||
try
|
||||
{
|
||||
var factory = (IDeviceFactory)Activator.CreateInstance(type);
|
||||
factory.LoadTypeFactories();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Debug.LogMessage(LogEventLevel.Information, "Unable to load type: '{1}' DeviceFactory: {0}", e, type.Name);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A dictionary of factory methods, keyed by config types, added by plugins.
|
||||
/// These methods are looked up and called by GetDevice in this class.
|
||||
/// </summary>
|
||||
static Dictionary<string, DeviceFactoryWrapper> FactoryMethods =
|
||||
new Dictionary<string, DeviceFactoryWrapper>(StringComparer.OrdinalIgnoreCase);
|
||||
|
||||
/// <summary>
|
||||
/// Adds a plugin factory method
|
||||
/// </summary>
|
||||
/// <param name="dc"></param>
|
||||
/// <returns></returns>
|
||||
public static void AddFactoryForType(string typeName, Func<DeviceConfig, IKeyed> method)
|
||||
{
|
||||
//Debug.LogMessage(LogEventLevel.Debug, "Adding factory method for type '{0}'", typeName);
|
||||
DeviceFactory.FactoryMethods.Add(typeName, new DeviceFactoryWrapper() { FactoryMethod = method});
|
||||
}
|
||||
|
||||
public static void AddFactoryForType(string typeName, string description, Type Type, Func<DeviceConfig, IKeyed> method)
|
||||
{
|
||||
//Debug.LogMessage(LogEventLevel.Debug, "Adding factory method for type '{0}'", typeName);
|
||||
|
||||
if(FactoryMethods.ContainsKey(typeName))
|
||||
{
|
||||
Debug.LogMessage(LogEventLevel.Information, "Unable to add type: '{0}'. Already exists in DeviceFactory", typeName);
|
||||
return;
|
||||
}
|
||||
|
||||
var wrapper = new DeviceFactoryWrapper() { Type = Type, Description = description, FactoryMethod = method };
|
||||
DeviceFactory.FactoryMethods.Add(typeName, wrapper);
|
||||
}
|
||||
|
||||
private static void CheckForSecrets(IEnumerable<JProperty> obj)
|
||||
{
|
||||
foreach (var prop in obj.Where(prop => prop.Value as JObject != null))
|
||||
{
|
||||
if (prop.Name.ToLower() == "secret")
|
||||
{
|
||||
var secret = GetSecret(prop.Children().First().ToObject<SecretsPropertiesConfig>());
|
||||
//var secret = GetSecret(JsonConvert.DeserializeObject<SecretsPropertiesConfig>(prop.Children().First().ToString()));
|
||||
prop.Parent.Replace(secret);
|
||||
}
|
||||
var recurseProp = prop.Value as JObject;
|
||||
if (recurseProp == null) return;
|
||||
CheckForSecrets(recurseProp.Properties());
|
||||
}
|
||||
}
|
||||
|
||||
private static string GetSecret(SecretsPropertiesConfig data)
|
||||
{
|
||||
var secretProvider = SecretsManager.GetSecretProviderByKey(data.Provider);
|
||||
if (secretProvider == null) return null;
|
||||
var secret = secretProvider.GetSecret(data.Key);
|
||||
if (secret != null) return (string) secret.Value;
|
||||
Debug.LogMessage(LogEventLevel.Debug,
|
||||
"Unable to retrieve secret {0}{1} - Make sure you've added it to the secrets provider",
|
||||
data.Provider, data.Key);
|
||||
return String.Empty;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// The factory method for Core "things". Also iterates the Factory methods that have
|
||||
/// been loaded from plugins
|
||||
/// </summary>
|
||||
/// <param name="dc"></param>
|
||||
/// <returns></returns>
|
||||
public static IKeyed GetDevice(DeviceConfig dc)
|
||||
foreach(var assembly in programAssemblies)
|
||||
{
|
||||
try
|
||||
{
|
||||
Debug.LogMessage(LogEventLevel.Information, "Loading '{0}' from Essentials Core", dc.Type);
|
||||
|
||||
var localDc = new DeviceConfig(dc);
|
||||
|
||||
var key = localDc.Key;
|
||||
var name = localDc.Name;
|
||||
var type = localDc.Type;
|
||||
var properties = localDc.Properties;
|
||||
//var propRecurse = properties;
|
||||
|
||||
var typeName = localDc.Type.ToLower();
|
||||
|
||||
|
||||
var jObject = properties as JObject;
|
||||
if (jObject != null)
|
||||
{
|
||||
var jProp = jObject.Properties();
|
||||
|
||||
CheckForSecrets(jProp);
|
||||
}
|
||||
|
||||
Debug.LogMessage(LogEventLevel.Verbose, "typeName = {0}", typeName);
|
||||
// Check for types that have been added by plugin dlls.
|
||||
return !FactoryMethods.ContainsKey(typeName) ? null : FactoryMethods[typeName].FactoryMethod(localDc);
|
||||
Assembly.LoadFrom(assembly);
|
||||
}
|
||||
catch (Exception ex)
|
||||
catch (Exception e)
|
||||
{
|
||||
Debug.LogMessage(ex, "Exception occurred while creating device {0}: {1}", null, dc.Key, ex.Message);
|
||||
return null;
|
||||
Debug.LogError("Unable to load assembly: {assemblyName} - {message}", assembly, e.Message);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Prints the type names and associated metadata from the FactoryMethods collection.
|
||||
/// </summary>
|
||||
/// <param name="filter"></param>
|
||||
public static void GetDeviceFactoryTypes(string filter)
|
||||
var loadedAssemblies = AppDomain.CurrentDomain.GetAssemblies();
|
||||
|
||||
// Loop through all loaded assemblies that contain at least 1 type that implements IDeviceFactory
|
||||
foreach (var assembly in loadedAssemblies)
|
||||
{
|
||||
Debug.LogDebug("loaded assembly: {assemblyName}", assembly.GetName().Name);
|
||||
|
||||
PluginLoader.AddLoadedAssembly(assembly.GetName().Name, assembly);
|
||||
|
||||
var types = assembly.GetTypes().Where(ct => typeof(IDeviceFactory).IsAssignableFrom(ct) && !ct.IsInterface && !ct.IsAbstract);
|
||||
|
||||
if(types == null || !types.Any())
|
||||
{
|
||||
Debug.LogDebug("No DeviceFactory types found in assembly: {assemblyName}", assembly.GetName().Name);
|
||||
continue;
|
||||
}
|
||||
|
||||
foreach (var type in types)
|
||||
{
|
||||
try
|
||||
{
|
||||
var factory = (IDeviceFactory)Activator.CreateInstance(type);
|
||||
LoadDeviceFactories(factory);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Debug.LogError("Unable to load type: '{message}' DeviceFactory: {type}", e.Message, type.Name);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Loads device factories from the specified plugin device factory and registers them for use.
|
||||
/// </summary>
|
||||
/// <remarks>This method retrieves metadata from the provided <paramref name="deviceFactory"/>, including
|
||||
/// type names, descriptions, and configuration snippets, and registers the factory for each device type. The type
|
||||
/// names are converted to lowercase for registration.</remarks>
|
||||
/// <param name="deviceFactory">The plugin device factory that provides the device types, descriptions, and factory methods to be registered.</param>
|
||||
private static void LoadDeviceFactories(IDeviceFactory deviceFactory)
|
||||
{
|
||||
foreach (var typeName in deviceFactory.TypeNames)
|
||||
{
|
||||
var types = !string.IsNullOrEmpty(filter)
|
||||
? FactoryMethods.Where(k => k.Key.Contains(filter)).ToDictionary(k => k.Key, k => k.Value)
|
||||
: FactoryMethods;
|
||||
//Debug.LogMessage(LogEventLevel.Verbose, "Getting Description Attribute from class: '{0}'", typeof(T).FullName);
|
||||
var descriptionAttribute = deviceFactory.FactoryType.GetCustomAttributes(typeof(DescriptionAttribute), true) as DescriptionAttribute[];
|
||||
string description = descriptionAttribute[0].Description;
|
||||
var snippetAttribute = deviceFactory.FactoryType.GetCustomAttributes(typeof(ConfigSnippetAttribute), true) as ConfigSnippetAttribute[];
|
||||
AddFactoryForType(typeName.ToLower(), description, deviceFactory.FactoryType, deviceFactory.BuildDevice);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A dictionary of factory methods, keyed by config types, added by plugins.
|
||||
/// These methods are looked up and called by GetDevice in this class.
|
||||
/// </summary>
|
||||
private static readonly Dictionary<string, DeviceFactoryWrapper> FactoryMethods =
|
||||
new(StringComparer.OrdinalIgnoreCase);
|
||||
|
||||
CrestronConsole.ConsoleCommandResponse("Device Types:");
|
||||
/// <summary>
|
||||
/// Registers a factory method for creating instances of a specific type.
|
||||
/// </summary>
|
||||
/// <remarks>This method associates a type name with a factory method, allowing instances of the type to
|
||||
/// be created dynamically. The factory method is stored internally and can be retrieved or invoked as
|
||||
/// needed.</remarks>
|
||||
/// <param name="typeName">The name of the type for which the factory method is being registered. This value cannot be null or empty.</param>
|
||||
/// <param name="method">A delegate that defines the factory method. The delegate takes a <see cref="DeviceConfig"/> parameter and
|
||||
/// returns an instance of <see cref="IKeyed"/>.</param>
|
||||
public static void AddFactoryForType(string typeName, Func<DeviceConfig, IKeyed> method)
|
||||
{
|
||||
FactoryMethods.Add(typeName, new DeviceFactoryWrapper() { FactoryMethod = method});
|
||||
}
|
||||
|
||||
foreach (var type in types.OrderBy(t => t.Key))
|
||||
/// <summary>
|
||||
/// Registers a factory method for creating instances of a specific device type.
|
||||
/// </summary>
|
||||
/// <remarks>If a factory method for the specified <paramref name="typeName"/> already exists, the method
|
||||
/// will not overwrite it and will log an informational message instead.</remarks>
|
||||
/// <param name="typeName">The unique name of the device type. This serves as the key for identifying the factory method.</param>
|
||||
/// <param name="description">A brief description of the device type. This is used for informational purposes.</param>
|
||||
/// <param name="Type">The <see cref="Type"/> of the device being registered. This represents the runtime type of the device.</param>
|
||||
/// <param name="method">A factory method that takes a <see cref="DeviceConfig"/> as input and returns an instance of <see
|
||||
/// cref="IKeyed"/>.</param>
|
||||
public static void AddFactoryForType(string typeName, string description, Type Type, Func<DeviceConfig, IKeyed> method)
|
||||
{
|
||||
if(FactoryMethods.ContainsKey(typeName))
|
||||
{
|
||||
Debug.LogInformation("Unable to add type: '{typeName}'. Already exists in DeviceFactory", typeName);
|
||||
return;
|
||||
}
|
||||
|
||||
var wrapper = new DeviceFactoryWrapper() { Type = Type, Description = description, FactoryMethod = method };
|
||||
|
||||
FactoryMethods.Add(typeName, wrapper);
|
||||
}
|
||||
|
||||
private static void CheckForSecrets(IEnumerable<JProperty> obj)
|
||||
{
|
||||
foreach (var prop in obj.Where(prop => prop.Value as JObject != null))
|
||||
{
|
||||
if (prop.Name.Equals("secret", StringComparison.CurrentCultureIgnoreCase))
|
||||
{
|
||||
var description = type.Value.Description;
|
||||
var Type = "Not Specified by Plugin";
|
||||
var secret = GetSecret(prop.Children().First().ToObject<SecretsPropertiesConfig>());
|
||||
|
||||
prop.Parent.Replace(secret);
|
||||
}
|
||||
if (prop.Value is not JObject recurseProp) return;
|
||||
CheckForSecrets(recurseProp.Properties());
|
||||
}
|
||||
}
|
||||
|
||||
if (type.Value.Type != null)
|
||||
{
|
||||
Type = type.Value.Type.FullName;
|
||||
}
|
||||
private static string GetSecret(SecretsPropertiesConfig data)
|
||||
{
|
||||
var secretProvider = SecretsManager.GetSecretProviderByKey(data.Provider);
|
||||
if (secretProvider == null) return null;
|
||||
var secret = secretProvider.GetSecret(data.Key);
|
||||
if (secret != null) return (string) secret.Value;
|
||||
Debug.LogMessage(LogEventLevel.Debug,
|
||||
"Unable to retrieve secret {0}{1} - Make sure you've added it to the secrets provider",
|
||||
data.Provider, data.Key);
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
CrestronConsole.ConsoleCommandResponse(
|
||||
@"Type: '{0}'
|
||||
|
||||
/// <summary>
|
||||
/// Creates and returns a device instance based on the provided <see cref="DeviceConfig"/>.
|
||||
/// </summary>
|
||||
/// <remarks>This method attempts to create a device using the type specified in the <paramref name="dc"/>
|
||||
/// parameter. If the type corresponds to a registered factory method, the device is created and returned. If the
|
||||
/// type is unrecognized or an exception occurs, the method logs the error and returns <see
|
||||
/// langword="null"/>.</remarks>
|
||||
/// <param name="dc">The configuration object containing the key, name, type, and properties required to create the device.</param>
|
||||
/// <returns>An instance of a device that implements <see cref="IKeyed"/>, or <see langword="null"/> if the device type is
|
||||
/// not recognized or an error occurs during creation.</returns>
|
||||
public static IKeyed GetDevice(DeviceConfig dc)
|
||||
{
|
||||
try
|
||||
{
|
||||
var localDc = new DeviceConfig(dc);
|
||||
|
||||
var key = localDc.Key;
|
||||
var name = localDc.Name;
|
||||
var type = localDc.Type;
|
||||
var properties = localDc.Properties;
|
||||
|
||||
var typeName = localDc.Type.ToLower();
|
||||
|
||||
if (properties is JObject jObject)
|
||||
{
|
||||
var jProp = jObject.Properties();
|
||||
|
||||
CheckForSecrets(jProp);
|
||||
}
|
||||
|
||||
if (!FactoryMethods.TryGetValue(typeName, out var wrapper))
|
||||
{
|
||||
Debug.LogWarning("Device type '{typeName}' not found in DeviceFactory", typeName);
|
||||
return null;
|
||||
}
|
||||
|
||||
Debug.LogInformation("Loading '{type}' from {assemblyName}", typeName, wrapper.Type.Assembly.FullName);
|
||||
|
||||
// Check for types that have been added by plugin dlls.
|
||||
return wrapper.FactoryMethod(localDc);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Debug.LogError(ex, "Exception occurred while creating device {0}: {1}", null, dc.Key, ex.Message);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Displays a list of device factory types that match the specified filter.
|
||||
/// </summary>
|
||||
/// <remarks>The method outputs the filtered list of device factory types to the console, including their
|
||||
/// key, type, and description. If a type is not specified by the plugin, it will be displayed as "Not Specified by
|
||||
/// Plugin."</remarks>
|
||||
/// <param name="filter">A string used to filter the device factory types by their keys. If the filter is null or empty, all device
|
||||
/// factory types are displayed.</param>
|
||||
public static void GetDeviceFactoryTypes(string filter)
|
||||
{
|
||||
var types = !string.IsNullOrEmpty(filter)
|
||||
? FactoryMethods.Where(k => k.Key.Contains(filter)).ToDictionary(k => k.Key, k => k.Value)
|
||||
: FactoryMethods;
|
||||
|
||||
CrestronConsole.ConsoleCommandResponse("Device Types:");
|
||||
|
||||
foreach (var type in types.OrderBy(t => t.Key))
|
||||
{
|
||||
var description = type.Value.Description;
|
||||
var Type = "Not Specified by Plugin";
|
||||
|
||||
if (type.Value.Type != null)
|
||||
{
|
||||
Type = type.Value.Type.FullName;
|
||||
}
|
||||
|
||||
CrestronConsole.ConsoleCommandResponse(
|
||||
@"Type: '{0}'
|
||||
Type: '{1}'
|
||||
Description: {2}{3}", type.Key, Type, description, CrestronEnvironment.NewLine);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the device factory dictionary
|
||||
/// </summary>
|
||||
/// <param name="filter"></param>
|
||||
/// <returns></returns>
|
||||
public static Dictionary<string, DeviceFactoryWrapper> GetDeviceFactoryDictionary(string filter)
|
||||
{
|
||||
return string.IsNullOrEmpty(filter)
|
||||
? FactoryMethods
|
||||
: FactoryMethods.Where(k => k.Key.Contains(filter)).ToDictionary(k => k.Key, k => k.Value);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Retrieves a dictionary of device factory wrappers, optionally filtered by a specified string.
|
||||
/// </summary>
|
||||
/// <param name="filter">A string used to filter the dictionary keys. Only entries with keys containing the specified filter will be
|
||||
/// included. If <see langword="null"/> or empty, all entries are returned.</param>
|
||||
/// <returns>A dictionary where the keys are strings representing device identifiers and the values are <see
|
||||
/// cref="DeviceFactoryWrapper"/> instances. The dictionary may be empty if no entries match the filter.</returns>
|
||||
public static Dictionary<string, DeviceFactoryWrapper> GetDeviceFactoryDictionary(string filter)
|
||||
{
|
||||
return string.IsNullOrEmpty(filter)
|
||||
? FactoryMethods
|
||||
: FactoryMethods.Where(k => k.Key.Contains(filter)).ToDictionary(k => k.Key, k => k.Value);
|
||||
}
|
||||
}
|
||||
@@ -10,143 +10,143 @@ using System.Linq;
|
||||
namespace PepperDash.Essentials.Core;
|
||||
|
||||
|
||||
public class ProcessorExtensionDeviceFactory
|
||||
public class ProcessorExtensionDeviceFactory
|
||||
{
|
||||
public ProcessorExtensionDeviceFactory() {
|
||||
var assy = Assembly.GetExecutingAssembly();
|
||||
PluginLoader.AddLoadedAssembly(assy.GetName().Name, assy);
|
||||
|
||||
var extensions = assy.GetTypes().Where(ct => typeof(IProcessorExtensionDeviceFactory)
|
||||
.IsAssignableFrom(ct) && !ct.IsInterface && !ct.IsAbstract);
|
||||
|
||||
if (extensions != null )
|
||||
{
|
||||
foreach ( var extension in extensions )
|
||||
{
|
||||
try
|
||||
{
|
||||
var factory = (IProcessorExtensionDeviceFactory)Activator.CreateInstance(extension);
|
||||
factory.LoadFactories();
|
||||
}
|
||||
catch( Exception e )
|
||||
{
|
||||
Debug.LogMessage(LogEventLevel.Information, "Unable to load extension device: '{1}' ProcessorExtensionDeviceFactory: {0}", e, extension.Name);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A dictionary of factory methods, keyed by config types, added by plugins.
|
||||
/// These methods are looked up and called by GetDevice in this class.
|
||||
/// </summary>
|
||||
static Dictionary<string, DeviceFactoryWrapper> ProcessorExtensionFactoryMethods =
|
||||
new Dictionary<string, DeviceFactoryWrapper>(StringComparer.OrdinalIgnoreCase);
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Adds a plugin factory method
|
||||
/// </summary>
|
||||
/// <param name="dc"></param>
|
||||
/// <returns></returns>
|
||||
public static void AddFactoryForType(string extensionName, Func<DeviceConfig, IKeyed> method)
|
||||
{
|
||||
public ProcessorExtensionDeviceFactory() {
|
||||
var assy = Assembly.GetExecutingAssembly();
|
||||
PluginLoader.SetEssentialsAssembly(assy.GetName().Name, assy);
|
||||
//Debug.LogMessage(LogEventLevel.Debug, "Adding factory method for type '{0}'", typeName);
|
||||
ProcessorExtensionDeviceFactory.ProcessorExtensionFactoryMethods.Add(extensionName, new DeviceFactoryWrapper() { FactoryMethod = method });
|
||||
}
|
||||
|
||||
var extensions = assy.GetTypes().Where(ct => typeof(IProcessorExtensionDeviceFactory)
|
||||
.IsAssignableFrom(ct) && !ct.IsInterface && !ct.IsAbstract);
|
||||
public static void AddFactoryForType(string extensionName, string description, Type Type, Func<DeviceConfig, IKeyed> method)
|
||||
{
|
||||
//Debug.LogMessage(LogEventLevel.Debug, "Adding factory method for type '{0}'", typeName);
|
||||
|
||||
if (extensions != null )
|
||||
if (ProcessorExtensionFactoryMethods.ContainsKey(extensionName))
|
||||
{
|
||||
Debug.LogMessage(LogEventLevel.Information, "Unable to add extension device: '{0}'. Already exists in ProcessorExtensionDeviceFactory", extensionName);
|
||||
return;
|
||||
}
|
||||
|
||||
var wrapper = new DeviceFactoryWrapper() { Type = Type, Description = description, FactoryMethod = method };
|
||||
ProcessorExtensionDeviceFactory.ProcessorExtensionFactoryMethods.Add(extensionName, wrapper);
|
||||
}
|
||||
|
||||
private static void CheckForSecrets(IEnumerable<Newtonsoft.Json.Linq.JProperty> obj)
|
||||
{
|
||||
foreach (var prop in obj.Where(prop => prop.Value as Newtonsoft.Json.Linq.JObject != null))
|
||||
{
|
||||
if (prop.Name.ToLower() == "secret")
|
||||
{
|
||||
foreach ( var extension in extensions )
|
||||
{
|
||||
try
|
||||
{
|
||||
var factory = (IProcessorExtensionDeviceFactory)Activator.CreateInstance(extension);
|
||||
factory.LoadFactories();
|
||||
}
|
||||
catch( Exception e )
|
||||
{
|
||||
Debug.LogMessage(LogEventLevel.Information, "Unable to load extension device: '{1}' ProcessorExtensionDeviceFactory: {0}", e, extension.Name);
|
||||
}
|
||||
}
|
||||
var secret = GetSecret(prop.Children().First().ToObject<SecretsPropertiesConfig>());
|
||||
//var secret = GetSecret(JsonConvert.DeserializeObject<SecretsPropertiesConfig>(prop.Children().First().ToString()));
|
||||
prop.Parent.Replace(secret);
|
||||
}
|
||||
var recurseProp = prop.Value as Newtonsoft.Json.Linq.JObject;
|
||||
if (recurseProp == null) return;
|
||||
CheckForSecrets(recurseProp.Properties());
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A dictionary of factory methods, keyed by config types, added by plugins.
|
||||
/// These methods are looked up and called by GetDevice in this class.
|
||||
/// </summary>
|
||||
static Dictionary<string, DeviceFactoryWrapper> ProcessorExtensionFactoryMethods =
|
||||
new Dictionary<string, DeviceFactoryWrapper>(StringComparer.OrdinalIgnoreCase);
|
||||
private static string GetSecret(SecretsPropertiesConfig data)
|
||||
{
|
||||
var secretProvider = SecretsManager.GetSecretProviderByKey(data.Provider);
|
||||
if (secretProvider == null) return null;
|
||||
var secret = secretProvider.GetSecret(data.Key);
|
||||
if (secret != null) return (string)secret.Value;
|
||||
Debug.LogMessage(LogEventLevel.Debug,
|
||||
"Unable to retrieve secret {0}{1} - Make sure you've added it to the secrets provider",
|
||||
data.Provider, data.Key);
|
||||
return String.Empty;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Adds a plugin factory method
|
||||
/// </summary>
|
||||
/// <param name="dc"></param>
|
||||
/// <returns></returns>
|
||||
public static void AddFactoryForType(string extensionName, Func<DeviceConfig, IKeyed> method)
|
||||
/// <summary>
|
||||
/// The factory method for processor extension devices. Also iterates the Factory methods that have
|
||||
/// been loaded from plugins
|
||||
/// </summary>
|
||||
/// <param name="dc"></param>
|
||||
/// <returns></returns>
|
||||
public static IKeyed GetExtensionDevice(DeviceConfig dc)
|
||||
{
|
||||
try
|
||||
{
|
||||
//Debug.LogMessage(LogEventLevel.Debug, "Adding factory method for type '{0}'", typeName);
|
||||
ProcessorExtensionDeviceFactory.ProcessorExtensionFactoryMethods.Add(extensionName, new DeviceFactoryWrapper() { FactoryMethod = method });
|
||||
}
|
||||
Debug.LogMessage(LogEventLevel.Information, "Loading '{0}' from Essentials Core", dc.Type);
|
||||
|
||||
public static void AddFactoryForType(string extensionName, string description, Type Type, Func<DeviceConfig, IKeyed> method)
|
||||
{
|
||||
//Debug.LogMessage(LogEventLevel.Debug, "Adding factory method for type '{0}'", typeName);
|
||||
var localDc = new DeviceConfig(dc);
|
||||
|
||||
if (ProcessorExtensionFactoryMethods.ContainsKey(extensionName))
|
||||
var key = localDc.Key;
|
||||
var name = localDc.Name;
|
||||
var type = localDc.Type;
|
||||
var properties = localDc.Properties;
|
||||
//var propRecurse = properties;
|
||||
|
||||
var typeName = localDc.Type.ToLower();
|
||||
|
||||
var jObject = properties as Newtonsoft.Json.Linq.JObject;
|
||||
if (jObject != null)
|
||||
{
|
||||
Debug.LogMessage(LogEventLevel.Information, "Unable to add extension device: '{0}'. Already exists in ProcessorExtensionDeviceFactory", extensionName);
|
||||
return;
|
||||
var jProp = jObject.Properties();
|
||||
|
||||
CheckForSecrets(jProp);
|
||||
}
|
||||
|
||||
var wrapper = new DeviceFactoryWrapper() { Type = Type, Description = description, FactoryMethod = method };
|
||||
ProcessorExtensionDeviceFactory.ProcessorExtensionFactoryMethods.Add(extensionName, wrapper);
|
||||
Debug.LogMessage(LogEventLevel.Verbose, "typeName = {0}", typeName);
|
||||
// Check for types that have been added by plugin dlls.
|
||||
return !ProcessorExtensionFactoryMethods.ContainsKey(typeName) ? null : ProcessorExtensionFactoryMethods[typeName].FactoryMethod(localDc);
|
||||
}
|
||||
|
||||
private static void CheckForSecrets(IEnumerable<Newtonsoft.Json.Linq.JProperty> obj)
|
||||
catch (Exception ex)
|
||||
{
|
||||
foreach (var prop in obj.Where(prop => prop.Value as Newtonsoft.Json.Linq.JObject != null))
|
||||
Debug.LogMessage(LogEventLevel.Information, "Exception occurred while creating device {0}: {1}", dc.Key, ex.Message);
|
||||
|
||||
Debug.LogMessage(LogEventLevel.Verbose, "{0}", ex.StackTrace);
|
||||
|
||||
if (ex.InnerException == null)
|
||||
{
|
||||
if (prop.Name.ToLower() == "secret")
|
||||
{
|
||||
var secret = GetSecret(prop.Children().First().ToObject<SecretsPropertiesConfig>());
|
||||
//var secret = GetSecret(JsonConvert.DeserializeObject<SecretsPropertiesConfig>(prop.Children().First().ToString()));
|
||||
prop.Parent.Replace(secret);
|
||||
}
|
||||
var recurseProp = prop.Value as Newtonsoft.Json.Linq.JObject;
|
||||
if (recurseProp == null) return;
|
||||
CheckForSecrets(recurseProp.Properties());
|
||||
}
|
||||
}
|
||||
|
||||
private static string GetSecret(SecretsPropertiesConfig data)
|
||||
{
|
||||
var secretProvider = SecretsManager.GetSecretProviderByKey(data.Provider);
|
||||
if (secretProvider == null) return null;
|
||||
var secret = secretProvider.GetSecret(data.Key);
|
||||
if (secret != null) return (string)secret.Value;
|
||||
Debug.LogMessage(LogEventLevel.Debug,
|
||||
"Unable to retrieve secret {0}{1} - Make sure you've added it to the secrets provider",
|
||||
data.Provider, data.Key);
|
||||
return String.Empty;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The factory method for processor extension devices. Also iterates the Factory methods that have
|
||||
/// been loaded from plugins
|
||||
/// </summary>
|
||||
/// <param name="dc"></param>
|
||||
/// <returns></returns>
|
||||
public static IKeyed GetExtensionDevice(DeviceConfig dc)
|
||||
{
|
||||
try
|
||||
{
|
||||
Debug.LogMessage(LogEventLevel.Information, "Loading '{0}' from Essentials Core", dc.Type);
|
||||
|
||||
var localDc = new DeviceConfig(dc);
|
||||
|
||||
var key = localDc.Key;
|
||||
var name = localDc.Name;
|
||||
var type = localDc.Type;
|
||||
var properties = localDc.Properties;
|
||||
//var propRecurse = properties;
|
||||
|
||||
var typeName = localDc.Type.ToLower();
|
||||
|
||||
var jObject = properties as Newtonsoft.Json.Linq.JObject;
|
||||
if (jObject != null)
|
||||
{
|
||||
var jProp = jObject.Properties();
|
||||
|
||||
CheckForSecrets(jProp);
|
||||
}
|
||||
|
||||
Debug.LogMessage(LogEventLevel.Verbose, "typeName = {0}", typeName);
|
||||
// Check for types that have been added by plugin dlls.
|
||||
return !ProcessorExtensionFactoryMethods.ContainsKey(typeName) ? null : ProcessorExtensionFactoryMethods[typeName].FactoryMethod(localDc);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Debug.LogMessage(LogEventLevel.Information, "Exception occurred while creating device {0}: {1}", dc.Key, ex.Message);
|
||||
|
||||
Debug.LogMessage(LogEventLevel.Verbose, "{0}", ex.StackTrace);
|
||||
|
||||
if (ex.InnerException == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
Debug.LogMessage(LogEventLevel.Information, "Inner exception while creating device {0}: {1}", dc.Key,
|
||||
ex.InnerException.Message);
|
||||
Debug.LogMessage(LogEventLevel.Verbose, "{0}", ex.InnerException.StackTrace);
|
||||
return null;
|
||||
}
|
||||
|
||||
Debug.LogMessage(LogEventLevel.Information, "Inner exception while creating device {0}: {1}", dc.Key,
|
||||
ex.InnerException.Message);
|
||||
Debug.LogMessage(LogEventLevel.Verbose, "{0}", ex.InnerException.StackTrace);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user