1
0
mirror of https://github.com/InsanusMokrassar/TelegramBotAPI.git synced 2026-06-12 06:16:43 +00:00

Compare commits

..

18 Commits

Author SHA1 Message Date
71ccfc88cc start add SendChecklist 2025-07-07 16:25:21 +06:00
dd2923f92d complete base checklists? 2025-07-07 15:39:48 +06:00
ff78153591 small improvements 2025-07-07 15:18:22 +06:00
e2ce9cfebf preview version of inputs for tasks 2025-07-07 14:38:39 +06:00
0a01d2567e add checklist 2025-07-04 11:53:16 +06:00
e4fb45c09b start realize Bots API 9.1 2025-07-03 22:25:47 +06:00
db0df975c7 start 26.1.0 2025-07-03 22:07:16 +06:00
2003b314a3 update maven badge 2025-06-30 14:00:07 +06:00
55a78375be Merge pull request #977 from centralhardware/PR1
docs: make buildEntities usage more obvious to anyone not familiar with Telegram Bot API or ktgbotapi
2025-06-23 21:20:33 +06:00
alex
256607e336 docs: make buildEntities usage more obvious to anyone not familiar with Telegram Bot API or ktgbotapi 2025-06-23 18:58:08 +08:00
92f2a5afdb Merge pull request #974 from InsanusMokrassar/26.0.0
26.0.0
2025-06-15 19:46:05 +06:00
3affcf4399 Update build.gradle 2025-06-15 19:37:59 +06:00
67dfa19a1b Update CHANGELOG.md 2025-06-15 19:37:26 +06:00
86e83f7f1a refactor: expectFlow 2025-06-15 12:24:23 +06:00
429fc5d2f9 small improvements in long polling and behaviour buildr 2025-06-15 11:38:17 +06:00
d19e6ad4e0 fill changelog 2025-06-15 10:34:42 +06:00
134145f441 fix version in gradle.properties -.- 2025-06-14 23:41:23 +06:00
ef76fe52ca fill changelog 2025-06-14 19:40:05 +06:00
26 changed files with 694 additions and 55 deletions

View File

@@ -1,6 +1,10 @@
# TelegramBotAPI changelog
## 25.0.2
## 26.1.0
## 26.0.0
**THIS UPDATE CONTAINS BREAKING CHANGES IN BEHAVIOUR BUILDER AND CORE. BE CAREFUL ON UPDATE**
* `Version`:
* `Serialization`: `1.8.0` -> `1.8.1`
@@ -8,7 +12,13 @@
* `Ktor`: `3.1.1` -> `3.1.3`
* `MicroUtils`: `0.25.3` -> `0.25.7`
* `Core`:
* `RequestsExecutor` got property `RequestsExecutor.Log: KSLog?`
* **POTENTIALLY BREAKING CHANGE** Long polling has been reworked a bit
* **BREAKING CHANGE** `RequestsExecutor` got property `RequestsExecutor.Log: KSLog`
* `BehaviourContext`:
* **BREAKING CHANGE** All triggers and waiters become non-suspend functions
* **BREAKING CHANGE** Behaviour of counted extensions (commands, data callback queries, etc.) has been changed a bit: now each one will
create subcontext and work in it
* New extension `BehaviourContext.launchInNewSubContext` which will launch some job in subcontext of receiver
## 25.0.1

View File

@@ -1,4 +1,4 @@
# TelegramBotAPI [![Maven Central](https://maven-badges.herokuapp.com/maven-central/dev.inmo/tgbotapi/badge.svg)](https://maven-badges.herokuapp.com/maven-central/dev.inmo/tgbotapi) [![Supported version](https://img.shields.io/badge/Telegram%20Bot%20API-9.0-blue)](https://core.telegram.org/bots/api-changelog#april-11-2025)
# TelegramBotAPI [![Maven Central Version](https://img.shields.io/maven-central/v/dev.inmo/tgbotapi)](https://maven-badges.herokuapp.com/maven-central/dev.inmo/tgbotapi) [![Supported version](https://img.shields.io/badge/Telegram%20Bot%20API-9.0-blue)](https://core.telegram.org/bots/api-changelog#april-11-2025)
| Docs | [![KDocs](https://img.shields.io/static/v1?label=Dokka&message=KDocs&color=blue&logo=kotlin)](https://tgbotapi.inmo.dev/index.html) [![Mini tutorial](https://img.shields.io/static/v1?label=Mk&message=Docs&color=blue&logo=mkdocs)](https://docs.inmo.dev/tgbotapi/index.html) |
|:----------------------:|:-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------:|

View File

@@ -38,9 +38,9 @@ if ((project.hasProperty('SONATYPE_USER') || System.getenv('SONATYPE_USER') != n
// temporal crutch until legacy tests will be stabled or legacy target will be removed
allprojects {
repositories {
maven { url "https://nexus.inmo.dev/repository/maven-releases/" }
mavenCentral()
google()
maven { url "https://nexus.inmo.dev/repository/maven-releases/" }
mavenLocal()
}
if (it != rootProject.findProject("docs")) {

View File

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

View File

@@ -217,7 +217,7 @@ fun <T, BC : BehaviourContext> BC.launchInNewSubContext(
updatesUpstreamFlow = updatesUpstreamFlow,
subcontextInitialAction = subcontextInitialAction
).apply {
this@apply.launchLoggingDropExceptions(logger = Log ?: KSLog) {
this@apply.launchLoggingDropExceptions(logger = Log) {
behaviourContextReceiver()
}
}.coroutineContext.job

View File

@@ -40,7 +40,7 @@ class CombinedSubcontextInitialAction(
runCatching {
invoke(update)
}.onFailure {
(Log ?: logger).error(it) {
Log.error(it) {
"Unable to execute $subaction for update $update. Will try on next round"
}
}.onSuccess {
@@ -50,7 +50,7 @@ class CombinedSubcontextInitialAction(
}
leftSubActions.removeAll(successSubActions)
if (successSubActions.isEmpty()) {
(Log ?: logger).error {
Log.error {
"Some SubActions have been unable to complete successfully:${leftSubActions.joinToString("\n") { it.toString() }}"
}
break

View File

@@ -58,13 +58,16 @@ fun <T> FlowsUpdatesFilter.expectFlow(
result.getOrThrow()
}
}.flatten()
return flow {
initRequest ?.also {
return if (initRequest == null) {
flow
} else {
flow {
runCatching {
bot.execute(initRequest)
}
flow.collect(this)
}
emitAll(flow)
}
}

View File

@@ -27,3 +27,12 @@ interface TextedOutput : ParsableOutput, EntitiesOutput
interface TextedInput : TextedWithTextSources {
override val textSources: List<TextSource>
}
interface TitledInput : TextedInput {
val title: String
val titleTextSources: List<TextSource>
override val text: String
get() = title
override val textSources: List<TextSource>
get() = titleTextSources
}

View File

@@ -2,6 +2,7 @@ package dev.inmo.tgbotapi.bot
import dev.inmo.kslog.common.KSLog
import dev.inmo.tgbotapi.requests.abstracts.Request
import dev.inmo.tgbotapi.utils.DefaultKTgBotAPIKSLog
import io.ktor.utils.io.core.Closeable
/**
@@ -12,8 +13,8 @@ import io.ktor.utils.io.core.Closeable
* @see dev.inmo.tgbotapi.bot.Ktor.KtorRequestsExecutor
*/
interface RequestsExecutor : Closeable {
val Log: KSLog?
get() = null
val Log: KSLog
get() = DefaultKTgBotAPIKSLog
/**
* Unsafe execution of incoming [request]. Can throw almost any exception. So, it is better to use
* something like [dev.inmo.tgbotapi.extensions.utils.shortcuts.executeAsync] or

View File

@@ -29,7 +29,7 @@ expect class KtorRequestsExecutor internal constructor(
logger: KSLog,
diff: Unit // just a diff property to know where constructor and where calling function with defaults
) : BaseRequestsExecutor {
override val Log: KSLog?
override val Log: KSLog
override suspend fun <T : Any> execute(request: Request<T>): T
override fun close()
}

View File

@@ -30,7 +30,7 @@ class DefaultKtorRequestsExecutor internal constructor(
private val logger: KSLog,
diff: Unit
) : BaseRequestsExecutor(telegramAPIUrlsKeeper) {
override val Log: KSLog? = logger
override val Log: KSLog = logger
private val callsFactories: List<KtorCallFactory> = callsFactories.run {
if (!excludeDefaultFactories) {
this@DefaultKtorRequestsExecutor.logger.v { "Installing default factories" }

View File

@@ -49,7 +49,7 @@ class MultipleClientKtorRequestsExecutor(
logger: KSLog,
clientFactory: () -> HttpClient,
) : BaseRequestsExecutor(telegramAPIUrlsKeeper) {
override val Log: KSLog? = logger
override val Log: KSLog = logger
private val requestExecutors = (0 until requestExecutorsCount).map {
DefaultKtorRequestsExecutor(
telegramAPIUrlsKeeper,

View File

@@ -6,6 +6,7 @@ import dev.inmo.tgbotapi.bot.ktor.telegramBot
import dev.inmo.tgbotapi.bot.RequestsExecutor
import dev.inmo.tgbotapi.bot.TelegramBot
import dev.inmo.tgbotapi.requests.abstracts.Request
import dev.inmo.tgbotapi.utils.DefaultKTgBotAPIKSLog
import dev.inmo.tgbotapi.utils.TelegramAPIUrlsKeeper
import kotlinx.coroutines.*
import kotlin.js.JsName
@@ -30,8 +31,8 @@ class SimpleMultiServerRequestsExecutor(
bots.forEach(TelegramBot::close)
}
) : RequestsExecutor {
override val Log: KSLog?
get() = bots.firstNotNullOfOrNull { it.Log }
override val Log: KSLog
get() = bots.firstNotNullOfOrNull { it.Log } ?: DefaultKTgBotAPIKSLog
override suspend fun <T : Any> execute(request: Request<T>): T {
var currentBot = bots.botSelector(-1, null)
while (currentCoroutineContext().isActive) {

View File

@@ -0,0 +1,75 @@
package dev.inmo.tgbotapi.requests.send
import dev.inmo.tgbotapi.abstracts.types.AllowPaidBroadcast
import dev.inmo.tgbotapi.abstracts.types.DisableNotification
import dev.inmo.tgbotapi.abstracts.types.OptionallyWithEffectId
import dev.inmo.tgbotapi.abstracts.types.ProtectContent
import dev.inmo.tgbotapi.abstracts.types.WithBusinessConnectionId
import dev.inmo.tgbotapi.abstracts.types.WithReplyMarkup
import dev.inmo.tgbotapi.abstracts.types.WithReplyParameters
import dev.inmo.tgbotapi.requests.send.abstracts.OptionallyMessageThreadRequest
import dev.inmo.tgbotapi.requests.send.abstracts.SendChatMessageRequest
import dev.inmo.tgbotapi.requests.send.abstracts.SendContentMessageRequest
import dev.inmo.tgbotapi.types.*
import dev.inmo.tgbotapi.types.business_connection.BusinessConnectionId
import dev.inmo.tgbotapi.types.buttons.KeyboardMarkup
import dev.inmo.tgbotapi.types.checklists.Checklist
import dev.inmo.tgbotapi.types.message.abstracts.ContentMessage
import dev.inmo.tgbotapi.types.message.abstracts.TelegramBotAPIMessageDeserializationStrategyClass
import dev.inmo.tgbotapi.types.message.content.ChecklistContent
import dev.inmo.tgbotapi.types.message.content.GameContent
import kotlinx.serialization.*
private val commonResultDeserializer: DeserializationStrategy<ContentMessage<ChecklistContent>>
= TelegramBotAPIMessageDeserializationStrategyClass()
@Serializable
data class SendChecklist (
@SerialName(chatIdField)
override val chatId: ChatIdentifier,
@SerialName(checklistField)
val checklist: Checklist.Input,
@SerialName(businessConnectionIdField)
override val businessConnectionId: BusinessConnectionId,
@SerialName(disableNotificationField)
override val disableNotification: Boolean = false,
@SerialName(protectContentField)
override val protectContent: Boolean = false,
@SerialName(messageEffectIdField)
override val effectId: EffectId? = null,
@SerialName(replyParametersField)
override val replyParameters: ReplyParameters? = null,
@SerialName(replyMarkupField)
override val replyMarkup: KeyboardMarkup? = null
) : SendChatMessageRequest<ContentMessage<ChecklistContent>>,
WithReplyParameters,
DisableNotification,
ProtectContent,
OptionallyWithEffectId,
WithBusinessConnectionId,
WithReplyMarkup {
constructor(
chatId: BusinessChatId,
checklist: Checklist.Input,
disableNotification: Boolean = false,
protectContent: Boolean = false,
effectId: EffectId? = null,
replyParameters: ReplyParameters? = null,
replyMarkup: KeyboardMarkup? = null
) : this(
chatId = chatId,
checklist = checklist,
businessConnectionId = chatId.businessConnectionId,
disableNotification = disableNotification,
protectContent = protectContent,
effectId = effectId,
replyParameters = replyParameters,
replyMarkup = replyMarkup
)
override fun method(): String = "sendChecklist"
override val resultDeserializer: DeserializationStrategy<ContentMessage<ChecklistContent>>
get() = commonResultDeserializer
override val requestSerializer: SerializationStrategy<*>
get() = serializer()
}

View File

@@ -308,6 +308,13 @@ const val pendingJoinRequestCountField = "pending_join_request_count"
const val memberLimitField = "member_limit"
const val iconColorField = "icon_color"
const val emojiListField = "emoji_list"
const val completedByUserField = "completed_by_user"
const val completionDateField = "completion_date"
const val titleEntitiesField = "title_entities"
const val tasksField = "tasks"
const val othersCanAddTasksField = "others_can_add_tasks"
const val othersCanMarkTasksAsDoneField = "others_can_mark_tasks_as_done"
const val checklistField = "checklist"
const val requestContactField = "request_contact"
const val requestLocationField = "request_location"

View File

@@ -0,0 +1,181 @@
package dev.inmo.tgbotapi.types.checklists
import dev.inmo.micro_utils.common.Warning
import dev.inmo.tgbotapi.abstracts.TitledInput
import dev.inmo.tgbotapi.types.checklists.ChecklistTask.Input
import dev.inmo.tgbotapi.types.message.ParseMode
import dev.inmo.tgbotapi.types.message.RawMessageEntity
import dev.inmo.tgbotapi.types.message.asTextSources
import dev.inmo.tgbotapi.types.message.parseModeField
import dev.inmo.tgbotapi.types.message.textsources.TextSource
import dev.inmo.tgbotapi.types.message.toRawMessageEntities
import dev.inmo.tgbotapi.types.othersCanAddTasksField
import dev.inmo.tgbotapi.types.othersCanMarkTasksAsDoneField
import dev.inmo.tgbotapi.types.tasksField
import dev.inmo.tgbotapi.types.titleEntitiesField
import dev.inmo.tgbotapi.types.titleField
import dev.inmo.tgbotapi.utils.EntitiesBuilder
import dev.inmo.tgbotapi.utils.EntitiesBuilderBody
import dev.inmo.tgbotapi.utils.extensions.makeSourceString
import kotlinx.serialization.KSerializer
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
import kotlinx.serialization.descriptors.SerialDescriptor
import kotlinx.serialization.encoding.Decoder
import kotlinx.serialization.encoding.Encoder
@Serializable
sealed interface Checklist : TitledInput {
val tasks: List<ChecklistTask>
val othersCanAddTasks: Boolean
val othersCanCompleteTasks: Boolean
@Serializable
data class Input @Warning("It is low level API. Do not use it without need") constructor(
@SerialName(titleField)
override val title: String,
@SerialName(tasksField)
override val tasks: List<ChecklistTask.Input>,
@SerialName(parseModeField)
val parseMode: ParseMode? = null,
@SerialName(titleEntitiesField)
override val titleTextSources: List<TextSource> = emptyList(),
@SerialName(othersCanAddTasksField)
override val othersCanAddTasks: Boolean = false,
@SerialName(othersCanMarkTasksAsDoneField)
override val othersCanCompleteTasks: Boolean = false,
) : Checklist {
constructor(
text: String,
tasks: List<ChecklistTask.Input>,
parseMode: ParseMode? = null,
othersCanAddTasks: Boolean = false,
othersCanCompleteTasks: Boolean = false,
) : this(
title = text,
parseMode = parseMode,
titleTextSources = emptyList(),
tasks = tasks,
othersCanAddTasks = othersCanAddTasks,
othersCanCompleteTasks = othersCanCompleteTasks
)
constructor(
titleTextSources: List<TextSource>,
tasks: List<ChecklistTask.Input>,
othersCanAddTasks: Boolean = false,
othersCanCompleteTasks: Boolean = false,
) : this(
title = titleTextSources.makeSourceString(),
parseMode = null,
titleTextSources = titleTextSources,
tasks = tasks,
othersCanAddTasks = othersCanAddTasks,
othersCanCompleteTasks = othersCanCompleteTasks
)
constructor(
tasks: List<ChecklistTask.Input>,
othersCanAddTasks: Boolean = false,
othersCanCompleteTasks: Boolean = false,
builderBody: EntitiesBuilderBody
) : this(
titleTextSources = EntitiesBuilder().apply(builderBody).build(),
tasks = tasks,
othersCanAddTasks = othersCanAddTasks,
othersCanCompleteTasks = othersCanCompleteTasks
)
companion object : KSerializer<Input> {
@Serializable
private class RawChecklist(
val title: String,
val parseMode: ParseMode? = null,
val title_entities: List<RawMessageEntity> = emptyList(),
val tasks: List<ChecklistTask.Input>,
val others_can_add_tasks: Boolean = false,
val others_can_mark_tasks_as_done: Boolean = false,
)
override val descriptor: SerialDescriptor = RawChecklist.serializer().descriptor
override fun serialize(
encoder: Encoder,
value: Input
) {
RawChecklist.serializer().serialize(
encoder,
RawChecklist(
title = value.title,
title_entities = value.titleTextSources.toRawMessageEntities(),
tasks = value.tasks,
parseMode = value.parseMode,
others_can_add_tasks = value.othersCanAddTasks,
others_can_mark_tasks_as_done = value.othersCanCompleteTasks,
)
)
}
override fun deserialize(decoder: Decoder): Input {
val raw = RawChecklist.serializer().deserialize(decoder)
return Input(
title = raw.title,
titleTextSources = raw.title_entities.asTextSources(raw.title),
tasks = raw.tasks,
parseMode = raw.parseMode,
othersCanAddTasks = raw.others_can_add_tasks,
othersCanCompleteTasks = raw.others_can_mark_tasks_as_done
)
}
}
}
@Serializable(Created.Companion::class)
data class Created(
override val titleTextSources: List<TextSource>,
@SerialName(tasksField)
override val tasks: List<ChecklistTask.Created>,
@SerialName(othersCanAddTasksField)
override val othersCanAddTasks: Boolean = false,
@SerialName(othersCanMarkTasksAsDoneField)
override val othersCanCompleteTasks: Boolean = false,
): Checklist {
override val title: String by lazy {
titleTextSources.makeSourceString()
}
companion object : KSerializer<Created> {
@Serializable
private class RawChecklist(
val title: String,
val title_entities: List<RawMessageEntity> = emptyList(),
val tasks: List<ChecklistTask.Created>,
val others_can_add_tasks: Boolean = false,
val others_can_mark_tasks_as_done: Boolean = false,
)
override val descriptor: SerialDescriptor = RawChecklist.serializer().descriptor
override fun serialize(
encoder: Encoder,
value: Created
) {
RawChecklist.serializer().serialize(
encoder,
RawChecklist(
title = value.title,
title_entities = value.titleTextSources.toRawMessageEntities(),
tasks = value.tasks,
others_can_add_tasks = value.othersCanAddTasks,
others_can_mark_tasks_as_done = value.othersCanCompleteTasks,
)
)
}
override fun deserialize(decoder: Decoder): Created {
val raw = RawChecklist.serializer().deserialize(decoder)
return Created(
titleTextSources = raw.title_entities.asTextSources(raw.title),
tasks = raw.tasks,
othersCanAddTasks = raw.others_can_add_tasks,
othersCanCompleteTasks = raw.others_can_mark_tasks_as_done
)
}
}
}
}

View File

@@ -0,0 +1,219 @@
package dev.inmo.tgbotapi.types.checklists
import dev.inmo.micro_utils.common.Warning
import dev.inmo.tgbotapi.abstracts.TextedInput
import dev.inmo.tgbotapi.abstracts.TitledInput
import dev.inmo.tgbotapi.types.TelegramDate
import dev.inmo.tgbotapi.types.chat.PreviewUser
import dev.inmo.tgbotapi.types.completedByUserField
import dev.inmo.tgbotapi.types.completionDateField
import dev.inmo.tgbotapi.types.idField
import dev.inmo.tgbotapi.types.message.ParseMode
import dev.inmo.tgbotapi.types.message.RawMessageEntity
import dev.inmo.tgbotapi.types.message.asTextSources
import dev.inmo.tgbotapi.types.message.parseModeField
import dev.inmo.tgbotapi.types.message.textsources.RegularTextSource
import dev.inmo.tgbotapi.types.message.textsources.TextSource
import dev.inmo.tgbotapi.types.message.toRawMessageEntities
import dev.inmo.tgbotapi.types.tasksField
import dev.inmo.tgbotapi.types.textEntitiesField
import dev.inmo.tgbotapi.types.textField
import dev.inmo.tgbotapi.types.textParseModeField
import dev.inmo.tgbotapi.types.titleEntitiesField
import dev.inmo.tgbotapi.types.titleField
import dev.inmo.tgbotapi.utils.EntitiesBuilder
import dev.inmo.tgbotapi.utils.EntitiesBuilderBody
import dev.inmo.tgbotapi.utils.RiskFeature
import dev.inmo.tgbotapi.utils.extensions.makeSourceString
import kotlinx.serialization.EncodeDefault
import kotlinx.serialization.ExperimentalSerializationApi
import kotlinx.serialization.KSerializer
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
import kotlinx.serialization.descriptors.SerialDescriptor
import kotlinx.serialization.encoding.Decoder
import kotlinx.serialization.encoding.Encoder
@Serializable
sealed interface ChecklistTask : TextedInput {
val id: ChecklistTaskId
override val text: String
@Serializable(Input.Companion::class)
data class Input @Warning("It is low level API. Do not use it without need") constructor(
@SerialName(idField)
override val id: ChecklistTaskId,
@SerialName(textField)
override val text: String,
@SerialName(textParseModeField)
val parseMode: ParseMode? = null,
@SerialName(textEntitiesField)
override val textSources: List<TextSource> = emptyList(),
) : ChecklistTask {
constructor(id: ChecklistTaskId, text: String, parseMode: ParseMode? = null) : this(
id = id,
text = text,
parseMode = parseMode,
textSources = emptyList()
)
constructor(id: ChecklistTaskId, textSources: List<TextSource>) : this(
id = id,
text = textSources.makeSourceString(),
parseMode = null,
textSources = textSources
)
constructor(id: ChecklistTaskId, builderBody: EntitiesBuilderBody) : this(
id = id,
textSources = EntitiesBuilder().apply(builderBody).build()
)
companion object : KSerializer<Input> {
@Serializable
private data class RawInput(
@SerialName(idField)
val id: ChecklistTaskId,
@SerialName(textField)
val text: String,
@SerialName(textParseModeField)
val parseMode: ParseMode? = null,
@SerialName(textEntitiesField)
val textSources: List<RawMessageEntity> = emptyList(),
)
override val descriptor: SerialDescriptor
get() = RawInput.serializer().descriptor
override fun deserialize(decoder: Decoder): Input {
val raw = RawInput.serializer().deserialize(decoder)
return Input(
raw.id,
raw.text,
raw.parseMode,
raw.textSources.asTextSources(raw.text)
)
}
override fun serialize(encoder: Encoder, value: Input) {
RawInput.serializer().serialize(
encoder,
RawInput(
value.id,
value.text,
value.parseMode,
value.textSources.toRawMessageEntities()
)
)
}
}
}
@Serializable(Created.Serializer::class)
data class Undone(
@SerialName(idField)
override val id: ChecklistTaskId,
@SerialName(textEntitiesField)
override val textSources: List<TextSource> = emptyList(),
) : ChecklistTask.Created {
@OptIn(ExperimentalSerializationApi::class)
@EncodeDefault
@Serializable
@SerialName(textField)
override val text: String = textSources.makeSourceString()
constructor(id: ChecklistTaskId, text: String): this(
id,
listOf(
RegularTextSource(text)
)
)
}
@Serializable(Created.Serializer::class)
data class Done(
@SerialName(idField)
override val id: ChecklistTaskId,
@SerialName(completedByUserField)
override val completedByUser: PreviewUser,
@SerialName(completionDateField)
override val completionDate: TelegramDate,
@SerialName(textEntitiesField)
override val textSources: List<TextSource> = emptyList()
) : ChecklistTask.Created {
@OptIn(ExperimentalSerializationApi::class)
@EncodeDefault
@Serializable
@SerialName(textField)
override val text: String = textSources.makeSourceString()
constructor(
id: ChecklistTaskId,
text: String,
completedByUser: PreviewUser,
completionDate: TelegramDate,
): this(
id,
completedByUser,
completionDate,
listOf(
RegularTextSource(text)
)
)
}
@Serializable(Created.Serializer::class)
sealed interface Created : ChecklistTask {
val completedByUser: PreviewUser?
get() = null
val completionDate: TelegramDate?
get() = null
@RiskFeature
object Serializer : KSerializer<Created> {
@Serializable
private data class RawCreatedChecklistTask(
@SerialName(idField)
val id: ChecklistTaskId,
@SerialName(textField)
val text: String,
@SerialName(textEntitiesField)
val textSources: List<RawMessageEntity> = emptyList(),
@SerialName(completedByUserField)
val completedByUser: PreviewUser? = null,
@SerialName(completionDateField)
val completionDate: TelegramDate = TelegramDate(0), // TelegramDate(0) is the default according to https://core.telegram.org/bots/api#checklisttask
)
override val descriptor: SerialDescriptor = RawCreatedChecklistTask.serializer().descriptor
override fun deserialize(decoder: Decoder): Created {
val raw = RawCreatedChecklistTask.serializer().deserialize(
decoder
)
return when {
raw.completedByUser != null -> Done(
id = raw.id,
completedByUser = raw.completedByUser,
completionDate = raw.completionDate,
textSources = raw.textSources.asTextSources(raw.text),
)
else -> Undone(
id = raw.id,
textSources = raw.textSources.asTextSources(raw.text),
)
}
}
override fun serialize(encoder: Encoder, value: Created) {
RawCreatedChecklistTask.serializer().serialize(
encoder,
RawCreatedChecklistTask(
id = value.id,
text = value.text,
completedByUser = value.completedByUser,
completionDate = value.completionDate ?: TelegramDate(0),
textSources = value.textSources.toRawMessageEntities()
)
)
}
}
}
}

View File

@@ -0,0 +1,10 @@
package dev.inmo.tgbotapi.types.checklists
import kotlinx.serialization.Serializable
import kotlin.jvm.JvmInline
@Serializable
@JvmInline
value class ChecklistTaskId(
val int: UInt
)

View File

@@ -0,0 +1,15 @@
package dev.inmo.tgbotapi.types.checklists
import dev.inmo.micro_utils.common.Warning
import dev.inmo.tgbotapi.abstracts.TextedInput
import dev.inmo.tgbotapi.abstracts.TitledInput
import dev.inmo.tgbotapi.types.message.ParseMode
import dev.inmo.tgbotapi.types.message.parseModeField
import dev.inmo.tgbotapi.types.message.textsources.TextSource
import dev.inmo.tgbotapi.types.tasksField
import dev.inmo.tgbotapi.types.titleEntitiesField
import dev.inmo.tgbotapi.types.titleField
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable

View File

@@ -165,6 +165,10 @@ internal data class RawMessage(
private val giveaway_winners: GiveawayPublicResults? = null,
private val giveaway_completed: GiveawayPrivateResults? = null,
// Checklists
private val checklist_tasks_done: Nothing,
private val checklist_tasks_added: Nothing,
// Gifts
private val gift: GiftSentOrReceived.Regular? = null,
private val unique_gift: GiftSentOrReceived.Unique? = null,

View File

@@ -0,0 +1,32 @@
package dev.inmo.tgbotapi.types.message.content
import dev.inmo.tgbotapi.requests.abstracts.Request
import dev.inmo.tgbotapi.types.ChatIdentifier
import dev.inmo.tgbotapi.types.EffectId
import dev.inmo.tgbotapi.types.MessageThreadId
import dev.inmo.tgbotapi.types.ReplyParameters
import dev.inmo.tgbotapi.types.business_connection.BusinessConnectionId
import dev.inmo.tgbotapi.types.buttons.KeyboardMarkup
import dev.inmo.tgbotapi.types.checklists.Checklist
import dev.inmo.tgbotapi.types.message.abstracts.AccessibleMessage
import dev.inmo.tgbotapi.types.message.abstracts.CommonMessage
import kotlinx.serialization.Serializable
@Serializable
data class ChecklistContent(
val checklist: Checklist
) : MessageContent {
override fun createResend(
chatId: ChatIdentifier,
messageThreadId: MessageThreadId?,
businessConnectionId: BusinessConnectionId?,
disableNotification: Boolean,
protectContent: Boolean,
allowPaidBroadcast: Boolean,
effectId: EffectId?,
replyParameters: ReplyParameters?,
replyMarkup: KeyboardMarkup?
): Request<CommonMessage<ChecklistContent>> {
return SendChecklist
}
}

View File

@@ -12,7 +12,56 @@ import dev.inmo.tgbotapi.types.message.textsources.*
typealias EntitiesBuilderBody = EntitiesBuilder.() -> Unit
val newLine = regularTextSource("\n")
/**
* Documentation: [DSL text](https://docs.inmo.dev/tgbotapi/dsls/text.html)
*
* Example: [PollsBot](https://github.com/InsanusMokrassar/TelegramBotAPI-examples/blob/master/PollsBot/src/main/kotlin/PollsBot.kt)
*
* @see dev.inmo.tgbotapi.utils.bold
* @see dev.inmo.tgbotapi.utils.blockquote
* @see dev.inmo.tgbotapi.utils.expandableBlockquote
* @see dev.inmo.tgbotapi.utils.spoiler
* @see dev.inmo.tgbotapi.utils.botCommand
* @see dev.inmo.tgbotapi.utils.cashTag
* @see dev.inmo.tgbotapi.utils.code
* @see dev.inmo.tgbotapi.utils.email
* @see dev.inmo.tgbotapi.utils.hashtag
* @see dev.inmo.tgbotapi.utils.italic
* @see dev.inmo.tgbotapi.utils.mention
* @see dev.inmo.tgbotapi.utils.phone
* @see dev.inmo.tgbotapi.utils.pre
* @see dev.inmo.tgbotapi.utils.regular
* @see dev.inmo.tgbotapi.utils.strikethrough
* @see dev.inmo.tgbotapi.utils.link
* @see dev.inmo.tgbotapi.utils.underline
* @see dev.inmo.tgbotapi.utils.customEmoji
*/
inline fun buildEntities(separator: TextSource? = null, init: EntitiesBuilderBody): TextSourcesList = EntitiesBuilder(separator).apply(init).build()
/**
* Documentation: [DSL text](https://docs.inmo.dev/tgbotapi/dsls/text.html)
*
* Example: [PollsBot](https://github.com/InsanusMokrassar/TelegramBotAPI-examples/blob/master/PollsBot/src/main/kotlin/PollsBot.kt)
*
* @see dev.inmo.tgbotapi.utils.bold
* @see dev.inmo.tgbotapi.utils.blockquote
* @see dev.inmo.tgbotapi.utils.expandableBlockquote
* @see dev.inmo.tgbotapi.utils.spoiler
* @see dev.inmo.tgbotapi.utils.botCommand
* @see dev.inmo.tgbotapi.utils.cashTag
* @see dev.inmo.tgbotapi.utils.code
* @see dev.inmo.tgbotapi.utils.email
* @see dev.inmo.tgbotapi.utils.hashtag
* @see dev.inmo.tgbotapi.utils.italic
* @see dev.inmo.tgbotapi.utils.mention
* @see dev.inmo.tgbotapi.utils.phone
* @see dev.inmo.tgbotapi.utils.pre
* @see dev.inmo.tgbotapi.utils.regular
* @see dev.inmo.tgbotapi.utils.strikethrough
* @see dev.inmo.tgbotapi.utils.link
* @see dev.inmo.tgbotapi.utils.underline
* @see dev.inmo.tgbotapi.utils.customEmoji
*/
inline fun buildEntities(separator: String, init: EntitiesBuilderBody) = buildEntities(regularTextSource(separator), init)
/**

View File

@@ -3609,20 +3609,21 @@ public final class dev/inmo/tgbotapi/extensions/utils/updates/retrieving/LongPol
}
public final class dev/inmo/tgbotapi/extensions/utils/updates/retrieving/MediaGroupsIncluderKt {
public static final fun updateHandlerWithMediaGroupsAdaptation (Lkotlinx/coroutines/CoroutineScope;Lkotlin/jvm/functions/Function2;)Lkotlin/jvm/functions/Function2;
public static final fun updateHandlerWithMediaGroupsAdaptation (Lkotlinx/coroutines/CoroutineScope;Lkotlin/jvm/functions/Function2;J)Lkotlin/jvm/functions/Function2;
public static synthetic fun updateHandlerWithMediaGroupsAdaptation$default (Lkotlinx/coroutines/CoroutineScope;Lkotlin/jvm/functions/Function2;JILjava/lang/Object;)Lkotlin/jvm/functions/Function2;
public static final fun updateHandlerWithMediaGroupsAdaptation (Lkotlinx/coroutines/CoroutineScope;Ldev/inmo/kslog/common/KSLog;Lkotlin/jvm/functions/Function2;)Lkotlin/jvm/functions/Function2;
public static final fun updateHandlerWithMediaGroupsAdaptation (Lkotlinx/coroutines/CoroutineScope;Lkotlin/jvm/functions/Function2;JLdev/inmo/kslog/common/KSLog;)Lkotlin/jvm/functions/Function2;
public static synthetic fun updateHandlerWithMediaGroupsAdaptation$default (Lkotlinx/coroutines/CoroutineScope;Ldev/inmo/kslog/common/KSLog;Lkotlin/jvm/functions/Function2;ILjava/lang/Object;)Lkotlin/jvm/functions/Function2;
public static synthetic fun updateHandlerWithMediaGroupsAdaptation$default (Lkotlinx/coroutines/CoroutineScope;Lkotlin/jvm/functions/Function2;JLdev/inmo/kslog/common/KSLog;ILjava/lang/Object;)Lkotlin/jvm/functions/Function2;
}
public final class dev/inmo/tgbotapi/extensions/utils/updates/retrieving/WebhookKt {
public static final fun includeWebhookHandlingInRoute (Lio/ktor/server/routing/Route;Lkotlinx/coroutines/CoroutineScope;Lkotlin/jvm/functions/Function2;JLkotlin/jvm/functions/Function2;)V
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/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 static final fun includeWebhookHandlingInRoute (Lio/ktor/server/routing/Route;Lkotlinx/coroutines/CoroutineScope;Lkotlin/jvm/functions/Function2;JLdev/inmo/kslog/common/KSLog;Lkotlin/jvm/functions/Function2;)V
public static synthetic fun includeWebhookHandlingInRoute$default (Lio/ktor/server/routing/Route;Lkotlinx/coroutines/CoroutineScope;Lkotlin/jvm/functions/Function2;JLdev/inmo/kslog/common/KSLog;Lkotlin/jvm/functions/Function2;ILjava/lang/Object;)V
public static final fun includeWebhookHandlingInRouteWithFlows (Lio/ktor/server/routing/Route;Lkotlinx/coroutines/CoroutineScope;Lkotlin/jvm/functions/Function2;JLdev/inmo/kslog/common/KSLog;Lkotlin/jvm/functions/Function1;)V
public static synthetic fun includeWebhookHandlingInRouteWithFlows$default (Lio/ktor/server/routing/Route;Lkotlinx/coroutines/CoroutineScope;Lkotlin/jvm/functions/Function2;JLdev/inmo/kslog/common/KSLog;Lkotlin/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/Function1;Ldev/inmo/kslog/common/KSLog;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;Ldev/inmo/kslog/common/KSLog;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;Ldev/inmo/kslog/common/KSLog;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;Ldev/inmo/kslog/common/KSLog;Lkotlin/jvm/functions/Function2;ILjava/lang/Object;)Lio/ktor/server/engine/EmbeddedServer;
}
public final class dev/inmo/tgbotapi/types/files/PathedFileAsStreamKt {

View File

@@ -14,6 +14,7 @@ import dev.inmo.tgbotapi.types.update.*
import dev.inmo.tgbotapi.types.update.abstracts.BaseSentMessageUpdate
import dev.inmo.tgbotapi.types.update.abstracts.Update
import dev.inmo.tgbotapi.updateshandlers.*
import dev.inmo.tgbotapi.utils.DefaultKTgBotAPIKSLog
import io.ktor.client.plugins.HttpRequestTimeoutException
import io.ktor.utils.io.CancellationException
import kotlinx.coroutines.*
@@ -33,20 +34,20 @@ fun TelegramBot.longPollingFlow(
mediaGroupsDebounceTimeMillis: Long? = 1000L,
): Flow<Update> = channelFlow {
if (autoDisableWebhooks) {
runCatching {
runCatchingLogging(logger = Log) {
execute(DeleteWebhook())
}
}
val contextSafelyExceptionHandler = coroutineContext[ContextSafelyExceptionHandlerKey]
val contextToWork = if (contextSafelyExceptionHandler == null || !autoSkipTimeoutExceptions) {
val contextSafelyExceptionHandler = coroutineContext[ContextSafelyExceptionHandlerKey] ?.handler ?: defaultSafelyExceptionHandler
val contextToWork = if (!autoSkipTimeoutExceptions) {
coroutineContext
} else {
coroutineContext + ContextSafelyExceptionHandler { e ->
if (e is HttpRequestTimeoutException || (e is CommonBotException && e.cause is HttpRequestTimeoutException)) {
return@ContextSafelyExceptionHandler
} else {
contextSafelyExceptionHandler.handler(e)
contextSafelyExceptionHandler(e)
}
}
}
@@ -61,7 +62,8 @@ fun TelegramBot.longPollingFlow(
send(it)
}
},
mediaGroupsDebounceTimeMillis
mediaGroupsDebounceTimeMillis,
logger = Log
);
{ originalUpdates: List<Update> ->
originalUpdates.forEach {

View File

@@ -1,11 +1,14 @@
package dev.inmo.tgbotapi.extensions.utils.updates.retrieving
import dev.inmo.kslog.common.KSLog
import dev.inmo.micro_utils.coroutines.launchLoggingDropExceptions
import dev.inmo.micro_utils.coroutines.launchSafelyWithoutExceptions
import dev.inmo.tgbotapi.extensions.utils.updates.convertWithMediaGroupUpdates
import dev.inmo.tgbotapi.types.message.abstracts.PossiblyMediaGroupMessage
import dev.inmo.tgbotapi.types.update.abstracts.BaseMessageUpdate
import dev.inmo.tgbotapi.types.update.abstracts.Update
import dev.inmo.tgbotapi.updateshandlers.UpdateReceiver
import dev.inmo.tgbotapi.utils.DefaultKTgBotAPIKSLog
import dev.inmo.tgbotapi.utils.extensions.accumulateByKey
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.channels.Channel
@@ -19,7 +22,8 @@ import kotlinx.coroutines.launch
*/
fun CoroutineScope.updateHandlerWithMediaGroupsAdaptation(
output: UpdateReceiver<Update>,
debounceTimeMillis: Long = 1000L
debounceTimeMillis: Long = 1000L,
logger: KSLog = DefaultKTgBotAPIKSLog
): UpdateReceiver<Update> {
val updatesChannel = Channel<Update>(Channel.UNLIMITED)
val mediaGroupChannel = Channel<Pair<String, BaseMessageUpdate>>(Channel.UNLIMITED)
@@ -29,7 +33,7 @@ fun CoroutineScope.updateHandlerWithMediaGroupsAdaptation(
)
launch {
launchSafelyWithoutExceptions {
launchLoggingDropExceptions(logger = logger) {
for (update in updatesChannel) {
val data = update.data
when {
@@ -40,7 +44,7 @@ fun CoroutineScope.updateHandlerWithMediaGroupsAdaptation(
}
}
}
launchSafelyWithoutExceptions {
launchLoggingDropExceptions(logger = logger) {
for ((_, mediaGroup) in mediaGroupAccumulatedChannel) {
mediaGroup.convertWithMediaGroupUpdates().forEach {
output(it)
@@ -59,5 +63,6 @@ fun CoroutineScope.updateHandlerWithMediaGroupsAdaptation(
* @see UpdateReceiver
*/
fun CoroutineScope.updateHandlerWithMediaGroupsAdaptation(
logger: KSLog = DefaultKTgBotAPIKSLog,
output: UpdateReceiver<Update>
) = updateHandlerWithMediaGroupsAdaptation(output, 1000L)
) = updateHandlerWithMediaGroupsAdaptation(output, 1000L, logger = logger)

View File

@@ -1,5 +1,6 @@
package dev.inmo.tgbotapi.extensions.utils.updates.retrieving
import dev.inmo.kslog.common.KSLog
import dev.inmo.micro_utils.coroutines.ExceptionHandler
import dev.inmo.micro_utils.coroutines.runCatchingSafely
import dev.inmo.tgbotapi.bot.RequestsExecutor
@@ -12,6 +13,7 @@ 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 dev.inmo.tgbotapi.utils.DefaultKTgBotAPIKSLog
import io.ktor.http.*
import io.ktor.server.engine.*
import io.ktor.server.request.*
@@ -40,9 +42,10 @@ fun Route.includeWebhookHandlingInRoute(
scope: CoroutineScope,
exceptionsHandler: ExceptionHandler<Unit>? = null,
mediaGroupsDebounceTimeMillis: Long = 1000L,
logger: KSLog = DefaultKTgBotAPIKSLog,
block: UpdateReceiver<Update>,
) {
val transformer = scope.updateHandlerWithMediaGroupsAdaptation(block, mediaGroupsDebounceTimeMillis)
val transformer = scope.updateHandlerWithMediaGroupsAdaptation(block, mediaGroupsDebounceTimeMillis, logger = logger)
post {
try {
runCatchingSafely {
@@ -71,11 +74,13 @@ fun Route.includeWebhookHandlingInRouteWithFlows(
scope: CoroutineScope,
exceptionsHandler: ExceptionHandler<Unit>? = null,
mediaGroupsDebounceTimeMillis: Long = 1000L,
logger: KSLog = DefaultKTgBotAPIKSLog,
block: FlowsUpdatesFilter.() -> Unit,
) = includeWebhookHandlingInRoute(
scope,
exceptionsHandler,
mediaGroupsDebounceTimeMillis,
logger,
flowsUpdatesFilter(block = block).asUpdateReceiver
)
@@ -105,6 +110,7 @@ fun <TEngine : ApplicationEngine, TConfiguration : ApplicationEngine.Configurati
mediaGroupsDebounceTimeMillis: Long = 1000L,
additionalApplicationEnvironmentConfigurator: ApplicationEnvironmentBuilder.() -> Unit = {},
additionalEngineConfigurator: TConfiguration.() -> Unit = {},
logger: KSLog = DefaultKTgBotAPIKSLog,
block: UpdateReceiver<Update>,
): EmbeddedServer<TEngine, TConfiguration> =
embeddedServer(
@@ -134,12 +140,19 @@ fun <TEngine : ApplicationEngine, TConfiguration : ApplicationEngine.Configurati
routing {
listenRoute?.also {
createRouteFromPath(it).includeWebhookHandlingInRoute(
scope,
exceptionsHandler,
mediaGroupsDebounceTimeMillis,
block
scope = scope,
exceptionsHandler = exceptionsHandler,
mediaGroupsDebounceTimeMillis = mediaGroupsDebounceTimeMillis,
logger = logger,
block = block
)
} ?: includeWebhookHandlingInRoute(scope, exceptionsHandler, mediaGroupsDebounceTimeMillis, block)
} ?: includeWebhookHandlingInRoute(
scope = scope,
exceptionsHandler = exceptionsHandler,
mediaGroupsDebounceTimeMillis = mediaGroupsDebounceTimeMillis,
logger = logger,
block = block
)
}
}
).also {
@@ -173,21 +186,23 @@ suspend fun <TEngine : ApplicationEngine, TConfiguration : ApplicationEngine.Con
mediaGroupsDebounceTimeMillis: Long = 1000L,
additionalApplicationEnvironmentConfigurator: ApplicationEnvironmentBuilder.() -> Unit = {},
additionalEngineConfigurator: TConfiguration.() -> Unit = {},
logger: KSLog = Log,
block: UpdateReceiver<Update>,
): EmbeddedServer<TEngine, TConfiguration> = try {
execute(setWebhookRequest)
startListenWebhooks(
listenPort,
engineFactory,
exceptionsHandler,
listenHost,
listenRoute,
privateKeyConfig,
scope,
mediaGroupsDebounceTimeMillis,
additionalApplicationEnvironmentConfigurator,
additionalEngineConfigurator,
block
listenPort = listenPort,
engineFactory = engineFactory,
exceptionsHandler = exceptionsHandler,
listenHost = listenHost,
listenRoute = listenRoute,
privateKeyConfig = privateKeyConfig,
scope = scope,
mediaGroupsDebounceTimeMillis = mediaGroupsDebounceTimeMillis,
additionalApplicationEnvironmentConfigurator = additionalApplicationEnvironmentConfigurator,
additionalEngineConfigurator = additionalEngineConfigurator,
logger = logger,
block = block
)
} catch (e: Exception) {
throw e