178 lines
6.6 KiB
C#
Executable File
178 lines
6.6 KiB
C#
Executable File
using MarketAlly.AIPlugin;
|
|
using MarketAlly.AIPlugin.Analysis.Plugins;
|
|
using Microsoft.Extensions.Logging;
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.IO;
|
|
using System.Linq;
|
|
using System.Reflection;
|
|
using System.Threading.Tasks;
|
|
|
|
namespace MarketAlly.AIPlugin.Analysis.Infrastructure
|
|
{
|
|
/// <summary>
|
|
/// Service for discovering and loading analysis plugins
|
|
/// </summary>
|
|
public class PluginDiscoveryService : IPluginDiscovery
|
|
{
|
|
private readonly ILogger<PluginDiscoveryService>? _logger;
|
|
|
|
public PluginDiscoveryService(ILogger<PluginDiscoveryService>? logger = null)
|
|
{
|
|
_logger = logger;
|
|
}
|
|
|
|
public Task<IEnumerable<IAIPlugin>> DiscoverPluginsAsync(string pluginDirectory)
|
|
{
|
|
_logger?.LogInformation("Discovering plugins in directory: {PluginDirectory}", pluginDirectory);
|
|
|
|
var plugins = new List<IAIPlugin>();
|
|
|
|
if (!Directory.Exists(pluginDirectory))
|
|
{
|
|
_logger?.LogWarning("Plugin directory does not exist: {PluginDirectory}", pluginDirectory);
|
|
return Task.FromResult<IEnumerable<IAIPlugin>>(plugins);
|
|
}
|
|
|
|
var assemblyFiles = Directory.GetFiles(pluginDirectory, "*.dll", SearchOption.AllDirectories);
|
|
|
|
foreach (var assemblyFile in assemblyFiles)
|
|
{
|
|
try
|
|
{
|
|
var assembly = Assembly.LoadFrom(assemblyFile);
|
|
var pluginTypes = assembly.GetTypes()
|
|
.Where(t => typeof(IAIPlugin).IsAssignableFrom(t) && !t.IsInterface && !t.IsAbstract);
|
|
|
|
foreach (var pluginType in pluginTypes)
|
|
{
|
|
try
|
|
{
|
|
var plugin = Activator.CreateInstance(pluginType) as IAIPlugin;
|
|
if (plugin != null && ValidatePlugin(plugin))
|
|
{
|
|
plugins.Add(plugin);
|
|
_logger?.LogDebug("Loaded plugin: {PluginType} from {AssemblyFile}",
|
|
pluginType.Name, assemblyFile);
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
_logger?.LogError(ex, "Failed to create instance of plugin type: {PluginType}",
|
|
pluginType.Name);
|
|
}
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
_logger?.LogError(ex, "Failed to load assembly: {AssemblyFile}", assemblyFile);
|
|
}
|
|
}
|
|
|
|
_logger?.LogInformation("Discovered {PluginCount} plugins", plugins.Count);
|
|
return Task.FromResult<IEnumerable<IAIPlugin>>(plugins);
|
|
}
|
|
|
|
public Task<IAIPlugin> LoadPluginAsync(string assemblyPath, string typeName)
|
|
{
|
|
_logger?.LogInformation("Loading specific plugin: {TypeName} from {AssemblyPath}",
|
|
typeName, assemblyPath);
|
|
|
|
if (!File.Exists(assemblyPath))
|
|
{
|
|
throw new FileNotFoundException($"Assembly file not found: {assemblyPath}");
|
|
}
|
|
|
|
var assembly = Assembly.LoadFrom(assemblyPath);
|
|
var pluginType = assembly.GetType(typeName);
|
|
|
|
if (pluginType == null)
|
|
{
|
|
throw new TypeLoadException($"Type not found: {typeName}");
|
|
}
|
|
|
|
if (!typeof(IAIPlugin).IsAssignableFrom(pluginType))
|
|
{
|
|
throw new InvalidOperationException($"Type does not implement IAIPlugin: {typeName}");
|
|
}
|
|
|
|
var plugin = Activator.CreateInstance(pluginType) as IAIPlugin;
|
|
if (plugin == null)
|
|
{
|
|
throw new InvalidOperationException($"Failed to create instance of type: {typeName}");
|
|
}
|
|
|
|
if (!ValidatePlugin(plugin))
|
|
{
|
|
throw new InvalidOperationException($"Plugin validation failed: {typeName}");
|
|
}
|
|
|
|
_logger?.LogInformation("Successfully loaded plugin: {TypeName}", typeName);
|
|
return Task.FromResult(plugin);
|
|
}
|
|
|
|
public IEnumerable<IAIPlugin> GetBuiltInPlugins()
|
|
{
|
|
_logger?.LogInformation("Getting built-in analysis plugins");
|
|
|
|
var plugins = new List<IAIPlugin>
|
|
{
|
|
new PerformanceAnalyzerPlugin(),
|
|
new ArchitectureValidatorPlugin(),
|
|
new TechnicalDebtPlugin(),
|
|
new ComplexityAnalyzerPlugin(),
|
|
new TestAnalysisPlugin(),
|
|
new BehaviorAnalysisPlugin(),
|
|
new SQLiteSchemaReaderPlugin()
|
|
};
|
|
|
|
_logger?.LogInformation("Loaded {PluginCount} built-in plugins", plugins.Count);
|
|
return plugins;
|
|
}
|
|
|
|
public bool ValidatePlugin(IAIPlugin plugin)
|
|
{
|
|
if (plugin == null)
|
|
{
|
|
_logger?.LogWarning("Plugin is null");
|
|
return false;
|
|
}
|
|
|
|
try
|
|
{
|
|
// Check if plugin has required attributes
|
|
var pluginType = plugin.GetType();
|
|
var aiPluginAttribute = pluginType.GetCustomAttribute<AIPluginAttribute>();
|
|
|
|
if (aiPluginAttribute == null)
|
|
{
|
|
_logger?.LogWarning("Plugin missing AIPluginAttribute: {PluginType}", pluginType.Name);
|
|
return false;
|
|
}
|
|
|
|
// Check if SupportedParameters is implemented
|
|
if (plugin.SupportedParameters == null)
|
|
{
|
|
_logger?.LogWarning("Plugin SupportedParameters is null: {PluginType}", pluginType.Name);
|
|
return false;
|
|
}
|
|
|
|
// Validate that ExecuteAsync method exists and is properly implemented
|
|
var executeMethod = pluginType.GetMethod("ExecuteAsync");
|
|
if (executeMethod == null)
|
|
{
|
|
_logger?.LogWarning("Plugin missing ExecuteAsync method: {PluginType}", pluginType.Name);
|
|
return false;
|
|
}
|
|
|
|
_logger?.LogDebug("Plugin validation successful: {PluginType}", pluginType.Name);
|
|
return true;
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
_logger?.LogError(ex, "Plugin validation failed: {PluginType}", plugin.GetType().Name);
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
} |