External plugins
This commit is contained in:
parent
04537e3a46
commit
e97c52212a
6 changed files with 124 additions and 26 deletions
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -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"),
|
||||
|
|
|
@ -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]
|
||||
|
||||
}
|
|
@ -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)) }
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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")
|
||||
)
|
||||
}
|
||||
},
|
||||
|
|
Loading…
Reference in a new issue