From 96101ec434d58833977ad515a688e2ab237b1e37 Mon Sep 17 00:00:00 2001 From: Eyre_S Date: Thu, 20 Feb 2025 12:40:27 +0800 Subject: [PATCH] add TelegramBotEvents.{OnGetUpdateFailed, OnListenerOccursException} - also add dependency da4a, change GivenContext to da4a version. - make MornyReport uses the above events to function, instead of calling MornyReport directly in Coeur. --- build.sbt | 9 +- .../sukazyo/cono/morny/core/MornyCoeur.scala | 13 +- .../core/bot/api/EventListenerManager.scala | 8 +- .../morny/core/event/TelegramBotEvents.scala | 41 +++++ .../sukazyo/cono/morny/reporter/Module.scala | 11 ++ .../cono/morny/reporter/MornyReport.scala | 14 +- .../telegram_bot/BotErrorsReport.scala | 38 +++++ .../external/twitter/package.scala | 20 +++ .../system/telegram_api/event/EventEnv.scala | 2 +- .../morny/system/utils/GivenContext.scala | 156 ------------------ project/MornyConfiguration.scala | 6 +- 11 files changed, 147 insertions(+), 171 deletions(-) create mode 100644 morny-coeur/src/main/scala/cc/sukazyo/cono/morny/core/event/TelegramBotEvents.scala create mode 100644 morny-coeur/src/main/scala/cc/sukazyo/cono/morny/reporter/telegram_bot/BotErrorsReport.scala delete mode 100644 morny-system-lib/src/main/scala/cc/sukazyo/cono/morny/system/utils/GivenContext.scala diff --git a/build.sbt b/build.sbt index e7c3f54..8e6d5b9 100644 --- a/build.sbt +++ b/build.sbt @@ -8,8 +8,13 @@ ThisBuild / version := MornyProject.version ThisBuild / scalaVersion := "3.4.1" ThisBuild / resolvers ++= Seq( - "-ws-releases" at "https://mvn.sukazyo.cc/releases" -) + "-ws-releases" at "https://mvn.sukazyo.cc/releases", + if (MornyProject.version_is_snapshot) { + "-ws-snapshots" at "https://mvn.sukazyo.cc/snapshots" + } else { + null + } +).filter(x => x != null) ThisBuild / crossPaths := false diff --git a/morny-coeur/src/main/scala/cc/sukazyo/cono/morny/core/MornyCoeur.scala b/morny-coeur/src/main/scala/cc/sukazyo/cono/morny/core/MornyCoeur.scala index 768bc83..8cf7a44 100644 --- a/morny-coeur/src/main/scala/cc/sukazyo/cono/morny/core/MornyCoeur.scala +++ b/morny-coeur/src/main/scala/cc/sukazyo/cono/morny/core/MornyCoeur.scala @@ -6,16 +6,16 @@ import cc.sukazyo.cono.morny.core.bot.api.{BotExtension, EventListenerManager, M import cc.sukazyo.cono.morny.core.bot.api.messages.ThreadingManager import cc.sukazyo.cono.morny.core.bot.event.{MornyOnInlineQuery, MornyOnTelegramCommand, MornyOnUpdateTimestampOffsetLock} import cc.sukazyo.cono.morny.core.bot.internal.{ErrorMessageManager, ThreadingManagerImpl} +import cc.sukazyo.cono.morny.core.event.TelegramBotEvents import cc.sukazyo.cono.morny.core.http.api.{HttpServer, MornyHttpServerContext} import cc.sukazyo.cono.morny.core.http.internal.MornyHttpServerContextImpl import cc.sukazyo.cono.morny.core.module.ModuleHelper -import cc.sukazyo.cono.morny.reporter.MornyReport import cc.sukazyo.cono.morny.system.utils.EpochDateTime.EpochMillis -import cc.sukazyo.cono.morny.system.utils.GivenContext import cc.sukazyo.cono.morny.util.schedule.Scheduler import cc.sukazyo.cono.morny.util.time.WatchDog import cc.sukazyo.cono.morny.util.UseString.MString import cc.sukazyo.cono.morny.util.UseThrowable.toLogString +import cc.sukazyo.std.contexts.GivenContext import com.pengrad.telegrambot.TelegramBot import com.pengrad.telegrambot.request.GetMe @@ -118,6 +118,8 @@ class MornyCoeur (modules: List[MornyModule])(using val config: MornyConfig)(tes given MornyCoeur = this + val telegramBotEvents = new TelegramBotEvents() + val externalContext: GivenContext = GivenContext() logger `info` m"""The following Modules have been added to current Morny: @@ -150,7 +152,7 @@ class MornyCoeur (modules: List[MornyModule])(using val config: MornyConfig)(tes ///<<< BLOCK END instance configure & startup stage 1 - /** inner value: about why morny exit, used in [[daemon.MornyReport]]. */ + /** inner value: about why morny exit. */ private var whileExit_reason: Option[AnyRef] = None /** About why morny exits. */ def exitReason: Option[AnyRef] = whileExit_reason @@ -295,7 +297,6 @@ class MornyCoeur (modules: List[MornyModule])(using val config: MornyConfig)(tes | server responses: |${GsonBuilder().setPrettyPrinting().create.toJson(e.response).indent(4)} |""".stripMargin - externalContext.consume[MornyReport](_.exception(e, "Failed get updates.")) } if (e.getCause != null) { @@ -319,7 +320,9 @@ class MornyCoeur (modules: List[MornyModule])(using val config: MornyConfig)(tes logger `error` s"""Failed get updates: |${e_other.toLogString `indent` 3}""".stripMargin - externalContext.consume[MornyReport](_.exception(e_other, "Failed get updates.")) + + TelegramBotEvents.inCoeur.OnGetUpdateFailed.emit(e) + } }) diff --git a/morny-coeur/src/main/scala/cc/sukazyo/cono/morny/core/bot/api/EventListenerManager.scala b/morny-coeur/src/main/scala/cc/sukazyo/cono/morny/core/bot/api/EventListenerManager.scala index 0baf58c..f0b64d5 100644 --- a/morny-coeur/src/main/scala/cc/sukazyo/cono/morny/core/bot/api/EventListenerManager.scala +++ b/morny-coeur/src/main/scala/cc/sukazyo/cono/morny/core/bot/api/EventListenerManager.scala @@ -2,7 +2,7 @@ package cc.sukazyo.cono.morny.core.bot.api import cc.sukazyo.cono.morny.core.{Log, MornyCoeur} import cc.sukazyo.cono.morny.core.Log.logger -import cc.sukazyo.cono.morny.reporter.MornyReport +import cc.sukazyo.cono.morny.core.event.TelegramBotEvents import cc.sukazyo.cono.morny.system.telegram_api.event.{EventEnv, EventListener, EventRuntimeException} import cc.sukazyo.cono.morny.util.UseThrowable.toLogString import com.google.gson.GsonBuilder @@ -49,7 +49,7 @@ class EventListenerManager (using coeur: MornyCoeur) extends UpdatesListener { i.atEventPost } - private def runEventListener (i: EventListener)(using EventEnv): Unit = { + private def runEventListener (i: EventListener)(using event: EventEnv): Unit = { try { i.on updateThreadName("message") @@ -80,7 +80,7 @@ class EventListenerManager (using coeur: MornyCoeur) extends UpdatesListener { if update.chatMember ne null then i.onChatMemberUpdated updateThreadName("chat-join-request") if update.chatJoinRequest ne null then i.onChatJoinRequest - } catch case e => { + } catch case e: Throwable => { val errorMessage = StringBuilder() errorMessage ++= "Event throws unexpected exception:\n" errorMessage ++= (e.toLogString `indent` 4) @@ -92,7 +92,7 @@ class EventListenerManager (using coeur: MornyCoeur) extends UpdatesListener { ) `indent` 4) ++= "\n" case _ => logger `error` errorMessage.toString - coeur.externalContext.consume[MornyReport](_.exception(e, "on event running")) + TelegramBotEvents.inCoeur.OnListenerOccursException.emit((e, i, event)) } } diff --git a/morny-coeur/src/main/scala/cc/sukazyo/cono/morny/core/event/TelegramBotEvents.scala b/morny-coeur/src/main/scala/cc/sukazyo/cono/morny/core/event/TelegramBotEvents.scala new file mode 100644 index 0000000..c16b94b --- /dev/null +++ b/morny-coeur/src/main/scala/cc/sukazyo/cono/morny/core/event/TelegramBotEvents.scala @@ -0,0 +1,41 @@ +package cc.sukazyo.cono.morny.core.event + +import cc.sukazyo.cono.morny.core.MornyCoeur +import cc.sukazyo.cono.morny.system.telegram_api.event.{EventEnv, EventListener as TelegramEventListener} +import cc.sukazyo.std.event.{EventContext, RichEvent} +import cc.sukazyo.std.event.impl.NormalEventManager +import com.pengrad.telegrambot.TelegramException + +class TelegramBotEvents (using coeur: MornyCoeur) { + + private val contextInitializer: EventContext[?]=>Unit = context => { + context.givenCxt << coeur + } + + /** + * Event: OnGetUpdateFailed in TelegramBotEvents + * + * This event will be emitted when an exception occurred when the Telegram Bot is trying + * to execute the GetUpdate. + * + * Provides a [[TelegramException]] that contains the exception information. + * + * Event is initialized after the [[MornyModule.onStarting]] stage, and before the + * [[MornyModule.onStartingPost]] stage. + * You should register your own listener at stage [[MornyModule.onStartingPost]]. + */ + val OnGetUpdateFailed: NormalEventManager[TelegramException, Unit] = + NormalEventManager().initContextWith(contextInitializer) + + val OnListenerOccursException: RichEvent[(Throwable, TelegramEventListener, EventEnv), Unit] = + NormalEventManager().initContextWith(contextInitializer) + +} + +object TelegramBotEvents { + + def inCoeur (using coeur: MornyCoeur): TelegramBotEvents = in(coeur) + def in (coeur: MornyCoeur): TelegramBotEvents = + coeur.telegramBotEvents + +} diff --git a/morny-coeur/src/main/scala/cc/sukazyo/cono/morny/reporter/Module.scala b/morny-coeur/src/main/scala/cc/sukazyo/cono/morny/reporter/Module.scala index e99c771..ec34094 100644 --- a/morny-coeur/src/main/scala/cc/sukazyo/cono/morny/reporter/Module.scala +++ b/morny-coeur/src/main/scala/cc/sukazyo/cono/morny/reporter/Module.scala @@ -3,6 +3,7 @@ package cc.sukazyo.cono.morny.reporter import cc.sukazyo.cono.morny.core.internal.MornyInternalModule import cc.sukazyo.cono.morny.core.Log.logger import cc.sukazyo.cono.morny.core.MornyCoeur +import cc.sukazyo.cono.morny.core.event.TelegramBotEvents class Module extends MornyInternalModule { @@ -38,17 +39,27 @@ class Module extends MornyInternalModule { override def onStarting (using coeur: MornyCoeur)(cxt: MornyCoeur.OnStartingContext): Unit = { import coeur.externalContext externalContext >> { (instance: MornyReport) => + instance.start() + + TelegramBotEvents.inCoeur.OnGetUpdateFailed + .registerListener(instance.botErrorsReport.onGetUpdateFailed) + TelegramBotEvents.inCoeur.OnListenerOccursException + .registerListener(instance.botErrorsReport.onEventListenersThrowException) + } || { logger `warn` "There seems no reporter instance is provided; skipped start it." } } override def onStartingPost (using coeur: MornyCoeur)(cxt: MornyCoeur.OnStartingPostContext): Unit = { + import coeur.externalContext + externalContext >> { (instance: MornyReport) => instance.reportCoeurMornyLogin() } + } override def onExiting (using coeur: MornyCoeur): Unit = { diff --git a/morny-coeur/src/main/scala/cc/sukazyo/cono/morny/reporter/MornyReport.scala b/morny-coeur/src/main/scala/cc/sukazyo/cono/morny/reporter/MornyReport.scala index 2a66753..cb21f55 100644 --- a/morny-coeur/src/main/scala/cc/sukazyo/cono/morny/reporter/MornyReport.scala +++ b/morny-coeur/src/main/scala/cc/sukazyo/cono/morny/reporter/MornyReport.scala @@ -3,6 +3,7 @@ package cc.sukazyo.cono.morny.reporter import cc.sukazyo.cono.morny.core.{MornyCoeur, MornyConfig} import cc.sukazyo.cono.morny.core.Log.logger import cc.sukazyo.cono.morny.data.MornyInformation.getVersionAllFullTagHTML +import cc.sukazyo.cono.morny.reporter.telegram_bot.BotErrorsReport import cc.sukazyo.cono.morny.system.telegram_api.event.{EventEnv, EventListener, EventRuntimeException} import cc.sukazyo.cono.morny.system.telegram_api.formatting.TelegramFormatter.* import cc.sukazyo.cono.morny.system.telegram_api.formatting.TelegramParseEscape.escapeHtml as h @@ -26,7 +27,9 @@ import com.pengrad.telegrambot.TelegramException import java.time.ZoneId -class MornyReport (using coeur: MornyCoeur) { +class MornyReport (using val coeur: MornyCoeur) { + + given reporter: MornyReport = this private val enabled = coeur.config.reportToChat != -1 if !enabled then @@ -146,6 +149,8 @@ class MornyReport (using coeur: MornyCoeur) { ).parseMode(ParseMode HTML)) } + object botErrorsReport extends BotErrorsReport() + object EventStatistics { private var eventTotal = 0 @@ -280,3 +285,10 @@ class MornyReport (using coeur: MornyCoeur) { } } + +object MornyReport { + + def inCoeur (coeur: MornyCoeur): MornyReport = + coeur.externalContext.getUnsafe[MornyReport] + +} diff --git a/morny-coeur/src/main/scala/cc/sukazyo/cono/morny/reporter/telegram_bot/BotErrorsReport.scala b/morny-coeur/src/main/scala/cc/sukazyo/cono/morny/reporter/telegram_bot/BotErrorsReport.scala new file mode 100644 index 0000000..188bc26 --- /dev/null +++ b/morny-coeur/src/main/scala/cc/sukazyo/cono/morny/reporter/telegram_bot/BotErrorsReport.scala @@ -0,0 +1,38 @@ +package cc.sukazyo.cono.morny.reporter.telegram_bot + +import cc.sukazyo.cono.morny.core.event.TelegramBotEvents +import cc.sukazyo.cono.morny.reporter.MornyReport + +class BotErrorsReport (using reporter: MornyReport) { + + private val _TBotEvents = TelegramBotEvents.inCoeur(using reporter.coeur) + + val onGetUpdateFailed: _TBotEvents.OnGetUpdateFailed.MyCallback + = telegramException => { + + if (telegramException.response != null) { + // if the response exists, means connections to the server is successful, but + // server can't process the request. + // due to connections to the server is ok, the report should be able to send to + // the telegram side. + reporter.exception(telegramException, "Failed get updates.") + } + + if (telegramException.getCause != null) { + import java.net.{SocketException, SocketTimeoutException} + import javax.net.ssl.SSLHandshakeException + val caused = telegramException.getCause + caused match + case _: (SSLHandshakeException|SocketException|SocketTimeoutException) => + case e_other => + reporter.exception(e_other, "Failed get updates.") + } + + } + + val onEventListenersThrowException: _TBotEvents.OnListenerOccursException.MyCallback + = (e, _, _) => { + reporter.exception(e, "on event running") + } + +} diff --git a/morny-coeur/src/main/scala/cc/sukazyo/cono/morny/social_share/external/twitter/package.scala b/morny-coeur/src/main/scala/cc/sukazyo/cono/morny/social_share/external/twitter/package.scala index bfe5892..16a403c 100644 --- a/morny-coeur/src/main/scala/cc/sukazyo/cono/morny/social_share/external/twitter/package.scala +++ b/morny-coeur/src/main/scala/cc/sukazyo/cono/morny/social_share/external/twitter/package.scala @@ -2,6 +2,12 @@ package cc.sukazyo.cono.morny.social_share.external import scala.util.matching.Regex +/** Public twitter objects and utilities. + * + * Contains: + * - Twitter's tweet url object [[TweetUrlInformation]], and its parser [[parseTweetUrl]] & + * [[guessTweetUrl]]. + */ package object twitter { private val REGEX_TWEET_URL: Regex = "(?:https?://)?((?:(?:(?:c\\.)?vx|fx|www\\.)?twitter|(?:www\\.|fixup|fixv)?x)\\.com)/((\\w+)/status/(\\d+)(?:/photo/(\\d+))?)/?(?:\\?(\\S+))?"r @@ -69,6 +75,20 @@ package object twitter { )) case _ => None + /** Find all the possible Twitter/X URL from the given text. + * + * It supports url like [[parseTweetUrl]] supports, the only difference is that this + * method can find all the possible urls in the text using [[Regex.findAllMatchIn]], + * instead of strictly match the text. + * + * For each Twitter URL found in the text, a corresponds [[TweetUrlInformation]] will be + * created. + * + * @param text The text that may contain tweet url. + * @return A list of [[TweetUrlInformation]]. + * Each twitter url found in the text corresponds to one [[TwitterUrlInformation]]. + * If no url is found, an empty list will be returned. + */ def guessTweetUrl (text: String): List[TweetUrlInformation] = REGEX_TWEET_URL.findAllMatchIn(text).map(f => { TweetUrlInformation( diff --git a/morny-system-lib/src/main/scala/cc/sukazyo/cono/morny/system/telegram_api/event/EventEnv.scala b/morny-system-lib/src/main/scala/cc/sukazyo/cono/morny/system/telegram_api/event/EventEnv.scala index 9a657ab..f9a89d7 100644 --- a/morny-system-lib/src/main/scala/cc/sukazyo/cono/morny/system/telegram_api/event/EventEnv.scala +++ b/morny-system-lib/src/main/scala/cc/sukazyo/cono/morny/system/telegram_api/event/EventEnv.scala @@ -1,8 +1,8 @@ package cc.sukazyo.cono.morny.system.telegram_api.event import cc.sukazyo.cono.morny.system.utils.EpochDateTime.EpochMillis -import cc.sukazyo.cono.morny.system.utils.GivenContext import cc.sukazyo.messiva.utils.StackUtils +import cc.sukazyo.std.contexts.GivenContext import com.pengrad.telegrambot.model.Update import scala.collection.mutable diff --git a/morny-system-lib/src/main/scala/cc/sukazyo/cono/morny/system/utils/GivenContext.scala b/morny-system-lib/src/main/scala/cc/sukazyo/cono/morny/system/utils/GivenContext.scala deleted file mode 100644 index a25a36e..0000000 --- a/morny-system-lib/src/main/scala/cc/sukazyo/cono/morny/system/utils/GivenContext.scala +++ /dev/null @@ -1,156 +0,0 @@ -package cc.sukazyo.cono.morny.system.utils - -import cc.sukazyo.cono.morny.system.utils.GivenContext.{ContextNotGivenException, FolderClass, RequestItemClass} - -import scala.annotation.targetName -import scala.collection.mutable -import scala.reflect.{classTag, ClassTag} - -object GivenContext { - case class FolderClass (clazz: Option[Class[?]]) - object FolderClass: - def default: FolderClass = FolderClass(None) - case class RequestItemClass (clazz: Class[?]) - - 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. - * - * @example {{{ - * val cxt = GivenContext() - * class BaseClass {} - * class MyImplementation extends BaseClass {} - * - * - * cxt.provide(true) // this provides a Boolean - * cxt.provide[BaseClass](new MyImplementation()) // although this object is of type MyImplementation, but it is stored - * // as BaseClass so you can (and actually can only) read it using BaseClass - * cxt << "string" - * cxt << classOf[Int] -> 1 // you can also manually set the stored type using this method - * - * - * cxt >> { (i: Int) => println(i) } || { println("no Int data in the context") } - * val bool = - * cxt.use[String, Boolean] { s => println(s); true } || { false } // when using .use, the return value must declared - * cxt.consume[String] { s => println(s) } // you can use .consume if you don't care the return - * // and this will return a cxt.ConsumeResult[Any] - * val cxtResultOpt = // use toOption if you do not want fallback calculation - * cxt.use[Int, String](int => s"int: $int").toOption // this returns Option[String] - * val cxtResultOpt2 = - * cxt >> { (int: Int) => s"int: $int" } |? // this returns Option[String] too - * // cxt >> { (int: Int) => cxt >> { (str: String) => { str + int } } } |? // this below is not good to use due to .flatUse - * // is not supported yet. It will return a - * // cxt.ConsumeResult[Option[String]] which is very bad - * - * try { // for now, you can use this way to use multiple data - * val int = cxt.use[Int] // this returns CxtOption[Int] which is Either[ContextNotGivenException, Int] - * .toTry.get - * val str = cxt >> classOf[String] match // this >> returns the same with the .use above - * case Right(s) => s - * case Left(err) => throw err // this is ContextNotGivenException - * val bool = cxt >!> classOf[Boolean] // the easier way to do the above - * } catch case e: ContextNotGivenException => // if any of the above val is not available, it will catch the exception - * e.printStackTrace() - * }}} - * - * TODO: Tests - * - * @since 2.0.0 - */ -//noinspection NoTargetNameAnnotationForOperatorLikeDefinition -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 - - infix def provide [T: ClassTag] (i: T): Unit = - variables += (classTag[T].runtimeClass -> i) - def << [T: ClassTag] (is: (Class[T], T)): Unit = - val (_, i) = is - this.provide[T](i) - def << [T: ClassTag] (i: T): Unit = - this.provide[T](i) - - private type CxtOption[T] = Either[ContextNotGivenException, T] - def use [T: ClassTag]: CxtOption[T] = - given t: RequestItemClass = RequestItemClass(classTag[T].runtimeClass) - variables get t.clazz match - case Some(i) => Right(i.asInstanceOf[T]) - case None => Left(ContextNotGivenException()) - infix def use [T: ClassTag, U] (consumer: T => U): ConsumeResult[U] = - this.use[T] match - case Left(_) => ConsumeFailed[U]() - case Right(i) => ConsumeSucceed[U](consumer(i)) - def >> [T: ClassTag] (t: Class[T]): CxtOption[T] = - this.use[T] - def >!> [T: ClassTag] (t: Class[T]): T = - this.use[T].toTry.get - def >>[T: ClassTag, U] (consumer: T => U): ConsumeResult[U] = - this.use[T,U](consumer) - infix def consume [T: ClassTag] (consume: T => Any): ConsumeResult[Any] = - this.use[T,Any](consume) - - @targetName("ownedBy") - def / [O: ClassTag] (owner: O): OwnedContext[O] = - OwnedContext[O]() - def ownedBy [O: ClassTag]: OwnedContext[O] = - OwnedContext[O]() - - class OwnedContext [O: ClassTag] { - - infix def provide [T: ClassTag] (i: T): Unit = - (variablesWithOwner getOrElseUpdate (classTag[O].runtimeClass, mutable.HashMap.empty)) - .addOne(classTag[T].runtimeClass -> i) - def << [T: ClassTag] (is: (Class[T], T)): Unit = - val (_, i) = is - this.provide[T](i) - def << [T: ClassTag] (i: T): Unit = - this.provide[T](i) - - def use [T: ClassTag]: CxtOption[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()) - infix def use [T: ClassTag, U] (consumer: T => U): ConsumeResult[U] = - use[T] match - case Left(_) => ConsumeFailed[U]() - case Right(i) => ConsumeSucceed[U](consumer(i)) - def >> [T: ClassTag] (t: Class[T]): CxtOption[T] = - this.use[T] - def >!> [T: ClassTag] (t: Class[T]): T = - this.use[T].toTry.get - def >> [T: ClassTag, U] (consumer: T => U): ConsumeResult[U] = - this.use[T,U](consumer) - infix def consume [T: ClassTag] (consume: T => Any): ConsumeResult[Any] = - this.use[T,Any](consume) - - } - - trait ConsumeResult[U]: - def toOption: Option[U] - def |? : Option[U] = toOption - @targetName("orElse") - def || (processor: =>U): U - private class ConsumeSucceed[U] (succeedValue: U) extends ConsumeResult[U]: - override def toOption: Option[U] = Some(succeedValue) - @targetName("orElse") - override def || (processor: => U): U = succeedValue - private class ConsumeFailed[U] extends ConsumeResult[U]: - override def toOption: Option[U] = None - @targetName("orElse") - override def || (processor: => U): U = processor - -} diff --git a/project/MornyConfiguration.scala b/project/MornyConfiguration.scala index 854d35a..3f1f27c 100644 --- a/project/MornyConfiguration.scala +++ b/project/MornyConfiguration.scala @@ -42,10 +42,11 @@ object MornyConfiguration { override val dependencies = Seq( - "com.github.spotbugs" % "spotbugs-annotations" % "4.9.0" % Compile, + "com.github.spotbugs" % "spotbugs-annotations" % "4.9.1" % Compile, "cc.sukazyo" % "messiva" % "0.2.0", "cc.sukazyo" % "resource-tools" % "0.3.1", + "cc.sukazyo" % "da4a" % "0.2.0-SNAPSHOT" changing(), "com.github.pengrad" % "java-telegram-bot-api" % "6.2.0", @@ -88,10 +89,11 @@ object MornyConfiguration { override val dependencies = Seq( - "com.github.spotbugs" % "spotbugs-annotations" % "4.9.0" % Compile, + "com.github.spotbugs" % "spotbugs-annotations" % "4.9.1" % Compile, "cc.sukazyo" % "messiva" % "0.2.0", "cc.sukazyo" % "resource-tools" % "0.3.1", + "cc.sukazyo" % "da4a" % "0.2.0-SNAPSHOT" changing(), "com.github.pengrad" % "java-telegram-bot-api" % "6.2.0", "org.http4s" %% "http4s-dsl" % "0.23.30",