mirror of
https://github.com/InsanusMokrassar/TelegramBotAPI.git
synced 2024-11-22 16:23:48 +00:00
#773 fix, improvements in updates handling
This commit is contained in:
parent
81ed820602
commit
2e815a4c37
@ -4,6 +4,10 @@
|
|||||||
|
|
||||||
**THIS UPDATE CONTAINS BREAKING CHANGES: USERNAMES OF BOTS NOW BECAME NULLABLE**
|
**THIS UPDATE CONTAINS BREAKING CHANGES: USERNAMES OF BOTS NOW BECAME NULLABLE**
|
||||||
|
|
||||||
|
* `Core`:
|
||||||
|
* All bots now have nullable usernames just like common users ([#772](https://github.com/InsanusMokrassar/ktgbotapi/issues/772))
|
||||||
|
* Decrease possible errors in updates handling by additional handling of update deserialization wrapping ([#773](https://github.com/InsanusMokrassar/ktgbotapi/issues/773))
|
||||||
|
* Now it is possible to get raw updates with `GetUpdatesRaw` request
|
||||||
* `Utils`:
|
* `Utils`:
|
||||||
* Improve extension `Update.sourceChat` to add opportunity to select some chats by logic different with the default
|
* Improve extension `Update.sourceChat` to add opportunity to select some chats by logic different with the default
|
||||||
|
|
||||||
|
@ -0,0 +1,27 @@
|
|||||||
|
package dev.inmo.tgbotapi.extensions.api
|
||||||
|
|
||||||
|
import dev.inmo.tgbotapi.bot.TelegramBot
|
||||||
|
import dev.inmo.tgbotapi.requests.GetUpdates
|
||||||
|
import dev.inmo.tgbotapi.requests.GetUpdatesRaw
|
||||||
|
import dev.inmo.tgbotapi.types.*
|
||||||
|
import dev.inmo.tgbotapi.types.update.abstracts.Update
|
||||||
|
|
||||||
|
suspend fun TelegramBot.getRawUpdates(
|
||||||
|
offset: UpdateIdentifier? = null,
|
||||||
|
limit: Int = getUpdatesLimit.last,
|
||||||
|
timeout: Seconds? = null,
|
||||||
|
allowed_updates: List<String>? = ALL_UPDATES_LIST
|
||||||
|
) = execute(
|
||||||
|
GetUpdatesRaw(
|
||||||
|
offset, limit, timeout, allowed_updates
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
suspend fun TelegramBot.getRawUpdates(
|
||||||
|
lastUpdate: Update,
|
||||||
|
limit: Int = getUpdatesLimit.last,
|
||||||
|
timeout: Seconds? = null,
|
||||||
|
allowed_updates: List<String>? = ALL_UPDATES_LIST
|
||||||
|
) = getRawUpdates(
|
||||||
|
lastUpdate.updateId + 1, limit, timeout, allowed_updates
|
||||||
|
)
|
@ -3,7 +3,7 @@ package dev.inmo.tgbotapi.bot.ktor.base
|
|||||||
import dev.inmo.micro_utils.coroutines.runCatchingSafely
|
import dev.inmo.micro_utils.coroutines.runCatchingSafely
|
||||||
import dev.inmo.tgbotapi.bot.ktor.KtorCallFactory
|
import dev.inmo.tgbotapi.bot.ktor.KtorCallFactory
|
||||||
import dev.inmo.tgbotapi.bot.exceptions.newRequestException
|
import dev.inmo.tgbotapi.bot.exceptions.newRequestException
|
||||||
import dev.inmo.tgbotapi.requests.GetUpdates
|
import dev.inmo.tgbotapi.requests.GetUpdatesRequest
|
||||||
import dev.inmo.tgbotapi.requests.abstracts.Request
|
import dev.inmo.tgbotapi.requests.abstracts.Request
|
||||||
import dev.inmo.tgbotapi.types.Response
|
import dev.inmo.tgbotapi.types.Response
|
||||||
import dev.inmo.tgbotapi.utils.TelegramAPIUrlsKeeper
|
import dev.inmo.tgbotapi.utils.TelegramAPIUrlsKeeper
|
||||||
@ -35,7 +35,7 @@ abstract class AbstractRequestCallFactory : KtorCallFactory {
|
|||||||
)
|
)
|
||||||
accept(ContentType.Application.Json)
|
accept(ContentType.Application.Json)
|
||||||
|
|
||||||
if (request is GetUpdates) {
|
if (request is GetUpdatesRequest) {
|
||||||
request.timeout?.times(1000L) ?.let { customTimeoutMillis ->
|
request.timeout?.times(1000L) ?.let { customTimeoutMillis ->
|
||||||
if (customTimeoutMillis > 0) {
|
if (customTimeoutMillis > 0) {
|
||||||
timeout {
|
timeout {
|
||||||
|
@ -22,13 +22,11 @@ private val updatesListSerializer = ListSerializer(
|
|||||||
*/
|
*/
|
||||||
@Serializable
|
@Serializable
|
||||||
data class GetUpdates(
|
data class GetUpdates(
|
||||||
val offset: UpdateIdentifier? = null,// set `last update id + 1` to receive next part of updates
|
override val offset: UpdateIdentifier? = null,// set `last update id + 1` to receive next part of updates
|
||||||
val limit: Int = getUpdatesLimit.last,
|
override val limit: Int = getUpdatesLimit.last,
|
||||||
val timeout: Seconds? = null,
|
override val timeout: Seconds? = null,
|
||||||
val allowed_updates: List<String>? = ALL_UPDATES_LIST
|
override val allowed_updates: List<String>? = ALL_UPDATES_LIST
|
||||||
): SimpleRequest<List<Update>> {
|
): GetUpdatesRequest<List<Update>> {
|
||||||
override fun method(): String = "getUpdates"
|
|
||||||
|
|
||||||
override val resultDeserializer: DeserializationStrategy<List<Update>>
|
override val resultDeserializer: DeserializationStrategy<List<Update>>
|
||||||
get() = updatesListSerializer
|
get() = updatesListSerializer
|
||||||
|
|
||||||
|
@ -0,0 +1,37 @@
|
|||||||
|
package dev.inmo.tgbotapi.requests
|
||||||
|
|
||||||
|
import dev.inmo.tgbotapi.requests.abstracts.SimpleRequest
|
||||||
|
import dev.inmo.tgbotapi.types.ALL_UPDATES_LIST
|
||||||
|
import dev.inmo.tgbotapi.types.Seconds
|
||||||
|
import dev.inmo.tgbotapi.types.UpdateIdentifier
|
||||||
|
import dev.inmo.tgbotapi.types.getUpdatesLimit
|
||||||
|
import kotlinx.serialization.DeserializationStrategy
|
||||||
|
import kotlinx.serialization.Serializable
|
||||||
|
import kotlinx.serialization.SerializationStrategy
|
||||||
|
import kotlinx.serialization.json.JsonArray
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Raw variant of [GetUpdates]. This type will be useful in case you wish to get some updates and handle them by
|
||||||
|
* yourself or with [dev.inmo.tgbotapi.utils.convertWithMediaGroupUpdates]
|
||||||
|
*/
|
||||||
|
@Serializable
|
||||||
|
data class GetUpdatesRaw(
|
||||||
|
override val offset: UpdateIdentifier? = null,// set `last update id + 1` to receive next part of updates
|
||||||
|
override val limit: Int = getUpdatesLimit.last,
|
||||||
|
override val timeout: Seconds? = null,
|
||||||
|
override val allowed_updates: List<String>? = ALL_UPDATES_LIST
|
||||||
|
): GetUpdatesRequest<JsonArray> {
|
||||||
|
override fun method(): String = "getUpdates"
|
||||||
|
|
||||||
|
override val resultDeserializer: DeserializationStrategy<JsonArray>
|
||||||
|
get() = JsonArray.serializer()
|
||||||
|
|
||||||
|
override val requestSerializer: SerializationStrategy<*>
|
||||||
|
get() = serializer()
|
||||||
|
|
||||||
|
init {
|
||||||
|
if (limit !in getUpdatesLimit) {
|
||||||
|
error("GetUpdates request can be called only with limit in range $getUpdatesLimit (actual value is $limit)")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,17 @@
|
|||||||
|
package dev.inmo.tgbotapi.requests
|
||||||
|
|
||||||
|
import dev.inmo.tgbotapi.requests.abstracts.Request
|
||||||
|
import dev.inmo.tgbotapi.requests.abstracts.SimpleRequest
|
||||||
|
import dev.inmo.tgbotapi.types.ALL_UPDATES_LIST
|
||||||
|
import dev.inmo.tgbotapi.types.Seconds
|
||||||
|
import dev.inmo.tgbotapi.types.UpdateIdentifier
|
||||||
|
import dev.inmo.tgbotapi.types.getUpdatesLimit
|
||||||
|
|
||||||
|
interface GetUpdatesRequest<T : Any> : SimpleRequest<T> {
|
||||||
|
val offset: UpdateIdentifier?
|
||||||
|
val limit: Int
|
||||||
|
val timeout: Seconds?
|
||||||
|
val allowed_updates: List<String>?
|
||||||
|
|
||||||
|
override fun method(): String = "getUpdates"
|
||||||
|
}
|
@ -67,20 +67,19 @@ internal data class RawUpdate constructor(
|
|||||||
chat_join_request != null -> ChatJoinRequestUpdate(updateId, chat_join_request)
|
chat_join_request != null -> ChatJoinRequestUpdate(updateId, chat_join_request)
|
||||||
else -> UnknownUpdate(
|
else -> UnknownUpdate(
|
||||||
updateId,
|
updateId,
|
||||||
raw.toString(),
|
|
||||||
raw
|
raw
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
} catch (e: Error) {
|
} catch (e: NotImplementedError) {
|
||||||
when (e) {
|
UnknownUpdate(
|
||||||
is SerializationException,
|
updateId,
|
||||||
is NotImplementedError -> UnknownUpdate(
|
raw
|
||||||
|
)
|
||||||
|
} catch (e: SerializationException) {
|
||||||
|
UnknownUpdate(
|
||||||
updateId,
|
updateId,
|
||||||
raw.toString(),
|
|
||||||
raw
|
raw
|
||||||
)
|
)
|
||||||
else -> throw e
|
|
||||||
}
|
|
||||||
}.also {
|
}.also {
|
||||||
initedUpdate = it
|
initedUpdate = it
|
||||||
}
|
}
|
||||||
|
@ -3,6 +3,7 @@ package dev.inmo.tgbotapi.types.update.abstracts
|
|||||||
import dev.inmo.tgbotapi.utils.internal.ClassCastsIncluded
|
import dev.inmo.tgbotapi.utils.internal.ClassCastsIncluded
|
||||||
import dev.inmo.tgbotapi.types.UpdateIdentifier
|
import dev.inmo.tgbotapi.types.UpdateIdentifier
|
||||||
import dev.inmo.tgbotapi.types.update.RawUpdate
|
import dev.inmo.tgbotapi.types.update.RawUpdate
|
||||||
|
import dev.inmo.tgbotapi.types.updateIdField
|
||||||
import dev.inmo.tgbotapi.utils.RiskFeature
|
import dev.inmo.tgbotapi.utils.RiskFeature
|
||||||
import dev.inmo.tgbotapi.utils.nonstrictJsonFormat
|
import dev.inmo.tgbotapi.utils.nonstrictJsonFormat
|
||||||
import kotlinx.serialization.*
|
import kotlinx.serialization.*
|
||||||
@ -10,6 +11,9 @@ import kotlinx.serialization.descriptors.SerialDescriptor
|
|||||||
import kotlinx.serialization.encoding.Decoder
|
import kotlinx.serialization.encoding.Decoder
|
||||||
import kotlinx.serialization.encoding.Encoder
|
import kotlinx.serialization.encoding.Encoder
|
||||||
import kotlinx.serialization.json.JsonElement
|
import kotlinx.serialization.json.JsonElement
|
||||||
|
import kotlinx.serialization.json.JsonObject
|
||||||
|
import kotlinx.serialization.json.jsonPrimitive
|
||||||
|
import kotlinx.serialization.json.longOrNull
|
||||||
|
|
||||||
@ClassCastsIncluded
|
@ClassCastsIncluded
|
||||||
interface Update {
|
interface Update {
|
||||||
@ -19,9 +23,12 @@ interface Update {
|
|||||||
|
|
||||||
data class UnknownUpdate(
|
data class UnknownUpdate(
|
||||||
override val updateId: UpdateIdentifier,
|
override val updateId: UpdateIdentifier,
|
||||||
override val data: String,
|
override val data: JsonElement,
|
||||||
|
val throwable: Throwable? = null
|
||||||
|
) : Update {
|
||||||
val rawJson: JsonElement
|
val rawJson: JsonElement
|
||||||
) : Update
|
get() = data
|
||||||
|
}
|
||||||
|
|
||||||
@RiskFeature
|
@RiskFeature
|
||||||
object UpdateSerializerWithoutSerialization : KSerializer<Update> {
|
object UpdateSerializerWithoutSerialization : KSerializer<Update> {
|
||||||
@ -44,11 +51,19 @@ object UpdateDeserializationStrategy : DeserializationStrategy<Update> {
|
|||||||
|
|
||||||
override fun deserialize(decoder: Decoder): Update {
|
override fun deserialize(decoder: Decoder): Update {
|
||||||
val asJson = JsonElement.serializer().deserialize(decoder)
|
val asJson = JsonElement.serializer().deserialize(decoder)
|
||||||
return nonstrictJsonFormat.decodeFromJsonElement(
|
return runCatching {
|
||||||
|
nonstrictJsonFormat.decodeFromJsonElement(
|
||||||
RawUpdate.serializer(),
|
RawUpdate.serializer(),
|
||||||
asJson
|
asJson
|
||||||
).asUpdate(
|
).asUpdate(
|
||||||
asJson
|
asJson
|
||||||
)
|
)
|
||||||
|
}.getOrElse {
|
||||||
|
UnknownUpdate(
|
||||||
|
(asJson as? JsonObject) ?.get(updateIdField) ?.jsonPrimitive ?.longOrNull ?: -1L,
|
||||||
|
asJson,
|
||||||
|
it
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -15,7 +15,7 @@ import dev.inmo.tgbotapi.utils.extensions.asMediaGroupMessage
|
|||||||
* @see [Update.lastUpdateIdentifier]
|
* @see [Update.lastUpdateIdentifier]
|
||||||
*/
|
*/
|
||||||
fun List<Update>.lastUpdateIdentifier(): UpdateIdentifier? {
|
fun List<Update>.lastUpdateIdentifier(): UpdateIdentifier? {
|
||||||
return maxByOrNull { it.updateId } ?.updateId
|
return maxByOrNull { it.updateId } ?.updateId ?.takeIf { it > -1 }
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -6,6 +6,7 @@ import dev.inmo.tgbotapi.bot.TelegramBot
|
|||||||
import dev.inmo.tgbotapi.bot.exceptions.*
|
import dev.inmo.tgbotapi.bot.exceptions.*
|
||||||
import dev.inmo.tgbotapi.extensions.utils.updates.convertWithMediaGroupUpdates
|
import dev.inmo.tgbotapi.extensions.utils.updates.convertWithMediaGroupUpdates
|
||||||
import dev.inmo.tgbotapi.requests.GetUpdates
|
import dev.inmo.tgbotapi.requests.GetUpdates
|
||||||
|
import dev.inmo.tgbotapi.requests.GetUpdatesRaw
|
||||||
import dev.inmo.tgbotapi.requests.webhook.DeleteWebhook
|
import dev.inmo.tgbotapi.requests.webhook.DeleteWebhook
|
||||||
import dev.inmo.tgbotapi.types.*
|
import dev.inmo.tgbotapi.types.*
|
||||||
import dev.inmo.tgbotapi.types.message.abstracts.CommonMessage
|
import dev.inmo.tgbotapi.types.message.abstracts.CommonMessage
|
||||||
@ -91,8 +92,10 @@ fun TelegramBot.longPollingFlow(
|
|||||||
for (update in updates) {
|
for (update in updates) {
|
||||||
send(update)
|
send(update)
|
||||||
|
|
||||||
|
if (update.updateId > -1) {
|
||||||
lastUpdateIdentifier = update.updateId
|
lastUpdateIdentifier = update.updateId
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}.onFailure {
|
}.onFailure {
|
||||||
cancel(it as? CancellationException ?: return@onFailure)
|
cancel(it as? CancellationException ?: return@onFailure)
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user