From f0883e97cca5079b086d701feb5a3b8d95c74133 Mon Sep 17 00:00:00 2001 From: Axwabo Date: Mon, 28 Aug 2023 18:55:51 +0200 Subject: [PATCH 1/5] assembly loading fix --- NwPluginAPI/Loader/AssemblyLoader.cs | 36 +++++++++++++------ .../Loader/PluginAssemblyInformation.cs | 24 +++++++++++++ 2 files changed, 49 insertions(+), 11 deletions(-) create mode 100644 NwPluginAPI/Loader/PluginAssemblyInformation.cs diff --git a/NwPluginAPI/Loader/AssemblyLoader.cs b/NwPluginAPI/Loader/AssemblyLoader.cs index 03801c3..05daa34 100644 --- a/NwPluginAPI/Loader/AssemblyLoader.cs +++ b/NwPluginAPI/Loader/AssemblyLoader.cs @@ -115,16 +115,23 @@ private static void LoadPlugins(PluginDirectory directory) var loadedAssemblies = AppDomain.CurrentDomain .GetAssemblies() .Select(x => - $"{x.GetName().Name}&r v&6{x.GetName().Version.ToString(3)}"); + $"{x.GetName().Name}&r v&6{x.GetName().Version.ToString(3)}") + .ToHashSet(); + + var loadedPluginAssemblies = new List(); + var pluginsToInitialize = new List(); foreach (string pluginPath in files) { if (!TryGetAssembly(pluginPath, out Assembly assembly)) continue; + loadedPluginAssemblies.Add(new PluginAssemblyInformation(pluginPath, assembly)); + loadedAssemblies.Add($"{assembly.GetName().Name}&r v&6{assembly.GetName().Version.ToString(3)}"); + } - Type[] types = null; - - var missingDependencies = assembly + foreach (var pluginInfo in loadedPluginAssemblies) + { + var missingDependencies = pluginInfo.Assembly .GetReferencedAssemblies() .Select(x => $"{x.Name}&r v&6{x.Version.ToString(3)}") @@ -133,21 +140,28 @@ private static void LoadPlugins(PluginDirectory directory) try { if (missingDependencies.Length != 0) - ResolveAssemblyEmbeddedResources(assembly); - types = assembly.GetTypes(); + ResolveAssemblyEmbeddedResources(pluginInfo.Assembly); + pluginInfo.Types = pluginInfo.Assembly.GetTypes(); + pluginsToInitialize.Add(pluginInfo); } catch (Exception e) { if (missingDependencies.Length != 0) { - Log.Error($"Failed loading plugin &2{Path.GetFileNameWithoutExtension(pluginPath)}&r, missing dependencies\n&2{string.Join("\n", missingDependencies.Select(x => $"&r - &2{x}&r"))}\n\n{e}", "Loader"); - continue; + Log.Error($"Failed loading plugin &2{Path.GetFileNameWithoutExtension(pluginInfo.Path)}&r, missing dependencies\n&2{string.Join("\n", missingDependencies.Select(x => "&r - &2" + x + "&r"))}\n\n{e}", "Loader"); + } + else + { + Log.Error("Failed loading plugin &2" + Path.GetFileNameWithoutExtension(pluginInfo.Path) + "&r, " + e, "Loader"); } - - Log.Error($"Failed loading plugin &2{Path.GetFileNameWithoutExtension(pluginPath)}&r, {e.ToString()}"); - continue; } + } + foreach (var pluginInfo in pluginsToInitialize) + { + var pluginPath = pluginInfo.Path; + var assembly = pluginInfo.Assembly; + var types = pluginInfo.Types; foreach (var entryType in types) { try diff --git a/NwPluginAPI/Loader/PluginAssemblyInformation.cs b/NwPluginAPI/Loader/PluginAssemblyInformation.cs new file mode 100644 index 0000000..c3b756c --- /dev/null +++ b/NwPluginAPI/Loader/PluginAssemblyInformation.cs @@ -0,0 +1,24 @@ +namespace PluginAPI.Loader +{ + + using System; + using System.Reflection; + + internal sealed class PluginAssemblyInformation + { + + public PluginAssemblyInformation(string path, Assembly assembly) + { + Path = path; + Assembly = assembly; + } + + public Type[] Types = Array.Empty(); + + public readonly string Path; + + public readonly Assembly Assembly; + + } + +} \ No newline at end of file From 631a639583cdf295a9f56f9d26722e665e1a359d Mon Sep 17 00:00:00 2001 From: Axwabo Date: Mon, 28 Aug 2023 19:23:55 +0200 Subject: [PATCH 2/5] add "initializing" message --- NwPluginAPI/Loader/AssemblyLoader.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/NwPluginAPI/Loader/AssemblyLoader.cs b/NwPluginAPI/Loader/AssemblyLoader.cs index 05daa34..ae107da 100644 --- a/NwPluginAPI/Loader/AssemblyLoader.cs +++ b/NwPluginAPI/Loader/AssemblyLoader.cs @@ -157,6 +157,7 @@ private static void LoadPlugins(PluginDirectory directory) } } + Log.Info($"Initializing &2{pluginsToInitialize.Count}&r plugins..."); foreach (var pluginInfo in pluginsToInitialize) { var pluginPath = pluginInfo.Path; From e3c706c43c92ca7ec5771ebabbc18e20a17cc8bd Mon Sep 17 00:00:00 2001 From: Axwabo Date: Fri, 1 Sep 2023 13:08:07 +0200 Subject: [PATCH 3/5] log missing dependencies when no exception was thrown --- NwPluginAPI/Loader/AssemblyLoader.cs | 23 ++++++++++++++++------- 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/NwPluginAPI/Loader/AssemblyLoader.cs b/NwPluginAPI/Loader/AssemblyLoader.cs index ae107da..8597920 100644 --- a/NwPluginAPI/Loader/AssemblyLoader.cs +++ b/NwPluginAPI/Loader/AssemblyLoader.cs @@ -135,18 +135,18 @@ private static void LoadPlugins(PluginDirectory directory) .GetReferencedAssemblies() .Select(x => $"{x.Name}&r v&6{x.Version.ToString(3)}") - .Where(x => !loadedAssemblies.Contains(x)).ToArray(); + .Where(x => !loadedAssemblies.Contains(x)).ToHashSet(); try { - if (missingDependencies.Length != 0) - ResolveAssemblyEmbeddedResources(pluginInfo.Assembly); + if (missingDependencies.Count != 0) + ResolveAssemblyEmbeddedResources(pluginInfo.Assembly, missingDependencies); pluginInfo.Types = pluginInfo.Assembly.GetTypes(); pluginsToInitialize.Add(pluginInfo); } catch (Exception e) { - if (missingDependencies.Length != 0) + if (missingDependencies.Count != 0) { Log.Error($"Failed loading plugin &2{Path.GetFileNameWithoutExtension(pluginInfo.Path)}&r, missing dependencies\n&2{string.Join("\n", missingDependencies.Select(x => "&r - &2" + x + "&r"))}\n\n{e}", "Loader"); } @@ -155,6 +155,11 @@ private static void LoadPlugins(PluginDirectory directory) Log.Error("Failed loading plugin &2" + Path.GetFileNameWithoutExtension(pluginInfo.Path) + "&r, " + e, "Loader"); } } + + if (missingDependencies.Count != 0) + { + Log.Error($"Failed loading plugin &2{Path.GetFileNameWithoutExtension(pluginInfo.Path)}&r, missing dependencies\n&2{string.Join("\n", missingDependencies.Select(x => "&r - &2" + x + "&r"))}", "Loader"); + } } Log.Info($"Initializing &2{pluginsToInitialize.Count}&r plugins..."); @@ -232,6 +237,7 @@ private static void LoadDependencies(string path) Log.Error($"Failed loading dependency &2{Path.GetFileNameWithoutExtension(dependencyPath)}&r.\n{ex}"); continue; } + successes++; } @@ -264,7 +270,8 @@ private static bool TryGetAssembly(string path, out Assembly assembly) /// Attempts to load Embedded assemblies (compressed) from the target /// /// Assembly to check for embedded assemblies - private static void ResolveAssemblyEmbeddedResources(Assembly target) + /// + private static void ResolveAssemblyEmbeddedResources(Assembly target, HashSet missingDependencies) { Log.Debug($"Attempting to load embedded resources for {target.FullName}", Log.DebugMode); @@ -286,7 +293,8 @@ private static void ResolveAssemblyEmbeddedResources(Assembly target) } dataStream.CopyTo(stream); - Assembly.Load(stream.ToArray()); + var assemblyName = Assembly.Load(stream.ToArray()).GetName(); + missingDependencies.Remove($"{assemblyName.Name}&r v&6{assemblyName.Version.ToString(3)}"); Log.Debug($"Loaded {name}", Log.DebugMode); } } @@ -304,7 +312,8 @@ private static void ResolveAssemblyEmbeddedResources(Assembly target) { Log.Debug($"Loading {name}", Log.DebugMode); stream.CopyTo(memStream); - Assembly.Load(memStream.ToArray()); + var assemblyName = Assembly.Load(memStream.ToArray()).GetName(); + missingDependencies.Remove($"{assemblyName.Name}&r v&6{assemblyName.Version.ToString(3)}"); Log.Debug($"Loaded {name}", Log.DebugMode); } } From 1a7a1f60702bcdacfdc4975b29a0aac1e4a19263 Mon Sep 17 00:00:00 2001 From: Axwabo Date: Fri, 1 Sep 2023 13:12:19 +0200 Subject: [PATCH 4/5] move deps count check --- NwPluginAPI/Loader/AssemblyLoader.cs | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/NwPluginAPI/Loader/AssemblyLoader.cs b/NwPluginAPI/Loader/AssemblyLoader.cs index 8597920..bdbe5a9 100644 --- a/NwPluginAPI/Loader/AssemblyLoader.cs +++ b/NwPluginAPI/Loader/AssemblyLoader.cs @@ -141,6 +141,12 @@ private static void LoadPlugins(PluginDirectory directory) { if (missingDependencies.Count != 0) ResolveAssemblyEmbeddedResources(pluginInfo.Assembly, missingDependencies); + if (missingDependencies.Count != 0) + { + Log.Error($"Failed loading plugin &2{Path.GetFileNameWithoutExtension(pluginInfo.Path)}&r, missing dependencies\n&2{string.Join("\n", missingDependencies.Select(x => "&r - &2" + x + "&r"))}", "Loader"); + continue; + } + pluginInfo.Types = pluginInfo.Assembly.GetTypes(); pluginsToInitialize.Add(pluginInfo); } @@ -155,11 +161,6 @@ private static void LoadPlugins(PluginDirectory directory) Log.Error("Failed loading plugin &2" + Path.GetFileNameWithoutExtension(pluginInfo.Path) + "&r, " + e, "Loader"); } } - - if (missingDependencies.Count != 0) - { - Log.Error($"Failed loading plugin &2{Path.GetFileNameWithoutExtension(pluginInfo.Path)}&r, missing dependencies\n&2{string.Join("\n", missingDependencies.Select(x => "&r - &2" + x + "&r"))}", "Loader"); - } } Log.Info($"Initializing &2{pluginsToInitialize.Count}&r plugins..."); From 278a04960d0d2839bff2b434d60e4f84330350b1 Mon Sep 17 00:00:00 2001 From: Axwabo Date: Sat, 2 Sep 2023 11:24:14 +0200 Subject: [PATCH 5/5] allow mismatched dependency versions --- NwPluginAPI/Loader/AssemblyLoader.cs | 32 +++++++++++++++++----------- 1 file changed, 20 insertions(+), 12 deletions(-) diff --git a/NwPluginAPI/Loader/AssemblyLoader.cs b/NwPluginAPI/Loader/AssemblyLoader.cs index bdbe5a9..ea303b1 100644 --- a/NwPluginAPI/Loader/AssemblyLoader.cs +++ b/NwPluginAPI/Loader/AssemblyLoader.cs @@ -114,9 +114,7 @@ private static void LoadPlugins(PluginDirectory directory) var loadedAssemblies = AppDomain.CurrentDomain .GetAssemblies() - .Select(x => - $"{x.GetName().Name}&r v&6{x.GetName().Version.ToString(3)}") - .ToHashSet(); + .ToDictionary(x => x.GetName().Name, x => x.GetName().Version); var loadedPluginAssemblies = new List(); var pluginsToInitialize = new List(); @@ -126,16 +124,19 @@ private static void LoadPlugins(PluginDirectory directory) if (!TryGetAssembly(pluginPath, out Assembly assembly)) continue; loadedPluginAssemblies.Add(new PluginAssemblyInformation(pluginPath, assembly)); - loadedAssemblies.Add($"{assembly.GetName().Name}&r v&6{assembly.GetName().Version.ToString(3)}"); + loadedAssemblies[assembly.GetName().Name] = assembly.GetName().Version; } foreach (var pluginInfo in loadedPluginAssemblies) { var missingDependencies = pluginInfo.Assembly .GetReferencedAssemblies() - .Select(x => - $"{x.Name}&r v&6{x.Version.ToString(3)}") - .Where(x => !loadedAssemblies.Contains(x)).ToHashSet(); + .Where(x => !loadedAssemblies.ContainsKey(x.Name)) + .ToDictionary(x => x.Name, x => x.Version); + var versionMismatch = pluginInfo.Assembly + .GetReferencedAssemblies() + .Where(x => loadedAssemblies.ContainsKey(x.Name) && loadedAssemblies[x.Name] != x.Version) + .ToDictionary(x => x.Name, x => (Expected: x.Version, Actual: loadedAssemblies[x.Name])); try { @@ -143,7 +144,7 @@ private static void LoadPlugins(PluginDirectory directory) ResolveAssemblyEmbeddedResources(pluginInfo.Assembly, missingDependencies); if (missingDependencies.Count != 0) { - Log.Error($"Failed loading plugin &2{Path.GetFileNameWithoutExtension(pluginInfo.Path)}&r, missing dependencies\n&2{string.Join("\n", missingDependencies.Select(x => "&r - &2" + x + "&r"))}", "Loader"); + Log.Error($"Failed loading plugin &2{Path.GetFileNameWithoutExtension(pluginInfo.Path)}&r, missing dependencies\n&2{string.Join("\n", missingDependencies.Select(x => "&r - &2" + x.Key + " v" + x.Value.ToString(3) + "&r"))}", "Loader"); continue; } @@ -154,12 +155,19 @@ private static void LoadPlugins(PluginDirectory directory) { if (missingDependencies.Count != 0) { - Log.Error($"Failed loading plugin &2{Path.GetFileNameWithoutExtension(pluginInfo.Path)}&r, missing dependencies\n&2{string.Join("\n", missingDependencies.Select(x => "&r - &2" + x + "&r"))}\n\n{e}", "Loader"); + Log.Error($"Failed loading plugin &2{Path.GetFileNameWithoutExtension(pluginInfo.Path)}&r, missing dependencies\n&2{string.Join("\n", missingDependencies.Select(x => "&r - &2" + x.Key + " v" + x.Value.ToString(3) + "&r"))}\n\n{e}", "Loader"); } else { Log.Error("Failed loading plugin &2" + Path.GetFileNameWithoutExtension(pluginInfo.Path) + "&r, " + e, "Loader"); } + + continue; + } + + if (versionMismatch.Count != 0) + { + Log.Warning($"Dependency version mismatch in plugin &2{Path.GetFileNameWithoutExtension(pluginInfo.Path)}&r\n&2{string.Join("\n", versionMismatch.Select(x => "&r - &2" + x.Key + " v" + x.Value.Actual.ToString(3) + " (expected version by plugin: " + x.Value.Expected.ToString(3) + ")" + "&r"))}", "Loader"); } } @@ -272,7 +280,7 @@ private static bool TryGetAssembly(string path, out Assembly assembly) /// /// Assembly to check for embedded assemblies /// - private static void ResolveAssemblyEmbeddedResources(Assembly target, HashSet missingDependencies) + private static void ResolveAssemblyEmbeddedResources(Assembly target, Dictionary missingDependencies) { Log.Debug($"Attempting to load embedded resources for {target.FullName}", Log.DebugMode); @@ -295,7 +303,7 @@ private static void ResolveAssemblyEmbeddedResources(Assembly target, HashSet