diff --git a/src/mod/languages/mod_managed/managed/Loader.cs b/src/mod/languages/mod_managed/managed/Loader.cs index e3803ae427..e81157d1b6 100644 --- a/src/mod/languages/mod_managed/managed/Loader.cs +++ b/src/mod/languages/mod_managed/managed/Loader.cs @@ -141,7 +141,9 @@ namespace FreeSWITCH { static void watcher_Changed(object sender, FileSystemEventArgs e) { Action queueFile = fileName => { - var currentPi = pluginInfos.FirstOrDefault(p => string.Compare(fileName, p.FileName, StringComparison.OrdinalIgnoreCase) == 0); + var currentPi = pluginInfos + .Where(x => !string.IsNullOrEmpty(x.FileName)) + .FirstOrDefault(p => string.Compare(fileName, p.FileName, StringComparison.OrdinalIgnoreCase) == 0); if (currentPi != null) { var noReload = currentPi.Manager.ApiExecutors.Any(x => (x.PluginOptions & PluginOptions.NoAutoReload) == PluginOptions.NoAutoReload) || currentPi.Manager.AppExecutors.Any(x => (x.PluginOptions & PluginOptions.NoAutoReload) == PluginOptions.NoAutoReload); @@ -259,7 +261,7 @@ namespace FreeSWITCH { System.Threading.Interlocked.Increment(ref appDomainCount); setup.ApplicationName = Path.GetFileName(fileName) + "_" + appDomainCount; var domain = AppDomain.CreateDomain(setup.ApplicationName, null, setup); - + PluginManager pm; try { pm = (PluginManager)domain.CreateInstanceAndUnwrap(pmType.Assembly.FullName, pmType.FullName, null); @@ -276,9 +278,17 @@ namespace FreeSWITCH { return; } + addPlugin(fileName, domain, pm); + } + + static void addPlugin(string fileName, AppDomain domain, PluginManager pm) { // Update dictionaries atomically lock (loaderLock) { - unloadFile(fileName); + if (!string.IsNullOrEmpty(fileName)) { + if (domain == null) throw new ApplicationException("File based plugins must specify an AppDomain."); + unloadFile(fileName); + } + if (domain == null) domain = AppDomain.CurrentDomain; var pi = new PluginInfo { FileName = fileName, Domain = domain, Manager = pm }; pluginInfos.Add(pi); @@ -298,6 +308,11 @@ namespace FreeSWITCH { } } + public static void LoadEmbeddedPlugins(Assembly asm) { + var pm = new EmbeddedPluginManager(asm); + addPlugin(null, null, pm); + } + static void unloadFile(string fileName) { List pisToRemove; lock (loaderLock) { diff --git a/src/mod/languages/mod_managed/managed/PluginManager.cs b/src/mod/languages/mod_managed/managed/PluginManager.cs index f9bcf7f5b5..c5900e19b6 100644 --- a/src/mod/languages/mod_managed/managed/PluginManager.cs +++ b/src/mod/languages/mod_managed/managed/PluginManager.cs @@ -250,7 +250,7 @@ namespace FreeSWITCH { } } - public void BlockUntilUnloadIsSafe() { + public virtual void BlockUntilUnloadIsSafe() { if (isUnloading) throw new InvalidOperationException("PluginManager is already unloading."); isUnloading = true; unloadCount = ApiExecutors.Count + AppExecutors.Count; @@ -310,4 +310,36 @@ namespace FreeSWITCH { } + internal class EmbeddedPluginManager : PluginManager { + + // This is for cases where FreeSWITCH is "embedded", that is a .NET app hosts the FS core lib itself. + // In such a case, there may be plugins defined in the main process that need to share address space + // and be loaded from the main assembly. This class plus changes in Loader.cs (null filenames=embedded) + // work together to allow such plugins to work. These plugins cannot be reloaded. + + Assembly asm; + public EmbeddedPluginManager(Assembly asm) { + this.asm = asm; + var allTypes = asm.GetExportedTypes(); + var opts = GetOptions(allTypes); + AddApiPlugins(allTypes, opts); + AddAppPlugins(allTypes, opts); + } + + protected override bool LoadInternal(string fileName) { + throw new NotImplementedException("EmbeddedPluginManager should not have Load[Internal] called."); + } + + public override void BlockUntilUnloadIsSafe() { + throw new NotImplementedException("EmbeddedPluginManager should never be unloaded."); + } + + } + + public static class EmbeddedLoader { + public static void LoadEmbeddedPlugins(Assembly asm) { + Loader.LoadEmbeddedPlugins(asm); + } + } + }