diff --git a/src/main/scala/org/congressodeiradicali/karlmarx/Bot.scala b/src/main/scala/org/congressodeiradicali/karlmarx/Bot.scala index 3ca4261..6e89a31 100644 --- a/src/main/scala/org/congressodeiradicali/karlmarx/Bot.scala +++ b/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) diff --git a/src/main/scala/org/congressodeiradicali/karlmarx/JARPluginLoader.scala b/src/main/scala/org/congressodeiradicali/karlmarx/JARPluginLoader.scala new file mode 100644 index 0000000..8ac225e --- /dev/null +++ b/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 . + */ + +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) + } + + } + +} diff --git a/src/main/scala/org/congressodeiradicali/karlmarx/Localizer.scala b/src/main/scala/org/congressodeiradicali/karlmarx/Localizer.scala index 3b83637..5e8604a 100644 --- a/src/main/scala/org/congressodeiradicali/karlmarx/Localizer.scala +++ b/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"), diff --git a/src/main/scala/org/congressodeiradicali/karlmarx/PluginLoader.scala b/src/main/scala/org/congressodeiradicali/karlmarx/PluginLoader.scala new file mode 100644 index 0000000..9cb613a --- /dev/null +++ b/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 . + */ + +package org.congressodeiradicali.karlmarx + +import java.io.File + +import scala.util.Try + +trait PluginLoader { + + def loadFromFile(file: File): Try[Plugin] + +} diff --git a/src/main/scala/org/congressodeiradicali/karlmarx/coreplugins/BanPlugin.scala b/src/main/scala/org/congressodeiradicali/karlmarx/coreplugins/BanPlugin.scala index 076d72c..f2ad0b5 100644 --- a/src/main/scala/org/congressodeiradicali/karlmarx/coreplugins/BanPlugin.scala +++ b/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) => + stringToCommandFilter("ban") -> { (msg, _) => - 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 - } + 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)) } } } diff --git a/src/main/scala/org/congressodeiradicali/karlmarx/coreplugins/PluginManagerPlugin.scala b/src/main/scala/org/congressodeiradicali/karlmarx/coreplugins/PluginManagerPlugin.scala index 0370d40..56d742c 100644 --- a/src/main/scala/org/congressodeiradicali/karlmarx/coreplugins/PluginManagerPlugin.scala +++ b/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") ) } },