1
0
mirror of https://github.com/InsanusMokrassar/TelegramBotAPI.git synced 2025-12-11 08:45:44 +00:00

Compare commits

...

4 Commits

7 changed files with 149 additions and 32 deletions

View File

@@ -1,5 +1,10 @@
# TelegramBotAPI changelog
## 0.38.13
* `Core`:
* Fixes in `mention` creation
## 0.38.12
* `Common`:

View File

@@ -20,6 +20,6 @@ javax_activation_version=1.1.1
dokka_version=1.6.10
library_group=dev.inmo
library_version=0.38.12
library_version=0.38.13
github_release_plugin_version=2.2.12

View File

@@ -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

View File

@@ -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<KtorCallFactory> = 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<KtorCallFactory> = callsFactories.run {
if (!excludeDefaultFactories) {
@@ -73,37 +75,51 @@ class KtorRequestsExecutor(
}
override suspend fun <T : Any> execute(request: Request<T>): T {
return safely(
{ e ->
throw if (e is ClientRequestException) {
val content = e.response.readText()
val responseObject = jsonFormatter.decodeFromString(Response.serializer(), content)
newRequestException(
responseObject,
content,
"Can't get result object from $content"
)
} else {
e
}
}
) {
requestsLimiter.limit {
var result: T? = null
for (potentialFactory in callsFactories) {
result = potentialFactory.makeCall(
client,
telegramAPIUrlsKeeper,
request,
jsonFormatter
)
if (result != null) {
break
}
}
return runCatching {
safely(
{ e ->
pipelineStepsHolder.onRequestException(request, e) ?.let { return@safely it }
result ?: error("Can't execute request: $request")
throw if (e is ClientRequestException) {
val content = e.response.readText()
val responseObject = jsonFormatter.decodeFromString(Response.serializer(), content)
newRequestException(
responseObject,
content,
"Can't get result object from $content"
)
} else {
e
}
}
) {
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 ?.let {
pipelineStepsHolder.onRequestResultPresented(it, request, factoryHandledRequest, callsFactories)
} ?: pipelineStepsHolder.onRequestResultAbsent(request, callsFactories) ?: error("Can't execute request: $request")
}
}
}.let {
pipelineStepsHolder.onRequestReturnResult(it, request, callsFactories)
}
}

View File

@@ -0,0 +1,73 @@
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 <T: Any> onRequestException(
request: Request<T>,
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<KtorCallFactory>
) {}
/**
* 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 <T: Any> onAfterCallFactoryMakeCall(
result: T?,
request: Request<T>,
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 <T: Any> onRequestResultPresented(
result: T,
request: Request<T>,
resultCallFactory: KtorCallFactory,
callsFactories: List<KtorCallFactory>
): 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 <T: Any> onRequestResultAbsent(
request: Request<T>,
callsFactories: List<KtorCallFactory>
): T? = null
/**
* This step will be called when the [result] has been retrieved (or exception has happened). If returns value -
* that value will be returned from [dev.inmo.tgbotapi.bot.RequestsExecutor.execute] instead
*/
suspend fun <T: Any> onRequestReturnResult(
result: Result<T>,
request: Request<T>,
callsFactories: List<KtorCallFactory>
): T = result.getOrThrow()
}

View File

@@ -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")

View File

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