add a simple plugin system
This commit is contained in:
7
Pilz.Plugins/IPlugin.cs
Normal file
7
Pilz.Plugins/IPlugin.cs
Normal file
@@ -0,0 +1,7 @@
|
||||
namespace Pilz.Plugins
|
||||
{
|
||||
public interface IPlugin
|
||||
{
|
||||
public string Name { get; }
|
||||
}
|
||||
}
|
||||
9
Pilz.Plugins/Pilz.Plugins.csproj
Normal file
9
Pilz.Plugins/Pilz.Plugins.csproj
Normal file
@@ -0,0 +1,9 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net6.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
|
||||
</Project>
|
||||
40
Pilz.Plugins/PluginLoadContext.cs
Normal file
40
Pilz.Plugins/PluginLoadContext.cs
Normal file
@@ -0,0 +1,40 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Runtime.Loader;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Pilz.Plugins
|
||||
{
|
||||
internal class PluginLoadContext : AssemblyLoadContext
|
||||
{
|
||||
private readonly AssemblyDependencyResolver _resolver;
|
||||
|
||||
public PluginLoadContext(string pluginPath)
|
||||
{
|
||||
_resolver = new AssemblyDependencyResolver(pluginPath);
|
||||
}
|
||||
|
||||
protected override Assembly? Load(AssemblyName assemblyName)
|
||||
{
|
||||
var assemblyPath = _resolver.ResolveAssemblyToPath(assemblyName);
|
||||
|
||||
if (assemblyPath != null)
|
||||
return LoadFromAssemblyPath(assemblyPath);
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
protected override IntPtr LoadUnmanagedDll(string unmanagedDllName)
|
||||
{
|
||||
var libraryPath = _resolver.ResolveUnmanagedDllToPath(unmanagedDllName);
|
||||
|
||||
if (libraryPath != null)
|
||||
return LoadUnmanagedDllFromPath(libraryPath);
|
||||
|
||||
return IntPtr.Zero;
|
||||
}
|
||||
}
|
||||
}
|
||||
14
Pilz.Plugins/PluginManager.cs
Normal file
14
Pilz.Plugins/PluginManager.cs
Normal file
@@ -0,0 +1,14 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Pilz.Plugins
|
||||
{
|
||||
public class PluginManager : PluginManager<IPlugin, PluginRuntimeInfo>
|
||||
{
|
||||
public static PluginManager Instance { get; private set; } = new();
|
||||
}
|
||||
}
|
||||
71
Pilz.Plugins/PluginManagerT.cs
Normal file
71
Pilz.Plugins/PluginManagerT.cs
Normal file
@@ -0,0 +1,71 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Pilz.Plugins
|
||||
{
|
||||
public class PluginManager<TPluginInterface, TPluginRuntimeInfo> where TPluginInterface : class where TPluginRuntimeInfo : PluginRuntimeInfo<TPluginInterface>
|
||||
{
|
||||
public static IEnumerable<TPluginRuntimeInfo> LoadPlugins(string[] paths)
|
||||
{
|
||||
var states = new List<TPluginRuntimeInfo>();
|
||||
|
||||
foreach (string path in paths)
|
||||
states.Add(LoadPlugin(path));
|
||||
|
||||
return states;
|
||||
}
|
||||
|
||||
public static TPluginRuntimeInfo LoadPlugin(string path)
|
||||
{
|
||||
var info = Activator.CreateInstance<TPluginRuntimeInfo>();
|
||||
var irmplugin = typeof(TPluginInterface);
|
||||
var loadContext = new PluginLoadContext(path);
|
||||
Assembly? assembly = null;
|
||||
|
||||
if (File.Exists(path))
|
||||
{
|
||||
try
|
||||
{
|
||||
assembly = loadContext.LoadFromAssemblyName(new AssemblyName(Path.GetFileNameWithoutExtension(path)));
|
||||
}
|
||||
catch
|
||||
{
|
||||
info.Status = PluginStatus.ErrorAtLoading;
|
||||
}
|
||||
}
|
||||
else
|
||||
info.Status = PluginStatus.FileNotFound;
|
||||
|
||||
if (assembly != null)
|
||||
{
|
||||
foreach (var type in assembly.GetTypes())
|
||||
{
|
||||
if (info.Plugin == null && irmplugin.IsAssignableFrom(type))
|
||||
{
|
||||
try
|
||||
{
|
||||
if (Activator.CreateInstance(type) is TPluginInterface plugin)
|
||||
{
|
||||
info.Plugin = plugin;
|
||||
info.Status = PluginStatus.Success;
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
info.Status = PluginStatus.ErrorAtInitializing;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (info.Plugin == null)
|
||||
info.Status = PluginStatus.NoValidPlugin;
|
||||
}
|
||||
|
||||
return info;
|
||||
}
|
||||
}
|
||||
}
|
||||
12
Pilz.Plugins/PluginRuntimeInfo.cs
Normal file
12
Pilz.Plugins/PluginRuntimeInfo.cs
Normal file
@@ -0,0 +1,12 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Pilz.Plugins
|
||||
{
|
||||
public class PluginRuntimeInfo : PluginRuntimeInfo<IPlugin>
|
||||
{
|
||||
}
|
||||
}
|
||||
14
Pilz.Plugins/PluginRuntimeInfoT.cs
Normal file
14
Pilz.Plugins/PluginRuntimeInfoT.cs
Normal file
@@ -0,0 +1,14 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Pilz.Plugins
|
||||
{
|
||||
public class PluginRuntimeInfo<T> where T : class
|
||||
{
|
||||
public T? Plugin { get; internal set; }
|
||||
public PluginStatus Status { get; internal set; }
|
||||
}
|
||||
}
|
||||
18
Pilz.Plugins/PluginStatus.cs
Normal file
18
Pilz.Plugins/PluginStatus.cs
Normal file
@@ -0,0 +1,18 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Pilz.Plugins
|
||||
{
|
||||
public enum PluginStatus
|
||||
{
|
||||
None,
|
||||
Success,
|
||||
FileNotFound,
|
||||
ErrorAtLoading,
|
||||
ErrorAtInitializing,
|
||||
NoValidPlugin
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user