mirror of
https://github.com/InsanusMokrassar/TelegramBotAPI.git
synced 2024-12-22 16:47:13 +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**
|
||||
|
||||
* `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`:
|
||||
* 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.tgbotapi.bot.ktor.KtorCallFactory
|
||||
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.types.Response
|
||||
import dev.inmo.tgbotapi.utils.TelegramAPIUrlsKeeper
|
||||
@ -35,7 +35,7 @@ abstract class AbstractRequestCallFactory : KtorCallFactory {
|
||||
)
|
||||
accept(ContentType.Application.Json)
|
||||
|
||||
if (request is GetUpdates) {
|
||||
if (request is GetUpdatesRequest) {
|
||||
request.timeout?.times(1000L) ?.let { customTimeoutMillis ->
|
||||
if (customTimeoutMillis > 0) {
|
||||
timeout {
|
||||
|
@ -22,13 +22,11 @@ private val updatesListSerializer = ListSerializer(
|
||||
*/
|
||||
@Serializable
|
||||
data class GetUpdates(
|
||||
val offset: UpdateIdentifier? = null,// set `last update id + 1` to receive next part of updates
|
||||
val limit: Int = getUpdatesLimit.last,
|
||||
val timeout: Seconds? = null,
|
||||
val allowed_updates: List<String>? = ALL_UPDATES_LIST
|
||||
): SimpleRequest<List<Update>> {
|
||||
override fun method(): String = "getUpdates"
|
||||
|
||||
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<List<Update>> {
|
||||
override val resultDeserializer: DeserializationStrategy<List<Update>>
|
||||
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)
|
||||
else -> UnknownUpdate(
|
||||
updateId,
|
||||
raw.toString(),
|
||||
raw
|
||||
)
|
||||
}
|
||||
} catch (e: Error) {
|
||||
when (e) {
|
||||
is SerializationException,
|
||||
is NotImplementedError -> UnknownUpdate(
|
||||
updateId,
|
||||
raw.toString(),
|
||||
raw
|
||||
)
|
||||
else -> throw e
|
||||
}
|
||||
} catch (e: NotImplementedError) {
|
||||
UnknownUpdate(
|
||||
updateId,
|
||||
raw
|
||||
)
|
||||
} catch (e: SerializationException) {
|
||||
UnknownUpdate(
|
||||
updateId,
|
||||
raw
|
||||
)
|
||||
}.also {
|
||||
initedUpdate = it
|
||||
}
|
||||
|
@ -3,6 +3,7 @@ package dev.inmo.tgbotapi.types.update.abstracts
|
||||
import dev.inmo.tgbotapi.utils.internal.ClassCastsIncluded
|
||||
import dev.inmo.tgbotapi.types.UpdateIdentifier
|
||||
import dev.inmo.tgbotapi.types.update.RawUpdate
|
||||
import dev.inmo.tgbotapi.types.updateIdField
|
||||
import dev.inmo.tgbotapi.utils.RiskFeature
|
||||
import dev.inmo.tgbotapi.utils.nonstrictJsonFormat
|
||||
import kotlinx.serialization.*
|
||||
@ -10,6 +11,9 @@ import kotlinx.serialization.descriptors.SerialDescriptor
|
||||
import kotlinx.serialization.encoding.Decoder
|
||||
import kotlinx.serialization.encoding.Encoder
|
||||
import kotlinx.serialization.json.JsonElement
|
||||
import kotlinx.serialization.json.JsonObject
|
||||
import kotlinx.serialization.json.jsonPrimitive
|
||||
import kotlinx.serialization.json.longOrNull
|
||||
|
||||
@ClassCastsIncluded
|
||||
interface Update {
|
||||
@ -19,9 +23,12 @@ interface Update {
|
||||
|
||||
data class UnknownUpdate(
|
||||
override val updateId: UpdateIdentifier,
|
||||
override val data: String,
|
||||
override val data: JsonElement,
|
||||
val throwable: Throwable? = null
|
||||
) : Update {
|
||||
val rawJson: JsonElement
|
||||
) : Update
|
||||
get() = data
|
||||
}
|
||||
|
||||
@RiskFeature
|
||||
object UpdateSerializerWithoutSerialization : KSerializer<Update> {
|
||||
@ -44,11 +51,19 @@ object UpdateDeserializationStrategy : DeserializationStrategy<Update> {
|
||||
|
||||
override fun deserialize(decoder: Decoder): Update {
|
||||
val asJson = JsonElement.serializer().deserialize(decoder)
|
||||
return nonstrictJsonFormat.decodeFromJsonElement(
|
||||
RawUpdate.serializer(),
|
||||
asJson
|
||||
).asUpdate(
|
||||
asJson
|
||||
)
|
||||
return runCatching {
|
||||
nonstrictJsonFormat.decodeFromJsonElement(
|
||||
RawUpdate.serializer(),
|
||||
asJson
|
||||
).asUpdate(
|
||||
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]
|
||||
*/
|
||||
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.extensions.utils.updates.convertWithMediaGroupUpdates
|
||||
import dev.inmo.tgbotapi.requests.GetUpdates
|
||||
import dev.inmo.tgbotapi.requests.GetUpdatesRaw
|
||||
import dev.inmo.tgbotapi.requests.webhook.DeleteWebhook
|
||||
import dev.inmo.tgbotapi.types.*
|
||||
import dev.inmo.tgbotapi.types.message.abstracts.CommonMessage
|
||||
@ -91,7 +92,9 @@ fun TelegramBot.longPollingFlow(
|
||||
for (update in updates) {
|
||||
send(update)
|
||||
|
||||
lastUpdateIdentifier = update.updateId
|
||||
if (update.updateId > -1) {
|
||||
lastUpdateIdentifier = update.updateId
|
||||
}
|
||||
}
|
||||
}.onFailure {
|
||||
cancel(it as? CancellationException ?: return@onFailure)
|
||||
|
Loading…
Reference in New Issue
Block a user