Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

19.0.0 #913

Merged
merged 7 commits into from
Oct 30, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/packages_publishing.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ jobs:
rm gradle.properties
mv gradle.properties.tmp gradle.properties
- name: KotlinSymbolProcessing execution
run: ./gradlew ksp
run: ./gradlew kspCommonMainKotlinMetadata
- name: Build
run: ./gradlew build
- name: API compatibility check
Expand Down
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
# TelegramBotAPI changelog

## 19.0.0

**THIS UPDATE CONTAINS BREAKING CHANGES**

**THIS UPDATE CONTAINS UPGRADE UP TO KTOR 3.0 (thanks to [@d1snin](https://github.com/d1snin))**

## 18.2.3

* `Core`:
Expand Down
2 changes: 1 addition & 1 deletion gradle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,4 @@ kotlin.incremental=true
kotlin.incremental.js=true

library_group=dev.inmo
library_version=18.2.3
library_version=19.0.0
6 changes: 3 additions & 3 deletions gradle/libs.versions.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,12 @@ javax-activation = "1.1.1"

korlibs = "5.4.0"
uuid = "0.8.4"
ktor = "2.3.12"
ktor = "3.0.1"

ksp = "2.0.21-1.0.25"
ksp = "2.0.21-1.0.26"
kotlin-poet = "1.18.1"

microutils = "0.22.7"
microutils = "0.23.0"
kslog = "1.3.6"

versions = "0.51.0"
Expand Down
2 changes: 1 addition & 1 deletion tgbotapi.core/api/tgbotapi.core.api
Original file line number Diff line number Diff line change
Expand Up @@ -1034,7 +1034,7 @@ public final class dev/inmo/tgbotapi/requests/abstracts/MultipartFile : dev/inmo
public fun equals (Ljava/lang/Object;)Z
public fun getFileId ()Ljava/lang/String;
public final fun getFilename ()Ljava/lang/String;
public final fun getInput ()Lio/ktor/utils/io/core/Input;
public final fun getInput ()Lkotlinx/io/Source;
public fun hashCode ()I
public fun toString ()Ljava/lang/String;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,7 @@ 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
import io.ktor.client.request.get
import io.ktor.client.statement.HttpStatement
import io.ktor.client.statement.bodyAsChannel
import io.ktor.utils.io.*
import kotlinx.coroutines.*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@ 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 io.ktor.client.*
import io.ktor.client.request.*
import io.ktor.client.statement.*
import kotlinx.serialization.json.Json

@RiskFeature
Expand All @@ -17,13 +17,13 @@ object DownloadFileRequestCallFactory : KtorCallFactory {
client: HttpClient,
urlsKeeper: TelegramAPIUrlsKeeper,
request: Request<T>,
jsonFormatter: Json
): T? = (request as? DownloadFile) ?.let {
jsonFormatter: Json,
): T? = (request as? DownloadFile)?.let {
val fullUrl = urlsKeeper.createFileLinkUrl(it.filePath)

safely {
@Suppress("UNCHECKED_CAST")
client.get(fullUrl).readBytes() as T // always ByteArray
client.get(fullUrl).readRawBytes() as T // always ByteArray
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ internal expect inline fun platformClientCopy(client: HttpClient): HttpClient
* @param requestExecutorsCount Amount of [DefaultKtorRequestsExecutor] which will be created and used under the
* hood
*/
class MultipleClientKtorRequestsExecutor (
class MultipleClientKtorRequestsExecutor(
telegramAPIUrlsKeeper: TelegramAPIUrlsKeeper,
callsFactories: List<KtorCallFactory>,
excludeDefaultFactories: Boolean,
Expand All @@ -47,7 +47,7 @@ class MultipleClientKtorRequestsExecutor (
pipelineStepsHolder: TelegramBotPipelinesHandler,
requestExecutorsCount: Int,
logger: KSLog,
clientFactory: () -> HttpClient
clientFactory: () -> HttpClient,
) : BaseRequestsExecutor(telegramAPIUrlsKeeper) {
private val requestExecutors = (0 until requestExecutorsCount).map {
DefaultKtorRequestsExecutor(
Expand All @@ -66,7 +66,7 @@ class MultipleClientKtorRequestsExecutor (
private val clientAllocationMutex = Mutex()
private val takerFlow = freeClients.mapNotNull {
clientAllocationMutex.withLock {
freeClients.value.firstOrNull() ?.also {
freeClients.value.firstOrNull()?.also {
freeClients.value -= it
} ?: return@mapNotNull null
}
Expand All @@ -81,15 +81,15 @@ class MultipleClientKtorRequestsExecutor (
jsonFormatter: Json,
pipelineStepsHolder: TelegramBotPipelinesHandler,
logger: KSLog,
diff: Unit
diff: Unit,
) : this(
telegramAPIUrlsKeeper,
callsFactories,
excludeDefaultFactories,
requestsLimiter,
jsonFormatter,
pipelineStepsHolder,
client.engineConfig.threadsCount,
requestExecutorsCount = 4, // default threads count; configurable through dispatcher property
logger,
{ platformClientCopy(client) }
)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
package dev.inmo.tgbotapi.utils

import io.ktor.util.toByteArray
import io.ktor.utils.io.ByteReadChannel
import io.ktor.utils.io.core.ByteReadPacket
import io.ktor.utils.io.core.Input
import io.ktor.utils.io.*
import io.ktor.utils.io.core.*

actual suspend fun ByteReadChannel.asInput(): Input = ByteReadPacket(toByteArray())
8 changes: 4 additions & 4 deletions tgbotapi.utils/api/tgbotapi.utils.api
Original file line number Diff line number Diff line change
Expand Up @@ -3541,10 +3541,10 @@ public final class dev/inmo/tgbotapi/extensions/utils/updates/retrieving/Webhook
public static synthetic fun includeWebhookHandlingInRoute$default (Lio/ktor/server/routing/Route;Lkotlinx/coroutines/CoroutineScope;Lkotlin/jvm/functions/Function2;JLkotlin/jvm/functions/Function2;ILjava/lang/Object;)V
public static final fun includeWebhookHandlingInRouteWithFlows (Lio/ktor/server/routing/Route;Lkotlinx/coroutines/CoroutineScope;Lkotlin/jvm/functions/Function2;JLkotlin/jvm/functions/Function1;)V
public static synthetic fun includeWebhookHandlingInRouteWithFlows$default (Lio/ktor/server/routing/Route;Lkotlinx/coroutines/CoroutineScope;Lkotlin/jvm/functions/Function2;JLkotlin/jvm/functions/Function1;ILjava/lang/Object;)V
public static final fun setWebhookInfoAndStartListenWebhooks (Ldev/inmo/tgbotapi/bot/RequestsExecutor;ILio/ktor/server/engine/ApplicationEngineFactory;Ldev/inmo/tgbotapi/requests/webhook/SetWebhookRequest;Lkotlin/jvm/functions/Function2;Ljava/lang/String;Ljava/lang/String;Ldev/inmo/tgbotapi/updateshandlers/webhook/WebhookPrivateKeyConfig;Lkotlinx/coroutines/CoroutineScope;JLkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function2;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
public static synthetic fun setWebhookInfoAndStartListenWebhooks$default (Ldev/inmo/tgbotapi/bot/RequestsExecutor;ILio/ktor/server/engine/ApplicationEngineFactory;Ldev/inmo/tgbotapi/requests/webhook/SetWebhookRequest;Lkotlin/jvm/functions/Function2;Ljava/lang/String;Ljava/lang/String;Ldev/inmo/tgbotapi/updateshandlers/webhook/WebhookPrivateKeyConfig;Lkotlinx/coroutines/CoroutineScope;JLkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function2;Lkotlin/coroutines/Continuation;ILjava/lang/Object;)Ljava/lang/Object;
public static final fun startListenWebhooks (ILio/ktor/server/engine/ApplicationEngineFactory;Lkotlin/jvm/functions/Function2;Ljava/lang/String;Ljava/lang/String;Ldev/inmo/tgbotapi/updateshandlers/webhook/WebhookPrivateKeyConfig;Lkotlinx/coroutines/CoroutineScope;JLkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function2;)Lio/ktor/server/engine/ApplicationEngine;
public static synthetic fun startListenWebhooks$default (ILio/ktor/server/engine/ApplicationEngineFactory;Lkotlin/jvm/functions/Function2;Ljava/lang/String;Ljava/lang/String;Ldev/inmo/tgbotapi/updateshandlers/webhook/WebhookPrivateKeyConfig;Lkotlinx/coroutines/CoroutineScope;JLkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function2;ILjava/lang/Object;)Lio/ktor/server/engine/ApplicationEngine;
public static final fun setWebhookInfoAndStartListenWebhooks (Ldev/inmo/tgbotapi/bot/RequestsExecutor;ILio/ktor/server/engine/ApplicationEngineFactory;Ldev/inmo/tgbotapi/requests/webhook/SetWebhookRequest;Lkotlin/jvm/functions/Function2;Ljava/lang/String;Ljava/lang/String;Ldev/inmo/tgbotapi/updateshandlers/webhook/WebhookPrivateKeyConfig;Lkotlinx/coroutines/CoroutineScope;JLkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function2;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
public static synthetic fun setWebhookInfoAndStartListenWebhooks$default (Ldev/inmo/tgbotapi/bot/RequestsExecutor;ILio/ktor/server/engine/ApplicationEngineFactory;Ldev/inmo/tgbotapi/requests/webhook/SetWebhookRequest;Lkotlin/jvm/functions/Function2;Ljava/lang/String;Ljava/lang/String;Ldev/inmo/tgbotapi/updateshandlers/webhook/WebhookPrivateKeyConfig;Lkotlinx/coroutines/CoroutineScope;JLkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function2;Lkotlin/coroutines/Continuation;ILjava/lang/Object;)Ljava/lang/Object;
public static final fun startListenWebhooks (ILio/ktor/server/engine/ApplicationEngineFactory;Lkotlin/jvm/functions/Function2;Ljava/lang/String;Ljava/lang/String;Ldev/inmo/tgbotapi/updateshandlers/webhook/WebhookPrivateKeyConfig;Lkotlinx/coroutines/CoroutineScope;JLkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function2;)Lio/ktor/server/engine/EmbeddedServer;
public static synthetic fun startListenWebhooks$default (ILio/ktor/server/engine/ApplicationEngineFactory;Lkotlin/jvm/functions/Function2;Ljava/lang/String;Ljava/lang/String;Ldev/inmo/tgbotapi/updateshandlers/webhook/WebhookPrivateKeyConfig;Lkotlinx/coroutines/CoroutineScope;JLkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function2;ILjava/lang/Object;)Lio/ktor/server/engine/EmbeddedServer;
}

public final class dev/inmo/tgbotapi/types/files/PathedFileAsStreamKt {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,19 +1,21 @@
package dev.inmo.tgbotapi.extensions.utils.updates.retrieving

import dev.inmo.micro_utils.coroutines.*
import dev.inmo.micro_utils.coroutines.ExceptionHandler
import dev.inmo.micro_utils.coroutines.runCatchingSafely
import dev.inmo.tgbotapi.bot.RequestsExecutor
import dev.inmo.tgbotapi.extensions.utils.nonstrictJsonFormat
import dev.inmo.tgbotapi.extensions.utils.updates.flowsUpdatesFilter
import dev.inmo.tgbotapi.requests.webhook.SetWebhookRequest
import dev.inmo.tgbotapi.types.update.abstracts.Update
import dev.inmo.tgbotapi.types.update.abstracts.UpdateDeserializationStrategy
import dev.inmo.tgbotapi.updateshandlers.*
import dev.inmo.tgbotapi.updateshandlers.FlowsUpdatesFilter
import dev.inmo.tgbotapi.updateshandlers.UpdateReceiver
import dev.inmo.tgbotapi.updateshandlers.UpdatesFilter
import dev.inmo.tgbotapi.updateshandlers.webhook.WebhookPrivateKeyConfig
import io.ktor.http.HttpStatusCode
import io.ktor.server.application.call
import io.ktor.http.*
import io.ktor.server.engine.*
import io.ktor.server.request.receiveText
import io.ktor.server.response.respond
import io.ktor.server.request.*
import io.ktor.server.response.*
import io.ktor.server.routing.*
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.asCoroutineDispatcher
Expand All @@ -38,7 +40,7 @@ fun Route.includeWebhookHandlingInRoute(
scope: CoroutineScope,
exceptionsHandler: ExceptionHandler<Unit>? = null,
mediaGroupsDebounceTimeMillis: Long = 1000L,
block: UpdateReceiver<Update>
block: UpdateReceiver<Update>,
) {
val transformer = scope.updateHandlerWithMediaGroupsAdaptation(block, mediaGroupsDebounceTimeMillis)
post {
Expand All @@ -55,7 +57,7 @@ fun Route.includeWebhookHandlingInRoute(
call.respond(HttpStatusCode.InternalServerError)
}.getOrThrow()
} catch (e: Throwable) {
exceptionsHandler ?.invoke(e)
exceptionsHandler?.invoke(e)
}
}
}
Expand All @@ -69,7 +71,7 @@ fun Route.includeWebhookHandlingInRouteWithFlows(
scope: CoroutineScope,
exceptionsHandler: ExceptionHandler<Unit>? = null,
mediaGroupsDebounceTimeMillis: Long = 1000L,
block: FlowsUpdatesFilter.() -> Unit
block: FlowsUpdatesFilter.() -> Unit,
) = includeWebhookHandlingInRoute(
scope,
exceptionsHandler,
Expand All @@ -92,50 +94,57 @@ fun Route.includeWebhookHandlingInRouteWithFlows(
* @see UpdatesFilter
* @see UpdatesFilter.asUpdateReceiver
*/
fun startListenWebhooks(
fun <TEngine : ApplicationEngine, TConfiguration : ApplicationEngine.Configuration> startListenWebhooks(
listenPort: Int,
engineFactory: ApplicationEngineFactory<*, *>,
engineFactory: ApplicationEngineFactory<TEngine, TConfiguration>,
exceptionsHandler: ExceptionHandler<Unit>,
listenHost: String = "0.0.0.0",
listenRoute: String? = null,
privateKeyConfig: WebhookPrivateKeyConfig? = null,
scope: CoroutineScope = CoroutineScope(Executors.newFixedThreadPool(4).asCoroutineDispatcher()),
mediaGroupsDebounceTimeMillis: Long = 1000L,
additionalApplicationEngineEnvironmentConfigurator: ApplicationEngineEnvironmentBuilder.() -> Unit = {},
block: UpdateReceiver<Update>
): ApplicationEngine {
val env = applicationEngineEnvironment {
additionalApplicationEnvironmentConfigurator: ApplicationEnvironmentBuilder.() -> Unit = {},
additionalEngineConfigurator: TConfiguration.() -> Unit = {},
block: UpdateReceiver<Update>,
): EmbeddedServer<TEngine, TConfiguration> =
embeddedServer(
factory = engineFactory,
environment = applicationEnvironment {
additionalApplicationEnvironmentConfigurator()
},
configure = {
privateKeyConfig?.let {
sslConnector(
privateKeyConfig.keyStore,
privateKeyConfig.aliasName,
privateKeyConfig::keyStorePassword,
privateKeyConfig::aliasPassword
) {
host = listenHost
port = listenPort
}
} ?: connector {
host = listenHost
port = listenPort
}

module {
additionalEngineConfigurator()
},
module = {
routing {
listenRoute ?.also {
createRouteFromPath(it).includeWebhookHandlingInRoute(scope, exceptionsHandler, mediaGroupsDebounceTimeMillis, block)
listenRoute?.also {
createRouteFromPath(it).includeWebhookHandlingInRoute(
scope,
exceptionsHandler,
mediaGroupsDebounceTimeMillis,
block
)
} ?: includeWebhookHandlingInRoute(scope, exceptionsHandler, mediaGroupsDebounceTimeMillis, block)
}
}

privateKeyConfig ?.let {
sslConnector(
privateKeyConfig.keyStore,
privateKeyConfig.aliasName,
privateKeyConfig::keyStorePassword,
privateKeyConfig::aliasPassword
) {
host = listenHost
port = listenPort
}
} ?: connector {
host = listenHost
port = listenPort
}

additionalApplicationEngineEnvironmentConfigurator()
}

return embeddedServer(engineFactory, env).also {
).also {
it.start(false)
}
}

/**
* Setting up ktor server, set webhook info via [SetWebhookRequest] request.
Expand All @@ -152,21 +161,34 @@ fun startListenWebhooks(
* @see UpdatesFilter.asUpdateReceiver
*/
@Suppress("unused")
suspend fun RequestsExecutor.setWebhookInfoAndStartListenWebhooks(
suspend fun <TEngine : ApplicationEngine, TConfiguration : ApplicationEngine.Configuration> RequestsExecutor.setWebhookInfoAndStartListenWebhooks(
listenPort: Int,
engineFactory: ApplicationEngineFactory<*, *>,
engineFactory: ApplicationEngineFactory<TEngine, TConfiguration>,
setWebhookRequest: SetWebhookRequest,
exceptionsHandler: ExceptionHandler<Unit> = {},
listenHost: String = "0.0.0.0",
listenRoute: String = "/",
privateKeyConfig: WebhookPrivateKeyConfig? = null,
scope: CoroutineScope = CoroutineScope(Executors.newFixedThreadPool(4).asCoroutineDispatcher()),
mediaGroupsDebounceTimeMillis: Long = 1000L,
additionalApplicationEngineEnvironmentConfigurator: ApplicationEngineEnvironmentBuilder.() -> Unit = {},
block: UpdateReceiver<Update>
): ApplicationEngine = try {
additionalApplicationEnvironmentConfigurator: ApplicationEnvironmentBuilder.() -> Unit = {},
additionalEngineConfigurator: TConfiguration.() -> Unit = {},
block: UpdateReceiver<Update>,
): EmbeddedServer<TEngine, TConfiguration> = try {
execute(setWebhookRequest)
startListenWebhooks(listenPort, engineFactory, exceptionsHandler, listenHost, listenRoute, privateKeyConfig, scope, mediaGroupsDebounceTimeMillis, additionalApplicationEngineEnvironmentConfigurator, block)
startListenWebhooks(
listenPort,
engineFactory,
exceptionsHandler,
listenHost,
listenRoute,
privateKeyConfig,
scope,
mediaGroupsDebounceTimeMillis,
additionalApplicationEnvironmentConfigurator,
additionalEngineConfigurator,
block
)
} catch (e: Exception) {
throw e
}
Loading