diff --git a/tgbotapi.api/api/tgbotapi.api.api b/tgbotapi.api/api/tgbotapi.api.api index e0fdfb6d8e..425d275756 100644 --- a/tgbotapi.api/api/tgbotapi.api.api +++ b/tgbotapi.api/api/tgbotapi.api.api @@ -1766,6 +1766,7 @@ public final class dev/inmo/tgbotapi/extensions/api/send/SendLiveLocationKt { } public final class dev/inmo/tgbotapi/extensions/api/send/SendMessageDraftKt { + public static final fun getGlobalDraftIdAllocator ()Ldev/inmo/tgbotapi/utils/DraftIdAllocator; public static final fun sendMessageDraft-85jglgs (Ldev/inmo/tgbotapi/bot/RequestsExecutor;Ldev/inmo/tgbotapi/types/IdChatIdentifier;JLjava/util/List;Ldev/inmo/tgbotapi/types/MessageThreadId;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; public static final fun sendMessageDraft-85jglgs (Ldev/inmo/tgbotapi/bot/RequestsExecutor;Ldev/inmo/tgbotapi/types/chat/Chat;JLjava/util/List;Ldev/inmo/tgbotapi/types/MessageThreadId;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; public static synthetic fun sendMessageDraft-85jglgs$default (Ldev/inmo/tgbotapi/bot/RequestsExecutor;Ldev/inmo/tgbotapi/types/IdChatIdentifier;JLjava/util/List;Ldev/inmo/tgbotapi/types/MessageThreadId;Lkotlin/coroutines/Continuation;ILjava/lang/Object;)Ljava/lang/Object; @@ -1782,10 +1783,12 @@ public final class dev/inmo/tgbotapi/extensions/api/send/SendMessageDraftKt { public static final fun sendMessageDraft-PjdzSgQ (Ldev/inmo/tgbotapi/bot/RequestsExecutor;Ldev/inmo/tgbotapi/types/chat/Chat;JLjava/lang/String;Ldev/inmo/tgbotapi/types/message/ParseMode;Ldev/inmo/tgbotapi/types/MessageThreadId;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; public static synthetic fun sendMessageDraft-PjdzSgQ$default (Ldev/inmo/tgbotapi/bot/RequestsExecutor;Ldev/inmo/tgbotapi/types/IdChatIdentifier;JLjava/lang/String;Ldev/inmo/tgbotapi/types/message/ParseMode;Ldev/inmo/tgbotapi/types/MessageThreadId;Lkotlin/coroutines/Continuation;ILjava/lang/Object;)Ljava/lang/Object; public static synthetic fun sendMessageDraft-PjdzSgQ$default (Ldev/inmo/tgbotapi/bot/RequestsExecutor;Ldev/inmo/tgbotapi/types/chat/Chat;JLjava/lang/String;Ldev/inmo/tgbotapi/types/message/ParseMode;Ldev/inmo/tgbotapi/types/MessageThreadId;Lkotlin/coroutines/Continuation;ILjava/lang/Object;)Ljava/lang/Object; - public static final fun sendMessageDraftFlow-85jglgs (Ldev/inmo/tgbotapi/bot/RequestsExecutor;Ldev/inmo/tgbotapi/types/IdChatIdentifier;JLkotlinx/coroutines/flow/Flow;Ldev/inmo/tgbotapi/types/MessageThreadId;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; - public static synthetic fun sendMessageDraftFlow-85jglgs$default (Ldev/inmo/tgbotapi/bot/RequestsExecutor;Ldev/inmo/tgbotapi/types/IdChatIdentifier;JLkotlinx/coroutines/flow/Flow;Ldev/inmo/tgbotapi/types/MessageThreadId;Lkotlin/coroutines/Continuation;ILjava/lang/Object;)Ljava/lang/Object; - public static final fun sendMessageDraftFlowWithTextAndParseMode (Ldev/inmo/tgbotapi/bot/RequestsExecutor;Ldev/inmo/tgbotapi/types/IdChatIdentifier;JLkotlinx/coroutines/flow/Flow;Ldev/inmo/tgbotapi/types/MessageThreadId;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; - public static synthetic fun sendMessageDraftFlowWithTextAndParseMode$default (Ldev/inmo/tgbotapi/bot/RequestsExecutor;Ldev/inmo/tgbotapi/types/IdChatIdentifier;JLkotlinx/coroutines/flow/Flow;Ldev/inmo/tgbotapi/types/MessageThreadId;Lkotlin/coroutines/Continuation;ILjava/lang/Object;)Ljava/lang/Object; + public static final fun sendMessageDraftFlow-lJCFx7I (Ldev/inmo/tgbotapi/bot/RequestsExecutor;Ldev/inmo/tgbotapi/types/IdChatIdentifier;Lkotlinx/coroutines/flow/Flow;Ldev/inmo/tgbotapi/types/MessageThreadId;Ldev/inmo/tgbotapi/types/DraftId;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; + public static synthetic fun sendMessageDraftFlow-lJCFx7I$default (Ldev/inmo/tgbotapi/bot/RequestsExecutor;Ldev/inmo/tgbotapi/types/IdChatIdentifier;Lkotlinx/coroutines/flow/Flow;Ldev/inmo/tgbotapi/types/MessageThreadId;Ldev/inmo/tgbotapi/types/DraftId;Lkotlin/coroutines/Continuation;ILjava/lang/Object;)Ljava/lang/Object; + public static final fun sendMessageDraftFlowWithText (Ldev/inmo/tgbotapi/bot/RequestsExecutor;Ldev/inmo/tgbotapi/types/IdChatIdentifier;Lkotlinx/coroutines/flow/Flow;Ldev/inmo/tgbotapi/types/MessageThreadId;Ldev/inmo/tgbotapi/types/DraftId;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; + public static synthetic fun sendMessageDraftFlowWithText$default (Ldev/inmo/tgbotapi/bot/RequestsExecutor;Ldev/inmo/tgbotapi/types/IdChatIdentifier;Lkotlinx/coroutines/flow/Flow;Ldev/inmo/tgbotapi/types/MessageThreadId;Ldev/inmo/tgbotapi/types/DraftId;Lkotlin/coroutines/Continuation;ILjava/lang/Object;)Ljava/lang/Object; + public static final fun sendMessageDraftFlowWithTextAndParseMode (Ldev/inmo/tgbotapi/bot/RequestsExecutor;Ldev/inmo/tgbotapi/types/IdChatIdentifier;Lkotlinx/coroutines/flow/Flow;Ldev/inmo/tgbotapi/types/MessageThreadId;Ldev/inmo/tgbotapi/types/DraftId;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; + public static synthetic fun sendMessageDraftFlowWithTextAndParseMode$default (Ldev/inmo/tgbotapi/bot/RequestsExecutor;Ldev/inmo/tgbotapi/types/IdChatIdentifier;Lkotlinx/coroutines/flow/Flow;Ldev/inmo/tgbotapi/types/MessageThreadId;Ldev/inmo/tgbotapi/types/DraftId;Lkotlin/coroutines/Continuation;ILjava/lang/Object;)Ljava/lang/Object; } public final class dev/inmo/tgbotapi/extensions/api/send/SendMessageKt { diff --git a/tgbotapi.api/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/api/send/SendMessageDraft.kt b/tgbotapi.api/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/api/send/SendMessageDraft.kt index 45ca757da9..ed0cb85cfd 100644 --- a/tgbotapi.api/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/api/send/SendMessageDraft.kt +++ b/tgbotapi.api/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/api/send/SendMessageDraft.kt @@ -8,17 +8,21 @@ import dev.inmo.tgbotapi.types.* import dev.inmo.tgbotapi.types.message.textsources.TextSourcesList import dev.inmo.tgbotapi.types.message.ParseMode import dev.inmo.tgbotapi.types.chat.Chat +import dev.inmo.tgbotapi.types.message.MarkdownV2 import dev.inmo.tgbotapi.types.message.abstracts.ContentMessage import dev.inmo.tgbotapi.types.message.content.TextContent import dev.inmo.tgbotapi.types.message.textsources.TextSource +import dev.inmo.tgbotapi.utils.DraftIdAllocator import dev.inmo.tgbotapi.utils.EntitiesBuilderBody import dev.inmo.tgbotapi.utils.buildEntities +import dev.inmo.tgbotapi.utils.extensions.escapeMarkdownV2Common import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.collect import kotlinx.coroutines.flow.filter import kotlinx.coroutines.flow.firstOrNull import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.takeWhile +import kotlinx.coroutines.sync.Mutex import kotlin.js.JsName import kotlin.jvm.JvmName @@ -56,12 +60,15 @@ private suspend fun TelegramBot.sendMessageDraftFlow( return done == null } +public val GlobalDraftIdAllocator: DraftIdAllocator by lazy { DraftIdAllocator() } + public suspend fun TelegramBot.sendMessageDraftFlow( chatId: IdChatIdentifier, - draftId: DraftId, messagesFlow: Flow, - threadId: MessageThreadId? = chatId.threadId + threadId: MessageThreadId? = chatId.threadId, + draftId: DraftId? = null, ): Boolean { + val draftId = draftId ?: GlobalDraftIdAllocator.allocate() return sendMessageDraftFlow( messagesFlow.map { SendMessageDraft(chatId = chatId, draftId = draftId, entities = it, threadId = threadId) @@ -73,10 +80,11 @@ public suspend fun TelegramBot.sendMessageDraftFlow( @JsName("sendMessageDraftFlowWithTextAndParseMode") public suspend fun TelegramBot.sendMessageDraftFlow( chatId: IdChatIdentifier, - draftId: DraftId, messagesFlow: Flow>, - threadId: MessageThreadId? = chatId.threadId + threadId: MessageThreadId? = chatId.threadId, + draftId: DraftId? = null, ): Boolean { + val draftId = draftId ?: GlobalDraftIdAllocator.allocate() return sendMessageDraftFlow( messagesFlow.map { SendMessageDraft(chatId = chatId, draftId = draftId, text = it.first, parseMode = it.second, threadId = threadId) @@ -84,6 +92,25 @@ public suspend fun TelegramBot.sendMessageDraftFlow( ) } +@JvmName("sendMessageDraftFlowWithText") +@JsName("sendMessageDraftFlowWithText") +public suspend fun TelegramBot.sendMessageDraftFlow( + chatId: IdChatIdentifier, + messagesFlow: Flow, + threadId: MessageThreadId? = chatId.threadId, + draftId: DraftId? = null, +): Boolean { + val draftId = draftId ?: GlobalDraftIdAllocator.allocate() + return sendMessageDraftFlow( + chatId = chatId, + messagesFlow = messagesFlow.map { + it.escapeMarkdownV2Common() to MarkdownV2 + }, + threadId = threadId, + draftId = draftId + ) +} + public suspend fun TelegramBot.sendMessageDraft( chat: Chat, draftId: DraftId, diff --git a/tgbotapi.core/api/tgbotapi.core.api b/tgbotapi.core/api/tgbotapi.core.api index 6665adb154..234c9410f0 100644 --- a/tgbotapi.core/api/tgbotapi.core.api +++ b/tgbotapi.core/api/tgbotapi.core.api @@ -32718,6 +32718,14 @@ public final class dev/inmo/tgbotapi/utils/DeserializeWithUnknownKt { public static final fun deserializeWithRaw (Lkotlinx/serialization/encoding/Decoder;Lkotlinx/serialization/KSerializer;)Lkotlin/Pair; } +public final class dev/inmo/tgbotapi/utils/DraftIdAllocator { + public fun ()V + public final fun allocate-2sDQ-Rg (Lkotlin/coroutines/Continuation;)Ljava/lang/Object; + public final fun free-NZs9fbA (JLkotlin/coroutines/Continuation;)Ljava/lang/Object; + public final fun getAllocated ()Ljava/util/Set; + public final fun getMutex ()Lkotlinx/coroutines/sync/Mutex; +} + public final class dev/inmo/tgbotapi/utils/EntitiesBuilder { public fun ()V public fun (Ldev/inmo/tgbotapi/types/message/textsources/TextSource;)V diff --git a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/utils/DraftIdAllocator.kt b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/utils/DraftIdAllocator.kt new file mode 100644 index 0000000000..5a2f4e5050 --- /dev/null +++ b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/utils/DraftIdAllocator.kt @@ -0,0 +1,25 @@ +package dev.inmo.tgbotapi.utils + +import dev.inmo.tgbotapi.types.DraftId +import kotlinx.coroutines.NonCancellable.isActive +import kotlinx.coroutines.sync.Mutex +import kotlinx.coroutines.sync.withLock +import kotlin.random.Random + +class DraftIdAllocator { + val allocated = mutableSetOf() + val mutex = Mutex() + + suspend fun allocate(): DraftId = mutex.withLock { + while (isActive) { + val draftId = DraftId(Random.nextLong()) + if (allocated.add(draftId)) { + return draftId + } + } + error("Unable to allocate a unique draft ID") + } + suspend fun free(draftId: DraftId) = mutex.withLock { + allocated.remove(draftId) + } +} \ No newline at end of file