public static void ShutdownAllBackgroundThreads() { IsShuttingDown = true; CTS.Cancel(); SessionLog.Info("Shutting down"); Log.Information("Shutting down workers..."); WorkSpawner.Shutdown(); Log.Information("Shutting down counter monitor..."); SignalR.HomeDashboard.DotNetCoreCounterListener.Instance?.Stop(); Log.Information("Shutting down stats counter..."); Performance.StatsDB.Shutdown(); Log.Information("Shutting down common notifications..."); Hubs.CommonNotificationThread.Instance?.Shutdown(); Log.Information("Shutting down exception logger..."); ExceptionLogger.Instance?.Shutdown(); Log.Information("Shutting down background thread plugins..."); BackgroundThreadPluginManager.Instance?.Shutdown(); Log.Information("Shutting down real-time tracker..."); RealtimeTrackerThread.Instance.Shutdown(); Log.Information("Shutting down data collector..."); DataCollectorThread.Instance.Shutdown(); Log.Information("Shutting jsDAL health monitor..."); jsDALHealthMonitorThread.Instance.Shutdown(); Log.Information("Shutting down session log..."); SessionLog.Shutdown(); }
private void ParseAndLoadPluginAssembly(AssemblyLoadContext asmCtx, Assembly assembly, string inlineEntryId = null) { if (ParsePluginAssembly(assembly, out var pluginInfoList, out var errorList, checkForConflict: true)) { foreach (var pluginInfo in pluginInfoList) { SessionLog.Info($"{(inlineEntryId != null ? "(Inline) " : "")}Plugin '{pluginInfo.Name}' ({pluginInfo.Guid}) found in assembly: {assembly.FullName}"); var existing = PluginAssemblies.FirstOrDefault(a => a.Assembly == assembly); if (existing == null) { var newPA = new PluginAssembly(asmCtx, assembly, inlineEntryId); newPA.AddPlugin(pluginInfo); _pluginAssemblies.Add(newPA); } else { existing.AddPlugin(pluginInfo); } } } }
private void CompileCodeIntoAssemblyContext(InlineModuleManifestEntry inlineEntry, string code) { var ctxName = $"Inline Plugin Context {++_asmCtxCounter}"; var pluginPath = Path.GetFullPath("plugins"); var asmCtx = new PluginAssemblyLoadContext(pluginPath, ctxName, true /*enable unloading*/); ASM_CTXES.Add(asmCtx); SessionLog.Info($"Created {ctxName} for {inlineEntry.Name}".PadRight(35)); var assemblyBytes = CSharpCompilerHelper.CompileIntoAssembly(inlineEntry.Name, code, out var problems); if ((problems != null && problems.Count == 0)) { Assembly assembly = null; try { using (var ms = new MemoryStream(assemblyBytes)) { assembly = asmCtx.LoadFromStream(ms); ParseAndLoadPluginAssembly(asmCtx, assembly, inlineEntry.Id); } } catch (Exception ee) { SessionLog.Error($"Failed to load inline plugin assembly '{assembly?.FullName}' {inlineEntry.Name}/{inlineEntry.Id}. See exception that follows."); SessionLog.Exception(ee); } } else { SessionLog.Error($"Inline plugin {inlineEntry.Name} ({inlineEntry.Id}) failed to compile with the following error(s): {string.Join(", ", problems)}"); } }
public async Task InitAsync() { // load from plugin directory try { // AppDomain.CurrentDomain.AssemblyResolve += (sender, e) => // { // try // { // var asmName = new AssemblyName(e.Name); // var requestingLocation = e.RequestingAssembly.Location; // var requestingDir = Path.GetDirectoryName(requestingLocation); // // look for a dll in the same location as the requesting assembly // var path = Path.Combine(requestingDir, asmName.Name + ".dll"); // if (!File.Exists(path)) return null; // Assembly.LoadFrom(path); // return null; // } // catch // { // return null; // } // }; var pluginPath = Path.GetFullPath("plugins"); if (Directory.Exists("./plugins")) { var dllCollection = Directory.EnumerateFiles("plugins", "*.dll", SearchOption.TopDirectoryOnly); foreach (var dllPath in dllCollection) { // skip jsdal-plugin base if (dllPath.Equals("plugins\\jsdal-plugin.dll", StringComparison.OrdinalIgnoreCase)) { continue; } try { var ctxName = $"Plugin Context {++_asmCtxCounter}"; var asmCtx = new PluginAssemblyLoadContext(pluginPath, ctxName, true /*enable unloading*/); ASM_CTXES.Add(asmCtx); SessionLog.Info($"Created {ctxName} for {dllPath}".PadRight(35)); var dllFullPath = Path.GetFullPath(dllPath); var pluginAssembly = asmCtx.LoadFromAssemblyPath(dllFullPath); ParseAndLoadPluginAssembly(asmCtx, pluginAssembly, null); } catch (Exception ee) { SessionLog.Error("Failed to load plugin DLL '{0}'. See exception that follows.", dllPath); SessionLog.Exception(ee); } } } } catch (Exception ex) { SessionLog.Exception(ex); } // load inline assemblies try { foreach (var inlineEntry in InlineModuleManifest.Instance.Entries) { var sourcePath = Path.Combine(InlinePluginSourcePath, inlineEntry.Id); if (File.Exists(sourcePath)) { var code = await File.ReadAllTextAsync(sourcePath); CompileCodeIntoAssemblyContext(inlineEntry, code); } else { SessionLog.Error($"Inline module {inlineEntry.Name} not found at '{sourcePath}'"); } } } catch (Exception ex) { SessionLog.Exception(ex); } // init server-wide types // try // { // InitServerWidePlugins(); // } // catch (Exception ex) // { // SessionLog.Exception(ex); // } }
private void OnUnloading(AssemblyLoadContext ctx) { SessionLog.Info($"Unloading assembly context {ctx.Name}"); PluginLoader.RemoveAssemblyContextRef(this); }