Merge pull request #13 from InsanusMokrassar/0.9.3

0.9.3
This commit is contained in:
InsanusMokrassar 2019-02-05 16:01:26 +08:00 committed by GitHub
commit 6bdd17a186
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 103 additions and 43 deletions

View File

@ -27,6 +27,16 @@ must be regular text
* `RequestsExecutor#executeAsync(Request, CoroutineScope)` now will return `Deferred` for cases when you need result
* `RequestsExecutor#executeUnsafe` will automatically retry request if it was unsuccessful and retries > 0
### 0.9.3
* `KtorRequestsExecutor` now can use custom `JSON` string formatter (by default - non strict)
* `ResponseParameters` renamed to `Response`
* Add `RequestError` sealed class and described in documentation known errors
* Add `ResponseParametersRaw` which can create error based on input parameters
* Add `parameters` field in `Response` and remove useless fields from `Response`
* Add `leftToRetry` parameter in `RetryAfterError`
* Add handling of `RetryAfterError` in `KtorRequestsExecutor`
### 0.8.5
* Add extension `String#toMarkdown`

View File

@ -1,4 +1,4 @@
project.version = "0.9.2"
project.version = "0.9.3"
project.group = "com.github.insanusmokrassar"
buildscript {

View File

@ -7,12 +7,14 @@ import com.github.insanusmokrassar.TelegramBotAPI.bot.RequestException
import com.github.insanusmokrassar.TelegramBotAPI.bot.settings.limiters.EmptyLimiter
import com.github.insanusmokrassar.TelegramBotAPI.bot.settings.limiters.RequestLimiter
import com.github.insanusmokrassar.TelegramBotAPI.requests.abstracts.Request
import com.github.insanusmokrassar.TelegramBotAPI.types.ResponseParameters
import com.github.insanusmokrassar.TelegramBotAPI.types.Response
import com.github.insanusmokrassar.TelegramBotAPI.types.RetryAfterError
import io.ktor.client.HttpClient
import io.ktor.client.call.HttpClientCall
import io.ktor.client.engine.HttpClientEngine
import io.ktor.client.engine.okhttp.OkHttp
import io.ktor.util.cio.toByteArray
import kotlinx.coroutines.delay
import kotlinx.io.charsets.Charset
import kotlinx.serialization.json.JSON
@ -22,7 +24,8 @@ class KtorRequestsExecutor(
hostUrl: String = "https://api.telegram.org",
callsFactories: List<KtorCallFactory> = emptyList(),
excludeDefaultFactories: Boolean = false,
private val requestsLimiter: RequestLimiter = EmptyLimiter
private val requestsLimiter: RequestLimiter = EmptyLimiter,
private val jsonFormatter: JSON = JSON.nonstrict
) : BaseRequestsExecutor(token, hostUrl) {
constructor(
token: String,
@ -59,11 +62,19 @@ class KtorRequestsExecutor(
throw IllegalArgumentException("Can't execute request: $request")
}
val content = call.response.content.toByteArray().toString(Charset.defaultCharset())
val responseObject = JSON.parse(
ResponseParameters.serializer(request.resultSerializer()),
val responseObject = jsonFormatter.parse(
Response.serializer(request.resultSerializer()),
content
)
responseObject.result ?: call.let {
responseObject.result ?: responseObject.parameters ?.let {
val error = it.error
if (error is RetryAfterError) {
delay(error.leftToRetry)
execute(request)
} else {
null
}
} ?: call.let {
throw RequestException(
responseObject,
"Can't get result object"

View File

@ -1,10 +1,10 @@
package com.github.insanusmokrassar.TelegramBotAPI.bot
import com.github.insanusmokrassar.TelegramBotAPI.types.ResponseParameters
import com.github.insanusmokrassar.TelegramBotAPI.types.Response
import java.io.IOException
class RequestException(
val response: ResponseParameters<*>,
val response: Response<*>,
message: String? = null,
cause: Throwable? = null
) : IOException(

View File

@ -1,6 +1,6 @@
package com.github.insanusmokrassar.TelegramBotAPI.requests.abstracts
import com.github.insanusmokrassar.TelegramBotAPI.types.ResponseParameters
import com.github.insanusmokrassar.TelegramBotAPI.types.Response
import com.github.insanusmokrassar.TelegramBotAPI.utils.toJsonWithoutNulls
import kotlinx.serialization.*
import kotlinx.serialization.json.JsonObject
@ -15,6 +15,6 @@ interface Request<T: Any> {
fun <T : Any> StringFormat.extractResult(
from: String,
dataSerializer: KSerializer<T>
): ResponseParameters<T> {
return parse(ResponseParameters.serializer(dataSerializer), from)
): Response<T> {
return parse(Response.serializer(dataSerializer), from)
}

View File

@ -0,0 +1,20 @@
package com.github.insanusmokrassar.TelegramBotAPI.types
import java.util.concurrent.TimeUnit
sealed class RequestError
data class RetryAfterError(
val seconds: Long,
val startCountingMillis: Long
) : RequestError() {
val canContinue = TimeUnit.SECONDS.toMillis(seconds) + startCountingMillis
val leftToRetry: Long
get() = canContinue - System.currentTimeMillis()
}
data class MigrateChatId(
val newChatId: ChatId
) : RequestError()

View File

@ -0,0 +1,25 @@
package com.github.insanusmokrassar.TelegramBotAPI.types
import kotlinx.serialization.*
import org.joda.time.DateTime
import java.util.concurrent.TimeUnit
@Deprecated(
"Deprecated because incorrect name",
ReplaceWith("Response")
)
typealias ResponseParameters<T> = Response<T>
@Serializable
data class Response<T : Any>(
val ok: Boolean = false,
@Optional
val description: String? = null,
@SerialName("error_code")
@Optional
val errorCode: Int? = null,
@Optional
val result: T? = null,
@Optional
val parameters: ResponseParametersRaw? = null
)

View File

@ -1,30 +0,0 @@
package com.github.insanusmokrassar.TelegramBotAPI.types
import kotlinx.serialization.*
import org.joda.time.DateTime
import java.util.concurrent.TimeUnit
@Serializable
data class ResponseParameters<T : Any>(
val ok: Boolean = false,
@Optional
val description: String? = null,
@SerialName("migrate_to_chat_id")
@Optional
val migrateToChatId: Identifier? = null,
@SerialName("retry_after")
@Optional
val retryAfter: Int? = null,
@SerialName("error_code")
@Optional
val errorCode: Int? = null,
@Optional
val result: T? = null
) {
@Transient
val waitUntil: DateTime? by lazy {
retryAfter ?.let {
DateTime.now().plus(TimeUnit.SECONDS.toMillis(it.toLong()))
}
}
}

View File

@ -0,0 +1,24 @@
package com.github.insanusmokrassar.TelegramBotAPI.types
import kotlinx.serialization.*
@Serializable
data class ResponseParametersRaw(
@SerialName("migrate_to_chat_id")
@Optional
private val migrateToChatId: ChatId? = null,
@SerialName("retry_after")
@Optional
private val retryAfter: Long? = null
) {
@Transient
private val createTime: Long = System.currentTimeMillis()
@Transient
val error: RequestError? by lazy {
when {
migrateToChatId != null -> MigrateChatId(migrateToChatId);
retryAfter != null -> RetryAfterError(retryAfter, createTime);
else -> null
}
}
}

View File

@ -4,7 +4,7 @@ import com.github.insanusmokrassar.TelegramBotAPI.bot.RequestException
import com.github.insanusmokrassar.TelegramBotAPI.bot.RequestsExecutor
import com.github.insanusmokrassar.TelegramBotAPI.requests.*
import com.github.insanusmokrassar.TelegramBotAPI.requests.abstracts.Request
import com.github.insanusmokrassar.TelegramBotAPI.types.ResponseParameters
import com.github.insanusmokrassar.TelegramBotAPI.types.Response
import com.github.insanusmokrassar.TelegramBotAPI.types.UpdateIdentifier
import com.github.insanusmokrassar.TelegramBotAPI.types.message.abstracts.MediaGroupMessage
import com.github.insanusmokrassar.TelegramBotAPI.types.update.*
@ -147,7 +147,7 @@ fun RequestsExecutor.startGettingOfUpdates(
fun <T: Any> RequestsExecutor.executeAsync(
request: Request<T>,
onFail: (suspend (ResponseParameters<*>) -> Unit)? = null,
onFail: (suspend (Response<*>) -> Unit)? = null,
scope: CoroutineScope = GlobalScope,
onSuccess: (suspend (T) -> Unit)? = null
): Job {