mirror of
https://github.com/PepperDash/Essentials.git
synced 2026-02-12 19:24:53 +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:
@@ -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>
|
||||
@@ -402,7 +424,7 @@ namespace PepperDash.Essentials
|
||||
try
|
||||
{
|
||||
var assy = loadedAssembly.Assembly;
|
||||
Type[] types = {};
|
||||
Type[] types = { };
|
||||
try
|
||||
{
|
||||
types = assy.GetTypes();
|
||||
@@ -419,8 +441,8 @@ namespace PepperDash.Essentials
|
||||
foreach (var type in types)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (typeof (IPluginDeviceFactory).IsAssignableFrom(type) && !type.IsAbstract)
|
||||
{
|
||||
if (typeof(IPluginDeviceFactory).IsAssignableFrom(type) && !type.IsAbstract)
|
||||
{
|
||||
var plugin =
|
||||
(IPluginDeviceFactory)Activator.CreateInstance(type);
|
||||
@@ -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
|
||||
(developmentPlugin.DevelopmentEssentialsFrameworkVersions, developmentPlugin.MinimumEssentialsFrameworkVersion)
|
||||
: Global.IsRunningMinimumVersionOrHigher(plugin.MinimumEssentialsFrameworkVersion);
|
||||
var passed = pluginDeviceFactory is IPluginDevelopmentDeviceFactory developmentPlugin ? Global.IsRunningDevelopmentVersion
|
||||
(developmentPlugin.DevelopmentEssentialsFrameworkVersions, developmentPlugin.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);
|
||||
|
||||
if(!EssentialsPluginAssemblies.Contains(loadedAssembly))
|
||||
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;
|
||||
|
||||
Reference in New Issue
Block a user