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

Merge pull request #803 from InsanusMokrassar/9.4.0

9.4.0
This commit is contained in:
InsanusMokrassar 2023-11-26 04:30:56 +06:00 committed by GitHub
commit 3a5fed3dd9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
19 changed files with 106 additions and 21 deletions

View File

@ -5,6 +5,9 @@ on: [pull_request, issues]
jobs:
greeting:
runs-on: ubuntu-latest
permissions:
issues: write
pull-requests: write
steps:
- uses: actions/first-interaction@v1
with:

View File

@ -1,5 +1,13 @@
# TelegramBotAPI changelog
## 9.4.0
* `Version`:
* `Kotlin`: `1.9.20` -> `1.9.21`
* `Serialization`: `1.6.0` -> `1.6.1`
* `Ktor`: `2.3.5` -> `2.3.6`
* `MicroUtils`: `0.20.12` -> `0.20.15`
## 9.3.0
This release become possible thanks to [Anton Lakotka](https://youtrack.jetbrains.com/users/anton.lakotka)

View File

@ -16,6 +16,7 @@ buildscript {
plugins {
alias(libs.plugins.kotlin.dokka)
alias(libs.plugins.versions)
}
// temporal crutch until legacy tests will be stabled or legacy target will be removed

View File

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

View File

@ -1,19 +1,22 @@
[versions]
kotlin = "1.9.20"
kotlin-serialization = "1.6.0"
kotlin = "1.9.21"
kotlin-serialization = "1.6.1"
kotlin-coroutines = "1.7.3"
javax-activation = "1.1.1"
korlibs = "4.0.10"
uuid = "0.8.1"
ktor = "2.3.5"
ktor = "2.3.6"
ksp = "1.9.20-1.0.14"
kotlin-poet = "1.14.2"
kotlin-poet = "1.15.1"
microutils = "0.20.12"
microutils = "0.20.15"
kslog = "1.3.1"
versions = "0.50.0"
github-release-plugin = "2.4.1"
dokka = "1.9.10"
@ -52,6 +55,8 @@ microutils-languageCodes = { module = "dev.inmo:micro_utils.language_codes", ver
microutils-ktor-common = { module = "dev.inmo:micro_utils.ktor.common", version.ref = "microutils" }
microutils-fsm-common = { module = "dev.inmo:micro_utils.fsm.common", version.ref = "microutils" }
kslog = { module = "dev.inmo:kslog", version.ref = "kslog" }
# ksp dependencies
kotlin-poet = { module = "com.squareup:kotlinpoet-ksp", version.ref = "kotlin-poet" }
@ -71,3 +76,4 @@ kotlin-jvm = { id = "org.jetbrains.kotlin.jvm", version.ref = "kotlin" }
kotlin-multiplatform = { id = "org.jetbrains.kotlin.multiplatform", version.ref = "kotlin" }
kotlin-serialization = { id = "org.jetbrains.kotlin.plugin.serialization", version.ref = "kotlin" }
kotlin-dokka = { id = "org.jetbrains.dokka", version.ref = "dokka" }
versions = { id = "com.github.ben-manes.versions", version.ref = "versions" }

View File

@ -13,6 +13,8 @@ kotlin {
sourceSets {
commonMain {
dependencies {
api project(":tgbotapi.core")
api project(":tgbotapi.utils")
api project(":tgbotapi.behaviour_builder")
api libs.microutils.fsm.common
}

View File

@ -13,7 +13,8 @@ kotlin {
sourceSets {
commonMain {
dependencies {
api project(":tgbotapi.utils")
api project(path: ':tgbotapi.core')
api project(path: ':tgbotapi.utils')
}
}
}

View File

@ -31,6 +31,8 @@ kotlin {
api libs.microutils.languageCodes
api libs.ktor.client.core
api libs.kslog
}
}
commonTest {

View File

@ -1,8 +1,10 @@
package dev.inmo.tgbotapi.bot.ktor
import dev.inmo.kslog.common.KSLog
import dev.inmo.tgbotapi.bot.BaseRequestsExecutor
import dev.inmo.tgbotapi.bot.settings.limiters.ExceptionsOnlyLimiter
import dev.inmo.tgbotapi.bot.settings.limiters.RequestLimiter
import dev.inmo.tgbotapi.utils.DefaultKTgBotAPIKSLog
import dev.inmo.tgbotapi.utils.TelegramAPIUrlsKeeper
import dev.inmo.tgbotapi.utils.nonstrictJsonFormat
import io.ktor.client.*
@ -22,6 +24,7 @@ expect class KtorRequestsExecutor internal constructor(
requestsLimiter: RequestLimiter,
jsonFormatter: Json,
pipelineStepsHolder: KtorPipelineStepsHolder,
logger: KSLog,
diff: Unit // just a diff property to know where constructor and where calling function with defaults
) : BaseRequestsExecutor
@ -32,7 +35,8 @@ fun KtorRequestsExecutor(
excludeDefaultFactories: Boolean = false,
requestsLimiter: RequestLimiter = ExceptionsOnlyLimiter,
jsonFormatter: Json = nonstrictJsonFormat,
pipelineStepsHolder: KtorPipelineStepsHolder = KtorPipelineStepsHolder
pipelineStepsHolder: KtorPipelineStepsHolder = KtorPipelineStepsHolder,
logger: KSLog = DefaultKTgBotAPIKSLog,
) = KtorRequestsExecutor(
telegramAPIUrlsKeeper = telegramAPIUrlsKeeper,
client = client,
@ -41,5 +45,6 @@ fun KtorRequestsExecutor(
requestsLimiter = requestsLimiter,
jsonFormatter = jsonFormatter,
pipelineStepsHolder = pipelineStepsHolder,
diff = kotlin.Unit
logger = logger,
diff = kotlin.Unit,
)

View File

@ -1,5 +1,6 @@
package dev.inmo.tgbotapi.bot.ktor
import dev.inmo.kslog.common.KSLog
import dev.inmo.tgbotapi.bot.BaseRequestsExecutor
import dev.inmo.tgbotapi.bot.TelegramBot
import dev.inmo.tgbotapi.bot.ktor.base.*
@ -10,9 +11,9 @@ import io.ktor.client.HttpClient
import kotlinx.serialization.json.Json
@RiskFeature
fun createTelegramBotDefaultKtorCallRequestsFactories() = listOf(
SimpleRequestCallFactory(),
MultipartRequestCallFactory(),
fun createTelegramBotDefaultKtorCallRequestsFactories(logger: KSLog? = null) = listOf(
SimpleRequestCallFactory(logger),
MultipartRequestCallFactory(logger),
DownloadFileRequestCallFactory,
DownloadFileChannelRequestCallFactory
)
@ -25,6 +26,8 @@ class KtorRequestsExecutorBuilder(
var excludeDefaultFactories: Boolean = false
var requestsLimiter: RequestLimiter = ExceptionsOnlyLimiter
var jsonFormatter: Json = nonstrictJsonFormat
var logger: KSLog = DefaultKTgBotAPIKSLog
var pipelineStepsHolder: KtorPipelineStepsHolder = KtorPipelineStepsHolder
fun build() = KtorRequestsExecutor(
telegramAPIUrlsKeeper,
@ -32,7 +35,9 @@ class KtorRequestsExecutorBuilder(
callsFactories,
excludeDefaultFactories,
requestsLimiter,
jsonFormatter
jsonFormatter,
pipelineStepsHolder,
logger
)
}

View File

@ -1,23 +1,30 @@
package dev.inmo.tgbotapi.bot.ktor.base
import dev.inmo.kslog.common.KSLog
import dev.inmo.kslog.common.v
import dev.inmo.kslog.common.w
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.GetUpdatesRequest
import dev.inmo.tgbotapi.requests.abstracts.Request
import dev.inmo.tgbotapi.types.Response
import dev.inmo.tgbotapi.utils.DefaultKTgBotAPIKSLog
import dev.inmo.tgbotapi.utils.TelegramAPIUrlsKeeper
import io.ktor.client.HttpClient
import io.ktor.client.plugins.timeout
import io.ktor.client.request.*
import io.ktor.client.statement.bodyAsText
import io.ktor.http.ContentType
import kotlinx.serialization.Serializable
import kotlinx.serialization.json.Json
import kotlin.collections.set
var defaultUpdateTimeoutForZeroDelay = 1000L
abstract class AbstractRequestCallFactory : KtorCallFactory {
abstract class AbstractRequestCallFactory(
protected open val logger: KSLog = DefaultKTgBotAPIKSLog
) : KtorCallFactory {
private val methodsCache: MutableMap<String, String> = mutableMapOf()
override suspend fun <T : Any> makeCall(
client: HttpClient,
@ -26,6 +33,7 @@ abstract class AbstractRequestCallFactory : KtorCallFactory {
jsonFormatter: Json
): T? {
val preparedBody = prepareCallBody(client, urlsKeeper, request) ?: return null
logger.v { "Prepared body for $request: $preparedBody" }
client.post {
url(
@ -54,7 +62,9 @@ abstract class AbstractRequestCallFactory : KtorCallFactory {
setBody(preparedBody)
}.let { response ->
val content = response.bodyAsText()
logger.v { "Raw answer for $request: $content" }
val responseObject = jsonFormatter.decodeFromString(Response.serializer(), content)
logger.v { "Answer as json for $request: $responseObject" }
return runCatchingSafely {
(responseObject.result?.let {
@ -66,6 +76,8 @@ abstract class AbstractRequestCallFactory : KtorCallFactory {
"Can't get result object from $content"
)
})
}.onFailure {
logger.w { "Got exception answer for $request: $it" }
}.getOrThrow()
}
}

View File

@ -1,5 +1,9 @@
package dev.inmo.tgbotapi.bot.ktor.base
import dev.inmo.kslog.common.KSLog
import dev.inmo.kslog.common.e
import dev.inmo.kslog.common.i
import dev.inmo.kslog.common.v
import dev.inmo.micro_utils.coroutines.runCatchingSafely
import dev.inmo.tgbotapi.bot.BaseRequestsExecutor
import dev.inmo.tgbotapi.bot.exceptions.BotException
@ -28,12 +32,15 @@ class DefaultKtorRequestsExecutor internal constructor(
private val requestsLimiter: RequestLimiter,
private val jsonFormatter: Json,
private val pipelineStepsHolder: KtorPipelineStepsHolder,
private val logger: KSLog,
diff: Unit
) : BaseRequestsExecutor(telegramAPIUrlsKeeper) {
private val callsFactories: List<KtorCallFactory> = callsFactories.run {
if (!excludeDefaultFactories) {
this + createTelegramBotDefaultKtorCallRequestsFactories()
logger.v { "Installing default factories" }
this + createTelegramBotDefaultKtorCallRequestsFactories(logger)
} else {
logger.v { "Default factories will not be installed" }
this
}
}
@ -46,19 +53,23 @@ class DefaultKtorRequestsExecutor internal constructor(
override suspend fun <T : Any> execute(request: Request<T>): T {
return runCatchingSafely {
logger.v { "Start request $request" }
pipelineStepsHolder.onBeforeSearchCallFactory(request, callsFactories)
requestsLimiter.limit(request) {
var result: T? = null
lateinit var factoryHandledRequest: KtorCallFactory
for (potentialFactory in callsFactories) {
pipelineStepsHolder.onBeforeCallFactoryMakeCall(request, potentialFactory)
result = potentialFactory.makeCall(
logger.v { "Trying factory $potentialFactory for $request" }
val resultFromFactory = potentialFactory.makeCall(
client,
telegramAPIUrlsKeeper,
request,
jsonFormatter
)
result = pipelineStepsHolder.onAfterCallFactoryMakeCall(result, request, potentialFactory)
logger.v { "Result of factory $potentialFactory handling $request: $resultFromFactory" }
result = pipelineStepsHolder.onAfterCallFactoryMakeCall(resultFromFactory, request, potentialFactory)
logger.v { "Result of pipeline $pipelineStepsHolder handling $resultFromFactory: $result" }
if (result != null) {
factoryHandledRequest = potentialFactory
break
@ -71,6 +82,7 @@ class DefaultKtorRequestsExecutor internal constructor(
}
}.let {
val result = it.exceptionOrNull() ?.let { e ->
logger.v(e) { "Got exception on handling of $request" }
pipelineStepsHolder.onRequestException(request, e) ?.let { return@let it }
when (e) {
@ -90,9 +102,13 @@ class DefaultKtorRequestsExecutor internal constructor(
}
is BotException -> e
else -> CommonBotException(cause = e)
}.also {
logger.v(e) { "Result exception on handling of $request: $it" }
}
} ?.let { Result.failure(it) } ?: it
pipelineStepsHolder.onRequestReturnResult(result, request, callsFactories)
pipelineStepsHolder.onRequestReturnResult(result, request, callsFactories).also {
logger.v { "Result of handling $request: $it" }
}
}
}

View File

@ -5,6 +5,7 @@ import dev.inmo.tgbotapi.bot.ktor.KtorCallFactory
import dev.inmo.tgbotapi.requests.DownloadFileStream
import dev.inmo.tgbotapi.requests.abstracts.Request
import dev.inmo.tgbotapi.utils.ByteReadChannelAllocator
import dev.inmo.tgbotapi.utils.RiskFeature
import dev.inmo.tgbotapi.utils.TelegramAPIUrlsKeeper
import io.ktor.client.HttpClient
import io.ktor.client.call.receive
@ -15,6 +16,7 @@ import io.ktor.utils.io.*
import kotlinx.coroutines.*
import kotlinx.serialization.json.Json
@RiskFeature
object DownloadFileChannelRequestCallFactory : KtorCallFactory {
override suspend fun <T : Any> makeCall(
client: HttpClient,

View File

@ -4,12 +4,14 @@ import dev.inmo.micro_utils.coroutines.safely
import dev.inmo.tgbotapi.bot.ktor.KtorCallFactory
import dev.inmo.tgbotapi.requests.DownloadFile
import dev.inmo.tgbotapi.requests.abstracts.Request
import dev.inmo.tgbotapi.utils.RiskFeature
import dev.inmo.tgbotapi.utils.TelegramAPIUrlsKeeper
import io.ktor.client.HttpClient
import io.ktor.client.request.get
import io.ktor.client.statement.readBytes
import kotlinx.serialization.json.Json
@RiskFeature
object DownloadFileRequestCallFactory : KtorCallFactory {
override suspend fun <T : Any> makeCall(
client: HttpClient,

View File

@ -1,6 +1,8 @@
package dev.inmo.tgbotapi.bot.ktor.base
import dev.inmo.kslog.common.KSLog
import dev.inmo.tgbotapi.requests.abstracts.*
import dev.inmo.tgbotapi.utils.DefaultKTgBotAPIKSLog
import dev.inmo.tgbotapi.utils.TelegramAPIUrlsKeeper
import dev.inmo.tgbotapi.utils.mapWithCommonValues
import io.ktor.client.HttpClient
@ -8,7 +10,7 @@ import io.ktor.client.request.forms.*
import io.ktor.http.Headers
import io.ktor.http.HttpHeaders
class MultipartRequestCallFactory : AbstractRequestCallFactory() {
class MultipartRequestCallFactory(logger: KSLog? = null) : AbstractRequestCallFactory(logger ?: DefaultKTgBotAPIKSLog) {
override fun <T : Any> prepareCallBody(
client: HttpClient,
urlsKeeper: TelegramAPIUrlsKeeper,

View File

@ -1,5 +1,6 @@
package dev.inmo.tgbotapi.bot.ktor.base
import dev.inmo.kslog.common.KSLog
import dev.inmo.micro_utils.coroutines.runCatchingSafely
import dev.inmo.tgbotapi.bot.BaseRequestsExecutor
import dev.inmo.tgbotapi.bot.ktor.KtorCallFactory
@ -48,6 +49,7 @@ class MultipleClientKtorRequestsExecutor (
jsonFormatter: Json,
pipelineStepsHolder: KtorPipelineStepsHolder,
requestExecutorsCount: Int,
logger: KSLog,
clientFactory: () -> HttpClient
) : BaseRequestsExecutor(telegramAPIUrlsKeeper) {
private val requestExecutors = (0 until requestExecutorsCount).map {
@ -59,6 +61,7 @@ class MultipleClientKtorRequestsExecutor (
requestsLimiter,
jsonFormatter,
pipelineStepsHolder,
logger,
Unit
)
}.toSet()
@ -80,6 +83,7 @@ class MultipleClientKtorRequestsExecutor (
requestsLimiter: RequestLimiter,
jsonFormatter: Json,
pipelineStepsHolder: KtorPipelineStepsHolder,
logger: KSLog,
diff: Unit
) : this(
telegramAPIUrlsKeeper,
@ -89,6 +93,7 @@ class MultipleClientKtorRequestsExecutor (
jsonFormatter,
pipelineStepsHolder,
client.engineConfig.threadsCount,
logger,
{ platformClientCopy(client) }
)

View File

@ -1,12 +1,14 @@
package dev.inmo.tgbotapi.bot.ktor.base
import dev.inmo.kslog.common.KSLog
import dev.inmo.tgbotapi.requests.abstracts.*
import dev.inmo.tgbotapi.utils.DefaultKTgBotAPIKSLog
import dev.inmo.tgbotapi.utils.TelegramAPIUrlsKeeper
import io.ktor.client.HttpClient
import io.ktor.http.ContentType
import io.ktor.http.content.TextContent
class SimpleRequestCallFactory : AbstractRequestCallFactory() {
class SimpleRequestCallFactory(logger: KSLog? = null) : AbstractRequestCallFactory(logger ?: DefaultKTgBotAPIKSLog) {
override fun <T : Any> prepareCallBody(
client: HttpClient,
urlsKeeper: TelegramAPIUrlsKeeper,

View File

@ -0,0 +1,11 @@
package dev.inmo.tgbotapi.utils
import dev.inmo.kslog.common.KSLog
import dev.inmo.kslog.common.TagLogger
/**
* Default realization of [KSLog] which will be used everywhere where there is no some custom variant of [KSLog]
*
* By default, uses [TagLogger] with tag `KTgBot` (which in fact falling back to [KSLog.default] with `KTgBot` default tag)
*/
var DefaultKTgBotAPIKSLog: KSLog = TagLogger("KTgBot")

View File

@ -13,7 +13,7 @@ kotlin {
sourceSets {
commonMain {
dependencies {
api project(":tgbotapi.core")
api project(path: ":tgbotapi.core")
}
}
}