From 2fb5ab0dc0d0dff11f4d13d6db2a5c179ef6ed94 Mon Sep 17 00:00:00 2001 From: ForteScarlet Date: Tue, 23 Jul 2024 19:48:42 +0800 Subject: [PATCH] feat(core): Support `TelegramBotRegisteredEvent` and `TelegramBotStartedEvent` --- .../core/bot/internal/TelegramBotImpl.kt | 35 ++++++++++------ .../bot/internal/TelegramBotManagerImpl.kt | 28 ++++++------- .../telegram/core/event/TelegramEvent.kt | 14 ++++++- .../core/event/TelegramInternalEvent.kt | 42 +++++++++++++++++++ .../internal/TelegramInternalEventImpls.kt | 40 ++++++++++++++++++ 5 files changed, 130 insertions(+), 29 deletions(-) create mode 100644 simbot-component-telegram-core/src/commonMain/kotlin/love/forte/simbot/component/telegram/core/event/TelegramInternalEvent.kt create mode 100644 simbot-component-telegram-core/src/commonMain/kotlin/love/forte/simbot/component/telegram/core/event/internal/TelegramInternalEventImpls.kt diff --git a/simbot-component-telegram-core/src/commonMain/kotlin/love/forte/simbot/component/telegram/core/bot/internal/TelegramBotImpl.kt b/simbot-component-telegram-core/src/commonMain/kotlin/love/forte/simbot/component/telegram/core/bot/internal/TelegramBotImpl.kt index fbdf92f..6f85fc4 100644 --- a/simbot-component-telegram-core/src/commonMain/kotlin/love/forte/simbot/component/telegram/core/bot/internal/TelegramBotImpl.kt +++ b/simbot-component-telegram-core/src/commonMain/kotlin/love/forte/simbot/component/telegram/core/bot/internal/TelegramBotImpl.kt @@ -19,7 +19,9 @@ package love.forte.simbot.component.telegram.core.bot.internal import kotlinx.coroutines.Job import kotlinx.coroutines.ensureActive +import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.collect +import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.onCompletion import kotlinx.coroutines.sync.Mutex import kotlinx.coroutines.sync.withLock @@ -37,12 +39,10 @@ import love.forte.simbot.component.telegram.core.bot.internal.command.TelegramBo import love.forte.simbot.component.telegram.core.bot.internal.command.toTGCommands import love.forte.simbot.component.telegram.core.component.TelegramComponent import love.forte.simbot.component.telegram.core.event.TelegramUnsupportedEvent -import love.forte.simbot.component.telegram.core.event.internal.TelegramChannelMessageEventImpl -import love.forte.simbot.component.telegram.core.event.internal.TelegramChatGroupMessageEventImpl -import love.forte.simbot.component.telegram.core.event.internal.TelegramPrivateMessageEventImpl -import love.forte.simbot.component.telegram.core.event.internal.TelegramSuperGroupMessageEventImpl +import love.forte.simbot.component.telegram.core.event.internal.* import love.forte.simbot.event.Event import love.forte.simbot.event.EventDispatcher +import love.forte.simbot.event.EventResult import love.forte.simbot.event.onEachError import love.forte.simbot.logger.LoggerFactory import love.forte.simbot.telegram.api.bot.GetMeApi @@ -114,6 +114,9 @@ internal class TelegramBotImpl( // mark started isStarted = true + // push start event + eventDispatcher.pushEventWithBot(TelegramBotStartedEventImpl(this), this) + .launchIn(this) } } @@ -139,9 +142,6 @@ internal class TelegramBotImpl( } - - - @OptIn(FragileSimbotAPI::class) internal fun subscribeInternalProcessor( bot: TelegramBotImpl, @@ -151,14 +151,11 @@ internal fun subscribeInternalProcessor( val divider = object : SuspendableUpdateDivider() { private suspend fun pushEvent(event: Event) { bot.logger.debug("Bot {} on event: {}", bot, event) - eventDispatcher.push(event) - .onEachError { result -> - bot.eventLogger.error("Bot {} on event dispatch error result: {}", bot, result, result.content) - } - .onCompletion { + eventDispatcher.pushEventWithBot(event, bot) { flow -> + flow.onCompletion { bot.eventLogger.trace("Bot {} event publish completed", bot) } - .collect() + }.collect() } override suspend fun onMismatchUpdateEvent(name: String, value: Any, update: Update?, context: StdlibEvent) { @@ -379,3 +376,15 @@ internal fun subscribeInternalProcessor( } } + +internal inline fun EventDispatcher.pushEventWithBot( + event: Event, + bot: TelegramBotImpl, + block: (Flow) -> Flow = { it } +): Flow { + return push(event) + .onEachError { result -> + bot.eventLogger.error("Bot {} on event dispatch error result: {}", bot, result, result.content) + } + .let(block) +} diff --git a/simbot-component-telegram-core/src/commonMain/kotlin/love/forte/simbot/component/telegram/core/bot/internal/TelegramBotManagerImpl.kt b/simbot-component-telegram-core/src/commonMain/kotlin/love/forte/simbot/component/telegram/core/bot/internal/TelegramBotManagerImpl.kt index 7a329e3..1f6ad6f 100644 --- a/simbot-component-telegram-core/src/commonMain/kotlin/love/forte/simbot/component/telegram/core/bot/internal/TelegramBotManagerImpl.kt +++ b/simbot-component-telegram-core/src/commonMain/kotlin/love/forte/simbot/component/telegram/core/bot/internal/TelegramBotManagerImpl.kt @@ -18,6 +18,7 @@ package love.forte.simbot.component.telegram.core.bot.internal import kotlinx.coroutines.Job +import kotlinx.coroutines.flow.launchIn import love.forte.simbot.bot.ConflictBotException import love.forte.simbot.bot.JobBasedBotManager import love.forte.simbot.common.collection.computeValue @@ -25,13 +26,13 @@ import love.forte.simbot.common.collection.concurrentMutableMap import love.forte.simbot.common.collection.removeValue import love.forte.simbot.common.coroutines.mergeWith import love.forte.simbot.common.id.ID -import love.forte.simbot.common.id.NumericalID import love.forte.simbot.common.id.literal import love.forte.simbot.component.telegram.core.bot.TelegramBot import love.forte.simbot.component.telegram.core.bot.TelegramBotConfiguration import love.forte.simbot.component.telegram.core.bot.TelegramBotManager import love.forte.simbot.component.telegram.core.bot.TelegramBotManagerConfiguration import love.forte.simbot.component.telegram.core.component.TelegramComponent +import love.forte.simbot.component.telegram.core.event.internal.TelegramBotRegisteredEventImpl import love.forte.simbot.event.EventDispatcher import love.forte.simbot.telegram.stdlib.bot.Bot import love.forte.simbot.telegram.stdlib.bot.BotFactory @@ -53,7 +54,7 @@ internal class TelegramBotManagerImpl( private val botsWithTokenKey = concurrentMutableMap() // id token cache - private val idTokenMap = concurrentMutableMap() + // private val idTokenMap = concurrentMutableMap() override fun register(ticket: Bot.Ticket, configuration: TelegramBotConfiguration): TelegramBot { val token = ticket.token @@ -78,12 +79,12 @@ internal class TelegramBotManagerImpl( createBot() }!! - // TODO register update idTokenMap - newBot.onCompletion { botsWithTokenKey.removeValue(token) { newBot } } + eventDispatcher.pushRegisteredEvent(newBot) + return newBot } @@ -91,17 +92,14 @@ internal class TelegramBotManagerImpl( botsWithTokenKey.values.asSequence() override fun find(id: ID): TelegramBot? { - fun findByLongId(lid: Long): TelegramBot? = - idTokenMap[lid]?.let { token -> botsWithTokenKey[token] }?.takeIf { it.isActive } - - if (id is NumericalID) { - return findByLongId(id.toLong()) - } - val token = id.literal - val foundByToken = botsWithTokenKey[token] - if (foundByToken != null) return foundByToken - - return token.toLongOrNull()?.let { longId -> findByLongId(longId) } + return botsWithTokenKey[token] } } + +internal fun EventDispatcher.pushRegisteredEvent( + bot: TelegramBotImpl +): Job { + val e = TelegramBotRegisteredEventImpl(bot) + return pushEventWithBot(e, bot).launchIn(bot) +} diff --git a/simbot-component-telegram-core/src/commonMain/kotlin/love/forte/simbot/component/telegram/core/event/TelegramEvent.kt b/simbot-component-telegram-core/src/commonMain/kotlin/love/forte/simbot/component/telegram/core/event/TelegramEvent.kt index b21aaac..8a85393 100644 --- a/simbot-component-telegram-core/src/commonMain/kotlin/love/forte/simbot/component/telegram/core/event/TelegramEvent.kt +++ b/simbot-component-telegram-core/src/commonMain/kotlin/love/forte/simbot/component/telegram/core/event/TelegramEvent.kt @@ -30,13 +30,25 @@ import love.forte.simbot.telegram.type.Message */ public typealias StdlibEvent = love.forte.simbot.telegram.stdlib.event.Event +/** + * An telegram bot event. + * + * @see TelegramEvent + */ +public interface TelegramBotEvent : BotEvent { + /** + * The [TelegramBot]. + */ + override val bot: TelegramBot +} + /** * Is a Telegram simbot component event definition type. * Is an implementation of the event type in the simbot API. * * @author ForteScarlet */ -public interface TelegramEvent : BotEvent { +public interface TelegramEvent : TelegramBotEvent { // 所有的 Telegram Event 都是建立在 Bot 之上的, // 因此所有 TelegramEvent 都实现 BotEvent diff --git a/simbot-component-telegram-core/src/commonMain/kotlin/love/forte/simbot/component/telegram/core/event/TelegramInternalEvent.kt b/simbot-component-telegram-core/src/commonMain/kotlin/love/forte/simbot/component/telegram/core/event/TelegramInternalEvent.kt new file mode 100644 index 0000000..a8e682a --- /dev/null +++ b/simbot-component-telegram-core/src/commonMain/kotlin/love/forte/simbot/component/telegram/core/event/TelegramInternalEvent.kt @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2024. ForteScarlet. + * + * This file is part of simbot-component-telegram. + * + * simbot-component-telegram is free software: you can redistribute it and/or modify it under the terms + * of the GNU Lesser General Public License as published by the Free Software Foundation, + * either version 3 of the License, or (at your option) any later version. + * + * simbot-component-telegram 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License along with simbot-component-telegram. + * If not, see . + */ + +package love.forte.simbot.component.telegram.core.event + +import love.forte.simbot.component.telegram.core.bot.TelegramBot +import love.forte.simbot.event.BotRegisteredEvent + + +/** + * An event that indicating a [TelegramBot] has been registered. + * + * This is an event used as a notification + * that the bot may not have been started yet. + */ +public interface TelegramBotRegisteredEvent : BotRegisteredEvent, TelegramBotEvent { + override val bot: TelegramBot +} + +/** + * An event that indicating a [TelegramBot] has been started at the first time. + * + * This is an event used as a notification. + * At this point, [bot.isStarted][TelegramBot.isStarted] is already `true`. + */ +public interface TelegramBotStartedEvent : BotRegisteredEvent, TelegramBotEvent { + override val bot: TelegramBot +} diff --git a/simbot-component-telegram-core/src/commonMain/kotlin/love/forte/simbot/component/telegram/core/event/internal/TelegramInternalEventImpls.kt b/simbot-component-telegram-core/src/commonMain/kotlin/love/forte/simbot/component/telegram/core/event/internal/TelegramInternalEventImpls.kt new file mode 100644 index 0000000..cc73def --- /dev/null +++ b/simbot-component-telegram-core/src/commonMain/kotlin/love/forte/simbot/component/telegram/core/event/internal/TelegramInternalEventImpls.kt @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2024. ForteScarlet. + * + * This file is part of simbot-component-telegram. + * + * simbot-component-telegram is free software: you can redistribute it and/or modify it under the terms + * of the GNU Lesser General Public License as published by the Free Software Foundation, + * either version 3 of the License, or (at your option) any later version. + * + * simbot-component-telegram 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License along with simbot-component-telegram. + * If not, see . + */ + +package love.forte.simbot.component.telegram.core.event.internal + +import love.forte.simbot.annotations.ExperimentalSimbotAPI +import love.forte.simbot.common.id.ID +import love.forte.simbot.common.id.UUID +import love.forte.simbot.common.time.Timestamp +import love.forte.simbot.component.telegram.core.bot.TelegramBot +import love.forte.simbot.component.telegram.core.event.TelegramBotRegisteredEvent +import love.forte.simbot.component.telegram.core.event.TelegramBotStartedEvent + +internal class TelegramBotRegisteredEventImpl(override val bot: TelegramBot) : TelegramBotRegisteredEvent { + override val id: ID = UUID.random() + + @OptIn(ExperimentalSimbotAPI::class) + override val time: Timestamp = Timestamp.now() +} + +internal class TelegramBotStartedEventImpl(override val bot: TelegramBot) : TelegramBotStartedEvent { + override val id: ID = UUID.random() + + @OptIn(ExperimentalSimbotAPI::class) + override val time: Timestamp = Timestamp.now() +}