1
0
mirror of https://github.com/InsanusMokrassar/TelegramBotAPI.git synced 2024-11-23 02:28:45 +00:00

Merge pull request #81 from InsanusMokrassar/0.26.3

0.26.3
This commit is contained in:
InsanusMokrassar 2020-04-13 12:55:48 +06:00 committed by GitHub
commit f1480c40a7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 188 additions and 115 deletions

View File

@ -38,6 +38,22 @@
and size of retrieved updates is equal to 100 (max count of retrieved updates) and size of retrieved updates is equal to 100 (max count of retrieved updates)
* Extensions `getUpdates` now will receive only not nullable `limit` parameter * Extensions `getUpdates` now will receive only not nullable `limit` parameter
### 0.26.3
* `TelegramBotAPI`:
* `CallbackGameInlineKeyboardButton` was added
([Issue-79](https://github.com/InsanusMokrassar/TelegramBotAPI/issues/79),
[PR-80](https://github.com/InsanusMokrassar/TelegramBotAPI/pull/80))
* `UnknownInlineKeyboardButton` was added. It is unavailable for creating, but you can receive it, for example, in
`InlineQueryResult`
* `Update` now will be created even if was `SerializationException` inside of creating the update instance - in this
case will be created `UnknownUpdateType`
* `UnknownUpdateType$rawJson` value now is included (`JsonElement`)
* **EXPERIMENTALLY** `BaseEditMessageUpdate#data` now is `CommonMessage<*>`
* Suspend inline function `handleSafely` was added
* `KtorRequestsExecutor` now use `handleSafely` instead of `try` with `supervisorScope`
* `UpdatesPolling` now use `handleSafely` instead of `try` with `supervisorScope`
### 0.26.2 ### 0.26.2
* `TelegramBotAPI`: * `TelegramBotAPI`:

View File

@ -11,6 +11,7 @@ import com.github.insanusmokrassar.TelegramBotAPI.types.update.MediaGroupUpdates
import com.github.insanusmokrassar.TelegramBotAPI.types.update.abstracts.Update import com.github.insanusmokrassar.TelegramBotAPI.types.update.abstracts.Update
import com.github.insanusmokrassar.TelegramBotAPI.updateshandlers.* import com.github.insanusmokrassar.TelegramBotAPI.updateshandlers.*
import com.github.insanusmokrassar.TelegramBotAPI.utils.PreviewFeature import com.github.insanusmokrassar.TelegramBotAPI.utils.PreviewFeature
import com.github.insanusmokrassar.TelegramBotAPI.utils.handleSafely
import io.ktor.client.features.HttpRequestTimeoutException import io.ktor.client.features.HttpRequestTimeoutException
import kotlinx.coroutines.* import kotlinx.coroutines.*
@ -24,8 +25,14 @@ fun RequestsExecutor.startGettingOfUpdates(
var lastUpdateIdentifier: UpdateIdentifier? = null var lastUpdateIdentifier: UpdateIdentifier? = null
while (isActive) { while (isActive) {
try { handleSafely(
supervisorScope { { e ->
exceptionsHandler ?.invoke(e)
if (e is RequestException) {
delay(1000L)
}
}
) {
val updates = getUpdates( val updates = getUpdates(
offset = lastUpdateIdentifier?.plus(1), offset = lastUpdateIdentifier?.plus(1),
timeout = timeoutSeconds, timeout = timeoutSeconds,
@ -45,7 +52,7 @@ fun RequestsExecutor.startGettingOfUpdates(
} }
} }
supervisorScope { handleSafely {
for (update in updates) { for (update in updates) {
updatesReceiver(update) updatesReceiver(update)
@ -53,14 +60,6 @@ fun RequestsExecutor.startGettingOfUpdates(
} }
} }
} }
} catch (e: HttpRequestTimeoutException) {
exceptionsHandler ?.invoke(e) // it is ok due to mechanism of long polling
} catch (e: RequestException) {
exceptionsHandler ?.invoke(e) // it is not ok, but in most cases it will mean that there is some limit for requests count
delay(1000L)
} catch (e: Exception) {
exceptionsHandler ?.invoke(e)
}
} }
} }

View File

@ -9,7 +9,7 @@ import com.github.insanusmokrassar.TelegramBotAPI.bot.settings.limiters.RequestL
import com.github.insanusmokrassar.TelegramBotAPI.requests.abstracts.Request import com.github.insanusmokrassar.TelegramBotAPI.requests.abstracts.Request
import com.github.insanusmokrassar.TelegramBotAPI.types.Response import com.github.insanusmokrassar.TelegramBotAPI.types.Response
import com.github.insanusmokrassar.TelegramBotAPI.types.RetryAfterError import com.github.insanusmokrassar.TelegramBotAPI.types.RetryAfterError
import com.github.insanusmokrassar.TelegramBotAPI.utils.TelegramAPIUrlsKeeper import com.github.insanusmokrassar.TelegramBotAPI.utils.*
import com.github.insanusmokrassar.TelegramBotAPI.utils.nonstrictJsonFormat import com.github.insanusmokrassar.TelegramBotAPI.utils.nonstrictJsonFormat
import io.ktor.client.HttpClient import io.ktor.client.HttpClient
import io.ktor.client.call.receive import io.ktor.client.call.receive
@ -17,7 +17,6 @@ import io.ktor.client.features.*
import io.ktor.client.statement.HttpStatement import io.ktor.client.statement.HttpStatement
import io.ktor.client.statement.readText import io.ktor.client.statement.readText
import kotlinx.coroutines.delay import kotlinx.coroutines.delay
import kotlinx.coroutines.supervisorScope
import kotlinx.serialization.json.Json import kotlinx.serialization.json.Json
class KtorRequestsExecutor( class KtorRequestsExecutor(
@ -43,8 +42,21 @@ class KtorRequestsExecutor(
} }
override suspend fun <T : Any> execute(request: Request<T>): T { override suspend fun <T : Any> execute(request: Request<T>): T {
return try { return handleSafely(
supervisorScope { { e ->
throw if (e is ClientRequestException) {
val content = e.response.readText()
val responseObject = jsonFormatter.parse(Response.serializer(), content)
newRequestException(
responseObject,
content,
"Can't get result object from $content"
)
} else {
e
}
}
) {
requestsLimiter.limit { requestsLimiter.limit {
var statement: HttpStatement? = null var statement: HttpStatement? = null
for (factory in callsFactories) { for (factory in callsFactories) {
@ -81,17 +93,6 @@ class KtorRequestsExecutor(
}) })
} }
} }
} catch (e: ClientRequestException) {
val content = e.response.readText()
val responseObject = jsonFormatter.parse(Response.serializer(), content)
throw newRequestException(
responseObject,
content,
"Can't get result object from $content"
)
} catch (e: Exception) {
throw e
}
} }
override fun close() { override fun close() {

View File

@ -82,6 +82,7 @@ const val containsMasksField = "contains_masks"
const val resultIdField = "result_id" const val resultIdField = "result_id"
const val inlineMessageIdField = "inline_message_id" const val inlineMessageIdField = "inline_message_id"
const val callbackDataField = "callback_data" const val callbackDataField = "callback_data"
const val callbackGameField = "callback_game"
const val callbackQueryIdField = "callback_query_id" const val callbackQueryIdField = "callback_query_id"
const val inlineQueryIdField = "inline_query_id" const val inlineQueryIdField = "inline_query_id"
const val inlineKeyboardField = "inline_keyboard" const val inlineKeyboardField = "inline_keyboard"

View File

@ -1,14 +1,23 @@
package com.github.insanusmokrassar.TelegramBotAPI.types.buttons.InlineKeyboardButtons package com.github.insanusmokrassar.TelegramBotAPI.types.buttons.InlineKeyboardButtons
import com.github.insanusmokrassar.TelegramBotAPI.types.* import com.github.insanusmokrassar.TelegramBotAPI.types.*
import com.github.insanusmokrassar.TelegramBotAPI.types.games.CallbackGame
import kotlinx.serialization.SerialName import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable import kotlinx.serialization.Serializable
import kotlinx.serialization.json.JsonElement
import kotlinx.serialization.json.JsonObject
@Serializable(InlineKeyboardButtonSerializer::class) @Serializable(InlineKeyboardButtonSerializer::class)
sealed class InlineKeyboardButton { sealed class InlineKeyboardButton {
abstract val text: String abstract val text: String
} }
@Serializable
data class UnknownInlineKeyboardButton internal constructor(
override val text: String,
val rawData: JsonElement
) : InlineKeyboardButton()
@Serializable @Serializable
data class PayInlineKeyboardButton( data class PayInlineKeyboardButton(
override val text: String, override val text: String,
@ -24,6 +33,14 @@ data class CallbackDataInlineKeyboardButton(
val callbackData: String val callbackData: String
) : InlineKeyboardButton() ) : InlineKeyboardButton()
@Serializable
data class CallbackGameInlineKeyboardButton(
@SerialName(textField)
override val text: String,
@SerialName(callbackGameField)
val callbackGame: CallbackGame
) : InlineKeyboardButton()
@Serializable @Serializable
data class LoginURLInlineKeyboardButton( data class LoginURLInlineKeyboardButton(
override val text: String, override val text: String,

View File

@ -3,8 +3,7 @@ package com.github.insanusmokrassar.TelegramBotAPI.types.buttons.InlineKeyboardB
import com.github.insanusmokrassar.TelegramBotAPI.types.* import com.github.insanusmokrassar.TelegramBotAPI.types.*
import com.github.insanusmokrassar.TelegramBotAPI.utils.nonstrictJsonFormat import com.github.insanusmokrassar.TelegramBotAPI.utils.nonstrictJsonFormat
import kotlinx.serialization.* import kotlinx.serialization.*
import kotlinx.serialization.json.JsonElementSerializer import kotlinx.serialization.json.*
import kotlinx.serialization.json.JsonObject
internal object InlineKeyboardButtonSerializer : KSerializer<InlineKeyboardButton> { internal object InlineKeyboardButtonSerializer : KSerializer<InlineKeyboardButton> {
override val descriptor: SerialDescriptor = SerialDescriptor( override val descriptor: SerialDescriptor = SerialDescriptor(
@ -12,22 +11,25 @@ internal object InlineKeyboardButtonSerializer : KSerializer<InlineKeyboardButto
PolymorphicKind.SEALED PolymorphicKind.SEALED
) )
private fun resolveSerializer(json: JsonObject): KSerializer<out InlineKeyboardButton> { private fun resolveSerializer(json: JsonObject): KSerializer<out InlineKeyboardButton>? {
return when { return when {
json[callbackDataField] != null -> CallbackDataInlineKeyboardButton.serializer() json[callbackDataField] != null -> CallbackDataInlineKeyboardButton.serializer()
json[callbackGameField] != null -> CallbackGameInlineKeyboardButton.serializer()
json[loginUrlField] != null -> LoginURLInlineKeyboardButton.serializer() json[loginUrlField] != null -> LoginURLInlineKeyboardButton.serializer()
json[payField] != null -> PayInlineKeyboardButton.serializer() json[payField] != null -> PayInlineKeyboardButton.serializer()
json[switchInlineQueryField] != null -> SwitchInlineQueryInlineKeyboardButton.serializer() json[switchInlineQueryField] != null -> SwitchInlineQueryInlineKeyboardButton.serializer()
json[switchInlineQueryCurrentChatField] != null -> SwitchInlineQueryCurrentChatInlineKeyboardButton.serializer() json[switchInlineQueryCurrentChatField] != null -> SwitchInlineQueryCurrentChatInlineKeyboardButton.serializer()
json[urlField] != null -> URLInlineKeyboardButton.serializer() json[urlField] != null -> URLInlineKeyboardButton.serializer()
else -> throw IllegalArgumentException("Can't find correct serializer for inline button serialized as $json") else -> null
} }
} }
override fun deserialize(decoder: Decoder): InlineKeyboardButton { override fun deserialize(decoder: Decoder): InlineKeyboardButton {
val json = JsonElementSerializer.deserialize(decoder) val json = JsonElementSerializer.deserialize(decoder)
return nonstrictJsonFormat.fromJson(resolveSerializer(json.jsonObject), json) return (json as? JsonObject) ?.let { resolveSerializer(it) } ?.let {
nonstrictJsonFormat.fromJson(it, json)
} ?: UnknownInlineKeyboardButton("", json)
} }
override fun serialize(encoder: Encoder, value: InlineKeyboardButton) { override fun serialize(encoder: Encoder, value: InlineKeyboardButton) {
@ -38,6 +40,8 @@ internal object InlineKeyboardButtonSerializer : KSerializer<InlineKeyboardButto
is SwitchInlineQueryInlineKeyboardButton -> SwitchInlineQueryInlineKeyboardButton.serializer().serialize(encoder, value) is SwitchInlineQueryInlineKeyboardButton -> SwitchInlineQueryInlineKeyboardButton.serializer().serialize(encoder, value)
is SwitchInlineQueryCurrentChatInlineKeyboardButton -> SwitchInlineQueryCurrentChatInlineKeyboardButton.serializer().serialize(encoder, value) is SwitchInlineQueryCurrentChatInlineKeyboardButton -> SwitchInlineQueryCurrentChatInlineKeyboardButton.serializer().serialize(encoder, value)
is URLInlineKeyboardButton -> URLInlineKeyboardButton.serializer().serialize(encoder, value) is URLInlineKeyboardButton -> URLInlineKeyboardButton.serializer().serialize(encoder, value)
is CallbackGameInlineKeyboardButton -> CallbackGameInlineKeyboardButton.serializer().serialize(encoder, value)
is UnknownInlineKeyboardButton -> JsonElementSerializer.serialize(encoder, value.rawData)
} }
} }
} }

View File

@ -1,10 +1,10 @@
package com.github.insanusmokrassar.TelegramBotAPI.types.update package com.github.insanusmokrassar.TelegramBotAPI.types.update
import com.github.insanusmokrassar.TelegramBotAPI.types.UpdateIdentifier import com.github.insanusmokrassar.TelegramBotAPI.types.UpdateIdentifier
import com.github.insanusmokrassar.TelegramBotAPI.types.message.abstracts.Message import com.github.insanusmokrassar.TelegramBotAPI.types.message.abstracts.CommonMessage
import com.github.insanusmokrassar.TelegramBotAPI.types.update.abstracts.BaseEditMessageUpdate import com.github.insanusmokrassar.TelegramBotAPI.types.update.abstracts.BaseEditMessageUpdate
data class EditChannelPostUpdate( data class EditChannelPostUpdate(
override val updateId: UpdateIdentifier, override val updateId: UpdateIdentifier,
override val data: Message override val data: CommonMessage<*>
) : BaseEditMessageUpdate ) : BaseEditMessageUpdate

View File

@ -1,10 +1,10 @@
package com.github.insanusmokrassar.TelegramBotAPI.types.update package com.github.insanusmokrassar.TelegramBotAPI.types.update
import com.github.insanusmokrassar.TelegramBotAPI.types.UpdateIdentifier import com.github.insanusmokrassar.TelegramBotAPI.types.UpdateIdentifier
import com.github.insanusmokrassar.TelegramBotAPI.types.message.abstracts.Message import com.github.insanusmokrassar.TelegramBotAPI.types.message.abstracts.CommonMessage
import com.github.insanusmokrassar.TelegramBotAPI.types.update.abstracts.BaseEditMessageUpdate import com.github.insanusmokrassar.TelegramBotAPI.types.update.abstracts.BaseEditMessageUpdate
data class EditMessageUpdate( data class EditMessageUpdate(
override val updateId: UpdateIdentifier, override val updateId: UpdateIdentifier,
override val data: Message override val data: CommonMessage<*>
) : BaseEditMessageUpdate ) : BaseEditMessageUpdate

View File

@ -4,7 +4,7 @@ import com.github.insanusmokrassar.TelegramBotAPI.types.CallbackQuery.RawCallbac
import com.github.insanusmokrassar.TelegramBotAPI.types.InlineQueries.ChosenInlineResult.RawChosenInlineResult import com.github.insanusmokrassar.TelegramBotAPI.types.InlineQueries.ChosenInlineResult.RawChosenInlineResult
import com.github.insanusmokrassar.TelegramBotAPI.types.InlineQueries.query.RawInlineQuery import com.github.insanusmokrassar.TelegramBotAPI.types.InlineQueries.query.RawInlineQuery
import com.github.insanusmokrassar.TelegramBotAPI.types.UpdateIdentifier import com.github.insanusmokrassar.TelegramBotAPI.types.UpdateIdentifier
import com.github.insanusmokrassar.TelegramBotAPI.types.message.abstracts.Message import com.github.insanusmokrassar.TelegramBotAPI.types.message.abstracts.*
import com.github.insanusmokrassar.TelegramBotAPI.types.message.abstracts.TelegramBotAPIMessageDeserializeOnlySerializer import com.github.insanusmokrassar.TelegramBotAPI.types.message.abstracts.TelegramBotAPIMessageDeserializeOnlySerializer
import com.github.insanusmokrassar.TelegramBotAPI.types.payments.PreCheckoutQuery import com.github.insanusmokrassar.TelegramBotAPI.types.payments.PreCheckoutQuery
import com.github.insanusmokrassar.TelegramBotAPI.types.payments.ShippingQuery import com.github.insanusmokrassar.TelegramBotAPI.types.payments.ShippingQuery
@ -13,8 +13,7 @@ import com.github.insanusmokrassar.TelegramBotAPI.types.polls.PollAnswer
import com.github.insanusmokrassar.TelegramBotAPI.types.update.abstracts.UnknownUpdateType import com.github.insanusmokrassar.TelegramBotAPI.types.update.abstracts.UnknownUpdateType
import com.github.insanusmokrassar.TelegramBotAPI.types.update.abstracts.Update import com.github.insanusmokrassar.TelegramBotAPI.types.update.abstracts.Update
import com.github.insanusmokrassar.TelegramBotAPI.types.updateIdField import com.github.insanusmokrassar.TelegramBotAPI.types.updateIdField
import kotlinx.serialization.SerialName import kotlinx.serialization.*
import kotlinx.serialization.Serializable
import kotlinx.serialization.json.JsonElement import kotlinx.serialization.json.JsonElement
@Serializable @Serializable
@ -22,11 +21,11 @@ internal data class RawUpdate constructor(
@SerialName(updateIdField) @SerialName(updateIdField)
val updateId: UpdateIdentifier, val updateId: UpdateIdentifier,
@Serializable(TelegramBotAPIMessageDeserializeOnlySerializer::class) @Serializable(TelegramBotAPIMessageDeserializeOnlySerializer::class)
private val edited_message: Message? = null, private val edited_message: CommonMessage<*>? = null,
@Serializable(TelegramBotAPIMessageDeserializeOnlySerializer::class) @Serializable(TelegramBotAPIMessageDeserializeOnlySerializer::class)
private val message: Message? = null, private val message: Message? = null,
@Serializable(TelegramBotAPIMessageDeserializeOnlySerializer::class) @Serializable(TelegramBotAPIMessageDeserializeOnlySerializer::class)
private val edited_channel_post: Message? = null, private val edited_channel_post: CommonMessage<*>? = null,
@Serializable(TelegramBotAPIMessageDeserializeOnlySerializer::class) @Serializable(TelegramBotAPIMessageDeserializeOnlySerializer::class)
private val channel_post: Message? = null, private val channel_post: Message? = null,
private val inline_query: RawInlineQuery? = null, private val inline_query: RawInlineQuery? = null,
@ -42,7 +41,8 @@ internal data class RawUpdate constructor(
* @return One of children of [Update] interface or null in case of unknown type of update * @return One of children of [Update] interface or null in case of unknown type of update
*/ */
fun asUpdate(raw: JsonElement): Update { fun asUpdate(raw: JsonElement): Update {
return initedUpdate ?: when { return initedUpdate ?: try {
when {
edited_message != null -> EditMessageUpdate(updateId, edited_message) edited_message != null -> EditMessageUpdate(updateId, edited_message)
message != null -> MessageUpdate(updateId, message) message != null -> MessageUpdate(updateId, message)
edited_channel_post != null -> EditChannelPostUpdate(updateId, edited_channel_post) edited_channel_post != null -> EditChannelPostUpdate(updateId, edited_channel_post)
@ -60,7 +60,15 @@ internal data class RawUpdate constructor(
poll_answer != null -> PollAnswerUpdate(updateId, poll_answer) poll_answer != null -> PollAnswerUpdate(updateId, poll_answer)
else -> UnknownUpdateType( else -> UnknownUpdateType(
updateId, updateId,
raw.toString() raw.toString(),
raw
)
}
} catch (e: SerializationException) {
UnknownUpdateType(
updateId,
raw.toString(),
raw
) )
}.also { }.also {
initedUpdate = it initedUpdate = it

View File

@ -1,3 +1,7 @@
package com.github.insanusmokrassar.TelegramBotAPI.types.update.abstracts package com.github.insanusmokrassar.TelegramBotAPI.types.update.abstracts
interface BaseEditMessageUpdate : BaseMessageUpdate import com.github.insanusmokrassar.TelegramBotAPI.types.message.abstracts.CommonMessage
interface BaseEditMessageUpdate : BaseMessageUpdate {
override val data: CommonMessage<*>
}

View File

@ -4,6 +4,7 @@ import com.github.insanusmokrassar.TelegramBotAPI.types.UpdateIdentifier
import com.github.insanusmokrassar.TelegramBotAPI.types.update.RawUpdate import com.github.insanusmokrassar.TelegramBotAPI.types.update.RawUpdate
import com.github.insanusmokrassar.TelegramBotAPI.utils.nonstrictJsonFormat import com.github.insanusmokrassar.TelegramBotAPI.utils.nonstrictJsonFormat
import kotlinx.serialization.* import kotlinx.serialization.*
import kotlinx.serialization.json.JsonElement
import kotlinx.serialization.json.JsonElementSerializer import kotlinx.serialization.json.JsonElementSerializer
interface Update { interface Update {
@ -13,7 +14,8 @@ interface Update {
data class UnknownUpdateType( data class UnknownUpdateType(
override val updateId: UpdateIdentifier, override val updateId: UpdateIdentifier,
override val data: String override val data: String,
val rawJson: JsonElement
) : Update ) : Update
internal object UpdateSerializerWithoutDeserialization : KSerializer<Update> { internal object UpdateSerializerWithoutDeserialization : KSerializer<Update> {

View File

@ -0,0 +1,21 @@
package com.github.insanusmokrassar.TelegramBotAPI.utils
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.supervisorScope
/**
* It will run [block] inside of [supervisorScope] to avoid problems with catching of exceptions
*
* @param [onException] Will be called when happen exception inside of [block]. By default will throw exception - this
* exception will be available for catching
*/
suspend inline fun <T> handleSafely(
noinline onException: suspend (Exception) -> T = { throw it },
noinline block: suspend CoroutineScope.() -> T
): T {
return try {
supervisorScope(block)
} catch (e: Exception) {
onException(e)
}
}

View File

@ -7,6 +7,6 @@ uuid_version=0.1.0
ktor_version=1.3.2 ktor_version=1.3.2
library_group=com.github.insanusmokrassar library_group=com.github.insanusmokrassar
library_version=0.26.2 library_version=0.26.3
gradle_bintray_plugin_version=1.8.4 gradle_bintray_plugin_version=1.8.4