diff --git a/CHANGELOG.md b/CHANGELOG.md index c880f4c995..fc0eeb7b71 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,9 @@ ## 0.38.13 +* `Core`: + * Fixes in `mention` creation + ## 0.38.12 * `Common`: diff --git a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/bot/Ktor/KtorCallFactory.kt b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/bot/Ktor/KtorCallFactory.kt index 859f7a4113..10d89d744c 100644 --- a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/bot/Ktor/KtorCallFactory.kt +++ b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/bot/Ktor/KtorCallFactory.kt @@ -1,5 +1,6 @@ package dev.inmo.tgbotapi.bot.Ktor +import dev.inmo.micro_utils.common.Optional import dev.inmo.tgbotapi.requests.abstracts.Request import dev.inmo.tgbotapi.utils.TelegramAPIUrlsKeeper import io.ktor.client.HttpClient diff --git a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/bot/Ktor/KtorRequestsExecutor.kt b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/bot/Ktor/KtorRequestsExecutor.kt index ebbc38bebb..16168229f7 100644 --- a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/bot/Ktor/KtorRequestsExecutor.kt +++ b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/bot/Ktor/KtorRequestsExecutor.kt @@ -5,6 +5,7 @@ import dev.inmo.tgbotapi.bot.BaseRequestsExecutor import dev.inmo.tgbotapi.bot.Ktor.base.* import dev.inmo.tgbotapi.bot.TelegramBot import dev.inmo.tgbotapi.bot.exceptions.newRequestException +import dev.inmo.tgbotapi.bot.ktor.KtorPipelineStepsHolder import dev.inmo.tgbotapi.bot.settings.limiters.ExceptionsOnlyLimiter import dev.inmo.tgbotapi.bot.settings.limiters.RequestLimiter import dev.inmo.tgbotapi.requests.abstracts.Request @@ -56,7 +57,8 @@ class KtorRequestsExecutor( callsFactories: List = emptyList(), excludeDefaultFactories: Boolean = false, private val requestsLimiter: RequestLimiter = ExceptionsOnlyLimiter(), - private val jsonFormatter: Json = nonstrictJsonFormat + private val jsonFormatter: Json = nonstrictJsonFormat, + private val pipelineStepsHolder: KtorPipelineStepsHolder = TODO() ) : BaseRequestsExecutor(telegramAPIUrlsKeeper) { private val callsFactories: List = callsFactories.run { if (!excludeDefaultFactories) { @@ -75,6 +77,8 @@ class KtorRequestsExecutor( override suspend fun execute(request: Request): T { return safely( { e -> + pipelineStepsHolder.onRequestException(request, e) ?.let { return@safely it } + throw if (e is ClientRequestException) { val content = e.response.readText() val responseObject = jsonFormatter.decodeFromString(Response.serializer(), content) @@ -88,21 +92,28 @@ class KtorRequestsExecutor( } } ) { + pipelineStepsHolder.onBeforeSearchCallFactory(request, callsFactories) requestsLimiter.limit { var result: T? = null + lateinit var factoryHandledRequest: KtorCallFactory for (potentialFactory in callsFactories) { + pipelineStepsHolder.onBeforeCallFactoryMakeCall(request, potentialFactory) result = potentialFactory.makeCall( client, telegramAPIUrlsKeeper, request, jsonFormatter ) + result = pipelineStepsHolder.onAfterCallFactoryMakeCall(result, request, potentialFactory) if (result != null) { + factoryHandledRequest = potentialFactory break } } - result ?: error("Can't execute request: $request") + result ?.let { + pipelineStepsHolder.onRequestResultPresented(it, request, factoryHandledRequest, callsFactories) + } ?: pipelineStepsHolder.onRequestResultAbsent(request, callsFactories) ?: error("Can't execute request: $request") } } } diff --git a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/bot/ktor/KtorPipelineStepsHolder.kt b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/bot/ktor/KtorPipelineStepsHolder.kt new file mode 100644 index 0000000000..f5b499e244 --- /dev/null +++ b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/bot/ktor/KtorPipelineStepsHolder.kt @@ -0,0 +1,63 @@ +package dev.inmo.tgbotapi.bot.ktor + +import dev.inmo.tgbotapi.bot.Ktor.KtorCallFactory +import dev.inmo.tgbotapi.requests.abstracts.Request + +interface KtorPipelineStepsHolder { + /** + * Will be called when any exception will happen due to the [request] handling. If returns value - that value + * will be returned from [dev.inmo.tgbotapi.bot.RequestsExecutor.execute] instead + */ + suspend fun onRequestException( + request: Request, + t: Throwable + ): T? = null + + /** + * Will always be called before requests executor will check all [callsFactories] for an opportunity to make call of + * [request] + */ + suspend fun onBeforeSearchCallFactory( + request: Request<*>, + callsFactories: List + ) {} + + /** + * Will always be called before [potentialFactory] will try to make [request] + */ + suspend fun onBeforeCallFactoryMakeCall( + request: Request<*>, + potentialFactory: KtorCallFactory + ) {} + + /** + * Will always be called after [potentialFactory] has tried to make [request] and got some [result]. If returns + * value - that value will be returned from [dev.inmo.tgbotapi.bot.RequestsExecutor.execute] instead + */ + suspend fun onAfterCallFactoryMakeCall( + result: T?, + request: Request, + potentialFactory: KtorCallFactory + ): T? = result + + /** + * Will be called when [resultCallFactory] is the [KtorCallFactory] from [callsFactories] which has successfully + * handled [request] and returned [result]. If returns value - that value will be returned from + * [dev.inmo.tgbotapi.bot.RequestsExecutor.execute] instead + */ + suspend fun onRequestResultPresented( + result: T, + request: Request, + resultCallFactory: KtorCallFactory, + callsFactories: List + ): T? = result + + /** + * Will be called when there is no [KtorCallFactory] from [callsFactories] which may handle [request]. If returns + * value - that value will be returned from [dev.inmo.tgbotapi.bot.RequestsExecutor.execute] instead + */ + suspend fun onRequestResultAbsent( + request: Request, + callsFactories: List + ): T? = null +} diff --git a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/MessageEntity/textsources/TextMentionTextSource.kt b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/MessageEntity/textsources/TextMentionTextSource.kt index 495b18c2c9..359c296b3c 100644 --- a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/MessageEntity/textsources/TextMentionTextSource.kt +++ b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/MessageEntity/textsources/TextMentionTextSource.kt @@ -33,7 +33,12 @@ inline fun mention(parts: TextSourcesList, id: Identifier) = mention(parts, User @Suppress("NOTHING_TO_INLINE") inline fun Identifier.mention(parts: TextSourcesList) = mention(parts, this) @Suppress("NOTHING_TO_INLINE") -inline fun mention(user: User, vararg parts: TextSource) = mention(parts.toList(), user) +inline fun mention(user: User, vararg parts: TextSource) = mention( + textSourcesOrElseTextSource(parts.toList()) { + RegularTextSource("${user.lastName} ${user.firstName}") + }, + user +) @Suppress("NOTHING_TO_INLINE") inline fun mention(text: String, user: User) = mention(user, regular(text)) @Suppress("NOTHING_TO_INLINE") diff --git a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/MessageEntity/textsources/TextSourcesOrElse.kt b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/MessageEntity/textsources/TextSourcesOrElse.kt new file mode 100644 index 0000000000..68643b5f34 --- /dev/null +++ b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/MessageEntity/textsources/TextSourcesOrElse.kt @@ -0,0 +1,17 @@ +package dev.inmo.tgbotapi.types.MessageEntity.textsources + +import dev.inmo.tgbotapi.utils.RiskFeature +import kotlin.js.JsName +import kotlin.jvm.JvmName + +@RiskFeature +inline fun textSourcesOrElse( + textSources: TextSourcesList, + block: () -> TextSourcesList +): TextSourcesList = textSources.takeIf { it.isNotEmpty() } ?: block() + +@RiskFeature +inline fun textSourcesOrElseTextSource( + textSources: TextSourcesList, + block: () -> TextSource +): TextSourcesList = textSources.takeIf { it.isNotEmpty() } ?: listOf(block())