mirror of
https://github.com/PepperDash/Essentials.git
synced 2026-01-11 19:44:52 +00:00
feat: factory updates & refactoring
This commit introduces significant updates to the device factory system, enhancing the way devices are created and managed within the PepperDash Essentials framework. The changes include: - New attributes for device configuration and description. - Refactoring of the device manager and essentials device classes to support new factory methods. - modified factory classes for essentials devices, plugin development devices, and processor extension devices. - The device factory interface has been updated to include a factory method for creating devices. - Added a wrapper for the device factory to streamline device creation. - Updated plugin loader to accommodate the new device factory structure. Fixes #1065 Fixed #1277
This commit is contained in:
@@ -0,0 +1,33 @@
|
||||
using System;
|
||||
|
||||
namespace PepperDash.Essentials.Core
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a ConfigSnippetAttribute
|
||||
/// </summary>
|
||||
[AttributeUsage(AttributeTargets.Class, Inherited = true, AllowMultiple = true)]
|
||||
public class ConfigSnippetAttribute : Attribute
|
||||
{
|
||||
private string _ConfigSnippet;
|
||||
|
||||
/// <summary>
|
||||
/// Represents a configuration snippet for the device.
|
||||
/// </summary>
|
||||
/// <param name="configSnippet"></param>
|
||||
public ConfigSnippetAttribute(string configSnippet)
|
||||
{
|
||||
//Debug.LogMessage(LogEventLevel.Verbose, "Setting Config Snippet {0}", configSnippet);
|
||||
_ConfigSnippet = configSnippet;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the configuration snippet for the device.
|
||||
/// This snippet can be used in the DeviceConfig to instantiate the device.
|
||||
/// </summary>
|
||||
public string ConfigSnippet
|
||||
{
|
||||
get { return _ConfigSnippet; }
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
using System;
|
||||
|
||||
namespace PepperDash.Essentials.Core
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a description attribute for a device.
|
||||
/// </summary>
|
||||
[AttributeUsage(AttributeTargets.Class, Inherited = true, AllowMultiple = true)]
|
||||
public class DescriptionAttribute : Attribute
|
||||
{
|
||||
private string _Description;
|
||||
|
||||
/// <summary>
|
||||
/// Represents a description attribute for a device.
|
||||
/// </summary>
|
||||
/// <param name="description"></param>
|
||||
public DescriptionAttribute(string description)
|
||||
{
|
||||
//Debug.LogMessage(LogEventLevel.Verbose, "Setting Description: {0}", description);
|
||||
_Description = description;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the description for the device.
|
||||
/// </summary>
|
||||
public string Description
|
||||
{
|
||||
get { return _Description; }
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,26 +1,38 @@
|
||||
using Crestron.SimplSharp;
|
||||
using Crestron.SimplSharpPro;
|
||||
using PepperDash.Core;
|
||||
using Serilog.Events;
|
||||
using System;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text.RegularExpressions;
|
||||
using Crestron.SimplSharp;
|
||||
using Crestron.SimplSharpPro;
|
||||
using PepperDash.Core;
|
||||
using Serilog.Events;
|
||||
|
||||
|
||||
namespace PepperDash.Essentials.Core
|
||||
{
|
||||
/// <summary>
|
||||
/// Manages the devices in the system
|
||||
/// </summary>
|
||||
public static class DeviceManager
|
||||
{
|
||||
/// <summary>
|
||||
/// Raised when all devices have been activated
|
||||
/// </summary>
|
||||
public static event EventHandler<EventArgs> AllDevicesActivated;
|
||||
|
||||
/// <summary>
|
||||
/// Raised when all devices have been registered
|
||||
/// </summary>
|
||||
public static event EventHandler<EventArgs> AllDevicesRegistered;
|
||||
|
||||
/// <summary>
|
||||
/// Raised when all devices have been initialized
|
||||
/// </summary>
|
||||
public static event EventHandler<EventArgs> AllDevicesInitialized;
|
||||
|
||||
private static readonly CCriticalSection DeviceCriticalSection = new CCriticalSection();
|
||||
private static readonly CEvent AllowAddDevicesCEvent = new CEvent(false, true);
|
||||
|
||||
//public static List<Device> Devices { get { return _Devices; } }
|
||||
//static List<Device> _Devices = new List<Device>();
|
||||
private static readonly CEvent AllowAddDevicesCEvent = new CEvent(false, true);
|
||||
|
||||
private static readonly Dictionary<string, IKeyed> Devices = new Dictionary<string, IKeyed>(StringComparer.OrdinalIgnoreCase);
|
||||
|
||||
@@ -188,27 +200,6 @@ namespace PepperDash.Essentials.Core
|
||||
}
|
||||
}
|
||||
|
||||
//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);
|
||||
@@ -397,6 +388,25 @@ namespace PepperDash.Essentials.Core
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// GetDeviceForKey method
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
public static T GetDeviceForKey<T>(string key)
|
||||
{
|
||||
//return _Devices.FirstOrDefault(d => d.Key.Equals(key, StringComparison.OrdinalIgnoreCase));
|
||||
if (key == null || !Devices.ContainsKey(key))
|
||||
return default;
|
||||
|
||||
if (!(Devices[key] is T))
|
||||
{
|
||||
Debug.LogMessage(LogEventLevel.Error, "Device with key '{0}' is not of type '{1}'", key, typeof(T).Name);
|
||||
return default;
|
||||
}
|
||||
|
||||
return (T)Devices[key];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Console handler that simulates com port data receive
|
||||
/// </summary>
|
||||
|
||||
@@ -1,12 +1,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using Crestron.SimplSharp;
|
||||
using System.Reflection;
|
||||
|
||||
using System.Threading.Tasks;
|
||||
using PepperDash.Core;
|
||||
using PepperDash.Essentials.Core.Config;
|
||||
using Serilog.Events;
|
||||
|
||||
namespace PepperDash.Essentials.Core
|
||||
@@ -17,9 +11,16 @@ namespace PepperDash.Essentials.Core
|
||||
[Description("The base Essentials Device Class")]
|
||||
public abstract class EssentialsDevice : Device
|
||||
{
|
||||
/// <summary>
|
||||
/// Event raised when the device is initialized.
|
||||
/// </summary>
|
||||
public event EventHandler Initialized;
|
||||
|
||||
private bool _isInitialized;
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether the device is initialized.
|
||||
/// </summary>
|
||||
public bool IsInitialized
|
||||
{
|
||||
get { return _isInitialized; }
|
||||
@@ -36,12 +37,21 @@ namespace PepperDash.Essentials.Core
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the EssentialsDevice class.
|
||||
/// </summary>
|
||||
/// <param name="key">The unique identifier for the device.</param>
|
||||
protected EssentialsDevice(string key)
|
||||
: base(key)
|
||||
{
|
||||
SubscribeToActivateComplete();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the EssentialsDevice class.
|
||||
/// </summary>
|
||||
/// <param name="key">The unique identifier for the device.</param>
|
||||
/// <param name="name">The name of the device.</param>
|
||||
protected EssentialsDevice(string key, string name)
|
||||
: base(key, name)
|
||||
{
|
||||
@@ -55,7 +65,7 @@ namespace PepperDash.Essentials.Core
|
||||
|
||||
private void DeviceManagerOnAllDevicesActivated(object sender, EventArgs eventArgs)
|
||||
{
|
||||
CrestronInvoke.BeginInvoke((o) =>
|
||||
Task.Run(() =>
|
||||
{
|
||||
try
|
||||
{
|
||||
@@ -90,138 +100,4 @@ namespace PepperDash.Essentials.Core
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
[AttributeUsage(AttributeTargets.Class, Inherited = true, AllowMultiple = true)]
|
||||
public class DescriptionAttribute : Attribute
|
||||
{
|
||||
private string _Description;
|
||||
|
||||
public DescriptionAttribute(string description)
|
||||
{
|
||||
//Debug.LogMessage(LogEventLevel.Verbose, "Setting Description: {0}", description);
|
||||
_Description = description;
|
||||
}
|
||||
|
||||
public string Description
|
||||
{
|
||||
get { return _Description; }
|
||||
}
|
||||
}
|
||||
|
||||
[AttributeUsage(AttributeTargets.Class, Inherited = true, AllowMultiple = true)]
|
||||
/// <summary>
|
||||
/// Represents a ConfigSnippetAttribute
|
||||
/// </summary>
|
||||
public class ConfigSnippetAttribute : Attribute
|
||||
{
|
||||
private string _ConfigSnippet;
|
||||
|
||||
public ConfigSnippetAttribute(string configSnippet)
|
||||
{
|
||||
//Debug.LogMessage(LogEventLevel.Verbose, "Setting Config Snippet {0}", configSnippet);
|
||||
_ConfigSnippet = configSnippet;
|
||||
}
|
||||
|
||||
public string ConfigSnippet
|
||||
{
|
||||
get { return _ConfigSnippet; }
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Devices the basic needs for a Device Factory
|
||||
/// </summary>
|
||||
public abstract class EssentialsDeviceFactory<T> : IDeviceFactory where T:EssentialsDevice
|
||||
{
|
||||
#region IDeviceFactory Members
|
||||
|
||||
/// <summary>
|
||||
/// A list of strings that can be used in the type property of a DeviceConfig object to build an instance of this device
|
||||
/// </summary>
|
||||
public List<string> TypeNames { get; protected set; }
|
||||
|
||||
/// <summary>
|
||||
/// LoadTypeFactories method
|
||||
/// </summary>
|
||||
public void LoadTypeFactories()
|
||||
{
|
||||
foreach (var typeName in TypeNames)
|
||||
{
|
||||
//Debug.LogMessage(LogEventLevel.Verbose, "Getting Description Attribute from class: '{0}'", typeof(T).FullName);
|
||||
var descriptionAttribute = typeof(T).GetCustomAttributes(typeof(DescriptionAttribute), true) as DescriptionAttribute[];
|
||||
string description = descriptionAttribute[0].Description;
|
||||
var snippetAttribute = typeof(T).GetCustomAttributes(typeof(ConfigSnippetAttribute), true) as ConfigSnippetAttribute[];
|
||||
DeviceFactory.AddFactoryForType(typeName.ToLower(), description, typeof(T), BuildDevice);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The method that will build the device
|
||||
/// </summary>
|
||||
/// <param name="dc">The device config</param>
|
||||
/// <returns>An instance of the device</returns>
|
||||
public abstract EssentialsDevice BuildDevice(DeviceConfig dc);
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
||||
public abstract class ProcessorExtensionDeviceFactory<T> : IProcessorExtensionDeviceFactory where T: EssentialsDevice
|
||||
{
|
||||
#region IProcessorExtensionDeviceFactory Members
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the TypeNames
|
||||
/// </summary>
|
||||
public List<string> TypeNames { get; protected set; }
|
||||
|
||||
/// <summary>
|
||||
/// LoadFactories method
|
||||
/// </summary>
|
||||
public void LoadFactories()
|
||||
{
|
||||
foreach (var typeName in TypeNames)
|
||||
{
|
||||
//Debug.LogMessage(LogEventLevel.Verbose, "Getting Description Attribute from class: '{0}'", typeof(T).FullName);
|
||||
var descriptionAttribute = typeof(T).GetCustomAttributes(typeof(DescriptionAttribute), true) as DescriptionAttribute[];
|
||||
string description = descriptionAttribute[0].Description;
|
||||
var snippetAttribute = typeof(T).GetCustomAttributes(typeof(ConfigSnippetAttribute), true) as ConfigSnippetAttribute[];
|
||||
ProcessorExtensionDeviceFactory.AddFactoryForType(typeName.ToLower(), description, typeof(T), BuildDevice);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The method that will build the device
|
||||
/// </summary>
|
||||
/// <param name="dc">The device config</param>
|
||||
/// <returns>An instance of the device</returns>
|
||||
public abstract EssentialsDevice BuildDevice(DeviceConfig dc);
|
||||
|
||||
#endregion
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Devices the basic needs for a Device Factory
|
||||
/// </summary>
|
||||
public abstract class EssentialsPluginDeviceFactory<T> : EssentialsDeviceFactory<T>, IPluginDeviceFactory where T : EssentialsDevice
|
||||
{
|
||||
/// <summary>
|
||||
/// Specifies the minimum version of Essentials required for a plugin to run. Must use the format Major.Minor.Build (ex. "1.4.33")
|
||||
/// </summary>
|
||||
public string MinimumEssentialsFrameworkVersion { get; protected set; }
|
||||
}
|
||||
|
||||
public abstract class EssentialsPluginDevelopmentDeviceFactory<T> : EssentialsDeviceFactory<T>, IPluginDevelopmentDeviceFactory where T : EssentialsDevice
|
||||
{
|
||||
/// <summary>
|
||||
/// Specifies the minimum version of Essentials required for a plugin to run. Must use the format Major.Minor.Build (ex. "1.4.33")
|
||||
/// </summary>
|
||||
public string MinimumEssentialsFrameworkVersion { get; protected set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the DevelopmentEssentialsFrameworkVersions
|
||||
/// </summary>
|
||||
public List<string> DevelopmentEssentialsFrameworkVersions { get; protected set; }
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using PepperDash.Essentials.Core.Config;
|
||||
|
||||
namespace PepperDash.Essentials.Core
|
||||
{
|
||||
/// <summary>
|
||||
/// Provides the basic needs for a Device Factory
|
||||
/// </summary>
|
||||
public abstract class EssentialsDeviceFactory<T> : IDeviceFactory where T : EssentialsDevice
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public Type FactoryType => typeof(T);
|
||||
|
||||
/// <summary>
|
||||
/// A list of strings that can be used in the type property of a DeviceConfig object to build an instance of this device
|
||||
/// </summary>
|
||||
public List<string> TypeNames { get; protected set; }
|
||||
|
||||
/// <summary>
|
||||
/// The method that will build the device
|
||||
/// </summary>
|
||||
/// <param name="dc">The device config</param>
|
||||
/// <returns>An instance of the device</returns>
|
||||
public abstract EssentialsDevice BuildDevice(DeviceConfig dc);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace PepperDash.Essentials.Core
|
||||
{
|
||||
public abstract class EssentialsPluginDevelopmentDeviceFactory<T> : EssentialsDeviceFactory<T>, IPluginDevelopmentDeviceFactory where T : EssentialsDevice
|
||||
{
|
||||
/// <summary>
|
||||
/// Specifies the minimum version of Essentials required for a plugin to run. Must use the format Major.Minor.Build (ex. "1.4.33")
|
||||
/// </summary>
|
||||
public string MinimumEssentialsFrameworkVersion { get; protected set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the DevelopmentEssentialsFrameworkVersions
|
||||
/// </summary>
|
||||
public List<string> DevelopmentEssentialsFrameworkVersions { get; protected set; }
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
namespace PepperDash.Essentials.Core
|
||||
{
|
||||
/// <summary>
|
||||
/// Devices the basic needs for a Device Factory
|
||||
/// </summary>
|
||||
public abstract class EssentialsPluginDeviceFactory<T> : EssentialsDeviceFactory<T>, IPluginDeviceFactory where T : EssentialsDevice
|
||||
{
|
||||
/// <summary>
|
||||
/// Specifies the minimum version of Essentials required for a plugin to run. Must use the format Major.Minor.Build (ex. "1.4.33")
|
||||
/// </summary>
|
||||
public string MinimumEssentialsFrameworkVersion { get; protected set; }
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
using System.Collections.Generic;
|
||||
using PepperDash.Essentials.Core.Config;
|
||||
|
||||
namespace PepperDash.Essentials.Core
|
||||
{
|
||||
public abstract class ProcessorExtensionDeviceFactory<T> : IProcessorExtensionDeviceFactory where T : EssentialsDevice
|
||||
{
|
||||
#region IProcessorExtensionDeviceFactory Members
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the TypeNames
|
||||
/// </summary>
|
||||
public List<string> TypeNames { get; protected set; }
|
||||
|
||||
/// <summary>
|
||||
/// LoadFactories method
|
||||
/// </summary>
|
||||
public void LoadFactories()
|
||||
{
|
||||
foreach (var typeName in TypeNames)
|
||||
{
|
||||
//Debug.LogMessage(LogEventLevel.Verbose, "Getting Description Attribute from class: '{0}'", typeof(T).FullName);
|
||||
var descriptionAttribute = typeof(T).GetCustomAttributes(typeof(DescriptionAttribute), true) as DescriptionAttribute[];
|
||||
string description = descriptionAttribute[0].Description;
|
||||
var snippetAttribute = typeof(T).GetCustomAttributes(typeof(ConfigSnippetAttribute), true) as ConfigSnippetAttribute[];
|
||||
ProcessorExtensionDeviceFactory.AddFactoryForType(typeName.ToLower(), description, typeof(T), BuildDevice);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The method that will build the device
|
||||
/// </summary>
|
||||
/// <param name="dc">The device config</param>
|
||||
/// <returns>An instance of the device</returns>
|
||||
public abstract EssentialsDevice BuildDevice(DeviceConfig dc);
|
||||
|
||||
#endregion
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,76 +1,102 @@
|
||||
|
||||
|
||||
using Crestron.SimplSharp;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using Crestron.SimplSharp;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using PepperDash.Core;
|
||||
using PepperDash.Essentials.Core.Config;
|
||||
using Serilog.Events;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace PepperDash.Essentials.Core
|
||||
{
|
||||
/// <summary>
|
||||
/// Wrapper class for device factory information
|
||||
/// </summary>
|
||||
public class DeviceFactoryWrapper
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets the device type
|
||||
/// </summary>
|
||||
public Type Type { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the Description
|
||||
/// </summary>
|
||||
public string Description { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the factory method for creating devices
|
||||
/// </summary>
|
||||
public Func<DeviceConfig, IKeyed> FactoryMethod { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the DeviceFactoryWrapper class
|
||||
/// </summary>
|
||||
public DeviceFactoryWrapper()
|
||||
{
|
||||
Type = null;
|
||||
Description = "Not Available";
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Represents a DeviceFactory
|
||||
/// 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 DeviceFactory class and loads all device type factories
|
||||
/// 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 assy = Assembly.GetExecutingAssembly();
|
||||
PluginLoader.SetEssentialsAssembly(assy.GetName().Name, assy);
|
||||
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 assembly in programAssemblies)
|
||||
{
|
||||
try
|
||||
{
|
||||
Assembly.LoadFrom(assembly);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Debug.LogError("Unable to load assembly: {assemblyName} - {message}", assembly, e.Message);
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
factory.LoadTypeFactories();
|
||||
LoadDeviceFactories(factory);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Debug.LogMessage(LogEventLevel.Information, "Unable to load type: '{1}' DeviceFactory: {0}", e, type.Name);
|
||||
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)
|
||||
{
|
||||
//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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -78,46 +104,59 @@ namespace PepperDash.Essentials.Core
|
||||
/// 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 =
|
||||
private static readonly Dictionary<string, DeviceFactoryWrapper> FactoryMethods =
|
||||
new Dictionary<string, DeviceFactoryWrapper>(StringComparer.OrdinalIgnoreCase);
|
||||
|
||||
/// <summary>
|
||||
/// Adds a plugin factory method
|
||||
/// Registers a factory method for creating instances of a specific type.
|
||||
/// </summary>
|
||||
/// <param name="dc"></param>
|
||||
/// <returns></returns>
|
||||
/// <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)
|
||||
{
|
||||
//Debug.LogMessage(LogEventLevel.Debug, "Adding factory method for type '{0}'", typeName);
|
||||
DeviceFactory.FactoryMethods.Add(typeName, new DeviceFactoryWrapper() { FactoryMethod = method});
|
||||
FactoryMethods.Add(typeName, new DeviceFactoryWrapper() { FactoryMethod = method });
|
||||
}
|
||||
|
||||
/// <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)
|
||||
{
|
||||
//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);
|
||||
Debug.LogInformation("Unable to add type: '{typeName}'. Already exists in DeviceFactory", typeName);
|
||||
return;
|
||||
}
|
||||
|
||||
var wrapper = new DeviceFactoryWrapper() { Type = Type, Description = description, FactoryMethod = method };
|
||||
DeviceFactory.FactoryMethods.Add(typeName, wrapper);
|
||||
|
||||
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")
|
||||
if (prop.Name.Equals("secret", StringComparison.CurrentCultureIgnoreCase))
|
||||
{
|
||||
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;
|
||||
|
||||
if (!(prop.Value is JObject recurseProp)) return;
|
||||
|
||||
CheckForSecrets(recurseProp.Properties());
|
||||
}
|
||||
}
|
||||
@@ -131,62 +170,66 @@ namespace PepperDash.Essentials.Core
|
||||
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;
|
||||
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>
|
||||
/// <summary>
|
||||
/// GetDevice method
|
||||
/// 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
|
||||
{
|
||||
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)
|
||||
if (properties is JObject jObject)
|
||||
{
|
||||
var jProp = jObject.Properties();
|
||||
|
||||
CheckForSecrets(jProp);
|
||||
}
|
||||
|
||||
Debug.LogMessage(LogEventLevel.Verbose, "typeName = {0}", typeName);
|
||||
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 !FactoryMethods.ContainsKey(typeName) ? null : FactoryMethods[typeName].FactoryMethod(localDc);
|
||||
return wrapper.FactoryMethod(localDc);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Debug.LogMessage(ex, "Exception occurred while creating device {0}: {1}", null, dc.Key, ex.Message);
|
||||
Debug.LogError(ex, "Exception occurred while creating device {0}: {1}", null, dc.Key, ex.Message);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Prints the type names and associated metadata from the FactoryMethods collection.
|
||||
/// </summary>
|
||||
/// <param name="filter"></param>
|
||||
/// <summary>
|
||||
/// GetDeviceFactoryTypes method
|
||||
/// 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)
|
||||
@@ -213,10 +256,12 @@ namespace PepperDash.Essentials.Core
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the device factory dictionary
|
||||
/// Retrieves a dictionary of device factory wrappers, optionally filtered by a specified string.
|
||||
/// </summary>
|
||||
/// <param name="filter"></param>
|
||||
/// <returns></returns>
|
||||
/// <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)
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
|
||||
|
||||
using System;
|
||||
using PepperDash.Core;
|
||||
using PepperDash.Essentials.Core.Config;
|
||||
|
||||
namespace PepperDash.Essentials.Core
|
||||
{
|
||||
/// <summary>
|
||||
/// Wraps a device factory, providing metadata and a factory method for creating devices.
|
||||
/// </summary>
|
||||
public class DeviceFactoryWrapper
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets the type associated with the current instance.
|
||||
/// </summary>
|
||||
public Type Type { get; set; }
|
||||
|
||||
/// <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";
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,8 @@
|
||||
namespace PepperDash.Essentials.Core
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using PepperDash.Essentials.Core.Config;
|
||||
|
||||
namespace PepperDash.Essentials.Core
|
||||
{
|
||||
/// <summary>
|
||||
/// Defines the contract for IDeviceFactory
|
||||
@@ -6,8 +10,21 @@
|
||||
public interface IDeviceFactory
|
||||
{
|
||||
/// <summary>
|
||||
/// Loads all the types to the DeviceFactory
|
||||
/// Gets the type of the factory associated with the current instance.
|
||||
/// </summary>
|
||||
void LoadTypeFactories();
|
||||
Type FactoryType { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets a list of type names associated with the current plugin.
|
||||
/// </summary>
|
||||
List<string> TypeNames { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Builds and returns an <see cref="EssentialsDevice"/> instance based on the provided configuration.
|
||||
/// </summary>
|
||||
/// <param name="deviceConfig">The configuration settings used to initialize the device. This parameter cannot be null.</param>
|
||||
/// <returns>An <see cref="EssentialsDevice"/> instance configured according to the specified <paramref
|
||||
/// name="deviceConfig"/>.</returns>
|
||||
EssentialsDevice BuildDevice(DeviceConfig deviceConfig);
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using PepperDash.Core;
|
||||
|
||||
|
||||
namespace PepperDash.Essentials.Core
|
||||
@@ -16,8 +16,16 @@ namespace PepperDash.Essentials.Core
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Defines a class that is capable of loading custom plugin device types for development purposes
|
||||
/// </summary>
|
||||
[Obsolete("This interface is obsolete and will be removed in a future version." +
|
||||
" Use IPluginDeviceFactory instead and check Global.IsRunningDevelopmentVersion to determine if the Essentials framework is in development mode.")]
|
||||
public interface IPluginDevelopmentDeviceFactory : IPluginDeviceFactory
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets a list of all the development versions of the Essentials framework that are supported by this factory.
|
||||
/// </summary>
|
||||
List<string> DevelopmentEssentialsFrameworkVersions { get; }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,15 +1,13 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using Crestron.SimplSharp;
|
||||
// using Crestron.SimplSharp.CrestronIO;
|
||||
using System.Reflection;
|
||||
|
||||
using Crestron.SimplSharp;
|
||||
using Newtonsoft.Json;
|
||||
using PepperDash.Core;
|
||||
using PepperDash.Essentials.Core;
|
||||
using Serilog.Events;
|
||||
using Newtonsoft.Json;
|
||||
using System.IO;
|
||||
|
||||
namespace PepperDash.Essentials
|
||||
{
|
||||
@@ -28,10 +26,19 @@ namespace PepperDash.Essentials
|
||||
/// </summary>
|
||||
static List<LoadedAssembly> LoadedPluginFolderAssemblies;
|
||||
|
||||
/// <summary>
|
||||
/// The assembly for the Essentials Framework
|
||||
/// </summary>
|
||||
public static LoadedAssembly EssentialsAssembly { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// The assembly for the PepperDash Core
|
||||
/// </summary>
|
||||
public static LoadedAssembly PepperDashCoreAssembly { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// The list of assemblies loaded from the Essentials plugins folder
|
||||
/// </summary>
|
||||
public static List<LoadedAssembly> EssentialsPluginAssemblies { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
@@ -131,7 +138,7 @@ namespace PepperDash.Essentials
|
||||
/// <summary>
|
||||
/// Loads an assembly via Reflection and adds it to the list of loaded assemblies
|
||||
/// </summary>
|
||||
/// <param name="fileName"></param>
|
||||
/// <param name="filePath"></param>
|
||||
static LoadedAssembly LoadAssembly(string filePath)
|
||||
{
|
||||
try
|
||||
@@ -153,7 +160,8 @@ namespace PepperDash.Essentials
|
||||
}
|
||||
|
||||
return null;
|
||||
} catch(Exception ex)
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Debug.LogMessage(ex, "Error loading assembly from {path}", null, filePath);
|
||||
return null;
|
||||
@@ -212,6 +220,20 @@ namespace PepperDash.Essentials
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Associates the specified assembly with the given name in the loaded assemblies collection.
|
||||
/// </summary>
|
||||
/// <remarks>If an assembly with the specified name already exists in the loaded assemblies collection,
|
||||
/// this method updates its associated assembly. If no matching name is found, the method does nothing.</remarks>
|
||||
/// <param name="name">The name used to identify the assembly. This value is case-sensitive and must not be null or empty.</param>
|
||||
/// <param name="assembly">The assembly to associate with the specified name. This value must not be null.</param>
|
||||
public static void AddLoadedAssembly(string name, Assembly assembly)
|
||||
{
|
||||
var loadedAssembly = LoadedAssemblies.FirstOrDefault(la => la.Name.Equals(name));
|
||||
|
||||
loadedAssembly?.SetAssembly(assembly);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Used by console command to report the currently loaded assemblies and versions
|
||||
/// </summary>
|
||||
@@ -454,37 +476,61 @@ namespace PepperDash.Essentials
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Loads a
|
||||
/// Loads a custom plugin and performs a dependency check to ensure compatibility with the required Essentials
|
||||
/// framework version.
|
||||
/// </summary>
|
||||
/// <param name="plugin"></param>
|
||||
/// <param name="loadedAssembly"></param>
|
||||
static void LoadCustomPlugin(IPluginDeviceFactory plugin, LoadedAssembly loadedAssembly)
|
||||
/// <remarks>This method verifies that the plugin meets the minimum required Essentials framework version
|
||||
/// before loading it. If the plugin fails the dependency check, it is skipped, and a log message is generated. If
|
||||
/// the plugin passes the check, it is loaded, and its type factories are initialized.</remarks>
|
||||
/// <param name="pluginDeviceFactory">The plugin to be loaded, implementing the <see cref="IPluginDeviceFactory"/> interface. If the plugin also
|
||||
/// implements <see cref="IPluginDevelopmentDeviceFactory"/>, additional checks for development versions are
|
||||
/// performed.</param>
|
||||
/// <param name="loadedAssembly">The assembly associated with the plugin being loaded. This is used for logging and tracking purposes.</param>
|
||||
static void LoadCustomPlugin(IPluginDeviceFactory pluginDeviceFactory, LoadedAssembly loadedAssembly)
|
||||
{
|
||||
var developmentPlugin = plugin as IPluginDevelopmentDeviceFactory;
|
||||
|
||||
var passed = developmentPlugin != null ? Global.IsRunningDevelopmentVersion
|
||||
var passed = pluginDeviceFactory is IPluginDevelopmentDeviceFactory developmentPlugin ? Global.IsRunningDevelopmentVersion
|
||||
(developmentPlugin.DevelopmentEssentialsFrameworkVersions, developmentPlugin.MinimumEssentialsFrameworkVersion)
|
||||
: Global.IsRunningMinimumVersionOrHigher(plugin.MinimumEssentialsFrameworkVersion);
|
||||
: Global.IsRunningMinimumVersionOrHigher(pluginDeviceFactory.MinimumEssentialsFrameworkVersion);
|
||||
|
||||
if (!passed)
|
||||
{
|
||||
Debug.LogMessage(LogEventLevel.Information,
|
||||
"\r\n********************\r\n\tPlugin indicates minimum Essentials version {0}. Dependency check failed. Skipping Plugin {1}\r\n********************",
|
||||
plugin.MinimumEssentialsFrameworkVersion, loadedAssembly.Name);
|
||||
pluginDeviceFactory.MinimumEssentialsFrameworkVersion, loadedAssembly.Name);
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.LogMessage(LogEventLevel.Information, "Passed plugin passed dependency check (required version {0})", plugin.MinimumEssentialsFrameworkVersion);
|
||||
Debug.LogMessage(LogEventLevel.Information, "Passed plugin passed dependency check (required version {0})", pluginDeviceFactory.MinimumEssentialsFrameworkVersion);
|
||||
}
|
||||
|
||||
Debug.LogMessage(LogEventLevel.Information, "Loading plugin: {0}", loadedAssembly.Name);
|
||||
plugin.LoadTypeFactories();
|
||||
Debug.LogMessage(LogEventLevel.Information, "Loading plugin factory: {0}", loadedAssembly.Name);
|
||||
|
||||
LoadDeviceFactories(pluginDeviceFactory);
|
||||
|
||||
if (!EssentialsPluginAssemblies.Contains(loadedAssembly))
|
||||
EssentialsPluginAssemblies.Add(loadedAssembly);
|
||||
}
|
||||
|
||||
/// <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(IPluginDeviceFactory deviceFactory)
|
||||
{
|
||||
foreach (var typeName in deviceFactory.TypeNames)
|
||||
{
|
||||
//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[];
|
||||
DeviceFactory.AddFactoryForType(typeName.ToLower(), description, deviceFactory.FactoryType, deviceFactory.BuildDevice);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Loads a a custom plugin via the legacy method
|
||||
/// </summary>
|
||||
@@ -567,13 +613,30 @@ namespace PepperDash.Essentials
|
||||
/// </summary>
|
||||
public class LoadedAssembly
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the name of the assembly
|
||||
/// </summary>
|
||||
[JsonProperty("name")]
|
||||
public string Name { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the version of the assembly
|
||||
/// </summary>
|
||||
[JsonProperty("version")]
|
||||
public string Version { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the assembly
|
||||
/// </summary>
|
||||
[JsonIgnore]
|
||||
public Assembly Assembly { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the LoadedAssembly class
|
||||
/// </summary>
|
||||
/// <param name="name">The name of the assembly</param>
|
||||
/// <param name="version">The version of the assembly</param>
|
||||
/// <param name="assembly">The assembly</param>
|
||||
public LoadedAssembly(string name, string version, Assembly assembly)
|
||||
{
|
||||
Name = name;
|
||||
|
||||
@@ -29,7 +29,7 @@ namespace PepperDash.Essentials.Devices.Common
|
||||
try
|
||||
{
|
||||
var factory = (IDeviceFactory)Activator.CreateInstance(type);
|
||||
factory.LoadTypeFactories();
|
||||
LoadDeviceFactories(factory);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
@@ -38,5 +38,24 @@ namespace PepperDash.Essentials.Devices.Common
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <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)
|
||||
{
|
||||
//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[];
|
||||
Core.DeviceFactory.AddFactoryForType(typeName.ToLower(), description, deviceFactory.FactoryType, deviceFactory.BuildDevice);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,8 +1,8 @@
|
||||
using PepperDash.Core;
|
||||
using PepperDash.Essentials.Core;
|
||||
using System;
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using PepperDash.Core;
|
||||
using PepperDash.Essentials.Core;
|
||||
|
||||
namespace PepperDash.Essentials
|
||||
{
|
||||
@@ -30,7 +30,7 @@ namespace PepperDash.Essentials
|
||||
{
|
||||
var factory = (IDeviceFactory)Activator.CreateInstance(type);
|
||||
|
||||
factory.LoadTypeFactories();
|
||||
LoadDeviceFactories(factory);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
@@ -38,5 +38,24 @@ namespace PepperDash.Essentials
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <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)
|
||||
{
|
||||
//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[];
|
||||
Core.DeviceFactory.AddFactoryForType(typeName.ToLower(), description, deviceFactory.FactoryType, deviceFactory.BuildDevice);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using Crestron.SimplSharp;
|
||||
using Crestron.SimplSharp.CrestronIO;
|
||||
using System.Reflection;
|
||||
using Crestron.SimplSharpPro;
|
||||
using Crestron.SimplSharpPro.CrestronThread;
|
||||
using Crestron.SimplSharpPro.Diagnostics;
|
||||
@@ -9,12 +11,9 @@ using PepperDash.Core;
|
||||
using PepperDash.Essentials.Core;
|
||||
using PepperDash.Essentials.Core.Bridges;
|
||||
using PepperDash.Essentials.Core.Config;
|
||||
using PepperDash.Essentials.Core.DeviceTypeInterfaces;
|
||||
using PepperDash.Essentials.Core.Web;
|
||||
using System;
|
||||
using System.Linq;
|
||||
using Serilog.Events;
|
||||
using PepperDash.Essentials.Core.Routing;
|
||||
using PepperDash.Essentials.Core.Web;
|
||||
using Serilog.Events;
|
||||
|
||||
namespace PepperDash.Essentials
|
||||
{
|
||||
@@ -46,22 +45,22 @@ namespace PepperDash.Essentials
|
||||
// AppDomain.CurrentDomain.AssemblyResolve += CurrentDomainOnAssemblyResolve;
|
||||
}
|
||||
|
||||
private System.Reflection.Assembly CurrentDomainOnAssemblyResolve(object sender, ResolveEventArgs args)
|
||||
private Assembly CurrentDomainOnAssemblyResolve(object sender, ResolveEventArgs args)
|
||||
{
|
||||
var assemblyName = new System.Reflection.AssemblyName(args.Name).Name;
|
||||
var assemblyName = new AssemblyName(args.Name).Name;
|
||||
if (assemblyName == "PepperDash_Core")
|
||||
{
|
||||
return System.Reflection.Assembly.LoadFrom("PepperDashCore.dll");
|
||||
return Assembly.LoadFrom("PepperDashCore.dll");
|
||||
}
|
||||
|
||||
if (assemblyName == "PepperDash_Essentials_Core")
|
||||
{
|
||||
return System.Reflection.Assembly.LoadFrom("PepperDash.Essentials.Core.dll");
|
||||
return Assembly.LoadFrom("PepperDash.Essentials.Core.dll");
|
||||
}
|
||||
|
||||
if (assemblyName == "Essentials Devices Common")
|
||||
{
|
||||
return System.Reflection.Assembly.LoadFrom("PepperDash.Essentials.Devices.Common.dll");
|
||||
return Assembly.LoadFrom("PepperDash.Essentials.Devices.Common.dll");
|
||||
}
|
||||
|
||||
return null;
|
||||
@@ -99,7 +98,7 @@ namespace PepperDash.Essentials
|
||||
|
||||
private void StartSystem(object preventInitialization)
|
||||
{
|
||||
Debug.SetErrorLogMinimumDebugLevel(Serilog.Events.LogEventLevel.Verbose);
|
||||
Debug.SetErrorLogMinimumDebugLevel(LogEventLevel.Verbose);
|
||||
|
||||
DeterminePlatform();
|
||||
|
||||
@@ -262,11 +261,11 @@ namespace PepperDash.Essentials
|
||||
PluginLoader.AddProgramAssemblies();
|
||||
|
||||
_ = new Core.DeviceFactory();
|
||||
_ = new Devices.Common.DeviceFactory();
|
||||
_ = new DeviceFactory();
|
||||
// _ = new Devices.Common.DeviceFactory();
|
||||
// _ = new DeviceFactory();
|
||||
|
||||
_ = new ProcessorExtensionDeviceFactory();
|
||||
_ = new MobileControlFactory();
|
||||
// _ = new ProcessorExtensionDeviceFactory();
|
||||
// _ = new MobileControlFactory();
|
||||
|
||||
Debug.LogMessage(LogEventLevel.Information, "Starting Essentials load from configuration");
|
||||
|
||||
@@ -414,8 +413,8 @@ namespace PepperDash.Essentials
|
||||
{
|
||||
var prompt = Global.ControlSystem.ControllerPrompt;
|
||||
|
||||
var typeMatch = String.Equals(devConf.Type, prompt, StringComparison.OrdinalIgnoreCase) ||
|
||||
String.Equals(devConf.Type, prompt.Replace("-", ""), StringComparison.OrdinalIgnoreCase);
|
||||
var typeMatch = string.Equals(devConf.Type, prompt, StringComparison.OrdinalIgnoreCase) ||
|
||||
string.Equals(devConf.Type, prompt.Replace("-", ""), StringComparison.OrdinalIgnoreCase);
|
||||
|
||||
if (!typeMatch)
|
||||
Debug.LogMessage(LogEventLevel.Information,
|
||||
@@ -495,7 +494,8 @@ namespace PepperDash.Essentials
|
||||
}
|
||||
|
||||
DeviceManager.AddDevice(room);
|
||||
} catch (Exception ex)
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Debug.LogMessage(ex, "Exception loading room {roomKey}:{roomType}", null, roomConfig.Key, roomConfig.Type);
|
||||
continue;
|
||||
|
||||
@@ -3,11 +3,10 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using Crestron.SimplSharp;
|
||||
using Crestron.SimplSharp.CrestronIO;
|
||||
using Crestron.SimplSharpPro;
|
||||
using System.Reflection;
|
||||
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using PepperDash.Core;
|
||||
@@ -39,7 +38,7 @@ namespace PepperDash.Essentials
|
||||
try
|
||||
{
|
||||
var factory = (IDeviceFactory)Activator.CreateInstance(type);
|
||||
factory.LoadTypeFactories();
|
||||
LoadDeviceFactories(factory);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
@@ -48,5 +47,24 @@ namespace PepperDash.Essentials
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <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)
|
||||
{
|
||||
//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[];
|
||||
Core.DeviceFactory.AddFactoryForType(typeName.ToLower(), description, deviceFactory.FactoryType, deviceFactory.BuildDevice);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user