Add Set plugin, message handlers for plugins
This commit is contained in:
parent
4baedb0804
commit
55c179bc49
7 changed files with 76 additions and 23 deletions
|
@ -22,8 +22,9 @@ import com.bot4s.telegram.api.declarative.{Command, Commands}
|
||||||
import com.bot4s.telegram.clients.ScalajHttpClient
|
import com.bot4s.telegram.clients.ScalajHttpClient
|
||||||
import com.bot4s.telegram.future.{Polling, TelegramBot}
|
import com.bot4s.telegram.future.{Polling, TelegramBot}
|
||||||
import com.bot4s.telegram.models.{Message, User}
|
import com.bot4s.telegram.models.{Message, User}
|
||||||
import org.congressodeiradicali.karlmarx.coreplugins.{BanPlugin, EchoPlugin, PluginManagerPlugin}
|
import org.congressodeiradicali.karlmarx.coreplugins.{BanPlugin, EchoPlugin, PluginManagerPlugin, SetPlugin}
|
||||||
import slogging.{LogLevel, LoggerConfig, PrintLoggerFactory}
|
import slogging.{LogLevel, LoggerConfig, PrintLoggerFactory}
|
||||||
|
import com.redis._
|
||||||
|
|
||||||
import scala.concurrent.Future
|
import scala.concurrent.Future
|
||||||
|
|
||||||
|
@ -40,40 +41,51 @@ class Bot(val token: String) extends TelegramBot
|
||||||
|
|
||||||
override val client: RequestHandler[Future] = new ScalajHttpClient(token)
|
override val client: RequestHandler[Future] = new ScalajHttpClient(token)
|
||||||
|
|
||||||
|
val redis = new RedisClient(sys.env("REDIS_HOST"), 6379)
|
||||||
|
|
||||||
def getLogger() = logger
|
def getLogger() = logger
|
||||||
|
|
||||||
var plugins: Map[String, Plugin] = Map(
|
var plugins: Map[String, Plugin] = Map(
|
||||||
"pluginmanager" -> new PluginManagerPlugin(this),
|
"pluginmanager" -> new PluginManagerPlugin(this),
|
||||||
"ban" -> new BanPlugin(this),
|
"ban" -> new BanPlugin(this),
|
||||||
"echo" -> new EchoPlugin(this)
|
"echo" -> new EchoPlugin(this),
|
||||||
|
"set" -> new SetPlugin(this)
|
||||||
)
|
)
|
||||||
|
|
||||||
def runAgainst(handlerPair: Plugin#HandlerPair, botUser: Option[User], cmd: Command): Boolean = {
|
// 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)
|
||||||
|
case None => Future.failed(new RuntimeException("Future contains null option"))
|
||||||
|
}
|
||||||
|
|
||||||
|
def runAgainst(handlerPair: Plugin#CommandHandlerPair, botUser: Option[User], cmd: Command): Boolean = {
|
||||||
handlerPair._1
|
handlerPair._1
|
||||||
.to(botUser.flatMap(_.username)) // Apply filter to bot username
|
.to(botUser.flatMap(_.username)) // Apply filter to bot username
|
||||||
.accept(cmd)
|
.accept(cmd)
|
||||||
}
|
}
|
||||||
|
|
||||||
def runHandler(handlerPair: Plugin#HandlerPair, message: Message, argv: Array[String]): Future[String] = {
|
|
||||||
handlerPair._2(message, argv).flatMap {
|
|
||||||
case Some(s) => Future(s)
|
|
||||||
case None => Future.failed(new RuntimeException("Handler did not return a message"))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
onExtMessage { case (message, botUser) =>
|
onExtMessage { case (message, botUser) =>
|
||||||
val argv: Array[String] = message.text match {
|
val argv: Array[String] = message.text match {
|
||||||
case Some(text) => text.split(" ")
|
case Some(text) => text.split(" ")
|
||||||
case None => Array()
|
case None => Array()
|
||||||
}
|
}
|
||||||
using(command) { cmd =>
|
val enabledPlugins = plugins.values filter(_.enabled)
|
||||||
Future.sequence(plugins.values
|
|
||||||
.filter(_.enabled)
|
val messagesFuture = Future.sequence(enabledPlugins
|
||||||
.flatMap(_.handlers)
|
.flatMap(_.messageHandlers)
|
||||||
|
.map(handler => handler(message))
|
||||||
|
.map(collapseFutureOption)
|
||||||
|
.map(maybeResponse => maybeResponse.flatMap { response => reply(response)(message) })
|
||||||
|
)
|
||||||
|
val commandsFuture = using(command) { cmd =>
|
||||||
|
Future.sequence(enabledPlugins
|
||||||
|
.flatMap(_.commandHandlers)
|
||||||
.filter(pair => runAgainst(pair, botUser, cmd))
|
.filter(pair => runAgainst(pair, botUser, cmd))
|
||||||
.map(runHandler(_, message, argv))
|
.map(pair => pair._2(message, argv))
|
||||||
.map(it => it.flatMap { it => reply(it)(message) })
|
.map(collapseFutureOption)
|
||||||
).flatMap(_ => Future{unit}) // Discard the content
|
.map(maybeResponse => maybeResponse.flatMap { response => reply(response)(message) })
|
||||||
|
).flatMap(_ => Future{unit})
|
||||||
}(message)
|
}(message)
|
||||||
|
Future.sequence(List(messagesFuture, commandsFuture)).flatMap(_ => Future{unit}) // Discard the content
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -21,6 +21,7 @@ import org.congressodeiradicali.karlmarx.Locales.Locale
|
||||||
|
|
||||||
object LocalizableString extends Enumeration {
|
object LocalizableString extends Enumeration {
|
||||||
type LocalizableString = Value
|
type LocalizableString = Value
|
||||||
|
val DONE = Value
|
||||||
val BAN_UNAUTHORIZED, BAN_SUCCESSFUL, BAN_FAILED, BAN_FAILED_INVALID_USER, BAN_FAILED_BAN_ADMIN, BAN_FAILED_REPLY, KICK_UNAUTHORIZED = Value
|
val BAN_UNAUTHORIZED, BAN_SUCCESSFUL, BAN_FAILED, BAN_FAILED_INVALID_USER, BAN_FAILED_BAN_ADMIN, BAN_FAILED_REPLY, KICK_UNAUTHORIZED = Value
|
||||||
val NO_SUCH_PLUGIN, PLUGIN_ENABLED, PLUGIN_DISABLED = Value
|
val NO_SUCH_PLUGIN, PLUGIN_ENABLED, PLUGIN_DISABLED = Value
|
||||||
}
|
}
|
||||||
|
@ -28,6 +29,8 @@ object LocalizableString extends Enumeration {
|
||||||
object Locales {
|
object Locales {
|
||||||
type Locale = Map[LocalizableString.Value, String]
|
type Locale = Map[LocalizableString.Value, String]
|
||||||
val ENGLISH_LOCALE: Locale = Map(
|
val ENGLISH_LOCALE: Locale = Map(
|
||||||
|
(LocalizableString.DONE, "Done"),
|
||||||
|
|
||||||
(LocalizableString.BAN_UNAUTHORIZED, "Only an administrator can ban users"),
|
(LocalizableString.BAN_UNAUTHORIZED, "Only an administrator can ban users"),
|
||||||
(LocalizableString.BAN_SUCCESSFUL, "User was banned successfully"),
|
(LocalizableString.BAN_SUCCESSFUL, "User was banned successfully"),
|
||||||
(LocalizableString.BAN_FAILED, "Cannot ban, something went wrong"),
|
(LocalizableString.BAN_FAILED, "Cannot ban, something went wrong"),
|
||||||
|
@ -42,6 +45,8 @@ object Locales {
|
||||||
)
|
)
|
||||||
|
|
||||||
val ITALIAN_LOCALE: Locale = Map(
|
val ITALIAN_LOCALE: Locale = Map(
|
||||||
|
(LocalizableString.DONE, "Fatto"),
|
||||||
|
|
||||||
(LocalizableString.BAN_UNAUTHORIZED, "Solo un amministratore può bannare gli utenti"),
|
(LocalizableString.BAN_UNAUTHORIZED, "Solo un amministratore può bannare gli utenti"),
|
||||||
(LocalizableString.BAN_SUCCESSFUL, "Utente bannato con successo"),
|
(LocalizableString.BAN_SUCCESSFUL, "Utente bannato con successo"),
|
||||||
(LocalizableString.BAN_FAILED, "Non sono riuscito a bannare, qualcosa è andato storto"),
|
(LocalizableString.BAN_FAILED, "Non sono riuscito a bannare, qualcosa è andato storto"),
|
||||||
|
|
|
@ -6,8 +6,9 @@ import com.bot4s.telegram.models.Message
|
||||||
import scala.concurrent.Future
|
import scala.concurrent.Future
|
||||||
|
|
||||||
trait Plugin {
|
trait Plugin {
|
||||||
type Handler = (Message, Array[String]) => Future[Option[String]]
|
type MessageHandler = Message => Future[Option[String]]
|
||||||
type HandlerPair = (CommandFilterMagnet, Handler)
|
type CommandHandler = (Message, Array[String]) => Future[Option[String]]
|
||||||
|
type CommandHandlerPair = (CommandFilterMagnet, CommandHandler)
|
||||||
|
|
||||||
// Do not set this manually, it is handled by PluginManager
|
// Do not set this manually, it is handled by PluginManager
|
||||||
var enabled = false
|
var enabled = false
|
||||||
|
@ -23,5 +24,6 @@ trait Plugin {
|
||||||
*/
|
*/
|
||||||
val identifier: String
|
val identifier: String
|
||||||
|
|
||||||
var handlers: Map[CommandFilterMagnet, Handler]
|
var messageHandlers: List[MessageHandler]
|
||||||
|
var commandHandlers: Map[CommandFilterMagnet, CommandHandler]
|
||||||
}
|
}
|
|
@ -13,7 +13,7 @@ class BanPlugin(bot: Bot) extends CorePlugin with CommandImplicits {
|
||||||
|
|
||||||
override val identifier: String = "ban"
|
override val identifier: String = "ban"
|
||||||
|
|
||||||
override var handlers: Map[CommandFilterMagnet, Handler] = Map {
|
override var commandHandlers: Map[CommandFilterMagnet, CommandHandler] = Map {
|
||||||
stringToCommandFilter("ban") -> { (msg, _) =>
|
stringToCommandFilter("ban") -> { (msg, _) =>
|
||||||
|
|
||||||
implicit val ec: ExecutionContext = ExecutionContext.global
|
implicit val ec: ExecutionContext = ExecutionContext.global
|
||||||
|
@ -37,4 +37,5 @@ class BanPlugin(bot: Bot) extends CorePlugin with CommandImplicits {
|
||||||
futureLocalizedString.map { s => Some(bot.localize(s)) }
|
futureLocalizedString.map { s => Some(bot.localize(s)) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
override var messageHandlers: List[MessageHandler] = List()
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,7 +12,8 @@ class EchoPlugin(bot: Bot) extends CorePlugin with CommandImplicits {
|
||||||
|
|
||||||
override val identifier: String = "echo"
|
override val identifier: String = "echo"
|
||||||
|
|
||||||
override var handlers: Map[CommandFilterMagnet, Handler] = Map(
|
override var commandHandlers: Map[CommandFilterMagnet, CommandHandler] = Map(
|
||||||
stringToCommandFilter("echo") -> { (_, argv) => Future { Some(argv.drop(1).mkString(" ")) }(ExecutionContext.global) }
|
stringToCommandFilter("echo") -> { (_, argv) => Future { Some(argv.drop(1).mkString(" ")) }(ExecutionContext.global) }
|
||||||
)
|
)
|
||||||
|
override var messageHandlers: List[MessageHandler] = List()
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,7 +28,7 @@ class PluginManagerPlugin(bot: Bot) extends CorePlugin with CommandImplicits {
|
||||||
true
|
true
|
||||||
} else false
|
} else false
|
||||||
|
|
||||||
override var handlers: Map[CommandFilterMagnet, Handler] = Map(
|
override var commandHandlers: Map[CommandFilterMagnet, CommandHandler] = Map(
|
||||||
stringToCommandFilter("enable") -> { (_: Message, argv: Array[String]) =>
|
stringToCommandFilter("enable") -> { (_: Message, argv: Array[String]) =>
|
||||||
val name = argv(1)
|
val name = argv(1)
|
||||||
val response = if (enableByIdentifier(name))
|
val response = if (enableByIdentifier(name))
|
||||||
|
@ -54,4 +54,5 @@ class PluginManagerPlugin(bot: Bot) extends CorePlugin with CommandImplicits {
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
)
|
)
|
||||||
|
override var messageHandlers: List[MessageHandler] = List()
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,31 @@
|
||||||
|
package org.congressodeiradicali.karlmarx.coreplugins
|
||||||
|
|
||||||
|
import com.bot4s.telegram.api.declarative.{CommandFilterMagnet, CommandImplicits}
|
||||||
|
import com.bot4s.telegram.models.Message
|
||||||
|
import org.congressodeiradicali.karlmarx.{Bot, LocalizableString}
|
||||||
|
|
||||||
|
import scala.concurrent.{ExecutionContext, Future}
|
||||||
|
|
||||||
|
class SetPlugin(bot: Bot) extends CorePlugin with CommandImplicits {
|
||||||
|
override val name: String = "Set Plugin"
|
||||||
|
override val description: String = "A plugin to set responses to triggers."
|
||||||
|
|
||||||
|
override val identifier: String = "set"
|
||||||
|
|
||||||
|
override var commandHandlers: Map[CommandFilterMagnet, CommandHandler] = Map(
|
||||||
|
stringToCommandFilter("set") -> { (_, argv) =>
|
||||||
|
val trigger = argv(1)
|
||||||
|
val response = argv.drop(2).mkString(" ") // Drop command + trigger
|
||||||
|
bot.redis.set("PLUGIN_SET_" + trigger, response)
|
||||||
|
Future { Some(bot.localize(LocalizableString.DONE)) }(ExecutionContext.global)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
override var messageHandlers: List[MessageHandler] = List(
|
||||||
|
{ msg: Message => Future {
|
||||||
|
msg.text.flatMap { text =>
|
||||||
|
val firstWord = text.takeWhile(_ != ' ')
|
||||||
|
bot.redis.get("PLUGIN_SET_" + firstWord)
|
||||||
|
}
|
||||||
|
}(ExecutionContext.global) }
|
||||||
|
)
|
||||||
|
}
|
Loading…
Reference in a new issue