1
0
mirror of https://github.com/InsanusMokrassar/TelegramBotAPI.git synced 2024-12-22 16:47:13 +00:00

start adding middlewares

This commit is contained in:
InsanusMokrassar 2024-10-14 14:44:07 +06:00
parent 7398e53b85
commit a7f4ab36c6
8 changed files with 175 additions and 20 deletions

View File

@ -24,7 +24,7 @@ expect class KtorRequestsExecutor internal constructor(
excludeDefaultFactories: Boolean,
requestsLimiter: RequestLimiter,
jsonFormatter: Json,
pipelineStepsHolder: KtorPipelineStepsHolder,
pipelineStepsHolder: TelegramBotPipelinesHandler,
logger: KSLog,
diff: Unit // just a diff property to know where constructor and where calling function with defaults
) : BaseRequestsExecutor {
@ -39,7 +39,7 @@ fun KtorRequestsExecutor(
excludeDefaultFactories: Boolean = false,
requestsLimiter: RequestLimiter = ExceptionsOnlyLimiter,
jsonFormatter: Json = nonstrictJsonFormat,
pipelineStepsHolder: KtorPipelineStepsHolder = KtorPipelineStepsHolder,
pipelineStepsHolder: TelegramBotPipelinesHandler = TelegramBotPipelinesHandler,
logger: KSLog = DefaultKTgBotAPIKSLog,
) = KtorRequestsExecutor(
telegramAPIUrlsKeeper = telegramAPIUrlsKeeper,

View File

@ -1,7 +1,6 @@
package dev.inmo.tgbotapi.bot.ktor
import dev.inmo.kslog.common.KSLog
import dev.inmo.tgbotapi.bot.BaseRequestsExecutor
import dev.inmo.tgbotapi.bot.TelegramBot
import dev.inmo.tgbotapi.bot.ktor.base.*
import dev.inmo.tgbotapi.bot.settings.limiters.ExceptionsOnlyLimiter
@ -27,7 +26,7 @@ class KtorRequestsExecutorBuilder(
var requestsLimiter: RequestLimiter = ExceptionsOnlyLimiter
var jsonFormatter: Json = nonstrictJsonFormat
var logger: KSLog = DefaultKTgBotAPIKSLog
var pipelineStepsHolder: KtorPipelineStepsHolder = KtorPipelineStepsHolder
var pipelineStepsHolder: TelegramBotPipelinesHandler = TelegramBotPipelinesHandler
fun build() = KtorRequestsExecutor(
telegramAPIUrlsKeeper,

View File

@ -2,7 +2,7 @@ package dev.inmo.tgbotapi.bot.ktor
import dev.inmo.tgbotapi.requests.abstracts.Request
interface KtorPipelineStepsHolder {
interface TelegramBotPipelinesHandler {
/**
* 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
@ -68,7 +68,10 @@ interface KtorPipelineStepsHolder {
result: Result<T>,
request: Request<T>,
callsFactories: List<KtorCallFactory>
): T = result.getOrThrow()
): Result<T> = result.getOrThrow()
companion object : KtorPipelineStepsHolder
companion object : TelegramBotPipelinesHandler
}
@Deprecated("Renamed", ReplaceWith("TelegramBotPipelinesHandler", "dev.inmo.tgbotapi.bot.ktor.TelegramBotPipelinesHandler"))
typealias KtorPipelineStepsHolder = TelegramBotPipelinesHandler

View File

@ -1,7 +1,6 @@
package dev.inmo.tgbotapi.bot.ktor.base
import dev.inmo.kslog.common.*
import dev.inmo.micro_utils.coroutines.defaultSafelyExceptionHandler
import dev.inmo.micro_utils.coroutines.runCatchingSafely
import dev.inmo.tgbotapi.bot.BaseRequestsExecutor
import dev.inmo.tgbotapi.bot.exceptions.BotException
@ -9,15 +8,12 @@ import dev.inmo.tgbotapi.bot.exceptions.CommonBotException
import dev.inmo.tgbotapi.bot.exceptions.GetUpdatesConflict
import dev.inmo.tgbotapi.bot.exceptions.newRequestException
import dev.inmo.tgbotapi.bot.ktor.KtorCallFactory
import dev.inmo.tgbotapi.bot.ktor.KtorPipelineStepsHolder
import dev.inmo.tgbotapi.bot.ktor.KtorRequestsExecutor
import dev.inmo.tgbotapi.bot.ktor.TelegramBotPipelinesHandler
import dev.inmo.tgbotapi.bot.ktor.createTelegramBotDefaultKtorCallRequestsFactories
import dev.inmo.tgbotapi.bot.settings.limiters.ExceptionsOnlyLimiter
import dev.inmo.tgbotapi.bot.settings.limiters.RequestLimiter
import dev.inmo.tgbotapi.requests.abstracts.Request
import dev.inmo.tgbotapi.types.Response
import dev.inmo.tgbotapi.utils.TelegramAPIUrlsKeeper
import dev.inmo.tgbotapi.utils.nonstrictJsonFormat
import io.ktor.client.*
import io.ktor.client.plugins.*
import io.ktor.client.statement.*
@ -30,7 +26,7 @@ class DefaultKtorRequestsExecutor internal constructor(
excludeDefaultFactories: Boolean,
private val requestsLimiter: RequestLimiter,
private val jsonFormatter: Json,
private val pipelineStepsHolder: KtorPipelineStepsHolder,
private val pipelineStepsHolder: TelegramBotPipelinesHandler,
private val logger: KSLog,
diff: Unit
) : BaseRequestsExecutor(telegramAPIUrlsKeeper) {
@ -110,7 +106,7 @@ class DefaultKtorRequestsExecutor internal constructor(
}
}
} ?.let { Result.failure(it) } ?: it
pipelineStepsHolder.onRequestReturnResult(result, request, callsFactories).also {
pipelineStepsHolder.onRequestReturnResult(result, request, callsFactories).getOrThrow().also {
logger.v { "Result of handling $request: $it" }
}
}

View File

@ -4,13 +4,10 @@ import dev.inmo.kslog.common.KSLog
import dev.inmo.micro_utils.coroutines.runCatchingSafely
import dev.inmo.tgbotapi.bot.BaseRequestsExecutor
import dev.inmo.tgbotapi.bot.ktor.KtorCallFactory
import dev.inmo.tgbotapi.bot.ktor.KtorPipelineStepsHolder
import dev.inmo.tgbotapi.bot.ktor.KtorRequestsExecutor
import dev.inmo.tgbotapi.bot.settings.limiters.ExceptionsOnlyLimiter
import dev.inmo.tgbotapi.bot.ktor.TelegramBotPipelinesHandler
import dev.inmo.tgbotapi.bot.settings.limiters.RequestLimiter
import dev.inmo.tgbotapi.requests.abstracts.Request
import dev.inmo.tgbotapi.utils.TelegramAPIUrlsKeeper
import dev.inmo.tgbotapi.utils.nonstrictJsonFormat
import io.ktor.client.*
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.first
@ -47,7 +44,7 @@ class MultipleClientKtorRequestsExecutor (
excludeDefaultFactories: Boolean,
requestsLimiter: RequestLimiter,
jsonFormatter: Json,
pipelineStepsHolder: KtorPipelineStepsHolder,
pipelineStepsHolder: TelegramBotPipelinesHandler,
requestExecutorsCount: Int,
logger: KSLog,
clientFactory: () -> HttpClient
@ -82,7 +79,7 @@ class MultipleClientKtorRequestsExecutor (
excludeDefaultFactories: Boolean,
requestsLimiter: RequestLimiter,
jsonFormatter: Json,
pipelineStepsHolder: KtorPipelineStepsHolder,
pipelineStepsHolder: TelegramBotPipelinesHandler,
logger: KSLog,
diff: Unit
) : this(

View File

@ -0,0 +1,64 @@
package dev.inmo.tgbotapi.bot.ktor.middlewares
import dev.inmo.tgbotapi.bot.ktor.KtorCallFactory
import dev.inmo.tgbotapi.bot.ktor.TelegramBotPipelinesHandler
import dev.inmo.tgbotapi.requests.abstracts.Request
class TelegramBotMiddleware(
internal val onRequestException: (suspend (request: Request<*>, t: Throwable?) -> Any?)? = null,
internal val onBeforeSearchCallFactory: (suspend (request: Request<*>, callsFactories: List<KtorCallFactory>) -> Unit)? = null,
internal val onBeforeCallFactoryMakeCall: (suspend (request: Request<*>, potentialFactory: KtorCallFactory) -> Unit)? = null,
internal val onAfterCallFactoryMakeCall: (suspend (result: Any?, request: Request<*>, potentialFactory: KtorCallFactory) -> Any?)? = null,
internal val onRequestResultPresented: (suspend (result: Any?, request: Request<*>, resultCallFactory: KtorCallFactory, callsFactories: List<KtorCallFactory>) -> Any?)? = null,
internal val onRequestResultAbsent: (suspend (request: Request<*>, callsFactories: List<KtorCallFactory>) -> Any?)? = null,
internal val onRequestReturnResult: (suspend (result: Result<*>, request: Request<*>, callsFactories: List<KtorCallFactory>) -> Result<Any?>?)? = null,
) : TelegramBotPipelinesHandler {
object ResultAbsence : Throwable()
override suspend fun <T : Any> onRequestException(request: Request<T>, t: Throwable): T? {
return onRequestException ?.invoke(request, t) as? T
}
override suspend fun onBeforeSearchCallFactory(request: Request<*>, callsFactories: List<KtorCallFactory>) {
onBeforeSearchCallFactory ?.invoke(request, callsFactories)
}
override suspend fun onBeforeCallFactoryMakeCall(request: Request<*>, potentialFactory: KtorCallFactory) {
onBeforeCallFactoryMakeCall ?.invoke(request, potentialFactory)
}
override suspend fun <T : Any> onAfterCallFactoryMakeCall(
result: T?,
request: Request<T>,
potentialFactory: KtorCallFactory
): T? {
return onAfterCallFactoryMakeCall ?.invoke(result, request, potentialFactory) as? T
}
override suspend fun <T : Any> onRequestResultPresented(
result: T,
request: Request<T>,
resultCallFactory: KtorCallFactory,
callsFactories: List<KtorCallFactory>
): T? {
return onRequestResultPresented ?.invoke(result, request, resultCallFactory, callsFactories) as? T
}
override suspend fun <T : Any> onRequestResultAbsent(
request: Request<T>,
callsFactories: List<KtorCallFactory>
): T? {
return onRequestResultAbsent ?.invoke(request, callsFactories) as? T
}
override suspend fun <T : Any> onRequestReturnResult(
result: Result<T>,
request: Request<T>,
callsFactories: List<KtorCallFactory>
): Result<T> {
return onRequestReturnResult ?.invoke(result, request, callsFactories) as? Result<T> ?: Result.failure(ResultAbsence)
}
companion object {
fun build(block: TelegramBotMiddlewareBuilder.() -> Unit): TelegramBotMiddleware = TelegramBotMiddlewareBuilder().apply(block).build()
}
}

View File

@ -0,0 +1,43 @@
package dev.inmo.tgbotapi.bot.ktor.middlewares
import dev.inmo.tgbotapi.bot.ktor.KtorCallFactory
import dev.inmo.tgbotapi.bot.ktor.TelegramBotPipelinesHandler
import dev.inmo.tgbotapi.requests.abstracts.Request
class TelegramBotMiddlewareBuilder {
var onRequestException: (suspend (request: Request<*>, t: Throwable?) -> Any?)? = null
var onBeforeSearchCallFactory: (suspend (request: Request<*>, callsFactories: List<KtorCallFactory>) -> Unit)? = null
var onBeforeCallFactoryMakeCall: (suspend (request: Request<*>, potentialFactory: KtorCallFactory) -> Unit)? = null
var onAfterCallFactoryMakeCall: (suspend (result: Any?, request: Request<*>, potentialFactory: KtorCallFactory) -> Any?)? = null
var onRequestResultPresented: (suspend (result: Any?, request: Request<*>, resultCallFactory: KtorCallFactory, callsFactories: List<KtorCallFactory>) -> Any?)? = null
var onRequestResultAbsent: (suspend (request: Request<*>, callsFactories: List<KtorCallFactory>) -> Any?)? = null
var onRequestReturnResult: (suspend (result: Result<*>, request: Request<*>, callsFactories: List<KtorCallFactory>) -> Result<Any?>?)? = null
fun build(): TelegramBotMiddleware {
return TelegramBotMiddleware(
onRequestException = onRequestException,
onBeforeSearchCallFactory = onBeforeSearchCallFactory,
onBeforeCallFactoryMakeCall = onBeforeCallFactoryMakeCall,
onAfterCallFactoryMakeCall = onAfterCallFactoryMakeCall,
onRequestResultPresented = onRequestResultPresented,
onRequestResultAbsent = onRequestResultAbsent,
onRequestReturnResult = onRequestReturnResult
)
}
companion object {
fun from(middleware: TelegramBotMiddleware, additionalSetup: TelegramBotMiddlewareBuilder.() -> Unit): TelegramBotMiddleware {
return TelegramBotMiddlewareBuilder().apply {
onRequestException = middleware.onRequestException
onBeforeSearchCallFactory = middleware.onBeforeSearchCallFactory
onBeforeCallFactoryMakeCall = middleware.onBeforeCallFactoryMakeCall
onAfterCallFactoryMakeCall = middleware.onAfterCallFactoryMakeCall
onRequestResultPresented = middleware.onRequestResultPresented
onRequestResultAbsent = middleware.onRequestResultAbsent
onRequestReturnResult = middleware.onRequestReturnResult
additionalSetup()
}.build()
}
}
}

View File

@ -0,0 +1,53 @@
package dev.inmo.tgbotapi.bot.ktor.middlewares
import dev.inmo.tgbotapi.bot.ktor.KtorCallFactory
import dev.inmo.tgbotapi.bot.ktor.TelegramBotPipelinesHandler
import dev.inmo.tgbotapi.requests.abstracts.Request
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)
}
override suspend fun onBeforeSearchCallFactory(request: Request<*>, callsFactories: List<KtorCallFactory>) {
super.onBeforeSearchCallFactory(request, callsFactories)
}
override suspend fun onBeforeCallFactoryMakeCall(request: Request<*>, potentialFactory: KtorCallFactory) {
super.onBeforeCallFactoryMakeCall(request, potentialFactory)
}
override suspend fun <T : Any> onAfterCallFactoryMakeCall(
result: T?,
request: Request<T>,
potentialFactory: KtorCallFactory
): T? {
return super.onAfterCallFactoryMakeCall(result, request, potentialFactory)
}
override suspend fun <T : Any> onRequestResultPresented(
result: T,
request: Request<T>,
resultCallFactory: KtorCallFactory,
callsFactories: List<KtorCallFactory>
): T? {
return super.onRequestResultPresented(result, request, resultCallFactory, callsFactories)
}
override suspend fun <T : Any> onRequestResultAbsent(
request: Request<T>,
callsFactories: List<KtorCallFactory>
): T? {
return super.onRequestResultAbsent(request, callsFactories)
}
override suspend fun <T : Any> onRequestReturnResult(
result: Result<T>,
request: Request<T>,
callsFactories: List<KtorCallFactory>
): Result<T> {
return super.onRequestReturnResult(result, request, callsFactories)
}
}