internal static void LoadAndInitializePlugins(TalknetEnv env) { var pluginsCache = new List <LoadedPlugin>(); pluginsCache.AddRange(LoadSelf()); pluginsCache.AddRange(LoadFromPluginDirectory()); // unique foreach (var plugin in pluginsCache) { var name = plugin.Info.Name; if (Plugins.ContainsKey(name)) { if (plugin.PluginInstance.GetType().IsInstanceOfType(Plugins[name].PluginInstance)) { continue; } throw new PluginLoadingException(string.Format(ErrMsg.PluginSameName, name, Plugins[name], plugin)); } Plugins[name] = plugin; } // check requirements var refs = new DAG <string>(Plugins.Keys); foreach (var plugin in pluginsCache) { var thisName = plugin.Info.Name; foreach (var req in plugin.Requirements) { var reqName = req.Requirement; if (!Plugins.ContainsKey(reqName)) { throw PluginLoadingException.ErrorReqNotSatisfied(plugin, reqName); } switch (req.Order) { case LoadOrderType.ThisFirst: refs.AddEdge(thisName, reqName); break; case LoadOrderType.RequiredFirst: refs.AddEdge(reqName, thisName); break; default: continue; } } } _order = null; try { _order = refs.TopologicalOrder(); } catch (NotADagException) { throw new PluginLoadingException(ErrMsg.LoadOrderCannotBeSatisfied); } foreach (var it in _order) { Plugins[it].PluginInstance.PluginInitialize(env); } }
// do not handle exceptions, just throw them internal static IEnumerable <LoadedPlugin> LoadFromAssembly(Assembly ass, string from) { var cache = new List <LoadedPlugin>(); TalknetPluginAssemblyAttribute attrAssembly; if ((attrAssembly = ass.GetCustomAttribute(typeof(TalknetPluginAssemblyAttribute)) as TalknetPluginAssemblyAttribute) == null) { return(new LoadedPlugin[0]); } var pluginsProvided = attrAssembly.Plugins; if (pluginsProvided == null || pluginsProvided.Length == 0) { throw new PluginLoadingException(Clet.AssemblyNoPluginList, from); } foreach (var pluginType in pluginsProvided) { if (pluginType == null) { throw new PluginLoadingException(Clet.PluginListNullItem, from); } if (!pluginType.GetInterfaces().Contains(typeof(ITalknetPlugin))) { throw new PluginLoadingException(Clet.PluginNoInterface, from, pluginType.FullName); } TalknetPluginAttribute attr = null; try { if (pluginType.GetCustomAttribute(typeof(TalknetPluginAttribute)) is TalknetPluginAttribute v) { attr = v; } } catch (Exception ex) { throw PluginLoadingException.ErrorGettingAttr(from, pluginType.FullName, ex); } if (attr == null) { throw new PluginLoadingException(Clet.PluginNoAttribute, from, pluginType.FullName); } // so it is var info = attr.Info; var ins = Activator.CreateInstance(pluginType) as ITalknetPlugin; var requirements = pluginType.GetCustomAttributes(typeof(RequireAttribute)).Select(t => t as RequireAttribute); if (!_pluginNameRegex.IsMatch(info.Name)) { throw new PluginLoadingException(Clet.PluginInvalidName, from, pluginType.FullName); } cache.Add(new LoadedPlugin { Info = info, PluginInstance = ins, Source = from, Requirements = requirements.ToArray() }); } return(cache); }