From 6b961a3de3a36c568be98ab2b2f69137d7b20968 Mon Sep 17 00:00:00 2001 From: Eyre_S Date: Thu, 21 Dec 2023 14:19:20 +0800 Subject: [PATCH] add coeur lifecycles, add MornyCoeur.externalContext --- project/MornyConfiguration.scala | 2 +- .../cc/sukazyo/cono/morny/MornyCoeur.scala | 101 +++++++++++++++--- .../sukazyo/cono/morny/MornyCoreModule.scala | 99 +++++++++++++++++ .../cc/sukazyo/cono/morny/MornyModule.scala | 24 +++++ .../cc/sukazyo/cono/morny/ServerMain.scala | 4 +- .../sukazyo/cono/morny/bot/api/EventEnv.scala | 23 +--- ...mmands.scala => MornyCommandManager.scala} | 69 +++--------- .../morny/bot/event/MornyEventListeners.scala | 25 ----- .../morny/bot/event/MornyOnInlineQuery.scala | 5 +- .../bot/event/MornyOnTelegramCommand.scala | 11 +- .../morny/bot/event/OnUniMeowTrigger.scala | 9 +- ...yQueries.scala => MornyQueryManager.scala} | 16 ++- .../cono/morny/daemon/MornyReport.scala | 4 +- .../cono/morny/util/GivenContext.scala | 58 ++++++++++ 14 files changed, 309 insertions(+), 141 deletions(-) create mode 100644 src/main/scala/cc/sukazyo/cono/morny/MornyCoreModule.scala create mode 100644 src/main/scala/cc/sukazyo/cono/morny/MornyModule.scala rename src/main/scala/cc/sukazyo/cono/morny/bot/command/{MornyCommands.scala => MornyCommandManager.scala} (62%) delete mode 100644 src/main/scala/cc/sukazyo/cono/morny/bot/event/MornyEventListeners.scala rename src/main/scala/cc/sukazyo/cono/morny/bot/query/{MornyQueries.scala => MornyQueryManager.scala} (62%) create mode 100644 src/main/scala/cc/sukazyo/cono/morny/util/GivenContext.scala diff --git a/project/MornyConfiguration.scala b/project/MornyConfiguration.scala index b6422b7..0c5052f 100644 --- a/project/MornyConfiguration.scala +++ b/project/MornyConfiguration.scala @@ -8,7 +8,7 @@ object MornyConfiguration { val MORNY_CODE_STORE = "https://github.com/Eyre-S/Coeur-Morny-Cono" val MORNY_COMMIT_PATH = "https://github.com/Eyre-S/Coeur-Morny-Cono/commit/%s" - val VERSION = "2.0.0-alpha3" + val VERSION = "2.0.0-alpha5" val VERSION_DELTA: Option[String] = None val CODENAME = "guanggu" diff --git a/src/main/scala/cc/sukazyo/cono/morny/MornyCoeur.scala b/src/main/scala/cc/sukazyo/cono/morny/MornyCoeur.scala index c17eb9b..9d29c51 100644 --- a/src/main/scala/cc/sukazyo/cono/morny/MornyCoeur.scala +++ b/src/main/scala/cc/sukazyo/cono/morny/MornyCoeur.scala @@ -1,19 +1,19 @@ package cc.sukazyo.cono.morny -import cc.sukazyo.cono.morny.bot.command.MornyCommands +import cc.sukazyo.cono.morny.bot.command.MornyCommandManager import cc.sukazyo.cono.morny.daemon.MornyDaemons import cc.sukazyo.cono.morny.Log.{exceptionLog, logger} -import cc.sukazyo.cono.morny.MornyCoeur.{TestRun, THREAD_SERVER_EXIT} +import cc.sukazyo.cono.morny.MornyCoeur.* import cc.sukazyo.cono.morny.bot.api.EventListenerManager -import cc.sukazyo.cono.morny.bot.event.{MornyEventListeners, MornyOnInlineQuery, MornyOnTelegramCommand, MornyOnUpdateTimestampOffsetLock} -import cc.sukazyo.cono.morny.bot.query.MornyQueries +import cc.sukazyo.cono.morny.bot.event.{MornyOnInlineQuery, MornyOnTelegramCommand, MornyOnUpdateTimestampOffsetLock} +import cc.sukazyo.cono.morny.bot.query.MornyQueryManager import cc.sukazyo.cono.morny.util.schedule.Scheduler import cc.sukazyo.cono.morny.util.EpochDateTime.EpochMillis import cc.sukazyo.cono.morny.util.time.WatchDog +import cc.sukazyo.cono.morny.util.GivenContext import com.pengrad.telegrambot.TelegramBot import com.pengrad.telegrambot.request.GetMe -import scala.annotation.unused import scala.util.boundary import scala.util.boundary.break @@ -23,15 +23,65 @@ object MornyCoeur { object TestRun + case class OnInitializingPreContext ( + externalContext: GivenContext, + coeurStartupTimes: EpochMillis, + account: TelegramBot, + username: String, + userid: Long, + tasks: Scheduler, + trusted: MornyTrusted, + givenCxt: GivenContext + ) + + case class OnInitializingContext ( + externalContext: GivenContext, + coeurStartupTimes: EpochMillis, + account: TelegramBot, + username: String, + userid: Long, + tasks: Scheduler, + trusted: MornyTrusted, + eventManager: EventListenerManager, + commandManager: MornyCommandManager, + queryManager: MornyQueryManager, + givenCxt: GivenContext + ) + + case class OnInitializingPostContext ( + externalContext: GivenContext, + coeurStartupTimes: EpochMillis, + account: TelegramBot, + username: String, + userid: Long, + tasks: Scheduler, + trusted: MornyTrusted, + eventManager: EventListenerManager, + commandManager: MornyCommandManager, + queryManager: MornyQueryManager, + givenCxt: GivenContext + ) + + case class OnStartingContext ( + givenCxt: GivenContext + ) + + case class OnStartingPostContext ( + givenCxt: GivenContext + ) + } -class MornyCoeur (using val config: MornyConfig)(testRun: Boolean = false) { +class MornyCoeur (modules: List[MornyModule])(using val config: MornyConfig)(testRun: Boolean = false) { given MornyCoeur = this + val externalContext: GivenContext = GivenContext() + ///>>> BLOCK START instance configure & startup stage 1 logger info "Coeur starting..." + private var initializeContext = GivenContext() import cc.sukazyo.cono.morny.util.StringEnsure.deSensitive logger info s"args key:\n ${config.telegramBotKey deSensitive 4}" @@ -44,6 +94,7 @@ class MornyCoeur (using val config: MornyConfig)(testRun: Boolean = false) { logger error "Login to bot failed." System exit -1 throw RuntimeException() + initializeContext << __loginResult ///<<< BLOCK END instance configure & startup stage 1 @@ -71,19 +122,29 @@ class MornyCoeur (using val config: MornyConfig)(testRun: Boolean = false) { /** current Morny's [[MornyTrusted]] instance */ val trusted: MornyTrusted = MornyTrusted() + modules.foreach(it => it.onInitializingPre(OnInitializingPreContext( + externalContext, + coeurStartTimestamp, account, username, userid, tasks, trusted, + initializeContext))) + val daemons: MornyDaemons = MornyDaemons() - //noinspection ScalaWeakerAccess + initializeContext << daemons val eventManager: EventListenerManager = EventListenerManager() eventManager register MornyOnUpdateTimestampOffsetLock() - val commands: MornyCommands = MornyCommands() - //noinspection ScalaWeakerAccess - val queries: MornyQueries = MornyQueries() + val commands: MornyCommandManager = MornyCommandManager() + val queries: MornyQueryManager = MornyQueryManager() eventManager register MornyOnTelegramCommand(using commands) eventManager register MornyOnInlineQuery(using queries) - //noinspection ScalaUnusedSymbol - val events: MornyEventListeners = MornyEventListeners(using eventManager) + + // Coeur Initializing Event + modules.foreach(it => it.onInitializing(OnInitializingContext( + externalContext, + coeurStartTimestamp, account, username, userid, tasks, trusted, + eventManager, commands, queries, + initializeContext))) + eventManager register daemons.reporter.EventStatistics.EventInfoCatcher - @unused + val watchDog: WatchDog = WatchDog("watch-dog", 1000, 1500, { (consumed, _) => import cc.sukazyo.cono.morny.util.CommonFormat.formatDuration as f logger warn @@ -91,6 +152,12 @@ class MornyCoeur (using val config: MornyConfig)(testRun: Boolean = false) { | current tick takes ${f(consumed)} to complete.""".stripMargin tasks.notifyIt() }) + initializeContext / this << watchDog + modules.foreach(it => it.onInitializingPost(OnInitializingPostContext( + externalContext, + coeurStartTimestamp, account, username, userid, tasks, trusted, + eventManager, commands, queries, + initializeContext))) ///>>> BLOCK START instance configure & startup stage 2 @@ -102,6 +169,8 @@ class MornyCoeur (using val config: MornyConfig)(testRun: Boolean = false) { configure_exitCleanup() // put things that need to cleanup when exit below // so that it will be correctly cleanup when normal run and will not execute in testRun. + modules.foreach(it => it.onStarting(OnStartingContext( + initializeContext))) daemons.start() logger info "start telegram event listening" import com.pengrad.telegrambot.TelegramException @@ -150,18 +219,21 @@ class MornyCoeur (using val config: MornyConfig)(testRun: Boolean = false) { } }) + modules.foreach(it => it.onStartingPost(OnStartingPostContext( + initializeContext))) if config.commandLoginRefresh then logger info "resetting telegram command list" commands.automaticTGListUpdate() daemons.reporter.reportCoeurMornyLogin() + initializeContext = null logger info "Coeur start complete." ///<<< BLOCK END instance configure & startup stage 2 def saveDataAll(): Unit = { - // nothing to do + modules.foreach(it => it.onRoutineSavingData) logger notice "done all save action." } @@ -169,6 +241,7 @@ class MornyCoeur (using val config: MornyConfig)(testRun: Boolean = false) { daemons.reporter.reportCoeurExit() account.shutdown() logger info "stopped bot account" + modules.foreach(it => it.onExit) daemons.stop() tasks.waitForStop() logger info s"morny tasks stopped: remains ${tasks.amount} tasks not be executed" diff --git a/src/main/scala/cc/sukazyo/cono/morny/MornyCoreModule.scala b/src/main/scala/cc/sukazyo/cono/morny/MornyCoreModule.scala new file mode 100644 index 0000000..69833ac --- /dev/null +++ b/src/main/scala/cc/sukazyo/cono/morny/MornyCoreModule.scala @@ -0,0 +1,99 @@ +package cc.sukazyo.cono.morny + +import cc.sukazyo.cono.morny.MornyCoeur.OnInitializingContext + +class MornyCoreModule extends MornyModule { + + override val id: String = "cc.sukazyo.cono.morny.bot" + override val name: String = "Morny Coeur - Core (for refactor temporary)" + override val version: String = MornySystem.VERSION + + override val description: String | Null = + """Core module of Morny Coeur. + | + |Exists for temporary use, when refactor completed it should be replaced + |by all other small modules that provide different functionality. + |""".stripMargin + + override def onInitializing (using MornyCoeur)(cxt: OnInitializingContext): Unit = { + import cc.sukazyo.cono.morny.bot.command.* + import cc.sukazyo.cono.morny.bot.event.* + import cc.sukazyo.cono.morny.bot.query.* + import cxt.* + + val $OnUserRandom = OnUserRandom() + eventManager.register( + // ACTIVITY_RECORDER + // KUOHUANHUAN_NEED_SLEEP + OnUniMeowTrigger(using commandManager), + $OnUserRandom.RandomSelect, + //noinspection NonAsciiCharacters + $OnUserRandom.尊嘟假嘟, + OnQuestionMarkReply(), + OnUserSlashAction(), + OnCallMe(), + OnCallMsgSend(), + OnGetSocial(), + OnMedicationNotifyApply(), + OnEventHackHandle() + ) + + val $MornyHellos = MornyHellos() + val $IP186Query = IP186Query() + val $MornyInformation = MornyInformation() + val $MornyInformationOlds = MornyInformationOlds(using $MornyInformation) + val $MornyManagers = MornyManagers() + //noinspection NonAsciiCharacters + val $喵呜 = 喵呜() + //noinspection NonAsciiCharacters + val $创 = 创() + commandManager.register( + + $MornyHellos.On, + $MornyHellos.Hello, + MornyInfoOnStart(), + GetUsernameAndId(), + EventHack(), + Nbnhhsh(), + $IP186Query.IP, + $IP186Query.Whois, + Encryptor(), + MornyOldJrrp(), + GetSocial(), + + $MornyManagers.SaveData, + $MornyInformation, + $MornyInformationOlds.Version, + $MornyInformationOlds.Runtime, + $MornyManagers.Exit, + + Testing(), + DirectMsgClear(), + + //noinspection NonAsciiCharacters + 私わね(), + //noinspection NonAsciiCharacters + $喵呜.Progynova, + //noinspection NonAsciiCharacters + $创.Chuang + + ) + //noinspection NonAsciiCharacters + commandManager.registerForUni( + $喵呜.抱抱, + $喵呜.揉揉, + $喵呜.贴贴, + $喵呜.蹭蹭 + ) + + queryManager.register( + RawText(), + MyInformation(), + ShareToolTwitter(), + ShareToolBilibili(), + ShareToolSocialContent() + ) + + } + +} diff --git a/src/main/scala/cc/sukazyo/cono/morny/MornyModule.scala b/src/main/scala/cc/sukazyo/cono/morny/MornyModule.scala new file mode 100644 index 0000000..5ae926b --- /dev/null +++ b/src/main/scala/cc/sukazyo/cono/morny/MornyModule.scala @@ -0,0 +1,24 @@ +package cc.sukazyo.cono.morny + +import cc.sukazyo.cono.morny.MornyCoeur.* + +trait MornyModule { + + val id: String + val name: String + val version: String + + val description: String|Null + + def onInitializingPre (using MornyCoeur)(cxt: OnInitializingPreContext): Unit = {} + def onInitializing (using MornyCoeur)(cxt: OnInitializingContext): Unit = {} + def onInitializingPost (using MornyCoeur)(cxt: OnInitializingPostContext): Unit = {} + + def onStarting (using MornyCoeur)(cxt: OnStartingContext): Unit = {} + def onStartingPost (using MornyCoeur)(cxt: OnStartingPostContext): Unit = {} + + def onRoutineSavingData (using MornyCoeur): Unit = {} + + def onExit (using MornyCoeur): Unit = {} + +} diff --git a/src/main/scala/cc/sukazyo/cono/morny/ServerMain.scala b/src/main/scala/cc/sukazyo/cono/morny/ServerMain.scala index ba86cd9..d1ec249 100644 --- a/src/main/scala/cc/sukazyo/cono/morny/ServerMain.scala +++ b/src/main/scala/cc/sukazyo/cono/morny/ServerMain.scala @@ -158,7 +158,9 @@ object ServerMain { Thread.currentThread setName THREAD_MORNY_INIT try - MornyCoeur(using config build)( + MornyCoeur( + MornyCoreModule() :: Nil + )(using config build)( testRun = mode_testRun ) catch { diff --git a/src/main/scala/cc/sukazyo/cono/morny/bot/api/EventEnv.scala b/src/main/scala/cc/sukazyo/cono/morny/bot/api/EventEnv.scala index 9061a1f..6d67742 100644 --- a/src/main/scala/cc/sukazyo/cono/morny/bot/api/EventEnv.scala +++ b/src/main/scala/cc/sukazyo/cono/morny/bot/api/EventEnv.scala @@ -1,6 +1,7 @@ package cc.sukazyo.cono.morny.bot.api import cc.sukazyo.cono.morny.util.EpochDateTime.EpochMillis +import cc.sukazyo.cono.morny.util.GivenContext import cc.sukazyo.messiva.utils.StackUtils import com.pengrad.telegrambot.model.Update @@ -19,7 +20,7 @@ class EventEnv ( case CANCELED (_from: StackTraceElement) extends State with StateSource(_from) private val _status: mutable.ListBuffer[State] = mutable.ListBuffer.empty - private val variables: mutable.HashMap[Class[?], Any] = mutable.HashMap.empty + val givenCxt: GivenContext = GivenContext() val timeStartup: EpochMillis = System.currentTimeMillis def isEventOk: Boolean = _status.lastOption match @@ -42,24 +43,4 @@ class EventEnv ( def status: List[State] = _status.toList - def provide (i: Any): Unit = - variables += (i.getClass -> i) - - def consume [T] (t: Class[T]) (consumer: T => Unit): ConsumeResult = { - variables get t match - case Some(i) => consumer(i.asInstanceOf[T]); ConsumeResult(true) - case None => ConsumeResult(false) - } - - def consume [T: ClassTag] (consumer: T => Unit): ConsumeResult = - variables get classTag[T].runtimeClass match - case Some(i) => consumer(i.asInstanceOf[T]); ConsumeResult(true) - case None => ConsumeResult(false) - - class ConsumeResult (success: Boolean) { - def onfail (processor: => Unit): Unit = { - if !success then processor - } - } - } diff --git a/src/main/scala/cc/sukazyo/cono/morny/bot/command/MornyCommands.scala b/src/main/scala/cc/sukazyo/cono/morny/bot/command/MornyCommandManager.scala similarity index 62% rename from src/main/scala/cc/sukazyo/cono/morny/bot/command/MornyCommands.scala rename to src/main/scala/cc/sukazyo/cono/morny/bot/command/MornyCommandManager.scala index 3f44ff2..78a3f81 100644 --- a/src/main/scala/cc/sukazyo/cono/morny/bot/command/MornyCommands.scala +++ b/src/main/scala/cc/sukazyo/cono/morny/bot/command/MornyCommandManager.scala @@ -8,69 +8,26 @@ import cc.sukazyo.cono.morny.util.tgapi.TelegramExtensions.Bot.exec import com.pengrad.telegrambot.model.{BotCommand, DeleteMyCommands, Update} import com.pengrad.telegrambot.request.{SendSticker, SetMyCommands} -import scala.collection.{mutable, SeqMap} +import scala.collection.mutable import scala.collection.mutable.ArrayBuffer import scala.language.postfixOps -class MornyCommands (using coeur: MornyCoeur) { +class MornyCommandManager (using coeur: MornyCoeur) { - private type CommandMap = SeqMap[String, ISimpleCommand] - private def CommandMap (commands: ISimpleCommand*): CommandMap = - val stash = mutable.SeqMap.empty[String, ISimpleCommand] + private type CommandMap = mutable.SeqMap[String, ISimpleCommand] + private val commands: CommandMap = mutable.SeqMap.empty + def register [T <: ISimpleCommand] (commands: T*): Unit = for (i <- commands) - stash += (i.name -> i) + this.commands += (i.name -> i) for (alias <- i.aliases) - stash += (alias.name -> i) - stash + this.commands += (alias.name -> i) - private val $MornyHellos = MornyHellos() - private val $IP186Query = IP186Query() - private val $MornyInformation = MornyInformation() - private val $MornyInformationOlds = MornyInformationOlds(using $MornyInformation) - private val $MornyManagers = MornyManagers() - //noinspection NonAsciiCharacters - private val $喵呜 = 喵呜() - //noinspection NonAsciiCharacters - private val $创 = 创() - private val commands: CommandMap = CommandMap( - - $MornyHellos.On, - $MornyHellos.Hello, - MornyInfoOnStart(), - GetUsernameAndId(), - EventHack(), - Nbnhhsh(), - $IP186Query.IP, - $IP186Query.Whois, - Encryptor(), - MornyOldJrrp(), - GetSocial(), - - $MornyManagers.SaveData, - $MornyInformation, - $MornyInformationOlds.Version, - $MornyInformationOlds.Runtime, - $MornyManagers.Exit, - - Testing(), - DirectMsgClear(), - - //noinspection NonAsciiCharacters - 私わね(), - //noinspection NonAsciiCharacters - $喵呜.Progynova, - //noinspection NonAsciiCharacters - $创.Chuang - - ) - - //noinspection NonAsciiCharacters - val commands_uni: CommandMap = CommandMap( - $喵呜.抱抱, - $喵呜.揉揉, - $喵呜.贴贴, - $喵呜.蹭蹭 - ) + private[bot] val commands_uni: CommandMap = mutable.SeqMap.empty + def registerForUni [T <: ISimpleCommand] (commands: T*): Unit = + for (i <- commands) + this.commands_uni += (i.name -> i) + for (alias <- i.aliases) + this.commands_uni += (alias.name -> i) def execute (using command: InputCommand, event: Update): Boolean = { if (commands contains command.command) diff --git a/src/main/scala/cc/sukazyo/cono/morny/bot/event/MornyEventListeners.scala b/src/main/scala/cc/sukazyo/cono/morny/bot/event/MornyEventListeners.scala deleted file mode 100644 index 9e2d674..0000000 --- a/src/main/scala/cc/sukazyo/cono/morny/bot/event/MornyEventListeners.scala +++ /dev/null @@ -1,25 +0,0 @@ -package cc.sukazyo.cono.morny.bot.event - -import cc.sukazyo.cono.morny.bot.api.EventListenerManager -import cc.sukazyo.cono.morny.MornyCoeur - -class MornyEventListeners (using manager: EventListenerManager) (using coeur: MornyCoeur) { - - private val $OnUserRandom = OnUserRandom() - manager.register( - // ACTIVITY_RECORDER - // KUOHUANHUAN_NEED_SLEEP - OnUniMeowTrigger(using coeur.commands), - $OnUserRandom.RandomSelect, - //noinspection NonAsciiCharacters - $OnUserRandom.尊嘟假嘟, - OnQuestionMarkReply(), - OnUserSlashAction(), - OnCallMe(), - OnCallMsgSend(), - OnGetSocial(), - OnMedicationNotifyApply(), - OnEventHackHandle() - ) - -} diff --git a/src/main/scala/cc/sukazyo/cono/morny/bot/event/MornyOnInlineQuery.scala b/src/main/scala/cc/sukazyo/cono/morny/bot/event/MornyOnInlineQuery.scala index e079dd0..db5c821 100644 --- a/src/main/scala/cc/sukazyo/cono/morny/bot/event/MornyOnInlineQuery.scala +++ b/src/main/scala/cc/sukazyo/cono/morny/bot/event/MornyOnInlineQuery.scala @@ -2,9 +2,8 @@ package cc.sukazyo.cono.morny.bot.event import cc.sukazyo.cono.morny.MornyCoeur import cc.sukazyo.cono.morny.bot.api.{EventEnv, EventListener} -import cc.sukazyo.cono.morny.bot.query.{InlineQueryUnit, MornyQueries} +import cc.sukazyo.cono.morny.bot.query.{InlineQueryUnit, MornyQueryManager} import cc.sukazyo.cono.morny.util.tgapi.TelegramExtensions.Bot.exec -import com.pengrad.telegrambot.model.Update import com.pengrad.telegrambot.model.request.InlineQueryResult import com.pengrad.telegrambot.request.AnswerInlineQuery @@ -12,7 +11,7 @@ import scala.collection.mutable.ListBuffer import scala.language.postfixOps import scala.reflect.ClassTag -class MornyOnInlineQuery (using queryManager: MornyQueries) (using coeur: MornyCoeur) extends EventListener { +class MornyOnInlineQuery (using queryManager: MornyQueryManager) (using coeur: MornyCoeur) extends EventListener { override def onInlineQuery (using event: EventEnv): Unit = { import event.update diff --git a/src/main/scala/cc/sukazyo/cono/morny/bot/event/MornyOnTelegramCommand.scala b/src/main/scala/cc/sukazyo/cono/morny/bot/event/MornyOnTelegramCommand.scala index 66c0f66..f49f292 100644 --- a/src/main/scala/cc/sukazyo/cono/morny/bot/event/MornyOnTelegramCommand.scala +++ b/src/main/scala/cc/sukazyo/cono/morny/bot/event/MornyOnTelegramCommand.scala @@ -3,14 +3,15 @@ package cc.sukazyo.cono.morny.bot.event import cc.sukazyo.cono.morny.bot.api.{EventEnv, EventListener} import cc.sukazyo.cono.morny.Log.logger import cc.sukazyo.cono.morny.MornyCoeur -import cc.sukazyo.cono.morny.bot.command.MornyCommands +import cc.sukazyo.cono.morny.bot.command.MornyCommandManager import cc.sukazyo.cono.morny.util.tgapi.InputCommand import com.pengrad.telegrambot.model.{Message, Update} -class MornyOnTelegramCommand (using commandManager: MornyCommands) (using coeur: MornyCoeur) extends EventListener { +class MornyOnTelegramCommand (using commandManager: MornyCommandManager) (using coeur: MornyCoeur) extends EventListener { override def onMessage (using event: EventEnv): Unit = { - given update: Update = event.update + import event.* + given Update = update def _isCommandMessage(message: Message): Boolean = if message.text eq null then false @@ -20,7 +21,7 @@ class MornyOnTelegramCommand (using commandManager: MornyCommands) (using coeur: if !_isCommandMessage(update.message) then return val inputCommand = InputCommand(update.message.text drop 1) - event provide inputCommand + givenCxt << inputCommand logger trace ":provided InputCommand for event" if (!(inputCommand.command matches "^\\w+$")) @@ -30,7 +31,7 @@ class MornyOnTelegramCommand (using commandManager: MornyCommands) (using coeur: else logger debug "is command" if commandManager.execute(using inputCommand) then - event.setEventOk + setEventOk } diff --git a/src/main/scala/cc/sukazyo/cono/morny/bot/event/OnUniMeowTrigger.scala b/src/main/scala/cc/sukazyo/cono/morny/bot/event/OnUniMeowTrigger.scala index 40e4fd3..45fe637 100644 --- a/src/main/scala/cc/sukazyo/cono/morny/bot/event/OnUniMeowTrigger.scala +++ b/src/main/scala/cc/sukazyo/cono/morny/bot/event/OnUniMeowTrigger.scala @@ -1,15 +1,16 @@ package cc.sukazyo.cono.morny.bot.event import cc.sukazyo.cono.morny.bot.api.{EventEnv, EventListener} -import cc.sukazyo.cono.morny.bot.command.MornyCommands +import cc.sukazyo.cono.morny.bot.command.MornyCommandManager import cc.sukazyo.cono.morny.util.tgapi.InputCommand import cc.sukazyo.cono.morny.Log.logger -class OnUniMeowTrigger (using commands: MornyCommands) extends EventListener { +class OnUniMeowTrigger (using commands: MornyCommandManager) extends EventListener { override def onMessage (using event: EventEnv): Unit = { + import event.* - event.consume[InputCommand] { input => + givenCxt >> { (input: InputCommand) => logger trace s"got input command {$input} from event-context" for ((name, command_instance) <- commands.commands_uni) { @@ -20,7 +21,7 @@ class OnUniMeowTrigger (using commands: MornyCommands) extends EventListener { event.setEventOk } - } onfail { logger trace "not command (for uni-meow)" } + } || { logger trace "not command (for uni-meow)" } } diff --git a/src/main/scala/cc/sukazyo/cono/morny/bot/query/MornyQueries.scala b/src/main/scala/cc/sukazyo/cono/morny/bot/query/MornyQueryManager.scala similarity index 62% rename from src/main/scala/cc/sukazyo/cono/morny/bot/query/MornyQueries.scala rename to src/main/scala/cc/sukazyo/cono/morny/bot/query/MornyQueryManager.scala index f0436ca..b4e92fc 100644 --- a/src/main/scala/cc/sukazyo/cono/morny/bot/query/MornyQueries.scala +++ b/src/main/scala/cc/sukazyo/cono/morny/bot/query/MornyQueryManager.scala @@ -4,21 +4,19 @@ import cc.sukazyo.cono.morny.bot.query import cc.sukazyo.cono.morny.MornyCoeur import com.pengrad.telegrambot.model.Update +import scala.collection.mutable import scala.collection.mutable.ListBuffer -class MornyQueries (using MornyCoeur) { +class MornyQueryManager (using MornyCoeur) { - private val queryInstances = Set[ITelegramQuery]( - RawText(), - MyInformation(), - ShareToolTwitter(), - ShareToolBilibili(), - ShareToolSocialContent() - ) + private val queries = mutable.Queue.empty[ITelegramQuery] + + def register (queries: ITelegramQuery*): Unit = + this.queries ++= queries def query (event: Update): List[InlineQueryUnit[_]] = { val results = ListBuffer[InlineQueryUnit[_]]() - for (instance <- queryInstances) { + for (instance <- queries) { val r = instance query event if (r != null) results ++= r } diff --git a/src/main/scala/cc/sukazyo/cono/morny/daemon/MornyReport.scala b/src/main/scala/cc/sukazyo/cono/morny/daemon/MornyReport.scala index 2ede970..0fd7a2e 100644 --- a/src/main/scala/cc/sukazyo/cono/morny/daemon/MornyReport.scala +++ b/src/main/scala/cc/sukazyo/cono/morny/daemon/MornyReport.scala @@ -184,12 +184,12 @@ class MornyReport (using coeur: MornyCoeur) { //noinspection ScalaWeakerAccess case class EventTimeUsed (it: DurationMillis) override def atEventPost (using event: EventEnv): Unit = { - import event.State + import event.* eventTotal += 1 event.state match case State.OK(from) => val timeUsed = EventTimeUsed(System.currentTimeMillis - event.timeStartup) - event provide timeUsed + givenCxt << timeUsed logger debug s"""event done with OK | with time consumed ${timeUsed.it}ms diff --git a/src/main/scala/cc/sukazyo/cono/morny/util/GivenContext.scala b/src/main/scala/cc/sukazyo/cono/morny/util/GivenContext.scala new file mode 100644 index 0000000..7dbfb19 --- /dev/null +++ b/src/main/scala/cc/sukazyo/cono/morny/util/GivenContext.scala @@ -0,0 +1,58 @@ +package cc.sukazyo.cono.morny.util + +import scala.annotation.targetName +import scala.collection.mutable +import scala.reflect.{classTag, ClassTag} + +class GivenContext { + + private type ImplicitsMap [T <: Any] = mutable.HashMap[Class[?], T] + + private val variables: ImplicitsMap[Any] = mutable.HashMap.empty + private val variablesWithOwner: ImplicitsMap[ImplicitsMap[Any]] = mutable.HashMap.empty + + def provide (i: Any): Unit = + variables += (i.getClass -> i) + def << (i: Any): Unit = + this.provide(i) + + def >>[T: ClassTag] (consumer: T => Unit): ConsumeResult = + this.use[T](consumer) + def use [T: ClassTag] (consumer: T => Unit): ConsumeResult = + variables get classTag[T].runtimeClass match + case Some(i) => consumer(i.asInstanceOf[T]); ConsumeResult(true) + case None => ConsumeResult(false) + def consume [T: ClassTag] (consume: T => Unit): ConsumeResult = + this.use[T](consume) + + @targetName("ownedBy") + def / [O: ClassTag] (owner: O): OwnedContext[O] = + OwnedContext[O]() + def ownedBy [O: ClassTag]: OwnedContext[O] = + OwnedContext[O]() + + class OwnedContext [O: ClassTag] { + + def provide (i: Any): Unit = + (variablesWithOwner getOrElseUpdate (classTag[O].runtimeClass, mutable.HashMap.empty)) + .addOne(i.getClass -> i) + def << (i: Any): Unit = + this.provide(i) + + def >> [T: ClassTag] (consumer: T => Unit): ConsumeResult = + this.use[T](consumer) + def use [T: ClassTag] (consumer: T => Unit): ConsumeResult = + variablesWithOwner(classTag[O].runtimeClass) get classTag[T].runtimeClass match + case Some(i) => consumer(i.asInstanceOf[T]); ConsumeResult(true) + case None => ConsumeResult(false) + + } + + class ConsumeResult (success: Boolean) { + @targetName("orElse") + def || (processor: => Unit): Unit = { + if !success then processor + } + } + +}