From 7718ae845a59266e8ea89f4c1630c6691a8c7e16 Mon Sep 17 00:00:00 2001 From: Eyre_S Date: Sat, 23 Dec 2023 20:16:16 +0800 Subject: [PATCH] better err report for GivenContext, module morny.event_hack --- .../sukazyo/cono/morny/MornyCoreModule.scala | 4 +-- .../cono/morny/ServerModulesLoader.scala | 18 ++++++++++ .../cono/morny/daemon/MornyDaemons.scala | 2 +- .../BotCmdEventHack.scala} | 8 +++-- .../BotEventEventHackHandle.scala} | 6 ++-- .../{daemon => event_hack}/EventHacker.scala | 2 +- .../morny/event_hack/ModuleEventHack.scala | 35 +++++++++++++++++++ .../morny/internal/MornyInternalModule.scala | 9 +++++ .../cono/morny/uni_meow/ModuleUniMeow.scala | 6 ++-- .../cono/morny/util/GivenContext.scala | 35 ++++++++++++++++--- .../sukazyo/cono/morny/util/UseStacks.scala | 20 +++++++++++ 11 files changed, 126 insertions(+), 19 deletions(-) create mode 100644 src/main/scala/cc/sukazyo/cono/morny/ServerModulesLoader.scala rename src/main/scala/cc/sukazyo/cono/morny/{bot/command/EventHack.scala => event_hack/BotCmdEventHack.scala} (85%) rename src/main/scala/cc/sukazyo/cono/morny/{bot/event/OnEventHackHandle.scala => event_hack/BotEventEventHackHandle.scala} (92%) rename src/main/scala/cc/sukazyo/cono/morny/{daemon => event_hack}/EventHacker.scala (97%) create mode 100644 src/main/scala/cc/sukazyo/cono/morny/event_hack/ModuleEventHack.scala create mode 100644 src/main/scala/cc/sukazyo/cono/morny/internal/MornyInternalModule.scala create mode 100644 src/main/scala/cc/sukazyo/cono/morny/util/UseStacks.scala diff --git a/src/main/scala/cc/sukazyo/cono/morny/MornyCoreModule.scala b/src/main/scala/cc/sukazyo/cono/morny/MornyCoreModule.scala index 0f7d7cc..30130b8 100644 --- a/src/main/scala/cc/sukazyo/cono/morny/MornyCoreModule.scala +++ b/src/main/scala/cc/sukazyo/cono/morny/MornyCoreModule.scala @@ -33,8 +33,7 @@ class MornyCoreModule extends MornyModule { OnCallMe(), OnCallMsgSend(), OnGetSocial(), - OnMedicationNotifyApply(), - OnEventHackHandle() + OnMedicationNotifyApply() ) val $MornyHellos = MornyHellos() @@ -50,7 +49,6 @@ class MornyCoreModule extends MornyModule { $MornyHellos.Hello, MornyInfoOnStart(), GetUsernameAndId(), - EventHack(), Nbnhhsh(), $IP186Query.IP, $IP186Query.Whois, diff --git a/src/main/scala/cc/sukazyo/cono/morny/ServerModulesLoader.scala b/src/main/scala/cc/sukazyo/cono/morny/ServerModulesLoader.scala new file mode 100644 index 0000000..4a1d1b2 --- /dev/null +++ b/src/main/scala/cc/sukazyo/cono/morny/ServerModulesLoader.scala @@ -0,0 +1,18 @@ +package cc.sukazyo.cono.morny + +import cc.sukazyo.cono.morny.event_hack.ModuleEventHack +import cc.sukazyo.cono.morny.uni_meow.ModuleUniMeow + +object ServerModulesLoader { + + def load (): List[MornyModule] = { + + List( + ModuleEventHack(), + ModuleUniMeow(), + MornyCoreModule() + ) + + } + +} diff --git a/src/main/scala/cc/sukazyo/cono/morny/daemon/MornyDaemons.scala b/src/main/scala/cc/sukazyo/cono/morny/daemon/MornyDaemons.scala index e3256bc..22f9fe0 100644 --- a/src/main/scala/cc/sukazyo/cono/morny/daemon/MornyDaemons.scala +++ b/src/main/scala/cc/sukazyo/cono/morny/daemon/MornyDaemons.scala @@ -2,12 +2,12 @@ package cc.sukazyo.cono.morny.daemon import cc.sukazyo.cono.morny.Log.logger import cc.sukazyo.cono.morny.MornyCoeur +import cc.sukazyo.cono.morny.event_hack.EventHacker class MornyDaemons (using val coeur: MornyCoeur) { val medicationTimer: MedicationTimer = MedicationTimer() val reporter: MornyReport = MornyReport() - val eventHack: EventHacker = EventHacker() def start (): Unit = { diff --git a/src/main/scala/cc/sukazyo/cono/morny/bot/command/EventHack.scala b/src/main/scala/cc/sukazyo/cono/morny/event_hack/BotCmdEventHack.scala similarity index 85% rename from src/main/scala/cc/sukazyo/cono/morny/bot/command/EventHack.scala rename to src/main/scala/cc/sukazyo/cono/morny/event_hack/BotCmdEventHack.scala index 0cc63fc..009da4e 100644 --- a/src/main/scala/cc/sukazyo/cono/morny/bot/command/EventHack.scala +++ b/src/main/scala/cc/sukazyo/cono/morny/event_hack/BotCmdEventHack.scala @@ -1,5 +1,7 @@ -package cc.sukazyo.cono.morny.bot.command +package cc.sukazyo.cono.morny.event_hack + import cc.sukazyo.cono.morny.MornyCoeur +import cc.sukazyo.cono.morny.bot.command.{ICommandAlias, ITelegramCommand} import cc.sukazyo.cono.morny.data.TelegramStickers import cc.sukazyo.cono.morny.util.tgapi.InputCommand import cc.sukazyo.cono.morny.util.tgapi.TelegramExtensions.Bot.exec @@ -8,7 +10,7 @@ import com.pengrad.telegrambot.request.SendSticker import scala.language.postfixOps -class EventHack (using coeur: MornyCoeur) extends ITelegramCommand { +class BotCmdEventHack (using hacker: EventHacker)(using coeur: MornyCoeur) extends ITelegramCommand { override val name: String = "event_hack" override val aliases: List[ICommandAlias] = Nil @@ -17,7 +19,7 @@ class EventHack (using coeur: MornyCoeur) extends ITelegramCommand { override def execute (using command: InputCommand, event: Update): Unit = { - import coeur.daemons.eventHack.{registerHack, HackType} + import hacker.{registerHack, HackType} val x_mode = if (command.args nonEmpty) command.args(0) else "" diff --git a/src/main/scala/cc/sukazyo/cono/morny/bot/event/OnEventHackHandle.scala b/src/main/scala/cc/sukazyo/cono/morny/event_hack/BotEventEventHackHandle.scala similarity index 92% rename from src/main/scala/cc/sukazyo/cono/morny/bot/event/OnEventHackHandle.scala rename to src/main/scala/cc/sukazyo/cono/morny/event_hack/BotEventEventHackHandle.scala index 13f78ae..ac6f245 100644 --- a/src/main/scala/cc/sukazyo/cono/morny/bot/event/OnEventHackHandle.scala +++ b/src/main/scala/cc/sukazyo/cono/morny/event_hack/BotEventEventHackHandle.scala @@ -1,4 +1,4 @@ -package cc.sukazyo.cono.morny.bot.event +package cc.sukazyo.cono.morny.event_hack import cc.sukazyo.cono.morny.bot.api.{EventEnv, EventListener} import cc.sukazyo.cono.morny.Log.logger @@ -11,11 +11,11 @@ import com.pengrad.telegrambot.request.SendMessage import scala.collection.mutable import scala.language.postfixOps -class OnEventHackHandle (using coeur: MornyCoeur) extends EventListener { +class BotEventEventHackHandle (using hacker: EventHacker)(using coeur: MornyCoeur) extends EventListener { private def trigger (chat_id: Long, from_id: Long)(using event: EventEnv): Unit = given Update = event.update - if coeur.daemons.eventHack.trigger(chat_id, from_id) then + if hacker.trigger(chat_id, from_id) then event.setEventOk override def onMessage (using event: EventEnv): Unit = diff --git a/src/main/scala/cc/sukazyo/cono/morny/daemon/EventHacker.scala b/src/main/scala/cc/sukazyo/cono/morny/event_hack/EventHacker.scala similarity index 97% rename from src/main/scala/cc/sukazyo/cono/morny/daemon/EventHacker.scala rename to src/main/scala/cc/sukazyo/cono/morny/event_hack/EventHacker.scala index 00596e7..b3afff9 100644 --- a/src/main/scala/cc/sukazyo/cono/morny/daemon/EventHacker.scala +++ b/src/main/scala/cc/sukazyo/cono/morny/event_hack/EventHacker.scala @@ -1,4 +1,4 @@ -package cc.sukazyo.cono.morny.daemon +package cc.sukazyo.cono.morny.event_hack import cc.sukazyo.cono.morny.Log.logger import cc.sukazyo.cono.morny.MornyCoeur diff --git a/src/main/scala/cc/sukazyo/cono/morny/event_hack/ModuleEventHack.scala b/src/main/scala/cc/sukazyo/cono/morny/event_hack/ModuleEventHack.scala new file mode 100644 index 0000000..949e750 --- /dev/null +++ b/src/main/scala/cc/sukazyo/cono/morny/event_hack/ModuleEventHack.scala @@ -0,0 +1,35 @@ +package cc.sukazyo.cono.morny.event_hack + +import cc.sukazyo.cono.morny.internal.MornyInternalModule +import cc.sukazyo.cono.morny.MornyCoeur + +class ModuleEventHack extends MornyInternalModule { + + override val id: String = "morny.event_hack" + override val name: String = "Morny Event Hack" + override val description: String | Null = + // language=markdown + """The `/event_hack` command which can make morny output the next + |serialized event. + |""".stripMargin + + override def onInitializingPre (using MornyCoeur)(cxt: MornyCoeur.OnInitializingPreContext): Unit = { + import cxt.* + + given hacker: EventHacker = EventHacker() + + externalContext << hacker + givenCxt << hacker + + } + + override def onInitializing (using MornyCoeur)(cxt: MornyCoeur.OnInitializingContext): Unit = { + import cxt.* + given EventHacker = externalContext >!> classOf[EventHacker] + + commandManager.register(BotCmdEventHack()) + eventManager.register(BotEventEventHackHandle()) + + } + +} diff --git a/src/main/scala/cc/sukazyo/cono/morny/internal/MornyInternalModule.scala b/src/main/scala/cc/sukazyo/cono/morny/internal/MornyInternalModule.scala new file mode 100644 index 0000000..03866c1 --- /dev/null +++ b/src/main/scala/cc/sukazyo/cono/morny/internal/MornyInternalModule.scala @@ -0,0 +1,9 @@ +package cc.sukazyo.cono.morny.internal + +import cc.sukazyo.cono.morny.{MornyModule, MornySystem} + +trait MornyInternalModule extends MornyModule { + + override val version: String = MornySystem.VERSION + +} diff --git a/src/main/scala/cc/sukazyo/cono/morny/uni_meow/ModuleUniMeow.scala b/src/main/scala/cc/sukazyo/cono/morny/uni_meow/ModuleUniMeow.scala index f5afb11..e673691 100644 --- a/src/main/scala/cc/sukazyo/cono/morny/uni_meow/ModuleUniMeow.scala +++ b/src/main/scala/cc/sukazyo/cono/morny/uni_meow/ModuleUniMeow.scala @@ -1,12 +1,12 @@ package cc.sukazyo.cono.morny.uni_meow -import cc.sukazyo.cono.morny.{MornyCoeur, MornyModule, MornySystem} +import cc.sukazyo.cono.morny.MornyCoeur +import cc.sukazyo.cono.morny.internal.MornyInternalModule -class ModuleUniMeow extends MornyModule { +class ModuleUniMeow extends MornyInternalModule { override val id: String = "coeur.uni_meow" override val name: String = "Coeur Uni-Meow Commands" - override val version: String = MornySystem.VERSION override val description: String | Null = // language=Markdown """Provides support for unicode command in Telegram. Also provided some diff --git a/src/main/scala/cc/sukazyo/cono/morny/util/GivenContext.scala b/src/main/scala/cc/sukazyo/cono/morny/util/GivenContext.scala index 46172b0..7814e48 100644 --- a/src/main/scala/cc/sukazyo/cono/morny/util/GivenContext.scala +++ b/src/main/scala/cc/sukazyo/cono/morny/util/GivenContext.scala @@ -1,13 +1,33 @@ package cc.sukazyo.cono.morny.util -import cc.sukazyo.cono.morny.util.GivenContext.ContextNotGivenException +import cc.sukazyo.cono.morny.util.GivenContext.{ContextNotGivenException, FolderClass, RequestItemClass} +import cc.sukazyo.messiva.utils.StackUtils import scala.annotation.targetName import scala.collection.mutable import scala.reflect.{classTag, ClassTag} +import scala.util.boundary object GivenContext { - class ContextNotGivenException extends NoSuchElementException + case class FolderClass (clazz: Option[Class[?]]) + object FolderClass: + def default: FolderClass = FolderClass(None) + case class RequestItemClass (clazz: Class[?]) + private def lastNonGCStack: StackTraceElement = + boundary { + for (stack <- StackUtils.getStackTrace(0)) { + if (!stack.getClassName.startsWith(classOf[GivenContext].getName)) + boundary break stack + } + StackTraceElement("unknown", "unknown", "unknown", -1) + } + class ContextNotGivenException (using + val requestItemClass: RequestItemClass, + val folderClass: FolderClass = FolderClass.default, + val requestStack: StackTraceElement = UseStacks.getStackHeadBeforeClass[GivenContext] + ) extends NoSuchElementException ( + s"None of the ${requestItemClass.clazz.getSimpleName} is in the context${folderClass.clazz.map(" and owned by " + _.getSimpleName).getOrElse("")}, which is required by $requestStack." + ) } /** A mutable collection that can store(provide) any typed value and read(use/consume) that value by type. @@ -67,7 +87,8 @@ class GivenContext { private type CxtOption[T] = Either[ContextNotGivenException, T] def use [T: ClassTag]: CxtOption[T] = - variables get classTag[T].runtimeClass match + given t: RequestItemClass = RequestItemClass(classTag[T].runtimeClass) + variables get t.clazz match case Some(i) => Right(i.asInstanceOf[T]) case None => Left(ContextNotGivenException()) def use [T: ClassTag, U] (consumer: T => U): ConsumeResult[U] = @@ -101,8 +122,12 @@ class GivenContext { this.provide[T](i) def use [T: ClassTag]: CxtOption[T] = - variablesWithOwner(classTag[O].runtimeClass) get classTag[T].runtimeClass match - case Some(i) => Right(i.asInstanceOf[T]) + given t: RequestItemClass = RequestItemClass(classTag[T].runtimeClass) + given u: FolderClass = FolderClass(Some(classTag[O].runtimeClass)) + variablesWithOwner get u.clazz.get match + case Some(varColl) => varColl get t.clazz match + case Some(i) => Right(i.asInstanceOf[T]) + case None => Left(ContextNotGivenException()) case None => Left(ContextNotGivenException()) def use [T: ClassTag, U] (consumer: T => U): ConsumeResult[U] = use[T] match diff --git a/src/main/scala/cc/sukazyo/cono/morny/util/UseStacks.scala b/src/main/scala/cc/sukazyo/cono/morny/util/UseStacks.scala new file mode 100644 index 0000000..f7dffa9 --- /dev/null +++ b/src/main/scala/cc/sukazyo/cono/morny/util/UseStacks.scala @@ -0,0 +1,20 @@ +package cc.sukazyo.cono.morny.util + +import cc.sukazyo.messiva.utils.StackUtils + +import scala.reflect.{classTag, ClassTag} +import scala.util.boundary + +object UseStacks { + + def getStackHeadBeforeClass[T: ClassTag]: StackTraceElement = { + boundary { + for (stack <- StackUtils.getStackTrace(1)) { + if (!stack.getClassName.startsWith(classTag[T].runtimeClass.getName)) + boundary break stack + } + StackTraceElement("unknown", "unknown", "unknown", -1) + } + } + +}