1
0
mirror of https://github.com/InsanusMokrassar/TelegramBotAPI.git synced 2025-09-15 21:29:25 +00:00

add middlewares

This commit is contained in:
2024-10-15 00:17:27 +06:00
parent a7f4ab36c6
commit b5b7482c2f
5 changed files with 168 additions and 44 deletions

View File

@@ -3,6 +3,7 @@ package dev.inmo.tgbotapi.bot.ktor
import dev.inmo.kslog.common.KSLog
import dev.inmo.tgbotapi.bot.TelegramBot
import dev.inmo.tgbotapi.bot.ktor.base.*
import dev.inmo.tgbotapi.bot.ktor.middlewares.TelegramBotMiddlewaresPipelinesHandler
import dev.inmo.tgbotapi.bot.settings.limiters.ExceptionsOnlyLimiter
import dev.inmo.tgbotapi.bot.settings.limiters.RequestLimiter
import dev.inmo.tgbotapi.utils.*
@@ -28,6 +29,10 @@ class KtorRequestsExecutorBuilder(
var logger: KSLog = DefaultKTgBotAPIKSLog
var pipelineStepsHolder: TelegramBotPipelinesHandler = TelegramBotPipelinesHandler
fun includeMiddlewares(block: TelegramBotMiddlewaresPipelinesHandler.Builder.() -> Unit) {
pipelineStepsHolder = TelegramBotMiddlewaresPipelinesHandler.build(block)
}
fun build() = KtorRequestsExecutor(
telegramAPIUrlsKeeper,
client,

View File

@@ -68,7 +68,7 @@ interface TelegramBotPipelinesHandler {
result: Result<T>,
request: Request<T>,
callsFactories: List<KtorCallFactory>
): Result<T> = result.getOrThrow()
): Result<T> = result
companion object : TelegramBotPipelinesHandler
}

View File

@@ -4,6 +4,22 @@ import dev.inmo.tgbotapi.bot.ktor.KtorCallFactory
import dev.inmo.tgbotapi.bot.ktor.TelegramBotPipelinesHandler
import dev.inmo.tgbotapi.requests.abstracts.Request
/**
* @param onRequestException Will be called when some exception happen during [Request] handling. Non-null result of
* lambda will be used as the result of request handling
* @param onBeforeSearchCallFactory Will be called when telegram bot starts to choose which [KtorCallFactory] will handle
* [Request]
* @param onBeforeCallFactoryMakeCall Will be called when telegram bot trying to use [KtorCallFactory] as potential
* handler for [Request]
* @param onAfterCallFactoryMakeCall Will be called when [KtorCallFactory] made call. Non-null result of
* lambda will be used as the result of request handling
* @param onRequestResultPresented Will be called when [KtorCallFactory] **or** [TelegramBotPipelinesHandler]/[TelegramBotMiddleware]
* returned non-null result. Non-null result of lambda will be used as the result of request handling
* @param onRequestResultAbsent Will be called when some there is no any result of [Request] handling. Non-null result of
* lambda will be used as the result of request handling
* @param onRequestReturnResult Latest lambda before result returning. Will be called after all previous stages.
* Non-null result of lambda will be used as the result of request handling
*/
class TelegramBotMiddleware(
internal val onRequestException: (suspend (request: Request<*>, t: Throwable?) -> Any?)? = null,
internal val onBeforeSearchCallFactory: (suspend (request: Request<*>, callsFactories: List<KtorCallFactory>) -> Unit)? = null,

View File

@@ -8,15 +8,21 @@ class TelegramBotMiddlewaresPipelinesHandler(
private val middlewares: List<TelegramBotMiddleware>
) : TelegramBotPipelinesHandler {
override suspend fun <T : Any> onRequestException(request: Request<T>, t: Throwable): T? {
return super.onRequestException(request, t)
return middlewares.firstNotNullOfOrNull {
it.onRequestException(request, t)
} ?: super.onRequestException(request, t)
}
override suspend fun onBeforeSearchCallFactory(request: Request<*>, callsFactories: List<KtorCallFactory>) {
super.onBeforeSearchCallFactory(request, callsFactories)
middlewares.forEach {
it.onBeforeSearchCallFactory(request, callsFactories)
}
}
override suspend fun onBeforeCallFactoryMakeCall(request: Request<*>, potentialFactory: KtorCallFactory) {
super.onBeforeCallFactoryMakeCall(request, potentialFactory)
middlewares.forEach {
it.onBeforeCallFactoryMakeCall(request, potentialFactory)
}
}
override suspend fun <T : Any> onAfterCallFactoryMakeCall(
@@ -24,7 +30,9 @@ class TelegramBotMiddlewaresPipelinesHandler(
request: Request<T>,
potentialFactory: KtorCallFactory
): T? {
return super.onAfterCallFactoryMakeCall(result, request, potentialFactory)
return middlewares.firstNotNullOfOrNull {
it.onAfterCallFactoryMakeCall(result, request, potentialFactory)
} ?: super.onAfterCallFactoryMakeCall(result, request, potentialFactory)
}
override suspend fun <T : Any> onRequestResultPresented(
@@ -33,14 +41,18 @@ class TelegramBotMiddlewaresPipelinesHandler(
resultCallFactory: KtorCallFactory,
callsFactories: List<KtorCallFactory>
): T? {
return super.onRequestResultPresented(result, request, resultCallFactory, callsFactories)
return middlewares.firstNotNullOfOrNull {
it.onRequestResultPresented(result, request, resultCallFactory, callsFactories)
} ?: super.onRequestResultPresented(result, request, resultCallFactory, callsFactories)
}
override suspend fun <T : Any> onRequestResultAbsent(
request: Request<T>,
callsFactories: List<KtorCallFactory>
): T? {
return super.onRequestResultAbsent(request, callsFactories)
return middlewares.firstNotNullOfOrNull {
it.onRequestResultAbsent(request, callsFactories)
} ?: super.onRequestResultAbsent(request, callsFactories)
}
override suspend fun <T : Any> onRequestReturnResult(
@@ -48,6 +60,27 @@ class TelegramBotMiddlewaresPipelinesHandler(
request: Request<T>,
callsFactories: List<KtorCallFactory>
): Result<T> {
return super.onRequestReturnResult(result, request, callsFactories)
return middlewares.firstNotNullOfOrNull {
it.onRequestReturnResult(result, request, callsFactories).takeIf {
it.onFailure { return@takeIf it !is TelegramBotMiddleware.ResultAbsence }
true
}
} ?: super.onRequestReturnResult(result, request, callsFactories)
}
class Builder {
val middlewares = mutableListOf<TelegramBotMiddleware>()
fun addMiddleware(block: TelegramBotMiddlewareBuilder.() -> Unit) = middlewares.add(
TelegramBotMiddleware.build(block)
)
fun build(): TelegramBotMiddlewaresPipelinesHandler = TelegramBotMiddlewaresPipelinesHandler(
middlewares.toList()
)
}
companion object {
fun build(block: Builder.() -> Unit) = Builder().apply(block).build()
}
}