Browse Source

External plugins

ekardnam 4 years ago
parent
commit
e97c52212a

+ 17 - 0
src/main/scala/org/congressodeiradicali/karlmarx/Bot.scala

@@ -17,6 +17,8 @@
 
 package org.congressodeiradicali.karlmarx
 
+import java.io.File
+
 import com.bot4s.telegram.api.RequestHandler
 import com.bot4s.telegram.api.declarative.{Command, Commands}
 import com.bot4s.telegram.clients.ScalajHttpClient
@@ -52,6 +54,21 @@ class Bot(val token: String) extends TelegramBot
     plugin(new SetPlugin(this))
   )
 
+  // Load external plugins
+
+  val pluginLoader: PluginLoader = new JARPluginLoader()
+
+  private def loadExternalPlugins = {
+    val d = new File("plugins")
+    if (d.exists && d.isDirectory) {
+      d.listFiles().filter(_.isFile).map(pluginLoader.loadFromFile)
+    }
+  }
+
+  loadExternalPlugins
+
+  ////////////////////////
+
   // Future[Option[T]] is just two wrappers; remove the inner, useless one
   def collapseFutureOption[T](arg: Future[Option[T]]): Future[T] = arg.flatMap {
     case Some(x) => Future(x)

+ 65 - 0
src/main/scala/org/congressodeiradicali/karlmarx/JARPluginLoader.scala

@@ -0,0 +1,65 @@
+/*
+    This file is part of karl-marx.
+
+    karl-marx is free software: you can redistribute it and/or modify
+    it under the terms of the GNU Affero General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+
+    karl-marx 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 Affero General Public License for more details.
+
+    You should have received a copy of the GNU Affero General Public License
+    along with karl-marx.  If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package org.congressodeiradicali.karlmarx
+
+import java.io.File
+import java.net.URL
+import java.util.Properties
+import java.util.jar.JarFile
+
+import scala.reflect.internal.util.ScalaClassLoader.URLClassLoader
+import scala.util.{Failure, Success, Try}
+
+class JARPluginLoader extends PluginLoader {
+
+  final val MANIFEST_LOCATION = "plugin-manifest.properties"
+  // manifest structure is
+  // package=some.package
+  // class=PluginClassName
+
+
+  override def loadFromFile(file: File): Try[Plugin] = {
+    val jarFile = new JarFile(file)
+    val manifestInputStream = jarFile.getInputStream(jarFile.getEntry(MANIFEST_LOCATION))
+
+    val props = new Properties()
+    props.load(manifestInputStream)
+
+    manifestInputStream.close()
+
+    val `package` = props.getProperty("package")
+    val `class`   = props.getProperty("class")
+
+    val fullClassName = s"${`package`}.${`class`}"
+
+    try {
+      val url = file.toURI.toURL
+      val jarUrl = s"jar:${url.toString}!/"
+      val urls = Seq[URL](new URL(jarUrl))
+      val ucl = new URLClassLoader(urls, null)
+
+      // TODO deprecation
+      val plugin = Class.forName(fullClassName, true, ucl).newInstance().asInstanceOf[Plugin]
+      Success(plugin)
+    } catch {
+      case e: Throwable => Failure(e)
+    }
+
+  }
+
+}

+ 0 - 2
src/main/scala/org/congressodeiradicali/karlmarx/Localizer.scala

@@ -33,7 +33,6 @@ object Locales {
 
     (LocalizableString.BAN_UNAUTHORIZED, "Only an administrator can ban users"),
     (LocalizableString.BAN_SUCCESSFUL, "User was banned successfully"),
-    (LocalizableString.BAN_FAILED, "Cannot ban, something went wrong"),
     (LocalizableString.BAN_FAILED_INVALID_USER, "Cannot ban, invalid user"),
     (LocalizableString.BAN_FAILED_BAN_ADMIN, "Cannot ban an admin user"),
     (LocalizableString.BAN_FAILED_REPLY, "Please reply to a message to ban someone"),
@@ -49,7 +48,6 @@ object Locales {
 
     (LocalizableString.BAN_UNAUTHORIZED, "Solo un amministratore può bannare gli utenti"),
     (LocalizableString.BAN_SUCCESSFUL, "Utente bannato con successo"),
-    (LocalizableString.BAN_FAILED, "Non sono riuscito a bannare, qualcosa è andato storto"),
     (LocalizableString.BAN_FAILED_INVALID_USER, "Impossibile bannare, utente non valido"),
     (LocalizableString.BAN_FAILED_BAN_ADMIN, "Non puoi bannare un admin"),
     (LocalizableString.BAN_FAILED_REPLY, "Rispondi a un messaggio per bannare qualcuno"),

+ 28 - 0
src/main/scala/org/congressodeiradicali/karlmarx/PluginLoader.scala

@@ -0,0 +1,28 @@
+/*
+    This file is part of karl-marx.
+
+    karl-marx is free software: you can redistribute it and/or modify
+    it under the terms of the GNU Affero General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+
+    karl-marx 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 Affero General Public License for more details.
+
+    You should have received a copy of the GNU Affero General Public License
+    along with karl-marx.  If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package org.congressodeiradicali.karlmarx
+
+import java.io.File
+
+import scala.util.Try
+
+trait PluginLoader {
+
+  def loadFromFile(file: File): Try[Plugin]
+
+}

+ 14 - 24
src/main/scala/org/congressodeiradicali/karlmarx/coreplugins/BanPlugin.scala

@@ -18,11 +18,9 @@
 package org.congressodeiradicali.karlmarx.coreplugins
 
 import com.bot4s.telegram.api.declarative.{CommandFilterMagnet, CommandImplicits}
-import org.congressodeiradicali.karlmarx.LocalizableString.LocalizableString
 import org.congressodeiradicali.karlmarx._
 
 import scala.concurrent.Future
-import scala.util.{Failure, Success}
 
 class BanPlugin(bot: Bot) extends CorePlugin with CommandImplicits {
 
@@ -32,33 +30,25 @@ class BanPlugin(bot: Bot) extends CorePlugin with CommandImplicits {
   override val identifier: String = "ban"
 
   override var commandHandlers: Map[CommandFilterMagnet, CommandHandler] = Map {
-    stringToCommandFilter("ban") -> { (msg, argv) =>
-
-      var futureLocalizedString: Future[LocalizableString] = null
-
-      if (argv.length > 0) {
-
-      } else {
-        futureLocalizedString = msg.replyToMessage.fold {
-          Future { LocalizableString.BAN_FAILED_REPLY }
-        } { reply =>
-          reply.from.fold {
-            Future { LocalizableString.BAN_FAILED_INVALID_USER }
-          } { user =>
-            bot.requestBotUser(user, msg.chat).map { target =>
-               if (target.isAdmin || target.isCreator)
-                 LocalizableString.BAN_FAILED_BAN_ADMIN
-               else {
-                   target.ban()
-                   LocalizableString.BAN_SUCCESSFUL
-               }
+    stringToCommandFilter("ban") -> { (msg, _) =>
+
+      val futureLocalizedString = msg.replyToMessage.fold {
+        Future { LocalizableString.BAN_FAILED_REPLY }
+      } { reply =>
+        reply.from.fold {
+          Future { LocalizableString.BAN_FAILED_INVALID_USER }
+        } { user =>
+          bot.requestBotUser(user, msg.chat).map { target =>
+            if (target.isAdmin || target.isCreator)
+              LocalizableString.BAN_FAILED_BAN_ADMIN
+            else {
+              target.ban()
+              LocalizableString.BAN_SUCCESSFUL
             }
           }
         }
-
       }
 
-
       futureLocalizedString.map { s => Some(bot.localize(s)) }
     }
   }

+ 1 - 1
src/main/scala/org/congressodeiradicali/karlmarx/coreplugins/PluginManagerPlugin.scala

@@ -71,7 +71,7 @@ class PluginManagerPlugin(bot: Bot) extends CorePlugin with CommandImplicits {
         Some(
           bot.plugins.values.map { plugin =>
             s"${plugin.identifier}: ${plugin.name}. ${plugin.description}. License: ${plugin.license}. Author: ${plugin.author}"
-          }.mkString("\n")
+          }.mkString("\n\n")
         )
       }
     },