Files
Disco/Disco.Services/Plugins/PluginFeatureManifest.cs
T
2025-07-20 13:47:56 +10:00

111 lines
4.5 KiB
C#

using Disco.Data.Repository;
using Newtonsoft.Json;
using System;
using System.Linq;
namespace Disco.Services.Plugins
{
public class PluginFeatureManifest
{
public string Id { get; set; }
public string Name { get; set; }
public string TypeName { get; set; }
public bool PrimaryFeature { get; set; }
[JsonProperty]
private string CategoryTypeName { get; set; }
[JsonIgnore]
public PluginManifest PluginManifest { get; private set; }
[JsonIgnore]
internal Type Type { get; private set; }
[JsonIgnore]
public Type CategoryType { get; private set; }
internal bool Initialize(DiscoDataContext Database, PluginManifest pluginManifest)
{
PluginManifest = pluginManifest;
if (Type == null)
Type = PluginManifest.PluginAssembly.GetType(TypeName, true, true);
if (CategoryType == null)
CategoryType = Type.GetType(CategoryTypeName, true, true);
using (var instance = CreateInstance())
{
instance.Initialize(Database);
}
PluginsLog.LogInitializedPluginFeature(PluginManifest, this);
return true;
}
public PluginFeature CreateInstance()
{
var i = (PluginFeature)Activator.CreateInstance(Type);
i.Manifest = this;
return i;
}
public CategoryType CreateInstance<CategoryType>() where CategoryType : PluginFeature
{
if (typeof(CategoryType).IsAssignableFrom(Type))
{
var i = (CategoryType)Activator.CreateInstance(Type);
i.Manifest = this;
return i;
}
else
throw new InvalidOperationException($"The feature [{Type.Name}] cannot be cast into type [{typeof(CategoryType).Name}]");
}
/// <summary>
/// Uses reflection to build a Plugin Manifest
/// </summary>
/// <param name="pluginAssembly">Assembly containing a plugin</param>
/// <returns>A plugin manifest for the first encountered plugin within the assembly</returns>
public static PluginFeatureManifest FromPluginFeatureType(Type featureType, PluginManifest pluginManifest)
{
var featureAttribute = (PluginFeatureAttribute)featureType.GetCustomAttributes(typeof(PluginFeatureAttribute), false).FirstOrDefault();
if (featureAttribute == null)
throw new ArgumentException($"Plugin Feature found [{featureType.Name}], but no PluginFeatureAttribute found", "featureType");
var featureId = featureAttribute.Id;
var featureName = featureAttribute.Name;
var featurePrimary = featureAttribute.PrimaryFeature;
// Determine Feature Category
var featureCategoryType = featureType.BaseType;
if (featureCategoryType == null)
throw new ArgumentException($"Plugin Feature found [{featureType.Name}], but has no Base Type to determine its Category", "featureType");
// Handle Generic-Type Features (Only use base-feature, not generic parameters)
if (featureCategoryType.IsGenericType)
featureCategoryType = featureCategoryType.GetGenericTypeDefinition();
if (featureCategoryType == typeof(PluginFeature) || !typeof(PluginFeature).IsAssignableFrom(featureCategoryType))
throw new ArgumentException($"Plugin Feature found [{featureType.Name}], but its Base Type is not a valid Feature Category Type (Base Feature or not assignable)", "featureType");
var featureCategoryAttribute = (PluginFeatureCategoryAttribute)featureCategoryType.GetCustomAttributes(typeof(PluginFeatureCategoryAttribute), false).FirstOrDefault();
if (featureCategoryAttribute == null)
throw new ArgumentException($"Plugin Feature found [{featureType.Name}], but its Base Type is not a valid Feature Category Type (no attribute)", "featureType");
return new PluginFeatureManifest()
{
PluginManifest = pluginManifest,
Id = featureId,
Name = featureName,
PrimaryFeature = featurePrimary,
Type = featureType,
TypeName = featureType.FullName,
CategoryType = featureCategoryType,
CategoryTypeName = featureCategoryType.FullName
};
}
}
}