mirror of
https://github.com/PepperDash/Essentials.git
synced 2026-02-16 13:15:03 +00:00
docs: update XML docs
This commit is contained in:
@@ -1,5 +1,4 @@
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using PepperDash.Core;
|
|
||||||
|
|
||||||
|
|
||||||
namespace PepperDash.Essentials.Core
|
namespace PepperDash.Essentials.Core
|
||||||
@@ -16,8 +15,16 @@ namespace PepperDash.Essentials.Core
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Defines a factory for creating plugin development devices, including support for specific framework versions.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>This interface extends <see cref="IPluginDeviceFactory"/> to provide additional functionality
|
||||||
|
/// specific to plugin development environments.</remarks>
|
||||||
public interface IPluginDevelopmentDeviceFactory : IPluginDeviceFactory
|
public interface IPluginDevelopmentDeviceFactory : IPluginDeviceFactory
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Gets a list of Essentials versions that this device is compatible with.
|
||||||
|
/// </summary>
|
||||||
List<string> DevelopmentEssentialsFrameworkVersions { get; }
|
List<string> DevelopmentEssentialsFrameworkVersions { get; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
47
src/PepperDash.Essentials.Core/Plugins/IncompatiblePlugin.cs
Normal file
47
src/PepperDash.Essentials.Core/Plugins/IncompatiblePlugin.cs
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
using Newtonsoft.Json;
|
||||||
|
|
||||||
|
|
||||||
|
namespace PepperDash.Essentials;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Represents a plugin that is incompatible with the current system or configuration.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>This class provides details about an incompatible plugin, including its name, the reason for the
|
||||||
|
/// incompatibility, and the plugin that triggered the incompatibility. The triggering plugin can be updated dynamically
|
||||||
|
/// using the <see cref="UpdateTriggeringPlugin(string)"/> method.</remarks>
|
||||||
|
/// <param name="name"></param>
|
||||||
|
/// <param name="reason"></param>
|
||||||
|
/// <param name="triggeredBy"></param>
|
||||||
|
public class IncompatiblePlugin(string name, string reason, string triggeredBy = null)
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the name associated with the object.
|
||||||
|
/// </summary>
|
||||||
|
[JsonProperty("name")]
|
||||||
|
public string Name { get; private set; } = name;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the reason associated with the current operation or response.
|
||||||
|
/// </summary>
|
||||||
|
[JsonProperty("reason")]
|
||||||
|
public string Reason { get; private set; } = reason;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the identifier of the entity or process that triggered the current operation.
|
||||||
|
/// </summary>
|
||||||
|
[JsonProperty("triggeredBy")]
|
||||||
|
public string TriggeredBy { get; private set; } = triggeredBy ?? "Direct load";
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Updates the name of the plugin that triggered the current operation.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="triggeringPlugin">The name of the triggering plugin. Must not be null or empty. If the value is null or empty, the operation is
|
||||||
|
/// ignored.</param>
|
||||||
|
public void UpdateTriggeringPlugin(string triggeringPlugin)
|
||||||
|
{
|
||||||
|
if (!string.IsNullOrEmpty(triggeringPlugin))
|
||||||
|
{
|
||||||
|
TriggeredBy = triggeringPlugin;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
46
src/PepperDash.Essentials.Core/Plugins/LoadedAssembly.cs
Normal file
46
src/PepperDash.Essentials.Core/Plugins/LoadedAssembly.cs
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
using System.Reflection;
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
|
||||||
|
|
||||||
|
namespace PepperDash.Essentials;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Represents an assembly that has been loaded, including its name, version, and the associated <see
|
||||||
|
/// cref="System.Reflection.Assembly"/> instance.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>This class provides information about a loaded assembly, including its name and version as strings,
|
||||||
|
/// and the associated <see cref="System.Reflection.Assembly"/> object. The assembly instance can be updated using the
|
||||||
|
/// <see cref="SetAssembly(Assembly)"/> method.</remarks>
|
||||||
|
/// <param name="name"></param>
|
||||||
|
/// <param name="version"></param>
|
||||||
|
/// <param name="assembly"></param>
|
||||||
|
public class LoadedAssembly(string name, string version, Assembly assembly)
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the name associated with the object.
|
||||||
|
/// </summary>
|
||||||
|
[JsonProperty("name")]
|
||||||
|
public string Name { get; private set; } = name;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the version of the object as a string.
|
||||||
|
/// </summary>
|
||||||
|
[JsonProperty("version")]
|
||||||
|
public string Version { get; private set; } = version;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the assembly associated with the current instance.
|
||||||
|
/// </summary>
|
||||||
|
[JsonIgnore]
|
||||||
|
public Assembly Assembly { get; private set; } = assembly;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Sets the assembly associated with the current instance.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="assembly">The <see cref="System.Reflection.Assembly"/> to associate with the current instance. Cannot be <see
|
||||||
|
/// langword="null"/>.</param>
|
||||||
|
public void SetAssembly(Assembly assembly)
|
||||||
|
{
|
||||||
|
Assembly = assembly;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
using System;
|
||||||
|
|
||||||
|
|
||||||
|
namespace PepperDash.Essentials;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Indicates whether the assembly is compatible with .NET 8.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>This attribute is used to specify compatibility with .NET 8 for an assembly. By default, the
|
||||||
|
/// assembly is considered compatible unless explicitly marked otherwise.</remarks>
|
||||||
|
/// <param name="isCompatible">A boolean value indicating whether the assembly is compatible with .NET 8. The default value is <see
|
||||||
|
/// langword="true"/>.</param>
|
||||||
|
[AttributeUsage(AttributeTargets.Assembly)]
|
||||||
|
public class Net8CompatibleAttribute(bool isCompatible = true) : Attribute
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Gets a value indicating whether the current object is compatible with the required conditions.
|
||||||
|
/// </summary>
|
||||||
|
public bool IsCompatible { get; } = isCompatible;
|
||||||
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using Crestron.SimplSharp;
|
using Crestron.SimplSharp;
|
||||||
@@ -10,53 +10,78 @@ using System.Reflection.Metadata;
|
|||||||
using PepperDash.Core;
|
using PepperDash.Core;
|
||||||
using PepperDash.Essentials.Core;
|
using PepperDash.Essentials.Core;
|
||||||
using Serilog.Events;
|
using Serilog.Events;
|
||||||
using Newtonsoft.Json;
|
|
||||||
|
|
||||||
|
|
||||||
namespace PepperDash.Essentials
|
namespace PepperDash.Essentials;
|
||||||
{
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Deals with loading plugins at runtime
|
/// Provides functionality for loading and managing plugins and assemblies in the application.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
/// <remarks>The <see cref="PluginLoader"/> class is responsible for discovering, loading, and managing assemblies
|
||||||
|
/// and plugins, including handling compatibility checks for .NET 8. It supports loading assemblies from the program
|
||||||
|
/// directory, plugins folder, and .cplz archives. Additionally, it tracks incompatible plugins and provides reporting
|
||||||
|
/// capabilities for loaded assemblies and their versions.</remarks>
|
||||||
public static class PluginLoader
|
public static class PluginLoader
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The complete list of loaded assemblies. Includes Essentials Framework assemblies and plugins
|
/// Gets the list of assemblies that have been loaded into the application.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static List<LoadedAssembly> LoadedAssemblies { get; private set; }
|
public static List<LoadedAssembly> LoadedAssemblies { get; private set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The list of assemblies loaded from the plugins folder
|
/// Represents a collection of assemblies loaded from the plugin folder.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
static List<LoadedAssembly> LoadedPluginFolderAssemblies;
|
/// <remarks>This field is used to store assemblies that have been dynamically loaded from a designated
|
||||||
|
/// plugin folder. It is intended for internal use and should not be modified directly.</remarks>
|
||||||
|
private static readonly List<LoadedAssembly> LoadedPluginFolderAssemblies;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// List of plugins that were found to be incompatible with .NET 8
|
/// Gets the list of plugins that are incompatible with the current system or configuration.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
/// <remarks>This property provides information about plugins that are not supported or cannot function
|
||||||
|
/// correctly in the current environment. Use this list to identify and handle incompatible plugins appropriately in
|
||||||
|
/// your application logic.</remarks>
|
||||||
public static List<IncompatiblePlugin> IncompatiblePlugins { get; private set; }
|
public static List<IncompatiblePlugin> IncompatiblePlugins { get; private set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the loaded assembly that contains the core functionality of the application.
|
||||||
|
/// </summary>
|
||||||
public static LoadedAssembly EssentialsAssembly { get; private set; }
|
public static LoadedAssembly EssentialsAssembly { get; private set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the loaded assembly information for the PepperDash Core library.
|
||||||
|
/// </summary>
|
||||||
public static LoadedAssembly PepperDashCoreAssembly { get; private set; }
|
public static LoadedAssembly PepperDashCoreAssembly { get; private set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the list of assemblies that are Essentials plugins loaded by the application.
|
||||||
|
/// </summary>
|
||||||
public static List<LoadedAssembly> EssentialsPluginAssemblies { get; private set; }
|
public static List<LoadedAssembly> EssentialsPluginAssemblies { get; private set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The directory to look in for .cplz plugin packages
|
/// Gets the directory path where plugins are stored.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
static string _pluginDirectory => Global.FilePathPrefix + "plugins";
|
private static string PluginDirectory => Global.FilePathPrefix + "plugins";
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The directory where plugins will be moved to and loaded from
|
/// Gets the directory path where loaded plugin assemblies are stored.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
static string _loadedPluginsDirectoryPath => _pluginDirectory + Global.DirectorySeparator + "loadedAssemblies";
|
private static string LoadedPluginsDirectoryPath => PluginDirectory + Global.DirectorySeparator + "loadedAssemblies";
|
||||||
|
|
||||||
// The temp directory where .cplz archives will be unzipped to
|
/// <summary>
|
||||||
static string _tempDirectory => _pluginDirectory + Global.DirectorySeparator + "temp";
|
/// Gets the path to the temporary directory used by the plugin.
|
||||||
|
/// </summary>
|
||||||
|
private static string TempDirectory => PluginDirectory + Global.DirectorySeparator + "temp";
|
||||||
|
|
||||||
// Known incompatible types in .NET 8
|
/// <summary>
|
||||||
private static readonly HashSet<string> KnownIncompatibleTypes = new HashSet<string>
|
/// Represents a collection of fully qualified type names that are known to be incompatible with the current
|
||||||
{
|
/// application or framework.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>This collection contains the names of types that are deprecated, obsolete, or otherwise
|
||||||
|
/// incompatible with the intended usage of the application. These types may represent security risks, unsupported
|
||||||
|
/// features, or legacy APIs that should be avoided.</remarks>
|
||||||
|
private static readonly HashSet<string> KnownIncompatibleTypes =
|
||||||
|
[
|
||||||
"System.Net.ICertificatePolicy",
|
"System.Net.ICertificatePolicy",
|
||||||
"System.Security.Cryptography.SHA1CryptoServiceProvider",
|
"System.Security.Cryptography.SHA1CryptoServiceProvider",
|
||||||
"System.Web.HttpUtility",
|
"System.Web.HttpUtility",
|
||||||
@@ -68,19 +93,31 @@ namespace PepperDash.Essentials
|
|||||||
"System.Security.SecurityManager",
|
"System.Security.SecurityManager",
|
||||||
"System.Security.Permissions.FileIOPermission",
|
"System.Security.Permissions.FileIOPermission",
|
||||||
"System.AppDomain.CreateDomain"
|
"System.AppDomain.CreateDomain"
|
||||||
};
|
];
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes static members of the <see cref="PluginLoader"/> class.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>This static constructor initializes the collections used to manage plugin assemblies and
|
||||||
|
/// track incompatible plugins.</remarks>
|
||||||
static PluginLoader()
|
static PluginLoader()
|
||||||
{
|
{
|
||||||
LoadedAssemblies = new List<LoadedAssembly>();
|
LoadedAssemblies = [];
|
||||||
LoadedPluginFolderAssemblies = new List<LoadedAssembly>();
|
LoadedPluginFolderAssemblies = [];
|
||||||
EssentialsPluginAssemblies = new List<LoadedAssembly>();
|
EssentialsPluginAssemblies = [];
|
||||||
IncompatiblePlugins = new List<IncompatiblePlugin>();
|
IncompatiblePlugins = [];
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Retrieves all the loaded assemblies from the program directory
|
/// Loads and registers assemblies from the application's directory that match specific naming patterns.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
/// <remarks>This method scans the application's directory for assemblies with filenames containing
|
||||||
|
/// "Essentials" or "PepperDash" and registers them in the <see cref="LoadedAssemblies"/> collection. It also
|
||||||
|
/// assigns specific assemblies to predefined properties, such as <see cref="EssentialsAssembly"/> and <see
|
||||||
|
/// cref="PepperDashCoreAssembly"/>, based on their names. Debug messages are logged at various stages to provide
|
||||||
|
/// detailed information about the process, including the number of assemblies found and their versions. This
|
||||||
|
/// method is intended to be used during application initialization to ensure required assemblies are loaded and
|
||||||
|
/// tracked.</remarks>
|
||||||
public static void AddProgramAssemblies()
|
public static void AddProgramAssemblies()
|
||||||
{
|
{
|
||||||
Debug.LogMessage(LogEventLevel.Verbose, "Getting Assemblies loaded with Essentials");
|
Debug.LogMessage(LogEventLevel.Verbose, "Getting Assemblies loaded with Essentials");
|
||||||
@@ -137,31 +174,42 @@ 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 SetEssentialsAssembly(string name, Assembly assembly)
|
public static void SetEssentialsAssembly(string name, Assembly assembly)
|
||||||
{
|
{
|
||||||
var loadedAssembly = LoadedAssemblies.FirstOrDefault(la => la.Name.Equals(name));
|
var loadedAssembly = LoadedAssemblies.FirstOrDefault(la => la.Name.Equals(name));
|
||||||
|
|
||||||
if (loadedAssembly != null)
|
loadedAssembly?.SetAssembly(assembly);
|
||||||
{
|
|
||||||
loadedAssembly.SetAssembly(assembly);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Checks if a plugin is compatible with .NET 8 by examining its metadata
|
/// Determines whether a plugin assembly is compatible with .NET 8.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="filePath">Path to the plugin assembly</param>
|
/// <remarks>This method analyzes the provided assembly to determine compatibility with .NET 8 by checking
|
||||||
/// <returns>Tuple with compatibility result, reason if incompatible, and referenced assemblies</returns>
|
/// for known incompatible types, inspecting custom attributes, and collecting assembly references. If the analysis
|
||||||
|
/// encounters an error, the method returns <see langword="false"/> with an appropriate error message.</remarks>
|
||||||
|
/// <param name="filePath">The file path to the plugin assembly to analyze.</param>
|
||||||
|
/// <returns>A tuple containing the following: <list type="bullet"> <item> <description><see langword="true"/> if the plugin
|
||||||
|
/// is compatible with .NET 8; otherwise, <see langword="false"/>.</description> </item> <item> <description>A
|
||||||
|
/// string providing the reason for incompatibility, or <see langword="null"/> if the plugin is
|
||||||
|
/// compatible.</description> </item> <item> <description>A list of assembly references found in the
|
||||||
|
/// plugin.</description> </item> </list></returns>
|
||||||
public static (bool IsCompatible, string Reason, List<string> References) IsPluginCompatibleWithNet8(string filePath)
|
public static (bool IsCompatible, string Reason, List<string> References) IsPluginCompatibleWithNet8(string filePath)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
List<string> referencedAssemblies = new List<string>();
|
List<string> referencedAssemblies = [];
|
||||||
|
|
||||||
|
using FileStream fs = new(filePath, FileMode.Open,
|
||||||
|
FileAccess.Read, FileShare.ReadWrite);
|
||||||
|
using PEReader peReader = new(fs);
|
||||||
|
|
||||||
using (FileStream fs = new FileStream(filePath, FileMode.Open,
|
|
||||||
FileAccess.Read, FileShare.ReadWrite))
|
|
||||||
using (PEReader peReader = new PEReader(fs))
|
|
||||||
{
|
|
||||||
if (!peReader.HasMetadata)
|
if (!peReader.HasMetadata)
|
||||||
return (false, "Not a valid .NET assembly", referencedAssemblies);
|
return (false, "Not a valid .NET assembly", referencedAssemblies);
|
||||||
|
|
||||||
@@ -218,7 +266,6 @@ namespace PepperDash.Essentials
|
|||||||
// If we can't determine incompatibility, assume it's compatible
|
// If we can't determine incompatibility, assume it's compatible
|
||||||
return (true, null, referencedAssemblies);
|
return (true, null, referencedAssemblies);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
return (false, $"Error analyzing assembly: {ex.Message}", new List<string>());
|
return (false, $"Error analyzing assembly: {ex.Message}", new List<string>());
|
||||||
@@ -226,11 +273,21 @@ namespace PepperDash.Essentials
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Loads an assembly via Reflection and adds it to the list of loaded assemblies
|
/// Loads an assembly from the specified file path and verifies its compatibility with .NET 8.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="filePath">Path to the assembly file</param>
|
/// <remarks>This method performs a compatibility check to ensure the assembly is compatible with .NET 8
|
||||||
/// <param name="requestedBy">Name of the plugin requesting this assembly (null for direct loads)</param>
|
/// before attempting to load it. If the assembly is incompatible, it is added to the list of incompatible plugins,
|
||||||
static LoadedAssembly LoadAssembly(string filePath, string requestedBy = null)
|
/// and a warning is logged. If the assembly is already loaded, the existing instance is returned instead of
|
||||||
|
/// reloading it. Exceptions during the load process are handled internally, and appropriate log messages are
|
||||||
|
/// generated for issues such as: <list type="bullet"> <item><description>Incompatibility with .NET
|
||||||
|
/// 8.</description></item> <item><description>File load conflicts (e.g., an assembly with the same name is already
|
||||||
|
/// loaded).</description></item> <item><description>General errors, including potential .NET Framework
|
||||||
|
/// compatibility issues.</description></item> </list></remarks>
|
||||||
|
/// <param name="filePath">The full path to the assembly file to load. This cannot be null or empty.</param>
|
||||||
|
/// <param name="requestedBy">An optional identifier for the entity requesting the load operation. This can be null.</param>
|
||||||
|
/// <returns>A <see cref="LoadedAssembly"/> object representing the loaded assembly if the operation succeeds; otherwise,
|
||||||
|
/// <see langword="null"/>.</returns>
|
||||||
|
private static LoadedAssembly LoadAssembly(string filePath, string requestedBy = null)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@@ -303,10 +360,16 @@ namespace PepperDash.Essentials
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Attempts to get the assembly informational version and if not possible gets the version
|
/// Retrieves the version information of the specified assembly.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="assembly"></param>
|
/// <remarks>This method first attempts to retrieve the version from the <see
|
||||||
/// <returns></returns>
|
/// cref="AssemblyInformationalVersionAttribute"/>. If the attribute is not present, it falls back to the assembly's
|
||||||
|
/// version as defined in its metadata.</remarks>
|
||||||
|
/// <param name="assembly">The assembly from which to retrieve the version information. Cannot be <see langword="null"/>.</param>
|
||||||
|
/// <returns>A string representing the version of the assembly. If the assembly has an <see
|
||||||
|
/// cref="AssemblyInformationalVersionAttribute"/>, its <see
|
||||||
|
/// cref="AssemblyInformationalVersionAttribute.InformationalVersion"/> value is returned. Otherwise, the assembly's
|
||||||
|
/// version is returned in the format "Major.Minor.Build.Revision".</returns>
|
||||||
public static string GetAssemblyVersion(Assembly assembly)
|
public static string GetAssemblyVersion(Assembly assembly)
|
||||||
{
|
{
|
||||||
var ver = assembly.GetCustomAttributes(typeof(AssemblyInformationalVersionAttribute), false);
|
var ver = assembly.GetCustomAttributes(typeof(AssemblyInformationalVersionAttribute), false);
|
||||||
@@ -326,10 +389,12 @@ namespace PepperDash.Essentials
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Checks if the filename matches an already loaded assembly file's name
|
/// Determines whether an assembly with the specified name is currently loaded.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="filename"></param>
|
/// <remarks>This method performs a case-sensitive comparison to determine if the specified assembly is
|
||||||
/// <returns>True if file already matches loaded assembly file.</returns>
|
/// loaded. It logs verbose messages indicating the status of the check.</remarks>
|
||||||
|
/// <param name="name">The name of the assembly to check. This value is case-sensitive.</param>
|
||||||
|
/// <returns><see langword="true"/> if an assembly with the specified name is loaded; otherwise, <see langword="false"/>.</returns>
|
||||||
public static bool CheckIfAssemblyLoaded(string name)
|
public static bool CheckIfAssemblyLoaded(string name)
|
||||||
{
|
{
|
||||||
Debug.LogMessage(LogEventLevel.Verbose, "Checking if assembly: {0} is loaded...", name);
|
Debug.LogMessage(LogEventLevel.Verbose, "Checking if assembly: {0} is loaded...", name);
|
||||||
@@ -348,9 +413,13 @@ namespace PepperDash.Essentials
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Used by console command to report the currently loaded assemblies and versions
|
/// Reports the versions of the Essentials framework, PepperDash Core, and loaded plugins to the console.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="command"></param>
|
/// <remarks>This method outputs version information for the Essentials framework, PepperDash Core, and
|
||||||
|
/// all loaded Essentials plugins to the Crestron console. If any incompatible plugins are detected, their details
|
||||||
|
/// are also reported, including the reason for incompatibility and the plugin that required them, if
|
||||||
|
/// applicable.</remarks>
|
||||||
|
/// <param name="command">The command string that triggered the version report. This parameter is not used directly by the method.</param>
|
||||||
public static void ReportAssemblyVersions(string command)
|
public static void ReportAssemblyVersions(string command)
|
||||||
{
|
{
|
||||||
CrestronConsole.ConsoleCommandResponse("Essentials Version: {0}" + CrestronEnvironment.NewLine, Global.AssemblyVersion);
|
CrestronConsole.ConsoleCommandResponse("Essentials Version: {0}" + CrestronEnvironment.NewLine, Global.AssemblyVersion);
|
||||||
@@ -381,20 +450,24 @@ namespace PepperDash.Essentials
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Moves any .dll assemblies not already loaded from the plugins folder to loadedPlugins folder
|
/// Moves .dll assemblies from the plugins folder to the loaded plugins directory.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
static void MoveDllAssemblies()
|
/// <remarks>This method scans the plugins folder for .dll files and moves them to the loaded plugins
|
||||||
|
/// directory if they are not already loaded. If a file with the same name exists in the target directory, it is
|
||||||
|
/// replaced. The method logs the process at various stages and handles exceptions for individual files to ensure
|
||||||
|
/// the operation continues for other files.</remarks>
|
||||||
|
private static void MoveDllAssemblies()
|
||||||
{
|
{
|
||||||
Debug.LogMessage(LogEventLevel.Information, "Looking for .dll assemblies from plugins folder...");
|
Debug.LogMessage(LogEventLevel.Information, "Looking for .dll assemblies from plugins folder...");
|
||||||
|
|
||||||
var pluginDi = new DirectoryInfo(_pluginDirectory);
|
var pluginDi = new DirectoryInfo(PluginDirectory);
|
||||||
var pluginFiles = pluginDi.GetFiles("*.dll");
|
var pluginFiles = pluginDi.GetFiles("*.dll");
|
||||||
|
|
||||||
if (pluginFiles.Length > 0)
|
if (pluginFiles.Length > 0)
|
||||||
{
|
{
|
||||||
if (!Directory.Exists(_loadedPluginsDirectoryPath))
|
if (!Directory.Exists(LoadedPluginsDirectoryPath))
|
||||||
{
|
{
|
||||||
Directory.CreateDirectory(_loadedPluginsDirectoryPath);
|
Directory.CreateDirectory(LoadedPluginsDirectoryPath);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -408,7 +481,7 @@ namespace PepperDash.Essentials
|
|||||||
{
|
{
|
||||||
string filePath = string.Empty;
|
string filePath = string.Empty;
|
||||||
|
|
||||||
filePath = _loadedPluginsDirectoryPath + Global.DirectorySeparator + pluginFile.Name;
|
filePath = LoadedPluginsDirectoryPath + Global.DirectorySeparator + pluginFile.Name;
|
||||||
|
|
||||||
// Check if there is a previous file in the loadedPlugins directory and delete
|
// Check if there is a previous file in the loadedPlugins directory and delete
|
||||||
if (File.Exists(filePath))
|
if (File.Exists(filePath))
|
||||||
@@ -437,12 +510,17 @@ namespace PepperDash.Essentials
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Unzips each .cplz archive into the temp directory and moves any unloaded files into loadedPlugins
|
/// Extracts and processes .cplz archive files found in the specified directories, moving their contents to the
|
||||||
|
/// appropriate plugin directory.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
static void UnzipAndMoveCplzArchives()
|
/// <remarks>This method searches for .cplz files in the plugin directory and user folder, extracts their
|
||||||
|
/// contents, and moves any .dll files to the loaded plugins directory. If a .dll file with the same name already
|
||||||
|
/// exists in the target directory, it is replaced with the new file. Temporary files and directories created during
|
||||||
|
/// the process are cleaned up after the operation completes.</remarks>
|
||||||
|
private static void UnzipAndMoveCplzArchives()
|
||||||
{
|
{
|
||||||
Debug.LogMessage(LogEventLevel.Information, "Looking for .cplz archives from plugins folder...");
|
Debug.LogMessage(LogEventLevel.Information, "Looking for .cplz archives from plugins folder...");
|
||||||
var di = new DirectoryInfo(_pluginDirectory);
|
var di = new DirectoryInfo(PluginDirectory);
|
||||||
var zFiles = di.GetFiles("*.cplz");
|
var zFiles = di.GetFiles("*.cplz");
|
||||||
|
|
||||||
//// Find cplz files at the root of the user folder. Makes development/testing easier for VC-4, and helps with mistakes by end users
|
//// Find cplz files at the root of the user folder. Makes development/testing easier for VC-4, and helps with mistakes by end users
|
||||||
@@ -457,16 +535,16 @@ namespace PepperDash.Essentials
|
|||||||
|
|
||||||
if (cplzFiles.Length > 0)
|
if (cplzFiles.Length > 0)
|
||||||
{
|
{
|
||||||
if (!Directory.Exists(_loadedPluginsDirectoryPath))
|
if (!Directory.Exists(LoadedPluginsDirectoryPath))
|
||||||
{
|
{
|
||||||
Directory.CreateDirectory(_loadedPluginsDirectoryPath);
|
Directory.CreateDirectory(LoadedPluginsDirectoryPath);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (var zfi in cplzFiles)
|
foreach (var zfi in cplzFiles)
|
||||||
{
|
{
|
||||||
Directory.CreateDirectory(_tempDirectory);
|
Directory.CreateDirectory(TempDirectory);
|
||||||
var tempDi = new DirectoryInfo(_tempDirectory);
|
var tempDi = new DirectoryInfo(TempDirectory);
|
||||||
|
|
||||||
Debug.LogMessage(LogEventLevel.Information, "Found cplz: {0}. Unzipping into temp plugins directory", zfi.FullName);
|
Debug.LogMessage(LogEventLevel.Information, "Found cplz: {0}. Unzipping into temp plugins directory", zfi.FullName);
|
||||||
var result = CrestronZIP.Unzip(zfi.FullName, tempDi.FullName);
|
var result = CrestronZIP.Unzip(zfi.FullName, tempDi.FullName);
|
||||||
@@ -481,7 +559,7 @@ namespace PepperDash.Essentials
|
|||||||
{
|
{
|
||||||
string filePath = string.Empty;
|
string filePath = string.Empty;
|
||||||
|
|
||||||
filePath = _loadedPluginsDirectoryPath + Global.DirectorySeparator + tempFile.Name;
|
filePath = LoadedPluginsDirectoryPath + Global.DirectorySeparator + tempFile.Name;
|
||||||
|
|
||||||
// Check if there is a previous file in the loadedPlugins directory and delete
|
// Check if there is a previous file in the loadedPlugins directory and delete
|
||||||
if (File.Exists(filePath))
|
if (File.Exists(filePath))
|
||||||
@@ -507,7 +585,7 @@ namespace PepperDash.Essentials
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Delete the .cplz and the temp directory
|
// Delete the .cplz and the temp directory
|
||||||
Directory.Delete(_tempDirectory, true);
|
Directory.Delete(TempDirectory, true);
|
||||||
zfi.Delete();
|
zfi.Delete();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -515,12 +593,16 @@ namespace PepperDash.Essentials
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Attempts to load the assemblies from the loadedPlugins folder
|
/// Loads plugin assemblies from the designated plugin directory, checks their compatibility with .NET 8, and loads
|
||||||
|
/// the compatible assemblies into the application.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
static void LoadPluginAssemblies()
|
/// <remarks>This method scans the plugin directory for all `.dll` files, verifies their compatibility
|
||||||
|
/// with .NET 8, and attempts to load the compatible assemblies. Assemblies that are incompatible are logged as
|
||||||
|
/// warnings and added to a list of incompatible plugins for further inspection.</remarks>
|
||||||
|
private static void LoadPluginAssemblies()
|
||||||
{
|
{
|
||||||
Debug.LogMessage(LogEventLevel.Information, "Loading assemblies from loadedPlugins folder...");
|
Debug.LogMessage(LogEventLevel.Information, "Loading assemblies from loadedPlugins folder...");
|
||||||
var pluginDi = new DirectoryInfo(_loadedPluginsDirectoryPath);
|
var pluginDi = new DirectoryInfo(LoadedPluginsDirectoryPath);
|
||||||
var pluginFiles = pluginDi.GetFiles("*.dll");
|
var pluginFiles = pluginDi.GetFiles("*.dll");
|
||||||
|
|
||||||
Debug.LogMessage(LogEventLevel.Verbose, "Found {0} plugin assemblies to load", pluginFiles.Length);
|
Debug.LogMessage(LogEventLevel.Verbose, "Found {0} plugin assemblies to load", pluginFiles.Length);
|
||||||
@@ -538,7 +620,7 @@ namespace PepperDash.Essentials
|
|||||||
foreach (var pluginFile in pluginFiles)
|
foreach (var pluginFile in pluginFiles)
|
||||||
{
|
{
|
||||||
string fileName = pluginFile.Name;
|
string fileName = pluginFile.Name;
|
||||||
var (isCompatible, reason, references) = assemblyCompatibility[fileName];
|
var (isCompatible, reason, _) = assemblyCompatibility[fileName];
|
||||||
|
|
||||||
if (!isCompatible)
|
if (!isCompatible)
|
||||||
{
|
{
|
||||||
@@ -560,9 +642,13 @@ namespace PepperDash.Essentials
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Iterate the loaded assemblies and try to call the LoadPlugin method
|
/// Loads and initializes custom plugin types from the assemblies in the plugin folder.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
static void LoadCustomPluginTypes()
|
/// <remarks>This method iterates through all loaded plugin assemblies, identifies types that implement
|
||||||
|
/// the <see cref="IPluginDeviceFactory"/> interface, and attempts to instantiate and load them. Assemblies or
|
||||||
|
/// types that cannot be loaded due to missing dependencies, type loading errors, or other exceptions are logged,
|
||||||
|
/// and incompatible plugins are tracked for further analysis.</remarks>
|
||||||
|
private static void LoadCustomPluginTypes()
|
||||||
{
|
{
|
||||||
Debug.LogMessage(LogEventLevel.Information, "Loading Custom Plugin Types...");
|
Debug.LogMessage(LogEventLevel.Information, "Loading Custom Plugin Types...");
|
||||||
|
|
||||||
@@ -576,7 +662,7 @@ namespace PepperDash.Essentials
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
var assy = loadedAssembly.Assembly;
|
var assy = loadedAssembly.Assembly;
|
||||||
Type[] types = {};
|
Type[] types = [];
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
types = assy.GetTypes();
|
types = assy.GetTypes();
|
||||||
@@ -682,8 +768,13 @@ namespace PepperDash.Essentials
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Updates incompatible plugins with information about which plugins depend on them
|
/// Updates the triggering plugin information for incompatible plugins based on their dependencies.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
/// <remarks>This method iterates through a predefined list of incompatible plugins and updates their
|
||||||
|
/// triggering plugin information if they were directly loaded and are found to be dependencies of other plugins.
|
||||||
|
/// The update is performed for the first plugin that depends on the incompatible plugin.</remarks>
|
||||||
|
/// <param name="pluginDependencies">A dictionary where the key is the name of a plugin and the value is a list of its dependencies. Each dependency
|
||||||
|
/// is represented as a string, which may include additional metadata.</param>
|
||||||
private static void UpdateIncompatiblePluginDependencies(Dictionary<string, List<string>> pluginDependencies)
|
private static void UpdateIncompatiblePluginDependencies(Dictionary<string, List<string>> pluginDependencies)
|
||||||
{
|
{
|
||||||
// For each incompatible plugin
|
// For each incompatible plugin
|
||||||
@@ -709,16 +800,21 @@ namespace PepperDash.Essentials
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/// <summary>
|
|
||||||
/// Loads a
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="plugin"></param>
|
|
||||||
/// <param name="loadedAssembly"></param>
|
|
||||||
static void LoadCustomPlugin(IPluginDeviceFactory plugin, LoadedAssembly loadedAssembly)
|
|
||||||
{
|
|
||||||
var developmentPlugin = plugin as IPluginDevelopmentDeviceFactory;
|
|
||||||
|
|
||||||
var passed = developmentPlugin != null ? Global.IsRunningDevelopmentVersion
|
/// <summary>
|
||||||
|
/// Loads a custom plugin and performs a dependency check to ensure compatibility with the required Essentials
|
||||||
|
/// framework version.
|
||||||
|
/// </summary>
|
||||||
|
/// <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="plugin">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>
|
||||||
|
private static void LoadCustomPlugin(IPluginDeviceFactory plugin, LoadedAssembly loadedAssembly)
|
||||||
|
{
|
||||||
|
var passed = plugin is IPluginDevelopmentDeviceFactory developmentPlugin ? Global.IsRunningDevelopmentVersion
|
||||||
(developmentPlugin.DevelopmentEssentialsFrameworkVersions, developmentPlugin.MinimumEssentialsFrameworkVersion)
|
(developmentPlugin.DevelopmentEssentialsFrameworkVersions, developmentPlugin.MinimumEssentialsFrameworkVersion)
|
||||||
: Global.IsRunningMinimumVersionOrHigher(plugin.MinimumEssentialsFrameworkVersion);
|
: Global.IsRunningMinimumVersionOrHigher(plugin.MinimumEssentialsFrameworkVersion);
|
||||||
|
|
||||||
@@ -742,59 +838,20 @@ namespace PepperDash.Essentials
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Loads a a custom plugin via the legacy method
|
/// Loads plugins from the designated plugin directory, processes them, and integrates them into the application.
|
||||||
/// </summary>
|
|
||||||
/// <param name="type"></param>
|
|
||||||
/// <param name="loadPlugin"></param>
|
|
||||||
static void LoadCustomLegacyPlugin(Type type, MethodInfo loadPlugin, LoadedAssembly loadedAssembly)
|
|
||||||
{
|
|
||||||
Debug.LogMessage(LogEventLevel.Verbose, "LoadPlugin method found in {0}", type.Name);
|
|
||||||
|
|
||||||
var fields = type.GetFields(BindingFlags.Public | BindingFlags.Static);
|
|
||||||
|
|
||||||
var minimumVersion = fields.FirstOrDefault(p => p.Name.Equals("MinimumEssentialsFrameworkVersion"));
|
|
||||||
if (minimumVersion != null)
|
|
||||||
{
|
|
||||||
Debug.LogMessage(LogEventLevel.Verbose, "MinimumEssentialsFrameworkVersion found");
|
|
||||||
|
|
||||||
var minimumVersionString = minimumVersion.GetValue(null) as string;
|
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(minimumVersionString))
|
|
||||||
{
|
|
||||||
var passed = Global.IsRunningMinimumVersionOrHigher(minimumVersionString);
|
|
||||||
|
|
||||||
if (!passed)
|
|
||||||
{
|
|
||||||
Debug.LogMessage(LogEventLevel.Information, "Plugin indicates minimum Essentials version {0}. Dependency check failed. Skipping Plugin", minimumVersionString);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Debug.LogMessage(LogEventLevel.Information, "Passed plugin passed dependency check (required version {0})", minimumVersionString);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Debug.LogMessage(LogEventLevel.Information, "MinimumEssentialsFrameworkVersion found but not set. Loading plugin, but your mileage may vary.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Debug.LogMessage(LogEventLevel.Information, "MinimumEssentialsFrameworkVersion not found. Loading plugin, but your mileage may vary.");
|
|
||||||
}
|
|
||||||
|
|
||||||
Debug.LogMessage(LogEventLevel.Information, "Loading legacy plugin: {0}", loadedAssembly.Name);
|
|
||||||
loadPlugin.Invoke(null, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Loads plugins
|
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
/// <remarks>This method performs the following steps: <list type="bullet"> <item><description>Checks if
|
||||||
|
/// the plugin directory exists.</description></item> <item><description>Processes any plugin files, including .dll
|
||||||
|
/// and .cplz files, by moving or extracting them as needed.</description></item> <item><description>Loads
|
||||||
|
/// assemblies from the processed plugins into the application domain.</description></item>
|
||||||
|
/// <item><description>Identifies and reports any incompatible plugins, including the reason for
|
||||||
|
/// incompatibility.</description></item> </list> Plugins that are successfully loaded are made available for use,
|
||||||
|
/// while incompatible plugins are logged for review.</remarks>
|
||||||
public static void LoadPlugins()
|
public static void LoadPlugins()
|
||||||
{
|
{
|
||||||
Debug.LogMessage(LogEventLevel.Information, "Attempting to Load Plugins from {_pluginDirectory}", _pluginDirectory);
|
Debug.LogMessage(LogEventLevel.Information, "Attempting to Load Plugins from {_pluginDirectory}", PluginDirectory);
|
||||||
|
|
||||||
if (Directory.Exists(_pluginDirectory))
|
if (Directory.Exists(PluginDirectory))
|
||||||
{
|
{
|
||||||
Debug.LogMessage(LogEventLevel.Information, "Plugins directory found, checking for plugins");
|
Debug.LogMessage(LogEventLevel.Information, "Plugins directory found, checking for plugins");
|
||||||
|
|
||||||
@@ -804,7 +861,7 @@ namespace PepperDash.Essentials
|
|||||||
// Deal with any .cplz files
|
// Deal with any .cplz files
|
||||||
UnzipAndMoveCplzArchives();
|
UnzipAndMoveCplzArchives();
|
||||||
|
|
||||||
if (Directory.Exists(_loadedPluginsDirectoryPath))
|
if (Directory.Exists(LoadedPluginsDirectoryPath))
|
||||||
{
|
{
|
||||||
// Load the assemblies from the loadedPlugins folder into the AppDomain
|
// Load the assemblies from the loadedPlugins folder into the AppDomain
|
||||||
LoadPluginAssemblies();
|
LoadPluginAssemblies();
|
||||||
@@ -834,77 +891,3 @@ namespace PepperDash.Essentials
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Represents an assembly loaded at runtime and it's associated metadata
|
|
||||||
/// </summary>
|
|
||||||
public class LoadedAssembly
|
|
||||||
{
|
|
||||||
[JsonProperty("name")]
|
|
||||||
public string Name { get; private set; }
|
|
||||||
[JsonProperty("version")]
|
|
||||||
public string Version { get; private set; }
|
|
||||||
[JsonIgnore]
|
|
||||||
public Assembly Assembly { get; private set; }
|
|
||||||
|
|
||||||
public LoadedAssembly(string name, string version, Assembly assembly)
|
|
||||||
{
|
|
||||||
Name = name;
|
|
||||||
Version = version;
|
|
||||||
Assembly = assembly;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void SetAssembly(Assembly assembly)
|
|
||||||
{
|
|
||||||
Assembly = assembly;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Represents a plugin that was found to be incompatible with .NET 8
|
|
||||||
/// </summary>
|
|
||||||
public class IncompatiblePlugin
|
|
||||||
{
|
|
||||||
[JsonProperty("name")]
|
|
||||||
public string Name { get; private set; }
|
|
||||||
|
|
||||||
[JsonProperty("reason")]
|
|
||||||
public string Reason { get; private set; }
|
|
||||||
|
|
||||||
[JsonProperty("triggeredBy")]
|
|
||||||
public string TriggeredBy { get; private set; }
|
|
||||||
|
|
||||||
public IncompatiblePlugin(string name, string reason, string triggeredBy = null)
|
|
||||||
{
|
|
||||||
Name = name;
|
|
||||||
Reason = reason;
|
|
||||||
TriggeredBy = triggeredBy ?? "Direct load";
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Updates the plugin that triggered this incompatibility
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="triggeringPlugin">Name of the plugin that requires this incompatible plugin</param>
|
|
||||||
public void UpdateTriggeringPlugin(string triggeringPlugin)
|
|
||||||
{
|
|
||||||
if (!string.IsNullOrEmpty(triggeringPlugin))
|
|
||||||
{
|
|
||||||
TriggeredBy = triggeringPlugin;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Attribute to explicitly mark a plugin as .NET 8 compatible
|
|
||||||
/// </summary>
|
|
||||||
[AttributeUsage(AttributeTargets.Assembly)]
|
|
||||||
public class Net8CompatibleAttribute : Attribute
|
|
||||||
{
|
|
||||||
public bool IsCompatible { get; }
|
|
||||||
|
|
||||||
public Net8CompatibleAttribute(bool isCompatible = true)
|
|
||||||
{
|
|
||||||
IsCompatible = isCompatible;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user