From c7d0e963f9309bba5a49f61d70a62368506bb64c Mon Sep 17 00:00:00 2001 From: "Andres G. Aragoneses" Date: Fri, 4 Nov 2016 22:52:47 +0800 Subject: [PATCH] Core/Engines: migrate to MonoAddins infrastructure Only for the backend for now. (TODO: Load frontends with mono-addins too.) This integration work opens the door for more add-in management love, such as loading/unloading capabilities at runtime, installing/updating add-ins from remote repositories (via Cydin[1]), etc. [1] https://github.com/slluis/cydin --- .travis.yml | 2 +- configure.ac | 3 + src/Engine-Campfire/Engine-Campfire.addin.xml | 22 +++++ src/Engine-Campfire/Engine-Campfire.csproj | 5 ++ src/Engine-Campfire/Makefile.am | 7 +- src/Engine-IRC/Engine-IRC.addin.xml | 22 +++++ src/Engine-IRC/Engine-IRC.csproj | 5 ++ src/Engine-IRC/Makefile.am | 3 +- src/Engine-JabbR/Engine-JabbR.addin.xml | 22 +++++ src/Engine-JabbR/Engine-JabbR.csproj | 5 ++ src/Engine-JabbR/Makefile.am | 7 +- src/Engine-Twitter/Engine-Twitter.addin.xml | 22 +++++ src/Engine-Twitter/Engine-Twitter.csproj | 5 ++ src/Engine-Twitter/Makefile.am | 7 +- src/Engine-XMPP/Engine-XMPP.addin.xml | 23 +++++ src/Engine-XMPP/Engine-XMPP.csproj | 5 ++ src/Engine-XMPP/Makefile.am | 8 +- src/Engine/AddinHost.cs | 25 ++++++ src/Engine/Engine.csproj | 4 + src/Engine/Makefile.am | 2 + .../Protocols/ProtocolManagerFactory.cs | 85 ++++++------------- 21 files changed, 219 insertions(+), 70 deletions(-) create mode 100644 src/Engine-Campfire/Engine-Campfire.addin.xml create mode 100644 src/Engine-IRC/Engine-IRC.addin.xml create mode 100644 src/Engine-JabbR/Engine-JabbR.addin.xml create mode 100644 src/Engine-Twitter/Engine-Twitter.addin.xml create mode 100644 src/Engine-XMPP/Engine-XMPP.addin.xml create mode 100644 src/Engine/AddinHost.cs diff --git a/.travis.yml b/.travis.yml index c80b99209..82d9917ff 100644 --- a/.travis.yml +++ b/.travis.yml @@ -23,7 +23,7 @@ install: - sudo apt-get build-dep smuxi > /dev/null - sudo apt-get install devscripts equivs > /dev/null - sudo mk-build-deps --install debian/control > /dev/null - - sudo apt-get install mono-devel nunit-console moreutils gtk-sharp2-gapi libgtkspell-dev > /dev/null + - sudo apt-get install mono-devel nunit-console moreutils gtk-sharp2-gapi libgtkspell-dev libmono-addins-cil-dev > /dev/null script: - ./autogen.sh MCS=/usr/bin/dmcs diff --git a/configure.ac b/configure.ac index d19501086..487e311f2 100644 --- a/configure.ac +++ b/configure.ac @@ -242,6 +242,9 @@ fi AC_SUBST(XBUILD_FLAGS) # Required Libraries +PKG_CHECK_MODULES(MONO_ADDINS, mono-addins >= 1.0) +AC_SUBST(MONO_ADDINS_LIBS) + PKG_CHECK_MODULES([LOG4NET], [log4net]) PKG_CHECK_EXISTS([nini-1.1], FOUND_NINI=yes, FOUND_NINI=no) diff --git a/src/Engine-Campfire/Engine-Campfire.addin.xml b/src/Engine-Campfire/Engine-Campfire.addin.xml new file mode 100644 index 000000000..4dc6f952a --- /dev/null +++ b/src/Engine-Campfire/Engine-Campfire.addin.xml @@ -0,0 +1,22 @@ + + + + + + + + + + + + diff --git a/src/Engine-Campfire/Engine-Campfire.csproj b/src/Engine-Campfire/Engine-Campfire.csproj index 4311eb553..cfcff9d22 100644 --- a/src/Engine-Campfire/Engine-Campfire.csproj +++ b/src/Engine-Campfire/Engine-Campfire.csproj @@ -69,4 +69,9 @@ ServiceStack.Interfaces + + + Enging-Campfire.addin.xml + + \ No newline at end of file diff --git a/src/Engine-Campfire/Makefile.am b/src/Engine-Campfire/Makefile.am index 7c89dfd14..cebdb3b77 100644 --- a/src/Engine-Campfire/Makefile.am +++ b/src/Engine-Campfire/Makefile.am @@ -11,6 +11,9 @@ SOURCES = \ Protocols/Campfire/CampfireEventStream.cs \ Protocols/Campfire/DTO.cs +RESOURCES = \ + Engine-Campfire.addin.xml + REFERENCES = \ System \ System.Web \ @@ -36,5 +39,5 @@ include $(top_srcdir)/Makefile.include all: $(ASSEMBLY_TARGET) -$(ASSEMBLY_TARGET) $(ASSEMBLY_TARGET).mdb: $(SOURCES) $(DLL_REFERENCES) - $(CSC) $(CSC_FLAGS) $(build_references_ref) -target:library -out:$(ASSEMBLY_TARGET) $(SOURCES_BUILD) +$(ASSEMBLY_TARGET) $(ASSEMBLY_TARGET).mdb: $(SOURCES) $(DLL_REFERENCES) $(build_resources) + $(CSC) $(CSC_FLAGS) $(build_references_ref) -target:library -out:$(ASSEMBLY_TARGET) $(SOURCES_BUILD) $(build_resources_embed) diff --git a/src/Engine-IRC/Engine-IRC.addin.xml b/src/Engine-IRC/Engine-IRC.addin.xml new file mode 100644 index 000000000..9253c2670 --- /dev/null +++ b/src/Engine-IRC/Engine-IRC.addin.xml @@ -0,0 +1,22 @@ + + + + + + + + + + + + diff --git a/src/Engine-IRC/Engine-IRC.csproj b/src/Engine-IRC/Engine-IRC.csproj index fba339f53..675ed2432 100644 --- a/src/Engine-IRC/Engine-IRC.csproj +++ b/src/Engine-IRC/Engine-IRC.csproj @@ -79,4 +79,9 @@ + + + Engine-IRC.addin.xml + + \ No newline at end of file diff --git a/src/Engine-IRC/Makefile.am b/src/Engine-IRC/Makefile.am index 8ed53dda7..bbc999a0d 100644 --- a/src/Engine-IRC/Makefile.am +++ b/src/Engine-IRC/Makefile.am @@ -71,7 +71,8 @@ FILES = \ DATA_FILES = -RESOURCES = +RESOURCES = \ + Engine-IRC.addin.xml EXTRAS = \ smuxi-engine-irc.pc.in diff --git a/src/Engine-JabbR/Engine-JabbR.addin.xml b/src/Engine-JabbR/Engine-JabbR.addin.xml new file mode 100644 index 000000000..e094fb9ce --- /dev/null +++ b/src/Engine-JabbR/Engine-JabbR.addin.xml @@ -0,0 +1,22 @@ + + + + + + + + + + + + diff --git a/src/Engine-JabbR/Engine-JabbR.csproj b/src/Engine-JabbR/Engine-JabbR.csproj index 9129518ea..2b381bf35 100644 --- a/src/Engine-JabbR/Engine-JabbR.csproj +++ b/src/Engine-JabbR/Engine-JabbR.csproj @@ -63,4 +63,9 @@ + + + Engine-JabbR.addin.xml + + \ No newline at end of file diff --git a/src/Engine-JabbR/Makefile.am b/src/Engine-JabbR/Makefile.am index 140958eb8..3a8a65f61 100644 --- a/src/Engine-JabbR/Makefile.am +++ b/src/Engine-JabbR/Makefile.am @@ -9,6 +9,9 @@ SOURCES = \ JabbrMessageBuilder.cs \ JabbrProtocolManager.cs +RESOURCES = \ + Engine-JabbR.addin.xml + REFERENCES = \ System \ System.Web \ @@ -33,5 +36,5 @@ include $(top_srcdir)/Makefile.include all: $(ASSEMBLY_TARGET) -$(ASSEMBLY_TARGET) $(ASSEMBLY_TARGET).mdb: $(SOURCES) $(DLL_REFERENCES) - $(CSC) $(CSC_FLAGS) $(build_references_ref) -target:library -out:$(ASSEMBLY_TARGET) $(SOURCES_BUILD) +$(ASSEMBLY_TARGET) $(ASSEMBLY_TARGET).mdb: $(SOURCES) $(DLL_REFERENCES) $(build_resources) + $(CSC) $(CSC_FLAGS) $(build_references_ref) -target:library -out:$(ASSEMBLY_TARGET) $(SOURCES_BUILD) $(build_resources_embed) diff --git a/src/Engine-Twitter/Engine-Twitter.addin.xml b/src/Engine-Twitter/Engine-Twitter.addin.xml new file mode 100644 index 000000000..4942b9e8e --- /dev/null +++ b/src/Engine-Twitter/Engine-Twitter.addin.xml @@ -0,0 +1,22 @@ + + + + + + + + + + + + diff --git a/src/Engine-Twitter/Engine-Twitter.csproj b/src/Engine-Twitter/Engine-Twitter.csproj index b1266fdf1..59b776950 100644 --- a/src/Engine-Twitter/Engine-Twitter.csproj +++ b/src/Engine-Twitter/Engine-Twitter.csproj @@ -69,4 +69,9 @@ + + + Engine-Twitter.addin.xml + + \ No newline at end of file diff --git a/src/Engine-Twitter/Makefile.am b/src/Engine-Twitter/Makefile.am index ee35f3351..ee63c25ec 100644 --- a/src/Engine-Twitter/Makefile.am +++ b/src/Engine-Twitter/Makefile.am @@ -11,6 +11,9 @@ SOURCES = \ Protocols/Twitter/TwitterMessageBuilder.cs \ Protocols/Twitter/TwitterSearchStream.cs +RESOURCES = \ + Engine-Twitter.addin.xml + REFERENCES = $(LOG4NET_LIBS) \ $(SMARTIRC4NET_LIBS) \ System.Web \ @@ -37,5 +40,5 @@ include $(top_srcdir)/Makefile.include all: $(ASSEMBLY_TARGET) -$(ASSEMBLY_TARGET): $(SOURCES) $(DLL_REFERENCES) - $(MCS) $(CSC_FLAGS) $(build_references_ref) -target:library -out:$(ASSEMBLY_TARGET) $(SOURCES_BUILD) +$(ASSEMBLY_TARGET): $(SOURCES) $(DLL_REFERENCES) $(build_resources) + $(MCS) $(CSC_FLAGS) $(build_references_ref) -target:library -out:$(ASSEMBLY_TARGET) $(SOURCES_BUILD) $(build_resources_embed) diff --git a/src/Engine-XMPP/Engine-XMPP.addin.xml b/src/Engine-XMPP/Engine-XMPP.addin.xml new file mode 100644 index 000000000..4cbd51819 --- /dev/null +++ b/src/Engine-XMPP/Engine-XMPP.addin.xml @@ -0,0 +1,23 @@ + + + + + + + + + + + + + diff --git a/src/Engine-XMPP/Engine-XMPP.csproj b/src/Engine-XMPP/Engine-XMPP.csproj index 0e8121077..7ce13f4cb 100644 --- a/src/Engine-XMPP/Engine-XMPP.csproj +++ b/src/Engine-XMPP/Engine-XMPP.csproj @@ -74,4 +74,9 @@ + + + Engine-XMPP.addin.xml + + diff --git a/src/Engine-XMPP/Makefile.am b/src/Engine-XMPP/Makefile.am index f66ee9774..bd4f576c3 100644 --- a/src/Engine-XMPP/Makefile.am +++ b/src/Engine-XMPP/Makefile.am @@ -11,6 +11,9 @@ SOURCES = \ Protocols/Xmpp/XmppProtocolManager.cs \ Config/XmppPersonModel.cs +RESOURCES = \ + Engine-XMPP.addin.xml + REFERENCES = \ System \ System.Core \ @@ -35,5 +38,6 @@ include $(top_srcdir)/Makefile.include all: $(ASSEMBLY_TARGET) -$(ASSEMBLY_TARGET) $(ASSEMBLY_TARGET).mdb: $(SOURCES) $(DLL_REFERENCES) - $(CSC) $(CSC_FLAGS) $(build_references_ref) -target:library -out:$(ASSEMBLY_TARGET) $(SOURCES_BUILD) +$(ASSEMBLY_TARGET) $(ASSEMBLY_TARGET).mdb: $(SOURCES) $(DLL_REFERENCES) $(build_resources) + $(CSC) $(CSC_FLAGS) $(build_references_ref) -target:library -out:$(ASSEMBLY_TARGET) $(SOURCES_BUILD) $(build_resources_embed) + diff --git a/src/Engine/AddinHost.cs b/src/Engine/AddinHost.cs new file mode 100644 index 000000000..405112cf0 --- /dev/null +++ b/src/Engine/AddinHost.cs @@ -0,0 +1,25 @@ +// Smuxi - Smart MUltipleXed Irc +// +// Copyright (c) 2016 Andrés G. Aragoneses +// +// Full GPL License: +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +using Mono.Addins; + +[assembly:AddinRoot("smuxi-engine", "1.1")] +[assembly:AddinDescription("This add-in root provides the engine extension point for add-in protocols to hook")] +[assembly:ExtensionPoint("/Smuxi/Server/Engine", NodeName="Engine")] diff --git a/src/Engine/Engine.csproj b/src/Engine/Engine.csproj index 717332e9a..2cbe7fe67 100644 --- a/src/Engine/Engine.csproj +++ b/src/Engine/Engine.csproj @@ -44,6 +44,7 @@ + @@ -150,6 +151,9 @@ + + mono-addins + diff --git a/src/Engine/Makefile.am b/src/Engine/Makefile.am index 2168cec20..ffd81b6f1 100644 --- a/src/Engine/Makefile.am +++ b/src/Engine/Makefile.am @@ -49,6 +49,7 @@ all: $(ASSEMBLY) $(PROGRAMFILES) $(LINUX_PKGCONFIG) FILES = \ ../AssemblyVersion.cs \ AssemblyInfo.cs \ + AddinHost.cs \ CertificateValidator.cs \ CommandModel.cs \ Engine.cs \ @@ -134,6 +135,7 @@ REFERENCES = \ System.Xml \ Mono.Posix \ Mono.Data.Sqlite \ + $(MONO_ADDINS_LIBS) \ $(NINI_LIBS) \ $(LOG4NET_LIBS) \ $(DB4O_LIBS) \ diff --git a/src/Engine/Protocols/ProtocolManagerFactory.cs b/src/Engine/Protocols/ProtocolManagerFactory.cs index c0140ea0e..cda82e71e 100644 --- a/src/Engine/Protocols/ProtocolManagerFactory.cs +++ b/src/Engine/Protocols/ProtocolManagerFactory.cs @@ -8,6 +8,7 @@ * Smuxi - Smart MUltipleXed Irc * * Copyright (c) 2005-2006 Mirco Bauer + * Copyright (c) 2016 Andrés G. Aragoneses * * Full GPL License: * @@ -30,6 +31,9 @@ using System.IO; using System.Reflection; using System.Collections.Generic; + +using Mono.Addins; + using Smuxi.Common; namespace Smuxi.Engine @@ -50,80 +54,41 @@ public IList ProtocolManagerInfos { public ProtocolManagerFactory() { } - - public void LoadProtocolManager(string filename) + + public void LoadAllProtocolManagers(string path) { - Trace.Call(filename); - - Assembly asm = Assembly.LoadFile(filename); - Type[] types; - try { - types = asm.GetTypes(); - } catch (ReflectionTypeLoadException ex) { -#if LOG4NET - _Logger.WarnFormat( - "LoadProtocolManager(): GetTypes() on {0} threw exceptions", - filename - ); - foreach (var loaderEx in ex.LoaderExceptions) { - _Logger.Warn( - "LoadProtocolManager(): LoaderException: ", - loaderEx - ); - _Logger.Warn( - "LoadProtocolManager(): LoaderException.InnerException: ", - loaderEx.InnerException - ); - } -#endif - types = ex.Types; - } - - foreach (Type type in types) { - if (type.IsAbstract) { - continue; - } - - Type foundType = null; - Type[] interfaceTypes = type.GetInterfaces(); - foreach (Type interfaceType in interfaceTypes) { - if (interfaceType == typeof(IProtocolManager)) { + Trace.Call(path); + + AddinManager.AddinLoadError += (o, a) => { + //try { + // AddinManager.Registry.DisableAddin (a.AddinId); + //} catch {} + throw new Exception(a.Message, a.Exception); + }; + + AddinManager.Initialize(path); + + var engineAddinNodes = AddinManager.GetExtensionNodes("/Smuxi/Server/Engine"); + + foreach(TypeExtensionNode protocolManagerNode in engineAddinNodes) { + Type foundType = protocolManagerNode.Type; #if LOG4NET - _Logger.Debug("LoadProtocolManager(): found " + type); + _Logger.Debug("LoadAllProtocolManagers(): found " + foundType); #endif - foundType = type; - break; - } - } - - if (foundType == null) { - continue; - } - // let's get the info attribute object[] attrs = foundType.GetCustomAttributes(typeof(ProtocolManagerInfoAttribute), true); if (attrs == null || attrs.Length == 0) { throw new ArgumentException("Assembly contains IProtocolManager but misses ProtocolManagerInfoAttribute", "filename"); //continue; } - + ProtocolManagerInfoAttribute attr = (ProtocolManagerInfoAttribute) attrs[0]; ProtocolManagerInfoModel info = new ProtocolManagerInfoModel(attr.Name, attr.Description, attr.Alias); - + _ProtocolManagerTypes.Add(info, foundType); } } - public void LoadAllProtocolManagers(string path) - { - Trace.Call(path); - - string[] filenames = Directory.GetFiles(path, "smuxi-engine*.dll"); - foreach (string filename in filenames) { - LoadProtocolManager(filename); - } - } - public ProtocolManagerInfoModel GetProtocolManagerInfoByAlias(string alias) { foreach (ProtocolManagerInfoModel info in _ProtocolManagerTypes.Keys) { @@ -155,7 +120,7 @@ public IProtocolManager CreateProtocolManager(ProtocolManagerInfoModel info, Ses if (session == null) { throw new ArgumentNullException("session"); } - + Type type = _ProtocolManagerTypes[info]; return (IProtocolManager) Activator.CreateInstance(type, session); }