Skip to content

Commit

Permalink
feat(core): Support TelegramBotRegisteredEvent and `TelegramBotStar…
Browse files Browse the repository at this point in the history
…tedEvent`
  • Loading branch information
ForteScarlet committed Jul 23, 2024
1 parent 16fc260 commit 2fb5ab0
Show file tree
Hide file tree
Showing 5 changed files with 130 additions and 29 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
Expand Down Expand Up @@ -114,6 +114,9 @@ internal class TelegramBotImpl(

// mark started
isStarted = true
// push start event
eventDispatcher.pushEventWithBot(TelegramBotStartedEventImpl(this), this)
.launchIn(this)
}
}

Expand All @@ -139,9 +142,6 @@ internal class TelegramBotImpl(
}





@OptIn(FragileSimbotAPI::class)
internal fun subscribeInternalProcessor(
bot: TelegramBotImpl,
Expand All @@ -151,14 +151,11 @@ internal fun subscribeInternalProcessor(
val divider = object : SuspendableUpdateDivider<StdlibEvent>() {
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) {
Expand Down Expand Up @@ -379,3 +376,15 @@ internal fun subscribeInternalProcessor(
}
}


internal inline fun EventDispatcher.pushEventWithBot(
event: Event,
bot: TelegramBotImpl,
block: (Flow<EventResult>) -> Flow<EventResult> = { it }
): Flow<EventResult> {
return push(event)
.onEachError { result ->
bot.eventLogger.error("Bot {} on event dispatch error result: {}", bot, result, result.content)
}
.let(block)
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,20 +18,21 @@
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
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
Expand All @@ -53,7 +54,7 @@ internal class TelegramBotManagerImpl(
private val botsWithTokenKey = concurrentMutableMap<String, TelegramBotImpl>()

// id token cache
private val idTokenMap = concurrentMutableMap<Long, String>()
// private val idTokenMap = concurrentMutableMap<Long, String>()

override fun register(ticket: Bot.Ticket, configuration: TelegramBotConfiguration): TelegramBot {
val token = ticket.token
Expand All @@ -78,30 +79,27 @@ internal class TelegramBotManagerImpl(
createBot()
}!!

// TODO register update idTokenMap

newBot.onCompletion {
botsWithTokenKey.removeValue(token) { newBot }
}

eventDispatcher.pushRegisteredEvent(newBot)

return newBot
}

override fun all(): Sequence<TelegramBot> =
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)
}
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
Original file line number Diff line number Diff line change
@@ -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 <https://www.gnu.org/licenses/>.
*/

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
}
Original file line number Diff line number Diff line change
@@ -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 <https://www.gnu.org/licenses/>.
*/

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()
}

0 comments on commit 2fb5ab0

Please sign in to comment.