Implement plugin depending/exporting API feature in plugin system

This commit is contained in:
ChronosX88 2020-09-13 18:53:10 +04:00
parent fdf85d5055
commit 803d898f45
Signed by: ChronosXYZ
GPG Key ID: 085A69A82C8C511A
4 changed files with 69 additions and 30 deletions

View File

@ -3,6 +3,8 @@ namespace Zirconium.Core.Plugins.Interfaces
public interface IPluginAPI public interface IPluginAPI
{ {
void Initialize(IPluginHostAPI hostModuleAPI); void Initialize(IPluginHostAPI hostModuleAPI);
void PreInitialize(IPluginManager pluginManager);
string GetPluginUniqueName(); string GetPluginUniqueName();
dynamic GetExportedAPI();
} }
} }

View File

@ -0,0 +1,7 @@
namespace Zirconium.Core.Plugins.Interfaces
{
public interface IPluginManager
{
dynamic Depends(IPluginAPI currentPlugin, string pluginName);
}
}

View File

@ -6,20 +6,22 @@ using System.Threading;
using McMaster.NETCore.Plugins; using McMaster.NETCore.Plugins;
using Zirconium.Core.Models; using Zirconium.Core.Models;
using Zirconium.Core.Plugins.Interfaces; using Zirconium.Core.Plugins.Interfaces;
using Zirconium.Utils;
namespace Zirconium.Core.Plugins namespace Zirconium.Core.Plugins
{ {
// Class which responsible for plugin managing (loading, initializing) and plugin lifetime cycle // Class which responsible for plugin managing (loading, initializing) and plugin lifetime cycle
public class PluginManager public class PluginManager : IPluginManager
{ {
private IList<IPluginAPI> _plugins; private IDictionary<string, IPluginAPI> _plugins;
private IPluginHostAPI _pluginHostAPI; private IPluginHostAPI _pluginHostAPI;
private Mutex _pluginsMutex; private Mutex _pluginsMutex;
private string _currentPluginFolderPath;
public PluginManager(IPluginHostAPI hostModuleAPI) public PluginManager(IPluginHostAPI hostModuleAPI)
{ {
_pluginHostAPI = hostModuleAPI; _pluginHostAPI = hostModuleAPI;
_plugins = new List<IPluginAPI>(); _plugins = new Dictionary<string, IPluginAPI>();
_pluginsMutex = new Mutex(); _pluginsMutex = new Mutex();
} }
@ -32,48 +34,71 @@ namespace Zirconium.Core.Plugins
return; return;
} }
// create module loaders _currentPluginFolderPath = folderPath;
foreach (var dir in Directory.GetDirectories(folderPath)) foreach (var dir in Directory.GetDirectories(folderPath))
{ {
var dirName = Path.GetFileName(dir); var pluginName = Path.GetFileName(dir);
if (enabledPlugins.Where(x => x == dirName).FirstOrDefault() == null) { if (enabledPlugins.Where(x => x == pluginName).FirstOrDefault() == null)
{
continue; continue;
} }
var pluginDll = Path.Combine(dir, dirName + ".dll");
if (File.Exists(pluginDll)) var plugin = this.LoadPlugin(pluginName);
{ _pluginsMutex.WaitOne();
Logging.Log.Debug("found plugin " + dirName); _plugins[pluginName] = plugin;
Logging.Log.Debug("try to init plugin " + dirName); _pluginsMutex.ReleaseMutex();
var loader = PluginLoader.CreateFromAssemblyFile( }
pluginDll, }
sharedTypes: new[] {
public IPluginAPI LoadPlugin(string pluginName)
{
PluginLoader loader;
var pluginDll = Path.Combine(_currentPluginFolderPath, pluginName + ".dll");
if (File.Exists(pluginDll))
{
Logging.Log.Debug("Found plugin " + pluginName);
Logging.Log.Debug("Try to initialize plugin " + pluginName);
loader = PluginLoader.CreateFromAssemblyFile(
pluginDll,
sharedTypes: new[] {
typeof(IPluginAPI), typeof(IPluginAPI),
typeof(IPluginHostAPI), typeof(IPluginHostAPI),
typeof(IPluginManager),
typeof(IC2SMessageHandler), typeof(IC2SMessageHandler),
typeof(ICoreEventHandler), typeof(ICoreEventHandler),
typeof(BaseMessage), typeof(BaseMessage),
typeof(CoreEvent) typeof(CoreEvent)
} }
); );
loaders.Add(loader); }
} else
{
throw new Exception("specified plugin is not found");
} }
// Create an instance of module types IPluginAPI plugin = null;
foreach (var loader in loaders) foreach (var pluginType in loader
{
foreach (var pluginType in loader
.LoadDefaultAssembly() .LoadDefaultAssembly()
.GetTypes() .GetTypes()
.Where(t => typeof(IPluginAPI).IsAssignableFrom(t) && !t.IsAbstract)) .Where(t => typeof(IPluginAPI).IsAssignableFrom(t) && !t.IsAbstract))
{ {
// This assumes the implementation of IPlugin has a parameterless constructor // This assumes the implementation of IPlugin has a parameterless constructor
IPluginAPI plugin = (IPluginAPI)Activator.CreateInstance(pluginType); plugin = (IPluginAPI)Activator.CreateInstance(pluginType);
Logging.Log.Debug($"Created plugin instance '{plugin.GetPluginUniqueName()}'."); Logging.Log.Debug($"Created plugin instance '{plugin.GetPluginUniqueName()}'.");
plugin.Initialize(_pluginHostAPI); plugin.PreInitialize(this);
_plugins.Add(plugin); plugin.Initialize(_pluginHostAPI);
}
} }
return plugin;
}
public dynamic Depends(IPluginAPI currentPlugin, string pluginName)
{
var dependantPlugin = _plugins.GetValueOrDefault(pluginName, null);
if (dependantPlugin != null) return dependantPlugin.GetExportedAPI();
this.LoadPlugin(pluginName);
dependantPlugin = _plugins[pluginName];
return dependantPlugin.GetExportedAPI();
} }
} }
} }

View File

@ -15,13 +15,18 @@ namespace HelloWorldPlugin
hostModuleAPI.Hook(handler); hostModuleAPI.Hook(handler);
Log.Debug("plugin is initialized"); Log.Debug("plugin is initialized");
} }
public void PreInitialize(IPluginManager pluginManager) { }
public dynamic GetExportedAPI() { return null; }
} }
internal class C2SHandler : IC2SMessageHandler internal class C2SHandler : IC2SMessageHandler
{ {
private IPluginHostAPI hostModuleAPI; private IPluginHostAPI hostModuleAPI;
public C2SHandler(IPluginHostAPI hostModuleAPI) { public C2SHandler(IPluginHostAPI hostModuleAPI)
{
this.hostModuleAPI = hostModuleAPI; this.hostModuleAPI = hostModuleAPI;
} }