-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
8 changed files
with
126 additions
and
136 deletions.
There are no files selected for viewing
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,8 +1,6 @@ | ||
namespace Loader; | ||
|
||
public interface IModule : IDisposable | ||
public interface IPlugin | ||
{ | ||
string Name { get; } | ||
void Initialize(); | ||
void Unload(); | ||
void Initialize(PluginData pluginData); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
namespace Loader; | ||
|
||
public interface IPlugin | ||
{ | ||
public void Initialize(PluginData pluginData); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
namespace Loader; | ||
|
||
public abstract class EntryPointAttributeBase : Attribute | ||
{ | ||
internal abstract IPlugin CreateInstance(); | ||
} | ||
|
||
[AttributeUsage(AttributeTargets.Assembly)] | ||
public sealed class EntryPointAttribute<T> : EntryPointAttributeBase where T | ||
: IPlugin, new() | ||
{ | ||
internal override IPlugin CreateInstance() => new T(); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
using System.Reflection; | ||
using System.Runtime.Loader; | ||
|
||
namespace Loader; | ||
|
||
public class PluginData | ||
{ | ||
internal FileInfo FileInfo { get; } | ||
internal AssemblyLoadContext AssemblyLoadContext { get; } | ||
public event EventHandler? Unloading; | ||
|
||
internal PluginData(FileInfo file, AssemblyLoadContext context) | ||
{ | ||
FileInfo = file; | ||
AssemblyLoadContext = context; | ||
} | ||
|
||
internal bool Load() | ||
{ | ||
Assembly assembly; | ||
try | ||
{ | ||
assembly = AssemblyLoadContext.LoadFromAssemblyPath(FileInfo.FullName); | ||
} | ||
catch (BadImageFormatException) | ||
{ | ||
return false; | ||
} | ||
EntryPointAttributeBase? entry = assembly.GetCustomAttribute<EntryPointAttributeBase>(); | ||
if (entry is null) | ||
{ | ||
AssemblyLoadContext.Unload(); | ||
return false; | ||
} | ||
IPlugin plugin = entry.CreateInstance(); | ||
plugin.Initialize(this); | ||
return true; | ||
} | ||
|
||
internal void Unload() | ||
{ | ||
if (Unloading is not null) | ||
{ | ||
Unloading(this, new()); | ||
} | ||
AssemblyLoadContext.Unload(); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
using System.Runtime.Loader; | ||
|
||
namespace Loader; | ||
|
||
public class PluginData | ||
{ | ||
internal FileInfo FileInfo { get; } | ||
internal AssemblyLoadContext AssemblyLoadContext { get; } | ||
public event EventHandler? Unloading; | ||
|
||
internal PluginData(FileInfo file, AssemblyLoadContext context) | ||
{ | ||
FileInfo = file; | ||
AssemblyLoadContext = context; | ||
} | ||
internal void Unload() | ||
{ | ||
if (Unloading is not null) | ||
{ | ||
Unloading(this, new()); | ||
} | ||
AssemblyLoadContext.Unload(); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,107 +1,47 @@ | ||
using System.Reflection; | ||
using System.Runtime.CompilerServices; | ||
using System.Runtime.Loader; | ||
using System.Runtime.Loader; | ||
|
||
namespace Loader; | ||
|
||
internal static class PluginManager | ||
{ | ||
public static Dictionary<AssemblyLoadContext, List<IModule>> PluginContexts { get; } | ||
private static readonly Dictionary<string, PluginData> _pluginContexts; | ||
private static readonly string _pluginDirectoryPath; | ||
|
||
static PluginManager() | ||
{ | ||
PluginContexts = new(); | ||
_pluginContexts = new(); | ||
_pluginDirectoryPath = "plugins"; | ||
} | ||
|
||
public static IEnumerable<string> EnumerableAllDll() | ||
public static bool Load(FileInfo file) | ||
{ | ||
DirectoryInfo directoryInfo = new("plugins"); | ||
if (!directoryInfo.Exists) | ||
{ | ||
directoryInfo.Create(); | ||
} | ||
foreach (var file in directoryInfo.EnumerateFiles("*.dll")) | ||
{ | ||
yield return file.FullName; | ||
} | ||
AssemblyLoadContext loadContext = new(file.FullName); | ||
PluginData pluginData = new(file, loadContext); | ||
if (!pluginData.Load()) | ||
{ | ||
return false; | ||
} | ||
_pluginContexts[file.Name] = pluginData; | ||
return true; | ||
} | ||
|
||
[MethodImpl(MethodImplOptions.Synchronized)] | ||
public static void ReloadAllPlugin() | ||
public static bool Unload(string name) | ||
{ | ||
//uninstall loaded modules | ||
foreach (var (ctx, unload) in PluginContexts) | ||
{ | ||
try | ||
{ | ||
foreach (var module in unload) | ||
{ | ||
try | ||
{ | ||
module.Unload(); | ||
} | ||
catch (Exception e) | ||
{ | ||
Console.Error.WriteLine( | ||
"plugin {0} unload failed. file {1}. {2}", | ||
module.Name, | ||
ctx.Name, | ||
e | ||
); | ||
} | ||
} | ||
ctx.Unload(); | ||
} | ||
catch (Exception e) | ||
{ | ||
Console.Error.WriteLine("assembly unload failed {0}. {1}", ctx.Name, e); | ||
} | ||
} | ||
//clear PluginContexts | ||
PluginContexts.Clear(); | ||
//dict for sort | ||
SortedDictionary< | ||
ModuleEntryPointAttributeBase, | ||
(AssemblyLoadContext ctx, List<IModule> unload) | ||
> allEntryPoint = new(); | ||
//enumerate all dll and load all EntryPointAttribute | ||
//then sort by priority | ||
foreach (var file in EnumerableAllDll()) | ||
{ | ||
try | ||
{ | ||
AssemblyLoadContext loadContext = new(file); | ||
Assembly assembly = loadContext.LoadFromAssemblyPath(file); | ||
foreach ( | ||
var entryPoint in assembly.GetCustomAttributes<ModuleEntryPointAttributeBase>() | ||
) | ||
{ | ||
allEntryPoint.Add(entryPoint, new()); | ||
} | ||
} | ||
catch (Exception e) | ||
{ | ||
Console.Error.WriteLine("{0} load failed. {1}", file, e); | ||
} | ||
} | ||
//load all modules | ||
foreach (var (entryPoint, (_, modules)) in allEntryPoint) | ||
if (!_pluginContexts.ContainsKey(name)) | ||
{ | ||
try | ||
{ | ||
var module = entryPoint.CreateInstance(); | ||
module.Initialize(); //initialize module | ||
modules.Add(module); | ||
} | ||
catch (Exception ex) | ||
{ | ||
Console.WriteLine(ex); | ||
} | ||
return false; | ||
} | ||
//add all modules to PluginContexts | ||
foreach (var (_, (ctx, modules)) in allEntryPoint) | ||
_pluginContexts[name].Unload(); | ||
_pluginContexts.Remove(name); | ||
return true; | ||
} | ||
|
||
public static IEnumerable<FileInfo> EnumerableAllFiles() | ||
{ | ||
DirectoryInfo directoryInfo = new(_pluginDirectoryPath); | ||
foreach (FileInfo file in directoryInfo.EnumerateFiles()) | ||
{ | ||
PluginContexts.Add(ctx, modules); | ||
yield return file; | ||
} | ||
} | ||
} |