Files
community/Ink Canvas/Plugins/PluginManager.cs
T
2026-04-08 12:41:56 +08:00

167 lines
5.3 KiB
C#

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using Weikio.PluginFramework;
using Weikio.PluginFramework.Abstractions;
using Weikio.PluginFramework.Catalogs;
namespace Ink_Canvas.Plugins
{
public class PluginInfo
{
public string Id { get; set; } = "";
public string Name { get; set; } = "";
public string Version { get; set; } = "";
public string FilePath { get; set; } = "";
public bool IsLoaded { get; set; }
public IPlugin? Instance { get; set; }
public Exception? LoadError { get; set; }
}
public class PluginManager : IPluginHost
{
private static PluginManager? _instance;
public static PluginManager Instance => _instance ??= new PluginManager();
private readonly List<PluginInfo> _plugins = new();
private readonly Dictionary<Type, object> _services = new();
private string _pluginsDirectory;
private FolderPluginCatalog? _catalog;
public IReadOnlyList<PluginInfo> Plugins => _plugins.AsReadOnly();
public event EventHandler<PluginInfo>? PluginLoaded;
public event EventHandler<PluginInfo>? PluginUnloaded;
public event EventHandler<string>? LogMessage;
private PluginManager()
{
_pluginsDirectory = Path.Combine(
AppDomain.CurrentDomain.BaseDirectory, "Plugins");
}
public void SetPluginsDirectory(string path)
{
if (Directory.Exists(path))
{
_pluginsDirectory = path;
}
}
public async Task LoadAllAsync()
{
if (!Directory.Exists(_pluginsDirectory))
{
Directory.CreateDirectory(_pluginsDirectory);
Log("Plugins directory created");
return;
}
try
{
var options = new FolderPluginCatalogOptions
{
SearchPatterns = new[] { "*.dll" },
IncludeSubfolders = false
};
_catalog = new FolderPluginCatalog(_pluginsDirectory, options);
await _catalog.Initialize();
var weikioPlugins = _catalog.GetPlugins();
foreach (var weikioPlugin in weikioPlugins)
{
try
{
var pluginType = weikioPlugin.GetType();
var instance = Activator.CreateInstance(pluginType) as IPlugin;
if (instance == null)
{
Log($"Failed to create instance of plugin from {weikioPlugin.AssemblyPath}");
continue;
}
var info = new PluginInfo
{
Id = instance.Id,
Name = instance.Name,
Version = instance.Version,
FilePath = weikioPlugin.AssemblyPath ?? "",
IsLoaded = true,
Instance = instance
};
instance.Initialize(this);
_plugins.Add(info);
PluginLoaded?.Invoke(this, info);
Log($"Plugin loaded: {info.Name} v{info.Version}");
}
catch (Exception ex)
{
LogError($"Failed to load plugin from {weikioPlugin.AssemblyPath}", ex);
}
}
Log($"Plugin loading complete. Loaded {_plugins.Count} plugins.");
}
catch (Exception ex)
{
LogError("Failed to initialize plugin catalog", ex);
}
}
public void UnloadPlugin(PluginInfo plugin)
{
if (!plugin.IsLoaded || plugin.Instance == null)
return;
try
{
plugin.Instance.Shutdown();
plugin.Instance = null;
plugin.IsLoaded = false;
_plugins.Remove(plugin);
PluginUnloaded?.Invoke(this, plugin);
Log($"Plugin unloaded: {plugin.Name}");
}
catch (Exception ex)
{
LogError($"Failed to unload plugin {plugin.Name}", ex);
}
}
public void UnloadAll()
{
foreach (var plugin in _plugins.ToList())
{
UnloadPlugin(plugin);
}
}
public void RegisterService<T>(T service) where T : class
{
_services[typeof(T)] = service;
}
public T? GetService<T>() where T : class
{
return _services.TryGetValue(typeof(T), out var service) ? service as T : null;
}
public void Log(string message)
{
LogMessage?.Invoke(this, message);
System.Diagnostics.Debug.WriteLine($"[PluginManager] {message}");
}
public void LogError(string message, Exception? ex = null)
{
var fullMessage = ex != null ? $"{message}: {ex.Message}\n{ex.StackTrace}" : message;
Log($"ERROR: {fullMessage}");
}
}
}