123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115 |
- /*
- 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 com.bot4s.telegram.api.RequestHandler
- import com.bot4s.telegram.api.declarative.{Command, Commands}
- import com.bot4s.telegram.clients.ScalajHttpClient
- import com.bot4s.telegram.future.{Polling, TelegramBot}
- import com.bot4s.telegram.methods.{GetChatMember, GetMe}
- import com.bot4s.telegram.models.{Chat, ChatId, User}
- import org.congressodeiradicali.karlmarx.coreplugins.{BanPlugin, EchoPlugin, PluginManagerPlugin, SetPlugin}
- import slogging.{LogLevel, LoggerConfig, PrintLoggerFactory}
- import scala.concurrent.{ExecutionContext, Future}
- class Bot(val token: String) extends TelegramBot
- with Polling
- with Commands[Future] {
- LoggerConfig.factory = PrintLoggerFactory()
- // set log level, e.g. to TRACE
- LoggerConfig.level = LogLevel.TRACE
- val localizer = new Localizer("it_IT")
- def localize(s: LocalizableString.Value) = localizer.getString(s)
- override val client: RequestHandler[Future] = new ScalajHttpClient(token)
- val redis = new RedisAsyncClient(sys.env("REDIS_HOST"), 6379)
- private def plugin(plugin: Plugin) = plugin.identifier -> plugin
- var plugins: Map[String, Plugin] = Map(
- plugin(new PluginManagerPlugin(this)),
- plugin(new BanPlugin(this)),
- plugin(new EchoPlugin(this)),
- 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)
- case None => Future.failed(new RuntimeException("Future contains null option"))
- }
- def runAgainst(handlerPair: Plugin#CommandHandlerPair, botUser: Option[User], cmd: Command): Boolean = {
- handlerPair._1
- .to(botUser.flatMap(_.username)) // Apply filter to bot username
- .accept(cmd)
- }
- onExtMessage { case (message, botUser) =>
- val argv: Array[String] = message.text match {
- case Some(text) => text.split(" ")
- case None => Array()
- }
- val enabledPlugins = plugins.values filter(_.enabled)
- val messagesFuture = Future.sequence(enabledPlugins
- .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))
- .map(pair => pair._2(message, argv))
- .map(collapseFutureOption)
- .map(maybeResponse => maybeResponse.flatMap { response => reply(response)(message) })
- ).flatMap(_ => Future{unit})
- }(message)
- Future.sequence(List(messagesFuture, commandsFuture)).flatMap(_ => Future{unit}) // Discard the content
- }
- def requestBotUser(user: User, chat: Chat) =
- request(GetChatMember(ChatId.fromChat(chat.id), user.id)).map {
- chatMember => new BotUser(user, chat, this, chatMember)
- }(ExecutionContext.global)
- }
|