mirror of
https://github.com/InsanusMokrassar/TelegramBotAPI.git
synced 2025-11-18 21:45:06 +00:00
Compare commits
35 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 8e6b3b7260 | |||
| e2cbd5ee0b | |||
| 1e87677ea7 | |||
| cb3494cb39 | |||
| ce81be9dcb | |||
| 2cc02c8c85 | |||
| f5b2ee79d6 | |||
| 0ba6ebb20f | |||
| 3d2df4e255 | |||
| 33b6ff1c1e | |||
| 2859f8ca2f | |||
| f1aa67ceda | |||
| 1c66d1e2fc | |||
| 44e6d7adbc | |||
| 61a6d4a880 | |||
| e37237cb71 | |||
| 9a5a196e41 | |||
| 68f6d8553c | |||
| 6fe8e73fca | |||
| 241545c0cb | |||
| 3b2310ece1 | |||
| e1adde0978 | |||
| 3b17bce71a | |||
| 999efc64eb | |||
| 05c99642cb | |||
| cd6f4831ae | |||
| 2778315aed | |||
| ff8d67a780 | |||
| 2a5f9a629d | |||
| 75b27858dd | |||
| 034e2d7ff3 | |||
| 1f69c16f2a | |||
| 8d24512413 | |||
| 09009003e3 | |||
| 048486146c |
4
.github/workflows/packages_publishing.yml
vendored
4
.github/workflows/packages_publishing.yml
vendored
@@ -8,12 +8,16 @@ jobs:
|
|||||||
- uses: actions/setup-java@v1
|
- uses: actions/setup-java@v1
|
||||||
with:
|
with:
|
||||||
java-version: 11
|
java-version: 11
|
||||||
|
- name: Setup LibCurl
|
||||||
|
run: sudo apt install -y libcurl4-openssl-dev
|
||||||
- name: Rewrite version
|
- name: Rewrite version
|
||||||
run: |
|
run: |
|
||||||
branch="`echo "${{ github.ref }}" | grep -o "[^/]*$"`"
|
branch="`echo "${{ github.ref }}" | grep -o "[^/]*$"`"
|
||||||
cat gradle.properties | sed -e "s/^library_version=\([0-9\.]*\)/library_version=\1-branch_$branch-build${{ github.run_number }}/" > gradle.properties.tmp
|
cat gradle.properties | sed -e "s/^library_version=\([0-9\.]*\)/library_version=\1-branch_$branch-build${{ github.run_number }}/" > gradle.properties.tmp
|
||||||
rm gradle.properties
|
rm gradle.properties
|
||||||
mv gradle.properties.tmp gradle.properties
|
mv gradle.properties.tmp gradle.properties
|
||||||
|
- name: KotlinSymbolProcessing execution
|
||||||
|
run: ./gradlew ksp
|
||||||
- name: Build
|
- name: Build
|
||||||
run: ./gradlew build
|
run: ./gradlew build
|
||||||
- name: Publish to Gitea
|
- name: Publish to Gitea
|
||||||
|
|||||||
25
CHANGELOG.md
25
CHANGELOG.md
@@ -1,5 +1,30 @@
|
|||||||
# TelegramBotAPI changelog
|
# TelegramBotAPI changelog
|
||||||
|
|
||||||
|
## 7.1.0
|
||||||
|
|
||||||
|
**This update contains changes according to the [Telegram Bot API 6.7](https://core.telegram.org/bots/api-changelog#april-21-2023)**
|
||||||
|
|
||||||
|
* `API`:
|
||||||
|
* Rename `editMessageCaption` to `editMessageMedia` due to wrong old naming
|
||||||
|
* Add `edit` extensions for `InlineMessageIdentifier`s
|
||||||
|
* `BehaviourBuilder`:
|
||||||
|
* `BehaviourContext` extensions `onDeepLink` and `waitDeepLinks` now can be used with `Regex` or `String` as first parameters
|
||||||
|
|
||||||
|
## 7.0.2
|
||||||
|
|
||||||
|
_This update brings experimental support of `linuxX64` and `mingwX64` platforms_
|
||||||
|
|
||||||
|
* `Versions`:
|
||||||
|
* `Kotlin`: `1.8.10` -> `1.8.20`
|
||||||
|
* `MicroUtils`: `0.17.5` -> `0.17.8`
|
||||||
|
* `Ktor`: `2.2.4` -> `2.3.0`
|
||||||
|
* `Core`:
|
||||||
|
* New `RequestsExecutor` - `MultipleClientKtorRequestsExecutor`
|
||||||
|
* Old `KtorRequestsExecutor` has been renamed to `DefaultKtorRequestsExecutor`
|
||||||
|
* `KtorRequestsExecutor` now is `expect class`
|
||||||
|
* On `JS`, `JVM` and `MinGWX64` platforms it is `DefaultKtorRequestsExecutor`
|
||||||
|
* On `LinuxX64` platform it is `MultipleClientKtorRequestsExecutor`
|
||||||
|
|
||||||
## 7.0.1
|
## 7.0.1
|
||||||
|
|
||||||
* `Core`:
|
* `Core`:
|
||||||
|
|||||||
12
README.md
12
README.md
@@ -1,9 +1,11 @@
|
|||||||
# TelegramBotAPI [](https://maven-badges.herokuapp.com/maven-central/dev.inmo/tgbotapi) [](https://core.telegram.org/bots/api-changelog#march-9-2023)
|
# TelegramBotAPI [](https://maven-badges.herokuapp.com/maven-central/dev.inmo/tgbotapi) [](https://core.telegram.org/bots/api-changelog#april-21-2023)
|
||||||
|
|
||||||
| Docs | [](https://tgbotapi.inmo.dev/index.html) [](https://bookstack.inmo.dev/books/telegrambotapi/chapter/introduction-tutorial) |
|
| Docs | [](https://tgbotapi.inmo.dev/index.html) [](https://bookstack.inmo.dev/books/telegrambotapi/chapter/introduction-tutorial) |
|
||||||
|:---:|:---:|
|
|:----------------------:|:-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------:|
|
||||||
| Useful repos | [](https://github.com/InsanusMokrassar/TelegramBotAPI-bot_template/generate) [](https://github.com/InsanusMokrassar/TelegramBotAPI-examples/) |
|
| Useful repos | [](https://github.com/InsanusMokrassar/TelegramBotAPI-bot_template/generate) [](https://github.com/InsanusMokrassar/TelegramBotAPI-examples/) |
|
||||||
| Misc | [](https://github.com/KotlinBy/awesome-kotlin) [](https://docs.google.com/forms/d/e/1FAIpQLSctdJHT_aEniyYT0-IUAEfo1hsIlezX2owlkEAYX4KPl2V2_A/viewform?usp=sf_link) |
|
| Misc | [](https://github.com/KotlinBy/awesome-kotlin) [](https://docs.google.com/forms/d/e/1FAIpQLSctdJHT_aEniyYT0-IUAEfo1hsIlezX2owlkEAYX4KPl2V2_A/viewform?usp=sf_link) |
|
||||||
|
| Platforms |   |
|
||||||
|
| Experimental Platforms |   |
|
||||||
|
|
||||||
<!--- [](https://t.me/ktgbotapi) --->
|
<!--- [](https://t.me/ktgbotapi) --->
|
||||||
|
|
||||||
|
|||||||
@@ -6,4 +6,4 @@ kotlin.incremental=true
|
|||||||
kotlin.incremental.js=true
|
kotlin.incremental.js=true
|
||||||
|
|
||||||
library_group=dev.inmo
|
library_group=dev.inmo
|
||||||
library_version=7.0.1
|
library_version=7.1.0
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
[versions]
|
[versions]
|
||||||
|
|
||||||
kotlin = "1.8.10"
|
kotlin = "1.8.20"
|
||||||
kotlin-serialization = "1.5.0"
|
kotlin-serialization = "1.5.0"
|
||||||
kotlin-coroutines = "1.6.4"
|
kotlin-coroutines = "1.6.4"
|
||||||
|
|
||||||
@@ -8,12 +8,12 @@ javax-activation = "1.1.1"
|
|||||||
|
|
||||||
korlibs = "3.4.0"
|
korlibs = "3.4.0"
|
||||||
uuid = "0.7.0"
|
uuid = "0.7.0"
|
||||||
ktor = "2.2.4"
|
ktor = "2.3.0"
|
||||||
|
|
||||||
ksp = "1.8.10-1.0.9"
|
ksp = "1.8.20-1.0.11"
|
||||||
kotlin-poet = "1.12.0"
|
kotlin-poet = "1.13.0"
|
||||||
|
|
||||||
microutils = "0.17.5"
|
microutils = "0.17.8"
|
||||||
|
|
||||||
github-release-plugin = "2.4.1"
|
github-release-plugin = "2.4.1"
|
||||||
dokka = "1.8.10"
|
dokka = "1.8.10"
|
||||||
@@ -31,6 +31,8 @@ kotlin-test-js = { module = "org.jetbrains.kotlin:kotlin-test-js", version.ref =
|
|||||||
|
|
||||||
ktor-client-core = { module = "io.ktor:ktor-client-core", version.ref = "ktor" }
|
ktor-client-core = { module = "io.ktor:ktor-client-core", version.ref = "ktor" }
|
||||||
ktor-client-cio = { module = "io.ktor:ktor-client-cio", version.ref = "ktor" }
|
ktor-client-cio = { module = "io.ktor:ktor-client-cio", version.ref = "ktor" }
|
||||||
|
ktor-client-curl = { module = "io.ktor:ktor-client-curl", version.ref = "ktor" }
|
||||||
|
ktor-client-winhttp = { module = "io.ktor:ktor-client-winhttp", version.ref = "ktor" }
|
||||||
ktor-server = { module = "io.ktor:ktor-server", version.ref = "ktor" }
|
ktor-server = { module = "io.ktor:ktor-server", version.ref = "ktor" }
|
||||||
ktor-server-host-common = { module = "io.ktor:ktor-server-host-common", version.ref = "ktor" }
|
ktor-server-host-common = { module = "io.ktor:ktor-server-host-common", version.ref = "ktor" }
|
||||||
|
|
||||||
|
|||||||
@@ -13,6 +13,8 @@ kotlin {
|
|||||||
browser()
|
browser()
|
||||||
nodejs()
|
nodejs()
|
||||||
}
|
}
|
||||||
|
linuxX64()
|
||||||
|
mingwX64()
|
||||||
|
|
||||||
sourceSets {
|
sourceSets {
|
||||||
commonMain {
|
commonMain {
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package dev.inmo.tgbotapi.extensions.api.answers
|
|||||||
|
|
||||||
import dev.inmo.tgbotapi.bot.TelegramBot
|
import dev.inmo.tgbotapi.bot.TelegramBot
|
||||||
import dev.inmo.tgbotapi.requests.answers.AnswerInlineQuery
|
import dev.inmo.tgbotapi.requests.answers.AnswerInlineQuery
|
||||||
|
import dev.inmo.tgbotapi.requests.answers.InlineQueryResultsButton
|
||||||
import dev.inmo.tgbotapi.types.InlineQueries.InlineQueryResult.abstracts.InlineQueryResult
|
import dev.inmo.tgbotapi.types.InlineQueries.InlineQueryResult.abstracts.InlineQueryResult
|
||||||
import dev.inmo.tgbotapi.types.InlineQueries.query.InlineQuery
|
import dev.inmo.tgbotapi.types.InlineQueries.query.InlineQuery
|
||||||
import dev.inmo.tgbotapi.types.InlineQueryIdentifier
|
import dev.inmo.tgbotapi.types.InlineQueryIdentifier
|
||||||
@@ -12,8 +13,37 @@ suspend fun TelegramBot.answerInlineQuery(
|
|||||||
cachedTime: Int? = null,
|
cachedTime: Int? = null,
|
||||||
isPersonal: Boolean? = null,
|
isPersonal: Boolean? = null,
|
||||||
nextOffset: String? = null,
|
nextOffset: String? = null,
|
||||||
switchPmText: String? = null,
|
button: InlineQueryResultsButton? = null
|
||||||
switchPmParameter: String? = null
|
) = execute(
|
||||||
|
AnswerInlineQuery(inlineQueryID, results, cachedTime, isPersonal, nextOffset, button)
|
||||||
|
)
|
||||||
|
|
||||||
|
suspend fun TelegramBot.answerInlineQuery(
|
||||||
|
inlineQuery: InlineQuery,
|
||||||
|
results: List<InlineQueryResult> = emptyList(),
|
||||||
|
cachedTime: Int? = null,
|
||||||
|
isPersonal: Boolean? = null,
|
||||||
|
nextOffset: String? = null,
|
||||||
|
button: InlineQueryResultsButton? = null
|
||||||
|
) = answerInlineQuery(inlineQuery.id, results, cachedTime, isPersonal, nextOffset, button)
|
||||||
|
|
||||||
|
suspend fun TelegramBot.answer(
|
||||||
|
inlineQuery: InlineQuery,
|
||||||
|
results: List<InlineQueryResult> = emptyList(),
|
||||||
|
cachedTime: Int? = null,
|
||||||
|
isPersonal: Boolean? = null,
|
||||||
|
nextOffset: String? = null,
|
||||||
|
button: InlineQueryResultsButton? = null
|
||||||
|
) = answerInlineQuery(inlineQuery.id, results, cachedTime, isPersonal, nextOffset, button)
|
||||||
|
|
||||||
|
suspend fun TelegramBot.answerInlineQuery(
|
||||||
|
inlineQueryID: InlineQueryIdentifier,
|
||||||
|
results: List<InlineQueryResult> = emptyList(),
|
||||||
|
cachedTime: Int? = null,
|
||||||
|
isPersonal: Boolean? = null,
|
||||||
|
nextOffset: String? = null,
|
||||||
|
switchPmText: String?,
|
||||||
|
switchPmParameter: String?
|
||||||
) = execute(
|
) = execute(
|
||||||
AnswerInlineQuery(inlineQueryID, results, cachedTime, isPersonal, nextOffset, switchPmText, switchPmParameter)
|
AnswerInlineQuery(inlineQueryID, results, cachedTime, isPersonal, nextOffset, switchPmText, switchPmParameter)
|
||||||
)
|
)
|
||||||
@@ -24,8 +54,8 @@ suspend fun TelegramBot.answerInlineQuery(
|
|||||||
cachedTime: Int? = null,
|
cachedTime: Int? = null,
|
||||||
isPersonal: Boolean? = null,
|
isPersonal: Boolean? = null,
|
||||||
nextOffset: String? = null,
|
nextOffset: String? = null,
|
||||||
switchPmText: String? = null,
|
switchPmText: String?,
|
||||||
switchPmParameter: String? = null
|
switchPmParameter: String?
|
||||||
) = answerInlineQuery(inlineQuery.id, results, cachedTime, isPersonal, nextOffset, switchPmText, switchPmParameter)
|
) = answerInlineQuery(inlineQuery.id, results, cachedTime, isPersonal, nextOffset, switchPmText, switchPmParameter)
|
||||||
|
|
||||||
suspend fun TelegramBot.answer(
|
suspend fun TelegramBot.answer(
|
||||||
@@ -34,6 +64,6 @@ suspend fun TelegramBot.answer(
|
|||||||
cachedTime: Int? = null,
|
cachedTime: Int? = null,
|
||||||
isPersonal: Boolean? = null,
|
isPersonal: Boolean? = null,
|
||||||
nextOffset: String? = null,
|
nextOffset: String? = null,
|
||||||
switchPmText: String? = null,
|
switchPmText: String?,
|
||||||
switchPmParameter: String? = null
|
switchPmParameter: String?
|
||||||
) = answerInlineQuery(inlineQuery.id, results, cachedTime, isPersonal, nextOffset, switchPmText, switchPmParameter)
|
) = answerInlineQuery(inlineQuery.id, results, cachedTime, isPersonal, nextOffset, switchPmText, switchPmParameter)
|
||||||
|
|||||||
@@ -0,0 +1,16 @@
|
|||||||
|
package dev.inmo.tgbotapi.extensions.api.bot
|
||||||
|
|
||||||
|
import dev.inmo.micro_utils.language_codes.IetfLanguageCode
|
||||||
|
import dev.inmo.tgbotapi.bot.TelegramBot
|
||||||
|
import dev.inmo.tgbotapi.requests.bot.GetMyCommands
|
||||||
|
import dev.inmo.tgbotapi.requests.bot.GetMyName
|
||||||
|
import dev.inmo.tgbotapi.types.commands.BotCommandScope
|
||||||
|
import dev.inmo.tgbotapi.types.commands.BotCommandScopeDefault
|
||||||
|
|
||||||
|
suspend fun TelegramBot.getMyName(
|
||||||
|
languageCode: IetfLanguageCode? = null
|
||||||
|
) = execute(GetMyName(languageCode))
|
||||||
|
|
||||||
|
suspend fun TelegramBot.getMyName(
|
||||||
|
languageCode: String?
|
||||||
|
) = getMyName(languageCode ?.let(::IetfLanguageCode))
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
package dev.inmo.tgbotapi.extensions.api.bot
|
||||||
|
|
||||||
|
import dev.inmo.micro_utils.language_codes.IetfLanguageCode
|
||||||
|
import dev.inmo.tgbotapi.bot.TelegramBot
|
||||||
|
import dev.inmo.tgbotapi.requests.bot.GetMyCommands
|
||||||
|
import dev.inmo.tgbotapi.requests.bot.GetMyName
|
||||||
|
import dev.inmo.tgbotapi.requests.bot.SetMyName
|
||||||
|
import dev.inmo.tgbotapi.types.commands.BotCommandScope
|
||||||
|
import dev.inmo.tgbotapi.types.commands.BotCommandScopeDefault
|
||||||
|
|
||||||
|
suspend fun TelegramBot.setMyName(
|
||||||
|
name: String? = null,
|
||||||
|
languageCode: IetfLanguageCode? = null
|
||||||
|
) = execute(SetMyName(name, languageCode))
|
||||||
|
|
||||||
|
suspend fun TelegramBot.setMyName(
|
||||||
|
name: String?,
|
||||||
|
languageCode: String?
|
||||||
|
) = setMyName(name, languageCode ?.let(::IetfLanguageCode))
|
||||||
@@ -0,0 +1,114 @@
|
|||||||
|
package dev.inmo.tgbotapi.extensions.api.edit
|
||||||
|
|
||||||
|
import dev.inmo.tgbotapi.abstracts.TextedWithTextSources
|
||||||
|
import dev.inmo.tgbotapi.bot.TelegramBot
|
||||||
|
import dev.inmo.tgbotapi.extensions.api.edit.caption.editMessageCaption
|
||||||
|
import dev.inmo.tgbotapi.extensions.api.edit.location.live.editLiveLocation
|
||||||
|
import dev.inmo.tgbotapi.extensions.api.edit.media.editMessageMedia
|
||||||
|
import dev.inmo.tgbotapi.extensions.api.edit.reply_markup.editMessageReplyMarkup
|
||||||
|
import dev.inmo.tgbotapi.extensions.api.edit.text.editMessageText
|
||||||
|
import dev.inmo.tgbotapi.types.*
|
||||||
|
import dev.inmo.tgbotapi.types.buttons.InlineKeyboardMarkup
|
||||||
|
import dev.inmo.tgbotapi.types.chat.Chat
|
||||||
|
import dev.inmo.tgbotapi.types.location.LiveLocation
|
||||||
|
import dev.inmo.tgbotapi.types.media.TelegramMedia
|
||||||
|
import dev.inmo.tgbotapi.types.message.ParseMode
|
||||||
|
import dev.inmo.tgbotapi.types.message.abstracts.ContentMessage
|
||||||
|
import dev.inmo.tgbotapi.types.message.abstracts.Message
|
||||||
|
import dev.inmo.tgbotapi.types.message.content.*
|
||||||
|
import dev.inmo.tgbotapi.types.message.textsources.TextSource
|
||||||
|
import dev.inmo.tgbotapi.types.message.textsources.TextSourcesList
|
||||||
|
import dev.inmo.tgbotapi.utils.EntitiesBuilderBody
|
||||||
|
import dev.inmo.tgbotapi.utils.buildEntities
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param replyMarkup Some [InlineKeyboardMarkup]. See [dev.inmo.tgbotapi.extensions.utils.types.buttons.inlineKeyboard]
|
||||||
|
* as a builder for that
|
||||||
|
*/
|
||||||
|
suspend fun TelegramBot.edit(
|
||||||
|
messageId: InlineMessageIdentifier,
|
||||||
|
latitude: Double,
|
||||||
|
longitude: Double,
|
||||||
|
horizontalAccuracy: Meters? = null,
|
||||||
|
heading: Degrees? = null,
|
||||||
|
proximityAlertRadius: Meters? = null,
|
||||||
|
replyMarkup: InlineKeyboardMarkup? = null
|
||||||
|
) = editLiveLocation(messageId, latitude, longitude, horizontalAccuracy, heading, proximityAlertRadius, replyMarkup)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param replyMarkup Some [InlineKeyboardMarkup]. See [dev.inmo.tgbotapi.extensions.utils.types.buttons.inlineKeyboard]
|
||||||
|
* as a builder for that
|
||||||
|
*/
|
||||||
|
suspend fun TelegramBot.edit(
|
||||||
|
messageId: InlineMessageIdentifier,
|
||||||
|
location: LiveLocation,
|
||||||
|
replyMarkup: InlineKeyboardMarkup? = null
|
||||||
|
) = editLiveLocation(
|
||||||
|
messageId, location, replyMarkup
|
||||||
|
)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param replyMarkup Some [InlineKeyboardMarkup]. See [dev.inmo.tgbotapi.extensions.utils.types.buttons.inlineKeyboard]
|
||||||
|
* as a builder for that
|
||||||
|
*/
|
||||||
|
suspend fun TelegramBot.edit(
|
||||||
|
messageId: InlineMessageIdentifier,
|
||||||
|
media: TelegramMedia,
|
||||||
|
replyMarkup: InlineKeyboardMarkup? = null
|
||||||
|
) = editMessageMedia(messageId, media, replyMarkup)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param replyMarkup Some [InlineKeyboardMarkup]. See [dev.inmo.tgbotapi.extensions.utils.types.buttons.inlineKeyboard]
|
||||||
|
* as a builder for that
|
||||||
|
*/
|
||||||
|
suspend fun TelegramBot.edit(
|
||||||
|
messageId: InlineMessageIdentifier,
|
||||||
|
replyMarkup: InlineKeyboardMarkup? = null
|
||||||
|
) = editMessageReplyMarkup(messageId, replyMarkup)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param replyMarkup Some [InlineKeyboardMarkup]. See [dev.inmo.tgbotapi.extensions.utils.types.buttons.inlineKeyboard]
|
||||||
|
* as a builder for that
|
||||||
|
*/
|
||||||
|
suspend fun TelegramBot.edit(
|
||||||
|
messageId: InlineMessageIdentifier,
|
||||||
|
text: String,
|
||||||
|
parseMode: ParseMode? = null,
|
||||||
|
disableWebPagePreview: Boolean? = null,
|
||||||
|
replyMarkup: InlineKeyboardMarkup? = null
|
||||||
|
) = editMessageText(messageId, text, parseMode, disableWebPagePreview, replyMarkup)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param replyMarkup Some [InlineKeyboardMarkup]. See [dev.inmo.tgbotapi.extensions.utils.types.buttons.inlineKeyboard]
|
||||||
|
* as a builder for that
|
||||||
|
*/
|
||||||
|
suspend fun TelegramBot.edit(
|
||||||
|
messageId: InlineMessageIdentifier,
|
||||||
|
entities: TextSourcesList,
|
||||||
|
disableWebPagePreview: Boolean? = null,
|
||||||
|
replyMarkup: InlineKeyboardMarkup? = null
|
||||||
|
) = editMessageText(messageId, entities, disableWebPagePreview, replyMarkup)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param replyMarkup Some [InlineKeyboardMarkup]. See [dev.inmo.tgbotapi.extensions.utils.types.buttons.inlineKeyboard]
|
||||||
|
* as a builder for that
|
||||||
|
*/
|
||||||
|
suspend fun TelegramBot.edit(
|
||||||
|
messageId: InlineMessageIdentifier,
|
||||||
|
separator: TextSource? = null,
|
||||||
|
disableWebPagePreview: Boolean? = null,
|
||||||
|
replyMarkup: InlineKeyboardMarkup? = null,
|
||||||
|
builderBody: EntitiesBuilderBody
|
||||||
|
) = edit(messageId, buildEntities(separator, builderBody), disableWebPagePreview, replyMarkup)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param replyMarkup Some [InlineKeyboardMarkup]. See [dev.inmo.tgbotapi.extensions.utils.types.buttons.inlineKeyboard]
|
||||||
|
* as a builder for that
|
||||||
|
*/
|
||||||
|
suspend fun TelegramBot.edit(
|
||||||
|
messageId: InlineMessageIdentifier,
|
||||||
|
separator: String,
|
||||||
|
disableWebPagePreview: Boolean? = null,
|
||||||
|
replyMarkup: InlineKeyboardMarkup? = null,
|
||||||
|
builderBody: EntitiesBuilderBody
|
||||||
|
) = edit(messageId, buildEntities(separator, builderBody), disableWebPagePreview, replyMarkup)
|
||||||
@@ -10,6 +10,17 @@ import dev.inmo.tgbotapi.types.buttons.InlineKeyboardMarkup
|
|||||||
* @param replyMarkup Some [InlineKeyboardMarkup]. See [dev.inmo.tgbotapi.extensions.utils.types.buttons.inlineKeyboard]
|
* @param replyMarkup Some [InlineKeyboardMarkup]. See [dev.inmo.tgbotapi.extensions.utils.types.buttons.inlineKeyboard]
|
||||||
* as a builder for that
|
* as a builder for that
|
||||||
*/
|
*/
|
||||||
|
suspend fun TelegramBot.editMessageMedia(
|
||||||
|
inlineMessageId: InlineMessageIdentifier,
|
||||||
|
media: TelegramMedia,
|
||||||
|
replyMarkup: InlineKeyboardMarkup? = null
|
||||||
|
) = execute(EditInlineMessageMedia(inlineMessageId, media, replyMarkup))
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param replyMarkup Some [InlineKeyboardMarkup]. See [dev.inmo.tgbotapi.extensions.utils.types.buttons.inlineKeyboard]
|
||||||
|
* as a builder for that
|
||||||
|
*/
|
||||||
|
@Deprecated("Renamed", ReplaceWith("this.editMessageMedia(inlineMessageId, media, replyMarkup)", "dev.inmo.tgbotapi.extensions.api.edit.media.editMessageMedia"))
|
||||||
suspend fun TelegramBot.editMessageCaption(
|
suspend fun TelegramBot.editMessageCaption(
|
||||||
inlineMessageId: InlineMessageIdentifier,
|
inlineMessageId: InlineMessageIdentifier,
|
||||||
media: TelegramMedia,
|
media: TelegramMedia,
|
||||||
|
|||||||
@@ -93,8 +93,9 @@ interface BehaviourContextWithFSM<T : State> : BehaviourContext, StatesMachine<T
|
|||||||
behaviourContext: BehaviourContext,
|
behaviourContext: BehaviourContext,
|
||||||
handlers: List<BehaviourWithFSMStateHandlerHolder<*, T>>,
|
handlers: List<BehaviourWithFSMStateHandlerHolder<*, T>>,
|
||||||
statesManager: StatesManager<T>,
|
statesManager: StatesManager<T>,
|
||||||
|
fallbackHandler: BehaviourWithFSMStateHandlerHolder<T, T>? = null,
|
||||||
onStateHandlingErrorHandler: StateHandlingErrorHandler<T> = defaultStateHandlingErrorHandler()
|
onStateHandlingErrorHandler: StateHandlingErrorHandler<T> = defaultStateHandlingErrorHandler()
|
||||||
) = DefaultBehaviourContextWithFSM<T>(behaviourContext, statesManager, handlers, onStateHandlingErrorHandler)
|
) = DefaultBehaviourContextWithFSM<T>(behaviourContext, statesManager, handlers, fallbackHandler, onStateHandlingErrorHandler)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -129,11 +130,12 @@ class DefaultBehaviourContextWithFSM<T : State>(
|
|||||||
private val behaviourContext: BehaviourContext,
|
private val behaviourContext: BehaviourContext,
|
||||||
private val statesManager: StatesManager<T>,
|
private val statesManager: StatesManager<T>,
|
||||||
private val handlers: List<BehaviourWithFSMStateHandlerHolder<*, T>>,
|
private val handlers: List<BehaviourWithFSMStateHandlerHolder<*, T>>,
|
||||||
|
private val fallbackHandler: BehaviourWithFSMStateHandlerHolder<T, T>? = null,
|
||||||
private val onStateHandlingErrorHandler: StateHandlingErrorHandler<T> = defaultStateHandlingErrorHandler()
|
private val onStateHandlingErrorHandler: StateHandlingErrorHandler<T> = defaultStateHandlingErrorHandler()
|
||||||
) : BehaviourContext by behaviourContext, BehaviourContextWithFSM<T> {
|
) : BehaviourContext by behaviourContext, BehaviourContextWithFSM<T> {
|
||||||
private val updatesFlows = mutableMapOf<Any, DefaultBehaviourContextWithFSM<T>>()
|
private val updatesFlows = mutableMapOf<Any, DefaultBehaviourContextWithFSM<T>>()
|
||||||
private val additionalHandlers = mutableListOf<BehaviourWithFSMStateHandlerHolder<*, T>>()
|
private val additionalHandlers = mutableListOf<BehaviourWithFSMStateHandlerHolder<*, T>>()
|
||||||
private var actualHandlersList = additionalHandlers + handlers
|
private var actualHandlersList = additionalHandlers + handlers + listOfNotNull(fallbackHandler)
|
||||||
|
|
||||||
protected val statesJobs = mutableMapOf<T, Job>()
|
protected val statesJobs = mutableMapOf<T, Job>()
|
||||||
protected val statesJobsMutex = Mutex()
|
protected val statesJobsMutex = Mutex()
|
||||||
@@ -250,6 +252,7 @@ class DefaultBehaviourContextWithFSM<T : State>(
|
|||||||
behaviourContext.copy(bot, scope, broadcastChannelsSize, onBufferOverflow, upstreamUpdatesFlow, triggersHolder),
|
behaviourContext.copy(bot, scope, broadcastChannelsSize, onBufferOverflow, upstreamUpdatesFlow, triggersHolder),
|
||||||
handlers,
|
handlers,
|
||||||
statesManager,
|
statesManager,
|
||||||
|
fallbackHandler,
|
||||||
onStateHandlingErrorHandler
|
onStateHandlingErrorHandler
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -265,6 +268,7 @@ class DefaultBehaviourContextWithFSM<T : State>(
|
|||||||
behaviourContext.copy(bot, scope, broadcastChannelsSize, onBufferOverflow, upstreamUpdatesFlow, triggersHolder),
|
behaviourContext.copy(bot, scope, broadcastChannelsSize, onBufferOverflow, upstreamUpdatesFlow, triggersHolder),
|
||||||
handlers,
|
handlers,
|
||||||
statesManager,
|
statesManager,
|
||||||
|
fallbackHandler,
|
||||||
onStateHandlingErrorHandler
|
onStateHandlingErrorHandler
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -31,6 +31,7 @@ suspend fun <T : State> TelegramBot.buildBehaviourWithFSM(
|
|||||||
defaultExceptionsHandler: ExceptionHandler<Unit>? = null,
|
defaultExceptionsHandler: ExceptionHandler<Unit>? = null,
|
||||||
statesManager: StatesManager<T> = DefaultStatesManager(InMemoryDefaultStatesManagerRepo()),
|
statesManager: StatesManager<T> = DefaultStatesManager(InMemoryDefaultStatesManagerRepo()),
|
||||||
presetHandlers: List<BehaviourWithFSMStateHandlerHolder<*, T>> = listOf(),
|
presetHandlers: List<BehaviourWithFSMStateHandlerHolder<*, T>> = listOf(),
|
||||||
|
fallbackHandler: BehaviourWithFSMStateHandlerHolder<T, T>? = null,
|
||||||
onStateHandlingErrorHandler: StateHandlingErrorHandler<T> = defaultStateHandlingErrorHandler(),
|
onStateHandlingErrorHandler: StateHandlingErrorHandler<T> = defaultStateHandlingErrorHandler(),
|
||||||
block: CustomBehaviourContextReceiver<DefaultBehaviourContextWithFSM<T>, Unit>
|
block: CustomBehaviourContextReceiver<DefaultBehaviourContextWithFSM<T>, Unit>
|
||||||
): DefaultBehaviourContextWithFSM<T> = BehaviourContextWithFSM(
|
): DefaultBehaviourContextWithFSM<T> = BehaviourContextWithFSM(
|
||||||
@@ -41,6 +42,7 @@ suspend fun <T : State> TelegramBot.buildBehaviourWithFSM(
|
|||||||
),
|
),
|
||||||
presetHandlers,
|
presetHandlers,
|
||||||
statesManager,
|
statesManager,
|
||||||
|
fallbackHandler,
|
||||||
onStateHandlingErrorHandler
|
onStateHandlingErrorHandler
|
||||||
).apply { block() }
|
).apply { block() }
|
||||||
|
|
||||||
@@ -59,6 +61,7 @@ suspend fun <T : State> TelegramBot.buildBehaviourWithFSMAndStartLongPolling(
|
|||||||
defaultExceptionsHandler: ExceptionHandler<Unit>? = null,
|
defaultExceptionsHandler: ExceptionHandler<Unit>? = null,
|
||||||
statesManager: StatesManager<T> = DefaultStatesManager(InMemoryDefaultStatesManagerRepo()),
|
statesManager: StatesManager<T> = DefaultStatesManager(InMemoryDefaultStatesManagerRepo()),
|
||||||
presetHandlers: List<BehaviourWithFSMStateHandlerHolder<*, T>> = listOf(),
|
presetHandlers: List<BehaviourWithFSMStateHandlerHolder<*, T>> = listOf(),
|
||||||
|
fallbackHandler: BehaviourWithFSMStateHandlerHolder<T, T>? = null,
|
||||||
onStateHandlingErrorHandler: StateHandlingErrorHandler<T> = defaultStateHandlingErrorHandler(),
|
onStateHandlingErrorHandler: StateHandlingErrorHandler<T> = defaultStateHandlingErrorHandler(),
|
||||||
timeoutSeconds: Seconds = 30,
|
timeoutSeconds: Seconds = 30,
|
||||||
autoDisableWebhooks: Boolean = true,
|
autoDisableWebhooks: Boolean = true,
|
||||||
@@ -71,6 +74,7 @@ suspend fun <T : State> TelegramBot.buildBehaviourWithFSMAndStartLongPolling(
|
|||||||
defaultExceptionsHandler,
|
defaultExceptionsHandler,
|
||||||
statesManager,
|
statesManager,
|
||||||
presetHandlers,
|
presetHandlers,
|
||||||
|
fallbackHandler,
|
||||||
onStateHandlingErrorHandler,
|
onStateHandlingErrorHandler,
|
||||||
block
|
block
|
||||||
).run {
|
).run {
|
||||||
@@ -104,6 +108,7 @@ suspend fun <T : State> TelegramBot.buildBehaviourWithFSM(
|
|||||||
defaultExceptionsHandler: ExceptionHandler<Unit>? = null,
|
defaultExceptionsHandler: ExceptionHandler<Unit>? = null,
|
||||||
statesManager: StatesManager<T> = DefaultStatesManager(InMemoryDefaultStatesManagerRepo()),
|
statesManager: StatesManager<T> = DefaultStatesManager(InMemoryDefaultStatesManagerRepo()),
|
||||||
presetHandlers: List<BehaviourWithFSMStateHandlerHolder<*, T>> = listOf(),
|
presetHandlers: List<BehaviourWithFSMStateHandlerHolder<*, T>> = listOf(),
|
||||||
|
fallbackHandler: BehaviourWithFSMStateHandlerHolder<T, T>? = null,
|
||||||
onStateHandlingErrorHandler: StateHandlingErrorHandler<T> = defaultStateHandlingErrorHandler(),
|
onStateHandlingErrorHandler: StateHandlingErrorHandler<T> = defaultStateHandlingErrorHandler(),
|
||||||
block: CustomBehaviourContextReceiver<DefaultBehaviourContextWithFSM<T>, Unit>
|
block: CustomBehaviourContextReceiver<DefaultBehaviourContextWithFSM<T>, Unit>
|
||||||
): DefaultBehaviourContextWithFSM<T> = BehaviourContextWithFSM(
|
): DefaultBehaviourContextWithFSM<T> = BehaviourContextWithFSM(
|
||||||
@@ -114,6 +119,7 @@ suspend fun <T : State> TelegramBot.buildBehaviourWithFSM(
|
|||||||
),
|
),
|
||||||
presetHandlers,
|
presetHandlers,
|
||||||
statesManager,
|
statesManager,
|
||||||
|
fallbackHandler,
|
||||||
onStateHandlingErrorHandler
|
onStateHandlingErrorHandler
|
||||||
).apply { block() }
|
).apply { block() }
|
||||||
|
|
||||||
@@ -137,6 +143,7 @@ suspend fun <T : State> TelegramBot.buildBehaviourWithFSMAndStartLongPolling(
|
|||||||
defaultExceptionsHandler: ExceptionHandler<Unit>? = null,
|
defaultExceptionsHandler: ExceptionHandler<Unit>? = null,
|
||||||
statesManager: StatesManager<T> = DefaultStatesManager(InMemoryDefaultStatesManagerRepo()),
|
statesManager: StatesManager<T> = DefaultStatesManager(InMemoryDefaultStatesManagerRepo()),
|
||||||
presetHandlers: List<BehaviourWithFSMStateHandlerHolder<*, T>> = listOf(),
|
presetHandlers: List<BehaviourWithFSMStateHandlerHolder<*, T>> = listOf(),
|
||||||
|
fallbackHandler: BehaviourWithFSMStateHandlerHolder<T, T>? = null,
|
||||||
onStateHandlingErrorHandler: StateHandlingErrorHandler<T> = defaultStateHandlingErrorHandler(),
|
onStateHandlingErrorHandler: StateHandlingErrorHandler<T> = defaultStateHandlingErrorHandler(),
|
||||||
timeoutSeconds: Seconds = 30,
|
timeoutSeconds: Seconds = 30,
|
||||||
autoDisableWebhooks: Boolean = true,
|
autoDisableWebhooks: Boolean = true,
|
||||||
@@ -150,6 +157,7 @@ suspend fun <T : State> TelegramBot.buildBehaviourWithFSMAndStartLongPolling(
|
|||||||
defaultExceptionsHandler,
|
defaultExceptionsHandler,
|
||||||
statesManager,
|
statesManager,
|
||||||
presetHandlers,
|
presetHandlers,
|
||||||
|
fallbackHandler,
|
||||||
onStateHandlingErrorHandler,
|
onStateHandlingErrorHandler,
|
||||||
block
|
block
|
||||||
).run {
|
).run {
|
||||||
|
|||||||
@@ -46,6 +46,7 @@ suspend fun <T : State> telegramBotWithBehaviourAndFSM(
|
|||||||
defaultExceptionsHandler: ExceptionHandler<Unit>? = null,
|
defaultExceptionsHandler: ExceptionHandler<Unit>? = null,
|
||||||
statesManager: StatesManager<T> = DefaultStatesManager(InMemoryDefaultStatesManagerRepo()),
|
statesManager: StatesManager<T> = DefaultStatesManager(InMemoryDefaultStatesManagerRepo()),
|
||||||
presetHandlers: List<BehaviourWithFSMStateHandlerHolder<*, T>> = listOf(),
|
presetHandlers: List<BehaviourWithFSMStateHandlerHolder<*, T>> = listOf(),
|
||||||
|
fallbackHandler: BehaviourWithFSMStateHandlerHolder<T, T>? = null,
|
||||||
testServer: Boolean = false,
|
testServer: Boolean = false,
|
||||||
onStateHandlingErrorHandler: StateHandlingErrorHandler<T> = defaultStateHandlingErrorHandler(),
|
onStateHandlingErrorHandler: StateHandlingErrorHandler<T> = defaultStateHandlingErrorHandler(),
|
||||||
timeoutSeconds: Seconds = 30,
|
timeoutSeconds: Seconds = 30,
|
||||||
@@ -65,6 +66,7 @@ suspend fun <T : State> telegramBotWithBehaviourAndFSM(
|
|||||||
defaultExceptionsHandler,
|
defaultExceptionsHandler,
|
||||||
statesManager,
|
statesManager,
|
||||||
presetHandlers,
|
presetHandlers,
|
||||||
|
fallbackHandler,
|
||||||
onStateHandlingErrorHandler,
|
onStateHandlingErrorHandler,
|
||||||
timeoutSeconds,
|
timeoutSeconds,
|
||||||
autoDisableWebhooks,
|
autoDisableWebhooks,
|
||||||
@@ -97,6 +99,7 @@ suspend fun <T : State> telegramBotWithBehaviourAndFSMAndStartLongPolling(
|
|||||||
defaultExceptionsHandler: ExceptionHandler<Unit>? = null,
|
defaultExceptionsHandler: ExceptionHandler<Unit>? = null,
|
||||||
statesManager: StatesManager<T> = DefaultStatesManager(InMemoryDefaultStatesManagerRepo()),
|
statesManager: StatesManager<T> = DefaultStatesManager(InMemoryDefaultStatesManagerRepo()),
|
||||||
presetHandlers: List<BehaviourWithFSMStateHandlerHolder<*, T>> = listOf(),
|
presetHandlers: List<BehaviourWithFSMStateHandlerHolder<*, T>> = listOf(),
|
||||||
|
fallbackHandler: BehaviourWithFSMStateHandlerHolder<T, T>? = null,
|
||||||
testServer: Boolean = false,
|
testServer: Boolean = false,
|
||||||
onStateHandlingErrorHandler: StateHandlingErrorHandler<T> = defaultStateHandlingErrorHandler(),
|
onStateHandlingErrorHandler: StateHandlingErrorHandler<T> = defaultStateHandlingErrorHandler(),
|
||||||
timeoutSeconds: Seconds = 30,
|
timeoutSeconds: Seconds = 30,
|
||||||
@@ -116,6 +119,7 @@ suspend fun <T : State> telegramBotWithBehaviourAndFSMAndStartLongPolling(
|
|||||||
defaultExceptionsHandler,
|
defaultExceptionsHandler,
|
||||||
statesManager,
|
statesManager,
|
||||||
presetHandlers,
|
presetHandlers,
|
||||||
|
fallbackHandler,
|
||||||
onStateHandlingErrorHandler,
|
onStateHandlingErrorHandler,
|
||||||
timeoutSeconds,
|
timeoutSeconds,
|
||||||
autoDisableWebhooks,
|
autoDisableWebhooks,
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ package dev.inmo.tgbotapi.extensions.behaviour_builder
|
|||||||
import dev.inmo.micro_utils.coroutines.*
|
import dev.inmo.micro_utils.coroutines.*
|
||||||
import dev.inmo.tgbotapi.bot.TelegramBot
|
import dev.inmo.tgbotapi.bot.TelegramBot
|
||||||
import dev.inmo.tgbotapi.extensions.behaviour_builder.utils.handlers_registrar.TriggersHolder
|
import dev.inmo.tgbotapi.extensions.behaviour_builder.utils.handlers_registrar.TriggersHolder
|
||||||
|
import dev.inmo.tgbotapi.types.UpdateIdentifier
|
||||||
import dev.inmo.tgbotapi.types.update.abstracts.Update
|
import dev.inmo.tgbotapi.types.update.abstracts.Update
|
||||||
import dev.inmo.tgbotapi.updateshandlers.*
|
import dev.inmo.tgbotapi.updateshandlers.*
|
||||||
import kotlinx.coroutines.*
|
import kotlinx.coroutines.*
|
||||||
@@ -71,9 +72,17 @@ class DefaultBehaviourContext(
|
|||||||
private val additionalUpdatesSharedFlow = MutableSharedFlow<Update>(0, broadcastChannelsSize, onBufferOverflow)
|
private val additionalUpdatesSharedFlow = MutableSharedFlow<Update>(0, broadcastChannelsSize, onBufferOverflow)
|
||||||
override val allUpdatesFlow: Flow<Update> = (additionalUpdatesSharedFlow.asSharedFlow()).let {
|
override val allUpdatesFlow: Flow<Update> = (additionalUpdatesSharedFlow.asSharedFlow()).let {
|
||||||
if (upstreamUpdatesFlow != null) {
|
if (upstreamUpdatesFlow != null) {
|
||||||
var lastHandledUpdate = -1L
|
val handledUpdates = mutableSetOf<UpdateIdentifier>()
|
||||||
(it + upstreamUpdatesFlow).filter {
|
(it + upstreamUpdatesFlow).filter {
|
||||||
(it.updateId > lastHandledUpdate).also { passed -> if (passed) { lastHandledUpdate = it.updateId } }
|
val passed = handledUpdates.add(it.updateId)
|
||||||
|
(passed).also { passed ->
|
||||||
|
val needToDropCount = handledUpdates.size - broadcastChannelsSize
|
||||||
|
if (needToDropCount > 0) {
|
||||||
|
handledUpdates.removeAll(
|
||||||
|
handledUpdates.take(needToDropCount).ifEmpty { return@also }
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
it
|
it
|
||||||
|
|||||||
@@ -21,3 +21,17 @@ suspend fun BehaviourContext.waitDeepLinks(
|
|||||||
.flattenCommandsWithParams().mapNotNull {
|
.flattenCommandsWithParams().mapNotNull {
|
||||||
it.first to (it.second.second.singleOrNull() ?.regularTextSourceOrNull() ?.source ?.removePrefix(" ") ?: return@mapNotNull null)
|
it.first to (it.second.second.singleOrNull() ?.regularTextSourceOrNull() ?.source ?.removePrefix(" ") ?: return@mapNotNull null)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
suspend fun BehaviourContext.waitDeepLinks(
|
||||||
|
regex: Regex,
|
||||||
|
initRequest: Request<*>? = null,
|
||||||
|
errorFactory: NullableRequestBuilder<*> = { null },
|
||||||
|
): Flow<Pair<CommonMessage<TextContent>, String>> = waitDeepLinks(initRequest, errorFactory).filter {
|
||||||
|
regex.matches(it.second)
|
||||||
|
}
|
||||||
|
|
||||||
|
suspend fun BehaviourContext.waitDeepLinks(
|
||||||
|
deepLink: String,
|
||||||
|
initRequest: Request<*>? = null,
|
||||||
|
errorFactory: NullableRequestBuilder<*> = { null },
|
||||||
|
): Flow<Pair<CommonMessage<TextContent>, String>> = waitDeepLinks(Regex("^$deepLink$"), initRequest, errorFactory)
|
||||||
|
|||||||
@@ -46,3 +46,24 @@ suspend fun <BC : BehaviourContext> BC.onDeepLink(
|
|||||||
this@onDeepLink.launchSafelyWithoutExceptions { triggersHolder.handleableCommandsHolder.unregisterHandleable(startRegex) }
|
this@onDeepLink.launchSafelyWithoutExceptions { triggersHolder.handleableCommandsHolder.unregisterHandleable(startRegex) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
suspend fun <BC : BehaviourContext> BC.onDeepLink(
|
||||||
|
regex: Regex,
|
||||||
|
initialFilter: SimpleFilter<Pair<TextMessage, String>>? = null,
|
||||||
|
subcontextUpdatesFilter: CustomBehaviourContextAndTwoTypesReceiver<BC, Boolean, Pair<TextMessage, String>, Update> = { (message, _), update -> MessageFilterByChat(this, message, update) },
|
||||||
|
markerFactory: MarkerFactory<Pair<TextMessage, String>, Any> = MarkerFactory { (message, _) -> ByChatMessageMarkerFactory(message) },
|
||||||
|
scenarioReceiver: CustomBehaviourContextAndTypeReceiver<BC, Unit, Pair<TextMessage, String>>
|
||||||
|
): Job {
|
||||||
|
val internalFilter = SimpleFilter<Pair<TextMessage, String>> {
|
||||||
|
regex.matches(it.second)
|
||||||
|
}
|
||||||
|
return onDeepLink(initialFilter ?.let { internalFilter * it } ?: internalFilter, subcontextUpdatesFilter, markerFactory, scenarioReceiver)
|
||||||
|
}
|
||||||
|
|
||||||
|
suspend fun <BC : BehaviourContext> BC.onDeepLink(
|
||||||
|
deepLink: String,
|
||||||
|
initialFilter: SimpleFilter<Pair<TextMessage, String>>? = null,
|
||||||
|
subcontextUpdatesFilter: CustomBehaviourContextAndTwoTypesReceiver<BC, Boolean, Pair<TextMessage, String>, Update> = { (message, _), update -> MessageFilterByChat(this, message, update) },
|
||||||
|
markerFactory: MarkerFactory<Pair<TextMessage, String>, Any> = MarkerFactory { (message, _) -> ByChatMessageMarkerFactory(message) },
|
||||||
|
scenarioReceiver: CustomBehaviourContextAndTypeReceiver<BC, Unit, Pair<TextMessage, String>>
|
||||||
|
): Job = onDeepLink(Regex("^$deepLink$"), initialFilter, subcontextUpdatesFilter, markerFactory, scenarioReceiver)
|
||||||
|
|||||||
@@ -0,0 +1,6 @@
|
|||||||
|
package dev.inmo.tgbotapi.extensions.behaviour_builder
|
||||||
|
|
||||||
|
import kotlinx.coroutines.CoroutineScope
|
||||||
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
|
||||||
|
actual var defaultCoroutineScopeProvider: () -> CoroutineScope = { CoroutineScope(Dispatchers.Default) }
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
package dev.inmo.tgbotapi.extensions.behaviour_builder
|
||||||
|
|
||||||
|
import kotlinx.coroutines.CoroutineScope
|
||||||
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
|
||||||
|
actual var defaultCoroutineScopeProvider: () -> CoroutineScope = { CoroutineScope(Dispatchers.Default) }
|
||||||
@@ -48,11 +48,23 @@ kotlin {
|
|||||||
api libs.javax.activation
|
api libs.javax.activation
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
linuxX64Main {
|
||||||
|
dependencies {
|
||||||
|
api libs.ktor.client.curl
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mingwX64Main {
|
||||||
|
dependencies {
|
||||||
|
api libs.ktor.client.winhttp
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
add("kspJvm", project(":tgbotapi.ksp"))
|
add("kspCommonMainMetadata", project(":tgbotapi.ksp"))
|
||||||
}
|
}
|
||||||
|
|
||||||
ksp {
|
ksp {
|
||||||
|
|||||||
@@ -1,134 +1,25 @@
|
|||||||
package dev.inmo.tgbotapi.bot.ktor
|
package dev.inmo.tgbotapi.bot.ktor
|
||||||
|
|
||||||
import dev.inmo.micro_utils.coroutines.runCatchingSafely
|
|
||||||
import dev.inmo.micro_utils.coroutines.safely
|
|
||||||
import dev.inmo.tgbotapi.bot.BaseRequestsExecutor
|
import dev.inmo.tgbotapi.bot.BaseRequestsExecutor
|
||||||
import dev.inmo.tgbotapi.bot.TelegramBot
|
|
||||||
import dev.inmo.tgbotapi.bot.exceptions.*
|
|
||||||
import dev.inmo.tgbotapi.bot.ktor.base.*
|
|
||||||
import dev.inmo.tgbotapi.bot.settings.limiters.ExceptionsOnlyLimiter
|
import dev.inmo.tgbotapi.bot.settings.limiters.ExceptionsOnlyLimiter
|
||||||
import dev.inmo.tgbotapi.bot.settings.limiters.RequestLimiter
|
import dev.inmo.tgbotapi.bot.settings.limiters.RequestLimiter
|
||||||
import dev.inmo.tgbotapi.requests.abstracts.Request
|
import dev.inmo.tgbotapi.utils.TelegramAPIUrlsKeeper
|
||||||
import dev.inmo.tgbotapi.types.Response
|
import dev.inmo.tgbotapi.utils.nonstrictJsonFormat
|
||||||
import dev.inmo.tgbotapi.utils.*
|
import io.ktor.client.*
|
||||||
import io.ktor.client.HttpClient
|
|
||||||
import io.ktor.client.plugins.*
|
|
||||||
import io.ktor.client.statement.bodyAsText
|
|
||||||
import io.ktor.client.statement.readText
|
|
||||||
import kotlinx.serialization.json.Json
|
import kotlinx.serialization.json.Json
|
||||||
|
|
||||||
@RiskFeature
|
/**
|
||||||
fun createTelegramBotDefaultKtorCallRequestsFactories() = listOf(
|
* Represents default [BaseRequestsExecutor] working on [Ktor](https://ktor.io) [HttpClient]
|
||||||
SimpleRequestCallFactory(),
|
*
|
||||||
MultipartRequestCallFactory(),
|
* * On JS, JVM and MingwX64 platforms it is [dev.inmo.tgbotapi.bot.ktor.base.DefaultKtorRequestsExecutor]
|
||||||
DownloadFileRequestCallFactory,
|
* * On LinuxX64 it is [dev.inmo.tgbotapi.bot.ktor.base.MultipleClientKtorRequestsExecutor]
|
||||||
DownloadFileChannelRequestCallFactory
|
*/
|
||||||
)
|
expect class KtorRequestsExecutor (
|
||||||
|
|
||||||
class KtorRequestsExecutor(
|
|
||||||
telegramAPIUrlsKeeper: TelegramAPIUrlsKeeper,
|
telegramAPIUrlsKeeper: TelegramAPIUrlsKeeper,
|
||||||
client: HttpClient = HttpClient(),
|
client: HttpClient = HttpClient(),
|
||||||
callsFactories: List<KtorCallFactory> = emptyList(),
|
callsFactories: List<KtorCallFactory> = emptyList(),
|
||||||
excludeDefaultFactories: Boolean = false,
|
excludeDefaultFactories: Boolean = false,
|
||||||
private val requestsLimiter: RequestLimiter = ExceptionsOnlyLimiter,
|
requestsLimiter: RequestLimiter = ExceptionsOnlyLimiter,
|
||||||
private val jsonFormatter: Json = nonstrictJsonFormat,
|
jsonFormatter: Json = nonstrictJsonFormat,
|
||||||
private val pipelineStepsHolder: KtorPipelineStepsHolder = KtorPipelineStepsHolder
|
pipelineStepsHolder: KtorPipelineStepsHolder = KtorPipelineStepsHolder
|
||||||
) : BaseRequestsExecutor(telegramAPIUrlsKeeper) {
|
) : BaseRequestsExecutor
|
||||||
private val callsFactories: List<KtorCallFactory> = callsFactories.run {
|
|
||||||
if (!excludeDefaultFactories) {
|
|
||||||
this + createTelegramBotDefaultKtorCallRequestsFactories()
|
|
||||||
} else {
|
|
||||||
this
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private val client = client.config {
|
|
||||||
if (client.pluginOrNull(HttpTimeout) == null) {
|
|
||||||
install(HttpTimeout)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override suspend fun <T : Any> execute(request: Request<T>): T {
|
|
||||||
return runCatchingSafely {
|
|
||||||
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(
|
|
||||||
client,
|
|
||||||
telegramAPIUrlsKeeper,
|
|
||||||
request,
|
|
||||||
jsonFormatter
|
|
||||||
)
|
|
||||||
result = pipelineStepsHolder.onAfterCallFactoryMakeCall(result, request, potentialFactory)
|
|
||||||
if (result != null) {
|
|
||||||
factoryHandledRequest = potentialFactory
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
result ?.let {
|
|
||||||
pipelineStepsHolder.onRequestResultPresented(it, request, factoryHandledRequest, callsFactories)
|
|
||||||
} ?: pipelineStepsHolder.onRequestResultAbsent(request, callsFactories) ?: error("Can't execute request: $request")
|
|
||||||
}
|
|
||||||
}.let {
|
|
||||||
val result = it.exceptionOrNull() ?.let { e ->
|
|
||||||
pipelineStepsHolder.onRequestException(request, e) ?.let { return@let it }
|
|
||||||
|
|
||||||
when (e) {
|
|
||||||
is ClientRequestException -> {
|
|
||||||
val exceptionResult = runCatchingSafely {
|
|
||||||
val content = e.response.bodyAsText()
|
|
||||||
val responseObject = jsonFormatter.decodeFromString(Response.serializer(), content)
|
|
||||||
newRequestException(
|
|
||||||
responseObject,
|
|
||||||
content,
|
|
||||||
"Can't get result object from $content"
|
|
||||||
)
|
|
||||||
}
|
|
||||||
exceptionResult.exceptionOrNull() ?.let {
|
|
||||||
CommonBotException(cause = e)
|
|
||||||
} ?: exceptionResult.getOrThrow()
|
|
||||||
}
|
|
||||||
is BotException -> e
|
|
||||||
else -> CommonBotException(cause = e)
|
|
||||||
}
|
|
||||||
} ?.let { Result.failure(it) } ?: it
|
|
||||||
pipelineStepsHolder.onRequestReturnResult(result, request, callsFactories)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun close() {
|
|
||||||
client.close()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class KtorRequestsExecutorBuilder(
|
|
||||||
var telegramAPIUrlsKeeper: TelegramAPIUrlsKeeper
|
|
||||||
) {
|
|
||||||
var client: HttpClient = HttpClient()
|
|
||||||
var callsFactories: List<KtorCallFactory> = emptyList()
|
|
||||||
var excludeDefaultFactories: Boolean = false
|
|
||||||
var requestsLimiter: RequestLimiter = ExceptionsOnlyLimiter
|
|
||||||
var jsonFormatter: Json = nonstrictJsonFormat
|
|
||||||
|
|
||||||
fun build() = KtorRequestsExecutor(telegramAPIUrlsKeeper, client, callsFactories, excludeDefaultFactories, requestsLimiter, jsonFormatter)
|
|
||||||
}
|
|
||||||
|
|
||||||
inline fun telegramBot(
|
|
||||||
telegramAPIUrlsKeeper: TelegramAPIUrlsKeeper,
|
|
||||||
builder: KtorRequestsExecutorBuilder.() -> Unit = {}
|
|
||||||
): TelegramBot = KtorRequestsExecutorBuilder(telegramAPIUrlsKeeper).apply(builder).build()
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Shortcut for [telegramBot]
|
|
||||||
*/
|
|
||||||
@Suppress("NOTHING_TO_INLINE")
|
|
||||||
inline fun telegramBot(
|
|
||||||
token: String,
|
|
||||||
apiUrl: String = telegramBotAPIDefaultUrl,
|
|
||||||
testServer: Boolean = false,
|
|
||||||
builder: KtorRequestsExecutorBuilder.() -> Unit = {}
|
|
||||||
): TelegramBot = telegramBot(TelegramAPIUrlsKeeper(token, testServer, apiUrl), builder)
|
|
||||||
|
|||||||
@@ -0,0 +1,54 @@
|
|||||||
|
package dev.inmo.tgbotapi.bot.ktor
|
||||||
|
|
||||||
|
import dev.inmo.tgbotapi.bot.BaseRequestsExecutor
|
||||||
|
import dev.inmo.tgbotapi.bot.TelegramBot
|
||||||
|
import dev.inmo.tgbotapi.bot.ktor.base.*
|
||||||
|
import dev.inmo.tgbotapi.bot.settings.limiters.ExceptionsOnlyLimiter
|
||||||
|
import dev.inmo.tgbotapi.bot.settings.limiters.RequestLimiter
|
||||||
|
import dev.inmo.tgbotapi.utils.*
|
||||||
|
import io.ktor.client.HttpClient
|
||||||
|
import kotlinx.serialization.json.Json
|
||||||
|
|
||||||
|
@RiskFeature
|
||||||
|
fun createTelegramBotDefaultKtorCallRequestsFactories() = listOf(
|
||||||
|
SimpleRequestCallFactory(),
|
||||||
|
MultipartRequestCallFactory(),
|
||||||
|
DownloadFileRequestCallFactory,
|
||||||
|
DownloadFileChannelRequestCallFactory
|
||||||
|
)
|
||||||
|
|
||||||
|
class KtorRequestsExecutorBuilder(
|
||||||
|
var telegramAPIUrlsKeeper: TelegramAPIUrlsKeeper
|
||||||
|
) {
|
||||||
|
var client: HttpClient = HttpClient()
|
||||||
|
var callsFactories: List<KtorCallFactory> = emptyList()
|
||||||
|
var excludeDefaultFactories: Boolean = false
|
||||||
|
var requestsLimiter: RequestLimiter = ExceptionsOnlyLimiter
|
||||||
|
var jsonFormatter: Json = nonstrictJsonFormat
|
||||||
|
|
||||||
|
fun build() = KtorRequestsExecutor(
|
||||||
|
telegramAPIUrlsKeeper,
|
||||||
|
client,
|
||||||
|
callsFactories,
|
||||||
|
excludeDefaultFactories,
|
||||||
|
requestsLimiter,
|
||||||
|
jsonFormatter
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
inline fun telegramBot(
|
||||||
|
telegramAPIUrlsKeeper: TelegramAPIUrlsKeeper,
|
||||||
|
builder: KtorRequestsExecutorBuilder.() -> Unit = {}
|
||||||
|
): TelegramBot = KtorRequestsExecutorBuilder(telegramAPIUrlsKeeper).apply(builder).build()
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Shortcut for [telegramBot]
|
||||||
|
*/
|
||||||
|
@Suppress("NOTHING_TO_INLINE")
|
||||||
|
inline fun telegramBot(
|
||||||
|
token: String,
|
||||||
|
apiUrl: String = telegramBotAPIDefaultUrl,
|
||||||
|
testServer: Boolean = false,
|
||||||
|
builder: KtorRequestsExecutorBuilder.() -> Unit = {}
|
||||||
|
): TelegramBot = telegramBot(TelegramAPIUrlsKeeper(token, testServer, apiUrl), builder)
|
||||||
|
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
package dev.inmo.tgbotapi.bot.ktor.base
|
package dev.inmo.tgbotapi.bot.ktor.base
|
||||||
|
|
||||||
import dev.inmo.micro_utils.coroutines.safelyWithResult
|
import dev.inmo.micro_utils.coroutines.runCatchingSafely
|
||||||
import dev.inmo.tgbotapi.bot.ktor.KtorCallFactory
|
import dev.inmo.tgbotapi.bot.ktor.KtorCallFactory
|
||||||
import dev.inmo.tgbotapi.bot.exceptions.newRequestException
|
import dev.inmo.tgbotapi.bot.exceptions.newRequestException
|
||||||
import dev.inmo.tgbotapi.requests.GetUpdates
|
import dev.inmo.tgbotapi.requests.GetUpdates
|
||||||
@@ -56,7 +56,7 @@ abstract class AbstractRequestCallFactory : KtorCallFactory {
|
|||||||
val content = response.bodyAsText()
|
val content = response.bodyAsText()
|
||||||
val responseObject = jsonFormatter.decodeFromString(Response.serializer(), content)
|
val responseObject = jsonFormatter.decodeFromString(Response.serializer(), content)
|
||||||
|
|
||||||
return safelyWithResult {
|
return runCatchingSafely {
|
||||||
(responseObject.result?.let {
|
(responseObject.result?.let {
|
||||||
jsonFormatter.decodeFromJsonElement(request.resultDeserializer, it)
|
jsonFormatter.decodeFromJsonElement(request.resultDeserializer, it)
|
||||||
} ?: response.let {
|
} ?: response.let {
|
||||||
|
|||||||
@@ -0,0 +1,100 @@
|
|||||||
|
package dev.inmo.tgbotapi.bot.ktor.base
|
||||||
|
|
||||||
|
import dev.inmo.micro_utils.coroutines.runCatchingSafely
|
||||||
|
import dev.inmo.tgbotapi.bot.BaseRequestsExecutor
|
||||||
|
import dev.inmo.tgbotapi.bot.exceptions.BotException
|
||||||
|
import dev.inmo.tgbotapi.bot.exceptions.CommonBotException
|
||||||
|
import dev.inmo.tgbotapi.bot.exceptions.newRequestException
|
||||||
|
import dev.inmo.tgbotapi.bot.ktor.KtorCallFactory
|
||||||
|
import dev.inmo.tgbotapi.bot.ktor.KtorPipelineStepsHolder
|
||||||
|
import dev.inmo.tgbotapi.bot.ktor.createTelegramBotDefaultKtorCallRequestsFactories
|
||||||
|
import dev.inmo.tgbotapi.bot.settings.limiters.ExceptionsOnlyLimiter
|
||||||
|
import dev.inmo.tgbotapi.bot.settings.limiters.RequestLimiter
|
||||||
|
import dev.inmo.tgbotapi.requests.abstracts.Request
|
||||||
|
import dev.inmo.tgbotapi.types.Response
|
||||||
|
import dev.inmo.tgbotapi.utils.TelegramAPIUrlsKeeper
|
||||||
|
import dev.inmo.tgbotapi.utils.nonstrictJsonFormat
|
||||||
|
import io.ktor.client.*
|
||||||
|
import io.ktor.client.plugins.*
|
||||||
|
import io.ktor.client.statement.*
|
||||||
|
import kotlinx.serialization.json.Json
|
||||||
|
|
||||||
|
class DefaultKtorRequestsExecutor(
|
||||||
|
telegramAPIUrlsKeeper: TelegramAPIUrlsKeeper,
|
||||||
|
client: HttpClient = HttpClient(),
|
||||||
|
callsFactories: List<KtorCallFactory> = emptyList(),
|
||||||
|
excludeDefaultFactories: Boolean = false,
|
||||||
|
private val requestsLimiter: RequestLimiter = ExceptionsOnlyLimiter,
|
||||||
|
private val jsonFormatter: Json = nonstrictJsonFormat,
|
||||||
|
private val pipelineStepsHolder: KtorPipelineStepsHolder = KtorPipelineStepsHolder
|
||||||
|
) : BaseRequestsExecutor(telegramAPIUrlsKeeper) {
|
||||||
|
private val callsFactories: List<KtorCallFactory> = callsFactories.run {
|
||||||
|
if (!excludeDefaultFactories) {
|
||||||
|
this + createTelegramBotDefaultKtorCallRequestsFactories()
|
||||||
|
} else {
|
||||||
|
this
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private val client = client.config {
|
||||||
|
if (client.pluginOrNull(HttpTimeout) == null) {
|
||||||
|
install(HttpTimeout)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override suspend fun <T : Any> execute(request: Request<T>): T {
|
||||||
|
return runCatchingSafely {
|
||||||
|
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(
|
||||||
|
client,
|
||||||
|
telegramAPIUrlsKeeper,
|
||||||
|
request,
|
||||||
|
jsonFormatter
|
||||||
|
)
|
||||||
|
result = pipelineStepsHolder.onAfterCallFactoryMakeCall(result, request, potentialFactory)
|
||||||
|
if (result != null) {
|
||||||
|
factoryHandledRequest = potentialFactory
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
result ?.let {
|
||||||
|
pipelineStepsHolder.onRequestResultPresented(it, request, factoryHandledRequest, callsFactories)
|
||||||
|
} ?: pipelineStepsHolder.onRequestResultAbsent(request, callsFactories) ?: error("Can't execute request: $request")
|
||||||
|
}
|
||||||
|
}.let {
|
||||||
|
val result = it.exceptionOrNull() ?.let { e ->
|
||||||
|
pipelineStepsHolder.onRequestException(request, e) ?.let { return@let it }
|
||||||
|
|
||||||
|
when (e) {
|
||||||
|
is ClientRequestException -> {
|
||||||
|
val exceptionResult = runCatchingSafely {
|
||||||
|
val content = e.response.bodyAsText()
|
||||||
|
val responseObject = jsonFormatter.decodeFromString(Response.serializer(), content)
|
||||||
|
newRequestException(
|
||||||
|
responseObject,
|
||||||
|
content,
|
||||||
|
"Can't get result object from $content"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
exceptionResult.exceptionOrNull() ?.let {
|
||||||
|
CommonBotException(cause = e)
|
||||||
|
} ?: exceptionResult.getOrThrow()
|
||||||
|
}
|
||||||
|
is BotException -> e
|
||||||
|
else -> CommonBotException(cause = e)
|
||||||
|
}
|
||||||
|
} ?.let { Result.failure(it) } ?: it
|
||||||
|
pipelineStepsHolder.onRequestReturnResult(result, request, callsFactories)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun close() {
|
||||||
|
client.close()
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -4,8 +4,7 @@ import dev.inmo.tgbotapi.requests.abstracts.*
|
|||||||
import dev.inmo.tgbotapi.utils.TelegramAPIUrlsKeeper
|
import dev.inmo.tgbotapi.utils.TelegramAPIUrlsKeeper
|
||||||
import dev.inmo.tgbotapi.utils.mapWithCommonValues
|
import dev.inmo.tgbotapi.utils.mapWithCommonValues
|
||||||
import io.ktor.client.HttpClient
|
import io.ktor.client.HttpClient
|
||||||
import io.ktor.client.request.forms.MultiPartFormDataContent
|
import io.ktor.client.request.forms.*
|
||||||
import io.ktor.client.request.forms.formData
|
|
||||||
import io.ktor.http.Headers
|
import io.ktor.http.Headers
|
||||||
import io.ktor.http.HttpHeaders
|
import io.ktor.http.HttpHeaders
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,118 @@
|
|||||||
|
package dev.inmo.tgbotapi.bot.ktor.base
|
||||||
|
|
||||||
|
import dev.inmo.micro_utils.coroutines.runCatchingSafely
|
||||||
|
import dev.inmo.tgbotapi.bot.BaseRequestsExecutor
|
||||||
|
import dev.inmo.tgbotapi.bot.ktor.KtorCallFactory
|
||||||
|
import dev.inmo.tgbotapi.bot.ktor.KtorPipelineStepsHolder
|
||||||
|
import dev.inmo.tgbotapi.bot.settings.limiters.RequestLimiter
|
||||||
|
import dev.inmo.tgbotapi.requests.abstracts.Request
|
||||||
|
import dev.inmo.tgbotapi.utils.TelegramAPIUrlsKeeper
|
||||||
|
import io.ktor.client.*
|
||||||
|
import kotlinx.coroutines.flow.MutableStateFlow
|
||||||
|
import kotlinx.coroutines.flow.first
|
||||||
|
import kotlinx.coroutines.flow.mapNotNull
|
||||||
|
import kotlinx.coroutines.sync.Mutex
|
||||||
|
import kotlinx.coroutines.sync.withLock
|
||||||
|
import kotlinx.serialization.json.Json
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This function is used in default constructor of [MultipleClientKtorRequestsExecutor] and on all non-native
|
||||||
|
* platforms and MingwX64 should return [client]
|
||||||
|
*
|
||||||
|
* On LinuxX64 it will create copy with Curl engine or throw an exception if engine is different with Curl
|
||||||
|
*
|
||||||
|
* @throws IllegalArgumentException When pass non Curl-based [HttpClient] on LinuxX64
|
||||||
|
*/
|
||||||
|
internal expect inline fun platformClientCopy(client: HttpClient): HttpClient
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Will use its parameters of constructor to create several [DefaultKtorRequestsExecutor] and use them in [execute]
|
||||||
|
* and [close] operations
|
||||||
|
*
|
||||||
|
* This [BaseRequestsExecutor] has been created for LinuxX64 target due to its inability of requests paralleling
|
||||||
|
*
|
||||||
|
* Under the hood on each [execute] it will take [DefaultKtorRequestsExecutor] and mark it as busy, execute
|
||||||
|
* [Request], free up taken [DefaultKtorRequestsExecutor] and return (or throw) the result of execution
|
||||||
|
*
|
||||||
|
* @param requestExecutorsCount Amount of [DefaultKtorRequestsExecutor] which will be created and used under the
|
||||||
|
* hood
|
||||||
|
*/
|
||||||
|
class MultipleClientKtorRequestsExecutor (
|
||||||
|
telegramAPIUrlsKeeper: TelegramAPIUrlsKeeper,
|
||||||
|
callsFactories: List<KtorCallFactory>,
|
||||||
|
excludeDefaultFactories: Boolean,
|
||||||
|
requestsLimiter: RequestLimiter,
|
||||||
|
jsonFormatter: Json,
|
||||||
|
pipelineStepsHolder: KtorPipelineStepsHolder,
|
||||||
|
requestExecutorsCount: Int,
|
||||||
|
clientFactory: () -> HttpClient
|
||||||
|
) : BaseRequestsExecutor(telegramAPIUrlsKeeper) {
|
||||||
|
private val requestExecutors = (0 until requestExecutorsCount).map {
|
||||||
|
DefaultKtorRequestsExecutor(
|
||||||
|
telegramAPIUrlsKeeper,
|
||||||
|
clientFactory(),
|
||||||
|
callsFactories,
|
||||||
|
excludeDefaultFactories,
|
||||||
|
requestsLimiter,
|
||||||
|
jsonFormatter,
|
||||||
|
pipelineStepsHolder
|
||||||
|
)
|
||||||
|
}.toSet()
|
||||||
|
private val freeClients = MutableStateFlow<Set<DefaultKtorRequestsExecutor>>(requestExecutors)
|
||||||
|
private val clientAllocationMutex = Mutex()
|
||||||
|
private val takerFlow = freeClients.mapNotNull {
|
||||||
|
clientAllocationMutex.withLock {
|
||||||
|
freeClients.value.firstOrNull() ?.also {
|
||||||
|
freeClients.value -= it
|
||||||
|
} ?: return@mapNotNull null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
telegramAPIUrlsKeeper: TelegramAPIUrlsKeeper,
|
||||||
|
client: HttpClient,
|
||||||
|
callsFactories: List<KtorCallFactory>,
|
||||||
|
excludeDefaultFactories: Boolean,
|
||||||
|
requestsLimiter: RequestLimiter,
|
||||||
|
jsonFormatter: Json,
|
||||||
|
pipelineStepsHolder: KtorPipelineStepsHolder
|
||||||
|
) : this(
|
||||||
|
telegramAPIUrlsKeeper,
|
||||||
|
callsFactories,
|
||||||
|
excludeDefaultFactories,
|
||||||
|
requestsLimiter,
|
||||||
|
jsonFormatter,
|
||||||
|
pipelineStepsHolder,
|
||||||
|
client.engineConfig.threadsCount,
|
||||||
|
{ platformClientCopy(client) }
|
||||||
|
)
|
||||||
|
|
||||||
|
private suspend fun prepareRequestsExecutor(): DefaultKtorRequestsExecutor {
|
||||||
|
return takerFlow.first()
|
||||||
|
}
|
||||||
|
|
||||||
|
private suspend fun freeRequestsExecutor(client: DefaultKtorRequestsExecutor) {
|
||||||
|
clientAllocationMutex.withLock {
|
||||||
|
freeClients.value += client
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private suspend fun <T> withRequestExecutor(block: suspend (DefaultKtorRequestsExecutor) -> T): T {
|
||||||
|
val requestsExecutor = prepareRequestsExecutor()
|
||||||
|
val result = runCatchingSafely {
|
||||||
|
block(requestsExecutor)
|
||||||
|
}
|
||||||
|
freeRequestsExecutor(requestsExecutor)
|
||||||
|
return result.getOrThrow()
|
||||||
|
}
|
||||||
|
|
||||||
|
override suspend fun <T : Any> execute(request: Request<T>): T = withRequestExecutor {
|
||||||
|
it.execute(request)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun close() {
|
||||||
|
requestExecutors.forEach {
|
||||||
|
it.close()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,18 +1,27 @@
|
|||||||
package dev.inmo.tgbotapi.bot.settings.limiters
|
package dev.inmo.tgbotapi.bot.settings.limiters
|
||||||
|
|
||||||
|
import dev.inmo.micro_utils.coroutines.runCatchingSafely
|
||||||
import dev.inmo.tgbotapi.bot.exceptions.TooMuchRequestsException
|
import dev.inmo.tgbotapi.bot.exceptions.TooMuchRequestsException
|
||||||
import kotlinx.coroutines.delay
|
import kotlinx.coroutines.delay
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Simple limiter which will lock any request when [TooMuchRequestsExceptions] is thrown and rerun request after lock time
|
* Simple limiter which will lock any request when [TooMuchRequestsException] is thrown and rerun request after lock time
|
||||||
*/
|
*/
|
||||||
object ExceptionsOnlyLimiter : RequestLimiter {
|
object ExceptionsOnlyLimiter : RequestLimiter {
|
||||||
override suspend fun <T> limit(block: suspend () -> T): T {
|
override suspend fun <T> limit(block: suspend () -> T): T {
|
||||||
return try {
|
var result: Result<T>? = null
|
||||||
block()
|
while (result == null || result.isFailure) {
|
||||||
} catch (e: TooMuchRequestsException) {
|
result = runCatchingSafely {
|
||||||
delay(e.retryAfter.leftToRetry)
|
block()
|
||||||
limit(block)
|
}.onFailure {
|
||||||
|
it.printStackTrace()
|
||||||
|
if (it is TooMuchRequestsException) {
|
||||||
|
delay(it.retryAfter.leftToRetry)
|
||||||
|
} else {
|
||||||
|
throw it
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
return result.getOrThrow()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,11 +23,30 @@ data class AnswerInlineQuery(
|
|||||||
val isPersonal: Boolean? = null,
|
val isPersonal: Boolean? = null,
|
||||||
@SerialName(nextOffsetField)
|
@SerialName(nextOffsetField)
|
||||||
val nextOffset: String? = null,
|
val nextOffset: String? = null,
|
||||||
@SerialName(switchPmTextField)
|
@SerialName(buttonField)
|
||||||
val switchPmText: String? = null,
|
val button: InlineQueryResultsButton? = null,
|
||||||
@SerialName(switchPmParameterField)
|
|
||||||
val switchPmParameter: String? = null
|
|
||||||
) : SimpleRequest<Boolean> {
|
) : SimpleRequest<Boolean> {
|
||||||
|
constructor(
|
||||||
|
inlineQueryID: InlineQueryIdentifier,
|
||||||
|
results: List<InlineQueryResult> = emptyList(),
|
||||||
|
cachedTime: Int? = null,
|
||||||
|
isPersonal: Boolean? = null,
|
||||||
|
nextOffset: String? = null,
|
||||||
|
switchPmText: String?,
|
||||||
|
switchPmParameter: String?
|
||||||
|
) : this(
|
||||||
|
inlineQueryID,
|
||||||
|
results,
|
||||||
|
cachedTime,
|
||||||
|
isPersonal,
|
||||||
|
nextOffset,
|
||||||
|
switchPmText ?.let {
|
||||||
|
switchPmParameter ?.let {
|
||||||
|
InlineQueryResultsButton.Start(switchPmText, switchPmParameter)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
override fun method(): String = "answerInlineQuery"
|
override fun method(): String = "answerInlineQuery"
|
||||||
override val resultDeserializer: DeserializationStrategy<Boolean>
|
override val resultDeserializer: DeserializationStrategy<Boolean>
|
||||||
get() = Boolean.serializer()
|
get() = Boolean.serializer()
|
||||||
@@ -40,8 +59,23 @@ fun InlineQuery.createAnswer(
|
|||||||
cachedTime: Int? = null,
|
cachedTime: Int? = null,
|
||||||
isPersonal: Boolean? = null,
|
isPersonal: Boolean? = null,
|
||||||
nextOffset: String? = null,
|
nextOffset: String? = null,
|
||||||
switchPmText: String? = null,
|
button: InlineQueryResultsButton? = null,
|
||||||
switchPmParameter: String? = null
|
) = AnswerInlineQuery(
|
||||||
|
id,
|
||||||
|
results,
|
||||||
|
cachedTime,
|
||||||
|
isPersonal,
|
||||||
|
nextOffset,
|
||||||
|
button
|
||||||
|
)
|
||||||
|
|
||||||
|
fun InlineQuery.createAnswer(
|
||||||
|
results: List<InlineQueryResult> = emptyList(),
|
||||||
|
cachedTime: Int? = null,
|
||||||
|
isPersonal: Boolean? = null,
|
||||||
|
nextOffset: String? = null,
|
||||||
|
switchPmText: String?,
|
||||||
|
switchPmParameter: String?
|
||||||
) = AnswerInlineQuery(
|
) = AnswerInlineQuery(
|
||||||
id,
|
id,
|
||||||
results,
|
results,
|
||||||
|
|||||||
@@ -0,0 +1,89 @@
|
|||||||
|
package dev.inmo.tgbotapi.requests.answers
|
||||||
|
|
||||||
|
import dev.inmo.micro_utils.common.Warning
|
||||||
|
import dev.inmo.tgbotapi.types.StartParameter
|
||||||
|
import dev.inmo.tgbotapi.types.startParameterField
|
||||||
|
import dev.inmo.tgbotapi.types.textField
|
||||||
|
import dev.inmo.tgbotapi.types.webAppField
|
||||||
|
import dev.inmo.tgbotapi.types.webapps.WebAppInfo
|
||||||
|
import dev.inmo.tgbotapi.utils.internal.ClassCastsIncluded
|
||||||
|
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(InlineQueryResultsButtonSerializer::class)
|
||||||
|
@ClassCastsIncluded
|
||||||
|
sealed interface InlineQueryResultsButton {
|
||||||
|
val text: String
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
class Raw internal constructor(
|
||||||
|
@SerialName(textField)
|
||||||
|
val text: String,
|
||||||
|
@SerialName(webAppField)
|
||||||
|
val webAppInfo: WebAppInfo? = null,
|
||||||
|
@SerialName(startParameterField)
|
||||||
|
val deepLinkParameter: String? = null
|
||||||
|
)
|
||||||
|
|
||||||
|
@Serializable(InlineQueryResultsButtonSerializer::class)
|
||||||
|
data class WebApp(
|
||||||
|
@SerialName(textField)
|
||||||
|
override val text: String,
|
||||||
|
@SerialName(webAppField)
|
||||||
|
val webAppInfo: WebAppInfo
|
||||||
|
) : InlineQueryResultsButton
|
||||||
|
|
||||||
|
@Serializable(InlineQueryResultsButtonSerializer::class)
|
||||||
|
data class Start(
|
||||||
|
@SerialName(textField)
|
||||||
|
override val text: String,
|
||||||
|
@SerialName(startParameterField)
|
||||||
|
val deepLinkParameter: String
|
||||||
|
) : InlineQueryResultsButton
|
||||||
|
|
||||||
|
@Serializable(InlineQueryResultsButtonSerializer::class)
|
||||||
|
data class Unknown internal constructor (
|
||||||
|
@SerialName(textField)
|
||||||
|
override val text: String
|
||||||
|
) : InlineQueryResultsButton
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
operator fun invoke(
|
||||||
|
text: String,
|
||||||
|
deepLinkParameter: String
|
||||||
|
) = Start(text, deepLinkParameter)
|
||||||
|
operator fun invoke(
|
||||||
|
text: String,
|
||||||
|
webAppInfo: WebAppInfo
|
||||||
|
) = WebApp(text, webAppInfo)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
object InlineQueryResultsButtonSerializer : KSerializer<InlineQueryResultsButton> {
|
||||||
|
override val descriptor: SerialDescriptor = InlineQueryResultsButton.Raw.serializer().descriptor
|
||||||
|
|
||||||
|
override fun deserialize(decoder: Decoder): InlineQueryResultsButton {
|
||||||
|
val raw = InlineQueryResultsButton.Raw.serializer().deserialize(decoder)
|
||||||
|
|
||||||
|
return when {
|
||||||
|
raw.webAppInfo != null -> InlineQueryResultsButton.WebApp(raw.text, raw.webAppInfo)
|
||||||
|
raw.deepLinkParameter != null -> InlineQueryResultsButton.Start(raw.text, raw.deepLinkParameter)
|
||||||
|
else -> InlineQueryResultsButton.Unknown(raw.text)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun serialize(encoder: Encoder, value: InlineQueryResultsButton) {
|
||||||
|
InlineQueryResultsButton.Raw.serializer().serialize(
|
||||||
|
encoder,
|
||||||
|
InlineQueryResultsButton.Raw(
|
||||||
|
value.text,
|
||||||
|
(value as? InlineQueryResultsButton.WebApp)?.webAppInfo,
|
||||||
|
(value as? InlineQueryResultsButton.Start)?.deepLinkParameter,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
package dev.inmo.tgbotapi.requests.bot
|
||||||
|
|
||||||
|
import dev.inmo.micro_utils.language_codes.IetfLanguageCode
|
||||||
|
import dev.inmo.micro_utils.language_codes.IetfLanguageCodeSerializer
|
||||||
|
import dev.inmo.tgbotapi.requests.abstracts.SimpleRequest
|
||||||
|
import dev.inmo.tgbotapi.types.*
|
||||||
|
import dev.inmo.tgbotapi.types.abstracts.WithOptionalLanguageCode
|
||||||
|
import dev.inmo.tgbotapi.types.commands.*
|
||||||
|
import kotlinx.serialization.*
|
||||||
|
import kotlinx.serialization.builtins.serializer
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
class GetMyName(
|
||||||
|
@SerialName(languageCodeField)
|
||||||
|
@Serializable(IetfLanguageCodeSerializer::class)
|
||||||
|
override val ietfLanguageCode: IetfLanguageCode? = null
|
||||||
|
) : SimpleRequest<BotName>, WithOptionalLanguageCode {
|
||||||
|
override fun method(): String = "getMyName"
|
||||||
|
override val resultDeserializer: DeserializationStrategy<BotName>
|
||||||
|
get() = BotName.serializer()
|
||||||
|
override val requestSerializer: SerializationStrategy<*>
|
||||||
|
get() = serializer()
|
||||||
|
}
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
package dev.inmo.tgbotapi.requests.bot
|
||||||
|
|
||||||
|
import dev.inmo.micro_utils.language_codes.IetfLanguageCode
|
||||||
|
import dev.inmo.micro_utils.language_codes.IetfLanguageCodeSerializer
|
||||||
|
import dev.inmo.tgbotapi.requests.abstracts.SimpleRequest
|
||||||
|
import dev.inmo.tgbotapi.types.*
|
||||||
|
import dev.inmo.tgbotapi.types.abstracts.WithOptionalLanguageCode
|
||||||
|
import dev.inmo.tgbotapi.types.commands.*
|
||||||
|
import kotlinx.serialization.*
|
||||||
|
import kotlinx.serialization.builtins.serializer
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
class SetMyName(
|
||||||
|
@SerialName(nameField)
|
||||||
|
val name: String? = null,
|
||||||
|
@SerialName(languageCodeField)
|
||||||
|
@Serializable(IetfLanguageCodeSerializer::class)
|
||||||
|
override val ietfLanguageCode: IetfLanguageCode? = null
|
||||||
|
) : SimpleRequest<Boolean>, WithOptionalLanguageCode {
|
||||||
|
override fun method(): String = "setMyName"
|
||||||
|
override val resultDeserializer: DeserializationStrategy<Boolean>
|
||||||
|
get() = Boolean.serializer()
|
||||||
|
override val requestSerializer: SerializationStrategy<*>
|
||||||
|
get() = serializer()
|
||||||
|
}
|
||||||
@@ -19,7 +19,7 @@ data class GetChat(
|
|||||||
override val resultDeserializer: DeserializationStrategy<ExtendedChat> = if (chatId is ChatIdWithThreadId) {
|
override val resultDeserializer: DeserializationStrategy<ExtendedChat> = if (chatId is ChatIdWithThreadId) {
|
||||||
ExtendedChatSerializer.BasedOnForumThread(chatId.threadId)
|
ExtendedChatSerializer.BasedOnForumThread(chatId.threadId)
|
||||||
} else {
|
} else {
|
||||||
ExtendedChatSerializer
|
ExtendedChatSerializer.Companion
|
||||||
}
|
}
|
||||||
override val requestSerializer: SerializationStrategy<*>
|
override val requestSerializer: SerializationStrategy<*>
|
||||||
get() = serializer()
|
get() = serializer()
|
||||||
|
|||||||
@@ -0,0 +1,10 @@
|
|||||||
|
package dev.inmo.tgbotapi.types
|
||||||
|
|
||||||
|
import kotlinx.serialization.SerialName
|
||||||
|
import kotlinx.serialization.Serializable
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
data class BotName(
|
||||||
|
@SerialName(nameField)
|
||||||
|
val name: String
|
||||||
|
)
|
||||||
@@ -13,8 +13,9 @@ import kotlinx.serialization.json.JsonPrimitive
|
|||||||
import kotlinx.serialization.json.longOrNull
|
import kotlinx.serialization.json.longOrNull
|
||||||
import kotlin.jvm.JvmInline
|
import kotlin.jvm.JvmInline
|
||||||
|
|
||||||
|
const val internalTgAppLinksBeginning = "tg://"
|
||||||
const val internalLinkBeginning = "https://t.me"
|
const val internalLinkBeginning = "https://t.me"
|
||||||
const val internalUserLinkBeginning = "tg://user?id="
|
const val internalUserLinkBeginning = "${internalTgAppLinksBeginning}user?id="
|
||||||
|
|
||||||
@Serializable(ChatIdentifierSerializer::class)
|
@Serializable(ChatIdentifierSerializer::class)
|
||||||
@ClassCastsIncluded
|
@ClassCastsIncluded
|
||||||
|
|||||||
@@ -41,7 +41,10 @@ typealias WebAppQueryId = String
|
|||||||
@JvmInline
|
@JvmInline
|
||||||
value class CustomEmojiId(
|
value class CustomEmojiId(
|
||||||
val string: String
|
val string: String
|
||||||
)
|
) {
|
||||||
|
val appLink
|
||||||
|
get() = "${internalTgAppLinksBeginning}emoji?id=$this"
|
||||||
|
}
|
||||||
|
|
||||||
typealias Seconds = Int
|
typealias Seconds = Int
|
||||||
typealias MilliSeconds = Long
|
typealias MilliSeconds = Long
|
||||||
@@ -247,10 +250,15 @@ const val errorMessageField = "error_message"
|
|||||||
const val messageTextField = "message_text"
|
const val messageTextField = "message_text"
|
||||||
const val isPersonalField = "is_personal"
|
const val isPersonalField = "is_personal"
|
||||||
const val nextOffsetField = "next_offset"
|
const val nextOffsetField = "next_offset"
|
||||||
|
const val buttonField = "button"
|
||||||
const val switchPmTextField = "switch_pm_text"
|
const val switchPmTextField = "switch_pm_text"
|
||||||
const val switchPmParameterField = "switch_pm_parameter"
|
const val switchPmParameterField = "switch_pm_parameter"
|
||||||
const val maxAllowedConnectionsField = "max_connections"
|
const val maxAllowedConnectionsField = "max_connections"
|
||||||
const val allowedUpdatesField = "allowed_updates"
|
const val allowedUpdatesField = "allowed_updates"
|
||||||
|
const val allowUserChatsField = "allow_user_chats"
|
||||||
|
const val allowBotChatsField = "allow_bot_chats"
|
||||||
|
const val allowGroupChatsField = "allow_group_chats"
|
||||||
|
const val allowChannelChatsField = "allow_channel_chats"
|
||||||
const val dropPendingUpdatesField = "drop_pending_updates"
|
const val dropPendingUpdatesField = "drop_pending_updates"
|
||||||
const val secretTokenField = "secret_token"
|
const val secretTokenField = "secret_token"
|
||||||
const val hasCustomCertificateField = "has_custom_certificate"
|
const val hasCustomCertificateField = "has_custom_certificate"
|
||||||
@@ -271,10 +279,12 @@ const val loginUrlField = "login_url"
|
|||||||
const val forwardTextField = "forward_text"
|
const val forwardTextField = "forward_text"
|
||||||
const val botUsernameField = "bot_username"
|
const val botUsernameField = "bot_username"
|
||||||
const val switchInlineQueryCurrentChatField = "switch_inline_query_current_chat"
|
const val switchInlineQueryCurrentChatField = "switch_inline_query_current_chat"
|
||||||
|
const val switchInlineQueryChosenChatField = "switch_inline_query_chosen_chat"
|
||||||
const val switchInlineQueryField = "switch_inline_query"
|
const val switchInlineQueryField = "switch_inline_query"
|
||||||
const val isAnimatedField = "is_animated"
|
const val isAnimatedField = "is_animated"
|
||||||
const val isVideoField = "is_video"
|
const val isVideoField = "is_video"
|
||||||
const val inviteLinkField = "invite_link"
|
const val inviteLinkField = "invite_link"
|
||||||
|
const val viaChatFolderInviteLinkField = "via_chat_folder_invite_link"
|
||||||
const val pinnedMessageField = "pinned_message"
|
const val pinnedMessageField = "pinned_message"
|
||||||
const val activeUsernamesField = "active_usernames"
|
const val activeUsernamesField = "active_usernames"
|
||||||
const val customTitleField = "custom_title"
|
const val customTitleField = "custom_title"
|
||||||
@@ -596,4 +606,5 @@ const val temporaryRegistrationField = "temporary_registration"
|
|||||||
|
|
||||||
const val buttonTextField = "button_text"
|
const val buttonTextField = "button_text"
|
||||||
const val webAppField = "web_app"
|
const val webAppField = "web_app"
|
||||||
|
const val webAppNameField = "web_app_name"
|
||||||
const val menuButtonField = "menu_button"
|
const val menuButtonField = "menu_button"
|
||||||
|
|||||||
@@ -11,9 +11,15 @@ const val UPDATE_SHIPPING_QUERY = "shipping_query"
|
|||||||
const val UPDATE_PRE_CHECKOUT_QUERY = "pre_checkout_query"
|
const val UPDATE_PRE_CHECKOUT_QUERY = "pre_checkout_query"
|
||||||
const val UPDATE_POLL = "poll"
|
const val UPDATE_POLL = "poll"
|
||||||
const val UPDATE_POLL_ANSWER = "poll_answer"
|
const val UPDATE_POLL_ANSWER = "poll_answer"
|
||||||
const val MY_CHAT_MEMBER = "my_chat_member"
|
const val UPDATE_MY_CHAT_MEMBER = "my_chat_member"
|
||||||
const val CHAT_MEMBER = "chat_member"
|
const val UPDATE_CHAT_MEMBER = "chat_member"
|
||||||
const val CHAT_JOIN_REQUEST = "chat_join_request"
|
const val UPDATE_CHAT_JOIN_REQUEST = "chat_join_request"
|
||||||
|
@Deprecated("Renamed", ReplaceWith("UPDATE_MY_CHAT_MEMBER", "dev.inmo.tgbotapi.types.UPDATE_MY_CHAT_MEMBER"))
|
||||||
|
const val MY_CHAT_MEMBER = UPDATE_MY_CHAT_MEMBER
|
||||||
|
@Deprecated("Renamed", ReplaceWith("UPDATE_CHAT_MEMBER", "dev.inmo.tgbotapi.types.UPDATE_CHAT_MEMBER"))
|
||||||
|
const val CHAT_MEMBER = UPDATE_CHAT_MEMBER
|
||||||
|
@Deprecated("Renamed", ReplaceWith("UPDATE_CHAT_JOIN_REQUEST", "dev.inmo.tgbotapi.types.UPDATE_CHAT_JOIN_REQUEST"))
|
||||||
|
const val CHAT_JOIN_REQUEST = UPDATE_CHAT_JOIN_REQUEST
|
||||||
|
|
||||||
val ALL_UPDATES_LIST = listOf(
|
val ALL_UPDATES_LIST = listOf(
|
||||||
UPDATE_MESSAGE,
|
UPDATE_MESSAGE,
|
||||||
@@ -27,7 +33,7 @@ val ALL_UPDATES_LIST = listOf(
|
|||||||
UPDATE_PRE_CHECKOUT_QUERY,
|
UPDATE_PRE_CHECKOUT_QUERY,
|
||||||
UPDATE_POLL,
|
UPDATE_POLL,
|
||||||
UPDATE_POLL_ANSWER,
|
UPDATE_POLL_ANSWER,
|
||||||
MY_CHAT_MEMBER,
|
UPDATE_MY_CHAT_MEMBER,
|
||||||
CHAT_MEMBER,
|
UPDATE_CHAT_MEMBER,
|
||||||
CHAT_JOIN_REQUEST
|
UPDATE_CHAT_JOIN_REQUEST
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -98,6 +98,23 @@ data class SwitchInlineQueryCurrentChatInlineKeyboardButton(
|
|||||||
val switchInlineQueryCurrentChat: String
|
val switchInlineQueryCurrentChat: String
|
||||||
) : InlineKeyboardButton
|
) : InlineKeyboardButton
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Complex button with [switchInlineQueryCurrentChat] which will be sent to you in an [dev.inmo.tgbotapi.types.InlineQueries.query.InlineQuery]
|
||||||
|
* which you may catch in [dev.inmo.tgbotapi.extensions.behaviour_builder.triggers_handling.onBaseInlineQuery] and get
|
||||||
|
* from [dev.inmo.tgbotapi.types.InlineQueries.query.BaseInlineQuery.query] (or changed by user query in case he will be
|
||||||
|
* the fastest hand in the wild west). Can be forwarded in any chat with message in case if it is the only one button in
|
||||||
|
* message, but will be converted to a [SwitchInlineQueryInlineKeyboardButton].
|
||||||
|
* Remember that clicking on this button will automatically insert username of this bot in current chat, paste
|
||||||
|
* [switchInlineQueryCurrentChat] as a query and create and inline request to your bot
|
||||||
|
* Visit https://core.telegram.org/bots/api#inlinekeyboardbutton for more info
|
||||||
|
*/
|
||||||
|
@Serializable
|
||||||
|
data class SwitchInlineQueryChosenChatInlineKeyboardButton(
|
||||||
|
override val text: String,
|
||||||
|
@SerialName(switchInlineQueryChosenChatField)
|
||||||
|
val parameters: SwitchInlineQueryChosenChat
|
||||||
|
) : InlineKeyboardButton
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Complex button with [switchInlineQuery] which will be sent to you in an [dev.inmo.tgbotapi.types.InlineQueries.query.InlineQuery]
|
* Complex button with [switchInlineQuery] which will be sent to you in an [dev.inmo.tgbotapi.types.InlineQueries.query.InlineQuery]
|
||||||
* which you may catch in [dev.inmo.tgbotapi.extensions.behaviour_builder.triggers_handling.onBaseInlineQuery] and get
|
* which you may catch in [dev.inmo.tgbotapi.extensions.behaviour_builder.triggers_handling.onBaseInlineQuery] and get
|
||||||
|
|||||||
@@ -27,6 +27,7 @@ object InlineKeyboardButtonSerializer : KSerializer<InlineKeyboardButton> {
|
|||||||
json[payField] != null -> PayInlineKeyboardButton.serializer()
|
json[payField] != null -> PayInlineKeyboardButton.serializer()
|
||||||
json[switchInlineQueryField] != null -> SwitchInlineQueryInlineKeyboardButton.serializer()
|
json[switchInlineQueryField] != null -> SwitchInlineQueryInlineKeyboardButton.serializer()
|
||||||
json[switchInlineQueryCurrentChatField] != null -> SwitchInlineQueryCurrentChatInlineKeyboardButton.serializer()
|
json[switchInlineQueryCurrentChatField] != null -> SwitchInlineQueryCurrentChatInlineKeyboardButton.serializer()
|
||||||
|
json[switchInlineQueryChosenChatField] != null -> SwitchInlineQueryChosenChatInlineKeyboardButton.serializer()
|
||||||
json[urlField] != null -> URLInlineKeyboardButton.serializer()
|
json[urlField] != null -> URLInlineKeyboardButton.serializer()
|
||||||
else -> null
|
else -> null
|
||||||
}
|
}
|
||||||
@@ -47,6 +48,7 @@ object InlineKeyboardButtonSerializer : KSerializer<InlineKeyboardButton> {
|
|||||||
is PayInlineKeyboardButton -> PayInlineKeyboardButton.serializer().serialize(encoder, value)
|
is PayInlineKeyboardButton -> PayInlineKeyboardButton.serializer().serialize(encoder, value)
|
||||||
is SwitchInlineQueryInlineKeyboardButton -> SwitchInlineQueryInlineKeyboardButton.serializer().serialize(encoder, value)
|
is SwitchInlineQueryInlineKeyboardButton -> SwitchInlineQueryInlineKeyboardButton.serializer().serialize(encoder, value)
|
||||||
is SwitchInlineQueryCurrentChatInlineKeyboardButton -> SwitchInlineQueryCurrentChatInlineKeyboardButton.serializer().serialize(encoder, value)
|
is SwitchInlineQueryCurrentChatInlineKeyboardButton -> SwitchInlineQueryCurrentChatInlineKeyboardButton.serializer().serialize(encoder, value)
|
||||||
|
is SwitchInlineQueryChosenChatInlineKeyboardButton -> SwitchInlineQueryChosenChatInlineKeyboardButton.serializer().serialize(encoder, value)
|
||||||
is URLInlineKeyboardButton -> URLInlineKeyboardButton.serializer().serialize(encoder, value)
|
is URLInlineKeyboardButton -> URLInlineKeyboardButton.serializer().serialize(encoder, value)
|
||||||
is WebAppInlineKeyboardButton -> WebAppInlineKeyboardButton.serializer().serialize(encoder, value)
|
is WebAppInlineKeyboardButton -> WebAppInlineKeyboardButton.serializer().serialize(encoder, value)
|
||||||
is CallbackGameInlineKeyboardButton -> CallbackGameInlineKeyboardButton.serializer().serialize(encoder, value)
|
is CallbackGameInlineKeyboardButton -> CallbackGameInlineKeyboardButton.serializer().serialize(encoder, value)
|
||||||
|
|||||||
@@ -0,0 +1,32 @@
|
|||||||
|
package dev.inmo.tgbotapi.types.buttons.InlineKeyboardButtons
|
||||||
|
|
||||||
|
import dev.inmo.tgbotapi.types.*
|
||||||
|
import kotlinx.serialization.EncodeDefault
|
||||||
|
import kotlinx.serialization.ExperimentalSerializationApi
|
||||||
|
import kotlinx.serialization.SerialName
|
||||||
|
import kotlinx.serialization.Serializable
|
||||||
|
|
||||||
|
@OptIn(ExperimentalSerializationApi::class)
|
||||||
|
@Serializable
|
||||||
|
data class SwitchInlineQueryChosenChat (
|
||||||
|
@SerialName(queryField)
|
||||||
|
val query: String? = null,
|
||||||
|
@SerialName(allowUserChatsField)
|
||||||
|
@EncodeDefault
|
||||||
|
val allowUsers: Boolean = false,
|
||||||
|
@SerialName(allowBotChatsField)
|
||||||
|
@EncodeDefault
|
||||||
|
val allowBots: Boolean = false,
|
||||||
|
@SerialName(allowGroupChatsField)
|
||||||
|
@EncodeDefault
|
||||||
|
val allowGroups: Boolean = false,
|
||||||
|
@SerialName(allowChannelChatsField)
|
||||||
|
@EncodeDefault
|
||||||
|
val allowChannels: Boolean = false,
|
||||||
|
) {
|
||||||
|
init {
|
||||||
|
require(allowUsers || allowBots || allowGroups || allowChannels) {
|
||||||
|
"Bot must allow to choose at least one of available variants in choosing of inline query recipient"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -57,6 +57,52 @@ inline fun inlineQueryInCurrentChatInlineButton(
|
|||||||
data: String
|
data: String
|
||||||
) = SwitchInlineQueryCurrentChatInlineKeyboardButton(text, data)
|
) = SwitchInlineQueryCurrentChatInlineKeyboardButton(text, data)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates and put [SwitchInlineQueryChosenChatInlineKeyboardButton]
|
||||||
|
*
|
||||||
|
* @see inlineKeyboard
|
||||||
|
* @see InlineKeyboardBuilder.row
|
||||||
|
*/
|
||||||
|
inline fun inlineQueryInCurrentChatInlineButton(
|
||||||
|
text: String,
|
||||||
|
parameters: SwitchInlineQueryChosenChat
|
||||||
|
) = SwitchInlineQueryChosenChatInlineKeyboardButton(text, parameters)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates and put [SwitchInlineQueryChosenChatInlineKeyboardButton]
|
||||||
|
*
|
||||||
|
* @see inlineKeyboard
|
||||||
|
* @see InlineKeyboardBuilder.row
|
||||||
|
*/
|
||||||
|
inline fun inlineQueryInCurrentChatInlineButton(
|
||||||
|
text: String,
|
||||||
|
query: String? = null,
|
||||||
|
allowUsers: Boolean = false,
|
||||||
|
allowBots: Boolean = false,
|
||||||
|
allowGroups: Boolean = false,
|
||||||
|
allowChannels: Boolean = false,
|
||||||
|
) = inlineQueryInCurrentChatInlineButton(
|
||||||
|
text,
|
||||||
|
SwitchInlineQueryChosenChat(
|
||||||
|
query = query,
|
||||||
|
allowUsers = allowUsers,
|
||||||
|
allowBots = allowBots,
|
||||||
|
allowGroups = allowGroups,
|
||||||
|
allowChannels = allowChannels
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates and put [SwitchInlineQueryChosenChatInlineKeyboardButton]
|
||||||
|
*
|
||||||
|
* @see inlineKeyboard
|
||||||
|
* @see InlineKeyboardBuilder.row
|
||||||
|
*/
|
||||||
|
inline fun inlineQueryInAnyCurrentChatInlineButton(
|
||||||
|
text: String,
|
||||||
|
query: String? = null,
|
||||||
|
) = inlineQueryInCurrentChatInlineButton(text, query, allowUsers = true, allowBots = true, allowGroups = true, allowChannels = true)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates and put [SwitchInlineQueryInlineKeyboardButton]
|
* Creates and put [SwitchInlineQueryInlineKeyboardButton]
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -5,17 +5,17 @@ import dev.inmo.tgbotapi.types.message.abstracts.Message
|
|||||||
import dev.inmo.tgbotapi.types.message.abstracts.TelegramBotAPIMessageDeserializeOnlySerializer
|
import dev.inmo.tgbotapi.types.message.abstracts.TelegramBotAPIMessageDeserializeOnlySerializer
|
||||||
import kotlinx.serialization.Serializable
|
import kotlinx.serialization.Serializable
|
||||||
|
|
||||||
@Serializable(ExtendedChatSerializer::class)
|
@Serializable(ExtendedChatSerializer.Companion::class)
|
||||||
sealed interface ExtendedChannelChat : ChannelChat, ExtendedPublicChat, ExtendedChatWithUsername {
|
sealed interface ExtendedChannelChat : ChannelChat, ExtendedPublicChat, ExtendedChatWithUsername {
|
||||||
val linkedGroupChatId: IdChatIdentifier?
|
val linkedGroupChatId: IdChatIdentifier?
|
||||||
}
|
}
|
||||||
|
|
||||||
@Serializable(ExtendedChatSerializer::class)
|
@Serializable(ExtendedChatSerializer.Companion::class)
|
||||||
sealed interface ExtendedGroupChat : GroupChat, ExtendedPublicChat {
|
sealed interface ExtendedGroupChat : GroupChat, ExtendedPublicChat {
|
||||||
val permissions: ChatPermissions
|
val permissions: ChatPermissions
|
||||||
}
|
}
|
||||||
|
|
||||||
@Serializable(ExtendedChatSerializer::class)
|
@Serializable(ExtendedChatSerializer.Companion::class)
|
||||||
sealed interface ExtendedPrivateChat : PrivateChat, ExtendedChatWithUsername {
|
sealed interface ExtendedPrivateChat : PrivateChat, ExtendedChatWithUsername {
|
||||||
val bio: String
|
val bio: String
|
||||||
val hasPrivateForwards: Boolean
|
val hasPrivateForwards: Boolean
|
||||||
@@ -34,7 +34,7 @@ sealed interface ExtendedPublicChat : ExtendedChat, PublicChat {
|
|||||||
val membersHidden: Boolean
|
val membersHidden: Boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
@Serializable(ExtendedChatSerializer::class)
|
@Serializable(ExtendedChatSerializer.Companion::class)
|
||||||
sealed interface ExtendedSupergroupChat : SupergroupChat, ExtendedGroupChat, ExtendedChatWithUsername {
|
sealed interface ExtendedSupergroupChat : SupergroupChat, ExtendedGroupChat, ExtendedChatWithUsername {
|
||||||
val slowModeDelay: Long?
|
val slowModeDelay: Long?
|
||||||
val stickerSetName: StickerSetName?
|
val stickerSetName: StickerSetName?
|
||||||
@@ -58,15 +58,15 @@ sealed interface ExtendedSupergroupChat : SupergroupChat, ExtendedGroupChat, Ext
|
|||||||
val isAggressiveAntiSpamEnabled: Boolean
|
val isAggressiveAntiSpamEnabled: Boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
@Serializable(ExtendedChatSerializer::class)
|
@Serializable(ExtendedChatSerializer.Companion::class)
|
||||||
sealed interface ExtendedForumChat : ExtendedSupergroupChat, ForumChat
|
sealed interface ExtendedForumChat : ExtendedSupergroupChat, ForumChat
|
||||||
|
|
||||||
@Serializable(ExtendedChatSerializer::class)
|
@Serializable(ExtendedChatSerializer.Companion::class)
|
||||||
sealed interface ExtendedChat : Chat {
|
sealed interface ExtendedChat : Chat {
|
||||||
val chatPhoto: ChatPhoto?
|
val chatPhoto: ChatPhoto?
|
||||||
}
|
}
|
||||||
|
|
||||||
@Serializable(ExtendedChatSerializer::class)
|
@Serializable(ExtendedChatSerializer.Companion::class)
|
||||||
sealed interface ExtendedChatWithUsername : UsernameChat, ExtendedChat {
|
sealed interface ExtendedChatWithUsername : UsernameChat, ExtendedChat {
|
||||||
val activeUsernames: List<Username>
|
val activeUsernames: List<Username>
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,5 +21,7 @@ data class ChatMemberUpdated(
|
|||||||
@SerialName(newChatMemberField)
|
@SerialName(newChatMemberField)
|
||||||
val newChatMemberState: ChatMember,
|
val newChatMemberState: ChatMember,
|
||||||
@SerialName(inviteLinkField)
|
@SerialName(inviteLinkField)
|
||||||
val inviteLink: ChatInviteLink? = null
|
val inviteLink: ChatInviteLink? = null,
|
||||||
|
@SerialName(viaChatFolderInviteLinkField)
|
||||||
|
val viaChatFolderInviteLink: Boolean? = false
|
||||||
) : WithChat, WithUser
|
) : WithChat, WithUser
|
||||||
|
|||||||
@@ -1,7 +1,12 @@
|
|||||||
package dev.inmo.tgbotapi.types.message.ChatEvents.forum
|
package dev.inmo.tgbotapi.types.message.ChatEvents.forum
|
||||||
|
|
||||||
import dev.inmo.tgbotapi.types.message.ChatEvents.abstracts.ForumEvent
|
import dev.inmo.tgbotapi.types.message.ChatEvents.abstracts.ForumEvent
|
||||||
|
import dev.inmo.tgbotapi.types.webAppNameField
|
||||||
|
import kotlinx.serialization.SerialName
|
||||||
import kotlinx.serialization.Serializable
|
import kotlinx.serialization.Serializable
|
||||||
|
|
||||||
@Serializable
|
@Serializable
|
||||||
object WriteAccessAllowed : ForumEvent
|
data class WriteAccessAllowed(
|
||||||
|
@SerialName(webAppNameField)
|
||||||
|
val webAppName: String? = null
|
||||||
|
) : ForumEvent
|
||||||
|
|||||||
@@ -16,8 +16,8 @@ data class CustomEmojiTextSource @RiskFeature(DirectInvocationOfTextSourceConstr
|
|||||||
override val subsources: TextSourcesList
|
override val subsources: TextSourcesList
|
||||||
) : MultilevelTextSource {
|
) : MultilevelTextSource {
|
||||||
override val markdown: String by lazy { source.customEmojiMarkdown() }
|
override val markdown: String by lazy { source.customEmojiMarkdown() }
|
||||||
override val markdownV2: String by lazy { source.customEmojiMarkdownV2() }
|
override val markdownV2: String by lazy { source.customEmojiMarkdownV2(customEmojiId) }
|
||||||
override val html: String by lazy { source.customEmojiHTML() }
|
override val html: String by lazy { source.customEmojiHTML(customEmojiId) }
|
||||||
}
|
}
|
||||||
|
|
||||||
@Suppress("NOTHING_TO_INLINE", "EXPERIMENTAL_API_USAGE")
|
@Suppress("NOTHING_TO_INLINE", "EXPERIMENTAL_API_USAGE")
|
||||||
|
|||||||
@@ -1,37 +1,78 @@
|
|||||||
package dev.inmo.tgbotapi.types.message.textsources
|
package dev.inmo.tgbotapi.types.message.textsources
|
||||||
|
|
||||||
|
import dev.inmo.micro_utils.serialization.mapper.MapperSerializer
|
||||||
import dev.inmo.micro_utils.serialization.typed_serializer.TypedSerializer
|
import dev.inmo.micro_utils.serialization.typed_serializer.TypedSerializer
|
||||||
import kotlinx.serialization.KSerializer
|
import kotlinx.serialization.KSerializer
|
||||||
|
import kotlinx.serialization.encoding.CompositeEncoder
|
||||||
|
import kotlinx.serialization.encoding.Decoder
|
||||||
|
import kotlinx.serialization.encoding.Encoder
|
||||||
|
|
||||||
private val baseSerializers: Map<String, KSerializer<out TextSource>> = mapOf(
|
//private val baseSerializers: Map<String, KSerializer<out TextSource>> = mapOf(
|
||||||
"regular" to RegularTextSource.serializer(),
|
// "regular" to RegularTextSource.serializer(),
|
||||||
"text_link" to TextLinkTextSource.serializer(),
|
// "text_link" to TextLinkTextSource.serializer(),
|
||||||
"code" to CodeTextSource.serializer(),
|
// "code" to CodeTextSource.serializer(),
|
||||||
"url" to URLTextSource.serializer(),
|
// "url" to URLTextSource.serializer(),
|
||||||
"pre" to PreTextSource.serializer(),
|
// "pre" to PreTextSource.serializer(),
|
||||||
"bot_command" to BotCommandTextSource.serializer(),
|
// "bot_command" to BotCommandTextSource.serializer(),
|
||||||
"strikethrough" to StrikethroughTextSource.serializer(),
|
// "strikethrough" to StrikethroughTextSource.serializer(),
|
||||||
"italic" to ItalicTextSource.serializer(),
|
// "italic" to ItalicTextSource.serializer(),
|
||||||
"bold" to BoldTextSource.serializer(),
|
// "bold" to BoldTextSource.serializer(),
|
||||||
"email" to EMailTextSource.serializer(),
|
// "email" to EMailTextSource.serializer(),
|
||||||
"underline" to UnderlineTextSource.serializer(),
|
// "underline" to UnderlineTextSource.serializer(),
|
||||||
"mention" to MentionTextSource.serializer(),
|
// "mention" to MentionTextSource.serializer(),
|
||||||
"phone_number" to PhoneNumberTextSource.serializer(),
|
// "phone_number" to PhoneNumberTextSource.serializer(),
|
||||||
"text_mention" to TextMentionTextSource.serializer(),
|
// "text_mention" to TextMentionTextSource.serializer(),
|
||||||
"hashtag" to HashTagTextSource.serializer(),
|
// "hashtag" to HashTagTextSource.serializer(),
|
||||||
"cashtag" to CashTagTextSource.serializer(),
|
// "cashtag" to CashTagTextSource.serializer(),
|
||||||
"spoiler" to SpoilerTextSource.serializer(),
|
// "spoiler" to SpoilerTextSource.serializer(),
|
||||||
"custom_emoji" to CustomEmojiTextSource.serializer(),
|
// "custom_emoji" to CustomEmojiTextSource.serializer(),
|
||||||
)
|
//)
|
||||||
|
|
||||||
|
object TextSourceSerializer : TypedSerializer<TextSource>(TextSource::class, emptyMap()) {
|
||||||
|
private val baseSerializers: Map<String, KSerializer<out TextSource>> by lazy {
|
||||||
|
mapOf(
|
||||||
|
"regular" to RegularTextSource.serializer(),
|
||||||
|
"text_link" to TextLinkTextSource.serializer(),
|
||||||
|
"code" to CodeTextSource.serializer(),
|
||||||
|
"url" to URLTextSource.serializer(),
|
||||||
|
"pre" to PreTextSource.serializer(),
|
||||||
|
"bot_command" to BotCommandTextSource.serializer(),
|
||||||
|
"strikethrough" to StrikethroughTextSource.serializer(),
|
||||||
|
"italic" to ItalicTextSource.serializer(),
|
||||||
|
"bold" to BoldTextSource.serializer(),
|
||||||
|
"email" to EMailTextSource.serializer(),
|
||||||
|
"underline" to UnderlineTextSource.serializer(),
|
||||||
|
"mention" to MentionTextSource.serializer(),
|
||||||
|
"phone_number" to PhoneNumberTextSource.serializer(),
|
||||||
|
"text_mention" to TextMentionTextSource.serializer(),
|
||||||
|
"hashtag" to HashTagTextSource.serializer(),
|
||||||
|
"cashtag" to CashTagTextSource.serializer(),
|
||||||
|
"spoiler" to SpoilerTextSource.serializer(),
|
||||||
|
"custom_emoji" to CustomEmojiTextSource.serializer(),
|
||||||
|
).also {
|
||||||
|
it.forEach { (k, s) ->
|
||||||
|
include(k, s)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun serialize(encoder: Encoder, value: TextSource) {
|
||||||
|
baseSerializers // init base serializers
|
||||||
|
super.serialize(encoder, value)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun deserialize(decoder: Decoder): TextSource {
|
||||||
|
baseSerializers // init base serializers
|
||||||
|
return super.deserialize(decoder)
|
||||||
|
}
|
||||||
|
|
||||||
object TextSourceSerializer : TypedSerializer<TextSource>(TextSource::class, baseSerializers) {
|
|
||||||
override fun <T: TextSource> include(type: String, serializer: KSerializer<T>) {
|
override fun <T: TextSource> include(type: String, serializer: KSerializer<T>) {
|
||||||
require(type !in baseSerializers.keys)
|
require(type !in serializers.keys)
|
||||||
super.include(type, serializer)
|
super.include(type, serializer)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun exclude(type: String) {
|
override fun exclude(type: String) {
|
||||||
require(type !in baseSerializers.keys)
|
require(type !in serializers.keys)
|
||||||
super.exclude(type)
|
super.exclude(type)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,6 +24,7 @@ const val htmlCodeControl = "code"
|
|||||||
const val htmlPreControl = "pre"
|
const val htmlPreControl = "pre"
|
||||||
const val htmlUnderlineControl = "u"
|
const val htmlUnderlineControl = "u"
|
||||||
const val htmlStrikethroughControl = "s"
|
const val htmlStrikethroughControl = "s"
|
||||||
|
const val htmlCustomEmojiControl = "tg-emoji"
|
||||||
|
|
||||||
private fun String.markdownDefault(
|
private fun String.markdownDefault(
|
||||||
openControlSymbol: String,
|
openControlSymbol: String,
|
||||||
@@ -120,8 +121,8 @@ internal fun String.commandMarkdownV2(): String = command(String::escapeMarkdown
|
|||||||
internal fun String.commandHTML(): String = command(String::toHtml)
|
internal fun String.commandHTML(): String = command(String::toHtml)
|
||||||
|
|
||||||
internal fun String.customEmojiMarkdown(): String = toMarkdown()
|
internal fun String.customEmojiMarkdown(): String = toMarkdown()
|
||||||
internal fun String.customEmojiMarkdownV2(): String = escapeMarkdownV2Common()
|
internal fun String.customEmojiMarkdownV2(customEmojiId: CustomEmojiId): String = "!${linkMarkdownV2(customEmojiId.appLink)}"
|
||||||
internal fun String.customEmojiHTML(): String = toHtml()
|
internal fun String.customEmojiHTML(customEmojiId: CustomEmojiId): String = "<$htmlCustomEmojiControl $htmlCustomEmojiControl=\"${customEmojiId.string}\">$this</$htmlCustomEmojiControl>"
|
||||||
|
|
||||||
internal fun String.regularMarkdown(): String = toMarkdown()
|
internal fun String.regularMarkdown(): String = toMarkdown()
|
||||||
internal fun String.regularMarkdownV2(): String = escapeMarkdownV2Common()
|
internal fun String.regularMarkdownV2(): String = escapeMarkdownV2Common()
|
||||||
|
|||||||
@@ -0,0 +1,5 @@
|
|||||||
|
package dev.inmo.tgbotapi.bot.ktor
|
||||||
|
|
||||||
|
import dev.inmo.tgbotapi.bot.ktor.base.DefaultKtorRequestsExecutor
|
||||||
|
|
||||||
|
actual typealias KtorRequestsExecutor = DefaultKtorRequestsExecutor
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
package dev.inmo.tgbotapi.bot.ktor.base
|
||||||
|
|
||||||
|
import io.ktor.client.*
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This function is used in default constructor of [MultipleClientKtorRequestsExecutor] and on all non-native
|
||||||
|
* platforms and MingwX64 should return [client]
|
||||||
|
*
|
||||||
|
* On LinuxX64 it will create copy with Curl engine or throw an exception if engine is different with Curl
|
||||||
|
*
|
||||||
|
* @throws IllegalArgumentException When pass non Curl-based [HttpClient] on LinuxX64
|
||||||
|
*/
|
||||||
|
internal actual inline fun platformClientCopy(client: HttpClient): HttpClient = client.config { }
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
package dev.inmo.tgbotapi.bot.ktor
|
||||||
|
|
||||||
|
import dev.inmo.tgbotapi.bot.ktor.base.DefaultKtorRequestsExecutor
|
||||||
|
|
||||||
|
actual typealias KtorRequestsExecutor = DefaultKtorRequestsExecutor
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
package dev.inmo.tgbotapi.bot.ktor.base
|
||||||
|
|
||||||
|
import io.ktor.client.*
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This function is used in default constructor of [MultipleClientKtorRequestsExecutor] and on all non-native
|
||||||
|
* platforms and MingwX64 should return [client]
|
||||||
|
*
|
||||||
|
* On LinuxX64 it will create copy with Curl engine or throw an exception if engine is different with Curl
|
||||||
|
*
|
||||||
|
* @throws IllegalArgumentException When pass non Curl-based [HttpClient] on LinuxX64
|
||||||
|
*/
|
||||||
|
internal actual inline fun platformClientCopy(client: HttpClient): HttpClient = client.config { }
|
||||||
1
tgbotapi.core/src/linuxX64Main/kotlin/PackageInfo.kt
Normal file
1
tgbotapi.core/src/linuxX64Main/kotlin/PackageInfo.kt
Normal file
@@ -0,0 +1 @@
|
|||||||
|
package dev.inmo.tgbotapi
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
package dev.inmo.tgbotapi.bot.ktor
|
||||||
|
|
||||||
|
import dev.inmo.tgbotapi.bot.ktor.base.MultipleClientKtorRequestsExecutor
|
||||||
|
|
||||||
|
actual typealias KtorRequestsExecutor = MultipleClientKtorRequestsExecutor
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
package dev.inmo.tgbotapi.bot.ktor.base
|
||||||
|
|
||||||
|
import io.ktor.client.*
|
||||||
|
import io.ktor.client.engine.curl.*
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This function is used in default constructor of [MultipleClientKtorRequestsExecutor] and on all non-native
|
||||||
|
* platforms and MingwX64 should return [client]
|
||||||
|
*
|
||||||
|
* On LinuxX64 it will create copy with Curl engine or throw an exception if engine is different with Curl
|
||||||
|
*
|
||||||
|
* @throws IllegalArgumentException When pass non Curl-based [HttpClient] on LinuxX64
|
||||||
|
*/
|
||||||
|
internal actual inline fun platformClientCopy(client: HttpClient): HttpClient = (client.engineConfig as? CurlClientEngineConfig) ?.let {
|
||||||
|
lateinit var config: HttpClientConfig<out CurlClientEngineConfig>
|
||||||
|
client.config {
|
||||||
|
config = this as HttpClientConfig<out CurlClientEngineConfig>
|
||||||
|
}.close()
|
||||||
|
HttpClient(Curl) {
|
||||||
|
this.plusAssign(config)
|
||||||
|
}
|
||||||
|
} ?: throw IllegalArgumentException("On LinuxX64 TelegramBotAPI currently support only Curl Ktor HttpClient engine")
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
package dev.inmo.tgbotapi.requests.abstracts
|
||||||
|
|
||||||
|
import dev.inmo.micro_utils.common.MPPFile
|
||||||
|
import dev.inmo.micro_utils.ktor.common.input
|
||||||
|
import dev.inmo.tgbotapi.requests.abstracts.MultipartFile
|
||||||
|
|
||||||
|
actual fun MPPFile.asMultipartFile(): MultipartFile = MultipartFile(this.name) {
|
||||||
|
input()
|
||||||
|
}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
package dev.inmo.tgbotapi.utils
|
||||||
|
|
||||||
|
import io.ktor.utils.io.ByteReadChannel
|
||||||
|
import io.ktor.utils.io.core.Input
|
||||||
|
import io.ktor.utils.io.readRemaining
|
||||||
|
|
||||||
|
actual suspend fun ByteReadChannel.asInput(): Input = readRemaining()
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
package dev.inmo.tgbotapi.utils
|
||||||
|
|
||||||
|
import kotlinx.serialization.Serializable
|
||||||
|
|
||||||
|
//actual typealias MimeType = MimeType
|
||||||
|
|
||||||
|
@Serializable(MimeTypeSerializer::class)
|
||||||
|
actual data class MimeType(
|
||||||
|
actual val raw: String
|
||||||
|
)
|
||||||
|
internal actual fun createMimeType(raw: String): MimeType = MimeType(raw)
|
||||||
1
tgbotapi.core/src/mingwX64Main/kotlin/PackageInfo.kt
Normal file
1
tgbotapi.core/src/mingwX64Main/kotlin/PackageInfo.kt
Normal file
@@ -0,0 +1 @@
|
|||||||
|
package dev.inmo.tgbotapi
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
package dev.inmo.tgbotapi.bot.ktor
|
||||||
|
|
||||||
|
import dev.inmo.tgbotapi.bot.ktor.base.DefaultKtorRequestsExecutor
|
||||||
|
|
||||||
|
actual typealias KtorRequestsExecutor = DefaultKtorRequestsExecutor
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
package dev.inmo.tgbotapi.bot.ktor.base
|
||||||
|
|
||||||
|
import io.ktor.client.*
|
||||||
|
import io.ktor.client.engine.winhttp.*
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This function is used in default constructor of [MultipleClientKtorRequestsExecutor] and on all non-native
|
||||||
|
* platforms and MingwX64 should return [client]
|
||||||
|
*
|
||||||
|
* On LinuxX64 it will create copy with Curl engine or throw an exception if engine is different with Curl
|
||||||
|
*
|
||||||
|
* @throws IllegalArgumentException When pass non Curl-based [HttpClient] on LinuxX64
|
||||||
|
*/
|
||||||
|
internal actual inline fun platformClientCopy(client: HttpClient): HttpClient = client.config { }
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
package dev.inmo.tgbotapi.requests.abstracts
|
||||||
|
|
||||||
|
import dev.inmo.micro_utils.common.MPPFile
|
||||||
|
import dev.inmo.micro_utils.ktor.common.input
|
||||||
|
import dev.inmo.tgbotapi.requests.abstracts.MultipartFile
|
||||||
|
|
||||||
|
actual fun MPPFile.asMultipartFile(): MultipartFile = MultipartFile(this.name) {
|
||||||
|
input()
|
||||||
|
}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
package dev.inmo.tgbotapi.utils
|
||||||
|
|
||||||
|
import io.ktor.utils.io.ByteReadChannel
|
||||||
|
import io.ktor.utils.io.core.Input
|
||||||
|
import io.ktor.utils.io.readRemaining
|
||||||
|
|
||||||
|
actual suspend fun ByteReadChannel.asInput(): Input = readRemaining()
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
package dev.inmo.tgbotapi.utils
|
||||||
|
|
||||||
|
import kotlinx.serialization.Serializable
|
||||||
|
|
||||||
|
//actual typealias MimeType = MimeType
|
||||||
|
|
||||||
|
@Serializable(MimeTypeSerializer::class)
|
||||||
|
actual data class MimeType(
|
||||||
|
actual val raw: String
|
||||||
|
)
|
||||||
|
internal actual fun createMimeType(raw: String): MimeType = MimeType(raw)
|
||||||
@@ -12,6 +12,7 @@ package dev.inmo.tgbotapi.extensions.utils
|
|||||||
import dev.inmo.tgbotapi.abstracts.CommonSendInvoiceData
|
import dev.inmo.tgbotapi.abstracts.CommonSendInvoiceData
|
||||||
import dev.inmo.tgbotapi.abstracts.FromUser
|
import dev.inmo.tgbotapi.abstracts.FromUser
|
||||||
import dev.inmo.tgbotapi.abstracts.WithUser
|
import dev.inmo.tgbotapi.abstracts.WithUser
|
||||||
|
import dev.inmo.tgbotapi.requests.answers.InlineQueryResultsButton
|
||||||
import dev.inmo.tgbotapi.requests.send.payments.CreateInvoiceLink
|
import dev.inmo.tgbotapi.requests.send.payments.CreateInvoiceLink
|
||||||
import dev.inmo.tgbotapi.requests.send.payments.SendInvoice
|
import dev.inmo.tgbotapi.requests.send.payments.SendInvoice
|
||||||
import dev.inmo.tgbotapi.requests.stickers.InputSticker
|
import dev.inmo.tgbotapi.requests.stickers.InputSticker
|
||||||
@@ -108,6 +109,7 @@ import dev.inmo.tgbotapi.types.buttons.InlineKeyboardButtons.CallbackGameInlineK
|
|||||||
import dev.inmo.tgbotapi.types.buttons.InlineKeyboardButtons.InlineKeyboardButton
|
import dev.inmo.tgbotapi.types.buttons.InlineKeyboardButtons.InlineKeyboardButton
|
||||||
import dev.inmo.tgbotapi.types.buttons.InlineKeyboardButtons.LoginURLInlineKeyboardButton
|
import dev.inmo.tgbotapi.types.buttons.InlineKeyboardButtons.LoginURLInlineKeyboardButton
|
||||||
import dev.inmo.tgbotapi.types.buttons.InlineKeyboardButtons.PayInlineKeyboardButton
|
import dev.inmo.tgbotapi.types.buttons.InlineKeyboardButtons.PayInlineKeyboardButton
|
||||||
|
import dev.inmo.tgbotapi.types.buttons.InlineKeyboardButtons.SwitchInlineQueryChosenChatInlineKeyboardButton
|
||||||
import dev.inmo.tgbotapi.types.buttons.InlineKeyboardButtons.SwitchInlineQueryCurrentChatInlineKeyboardButton
|
import dev.inmo.tgbotapi.types.buttons.InlineKeyboardButtons.SwitchInlineQueryCurrentChatInlineKeyboardButton
|
||||||
import dev.inmo.tgbotapi.types.buttons.InlineKeyboardButtons.SwitchInlineQueryInlineKeyboardButton
|
import dev.inmo.tgbotapi.types.buttons.InlineKeyboardButtons.SwitchInlineQueryInlineKeyboardButton
|
||||||
import dev.inmo.tgbotapi.types.buttons.InlineKeyboardButtons.URLInlineKeyboardButton
|
import dev.inmo.tgbotapi.types.buttons.InlineKeyboardButtons.URLInlineKeyboardButton
|
||||||
@@ -160,6 +162,7 @@ import dev.inmo.tgbotapi.types.chat.member.AdministratorChatMember
|
|||||||
import dev.inmo.tgbotapi.types.chat.member.AdministratorChatMemberImpl
|
import dev.inmo.tgbotapi.types.chat.member.AdministratorChatMemberImpl
|
||||||
import dev.inmo.tgbotapi.types.chat.member.BannedChatMember
|
import dev.inmo.tgbotapi.types.chat.member.BannedChatMember
|
||||||
import dev.inmo.tgbotapi.types.chat.member.ChatMember
|
import dev.inmo.tgbotapi.types.chat.member.ChatMember
|
||||||
|
import dev.inmo.tgbotapi.types.chat.member.ChatMemberUpdated
|
||||||
import dev.inmo.tgbotapi.types.chat.member.KickedChatMember
|
import dev.inmo.tgbotapi.types.chat.member.KickedChatMember
|
||||||
import dev.inmo.tgbotapi.types.chat.member.LeftChatMember
|
import dev.inmo.tgbotapi.types.chat.member.LeftChatMember
|
||||||
import dev.inmo.tgbotapi.types.chat.member.LeftChatMemberImpl
|
import dev.inmo.tgbotapi.types.chat.member.LeftChatMemberImpl
|
||||||
@@ -659,6 +662,15 @@ public inline fun WithUser.chatMemberOrThrow(): ChatMember = this as
|
|||||||
public inline fun <T> WithUser.ifChatMember(block: (ChatMember) -> T): T? = chatMemberOrNull()
|
public inline fun <T> WithUser.ifChatMember(block: (ChatMember) -> T): T? = chatMemberOrNull()
|
||||||
?.let(block)
|
?.let(block)
|
||||||
|
|
||||||
|
public inline fun WithUser.chatMemberUpdatedOrNull(): ChatMemberUpdated? = this as?
|
||||||
|
dev.inmo.tgbotapi.types.chat.member.ChatMemberUpdated
|
||||||
|
|
||||||
|
public inline fun WithUser.chatMemberUpdatedOrThrow(): ChatMemberUpdated = this as
|
||||||
|
dev.inmo.tgbotapi.types.chat.member.ChatMemberUpdated
|
||||||
|
|
||||||
|
public inline fun <T> WithUser.ifChatMemberUpdated(block: (ChatMemberUpdated) -> T): T? =
|
||||||
|
chatMemberUpdatedOrNull() ?.let(block)
|
||||||
|
|
||||||
public inline fun WithUser.kickedChatMemberOrNull(): KickedChatMember? = this as?
|
public inline fun WithUser.kickedChatMemberOrNull(): KickedChatMember? = this as?
|
||||||
dev.inmo.tgbotapi.types.chat.member.KickedChatMember
|
dev.inmo.tgbotapi.types.chat.member.KickedChatMember
|
||||||
|
|
||||||
@@ -1003,6 +1015,36 @@ public inline fun <T>
|
|||||||
WithUser.ifMessageGameShortNameCallbackQuery(block: (MessageGameShortNameCallbackQuery) -> T):
|
WithUser.ifMessageGameShortNameCallbackQuery(block: (MessageGameShortNameCallbackQuery) -> T):
|
||||||
T? = messageGameShortNameCallbackQueryOrNull() ?.let(block)
|
T? = messageGameShortNameCallbackQueryOrNull() ?.let(block)
|
||||||
|
|
||||||
|
public inline fun InlineQueryResultsButton.startOrNull(): InlineQueryResultsButton.Start? = this as?
|
||||||
|
dev.inmo.tgbotapi.requests.answers.InlineQueryResultsButton.Start
|
||||||
|
|
||||||
|
public inline fun InlineQueryResultsButton.startOrThrow(): InlineQueryResultsButton.Start = this as
|
||||||
|
dev.inmo.tgbotapi.requests.answers.InlineQueryResultsButton.Start
|
||||||
|
|
||||||
|
public inline fun <T>
|
||||||
|
InlineQueryResultsButton.ifStart(block: (InlineQueryResultsButton.Start) -> T): T? =
|
||||||
|
startOrNull() ?.let(block)
|
||||||
|
|
||||||
|
public inline fun InlineQueryResultsButton.unknownOrNull(): InlineQueryResultsButton.Unknown? = this
|
||||||
|
as? dev.inmo.tgbotapi.requests.answers.InlineQueryResultsButton.Unknown
|
||||||
|
|
||||||
|
public inline fun InlineQueryResultsButton.unknownOrThrow(): InlineQueryResultsButton.Unknown = this
|
||||||
|
as dev.inmo.tgbotapi.requests.answers.InlineQueryResultsButton.Unknown
|
||||||
|
|
||||||
|
public inline fun <T>
|
||||||
|
InlineQueryResultsButton.ifUnknown(block: (InlineQueryResultsButton.Unknown) -> T): T? =
|
||||||
|
unknownOrNull() ?.let(block)
|
||||||
|
|
||||||
|
public inline fun InlineQueryResultsButton.webAppOrNull(): InlineQueryResultsButton.WebApp? = this
|
||||||
|
as? dev.inmo.tgbotapi.requests.answers.InlineQueryResultsButton.WebApp
|
||||||
|
|
||||||
|
public inline fun InlineQueryResultsButton.webAppOrThrow(): InlineQueryResultsButton.WebApp = this
|
||||||
|
as dev.inmo.tgbotapi.requests.answers.InlineQueryResultsButton.WebApp
|
||||||
|
|
||||||
|
public inline fun <T>
|
||||||
|
InlineQueryResultsButton.ifWebApp(block: (InlineQueryResultsButton.WebApp) -> T): T? =
|
||||||
|
webAppOrNull() ?.let(block)
|
||||||
|
|
||||||
public inline fun InputSticker.maskOrNull(): InputSticker.Mask? = this as?
|
public inline fun InputSticker.maskOrNull(): InputSticker.Mask? = this as?
|
||||||
dev.inmo.tgbotapi.requests.stickers.InputSticker.Mask
|
dev.inmo.tgbotapi.requests.stickers.InputSticker.Mask
|
||||||
|
|
||||||
@@ -1888,6 +1930,18 @@ public inline fun <T>
|
|||||||
InlineKeyboardButton.ifSwitchInlineQueryCurrentChatInlineKeyboardButton(block: (SwitchInlineQueryCurrentChatInlineKeyboardButton) -> T):
|
InlineKeyboardButton.ifSwitchInlineQueryCurrentChatInlineKeyboardButton(block: (SwitchInlineQueryCurrentChatInlineKeyboardButton) -> T):
|
||||||
T? = switchInlineQueryCurrentChatInlineKeyboardButtonOrNull() ?.let(block)
|
T? = switchInlineQueryCurrentChatInlineKeyboardButtonOrNull() ?.let(block)
|
||||||
|
|
||||||
|
public inline fun InlineKeyboardButton.switchInlineQueryChosenChatInlineKeyboardButtonOrNull():
|
||||||
|
SwitchInlineQueryChosenChatInlineKeyboardButton? = this as?
|
||||||
|
dev.inmo.tgbotapi.types.buttons.InlineKeyboardButtons.SwitchInlineQueryChosenChatInlineKeyboardButton
|
||||||
|
|
||||||
|
public inline fun InlineKeyboardButton.switchInlineQueryChosenChatInlineKeyboardButtonOrThrow():
|
||||||
|
SwitchInlineQueryChosenChatInlineKeyboardButton = this as
|
||||||
|
dev.inmo.tgbotapi.types.buttons.InlineKeyboardButtons.SwitchInlineQueryChosenChatInlineKeyboardButton
|
||||||
|
|
||||||
|
public inline fun <T>
|
||||||
|
InlineKeyboardButton.ifSwitchInlineQueryChosenChatInlineKeyboardButton(block: (SwitchInlineQueryChosenChatInlineKeyboardButton) -> T):
|
||||||
|
T? = switchInlineQueryChosenChatInlineKeyboardButtonOrNull() ?.let(block)
|
||||||
|
|
||||||
public inline fun InlineKeyboardButton.switchInlineQueryInlineKeyboardButtonOrNull():
|
public inline fun InlineKeyboardButton.switchInlineQueryInlineKeyboardButtonOrNull():
|
||||||
SwitchInlineQueryInlineKeyboardButton? = this as?
|
SwitchInlineQueryInlineKeyboardButton? = this as?
|
||||||
dev.inmo.tgbotapi.types.buttons.InlineKeyboardButtons.SwitchInlineQueryInlineKeyboardButton
|
dev.inmo.tgbotapi.types.buttons.InlineKeyboardButtons.SwitchInlineQueryInlineKeyboardButton
|
||||||
|
|||||||
@@ -103,6 +103,45 @@ inline fun InlineKeyboardRowBuilder.inlineQueryInCurrentChatButton(
|
|||||||
data: String
|
data: String
|
||||||
) = add(SwitchInlineQueryCurrentChatInlineKeyboardButton(text, data))
|
) = add(SwitchInlineQueryCurrentChatInlineKeyboardButton(text, data))
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates and put [SwitchInlineQueryChosenChatInlineKeyboardButton]
|
||||||
|
*
|
||||||
|
* @see inlineKeyboard
|
||||||
|
* @see InlineKeyboardBuilder.row
|
||||||
|
*/
|
||||||
|
inline fun InlineKeyboardRowBuilder.inlineQueryInChosenChatButton(
|
||||||
|
text: String,
|
||||||
|
parameters: SwitchInlineQueryChosenChat
|
||||||
|
) = add(SwitchInlineQueryChosenChatInlineKeyboardButton(text, parameters))
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates and put [SwitchInlineQueryChosenChatInlineKeyboardButton]
|
||||||
|
*
|
||||||
|
* @see inlineKeyboard
|
||||||
|
* @see InlineKeyboardBuilder.row
|
||||||
|
*/
|
||||||
|
inline fun InlineKeyboardRowBuilder.inlineQueryInChosenChatButton(
|
||||||
|
text: String,
|
||||||
|
query: String? = null,
|
||||||
|
allowUsers: Boolean = false,
|
||||||
|
allowBots: Boolean = false,
|
||||||
|
allowGroups: Boolean = false,
|
||||||
|
allowChannels: Boolean = false,
|
||||||
|
) = inlineQueryInChosenChatButton(
|
||||||
|
text,
|
||||||
|
SwitchInlineQueryChosenChat(
|
||||||
|
query = query,
|
||||||
|
allowUsers = allowUsers,
|
||||||
|
allowBots = allowBots,
|
||||||
|
allowGroups = allowGroups,
|
||||||
|
allowChannels = allowChannels
|
||||||
|
)
|
||||||
|
)
|
||||||
|
inline fun InlineKeyboardRowBuilder.inlineQueryInAnyChosenChatButton(
|
||||||
|
text: String,
|
||||||
|
query: String? = null,
|
||||||
|
) = inlineQueryInChosenChatButton(text, query, allowUsers = true, allowBots = true, allowGroups = true, allowChannels = true)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates and put [SwitchInlineQueryInlineKeyboardButton]
|
* Creates and put [SwitchInlineQueryInlineKeyboardButton]
|
||||||
*
|
*
|
||||||
|
|||||||
5
tgbotapi.webapps/src/commonMain/kotlin/PackageInfo.kt
Normal file
5
tgbotapi.webapps/src/commonMain/kotlin/PackageInfo.kt
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
/**
|
||||||
|
* This file has been created to fix problem with native targets which didn't compile empty project klib file. This problem
|
||||||
|
* leads to impossible project publishing
|
||||||
|
*/
|
||||||
|
package dev.inmo.tgbotapi.webapps
|
||||||
5
tgbotapi/src/commonMain/kotlin/PackageInfo.kt
Normal file
5
tgbotapi/src/commonMain/kotlin/PackageInfo.kt
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
/**
|
||||||
|
* This file has been created to fix problem with native targets which didn't compile empty project klib file. This problem
|
||||||
|
* leads to impossible project publishing
|
||||||
|
*/
|
||||||
|
package dev.inmo.tgbotapi
|
||||||
Reference in New Issue
Block a user