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