1
0
mirror of https://github.com/InsanusMokrassar/TelegramBotAPI.git synced 2025-12-30 09:59:18 +00:00

Compare commits

...

8 Commits

9 changed files with 68 additions and 50 deletions

View File

@@ -1,6 +1,8 @@
# TelegramBotAPI changelog
## 3.1.2
## 3.2.0
**Since this update, `RequestsExecutor#execute` may throw only `BotException`. In case you wish to handle some exceptions from `execute` you must catch `BotException` and handle its `cause`**
* `Versions`:
* `Serialization`: `1.4.0-RC` -> `1.4.0`

View File

@@ -6,4 +6,4 @@ kotlin.incremental=true
kotlin.incremental.js=true
library_group=dev.inmo
library_version=3.1.2
library_version=3.2.0

View File

@@ -40,7 +40,7 @@ suspend fun BehaviourContext.waitCommandMessage(
) = waitCommandMessage(Regex(command), initRequest, errorFactory)
fun Flow<CommonMessage<TextContent>>.requireCommandAtStart() = filter {
(it.content.textSources.firstOrNull() as? BotCommandTextSource) != null
it.content.textSources.firstOrNull() is BotCommandTextSource
}
/**
@@ -61,7 +61,7 @@ fun Flow<CommonMessage<TextContent>>.requireSingleCommand() = filter {
}
}
true
count == 1
}
/**

View File

@@ -19,5 +19,5 @@ suspend fun BehaviourContext.waitDeepLinks(
.requireSingleCommand()
.requireCommandAtStart()
.flattenCommandsWithParams().mapNotNull {
it.first to (it.second.second.singleOrNull() ?.regularTextSourceOrNull() ?.source ?: return@mapNotNull null)
it.first to (it.second.second.singleOrNull() ?.regularTextSourceOrNull() ?.source ?.removePrefix(" ") ?: return@mapNotNull null)
}

View File

@@ -17,9 +17,11 @@ import dev.inmo.tgbotapi.types.message.content.TextContent
import dev.inmo.tgbotapi.types.message.content.TextMessage
import dev.inmo.tgbotapi.types.message.textsources.RegularTextSource
import dev.inmo.tgbotapi.types.update.abstracts.Update
import io.ktor.http.decodeURLQueryComponent
import kotlinx.coroutines.Job
import kotlinx.coroutines.flow.filter
private val startRegex = Regex("start")
suspend fun <BC : BehaviourContext> BC.onDeepLink(
initialFilter: SimpleFilter<Pair<TextMessage, String>>? = null,
subcontextUpdatesFilter: CustomBehaviourContextAndTwoTypesReceiver<BC, Boolean, Pair<TextMessage, String>, Update> = { (message, _), update -> MessageFilterByChat(this, message, update) },
@@ -36,6 +38,11 @@ suspend fun <BC : BehaviourContext> BC.onDeepLink(
scenarioReceiver,
) {
(it.messageUpdateOrNull()) ?.data ?.commonMessageOrNull() ?.withContentOrNull<TextContent>() ?.let { message ->
message to message.content.textSources[1].source
message to message.content.textSources[1].source.removePrefix(" ").decodeURLQueryComponent()
} ?.let(::listOfNotNull)
}.also {
triggersHolder.handleableCommandsHolder.registerHandleable(startRegex)
it.invokeOnCompletion {
this@onDeepLink.launchSafelyWithoutExceptions { triggersHolder.handleableCommandsHolder.unregisterHandleable(startRegex) }
}
}

View File

@@ -35,13 +35,18 @@ fun newRequestException(
}
} ?: CommonRequestException(response, plainAnswer, message, cause)
sealed class BotException(message: String = "Something went wrong", cause: Throwable? = null) : IOException(message, cause)
class CommonBotException(message: String = "Something went wrong", cause: Throwable? = null) : BotException(message, cause)
sealed class RequestException constructor(
val response: Response,
val plainAnswer: String,
message: String? = null,
override val cause: Throwable? = null
) : IOException(
message ?: "Something went wrong"
cause: Throwable? = null
) : BotException(
message ?: "Something went wrong",
cause
)
class CommonRequestException(response: Response, plainAnswer: String, message: String?, cause: Throwable?) :

View File

@@ -1,9 +1,10 @@
package dev.inmo.tgbotapi.bot.ktor
import dev.inmo.micro_utils.coroutines.runCatchingSafely
import dev.inmo.micro_utils.coroutines.safely
import dev.inmo.tgbotapi.bot.BaseRequestsExecutor
import dev.inmo.tgbotapi.bot.TelegramBot
import dev.inmo.tgbotapi.bot.exceptions.newRequestException
import dev.inmo.tgbotapi.bot.exceptions.*
import dev.inmo.tgbotapi.bot.ktor.base.*
import dev.inmo.tgbotapi.bot.settings.limiters.ExceptionsOnlyLimiter
import dev.inmo.tgbotapi.bot.settings.limiters.RequestLimiter
@@ -48,12 +49,36 @@ class KtorRequestsExecutor(
}
override suspend fun <T : Any> execute(request: Request<T>): T {
return runCatching {
safely(
{ e ->
pipelineStepsHolder.onRequestException(request, e) ?.let { return@safely it }
return runCatchingSafely {
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
}
}
throw if (e is ClientRequestException) {
result ?.let {
pipelineStepsHolder.onRequestResultPresented(it, request, factoryHandledRequest, callsFactories)
} ?: pipelineStepsHolder.onRequestResultAbsent(request, callsFactories) ?: error("Can't execute request: $request")
}
}.let {
val result = it.exceptionOrNull() ?.let { e ->
pipelineStepsHolder.onRequestException(request, e) ?.let { return@let it }
if (e is ClientRequestException) {
val exceptionResult = runCatchingSafely {
val content = e.response.bodyAsText()
val responseObject = jsonFormatter.decodeFromString(Response.serializer(), content)
newRequestException(
@@ -61,38 +86,15 @@ class KtorRequestsExecutor(
content,
"Can't get result object from $content"
)
} else {
e
}
exceptionResult.exceptionOrNull() ?.let {
CommonBotException(cause = e)
} ?: exceptionResult.getOrThrow()
} else {
CommonBotException(cause = 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)
} ?.let { Result.failure(it) } ?: it
pipelineStepsHolder.onRequestReturnResult(result, request, callsFactories)
}
}

View File

@@ -1,6 +1,7 @@
package dev.inmo.tgbotapi.types.message.textsources
import dev.inmo.tgbotapi.types.usernameRegex
import dev.inmo.tgbotapi.types.Username
import dev.inmo.tgbotapi.utils.RiskFeature
import dev.inmo.tgbotapi.utils.internal.*
import kotlinx.serialization.Serializable
@@ -17,8 +18,8 @@ data class BotCommandTextSource @RiskFeature(DirectInvocationOfTextSourceConstru
val command: String by lazy {
commandRegex.find(source) ?.value ?.substring(1) ?: source.substring(1)// skip first symbol like "/" or "!"
}
val username: String? by lazy {
usernameRegex.find(source) ?.value ?.substring(1) ?: source.substring(1)// skip first symbol "@"
val username: Username? by lazy {
Username(usernameRegex.find(source) ?.value ?: return@lazy null)
}
override val markdown: String by lazy { source.commandMarkdown() }

View File

@@ -4,6 +4,7 @@ import dev.inmo.tgbotapi.types.*
import dev.inmo.tgbotapi.types.chat.*
import dev.inmo.tgbotapi.types.message.abstracts.Message
import dev.inmo.tgbotapi.types.message.textsources.link
import io.ktor.http.encodeURLQueryComponent
fun makeUsernameLink(username: String) = "$internalLinkBeginning/$username"
@@ -17,11 +18,11 @@ inline val Username.deepLinkPrefix
inline val Username.startattachPrefix
get() = makeUsernameStartattachPrefix(usernameWithoutAt)
inline fun makeLink(username: Username) = username.link
inline fun makeTelegramDeepLink(username: String, startParameter: String) = "${makeUsernameDeepLinkPrefix(username)}$startParameter"
inline fun makeTelegramDeepLink(username: String, startParameter: String) = "${makeUsernameDeepLinkPrefix(username)}$startParameter".encodeURLQueryComponent()
inline fun makeTelegramStartattach(username: String, data: String? = null) = makeUsernameStartattachLink(username, data)
inline fun makeDeepLink(username: Username, startParameter: String) = "${username.deepLinkPrefix}$startParameter"
inline fun makeDeepLink(username: Username, startParameter: String) = makeTelegramDeepLink(username.usernameWithoutAt, startParameter)
inline fun makeTelegramDeepLink(username: Username, startParameter: String) = makeDeepLink(username, startParameter)
inline fun makeTelegramStartattach(username: Username, data: String? = null) = makeTelegramStartattach(username.username, data)
inline fun makeTelegramStartattach(username: Username, data: String? = null) = makeTelegramStartattach(username.usernameWithoutAt, data)
fun makeLinkToMessage(
username: String,