1
0
mirror of https://github.com/InsanusMokrassar/TelegramBotAPI.git synced 2026-06-01 21:27:20 +00:00

Compare commits

..

50 Commits

Author SHA1 Message Date
3c3607d817 fill changelog 2022-05-03 14:32:29 +06:00
d0add888c4 now the handlers from the upstream lists are not modified in the whole fsm behaviour context 2022-05-03 14:28:03 +06:00
3e3adab46b complete fix of issue with subcontexts 2022-05-03 13:58:13 +06:00
89d13de307 deprecation of BehaviourContextWithFSMBuilder 2022-05-03 10:38:48 +06:00
32451f4e1c start 0.38.19 2022-05-03 09:44:39 +06:00
ad50f41d1e Merge pull request #578 from InsanusMokrassar/0.38.18
0.38.18
2022-05-02 13:49:24 +06:00
8c9cd9df67 fix of #577 2022-05-02 13:21:43 +06:00
8e7f7a03c8 note about xzima help 2022-05-02 12:44:20 +06:00
484e09374d small refactor 2022-05-02 12:29:30 +06:00
Alex
619c82bb32 fix: new BehaviourContext ignored 2022-05-02 12:29:21 +06:00
33fb75a5eb start 0.38.18 2022-05-02 12:28:39 +06:00
a52f31f4c9 Merge pull request #575 from InsanusMokrassar/0.38.17
0.38.17
2022-05-01 17:23:33 +06:00
682f696866 fill changelog 2022-05-01 17:23:12 +06:00
87fff2e5d0 add BotCommandScope helper extensions 2022-05-01 17:18:44 +06:00
92b4ba2ff0 fix of #574 2022-05-01 16:50:03 +06:00
9014cdbc99 start 0.38.17 2022-05-01 16:41:47 +06:00
37317a1055 Merge pull request #573 from InsanusMokrassar/0.38.16
0.38.16
2022-04-29 23:28:12 +06:00
60c21002e1 fixes 2022-04-29 19:50:02 +06:00
78a7a3546a remove checking of webapp data from webapp module due to its existing in core 2022-04-29 19:18:22 +06:00
4799617ced "TelegramAPIUrlsKeeper" now have two new things: properties "webAppDataSecretKey" and fun "checkWebAppLink" 2022-04-29 19:11:38 +06:00
c70484076d start 0.38.16 2022-04-29 18:56:38 +06:00
0c92e6eeb4 Merge pull request #570 from InsanusMokrassar/0.38.15
0.38.15
2022-04-26 13:45:09 +06:00
efd1c8f83a add additional onDataCallbackQuery variants with regex filters 2022-04-26 13:22:00 +06:00
7e57a0e4e0 revert update of microutils version 2022-04-26 13:07:16 +06:00
6b977e67d0 Revert "add telegram update handler"
This reverts commit ab5937449c.
2022-04-26 13:05:56 +06:00
ab5937449c add telegram update handler 2022-04-25 22:28:35 +06:00
61d3131bf2 update micro_utils 2022-04-25 21:58:25 +06:00
048f244449 update microutils 2022-04-25 21:19:49 +06:00
6ebf4ff652 fixes in MessageContent#serializationModule 2022-04-25 21:19:08 +06:00
b4c41d7dd8 start 0.38.15 2022-04-24 18:39:07 +06:00
930507ab80 Merge pull request #568 from InsanusMokrassar/0.38.14
0.38.14
2022-04-23 12:43:02 +06:00
56d3628dd3 add support of menu buttons 2022-04-23 12:39:14 +06:00
56d7853f68 update defaults in telegramBot factories 2022-04-23 12:34:38 +06:00
0a27d9bf28 add shortcuts for telegram and webApp in webapps 2022-04-23 12:34:26 +06:00
c74df3960c fixes in viewport changed events 2022-04-23 12:34:13 +06:00
f4b080cb45 now WebAppData is data class 2022-04-23 12:34:05 +06:00
350b77f6ff add webAppButton overload with url as string 2022-04-23 12:33:56 +06:00
955e14f67c add trigger and expectation for WebAppData 2022-04-23 12:33:45 +06:00
ae88b7d94d fix dokka 2022-04-23 12:33:34 +06:00
88c62bd51c add checking of data in web app 2022-04-23 12:33:23 +06:00
705bcbe352 webapps 2022-04-23 12:32:39 +06:00
ffcc149c40 update info about supported telegram bot api version 2022-04-23 12:31:37 +06:00
402d91f9f2 add support of SentWebAppMessage 2022-04-23 12:31:22 +06:00
c19bccc7d1 add support of WebAppInfo 2022-04-23 12:30:35 +06:00
2c71377058 voice(_c/C)hat* -> video(_c/C)hat* renames 2022-04-23 12:30:15 +06:00
12d2c05110 add support of WebhookInfo#lastSynchronizationErrorDate 2022-04-23 12:28:40 +06:00
ddf46c1afd add support of ChatAdministratorRights 2022-04-23 12:27:24 +06:00
dd0a8b99c7 add WebAppData 2022-04-23 12:26:28 +06:00
75fb72936f fix of 563 2022-04-23 12:25:39 +06:00
1a6a010446 start 0.38.14 2022-04-23 12:24:52 +06:00
109 changed files with 1023 additions and 513 deletions

View File

@@ -1,19 +1,49 @@
# TelegramBotAPI changelog # TelegramBotAPI changelog
## 1.0.0 ## 0.38.19
* `BehaviourBuilder`:
* Hotfixes
* `BehaviourBuilder FSM`:
* `BehaviourContextWithFSMBuilder` deprecated in favor to `BehaviourContextWithFSM`
* Now it is possible to define additional handlers in subcontexts of `BehaviourBuilderWithFSM`
## 0.38.18
* `Core`:
* Add support of test servers (fix of [#577](https://github.com/InsanusMokrassar/TelegramBotAPI/issues/577))
* `BehaviourBuilder`:
* Fixes in extension `BehaviourContext#doInSubContextWithUpdatesFilter` (thanks to [xzima](https://github.com/xzima))
## 0.38.17
* `Core`:
* Add `BotCommandScopeChat` as new `BotCommandScope` (fix of [#574](https://github.com/InsanusMokrassar/TelegramBotAPI/issues/574))
* `BotCommandScope` companion got several properties and functions for more useful scope creation
## 0.38.16
* `Core`:
* `TelegramAPIUrlsKeeper` now have two new things: properties `webAppDataSecretKey` and fun `checkWebAppLink`
## 0.38.15
* `Common`:
* `Version`:
* `MicroUtils`: `0.9.20` -> `0.9.24`
* `Core`:
* Fixes in `MessageContent#serializationModule`
* `BehaviourBuilder`:
* Add triggers for `DataCallbackQuery` and subtypes with regex checking of data
## 0.38.14
__This update contains including of [Telegram Bot API 6.0](https://core.telegram.org/bots/api-changelog#april-16-2022)__ __This update contains including of [Telegram Bot API 6.0](https://core.telegram.org/bots/api-changelog#april-16-2022)__
__All the `tgbotapi.extensions.*` packages have been removed__
* `Core`: * `Core`:
* Constructor of `UnknownInlineKeyboardButton` is not internal and can be created with any `json` ([#563](https://github.com/InsanusMokrassar/TelegramBotAPI/issues/563)) * Constructor of `UnknownInlineKeyboardButton` is not internal and can be created with any `json`
* All the interfaces from `dev.inmo.tgbotapi.types.files.abstracts` have been replaced to `dev.inmo.tgbotapi.types.files` and converted to sealed ([#550](https://github.com/InsanusMokrassar/TelegramBotAPI/issues/550))
* `PassportFile` has been replaced to `dev.inmo.tgbotapi.types.files`
* `WebApps`: * `WebApps`:
* Created 🎉 * Created 🎉
* `BehaviourBuilder`:
* `SimpleFilter` now is a `fun interface` instead of just callback (fix of [#546](https://github.com/InsanusMokrassar/TelegramBotAPI/issues/546))
## 0.38.13 ## 0.38.13

View File

@@ -12,7 +12,7 @@ klock_version=2.7.0
uuid_version=0.4.0 uuid_version=0.4.0
ktor_version=1.6.8 ktor_version=1.6.8
micro_utils_version=0.9.20 micro_utils_version=0.9.24
javax_activation_version=1.1.1 javax_activation_version=1.1.1
@@ -20,6 +20,6 @@ javax_activation_version=1.1.1
dokka_version=1.6.10 dokka_version=1.6.10
library_group=dev.inmo library_group=dev.inmo
library_version=1.0.0 library_version=0.38.19
github_release_plugin_version=2.3.7 github_release_plugin_version=2.3.7

View File

@@ -16,6 +16,10 @@ include ":tgbotapi.api"
include ":tgbotapi.utils" include ":tgbotapi.utils"
include ":tgbotapi.behaviour_builder" include ":tgbotapi.behaviour_builder"
include ":tgbotapi.behaviour_builder.fsm" include ":tgbotapi.behaviour_builder.fsm"
include ":tgbotapi.extensions.api"
include ":tgbotapi.extensions.utils"
include ":tgbotapi.extensions.behaviour_builder"
include ":tgbotapi.extensions.behaviour_builder.fsm"
include ":tgbotapi" include ":tgbotapi"
include ":tgbotapi.webapps" include ":tgbotapi.webapps"
include ":docs" include ":docs"

View File

@@ -40,8 +40,9 @@ data class BotBuilder internal constructor(
fun buildBot( fun buildBot(
token: String, token: String,
apiUrl: String = telegramBotAPIDefaultUrl, apiUrl: String = telegramBotAPIDefaultUrl,
testServer: Boolean = false,
block: BotBuilder.() -> Unit block: BotBuilder.() -> Unit
) = telegramBot( ) = telegramBot(
TelegramAPIUrlsKeeper(token, apiUrl), TelegramAPIUrlsKeeper(token, testServer, apiUrl),
BotBuilder().apply(block).createHttpClient() BotBuilder().apply(block).createHttpClient()
) )

View File

@@ -13,7 +13,7 @@ import io.ktor.client.engine.*
*/ */
fun telegramBot( fun telegramBot(
urlsKeeper: TelegramAPIUrlsKeeper, urlsKeeper: TelegramAPIUrlsKeeper,
client: HttpClient client: HttpClient = HttpClient()
): TelegramBot = telegramBot(urlsKeeper) { ): TelegramBot = telegramBot(urlsKeeper) {
this.client = client this.client = client
} }
@@ -66,17 +66,19 @@ inline fun telegramBot(
inline fun telegramBot( inline fun telegramBot(
token: String, token: String,
apiUrl: String = telegramBotAPIDefaultUrl, apiUrl: String = telegramBotAPIDefaultUrl,
client: HttpClient testServer: Boolean = false,
): TelegramBot = telegramBot(TelegramAPIUrlsKeeper(token, apiUrl), client) client: HttpClient = HttpClient()
): TelegramBot = telegramBot(TelegramAPIUrlsKeeper(token, testServer, apiUrl), client)
@Suppress("NOTHING_TO_INLINE") @Suppress("NOTHING_TO_INLINE")
inline fun <T: HttpClientEngineConfig> telegramBot( inline fun <T: HttpClientEngineConfig> telegramBot(
token: String, token: String,
clientFactory: HttpClientEngineFactory<T>, clientFactory: HttpClientEngineFactory<T>,
apiUrl: String = telegramBotAPIDefaultUrl, apiUrl: String = telegramBotAPIDefaultUrl,
testServer: Boolean = false,
noinline clientConfig: HttpClientConfig<T>.() -> Unit = {} noinline clientConfig: HttpClientConfig<T>.() -> Unit = {}
) = telegramBot( ) = telegramBot(
TelegramAPIUrlsKeeper(token, apiUrl), TelegramAPIUrlsKeeper(token, testServer, apiUrl),
clientFactory, clientFactory,
clientConfig clientConfig
) )
@@ -90,9 +92,10 @@ inline fun telegramBot(
token: String, token: String,
clientEngine: HttpClientEngine, clientEngine: HttpClientEngine,
apiUrl: String = telegramBotAPIDefaultUrl, apiUrl: String = telegramBotAPIDefaultUrl,
testServer: Boolean = false,
noinline clientConfig: HttpClientConfig<*>.() -> Unit = {} noinline clientConfig: HttpClientConfig<*>.() -> Unit = {}
) = telegramBot( ) = telegramBot(
TelegramAPIUrlsKeeper(token, apiUrl), TelegramAPIUrlsKeeper(token, testServer, apiUrl),
clientEngine, clientEngine,
clientConfig clientConfig
) )
@@ -105,8 +108,9 @@ inline fun telegramBot(
inline fun telegramBot( inline fun telegramBot(
token: String, token: String,
apiUrl: String = telegramBotAPIDefaultUrl, apiUrl: String = telegramBotAPIDefaultUrl,
testServer: Boolean = false,
noinline clientConfig: HttpClientConfig<*>.() -> Unit noinline clientConfig: HttpClientConfig<*>.() -> Unit
) = telegramBot( ) = telegramBot(
TelegramAPIUrlsKeeper(token, apiUrl), TelegramAPIUrlsKeeper(token, testServer, apiUrl),
clientConfig clientConfig
) )

View File

@@ -5,7 +5,7 @@ import dev.inmo.tgbotapi.extensions.api.get.getFileAdditionalInfo
import dev.inmo.tgbotapi.requests.DownloadFile import dev.inmo.tgbotapi.requests.DownloadFile
import dev.inmo.tgbotapi.requests.abstracts.FileId import dev.inmo.tgbotapi.requests.abstracts.FileId
import dev.inmo.tgbotapi.types.files.PathedFile import dev.inmo.tgbotapi.types.files.PathedFile
import dev.inmo.tgbotapi.types.files.TelegramMediaFile import dev.inmo.tgbotapi.types.files.abstracts.TelegramMediaFile
import dev.inmo.tgbotapi.types.message.content.abstracts.MediaContent import dev.inmo.tgbotapi.types.message.content.abstracts.MediaContent
suspend fun TelegramBot.downloadFile( suspend fun TelegramBot.downloadFile(

View File

@@ -4,7 +4,7 @@ import dev.inmo.tgbotapi.bot.TelegramBot
import dev.inmo.tgbotapi.extensions.api.get.getFileAdditionalInfo import dev.inmo.tgbotapi.extensions.api.get.getFileAdditionalInfo
import dev.inmo.tgbotapi.requests.abstracts.FileId import dev.inmo.tgbotapi.requests.abstracts.FileId
import dev.inmo.tgbotapi.types.files.PathedFile import dev.inmo.tgbotapi.types.files.PathedFile
import dev.inmo.tgbotapi.types.files.TelegramMediaFile import dev.inmo.tgbotapi.types.files.abstracts.TelegramMediaFile
import dev.inmo.tgbotapi.types.message.content.abstracts.MediaContent import dev.inmo.tgbotapi.types.message.content.abstracts.MediaContent
suspend fun TelegramBot.downloadFileStream( suspend fun TelegramBot.downloadFileStream(

View File

@@ -5,7 +5,7 @@ import dev.inmo.tgbotapi.extensions.api.get.getFileAdditionalInfo
import dev.inmo.tgbotapi.requests.DownloadFileStream import dev.inmo.tgbotapi.requests.DownloadFileStream
import dev.inmo.tgbotapi.requests.abstracts.FileId import dev.inmo.tgbotapi.requests.abstracts.FileId
import dev.inmo.tgbotapi.types.files.PathedFile import dev.inmo.tgbotapi.types.files.PathedFile
import dev.inmo.tgbotapi.types.files.TelegramMediaFile import dev.inmo.tgbotapi.types.files.abstracts.TelegramMediaFile
import dev.inmo.tgbotapi.types.message.content.abstracts.MediaContent import dev.inmo.tgbotapi.types.message.content.abstracts.MediaContent
suspend fun TelegramBot.downloadFileStreamAllocator( suspend fun TelegramBot.downloadFileStreamAllocator(

View File

@@ -3,7 +3,7 @@ package dev.inmo.tgbotapi.extensions.api.get
import dev.inmo.tgbotapi.bot.TelegramBot import dev.inmo.tgbotapi.bot.TelegramBot
import dev.inmo.tgbotapi.requests.abstracts.FileId import dev.inmo.tgbotapi.requests.abstracts.FileId
import dev.inmo.tgbotapi.requests.get.GetFile import dev.inmo.tgbotapi.requests.get.GetFile
import dev.inmo.tgbotapi.types.files.TelegramMediaFile import dev.inmo.tgbotapi.types.files.abstracts.TelegramMediaFile
import dev.inmo.tgbotapi.types.message.content.abstracts.MediaContent import dev.inmo.tgbotapi.types.message.content.abstracts.MediaContent
suspend fun TelegramBot.getFileAdditionalInfo( suspend fun TelegramBot.getFileAdditionalInfo(

View File

@@ -2,7 +2,7 @@ package dev.inmo.tgbotapi.extensions.api.get
import dev.inmo.tgbotapi.bot.TelegramBot import dev.inmo.tgbotapi.bot.TelegramBot
import dev.inmo.tgbotapi.requests.get.GetStickerSet import dev.inmo.tgbotapi.requests.get.GetStickerSet
import dev.inmo.tgbotapi.types.files.Sticker import dev.inmo.tgbotapi.types.files.sticker.Sticker
suspend fun TelegramBot.getStickerSet( suspend fun TelegramBot.getStickerSet(
name: String name: String

View File

@@ -18,11 +18,12 @@ import dev.inmo.tgbotapi.types.buttons.KeyboardMarkup
import dev.inmo.tgbotapi.types.chat.abstracts.Chat import dev.inmo.tgbotapi.types.chat.abstracts.Chat
import dev.inmo.tgbotapi.types.dice.DiceAnimationType import dev.inmo.tgbotapi.types.dice.DiceAnimationType
import dev.inmo.tgbotapi.types.files.* import dev.inmo.tgbotapi.types.files.*
import dev.inmo.tgbotapi.types.files.TelegramMediaFile import dev.inmo.tgbotapi.types.files.abstracts.TelegramMediaFile
import dev.inmo.tgbotapi.types.files.Sticker import dev.inmo.tgbotapi.types.files.sticker.Sticker
import dev.inmo.tgbotapi.types.games.Game import dev.inmo.tgbotapi.types.games.Game
import dev.inmo.tgbotapi.types.location.* import dev.inmo.tgbotapi.types.location.*
import dev.inmo.tgbotapi.types.message.abstracts.Message import dev.inmo.tgbotapi.types.message.abstracts.Message
import dev.inmo.tgbotapi.types.message.content.*
import dev.inmo.tgbotapi.types.message.content.abstracts.MessageContent import dev.inmo.tgbotapi.types.message.content.abstracts.MessageContent
import dev.inmo.tgbotapi.types.message.content.media.* import dev.inmo.tgbotapi.types.message.content.media.*
import dev.inmo.tgbotapi.types.payments.LabeledPrice import dev.inmo.tgbotapi.types.payments.LabeledPrice

View File

@@ -7,7 +7,7 @@ import dev.inmo.tgbotapi.types.ChatIdentifier
import dev.inmo.tgbotapi.types.MessageIdentifier import dev.inmo.tgbotapi.types.MessageIdentifier
import dev.inmo.tgbotapi.types.buttons.KeyboardMarkup import dev.inmo.tgbotapi.types.buttons.KeyboardMarkup
import dev.inmo.tgbotapi.types.chat.abstracts.Chat import dev.inmo.tgbotapi.types.chat.abstracts.Chat
import dev.inmo.tgbotapi.types.files.Sticker import dev.inmo.tgbotapi.types.files.sticker.Sticker
/** /**
* @param replyMarkup Some of [KeyboardMarkup]. See [dev.inmo.tgbotapi.extensions.utils.types.buttons.replyKeyboard] or * @param replyMarkup Some of [KeyboardMarkup]. See [dev.inmo.tgbotapi.extensions.utils.types.buttons.replyKeyboard] or

View File

@@ -3,7 +3,7 @@ package dev.inmo.tgbotapi.extensions.api.stickers
import dev.inmo.tgbotapi.bot.TelegramBot import dev.inmo.tgbotapi.bot.TelegramBot
import dev.inmo.tgbotapi.requests.abstracts.FileId import dev.inmo.tgbotapi.requests.abstracts.FileId
import dev.inmo.tgbotapi.requests.stickers.DeleteStickerFromSet import dev.inmo.tgbotapi.requests.stickers.DeleteStickerFromSet
import dev.inmo.tgbotapi.types.files.Sticker import dev.inmo.tgbotapi.types.files.sticker.Sticker
suspend fun TelegramBot.deleteStickerFromSet( suspend fun TelegramBot.deleteStickerFromSet(
sticker: FileId sticker: FileId

View File

@@ -3,7 +3,7 @@ package dev.inmo.tgbotapi.extensions.api.stickers
import dev.inmo.tgbotapi.bot.TelegramBot import dev.inmo.tgbotapi.bot.TelegramBot
import dev.inmo.tgbotapi.requests.abstracts.FileId import dev.inmo.tgbotapi.requests.abstracts.FileId
import dev.inmo.tgbotapi.requests.stickers.SetStickerPositionInSet import dev.inmo.tgbotapi.requests.stickers.SetStickerPositionInSet
import dev.inmo.tgbotapi.types.files.Sticker import dev.inmo.tgbotapi.types.files.sticker.Sticker
suspend fun TelegramBot.setStickerPositionInSet( suspend fun TelegramBot.setStickerPositionInSet(
sticker: FileId, sticker: FileId,

View File

@@ -5,7 +5,7 @@ import dev.inmo.tgbotapi.bot.TelegramBot
import dev.inmo.tgbotapi.extensions.api.get.getFileAdditionalInfo import dev.inmo.tgbotapi.extensions.api.get.getFileAdditionalInfo
import dev.inmo.tgbotapi.requests.abstracts.FileId import dev.inmo.tgbotapi.requests.abstracts.FileId
import dev.inmo.tgbotapi.types.files.PathedFile import dev.inmo.tgbotapi.types.files.PathedFile
import dev.inmo.tgbotapi.types.files.TelegramMediaFile import dev.inmo.tgbotapi.types.files.abstracts.TelegramMediaFile
import dev.inmo.tgbotapi.types.message.content.abstracts.MediaContent import dev.inmo.tgbotapi.types.message.content.abstracts.MediaContent
import io.ktor.util.cio.use import io.ktor.util.cio.use
import io.ktor.util.cio.writeChannel import io.ktor.util.cio.writeChannel

View File

@@ -9,6 +9,8 @@ import dev.inmo.micro_utils.coroutines.accumulatorFlow
import kotlinx.coroutines.* import kotlinx.coroutines.*
import kotlinx.coroutines.channels.BufferOverflow import kotlinx.coroutines.channels.BufferOverflow
import kotlinx.coroutines.flow.* import kotlinx.coroutines.flow.*
import kotlin.jvm.JvmName
import kotlin.reflect.KClass
/** /**
* Interface which combine [BehaviourContext] and [StatesMachine]. Subcontext of triggers and states contexts must have * Interface which combine [BehaviourContext] and [StatesMachine]. Subcontext of triggers and states contexts must have
@@ -30,6 +32,25 @@ interface BehaviourContextWithFSM<T : State> : BehaviourContext, StatesMachine<T
} }
} }
/**
* Add NON STRICT [handler] to list of available in future [BehaviourContextWithFSM]. Non strict means that
* for input [State] will be used [KClass.isInstance] and any inheritor of [kClass] will pass this requirement
*
* @see BehaviourWithFSMStateHandlerHolder
* @see onStateOrSubstate
*/
fun <I : T> add(kClass: KClass<I>, strict: Boolean = false, handler: BehaviourWithFSMStateHandler<I, T>)
/**
* Add STRICT [handler] to list of available in future [BehaviourContextWithFSM]. Strict means that
* for input [State] will be used [State]::class == [kClass] and any [State] with exactly the same type will pass
* requirements
*
* @see BehaviourWithFSMStateHandlerHolder
* @see strictlyOn
*/
fun <I : T> addStrict(kClass: KClass<I>, handler: BehaviourWithFSMStateHandler<I, T>) = add(kClass, strict = true, handler)
override fun copy( override fun copy(
bot: TelegramBot, bot: TelegramBot,
scope: CoroutineScope, scope: CoroutineScope,
@@ -48,6 +69,28 @@ interface BehaviourContextWithFSM<T : State> : BehaviourContext, StatesMachine<T
} }
} }
/**
* Add NON STRICT [handler] to list of available in future [BehaviourContextWithFSM]. Non strict means that
* for input [State] will be used [KClass.isInstance] and any inheritor of [kClass] will pass this requirement
*
* @see BehaviourWithFSMStateHandlerHolder
* @see BehaviourContextWithFSM.add
*/
@Suppress("MemberVisibilityCanBePrivate")
inline fun <reified I : O, O: State> BehaviourContextWithFSM<O>.onStateOrSubstate(handler: BehaviourWithFSMStateHandler<I, O>) = add(I::class, strict = false, handler)
/**
* Add STRICT [handler] to list of available in future [BehaviourContextWithFSM]. Strict means that
* for input [State] will be used [State]::class == [kClass] and any [State] with exactly the same type will pass
* requirements
*
* @see BehaviourWithFSMStateHandlerHolder
* @see BehaviourContextWithFSM.addStrict
*/
@Suppress("MemberVisibilityCanBePrivate")
inline fun <reified I : O, O: State> BehaviourContextWithFSM<O>.strictlyOn(handler: BehaviourWithFSMStateHandler<I, O>) = addStrict(I::class, handler)
/** /**
* Default realization of [BehaviourContextWithFSM]. It uses [behaviourContext] as a base for this object as * Default realization of [BehaviourContextWithFSM]. It uses [behaviourContext] as a base for this object as
* [BehaviourContext], but managing substates contexts updates for avoiding of updates lost between states * [BehaviourContext], but managing substates contexts updates for avoiding of updates lost between states
@@ -58,6 +101,9 @@ class DefaultBehaviourContextWithFSM<T : State>(
private val handlers: List<BehaviourWithFSMStateHandlerHolder<*, T>> private val handlers: List<BehaviourWithFSMStateHandlerHolder<*, T>>
) : BehaviourContext by behaviourContext, BehaviourContextWithFSM<T> { ) : BehaviourContext by behaviourContext, BehaviourContextWithFSM<T> {
private val updatesFlows = mutableMapOf<Any, Flow<Update>>() private val updatesFlows = mutableMapOf<Any, Flow<Update>>()
private val additionalHandlers = mutableListOf<BehaviourWithFSMStateHandlerHolder<*, T>>()
private var actualHandlersList = additionalHandlers + handlers
private fun getContextUpdatesFlow(context: Any) = updatesFlows.getOrPut(context) { private fun getContextUpdatesFlow(context: Any) = updatesFlows.getOrPut(context) {
allUpdatesFlow.accumulatorFlow(scope) allUpdatesFlow.accumulatorFlow(scope)
} }
@@ -65,12 +111,17 @@ class DefaultBehaviourContextWithFSM<T : State>(
override suspend fun StatesMachine<in T>.handleState(state: T): T? = launchStateHandling( override suspend fun StatesMachine<in T>.handleState(state: T): T? = launchStateHandling(
state, state,
allUpdatesFlow, allUpdatesFlow,
handlers actualHandlersList
) )
override fun <I : T> add(kClass: KClass<I>, strict: Boolean, handler: BehaviourWithFSMStateHandler<I, T>) {
additionalHandlers.add(BehaviourWithFSMStateHandlerHolder(kClass, strict, handler))
actualHandlersList = additionalHandlers + handlers
}
override fun start(scope: CoroutineScope): Job = scope.launchSafelyWithoutExceptions { override fun start(scope: CoroutineScope): Job = scope.launchSafelyWithoutExceptions {
val statePerformer: suspend (T) -> Unit = { state: T -> val statePerformer: suspend (T) -> Unit = { state: T ->
val newState = launchStateHandling(state, getContextUpdatesFlow(state.context), handlers) val newState = launchStateHandling(state, getContextUpdatesFlow(state.context), actualHandlersList)
if (newState != null) { if (newState != null) {
statesManager.update(state, newState) statesManager.update(state, newState)
} else { } else {
@@ -94,6 +145,26 @@ class DefaultBehaviourContextWithFSM<T : State>(
launch { statePerformer(it) } launch { statePerformer(it) }
} }
} }
/**
* Add NON STRICT [handler] to list of available in future [BehaviourContextWithFSM]. Non strict means that
* for input [State] will be used [KClass.isInstance] and any inheritor of [kClass] will pass this requirement
*
* @see BehaviourWithFSMStateHandlerHolder
* @see BehaviourContextWithFSM.add
*/
@Suppress("MemberVisibilityCanBePrivate")
inline fun <reified I : T> onStateOrSubstate(handler: BehaviourWithFSMStateHandler<I, T>) = add(I::class, strict = false, handler)
/**
* Add STRICT [handler] to list of available in future [BehaviourContextWithFSM]. Strict means that
* for input [State] will be used [State]::class == [kClass] and any [State] with exactly the same type will pass
* requirements
*
* @see BehaviourWithFSMStateHandlerHolder
* @see BehaviourContextWithFSM.addStrict
*/
@Suppress("MemberVisibilityCanBePrivate")
inline fun <reified I : T> strictlyOn(handler: BehaviourWithFSMStateHandler<I, T>) = addStrict(I::class, handler)
override suspend fun startChain(state: T) { override suspend fun startChain(state: T) {
statesManager.startChain(state) statesManager.startChain(state)
@@ -106,7 +177,7 @@ class DefaultBehaviourContextWithFSM<T : State>(
onBufferOverflow: BufferOverflow, onBufferOverflow: BufferOverflow,
upstreamUpdatesFlow: Flow<Update>?, upstreamUpdatesFlow: Flow<Update>?,
updatesFilter: BehaviourContextAndTypeReceiver<Boolean, Update>? updatesFilter: BehaviourContextAndTypeReceiver<Boolean, Update>?
): BehaviourContextWithFSM<T> = BehaviourContextWithFSM( ): DefaultBehaviourContextWithFSM<T> = BehaviourContextWithFSM(
behaviourContext.copy(bot, scope, broadcastChannelsSize, onBufferOverflow, upstreamUpdatesFlow, updatesFilter), behaviourContext.copy(bot, scope, broadcastChannelsSize, onBufferOverflow, upstreamUpdatesFlow, updatesFilter),
handlers, handlers,
statesManager statesManager

View File

@@ -14,70 +14,8 @@ import kotlinx.coroutines.*
import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.Flow
import kotlin.reflect.KClass import kotlin.reflect.KClass
class BehaviourContextWithFSMBuilder<T : State> internal constructor( @Deprecated("Will be removed soon")
private val resultBehaviourContext: BehaviourContextWithFSM<T>, typealias BehaviourContextWithFSMBuilder<T> = BehaviourContextWithFSM<T>
private val handlers: MutableList<BehaviourWithFSMStateHandlerHolder<*, T>>
) : BehaviourContextWithFSM<T> by resultBehaviourContext {
internal constructor(
baseBehaviourContext: BehaviourContext,
statesManager: StatesManager<T> = DefaultStatesManager(InMemoryDefaultStatesManagerRepo()),
handlers: MutableList<BehaviourWithFSMStateHandlerHolder<*, T>> = mutableListOf()
) : this(DefaultBehaviourContextWithFSM(baseBehaviourContext, statesManager, handlers), handlers)
/**
* Add NON STRICT [handler] to list of available in future [BehaviourContextWithFSM]. Non strict means that
* for input [State] will be used [KClass.isInstance] and any inheritor of [kClass] will pass this requirement
*
* @see BehaviourWithFSMStateHandlerHolder
* @see onStateOrSubstate
*/
fun <I : T> add(kClass: KClass<I>, handler: BehaviourWithFSMStateHandler<I, T>) {
handlers.add(BehaviourWithFSMStateHandlerHolder(kClass, false, handler))
}
/**
* Add STRICT [handler] to list of available in future [BehaviourContextWithFSM]. Strict means that
* for input [State] will be used [State]::class == [kClass] and any [State] with exactly the same type will pass
* requirements
*
* @see BehaviourWithFSMStateHandlerHolder
* @see strictlyOn
*/
fun <I : T> addStrict(kClass: KClass<I>, handler: BehaviourWithFSMStateHandler<I, T>) {
handlers.add(BehaviourWithFSMStateHandlerHolder(kClass, true, handler))
}
/**
* Add NON STRICT [handler] to list of available in future [BehaviourContextWithFSM]. Non strict means that
* for input [State] will be used [KClass.isInstance] and any inheritor of [kClass] will pass this requirement
*
* @see BehaviourWithFSMStateHandlerHolder
* @see BehaviourContextWithFSMBuilder.add
*/
@Suppress("MemberVisibilityCanBePrivate")
inline fun <reified I : T> onStateOrSubstate(handler: BehaviourWithFSMStateHandler<I, T>) {
add(I::class, handler)
}
/**
* Add STRICT [handler] to list of available in future [BehaviourContextWithFSM]. Strict means that
* for input [State] will be used [State]::class == [kClass] and any [State] with exactly the same type will pass
* requirements
*
* @see BehaviourWithFSMStateHandlerHolder
* @see BehaviourContextWithFSMBuilder.addStrict
*/
@Suppress("MemberVisibilityCanBePrivate")
inline fun <reified I : T> strictlyOn(handler: BehaviourWithFSMStateHandler<I, T>) {
addStrict(I::class, handler)
}
/**
* Returns completed [resultBehaviourContext], [handlers] and [statesManager]
*/
internal fun build() = resultBehaviourContext
}
/** /**
* Creates [BehaviourContextWithFSM] via creating of [DefaultBehaviourContext] with [this] as [TelegramBot], * Creates [BehaviourContextWithFSM] via creating of [DefaultBehaviourContext] with [this] as [TelegramBot],
@@ -94,17 +32,17 @@ suspend fun <T : State> TelegramBot.buildBehaviourWithFSM(
scope: CoroutineScope = defaultCoroutineScopeProvider(), scope: CoroutineScope = defaultCoroutineScopeProvider(),
defaultExceptionsHandler: ExceptionHandler<Unit>? = null, defaultExceptionsHandler: ExceptionHandler<Unit>? = null,
statesManager: StatesManager<T> = DefaultStatesManager(InMemoryDefaultStatesManagerRepo()), statesManager: StatesManager<T> = DefaultStatesManager(InMemoryDefaultStatesManagerRepo()),
presetHandlers: MutableList<BehaviourWithFSMStateHandlerHolder<*, T>> = mutableListOf(), presetHandlers: List<BehaviourWithFSMStateHandlerHolder<*, T>> = listOf(),
block: CustomBehaviourContextReceiver<BehaviourContextWithFSMBuilder<T>, Unit> block: CustomBehaviourContextReceiver<DefaultBehaviourContextWithFSM<T>, Unit>
): BehaviourContextWithFSM<T> = BehaviourContextWithFSMBuilder( ): DefaultBehaviourContextWithFSM<T> = BehaviourContextWithFSM(
DefaultBehaviourContext( DefaultBehaviourContext(
this, this,
defaultExceptionsHandler ?.let { scope + ContextSafelyExceptionHandler(it) } ?: scope, defaultExceptionsHandler ?.let { scope + ContextSafelyExceptionHandler(it) } ?: scope,
upstreamUpdatesFlow = upstreamUpdatesFlow upstreamUpdatesFlow = upstreamUpdatesFlow
), ),
statesManager, presetHandlers,
presetHandlers statesManager
).apply { block() }.build() ).apply { block() }
/** /**
* Use [buildBehaviourWithFSM] to create [BehaviourContextWithFSM] and launch getting of updates * Use [buildBehaviourWithFSM] to create [BehaviourContextWithFSM] and launch getting of updates
@@ -116,9 +54,9 @@ suspend fun <T : State> TelegramBot.buildBehaviourWithFSMAndStartLongPolling(
scope: CoroutineScope = defaultCoroutineScopeProvider(), scope: CoroutineScope = defaultCoroutineScopeProvider(),
defaultExceptionsHandler: ExceptionHandler<Unit>? = null, defaultExceptionsHandler: ExceptionHandler<Unit>? = null,
statesManager: StatesManager<T> = DefaultStatesManager(InMemoryDefaultStatesManagerRepo()), statesManager: StatesManager<T> = DefaultStatesManager(InMemoryDefaultStatesManagerRepo()),
presetHandlers: MutableList<BehaviourWithFSMStateHandlerHolder<*, T>> = mutableListOf(), presetHandlers: List<BehaviourWithFSMStateHandlerHolder<*, T>> = listOf(),
block: CustomBehaviourContextReceiver<BehaviourContextWithFSMBuilder<T>, Unit> block: CustomBehaviourContextReceiver<DefaultBehaviourContextWithFSM<T>, Unit>
): Pair<BehaviourContextWithFSM<T>, Job> = buildBehaviourWithFSM( ): Pair<DefaultBehaviourContextWithFSM<T>, Job> = buildBehaviourWithFSM(
upstreamUpdatesFlow, upstreamUpdatesFlow,
scope, scope,
defaultExceptionsHandler, defaultExceptionsHandler,
@@ -147,8 +85,8 @@ suspend fun <T : State> TelegramBot.buildBehaviourWithFSMAndStartLongPolling(
* @see BehaviourContext * @see BehaviourContext
* @see BehaviourContextWithFSM * @see BehaviourContextWithFSM
* @see longPolling * @see longPolling
* @see BehaviourContextWithFSMBuilder.strictlyOn * @see BehaviourContextWithFSM.strictlyOn
* @see BehaviourContextWithFSMBuilder.onStateOrSubstate * @see BehaviourContextWithFSM.onStateOrSubstate
*/ */
@PreviewFeature @PreviewFeature
suspend fun <T : State> TelegramBot.buildBehaviourWithFSM( suspend fun <T : State> TelegramBot.buildBehaviourWithFSM(
@@ -156,17 +94,17 @@ suspend fun <T : State> TelegramBot.buildBehaviourWithFSM(
scope: CoroutineScope = defaultCoroutineScopeProvider(), scope: CoroutineScope = defaultCoroutineScopeProvider(),
defaultExceptionsHandler: ExceptionHandler<Unit>? = null, defaultExceptionsHandler: ExceptionHandler<Unit>? = null,
statesManager: StatesManager<T> = DefaultStatesManager(InMemoryDefaultStatesManagerRepo()), statesManager: StatesManager<T> = DefaultStatesManager(InMemoryDefaultStatesManagerRepo()),
presetHandlers: MutableList<BehaviourWithFSMStateHandlerHolder<*, T>> = mutableListOf(), presetHandlers: List<BehaviourWithFSMStateHandlerHolder<*, T>> = listOf(),
block: CustomBehaviourContextReceiver<BehaviourContextWithFSMBuilder<T>, Unit> block: CustomBehaviourContextReceiver<DefaultBehaviourContextWithFSM<T>, Unit>
): BehaviourContextWithFSM<T> = BehaviourContextWithFSMBuilder( ): DefaultBehaviourContextWithFSM<T> = BehaviourContextWithFSM(
DefaultBehaviourContext( DefaultBehaviourContext(
this, this,
defaultExceptionsHandler ?.let { scope + ContextSafelyExceptionHandler(it) } ?: scope, defaultExceptionsHandler ?.let { scope + ContextSafelyExceptionHandler(it) } ?: scope,
upstreamUpdatesFlow = flowUpdatesFilter.allUpdatesFlow upstreamUpdatesFlow = flowUpdatesFilter.allUpdatesFlow
), ),
statesManager, presetHandlers,
presetHandlers statesManager
).apply { block() }.build() ).apply { block() }
/** /**
* Use [buildBehaviourWithFSM] to create [BehaviourContextWithFSM] and launch getting of updates * Use [buildBehaviourWithFSM] to create [BehaviourContextWithFSM] and launch getting of updates
@@ -176,16 +114,16 @@ suspend fun <T : State> TelegramBot.buildBehaviourWithFSM(
* @see buildBehaviourWithFSMAndStartLongPolling * @see buildBehaviourWithFSMAndStartLongPolling
* @see BehaviourContext * @see BehaviourContext
* @see longPolling * @see longPolling
* @see BehaviourContextWithFSMBuilder.strictlyOn * @see BehaviourContextWithFSM.strictlyOn
* @see BehaviourContextWithFSMBuilder.onStateOrSubstate * @see BehaviourContextWithFSM.onStateOrSubstate
*/ */
@PreviewFeature @PreviewFeature
suspend fun <T : State> TelegramBot.buildBehaviourWithFSMAndStartLongPolling( suspend fun <T : State> TelegramBot.buildBehaviourWithFSMAndStartLongPolling(
scope: CoroutineScope = defaultCoroutineScopeProvider(), scope: CoroutineScope = defaultCoroutineScopeProvider(),
defaultExceptionsHandler: ExceptionHandler<Unit>? = null, defaultExceptionsHandler: ExceptionHandler<Unit>? = null,
statesManager: StatesManager<T> = DefaultStatesManager(InMemoryDefaultStatesManagerRepo()), statesManager: StatesManager<T> = DefaultStatesManager(InMemoryDefaultStatesManagerRepo()),
presetHandlers: MutableList<BehaviourWithFSMStateHandlerHolder<*, T>> = mutableListOf(), presetHandlers: List<BehaviourWithFSMStateHandlerHolder<*, T>> = listOf(),
block: CustomBehaviourContextReceiver<BehaviourContextWithFSMBuilder<T>, Unit> block: CustomBehaviourContextReceiver<DefaultBehaviourContextWithFSM<T>, Unit>
) = FlowsUpdatesFilter().let { ) = FlowsUpdatesFilter().let {
buildBehaviourWithFSM( buildBehaviourWithFSM(
it, it,

View File

@@ -37,11 +37,13 @@ suspend fun <T : State> telegramBotWithBehaviourAndFSM(
builder: KtorRequestsExecutorBuilder.() -> Unit = {}, builder: KtorRequestsExecutorBuilder.() -> Unit = {},
defaultExceptionsHandler: ExceptionHandler<Unit>? = null, defaultExceptionsHandler: ExceptionHandler<Unit>? = null,
statesManager: StatesManager<T> = DefaultStatesManager(InMemoryDefaultStatesManagerRepo()), statesManager: StatesManager<T> = DefaultStatesManager(InMemoryDefaultStatesManagerRepo()),
presetHandlers: MutableList<BehaviourWithFSMStateHandlerHolder<*, T>> = mutableListOf(), presetHandlers: List<BehaviourWithFSMStateHandlerHolder<*, T>> = listOf(),
block: CustomBehaviourContextReceiver<BehaviourContextWithFSMBuilder<T>, Unit> testServer: Boolean = false,
block: CustomBehaviourContextReceiver<DefaultBehaviourContextWithFSM<T>, Unit>
): TelegramBot = telegramBot( ): TelegramBot = telegramBot(
token, token,
apiUrl, apiUrl,
testServer,
builder builder
).apply { ).apply {
buildBehaviourWithFSMAndStartLongPolling( buildBehaviourWithFSMAndStartLongPolling(
@@ -72,12 +74,14 @@ suspend fun <T : State> telegramBotWithBehaviourAndFSMAndStartLongPolling(
builder: KtorRequestsExecutorBuilder.() -> Unit = {}, builder: KtorRequestsExecutorBuilder.() -> Unit = {},
defaultExceptionsHandler: ExceptionHandler<Unit>? = null, defaultExceptionsHandler: ExceptionHandler<Unit>? = null,
statesManager: StatesManager<T> = DefaultStatesManager(InMemoryDefaultStatesManagerRepo()), statesManager: StatesManager<T> = DefaultStatesManager(InMemoryDefaultStatesManagerRepo()),
presetHandlers: MutableList<BehaviourWithFSMStateHandlerHolder<*, T>> = mutableListOf(), presetHandlers: List<BehaviourWithFSMStateHandlerHolder<*, T>> = listOf(),
block: CustomBehaviourContextReceiver<BehaviourContextWithFSMBuilder<T>, Unit> testServer: Boolean = false,
block: CustomBehaviourContextReceiver<DefaultBehaviourContextWithFSM<T>, Unit>
): Pair<TelegramBot, Job> { ): Pair<TelegramBot, Job> {
return telegramBot( return telegramBot(
token, token,
apiUrl, apiUrl,
testServer,
builder builder
).let { ).let {
it to it.buildBehaviourWithFSMAndStartLongPolling ( it to it.buildBehaviourWithFSMAndStartLongPolling (

View File

@@ -26,7 +26,7 @@ internal inline fun <BC, T, I1, I2> CustomBehaviourContextAndTwoTypesReceiver<BC
): CustomBehaviourContextAndTypeReceiver<BC, T, I2> = { invoke(this, i1, it) } ): CustomBehaviourContextAndTypeReceiver<BC, T, I2> = { invoke(this, i1, it) }
/** /**
* This class contains all necessary tools for work with bots and especially for [buildBehaviour] * This class contains all necessary tools for work with bots and especially [buildBehaviour]
* *
* @see DefaultBehaviourContext * @see DefaultBehaviourContext
*/ */
@@ -90,7 +90,7 @@ class DefaultBehaviourContext(
onBufferOverflow: BufferOverflow, onBufferOverflow: BufferOverflow,
upstreamUpdatesFlow: Flow<Update>?, upstreamUpdatesFlow: Flow<Update>?,
updatesFilter: BehaviourContextAndTypeReceiver<Boolean, Update>? updatesFilter: BehaviourContextAndTypeReceiver<Boolean, Update>?
): BehaviourContext = DefaultBehaviourContext(bot, scope, broadcastChannelsSize, onBufferOverflow, upstreamUpdatesFlow, updatesFilter) ): DefaultBehaviourContext = DefaultBehaviourContext(bot, scope, broadcastChannelsSize, onBufferOverflow, upstreamUpdatesFlow, updatesFilter)
} }
fun BehaviourContext( fun BehaviourContext(
@@ -116,19 +116,20 @@ suspend fun <T, BC : BehaviourContext> BC.doInSubContextWithUpdatesFilter(
updatesUpstreamFlow: Flow<Update> = allUpdatesFlow, updatesUpstreamFlow: Flow<Update> = allUpdatesFlow,
scope: CoroutineScope = LinkedSupervisorScope(), scope: CoroutineScope = LinkedSupervisorScope(),
behaviourContextReceiver: CustomBehaviourContextReceiver<BC, T> behaviourContextReceiver: CustomBehaviourContextReceiver<BC, T>
): T = copy( ): T {
scope = scope, val newContext = copy(
updatesFilter = updatesFilter ?.let { _ -> scope = scope,
{ updatesFilter = updatesFilter ?.let { _ ->
(this as? BC) ?.run { {
updatesFilter(it) (this as? BC) ?.run {
} ?: true updatesFilter(it)
} } ?: true
}, }
upstreamUpdatesFlow = updatesUpstreamFlow },
).run { upstreamUpdatesFlow = updatesUpstreamFlow
withContext(coroutineContext) { ) as BC
behaviourContextReceiver().also { if (stopOnCompletion) stop() } return withContext(currentCoroutineContext()) {
newContext.behaviourContextReceiver().also { if (stopOnCompletion) newContext.stop() }
} }
} }

View File

@@ -30,10 +30,12 @@ suspend fun telegramBotWithBehaviour(
apiUrl: String = telegramBotAPIDefaultUrl, apiUrl: String = telegramBotAPIDefaultUrl,
builder: KtorRequestsExecutorBuilder.() -> Unit = {}, builder: KtorRequestsExecutorBuilder.() -> Unit = {},
defaultExceptionsHandler: ExceptionHandler<Unit>? = null, defaultExceptionsHandler: ExceptionHandler<Unit>? = null,
testServer: Boolean = false,
block: BehaviourContextReceiver<Unit> block: BehaviourContextReceiver<Unit>
): TelegramBot = telegramBot( ): TelegramBot = telegramBot(
token, token,
apiUrl, apiUrl,
testServer,
builder builder
).apply { ).apply {
buildBehaviour( buildBehaviour(
@@ -63,11 +65,13 @@ suspend fun telegramBotWithBehaviourAndLongPolling(
apiUrl: String = telegramBotAPIDefaultUrl, apiUrl: String = telegramBotAPIDefaultUrl,
builder: KtorRequestsExecutorBuilder.() -> Unit = {}, builder: KtorRequestsExecutorBuilder.() -> Unit = {},
defaultExceptionsHandler: ExceptionHandler<Unit>? = null, defaultExceptionsHandler: ExceptionHandler<Unit>? = null,
testServer: Boolean = false,
block: BehaviourContextReceiver<Unit> block: BehaviourContextReceiver<Unit>
): Pair<TelegramBot, Job> { ): Pair<TelegramBot, Job> {
return telegramBot( return telegramBot(
token, token,
apiUrl, apiUrl,
testServer,
builder builder
).let { ).let {
it to it.buildBehaviourWithLongPolling( it to it.buildBehaviourWithLongPolling(

View File

@@ -35,7 +35,7 @@ private suspend inline fun <reified T : CallbackQuery> BehaviourContext.waitCall
count: Int = 1, count: Int = 1,
initRequest: Request<*>? = null, initRequest: Request<*>? = null,
noinline errorFactory: NullableRequestBuilder<*> = { null }, noinline errorFactory: NullableRequestBuilder<*> = { null },
filter: SimpleFilter<T>? = null, noinline filter: SimpleFilter<T>? = null,
noinline mapper: CallbackQueryMapper<T>? = null noinline mapper: CallbackQueryMapper<T>? = null
) : List<T> = waitCallbackQueries<T>( ) : List<T> = waitCallbackQueries<T>(
count, count,

View File

@@ -15,7 +15,7 @@ private suspend inline fun <reified T : ChatMemberUpdatedUpdate> BehaviourContex
count: Int = 1, count: Int = 1,
initRequest: Request<*>? = null, initRequest: Request<*>? = null,
noinline errorFactory: NullableRequestBuilder<*> = { null }, noinline errorFactory: NullableRequestBuilder<*> = { null },
filter: SimpleFilter<T>? = null, noinline filter: SimpleFilter<T>? = null,
noinline mapper: ChatMemberUpdatedMapper<ChatMemberUpdated> noinline mapper: ChatMemberUpdatedMapper<ChatMemberUpdated>
): List<ChatMemberUpdated> = expectFlow( ): List<ChatMemberUpdated> = expectFlow(
initRequest, initRequest,
@@ -34,7 +34,7 @@ private suspend inline fun <reified T : ChatMemberUpdatedUpdate> BehaviourContex
count: Int = 1, count: Int = 1,
initRequest: Request<*>? = null, initRequest: Request<*>? = null,
noinline errorFactory: NullableRequestBuilder<*> = { null }, noinline errorFactory: NullableRequestBuilder<*> = { null },
filter: SimpleFilter<T>? = null, noinline filter: SimpleFilter<T>? = null,
noinline mapper: ChatMemberUpdatedMapper<ChatMemberUpdated>? = null noinline mapper: ChatMemberUpdatedMapper<ChatMemberUpdated>? = null
) : List<ChatMemberUpdated> = waitChatMemberUpdated<T>( ) : List<ChatMemberUpdated> = waitChatMemberUpdated<T>(
count, count,

View File

@@ -34,7 +34,7 @@ private suspend inline fun <reified T : ChosenInlineResult> BehaviourContext.wai
count: Int = 1, count: Int = 1,
initRequest: Request<*>? = null, initRequest: Request<*>? = null,
noinline errorFactory: NullableRequestBuilder<*> = { null }, noinline errorFactory: NullableRequestBuilder<*> = { null },
filter: SimpleFilter<T>? = null, noinline filter: SimpleFilter<T>? = null,
noinline mapper: ChosenInlineResultMapper<T>? = null noinline mapper: ChosenInlineResultMapper<T>? = null
) : List<T> = this@waitChosenInlineResults.waitChosenInlineResultsUpdates<T>( ) : List<T> = this@waitChosenInlineResults.waitChosenInlineResultsUpdates<T>(
count, count,

View File

@@ -75,7 +75,7 @@ private suspend inline fun <reified T : MessageContent> BehaviourContext.waitCon
initRequest: Request<*>? = null, initRequest: Request<*>? = null,
includeMediaGroups: Boolean = true, includeMediaGroups: Boolean = true,
noinline errorFactory: NullableRequestBuilder<*> = { null }, noinline errorFactory: NullableRequestBuilder<*> = { null },
filter: SimpleFilter<CommonMessage<T>>? = null, noinline filter: SimpleFilter<CommonMessage<T>>? = null,
noinline mapper: CommonMessageToContentMapper<T>? = null noinline mapper: CommonMessageToContentMapper<T>? = null
) : List<T> = waitCommonContent<T>( ) : List<T> = waitCommonContent<T>(
count, count,

View File

@@ -78,7 +78,7 @@ private suspend inline fun <reified T : MessageContent> BehaviourContext.waitCon
initRequest: Request<*>? = null, initRequest: Request<*>? = null,
includeMediaGroups: Boolean = true, includeMediaGroups: Boolean = true,
noinline errorFactory: NullableRequestBuilder<*> = { null }, noinline errorFactory: NullableRequestBuilder<*> = { null },
filter: SimpleFilter<CommonMessage<T>>? = null, noinline filter: SimpleFilter<CommonMessage<T>>? = null,
noinline mapper: CommonMessageToCommonMessageMapper<T>? = null noinline mapper: CommonMessageToCommonMessageMapper<T>? = null
) : List<CommonMessage<T>> = waitCommonMessage<T>( ) : List<CommonMessage<T>> = waitCommonMessage<T>(
count, count,

View File

@@ -58,7 +58,7 @@ private suspend inline fun <reified T : MessageContent> BehaviourContext.waitEdi
initRequest: Request<*>? = null, initRequest: Request<*>? = null,
includeMediaGroups: Boolean = true, includeMediaGroups: Boolean = true,
noinline errorFactory: NullableRequestBuilder<*> = { null }, noinline errorFactory: NullableRequestBuilder<*> = { null },
filter: SimpleFilter<CommonMessage<T>>? = null, noinline filter: SimpleFilter<CommonMessage<T>>? = null,
noinline mapper: CommonMessageToContentMapper<T>? = null noinline mapper: CommonMessageToContentMapper<T>? = null
) : List<T> = waitEditedCommonMessage<T>( ) : List<T> = waitEditedCommonMessage<T>(
count, count,

View File

@@ -41,7 +41,7 @@ private suspend inline fun <reified T : ChatEvent> BehaviourContext.waitEvents(
count: Int = 1, count: Int = 1,
initRequest: Request<*>? = null, initRequest: Request<*>? = null,
noinline errorFactory: NullableRequestBuilder<*> = { null }, noinline errorFactory: NullableRequestBuilder<*> = { null },
filter: SimpleFilter<ChatEventMessage<T>>? = null, noinline filter: SimpleFilter<ChatEventMessage<T>>? = null,
noinline mapper: EventMessageToEventMapper<T>? = null noinline mapper: EventMessageToEventMapper<T>? = null
) : List<T> = waitEventMessages<T>( ) : List<T> = waitEventMessages<T>(
initRequest, initRequest,

View File

@@ -33,7 +33,7 @@ private suspend inline fun <reified T : InlineQuery> BehaviourContext.waitInline
count: Int = 1, count: Int = 1,
initRequest: Request<*>? = null, initRequest: Request<*>? = null,
noinline errorFactory: NullableRequestBuilder<*> = { null }, noinline errorFactory: NullableRequestBuilder<*> = { null },
filter: SimpleFilter<T>? = null, noinline filter: SimpleFilter<T>? = null,
noinline mapper: InlineQueryMapper<T>? = null noinline mapper: InlineQueryMapper<T>? = null
) : List<T> = waitInlineQueries<T>( ) : List<T> = waitInlineQueries<T>(
count, count,

View File

@@ -37,7 +37,7 @@ suspend inline fun <reified T : EncryptedPassportElement> BehaviourContext.waitP
count: Int = 1, count: Int = 1,
initRequest: Request<*>? = null, initRequest: Request<*>? = null,
noinline errorFactory: NullableRequestBuilder<*> = { null }, noinline errorFactory: NullableRequestBuilder<*> = { null },
filter: SimpleFilter<PassportMessage>? = null, noinline filter: SimpleFilter<PassportMessage>? = null,
noinline mapper: PassportMessageMapper? = null noinline mapper: PassportMessageMapper? = null
) : List<PassportData> = waitPassportMessages( ) : List<PassportData> = waitPassportMessages(
initRequest, initRequest,

View File

@@ -33,7 +33,7 @@ private suspend inline fun BehaviourContext.waitPollAnswers(
count: Int = 1, count: Int = 1,
initRequest: Request<*>? = null, initRequest: Request<*>? = null,
noinline errorFactory: NullableRequestBuilder<*> = { null }, noinline errorFactory: NullableRequestBuilder<*> = { null },
filter: SimpleFilter<PollAnswer>? = null, noinline filter: SimpleFilter<PollAnswer>? = null,
noinline mapper: PollAnswerMapper? = null noinline mapper: PollAnswerMapper? = null
) : List<PollAnswer> = this@waitPollAnswers.waitPollsAnswers<PollAnswer>( ) : List<PollAnswer> = this@waitPollAnswers.waitPollsAnswers<PollAnswer>(
count, count,

View File

@@ -33,7 +33,7 @@ private suspend inline fun <reified T : Poll> BehaviourContext.waitPolls(
count: Int = 1, count: Int = 1,
initRequest: Request<*>? = null, initRequest: Request<*>? = null,
noinline errorFactory: NullableRequestBuilder<*> = { null }, noinline errorFactory: NullableRequestBuilder<*> = { null },
filter: SimpleFilter<T>? = null, noinline filter: SimpleFilter<T>? = null,
noinline mapper: PollMapper<T>? = null noinline mapper: PollMapper<T>? = null
) : List<T> = this@waitPolls.waitPollsUpdates<T>( ) : List<T> = this@waitPolls.waitPollsUpdates<T>(
count, count,

View File

@@ -2,9 +2,8 @@ package dev.inmo.tgbotapi.extensions.behaviour_builder.filters
import dev.inmo.tgbotapi.extensions.behaviour_builder.BehaviourContextAndTwoTypesReceiver import dev.inmo.tgbotapi.extensions.behaviour_builder.BehaviourContextAndTwoTypesReceiver
import dev.inmo.tgbotapi.extensions.behaviour_builder.triggers_handling.CommonMessageFilter import dev.inmo.tgbotapi.extensions.behaviour_builder.triggers_handling.CommonMessageFilter
import dev.inmo.tgbotapi.extensions.behaviour_builder.utils.SimpleFilter import dev.inmo.tgbotapi.types.message.abstracts.CommonMessage
import dev.inmo.tgbotapi.types.message.abstracts.* import dev.inmo.tgbotapi.types.message.abstracts.MediaGroupMessage
import dev.inmo.tgbotapi.types.message.content.abstracts.MessageContent
import dev.inmo.tgbotapi.types.update.abstracts.Update import dev.inmo.tgbotapi.types.update.abstracts.Update
/** /**
@@ -17,6 +16,6 @@ val MessageFilterExcludingMediaGroups: BehaviourContextAndTwoTypesReceiver<Boole
/** /**
* Allow only messages which are not [MediaGroupMessage] * Allow only messages which are not [MediaGroupMessage]
*/ */
val CommonMessageFilterExcludeMediaGroups = SimpleFilter<Message> { val CommonMessageFilterExcludeMediaGroups: CommonMessageFilter<*> = {
it !is MediaGroupMessage<*> it !is MediaGroupMessage<*>
} }

View File

@@ -7,12 +7,13 @@ import dev.inmo.tgbotapi.extensions.behaviour_builder.filters.CallbackQueryFilte
import dev.inmo.tgbotapi.extensions.behaviour_builder.utils.SimpleFilter import dev.inmo.tgbotapi.extensions.behaviour_builder.utils.SimpleFilter
import dev.inmo.tgbotapi.extensions.behaviour_builder.utils.marker_factories.ByUserCallbackQueryMarkerFactory import dev.inmo.tgbotapi.extensions.behaviour_builder.utils.marker_factories.ByUserCallbackQueryMarkerFactory
import dev.inmo.tgbotapi.extensions.behaviour_builder.utils.marker_factories.MarkerFactory import dev.inmo.tgbotapi.extensions.behaviour_builder.utils.marker_factories.MarkerFactory
import dev.inmo.tgbotapi.extensions.behaviour_builder.utils.plus
import dev.inmo.tgbotapi.extensions.utils.asCallbackQueryUpdate import dev.inmo.tgbotapi.extensions.utils.asCallbackQueryUpdate
import dev.inmo.tgbotapi.types.CallbackQuery.* import dev.inmo.tgbotapi.types.CallbackQuery.*
import dev.inmo.tgbotapi.types.update.abstracts.Update import dev.inmo.tgbotapi.types.update.abstracts.Update
internal suspend inline fun <BC : BehaviourContext, reified T : CallbackQuery> BC.onCallbackQuery( internal suspend inline fun <BC : BehaviourContext, reified T : CallbackQuery> BC.onCallbackQuery(
initialFilter: SimpleFilter<T>? = null, noinline initialFilter: SimpleFilter<T>? = null,
noinline subcontextUpdatesFilter: CustomBehaviourContextAndTwoTypesReceiver<BC, Boolean, T, Update>? = CallbackQueryFilterByUser, noinline subcontextUpdatesFilter: CustomBehaviourContextAndTwoTypesReceiver<BC, Boolean, T, Update>? = CallbackQueryFilterByUser,
markerFactory: MarkerFactory<in T, Any> = ByUserCallbackQueryMarkerFactory, markerFactory: MarkerFactory<in T, Any> = ByUserCallbackQueryMarkerFactory,
noinline scenarioReceiver: CustomBehaviourContextAndTypeReceiver<BC, Unit, T> noinline scenarioReceiver: CustomBehaviourContextAndTypeReceiver<BC, Unit, T>
@@ -44,6 +45,62 @@ suspend fun <BC : BehaviourContext> BC.onDataCallbackQuery(
scenarioReceiver scenarioReceiver
) )
/**
* @param dataRegex Will be used with [initialFilter] as [initialFilter] for upstream [onDataCallbackQuery] to filter
* [DataCallbackQuery] with [DataCallbackQuery.data] [String.matches] to [dataRegex]
* @param initialFilter This filter will be called to remove unnecessary data BEFORE [scenarioReceiver] call
* @param subcontextUpdatesFilter This filter will be applied to each update inside of [scenarioReceiver]. For example,
* this filter will be used if you will call [dev.inmo.tgbotapi.extensions.behaviour_builder.expectations.waitContentMessage].
* Use [dev.inmo.tgbotapi.extensions.behaviour_builder.BehaviourContextAndTwoTypesReceiver] function to create your own.
* Use [dev.inmo.tgbotapi.extensions.behaviour_builder.utils.plus] or [dev.inmo.tgbotapi.extensions.behaviour_builder.utils.times]
* to combinate several filters
* @param [markerFactory] Will be used to identify different "stream". [scenarioReceiver] will be called synchronously
* in one "stream". Output of [markerFactory] will be used as a key for "stream"
* @param scenarioReceiver Main callback which will be used to handle incoming data if [initialFilter] will pass that
* data
*/
suspend fun <BC : BehaviourContext> BC.onDataCallbackQuery(
dataRegex: Regex,
initialFilter: SimpleFilter<DataCallbackQuery>? = null,
subcontextUpdatesFilter: CustomBehaviourContextAndTwoTypesReceiver<BC, Boolean, DataCallbackQuery, Update>? = CallbackQueryFilterByUser,
markerFactory: MarkerFactory<in DataCallbackQuery, Any> = ByUserCallbackQueryMarkerFactory,
scenarioReceiver: CustomBehaviourContextAndTypeReceiver<BC, Unit, DataCallbackQuery>
) = onDataCallbackQuery(
initialFilter = initialFilter + {
it.data.matches(dataRegex)
},
subcontextUpdatesFilter,
markerFactory,
scenarioReceiver
)
/**
* @param data Will be converted to [Regex] via its constructor and pass it to upstream [onDataCallbackQuery]
* @param initialFilter This filter will be called to remove unnecessary data BEFORE [scenarioReceiver] call
* @param subcontextUpdatesFilter This filter will be applied to each update inside of [scenarioReceiver]. For example,
* this filter will be used if you will call [dev.inmo.tgbotapi.extensions.behaviour_builder.expectations.waitContentMessage].
* Use [dev.inmo.tgbotapi.extensions.behaviour_builder.BehaviourContextAndTwoTypesReceiver] function to create your own.
* Use [dev.inmo.tgbotapi.extensions.behaviour_builder.utils.plus] or [dev.inmo.tgbotapi.extensions.behaviour_builder.utils.times]
* to combinate several filters
* @param [markerFactory] Will be used to identify different "stream". [scenarioReceiver] will be called synchronously
* in one "stream". Output of [markerFactory] will be used as a key for "stream"
* @param scenarioReceiver Main callback which will be used to handle incoming data if [initialFilter] will pass that
* data
*/
suspend fun <BC : BehaviourContext> BC.onDataCallbackQuery(
data: String,
initialFilter: SimpleFilter<DataCallbackQuery>? = null,
subcontextUpdatesFilter: CustomBehaviourContextAndTwoTypesReceiver<BC, Boolean, DataCallbackQuery, Update>? = CallbackQueryFilterByUser,
markerFactory: MarkerFactory<in DataCallbackQuery, Any> = ByUserCallbackQueryMarkerFactory,
scenarioReceiver: CustomBehaviourContextAndTypeReceiver<BC, Unit, DataCallbackQuery>
) = onDataCallbackQuery(
Regex(data),
initialFilter,
subcontextUpdatesFilter,
markerFactory,
scenarioReceiver
)
/** /**
* @param initialFilter This filter will be called to remove unnecessary data BEFORE [scenarioReceiver] call * @param initialFilter This filter will be called to remove unnecessary data BEFORE [scenarioReceiver] call
* @param subcontextUpdatesFilter This filter will be applied to each update inside of [scenarioReceiver]. For example, * @param subcontextUpdatesFilter This filter will be applied to each update inside of [scenarioReceiver]. For example,
@@ -116,6 +173,62 @@ suspend fun <BC : BehaviourContext> BC.onInlineMessageIdDataCallbackQuery(
scenarioReceiver scenarioReceiver
) )
/**
* @param dataRegex Will be used with [initialFilter] as [initialFilter] for upstream [onInlineMessageIdDataCallbackQuery]
* to filter [InlineMessageIdDataCallbackQuery] with [InlineMessageIdDataCallbackQuery.data] [String.matches] to [dataRegex]
* @param initialFilter This filter will be called to remove unnecessary data BEFORE [scenarioReceiver] call
* @param subcontextUpdatesFilter This filter will be applied to each update inside of [scenarioReceiver]. For example,
* this filter will be used if you will call [dev.inmo.tgbotapi.extensions.behaviour_builder.expectations.waitContentMessage].
* Use [dev.inmo.tgbotapi.extensions.behaviour_builder.BehaviourContextAndTwoTypesReceiver] function to create your own.
* Use [dev.inmo.tgbotapi.extensions.behaviour_builder.utils.plus] or [dev.inmo.tgbotapi.extensions.behaviour_builder.utils.times]
* to combinate several filters
* @param [markerFactory] Will be used to identify different "stream". [scenarioReceiver] will be called synchronously
* in one "stream". Output of [markerFactory] will be used as a key for "stream"
* @param scenarioReceiver Main callback which will be used to handle incoming data if [initialFilter] will pass that
* data
*/
suspend fun <BC : BehaviourContext> BC.onInlineMessageIdDataCallbackQuery(
dataRegex: Regex,
initialFilter: SimpleFilter<InlineMessageIdDataCallbackQuery>? = null,
subcontextUpdatesFilter: CustomBehaviourContextAndTwoTypesReceiver<BC, Boolean, InlineMessageIdDataCallbackQuery, Update>? = CallbackQueryFilterByUser,
markerFactory: MarkerFactory<in InlineMessageIdDataCallbackQuery, Any> = ByUserCallbackQueryMarkerFactory,
scenarioReceiver: CustomBehaviourContextAndTypeReceiver<BC, Unit, InlineMessageIdDataCallbackQuery>
) = onInlineMessageIdDataCallbackQuery(
initialFilter = initialFilter + {
it.data.matches(dataRegex)
},
subcontextUpdatesFilter,
markerFactory,
scenarioReceiver
)
/**
* @param data Will be converted to [Regex] via its constructor and pass it to upstream [onInlineMessageIdDataCallbackQuery]
* @param initialFilter This filter will be called to remove unnecessary data BEFORE [scenarioReceiver] call
* @param subcontextUpdatesFilter This filter will be applied to each update inside of [scenarioReceiver]. For example,
* this filter will be used if you will call [dev.inmo.tgbotapi.extensions.behaviour_builder.expectations.waitContentMessage].
* Use [dev.inmo.tgbotapi.extensions.behaviour_builder.BehaviourContextAndTwoTypesReceiver] function to create your own.
* Use [dev.inmo.tgbotapi.extensions.behaviour_builder.utils.plus] or [dev.inmo.tgbotapi.extensions.behaviour_builder.utils.times]
* to combinate several filters
* @param [markerFactory] Will be used to identify different "stream". [scenarioReceiver] will be called synchronously
* in one "stream". Output of [markerFactory] will be used as a key for "stream"
* @param scenarioReceiver Main callback which will be used to handle incoming data if [initialFilter] will pass that
* data
*/
suspend fun <BC : BehaviourContext> BC.onInlineMessageIdDataCallbackQuery(
data: String,
initialFilter: SimpleFilter<InlineMessageIdDataCallbackQuery>? = null,
subcontextUpdatesFilter: CustomBehaviourContextAndTwoTypesReceiver<BC, Boolean, InlineMessageIdDataCallbackQuery, Update>? = CallbackQueryFilterByUser,
markerFactory: MarkerFactory<in InlineMessageIdDataCallbackQuery, Any> = ByUserCallbackQueryMarkerFactory,
scenarioReceiver: CustomBehaviourContextAndTypeReceiver<BC, Unit, InlineMessageIdDataCallbackQuery>
) = onInlineMessageIdDataCallbackQuery(
Regex(data),
initialFilter,
subcontextUpdatesFilter,
markerFactory,
scenarioReceiver
)
/** /**
* @param initialFilter This filter will be called to remove unnecessary data BEFORE [scenarioReceiver] call * @param initialFilter This filter will be called to remove unnecessary data BEFORE [scenarioReceiver] call
* @param subcontextUpdatesFilter This filter will be applied to each update inside of [scenarioReceiver]. For example, * @param subcontextUpdatesFilter This filter will be applied to each update inside of [scenarioReceiver]. For example,
@@ -188,6 +301,62 @@ suspend fun <BC : BehaviourContext> BC.onMessageDataCallbackQuery(
scenarioReceiver scenarioReceiver
) )
/**
* @param dataRegex Will be used with [initialFilter] as [initialFilter] for upstream [onMessageDataCallbackQuery] to filter
* [MessageDataCallbackQuery] with [MessageDataCallbackQuery.data] [String.matches] to [dataRegex]
* @param initialFilter This filter will be called to remove unnecessary data BEFORE [scenarioReceiver] call
* @param subcontextUpdatesFilter This filter will be applied to each update inside of [scenarioReceiver]. For example,
* this filter will be used if you will call [dev.inmo.tgbotapi.extensions.behaviour_builder.expectations.waitContentMessage].
* Use [dev.inmo.tgbotapi.extensions.behaviour_builder.BehaviourContextAndTwoTypesReceiver] function to create your own.
* Use [dev.inmo.tgbotapi.extensions.behaviour_builder.utils.plus] or [dev.inmo.tgbotapi.extensions.behaviour_builder.utils.times]
* to combinate several filters
* @param [markerFactory] Will be used to identify different "stream". [scenarioReceiver] will be called synchronously
* in one "stream". Output of [markerFactory] will be used as a key for "stream"
* @param scenarioReceiver Main callback which will be used to handle incoming data if [initialFilter] will pass that
* data
*/
suspend fun <BC : BehaviourContext> BC.onMessageDataCallbackQuery(
dataRegex: Regex,
initialFilter: SimpleFilter<MessageDataCallbackQuery>? = null,
subcontextUpdatesFilter: CustomBehaviourContextAndTwoTypesReceiver<BC, Boolean, MessageDataCallbackQuery, Update>? = CallbackQueryFilterByUser,
markerFactory: MarkerFactory<in MessageDataCallbackQuery, Any> = ByUserCallbackQueryMarkerFactory,
scenarioReceiver: CustomBehaviourContextAndTypeReceiver<BC, Unit, MessageDataCallbackQuery>
) = onMessageDataCallbackQuery(
initialFilter = initialFilter + {
it.data.matches(dataRegex)
},
subcontextUpdatesFilter,
markerFactory,
scenarioReceiver
)
/**
* @param data Will be converted to [Regex] via its constructor and pass it to upstream [onMessageDataCallbackQuery]
* @param initialFilter This filter will be called to remove unnecessary data BEFORE [scenarioReceiver] call
* @param subcontextUpdatesFilter This filter will be applied to each update inside of [scenarioReceiver]. For example,
* this filter will be used if you will call [dev.inmo.tgbotapi.extensions.behaviour_builder.expectations.waitContentMessage].
* Use [dev.inmo.tgbotapi.extensions.behaviour_builder.BehaviourContextAndTwoTypesReceiver] function to create your own.
* Use [dev.inmo.tgbotapi.extensions.behaviour_builder.utils.plus] or [dev.inmo.tgbotapi.extensions.behaviour_builder.utils.times]
* to combinate several filters
* @param [markerFactory] Will be used to identify different "stream". [scenarioReceiver] will be called synchronously
* in one "stream". Output of [markerFactory] will be used as a key for "stream"
* @param scenarioReceiver Main callback which will be used to handle incoming data if [initialFilter] will pass that
* data
*/
suspend fun <BC : BehaviourContext> BC.onMessageDataCallbackQuery(
data: String,
initialFilter: SimpleFilter<MessageDataCallbackQuery>? = null,
subcontextUpdatesFilter: CustomBehaviourContextAndTwoTypesReceiver<BC, Boolean, MessageDataCallbackQuery, Update>? = CallbackQueryFilterByUser,
markerFactory: MarkerFactory<in MessageDataCallbackQuery, Any> = ByUserCallbackQueryMarkerFactory,
scenarioReceiver: CustomBehaviourContextAndTypeReceiver<BC, Unit, MessageDataCallbackQuery>
) = onMessageDataCallbackQuery(
Regex(data),
initialFilter,
subcontextUpdatesFilter,
markerFactory,
scenarioReceiver
)
/** /**
* @param initialFilter This filter will be called to remove unnecessary data BEFORE [scenarioReceiver] call * @param initialFilter This filter will be called to remove unnecessary data BEFORE [scenarioReceiver] call
* @param subcontextUpdatesFilter This filter will be applied to each update inside of [scenarioReceiver]. For example, * @param subcontextUpdatesFilter This filter will be applied to each update inside of [scenarioReceiver]. For example,

View File

@@ -14,7 +14,7 @@ import dev.inmo.tgbotapi.types.update.abstracts.ChatMemberUpdatedUpdate
import dev.inmo.tgbotapi.types.update.abstracts.Update import dev.inmo.tgbotapi.types.update.abstracts.Update
internal suspend inline fun <BC : BehaviourContext, reified U : ChatMemberUpdatedUpdate> BC.onChatMemberUpdatedInternal( internal suspend inline fun <BC : BehaviourContext, reified U : ChatMemberUpdatedUpdate> BC.onChatMemberUpdatedInternal(
initialFilter: SimpleFilter<ChatMemberUpdated>? = null, noinline initialFilter: SimpleFilter<ChatMemberUpdated>? = null,
noinline subcontextUpdatesFilter: CustomBehaviourContextAndTwoTypesReceiver<BC, Boolean, ChatMemberUpdated, Update>? = ChatMemberUpdatedFilterByChat, noinline subcontextUpdatesFilter: CustomBehaviourContextAndTwoTypesReceiver<BC, Boolean, ChatMemberUpdated, Update>? = ChatMemberUpdatedFilterByChat,
markerFactory: MarkerFactory<ChatMemberUpdated, Any> = ByChatChatMemberUpdatedMarkerFactory, markerFactory: MarkerFactory<ChatMemberUpdated, Any> = ByChatChatMemberUpdatedMarkerFactory,
noinline scenarioReceiver: CustomBehaviourContextAndTypeReceiver<BC, Unit, ChatMemberUpdated> noinline scenarioReceiver: CustomBehaviourContextAndTypeReceiver<BC, Unit, ChatMemberUpdated>

View File

@@ -12,7 +12,7 @@ import dev.inmo.tgbotapi.types.polls.*
import dev.inmo.tgbotapi.types.update.abstracts.Update import dev.inmo.tgbotapi.types.update.abstracts.Update
internal suspend inline fun <BC : BehaviourContext, reified T : ChosenInlineResult> BC.onChosenInlineResultBase( internal suspend inline fun <BC : BehaviourContext, reified T : ChosenInlineResult> BC.onChosenInlineResultBase(
initialFilter: SimpleFilter<T>? = null, noinline initialFilter: SimpleFilter<T>? = null,
noinline subcontextUpdatesFilter: CustomBehaviourContextAndTwoTypesReceiver<BC, Boolean, T, Update>? = null, noinline subcontextUpdatesFilter: CustomBehaviourContextAndTwoTypesReceiver<BC, Boolean, T, Update>? = null,
markerFactory: MarkerFactory<in T, Any> = ByUserIdChosenInlineResultMarkerFactory, markerFactory: MarkerFactory<in T, Any> = ByUserIdChosenInlineResultMarkerFactory,
noinline scenarioReceiver: CustomBehaviourContextAndTypeReceiver<BC, Unit, T> noinline scenarioReceiver: CustomBehaviourContextAndTypeReceiver<BC, Unit, T>

View File

@@ -55,7 +55,7 @@ suspend fun <BC : BehaviourContext> BC.command(
suspend inline fun <BC : BehaviourContext> BC.onCommand( suspend inline fun <BC : BehaviourContext> BC.onCommand(
commandRegex: Regex, commandRegex: Regex,
requireOnlyCommandInMessage: Boolean = true, requireOnlyCommandInMessage: Boolean = true,
initialFilter: CommonMessageFilter<TextContent>? = CommonMessageFilterExcludeMediaGroups, noinline initialFilter: CommonMessageFilter<TextContent>? = CommonMessageFilterExcludeMediaGroups,
noinline subcontextUpdatesFilter: CustomBehaviourContextAndTwoTypesReceiver<BC, Boolean, CommonMessage<TextContent>, Update> = MessageFilterByChat, noinline subcontextUpdatesFilter: CustomBehaviourContextAndTwoTypesReceiver<BC, Boolean, CommonMessage<TextContent>, Update> = MessageFilterByChat,
markerFactory: MarkerFactory<in CommonMessage<TextContent>, Any> = ByChatMessageMarkerFactory, markerFactory: MarkerFactory<in CommonMessage<TextContent>, Any> = ByChatMessageMarkerFactory,
noinline scenarioReceiver: CustomBehaviourContextAndTypeReceiver<BC, Unit, CommonMessage<TextContent>> noinline scenarioReceiver: CustomBehaviourContextAndTypeReceiver<BC, Unit, CommonMessage<TextContent>>
@@ -64,7 +64,7 @@ suspend inline fun <BC : BehaviourContext> BC.onCommand(
suspend inline fun <BC : BehaviourContext> BC.onCommand( suspend inline fun <BC : BehaviourContext> BC.onCommand(
command: String, command: String,
requireOnlyCommandInMessage: Boolean = true, requireOnlyCommandInMessage: Boolean = true,
initialFilter: CommonMessageFilter<TextContent>? = CommonMessageFilterExcludeMediaGroups, noinline initialFilter: CommonMessageFilter<TextContent>? = CommonMessageFilterExcludeMediaGroups,
noinline subcontextUpdatesFilter: CustomBehaviourContextAndTwoTypesReceiver<BC, Boolean, CommonMessage<TextContent>, Update> = MessageFilterByChat, noinline subcontextUpdatesFilter: CustomBehaviourContextAndTwoTypesReceiver<BC, Boolean, CommonMessage<TextContent>, Update> = MessageFilterByChat,
markerFactory: MarkerFactory<in CommonMessage<TextContent>, Any> = ByChatMessageMarkerFactory, markerFactory: MarkerFactory<in CommonMessage<TextContent>, Any> = ByChatMessageMarkerFactory,
noinline scenarioReceiver: CustomBehaviourContextAndTypeReceiver<BC, Unit, CommonMessage<TextContent>> noinline scenarioReceiver: CustomBehaviourContextAndTypeReceiver<BC, Unit, CommonMessage<TextContent>>
@@ -106,7 +106,7 @@ suspend fun <BC : BehaviourContext> BC.commandWithArgs(
suspend inline fun <BC : BehaviourContext> BC.onCommandWithArgs( suspend inline fun <BC : BehaviourContext> BC.onCommandWithArgs(
commandRegex: Regex, commandRegex: Regex,
initialFilter: CommonMessageFilter<TextContent>? = CommonMessageFilterExcludeMediaGroups, noinline initialFilter: CommonMessageFilter<TextContent>? = CommonMessageFilterExcludeMediaGroups,
noinline subcontextUpdatesFilter: CustomBehaviourContextAndTwoTypesReceiver<BC, Boolean, CommonMessage<TextContent>, Update> = MessageFilterByChat, noinline subcontextUpdatesFilter: CustomBehaviourContextAndTwoTypesReceiver<BC, Boolean, CommonMessage<TextContent>, Update> = MessageFilterByChat,
markerFactory: MarkerFactory<in CommonMessage<TextContent>, Any> = ByChatMessageMarkerFactory, markerFactory: MarkerFactory<in CommonMessage<TextContent>, Any> = ByChatMessageMarkerFactory,
noinline scenarioReceiver: CustomBehaviourContextAndTwoTypesReceiver<BC, Unit, CommonMessage<TextContent>, Array<String>> noinline scenarioReceiver: CustomBehaviourContextAndTwoTypesReceiver<BC, Unit, CommonMessage<TextContent>, Array<String>>
@@ -114,7 +114,7 @@ suspend inline fun <BC : BehaviourContext> BC.onCommandWithArgs(
suspend inline fun <BC : BehaviourContext> BC.onCommandWithArgs( suspend inline fun <BC : BehaviourContext> BC.onCommandWithArgs(
command: String, command: String,
initialFilter: CommonMessageFilter<TextContent>? = CommonMessageFilterExcludeMediaGroups, noinline initialFilter: CommonMessageFilter<TextContent>? = CommonMessageFilterExcludeMediaGroups,
noinline subcontextUpdatesFilter: CustomBehaviourContextAndTwoTypesReceiver<BC, Boolean, CommonMessage<TextContent>, Update> = MessageFilterByChat, noinline subcontextUpdatesFilter: CustomBehaviourContextAndTwoTypesReceiver<BC, Boolean, CommonMessage<TextContent>, Update> = MessageFilterByChat,
markerFactory: MarkerFactory<in CommonMessage<TextContent>, Any> = ByChatMessageMarkerFactory, markerFactory: MarkerFactory<in CommonMessage<TextContent>, Any> = ByChatMessageMarkerFactory,
noinline scenarioReceiver: CustomBehaviourContextAndTwoTypesReceiver<BC, Unit, CommonMessage<TextContent>, Array<String>> noinline scenarioReceiver: CustomBehaviourContextAndTwoTypesReceiver<BC, Unit, CommonMessage<TextContent>, Array<String>>

View File

@@ -9,7 +9,7 @@ import dev.inmo.tgbotapi.extensions.behaviour_builder.utils.SimpleFilter
import dev.inmo.tgbotapi.extensions.behaviour_builder.utils.marker_factories.ByChatMessageMarkerFactory import dev.inmo.tgbotapi.extensions.behaviour_builder.utils.marker_factories.ByChatMessageMarkerFactory
import dev.inmo.tgbotapi.extensions.behaviour_builder.utils.marker_factories.MarkerFactory import dev.inmo.tgbotapi.extensions.behaviour_builder.utils.marker_factories.MarkerFactory
import dev.inmo.tgbotapi.extensions.utils.whenCommonMessage import dev.inmo.tgbotapi.extensions.utils.whenCommonMessage
import dev.inmo.tgbotapi.types.files.TelegramMediaFile import dev.inmo.tgbotapi.types.files.abstracts.TelegramMediaFile
import dev.inmo.tgbotapi.types.message.abstracts.CommonMessage import dev.inmo.tgbotapi.types.message.abstracts.CommonMessage
import dev.inmo.tgbotapi.types.message.content.* import dev.inmo.tgbotapi.types.message.content.*
import dev.inmo.tgbotapi.types.message.content.abstracts.* import dev.inmo.tgbotapi.types.message.content.abstracts.*
@@ -22,9 +22,10 @@ import dev.inmo.tgbotapi.types.update.abstracts.BaseSentMessageUpdate
import dev.inmo.tgbotapi.types.update.abstracts.Update import dev.inmo.tgbotapi.types.update.abstracts.Update
typealias CommonMessageFilter<T> = SimpleFilter<CommonMessage<T>> typealias CommonMessageFilter<T> = SimpleFilter<CommonMessage<T>>
inline fun <T : MessageContent> CommonMessageFilter(noinline block: CommonMessageFilter<T>) = block
internal suspend inline fun <BC : BehaviourContext, reified T : MessageContent> BC.onContentMessageWithType( internal suspend inline fun <BC : BehaviourContext, reified T : MessageContent> BC.onContentMessageWithType(
initialFilter: CommonMessageFilter<T>? = null, noinline initialFilter: CommonMessageFilter<T>? = null,
noinline subcontextUpdatesFilter: CustomBehaviourContextAndTwoTypesReceiver<BC, Boolean, CommonMessage<T>, Update>? = MessageFilterByChat, noinline subcontextUpdatesFilter: CustomBehaviourContextAndTwoTypesReceiver<BC, Boolean, CommonMessage<T>, Update>? = MessageFilterByChat,
markerFactory: MarkerFactory<in CommonMessage<T>, Any> = ByChatMessageMarkerFactory, markerFactory: MarkerFactory<in CommonMessage<T>, Any> = ByChatMessageMarkerFactory,
noinline scenarioReceiver: CustomBehaviourContextAndTypeReceiver<BC, Unit, CommonMessage<T>> noinline scenarioReceiver: CustomBehaviourContextAndTypeReceiver<BC, Unit, CommonMessage<T>>

View File

@@ -22,7 +22,7 @@ import dev.inmo.tgbotapi.extensions.behaviour_builder.utils.marker_factories.ByC
import dev.inmo.tgbotapi.extensions.behaviour_builder.utils.marker_factories.MarkerFactory import dev.inmo.tgbotapi.extensions.behaviour_builder.utils.marker_factories.MarkerFactory
import dev.inmo.tgbotapi.extensions.utils.asEditMessageUpdate import dev.inmo.tgbotapi.extensions.utils.asEditMessageUpdate
import dev.inmo.tgbotapi.extensions.utils.withContent import dev.inmo.tgbotapi.extensions.utils.withContent
import dev.inmo.tgbotapi.types.files.TelegramMediaFile import dev.inmo.tgbotapi.types.files.abstracts.TelegramMediaFile
import dev.inmo.tgbotapi.types.message.abstracts.CommonMessage import dev.inmo.tgbotapi.types.message.abstracts.CommonMessage
import dev.inmo.tgbotapi.types.message.content.* import dev.inmo.tgbotapi.types.message.content.*
import dev.inmo.tgbotapi.types.message.content.abstracts.* import dev.inmo.tgbotapi.types.message.content.abstracts.*
@@ -36,7 +36,7 @@ import dev.inmo.tgbotapi.utils.PreviewFeature
@PreviewFeature @PreviewFeature
internal suspend inline fun <BC : BehaviourContext, reified T : MessageContent> BC.onEditedContent( internal suspend inline fun <BC : BehaviourContext, reified T : MessageContent> BC.onEditedContent(
initialFilter: CommonMessageFilter<T>? = null, noinline initialFilter: CommonMessageFilter<T>? = null,
noinline subcontextUpdatesFilter: CustomBehaviourContextAndTwoTypesReceiver<BC, Boolean, CommonMessage<T>, Update>? = MessageFilterByChat, noinline subcontextUpdatesFilter: CustomBehaviourContextAndTwoTypesReceiver<BC, Boolean, CommonMessage<T>, Update>? = MessageFilterByChat,
markerFactory: MarkerFactory<in CommonMessage<T>, Any> = ByChatMessageMarkerFactory, markerFactory: MarkerFactory<in CommonMessage<T>, Any> = ByChatMessageMarkerFactory,
noinline scenarioReceiver: CustomBehaviourContextAndTypeReceiver<BC, Unit, CommonMessage<T>> noinline scenarioReceiver: CustomBehaviourContextAndTypeReceiver<BC, Unit, CommonMessage<T>>

View File

@@ -18,7 +18,7 @@ import dev.inmo.tgbotapi.types.message.payments.SuccessfulPaymentEvent
import dev.inmo.tgbotapi.types.update.abstracts.Update import dev.inmo.tgbotapi.types.update.abstracts.Update
internal suspend inline fun <BC : BehaviourContext, reified T : ChatEvent> BC.onEvent( internal suspend inline fun <BC : BehaviourContext, reified T : ChatEvent> BC.onEvent(
initialFilter: SimpleFilter<ChatEventMessage<T>>? = null, noinline initialFilter: SimpleFilter<ChatEventMessage<T>>? = null,
noinline subcontextUpdatesFilter: CustomBehaviourContextAndTwoTypesReceiver<BC, Boolean, ChatEventMessage<T>, Update>? = MessageFilterByChat, noinline subcontextUpdatesFilter: CustomBehaviourContextAndTwoTypesReceiver<BC, Boolean, ChatEventMessage<T>, Update>? = MessageFilterByChat,
markerFactory: MarkerFactory<in ChatEventMessage<T>, Any> = ByChatMessageMarkerFactory, markerFactory: MarkerFactory<in ChatEventMessage<T>, Any> = ByChatMessageMarkerFactory,
noinline scenarioReceiver: CustomBehaviourContextAndTypeReceiver<BC, Unit, ChatEventMessage<T>> noinline scenarioReceiver: CustomBehaviourContextAndTypeReceiver<BC, Unit, ChatEventMessage<T>>

View File

@@ -10,7 +10,7 @@ import dev.inmo.tgbotapi.types.InlineQueries.query.*
import dev.inmo.tgbotapi.types.update.abstracts.Update import dev.inmo.tgbotapi.types.update.abstracts.Update
internal suspend inline fun <BC : BehaviourContext, reified T : InlineQuery> BC.onInlineQuery( internal suspend inline fun <BC : BehaviourContext, reified T : InlineQuery> BC.onInlineQuery(
initialFilter: SimpleFilter<T>? = null, noinline initialFilter: SimpleFilter<T>? = null,
noinline subcontextUpdatesFilter: CustomBehaviourContextAndTwoTypesReceiver<BC, Boolean, T, Update>? = InlineQueryFilterByUser, noinline subcontextUpdatesFilter: CustomBehaviourContextAndTwoTypesReceiver<BC, Boolean, T, Update>? = InlineQueryFilterByUser,
markerFactory: MarkerFactory<in T, Any> = ByUserInlineQueryMarkerFactory, markerFactory: MarkerFactory<in T, Any> = ByUserInlineQueryMarkerFactory,
noinline scenarioReceiver: CustomBehaviourContextAndTypeReceiver<BC, Unit, T> noinline scenarioReceiver: CustomBehaviourContextAndTypeReceiver<BC, Unit, T>

View File

@@ -9,7 +9,7 @@ import dev.inmo.tgbotapi.types.update.abstracts.Update
internal suspend inline fun <BC : BehaviourContext, reified T> BC.on( internal suspend inline fun <BC : BehaviourContext, reified T> BC.on(
markerFactory: MarkerFactory<in T, Any>, markerFactory: MarkerFactory<in T, Any>,
initialFilter: SimpleFilter<T>? = null, noinline initialFilter: SimpleFilter<T>? = null,
noinline subcontextUpdatesFilter: CustomBehaviourContextAndTwoTypesReceiver<BC, Boolean, T, Update>? = null, noinline subcontextUpdatesFilter: CustomBehaviourContextAndTwoTypesReceiver<BC, Boolean, T, Update>? = null,
noinline scenarioReceiver: CustomBehaviourContextAndTypeReceiver<BC, Unit, T>, noinline scenarioReceiver: CustomBehaviourContextAndTypeReceiver<BC, Unit, T>,
noinline updateToData: (Update) -> List<T>? noinline updateToData: (Update) -> List<T>?

View File

@@ -19,7 +19,7 @@ import dev.inmo.tgbotapi.utils.PreviewFeature
@PreviewFeature @PreviewFeature
internal suspend inline fun <BC : BehaviourContext, reified T : MediaGroupContent> BC.buildMediaGroupTrigger( internal suspend inline fun <BC : BehaviourContext, reified T : MediaGroupContent> BC.buildMediaGroupTrigger(
initialFilter: SimpleFilter<List<MediaGroupMessage<T>>>? = null, noinline initialFilter: SimpleFilter<List<MediaGroupMessage<T>>>? = null,
noinline subcontextUpdatesFilter: CustomBehaviourContextAndTwoTypesReceiver<BC, Boolean, List<MediaGroupMessage<T>>, Update>? = MessagesFilterByChat, noinline subcontextUpdatesFilter: CustomBehaviourContextAndTwoTypesReceiver<BC, Boolean, List<MediaGroupMessage<T>>, Update>? = MessagesFilterByChat,
markerFactory: MarkerFactory<in List<MediaGroupMessage<T>>, Any> = ByChatMediaGroupMarkerFactory, markerFactory: MarkerFactory<in List<MediaGroupMessage<T>>, Any> = ByChatMediaGroupMarkerFactory,
noinline scenarioReceiver: CustomBehaviourContextAndTypeReceiver<BC, Unit, List<MediaGroupMessage<T>>> noinline scenarioReceiver: CustomBehaviourContextAndTypeReceiver<BC, Unit, List<MediaGroupMessage<T>>>

View File

@@ -12,7 +12,7 @@ import dev.inmo.tgbotapi.types.passport.encrypted.abstracts.EncryptedPassportEle
import dev.inmo.tgbotapi.types.update.abstracts.Update import dev.inmo.tgbotapi.types.update.abstracts.Update
internal suspend inline fun <BC : BehaviourContext, reified T : EncryptedPassportElement> BC.onPassportMessageWith( internal suspend inline fun <BC : BehaviourContext, reified T : EncryptedPassportElement> BC.onPassportMessageWith(
initialFilter: SimpleFilter<PassportMessage>? = null, noinline initialFilter: SimpleFilter<PassportMessage>? = null,
noinline subcontextUpdatesFilter: CustomBehaviourContextAndTwoTypesReceiver<BC, Boolean, PassportMessage, Update>? = MessageFilterByChat, noinline subcontextUpdatesFilter: CustomBehaviourContextAndTwoTypesReceiver<BC, Boolean, PassportMessage, Update>? = MessageFilterByChat,
markerFactory: MarkerFactory<in PassportMessage, Any> = ByChatMessageMarkerFactory, markerFactory: MarkerFactory<in PassportMessage, Any> = ByChatMessageMarkerFactory,
noinline scenarioReceiver: CustomBehaviourContextAndTypeReceiver<BC, Unit, PassportMessage> noinline scenarioReceiver: CustomBehaviourContextAndTypeReceiver<BC, Unit, PassportMessage>

View File

@@ -11,7 +11,7 @@ import dev.inmo.tgbotapi.types.polls.*
import dev.inmo.tgbotapi.types.update.abstracts.Update import dev.inmo.tgbotapi.types.update.abstracts.Update
internal suspend inline fun <BC : BehaviourContext> BC.onPollAnswered( internal suspend inline fun <BC : BehaviourContext> BC.onPollAnswered(
initialFilter: SimpleFilter<PollAnswer>? = null, noinline initialFilter: SimpleFilter<PollAnswer>? = null,
noinline subcontextUpdatesFilter: CustomBehaviourContextAndTwoTypesReceiver<BC, Boolean, PollAnswer, Update>? = null, noinline subcontextUpdatesFilter: CustomBehaviourContextAndTwoTypesReceiver<BC, Boolean, PollAnswer, Update>? = null,
markerFactory: MarkerFactory<in PollAnswer, Any> = ByIdPollAnswerMarkerFactory, markerFactory: MarkerFactory<in PollAnswer, Any> = ByIdPollAnswerMarkerFactory,
noinline scenarioReceiver: CustomBehaviourContextAndTypeReceiver<BC, Unit, PollAnswer> noinline scenarioReceiver: CustomBehaviourContextAndTypeReceiver<BC, Unit, PollAnswer>

View File

@@ -10,7 +10,7 @@ import dev.inmo.tgbotapi.types.polls.*
import dev.inmo.tgbotapi.types.update.abstracts.Update import dev.inmo.tgbotapi.types.update.abstracts.Update
internal suspend inline fun <BC : BehaviourContext, reified T : Poll> BC.onPollUpdatedBase( internal suspend inline fun <BC : BehaviourContext, reified T : Poll> BC.onPollUpdatedBase(
initialFilter: SimpleFilter<T>? = null, noinline initialFilter: SimpleFilter<T>? = null,
noinline subcontextUpdatesFilter: CustomBehaviourContextAndTwoTypesReceiver<BC, Boolean, T, Update>? = null, noinline subcontextUpdatesFilter: CustomBehaviourContextAndTwoTypesReceiver<BC, Boolean, T, Update>? = null,
markerFactory: MarkerFactory<in T, Any> = ByIdPollMarkerFactory, markerFactory: MarkerFactory<in T, Any> = ByIdPollMarkerFactory,
noinline scenarioReceiver: CustomBehaviourContextAndTypeReceiver<BC, Unit, T> noinline scenarioReceiver: CustomBehaviourContextAndTypeReceiver<BC, Unit, T>

View File

@@ -1,8 +1,8 @@
package dev.inmo.tgbotapi.extensions.behaviour_builder.utils package dev.inmo.tgbotapi.extensions.behaviour_builder.utils
fun interface SimpleFilter<in T> { typealias SimpleFilter<T> = suspend (T) -> Boolean
suspend operator fun invoke(o: T): Boolean
} inline fun <T> SimpleFilter(noinline block: SimpleFilter<T>) = block
/** /**
* @return [SimpleFilter] which will return true in case when all the items in incoming data passed [this] filter * @return [SimpleFilter] which will return true in case when all the items in incoming data passed [this] filter
@@ -28,20 +28,24 @@ fun <T> SimpleFilter<T>.listNone() = SimpleFilter<Iterable<T>> {
/** /**
* Makes an AND (&&) operation between [this] and [other] * Makes an AND (&&) operation between [this] and [other]
*/ */
operator fun <T> SimpleFilter<T>.times(other: SimpleFilter<T>) = SimpleFilter<T> { operator fun <T> SimpleFilter<T>?.times(other: SimpleFilter<T>): SimpleFilter<T> = this ?.let {
this(it) && other(it) {
} this(it) && other(it)
}
} ?: other
/** /**
* Makes an OR (||) operation between [this] and [other] * Makes an OR (||) operation between [this] and [other]
*/ */
operator fun <T> SimpleFilter<T>.plus(other: SimpleFilter<T>) = SimpleFilter<T> { operator fun <T> SimpleFilter<T>?.plus(other: SimpleFilter<T>): SimpleFilter<T> = this ?.let {
this(it) || other(it) {
} this(it) || other(it)
}
} ?: other
/** /**
* Reverse results of [this] * Reverse results of [this]
*/ */
operator fun <T> SimpleFilter<T>.not() = SimpleFilter<T> { operator fun <T> SimpleFilter<T>.not(): SimpleFilter<T> = {
!this(it) !this(it)
} }

View File

@@ -64,7 +64,7 @@ kotlin {
dependencies { dependencies {
implementation kotlin('test-common') implementation kotlin('test-common')
implementation kotlin('test-annotations-common') implementation kotlin('test-annotations-common')
implementation project(":tgbotapi.utils") implementation project(":tgbotapi.extensions.utils")
} }
} }

View File

@@ -16,33 +16,6 @@ import io.ktor.client.features.*
import io.ktor.client.statement.readText import io.ktor.client.statement.readText
import kotlinx.serialization.json.Json import kotlinx.serialization.json.Json
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,
crossinline builder: KtorRequestsExecutorBuilder.() -> Unit = {}
): TelegramBot = KtorRequestsExecutorBuilder(telegramAPIUrlsKeeper).apply(builder).build()
/**
* Shortcut for [telegramBot]
*/
@Suppress("NOTHING_TO_INLINE")
inline fun telegramBot(
token: String,
apiUrl: String = telegramBotAPIDefaultUrl,
crossinline builder: KtorRequestsExecutorBuilder.() -> Unit = {}
): TelegramBot = telegramBot(TelegramAPIUrlsKeeper(token, apiUrl), builder)
@RiskFeature @RiskFeature
fun createTelegramBotDefaultKtorCallRequestsFactories() = listOf( fun createTelegramBotDefaultKtorCallRequestsFactories() = listOf(
SimpleRequestCallFactory(), SimpleRequestCallFactory(),
@@ -127,3 +100,31 @@ class KtorRequestsExecutor(
client.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)

View File

@@ -2,8 +2,8 @@ package dev.inmo.tgbotapi.requests.get
import dev.inmo.tgbotapi.requests.abstracts.FileId import dev.inmo.tgbotapi.requests.abstracts.FileId
import dev.inmo.tgbotapi.requests.abstracts.SimpleRequest import dev.inmo.tgbotapi.requests.abstracts.SimpleRequest
import dev.inmo.tgbotapi.types.fileIdField
import dev.inmo.tgbotapi.types.files.PathedFile import dev.inmo.tgbotapi.types.files.PathedFile
import dev.inmo.tgbotapi.types.files.abstracts.fileIdField
import kotlinx.serialization.* import kotlinx.serialization.*
@Serializable @Serializable

View File

@@ -192,13 +192,6 @@ const val requestContactField = "request_contact"
const val requestLocationField = "request_location" const val requestLocationField = "request_location"
const val requestPollField = "request_poll" const val requestPollField = "request_poll"
const val fileNameField = "file_name"
const val mimeTypeField = "mime_type"
const val fileIdField = "file_id"
const val fileSizeField = "file_size"
const val fileDateField = "file_date"
const val filePathField = "file_path"
const val requestWriteAccessField = "request_write_access" const val requestWriteAccessField = "request_write_access"

View File

@@ -9,6 +9,7 @@ import dev.inmo.tgbotapi.types.MessageEntity.textsources.TextSourcesList
import dev.inmo.tgbotapi.types.ParseMode.ParseMode import dev.inmo.tgbotapi.types.ParseMode.ParseMode
import dev.inmo.tgbotapi.types.ParseMode.parseModeField import dev.inmo.tgbotapi.types.ParseMode.parseModeField
import dev.inmo.tgbotapi.types.buttons.InlineKeyboardMarkup import dev.inmo.tgbotapi.types.buttons.InlineKeyboardMarkup
import dev.inmo.tgbotapi.types.files.abstracts.mimeTypeField
import dev.inmo.tgbotapi.utils.MimeType import dev.inmo.tgbotapi.utils.MimeType
import dev.inmo.tgbotapi.utils.extensions.makeString import dev.inmo.tgbotapi.utils.extensions.makeString
import kotlinx.serialization.SerialName import kotlinx.serialization.SerialName

View File

@@ -9,6 +9,7 @@ import dev.inmo.tgbotapi.types.MessageEntity.textsources.TextSource
import dev.inmo.tgbotapi.types.ParseMode.ParseMode import dev.inmo.tgbotapi.types.ParseMode.ParseMode
import dev.inmo.tgbotapi.types.ParseMode.parseModeField import dev.inmo.tgbotapi.types.ParseMode.parseModeField
import dev.inmo.tgbotapi.types.buttons.InlineKeyboardMarkup import dev.inmo.tgbotapi.types.buttons.InlineKeyboardMarkup
import dev.inmo.tgbotapi.types.files.abstracts.mimeTypeField
import dev.inmo.tgbotapi.utils.MimeType import dev.inmo.tgbotapi.utils.MimeType
import dev.inmo.tgbotapi.utils.extensions.makeString import dev.inmo.tgbotapi.utils.extensions.makeString
import kotlinx.serialization.SerialName import kotlinx.serialization.SerialName

View File

@@ -22,11 +22,14 @@ private class SurrogateBotCommandScope(
BotCommandScopeAllGroupChats.type -> BotCommandScopeAllGroupChats BotCommandScopeAllGroupChats.type -> BotCommandScopeAllGroupChats
BotCommandScopeAllChatAdministrators.type -> BotCommandScopeAllChatAdministrators BotCommandScopeAllChatAdministrators.type -> BotCommandScopeAllChatAdministrators
BotCommandScopeChatAdministrators.type -> BotCommandScopeChatAdministrators( BotCommandScopeChatAdministrators.type -> BotCommandScopeChatAdministrators(
chatId ?: error("chat_administrators type must have $chatIdField field, but have no") chatId ?: error("${BotCommandScopeChatAdministrators.type} type must have $chatIdField field, but have no")
) )
BotCommandScopeChatMember.type -> BotCommandScopeChatMember( BotCommandScopeChatMember.type -> BotCommandScopeChatMember(
chatId ?: error("chat_administrators type must have $chatIdField field, but have no"), chatId ?: error("${BotCommandScopeChatMember.type} type must have $chatIdField field, but have no"),
userId ?: error("chat_administrators type must have $userIdField field, but have no") userId ?: error("${BotCommandScopeChatMember.type} type must have $userIdField field, but have no")
)
BotCommandScopeChat.type -> BotCommandScopeChat(
chatId ?: error("${BotCommandScopeChat.type} type must have $chatIdField field, but have no")
) )
else -> UnknownBotCommandScope(type) else -> UnknownBotCommandScope(type)
} }
@@ -40,6 +43,7 @@ private class SurrogateBotCommandScope(
BotCommandScopeAllChatAdministrators -> SurrogateBotCommandScope(scope.type) BotCommandScopeAllChatAdministrators -> SurrogateBotCommandScope(scope.type)
is BotCommandScopeChatAdministrators -> SurrogateBotCommandScope(scope.type, scope.chatId) is BotCommandScopeChatAdministrators -> SurrogateBotCommandScope(scope.type, scope.chatId)
is BotCommandScopeChatMember -> SurrogateBotCommandScope(scope.type, scope.chatId, scope.userId) is BotCommandScopeChatMember -> SurrogateBotCommandScope(scope.type, scope.chatId, scope.userId)
is BotCommandScopeChat -> SurrogateBotCommandScope(scope.type, scope.chatId)
} }
} }
} }
@@ -47,6 +51,16 @@ private class SurrogateBotCommandScope(
@Serializable(BotCommandScopeSerializer::class) @Serializable(BotCommandScopeSerializer::class)
sealed interface BotCommandScope { sealed interface BotCommandScope {
val type: String val type: String
companion object {
val Default = BotCommandScopeDefault
val AllPrivateChats = BotCommandScopeAllPrivateChats
val AllGroupChats = BotCommandScopeAllGroupChats
val AllChatAdministrators = BotCommandScopeAllChatAdministrators
fun ChatAdministrators(chatId: ChatIdentifier) = BotCommandScopeChatAdministrators(chatId)
fun Chat(chatId: ChatIdentifier) = BotCommandScopeChat(chatId)
fun ChatMember(chatId: ChatIdentifier, userId: UserId) = BotCommandScopeChatMember(chatId, userId)
}
} }
@Serializable @Serializable
@@ -94,6 +108,17 @@ data class BotCommandScopeChatAdministrators(
} }
} }
@Serializable
data class BotCommandScopeChat(
override val chatId: ChatIdentifier
) : ChatBotCommandScope {
@Required
override val type: String = BotCommandScopeChat.type
companion object {
const val type = "chat"
}
}
@Serializable @Serializable
data class BotCommandScopeChatMember( data class BotCommandScopeChatMember(
override val chatId: ChatIdentifier, override val chatId: ChatIdentifier,

View File

@@ -1,8 +1,9 @@
package dev.inmo.tgbotapi.types.files package dev.inmo.tgbotapi.types.files
import dev.inmo.tgbotapi.requests.abstracts.FileId import dev.inmo.tgbotapi.requests.abstracts.FileId
import dev.inmo.tgbotapi.types.* import dev.inmo.tgbotapi.types.FileUniqueId
import dev.inmo.tgbotapi.types.files.* import dev.inmo.tgbotapi.types.fileUniqueIdField
import dev.inmo.tgbotapi.types.files.abstracts.*
import dev.inmo.tgbotapi.utils.MimeType import dev.inmo.tgbotapi.utils.MimeType
import kotlinx.serialization.SerialName import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable import kotlinx.serialization.Serializable

View File

@@ -3,6 +3,7 @@ package dev.inmo.tgbotapi.types.files
import dev.inmo.tgbotapi.CommonAbstracts.Performerable import dev.inmo.tgbotapi.CommonAbstracts.Performerable
import dev.inmo.tgbotapi.requests.abstracts.FileId import dev.inmo.tgbotapi.requests.abstracts.FileId
import dev.inmo.tgbotapi.types.* import dev.inmo.tgbotapi.types.*
import dev.inmo.tgbotapi.types.files.abstracts.*
import dev.inmo.tgbotapi.utils.MimeType import dev.inmo.tgbotapi.utils.MimeType
import kotlinx.serialization.SerialName import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable import kotlinx.serialization.Serializable

View File

@@ -1,5 +0,0 @@
package dev.inmo.tgbotapi.types.files
sealed interface CustomNamedMediaFile {
val fileName: String?
}

View File

@@ -1,8 +1,10 @@
package dev.inmo.tgbotapi.types.files package dev.inmo.tgbotapi.types.files
import dev.inmo.tgbotapi.requests.abstracts.FileId import dev.inmo.tgbotapi.requests.abstracts.FileId
import dev.inmo.tgbotapi.types.* import dev.inmo.tgbotapi.types.FileUniqueId
import dev.inmo.tgbotapi.types.files.* import dev.inmo.tgbotapi.types.fileUniqueIdField
import dev.inmo.tgbotapi.types.files.abstracts.*
import dev.inmo.tgbotapi.types.message.content.media.DocumentContent
import dev.inmo.tgbotapi.utils.MimeType import dev.inmo.tgbotapi.utils.MimeType
import kotlinx.serialization.SerialName import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable import kotlinx.serialization.Serializable

View File

@@ -1,8 +1,9 @@
package dev.inmo.tgbotapi.types.files package dev.inmo.tgbotapi.types.files
import dev.inmo.tgbotapi.requests.abstracts.FileId import dev.inmo.tgbotapi.requests.abstracts.FileId
import dev.inmo.tgbotapi.types.* import dev.inmo.tgbotapi.types.FileUniqueId
import dev.inmo.tgbotapi.types.files.* import dev.inmo.tgbotapi.types.fileUniqueIdField
import dev.inmo.tgbotapi.types.files.abstracts.*
import kotlinx.serialization.SerialName import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable import kotlinx.serialization.Serializable

View File

@@ -1,6 +0,0 @@
package dev.inmo.tgbotapi.types.files
import dev.inmo.tgbotapi.CommonAbstracts.MimeTyped
import dev.inmo.tgbotapi.types.files.TelegramMediaFile
sealed interface MimedMediaFile : TelegramMediaFile, MimeTyped

View File

@@ -1,22 +0,0 @@
package dev.inmo.tgbotapi.types.files
import dev.inmo.tgbotapi.requests.abstracts.FileId
import dev.inmo.tgbotapi.types.*
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
/**
* This object represents a file uploaded to Telegram Passport. Currently all Telegram Passport files are in JPEG format
* when decrypted and don't exceed 10MB.
*/
@Serializable
data class PassportFile(
@SerialName(fileIdField)
override val fileId: FileId,
@SerialName(fileUniqueIdField)
override val fileUniqueId: FileUniqueId,
@SerialName(fileDateField)
val uploadingDate: TelegramDate,
@SerialName(fileSizeField)
override val fileSize: Long? = null
) : TelegramMediaFile

View File

@@ -1,7 +1,9 @@
package dev.inmo.tgbotapi.types.files package dev.inmo.tgbotapi.types.files
import dev.inmo.tgbotapi.requests.abstracts.FileId import dev.inmo.tgbotapi.requests.abstracts.FileId
import dev.inmo.tgbotapi.types.* import dev.inmo.tgbotapi.types.FileUniqueId
import dev.inmo.tgbotapi.types.fileUniqueIdField
import dev.inmo.tgbotapi.types.files.abstracts.*
import dev.inmo.tgbotapi.utils.* import dev.inmo.tgbotapi.utils.*
import kotlinx.serialization.* import kotlinx.serialization.*

View File

@@ -1,8 +1,9 @@
package dev.inmo.tgbotapi.types.files package dev.inmo.tgbotapi.types.files
import dev.inmo.tgbotapi.requests.abstracts.FileId import dev.inmo.tgbotapi.requests.abstracts.FileId
import dev.inmo.tgbotapi.types.* import dev.inmo.tgbotapi.types.FileUniqueId
import dev.inmo.tgbotapi.types.files.* import dev.inmo.tgbotapi.types.fileUniqueIdField
import dev.inmo.tgbotapi.types.files.abstracts.*
import dev.inmo.tgbotapi.utils.RiskFeature import dev.inmo.tgbotapi.utils.RiskFeature
import kotlinx.serialization.* import kotlinx.serialization.*
import kotlinx.serialization.builtins.ListSerializer import kotlinx.serialization.builtins.ListSerializer

View File

@@ -1,7 +0,0 @@
package dev.inmo.tgbotapi.types.files
import dev.inmo.tgbotapi.types.files.TelegramMediaFile
sealed interface PlayableMediaFile : TelegramMediaFile {
val duration: Long?
}

View File

@@ -1,8 +0,0 @@
package dev.inmo.tgbotapi.types.files
import dev.inmo.tgbotapi.types.files.TelegramMediaFile
sealed interface SizedMediaFile : TelegramMediaFile {
val width: Int
val height: Int
}

View File

@@ -1,156 +1,6 @@
package dev.inmo.tgbotapi.types.files package dev.inmo.tgbotapi.types.files
import dev.inmo.tgbotapi.requests.abstracts.FileId import dev.inmo.tgbotapi.types.files.sticker.Sticker
import dev.inmo.tgbotapi.types.*
import dev.inmo.tgbotapi.types.stickers.MaskPosition
import dev.inmo.tgbotapi.utils.RiskFeature
import kotlinx.serialization.*
import kotlinx.serialization.descriptors.SerialDescriptor
import kotlinx.serialization.encoding.Decoder
import kotlinx.serialization.encoding.Encoder
@Serializable @Deprecated("Replaced", ReplaceWith("Sticker", "dev.inmo.tgbotapi.types.files.sticker.Sticker"))
@RiskFeature("This class is used for serialization/deserialization of Sticker interface") typealias Sticker = Sticker
data class StickerSurrogate(
val file_id: FileId,
val file_unique_id: FileUniqueId,
val width: Int,
val height: Int,
val is_animated: Boolean? = null,
val is_video: Boolean? = null,
val thumb: PhotoSize? = null,
val emoji: String? = null,
val set_name: StickerSetName? = null,
val mask_position: MaskPosition? = null,
val file_size: Long? = null
)
// TODO:: Serializer
@Serializable(StickerSerializer::class)
sealed interface Sticker : TelegramMediaFile, SizedMediaFile, ThumbedMediaFile {
val emoji: String?
val maskPosition: MaskPosition?
val stickerSetName: StickerSetName?
val isAnimated
get() = this is AnimatedSticker
val isVideo
get() = this is VideoSticker
companion object {
fun serializer(): KSerializer<Sticker> = StickerSerializer
}
}
object StickerSerializer : KSerializer<Sticker> {
override val descriptor: SerialDescriptor = StickerSurrogate.serializer().descriptor
override fun deserialize(decoder: Decoder): Sticker {
val surrogate = StickerSurrogate.serializer().deserialize(decoder)
return when {
surrogate.is_animated == true -> AnimatedSticker(
surrogate.file_id,
surrogate.file_unique_id,
surrogate.width,
surrogate.height,
surrogate.thumb,
surrogate.emoji,
surrogate.set_name,
surrogate.mask_position,
surrogate.file_size
)
surrogate.is_video == true -> VideoSticker(
surrogate.file_id,
surrogate.file_unique_id,
surrogate.width,
surrogate.height,
surrogate.thumb,
surrogate.emoji,
surrogate.set_name,
surrogate.mask_position,
surrogate.file_size
)
else -> SimpleSticker(
surrogate.file_id,
surrogate.file_unique_id,
surrogate.width,
surrogate.height,
surrogate.thumb,
surrogate.emoji,
surrogate.set_name,
surrogate.mask_position,
surrogate.file_size
)
}
}
override fun serialize(encoder: Encoder, value: Sticker) {
TODO("Not yet implemented")
}
}
@Serializable
data class SimpleSticker(
@SerialName(fileIdField)
override val fileId: FileId,
@SerialName(fileUniqueIdField)
override val fileUniqueId: FileUniqueId,
@SerialName(widthField)
override val width: Int,
@SerialName(heightField)
override val height: Int,
@SerialName(thumbField)
override val thumb: PhotoSize? = null,
@SerialName(emojiField)
override val emoji: String? = null,
@SerialName(stickerSetNameField)
override val stickerSetName: StickerSetName? = null,
@SerialName(maskPositionField)
override val maskPosition: MaskPosition? = null,
@SerialName(fileSizeField)
override val fileSize: Long? = null,
) : Sticker
@Serializable
data class AnimatedSticker(
@SerialName(fileIdField)
override val fileId: FileId,
@SerialName(fileUniqueIdField)
override val fileUniqueId: FileUniqueId,
@SerialName(widthField)
override val width: Int,
@SerialName(heightField)
override val height: Int,
@SerialName(thumbField)
override val thumb: PhotoSize? = null,
@SerialName(emojiField)
override val emoji: String? = null,
@SerialName(stickerSetNameField)
override val stickerSetName: StickerSetName? = null,
@SerialName(maskPositionField)
override val maskPosition: MaskPosition? = null,
@SerialName(fileSizeField)
override val fileSize: Long? = null,
) : Sticker
@Serializable
data class VideoSticker(
@SerialName(fileIdField)
override val fileId: FileId,
@SerialName(fileUniqueIdField)
override val fileUniqueId: FileUniqueId,
@SerialName(widthField)
override val width: Int,
@SerialName(heightField)
override val height: Int,
@SerialName(thumbField)
override val thumb: PhotoSize? = null,
@SerialName(emojiField)
override val emoji: String? = null,
@SerialName(stickerSetNameField)
override val stickerSetName: StickerSetName? = null,
@SerialName(maskPositionField)
override val maskPosition: MaskPosition? = null,
@SerialName(fileSizeField)
override val fileSize: Long? = null,
) : Sticker

View File

@@ -1,8 +0,0 @@
package dev.inmo.tgbotapi.types.files
import dev.inmo.tgbotapi.types.files.PhotoSize
import dev.inmo.tgbotapi.types.files.TelegramMediaFile
sealed interface ThumbedMediaFile : TelegramMediaFile {
val thumb: PhotoSize?
}

View File

@@ -1,5 +0,0 @@
package dev.inmo.tgbotapi.types.files
sealed interface TitledMediaFile {
val title: String?
}

View File

@@ -5,6 +5,7 @@ import dev.inmo.tgbotapi.types.*
import dev.inmo.tgbotapi.types.InputMedia.InputMediaVideo import dev.inmo.tgbotapi.types.InputMedia.InputMediaVideo
import dev.inmo.tgbotapi.types.MessageEntity.textsources.TextSourcesList import dev.inmo.tgbotapi.types.MessageEntity.textsources.TextSourcesList
import dev.inmo.tgbotapi.types.ParseMode.ParseMode import dev.inmo.tgbotapi.types.ParseMode.ParseMode
import dev.inmo.tgbotapi.types.files.abstracts.*
import dev.inmo.tgbotapi.utils.MimeType import dev.inmo.tgbotapi.utils.MimeType
import kotlinx.serialization.SerialName import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable import kotlinx.serialization.Serializable

View File

@@ -1,8 +1,9 @@
package dev.inmo.tgbotapi.types.files package dev.inmo.tgbotapi.types.files
import dev.inmo.tgbotapi.requests.abstracts.FileId import dev.inmo.tgbotapi.requests.abstracts.FileId
import dev.inmo.tgbotapi.types.* import dev.inmo.tgbotapi.types.FileUniqueId
import dev.inmo.tgbotapi.types.files.* import dev.inmo.tgbotapi.types.fileUniqueIdField
import dev.inmo.tgbotapi.types.files.abstracts.*
import kotlinx.serialization.SerialName import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable import kotlinx.serialization.Serializable

View File

@@ -2,7 +2,7 @@ package dev.inmo.tgbotapi.types.files
import dev.inmo.tgbotapi.requests.abstracts.FileId import dev.inmo.tgbotapi.requests.abstracts.FileId
import dev.inmo.tgbotapi.types.* import dev.inmo.tgbotapi.types.*
import dev.inmo.tgbotapi.types.files.* import dev.inmo.tgbotapi.types.files.abstracts.*
import dev.inmo.tgbotapi.utils.MimeType import dev.inmo.tgbotapi.utils.MimeType
import kotlinx.serialization.SerialName import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable import kotlinx.serialization.Serializable

View File

@@ -0,0 +1,7 @@
package dev.inmo.tgbotapi.types.files.abstracts
internal const val fileNameField = "file_name"
interface CustomNamedMediaFile {
val fileName: String?
}

View File

@@ -0,0 +1,7 @@
package dev.inmo.tgbotapi.types.files.abstracts
import dev.inmo.tgbotapi.CommonAbstracts.MimeTyped
internal const val mimeTypeField = "mime_type"
interface MimedMediaFile : TelegramMediaFile, MimeTyped

View File

@@ -1,22 +0,0 @@
package dev.inmo.tgbotapi.types.files.abstracts
@Deprecated("Renamed", ReplaceWith("CustomNamedMediaFile", "dev.inmo.tgbotapi.types.files.CustomNamedMediaFile"))
typealias CustomNamedMediaFile = dev.inmo.tgbotapi.types.files.CustomNamedMediaFile
@Deprecated("Replaced", ReplaceWith("MimedMediaFile", "dev.inmo.tgbotapi.types.files.MimedMediaFile"))
typealias MimedMediaFile = dev.inmo.tgbotapi.types.files.MimedMediaFile
@Deprecated("Replaced", ReplaceWith("PlayableMediaFile", "dev.inmo.tgbotapi.types.files.PlayableMediaFile"))
typealias PlayableMediaFile = dev.inmo.tgbotapi.types.files.PlayableMediaFile
@Deprecated("Replaced", ReplaceWith("SizedMediaFile", "dev.inmo.tgbotapi.types.files.SizedMediaFile"))
typealias SizedMediaFile = dev.inmo.tgbotapi.types.files.SizedMediaFile
@Deprecated("Replaced", ReplaceWith("TelegramMediaFile", "dev.inmo.tgbotapi.types.files.TelegramMediaFile"))
typealias TelegramMediaFile = dev.inmo.tgbotapi.types.files.TelegramMediaFile
@Deprecated("Replaced", ReplaceWith("ThumbedMediaFile", "dev.inmo.tgbotapi.types.files.ThumbedMediaFile"))
typealias ThumbedMediaFile = dev.inmo.tgbotapi.types.files.ThumbedMediaFile
@Deprecated("Replaced", ReplaceWith("TitledMediaFile", "dev.inmo.tgbotapi.types.files.TitledMediaFile"))
typealias TitledMediaFile = dev.inmo.tgbotapi.types.files.TitledMediaFile

View File

@@ -0,0 +1,5 @@
package dev.inmo.tgbotapi.types.files.abstracts
interface PlayableMediaFile : TelegramMediaFile {
val duration: Long?
}

View File

@@ -0,0 +1,6 @@
package dev.inmo.tgbotapi.types.files.abstracts
interface SizedMediaFile : TelegramMediaFile {
val width: Int
val height: Int
}

View File

@@ -1,12 +1,17 @@
package dev.inmo.tgbotapi.types.files package dev.inmo.tgbotapi.types.files.abstracts
import dev.inmo.tgbotapi.requests.abstracts.FileId import dev.inmo.tgbotapi.requests.abstracts.FileId
import dev.inmo.tgbotapi.types.FileUniqueId import dev.inmo.tgbotapi.types.FileUniqueId
internal const val fileIdField = "file_id"
internal const val fileSizeField = "file_size"
internal const val fileDateField = "file_date"
internal const val filePathField = "file_path"
/** /**
* Declare common part of media files in Telegram. Note: it is not representation of JVM `File` type * Declare common part of media files in Telegram. Note: it is not representation of JVM `File` type
*/ */
sealed interface TelegramMediaFile { interface TelegramMediaFile {
val fileId: FileId val fileId: FileId
val fileUniqueId: FileUniqueId val fileUniqueId: FileUniqueId
val fileSize: Long? val fileSize: Long?

View File

@@ -0,0 +1,7 @@
package dev.inmo.tgbotapi.types.files.abstracts
import dev.inmo.tgbotapi.types.files.PhotoSize
interface ThumbedMediaFile : TelegramMediaFile {
val thumb: PhotoSize?
}

View File

@@ -0,0 +1,5 @@
package dev.inmo.tgbotapi.types.files.abstracts
interface TitledMediaFile {
val title: String?
}

View File

@@ -1,19 +1,158 @@
package dev.inmo.tgbotapi.types.files.sticker package dev.inmo.tgbotapi.types.files.sticker
@Deprecated("Replaced", ReplaceWith("StickerSurrogate", "dev.inmo.tgbotapi.types.files.StickerSurrogate")) import dev.inmo.tgbotapi.requests.abstracts.FileId
typealias StickerSurrogate = dev.inmo.tgbotapi.types.files.StickerSurrogate import dev.inmo.tgbotapi.types.*
import dev.inmo.tgbotapi.types.files.PhotoSize
import dev.inmo.tgbotapi.types.files.abstracts.*
import dev.inmo.tgbotapi.types.stickers.MaskPosition
import dev.inmo.tgbotapi.utils.RiskFeature
import kotlinx.serialization.*
import kotlinx.serialization.descriptors.SerialDescriptor
import kotlinx.serialization.encoding.Decoder
import kotlinx.serialization.encoding.Encoder
@Deprecated("Replaced", ReplaceWith("Sticker", "dev.inmo.tgbotapi.types.files.Sticker")) @Serializable
typealias Sticker = dev.inmo.tgbotapi.types.files.Sticker @RiskFeature("This class is used for serialization/deserialization of Sticker interface")
data class StickerSurrogate(
val file_id: FileId,
val file_unique_id: FileUniqueId,
val width: Int,
val height: Int,
val is_animated: Boolean? = null,
val is_video: Boolean? = null,
val thumb: PhotoSize? = null,
val emoji: String? = null,
val set_name: StickerSetName? = null,
val mask_position: MaskPosition? = null,
val file_size: Long? = null
)
@Deprecated("Replaced", ReplaceWith("StickerSerializer", "dev.inmo.tgbotapi.types.files.StickerSerializer")) // TODO:: Serializer
typealias StickerSerializer = dev.inmo.tgbotapi.types.files.StickerSerializer @Serializable(StickerSerializer::class)
sealed interface Sticker : TelegramMediaFile, SizedMediaFile, ThumbedMediaFile {
val emoji: String?
val maskPosition: MaskPosition?
val stickerSetName: StickerSetName?
@Deprecated("Replaced", ReplaceWith("SimpleSticker", "dev.inmo.tgbotapi.types.files.SimpleSticker")) val isAnimated
typealias SimpleSticker = dev.inmo.tgbotapi.types.files.SimpleSticker get() = this is AnimatedSticker
val isVideo
get() = this is VideoSticker
@Deprecated("Replaced", ReplaceWith("AnimatedSticker", "dev.inmo.tgbotapi.types.files.AnimatedSticker")) companion object {
typealias AnimatedSticker = dev.inmo.tgbotapi.types.files.AnimatedSticker fun serializer(): KSerializer<Sticker> = StickerSerializer
}
}
@Deprecated("Replaced", ReplaceWith("VideoSticker", "dev.inmo.tgbotapi.types.files.VideoSticker")) object StickerSerializer : KSerializer<Sticker> {
typealias VideoSticker = dev.inmo.tgbotapi.types.files.VideoSticker override val descriptor: SerialDescriptor = StickerSurrogate.serializer().descriptor
override fun deserialize(decoder: Decoder): Sticker {
val surrogate = StickerSurrogate.serializer().deserialize(decoder)
return when {
surrogate.is_animated == true -> AnimatedSticker(
surrogate.file_id,
surrogate.file_unique_id,
surrogate.width,
surrogate.height,
surrogate.thumb,
surrogate.emoji,
surrogate.set_name,
surrogate.mask_position,
surrogate.file_size
)
surrogate.is_video == true -> VideoSticker(
surrogate.file_id,
surrogate.file_unique_id,
surrogate.width,
surrogate.height,
surrogate.thumb,
surrogate.emoji,
surrogate.set_name,
surrogate.mask_position,
surrogate.file_size
)
else -> SimpleSticker(
surrogate.file_id,
surrogate.file_unique_id,
surrogate.width,
surrogate.height,
surrogate.thumb,
surrogate.emoji,
surrogate.set_name,
surrogate.mask_position,
surrogate.file_size
)
}
}
override fun serialize(encoder: Encoder, value: Sticker) {
TODO("Not yet implemented")
}
}
@Serializable
data class SimpleSticker(
@SerialName(fileIdField)
override val fileId: FileId,
@SerialName(fileUniqueIdField)
override val fileUniqueId: FileUniqueId,
@SerialName(widthField)
override val width: Int,
@SerialName(heightField)
override val height: Int,
@SerialName(thumbField)
override val thumb: PhotoSize? = null,
@SerialName(emojiField)
override val emoji: String? = null,
@SerialName(stickerSetNameField)
override val stickerSetName: StickerSetName? = null,
@SerialName(maskPositionField)
override val maskPosition: MaskPosition? = null,
@SerialName(fileSizeField)
override val fileSize: Long? = null,
) : Sticker
@Serializable
data class AnimatedSticker(
@SerialName(fileIdField)
override val fileId: FileId,
@SerialName(fileUniqueIdField)
override val fileUniqueId: FileUniqueId,
@SerialName(widthField)
override val width: Int,
@SerialName(heightField)
override val height: Int,
@SerialName(thumbField)
override val thumb: PhotoSize? = null,
@SerialName(emojiField)
override val emoji: String? = null,
@SerialName(stickerSetNameField)
override val stickerSetName: StickerSetName? = null,
@SerialName(maskPositionField)
override val maskPosition: MaskPosition? = null,
@SerialName(fileSizeField)
override val fileSize: Long? = null,
) : Sticker
@Serializable
data class VideoSticker(
@SerialName(fileIdField)
override val fileId: FileId,
@SerialName(fileUniqueIdField)
override val fileUniqueId: FileUniqueId,
@SerialName(widthField)
override val width: Int,
@SerialName(heightField)
override val height: Int,
@SerialName(thumbField)
override val thumb: PhotoSize? = null,
@SerialName(emojiField)
override val emoji: String? = null,
@SerialName(stickerSetNameField)
override val stickerSetName: StickerSetName? = null,
@SerialName(maskPositionField)
override val maskPosition: MaskPosition? = null,
@SerialName(fileSizeField)
override val fileSize: Long? = null,
) : Sticker

View File

@@ -7,7 +7,7 @@ import dev.inmo.tgbotapi.types.buttons.InlineKeyboardMarkup
import dev.inmo.tgbotapi.types.chat.abstracts.* import dev.inmo.tgbotapi.types.chat.abstracts.*
import dev.inmo.tgbotapi.types.dice.Dice import dev.inmo.tgbotapi.types.dice.Dice
import dev.inmo.tgbotapi.types.files.* import dev.inmo.tgbotapi.types.files.*
import dev.inmo.tgbotapi.types.files.Sticker import dev.inmo.tgbotapi.types.files.sticker.Sticker
import dev.inmo.tgbotapi.types.games.RawGame import dev.inmo.tgbotapi.types.games.RawGame
import dev.inmo.tgbotapi.types.location.Location import dev.inmo.tgbotapi.types.location.Location
import dev.inmo.tgbotapi.types.message.ChatEvents.* import dev.inmo.tgbotapi.types.message.ChatEvents.*

View File

@@ -1,6 +1,6 @@
package dev.inmo.tgbotapi.types.message.content.abstracts package dev.inmo.tgbotapi.types.message.content.abstracts
import dev.inmo.tgbotapi.types.files.TelegramMediaFile import dev.inmo.tgbotapi.types.files.abstracts.TelegramMediaFile
interface MediaCollectionContent<T: TelegramMediaFile>: MessageContent, MediaContent { interface MediaCollectionContent<T: TelegramMediaFile>: MessageContent, MediaContent {
val mediaCollection: List<T> val mediaCollection: List<T>

View File

@@ -1,7 +1,7 @@
package dev.inmo.tgbotapi.types.message.content.abstracts package dev.inmo.tgbotapi.types.message.content.abstracts
import dev.inmo.tgbotapi.types.InputMedia.InputMedia import dev.inmo.tgbotapi.types.InputMedia.InputMedia
import dev.inmo.tgbotapi.types.files.TelegramMediaFile import dev.inmo.tgbotapi.types.files.abstracts.TelegramMediaFile
interface MediaContent: MessageContent { interface MediaContent: MessageContent {
val media: TelegramMediaFile val media: TelegramMediaFile

View File

@@ -20,8 +20,7 @@ interface MessageContent: ResendableContent {
subclass(DiceContent::class) subclass(DiceContent::class)
subclass(TextContent::class) subclass(TextContent::class)
subclass(LiveLocationContent::class) subclass(LocationContent::class, LocationContentSerializer)
subclass(StaticLocationContent::class)
subclass(PhotoContent::class) subclass(PhotoContent::class)
subclass(VideoContent::class) subclass(VideoContent::class)

View File

@@ -6,7 +6,7 @@ import dev.inmo.tgbotapi.types.ChatIdentifier
import dev.inmo.tgbotapi.types.InputMedia.InputMediaDocument import dev.inmo.tgbotapi.types.InputMedia.InputMediaDocument
import dev.inmo.tgbotapi.types.MessageIdentifier import dev.inmo.tgbotapi.types.MessageIdentifier
import dev.inmo.tgbotapi.types.buttons.KeyboardMarkup import dev.inmo.tgbotapi.types.buttons.KeyboardMarkup
import dev.inmo.tgbotapi.types.files.Sticker import dev.inmo.tgbotapi.types.files.sticker.Sticker
import dev.inmo.tgbotapi.types.message.abstracts.ContentMessage import dev.inmo.tgbotapi.types.message.abstracts.ContentMessage
import dev.inmo.tgbotapi.types.message.content.abstracts.MediaContent import dev.inmo.tgbotapi.types.message.content.abstracts.MediaContent
import kotlinx.serialization.Serializable import kotlinx.serialization.Serializable

View File

@@ -2,7 +2,6 @@ package dev.inmo.tgbotapi.types.passport.encrypted
import dev.inmo.micro_utils.serialization.base64.Base64BytesToFromStringSerializer import dev.inmo.micro_utils.serialization.base64.Base64BytesToFromStringSerializer
import dev.inmo.tgbotapi.types.* import dev.inmo.tgbotapi.types.*
import dev.inmo.tgbotapi.types.files.PassportFile
import dev.inmo.tgbotapi.types.passport.encrypted.abstracts.* import dev.inmo.tgbotapi.types.passport.encrypted.abstracts.*
import kotlinx.serialization.SerialName import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable import kotlinx.serialization.Serializable

View File

@@ -2,7 +2,6 @@ package dev.inmo.tgbotapi.types.passport.encrypted
import dev.inmo.micro_utils.serialization.base64.Base64BytesToFromStringSerializer import dev.inmo.micro_utils.serialization.base64.Base64BytesToFromStringSerializer
import dev.inmo.tgbotapi.types.* import dev.inmo.tgbotapi.types.*
import dev.inmo.tgbotapi.types.files.PassportFile
import dev.inmo.tgbotapi.types.passport.credentials.EncryptedData import dev.inmo.tgbotapi.types.passport.credentials.EncryptedData
import dev.inmo.tgbotapi.types.passport.encrypted.abstracts.* import dev.inmo.tgbotapi.types.passport.encrypted.abstracts.*
import kotlinx.serialization.SerialName import kotlinx.serialization.SerialName

View File

@@ -2,7 +2,6 @@ package dev.inmo.tgbotapi.types.passport.encrypted
import dev.inmo.micro_utils.serialization.base64.Base64BytesToFromStringSerializer import dev.inmo.micro_utils.serialization.base64.Base64BytesToFromStringSerializer
import dev.inmo.tgbotapi.types.* import dev.inmo.tgbotapi.types.*
import dev.inmo.tgbotapi.types.files.PassportFile
import dev.inmo.tgbotapi.types.passport.credentials.EncryptedData import dev.inmo.tgbotapi.types.passport.credentials.EncryptedData
import dev.inmo.tgbotapi.types.passport.encrypted.abstracts.* import dev.inmo.tgbotapi.types.passport.encrypted.abstracts.*
import kotlinx.serialization.SerialName import kotlinx.serialization.SerialName

View File

@@ -1,4 +1,23 @@
package dev.inmo.tgbotapi.types.passport.encrypted package dev.inmo.tgbotapi.types.passport.encrypted
@Deprecated("Replaced", ReplaceWith("PassportFile", "dev.inmo.tgbotapi.types.files.PassportFile")) import dev.inmo.tgbotapi.requests.abstracts.FileId
typealias PassportFile = dev.inmo.tgbotapi.types.files.PassportFile import dev.inmo.tgbotapi.types.*
import dev.inmo.tgbotapi.types.files.abstracts.*
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
/**
* This object represents a file uploaded to Telegram Passport. Currently all Telegram Passport files are in JPEG format
* when decrypted and don't exceed 10MB.
*/
@Serializable
data class PassportFile(
@SerialName(fileIdField)
override val fileId: FileId,
@SerialName(fileUniqueIdField)
override val fileUniqueId: FileUniqueId,
@SerialName(fileDateField)
val uploadingDate: TelegramDate,
@SerialName(fileSizeField)
override val fileSize: Long? = null
) : TelegramMediaFile

View File

@@ -1,10 +1,10 @@
package dev.inmo.tgbotapi.types.passport.encrypted.abstracts package dev.inmo.tgbotapi.types.passport.encrypted.abstracts
import dev.inmo.tgbotapi.types.passport.encrypted.EncryptedElementSerializer import dev.inmo.tgbotapi.types.passport.encrypted.EncryptedElementSerializer
import dev.inmo.tgbotapi.types.files.PassportFile import dev.inmo.tgbotapi.types.passport.encrypted.PassportFile
import kotlinx.serialization.Serializable import kotlinx.serialization.Serializable
@Serializable(EncryptedElementSerializer::class) @Serializable(EncryptedElementSerializer::class)
interface EncryptedPassportElementTranslatable : EncryptedPassportElement { interface EncryptedPassportElementTranslatable : EncryptedPassportElement {
val translations: List<PassportFile> val translations: List<PassportFile>
} }

View File

@@ -1,10 +1,10 @@
package dev.inmo.tgbotapi.types.passport.encrypted.abstracts package dev.inmo.tgbotapi.types.passport.encrypted.abstracts
import dev.inmo.tgbotapi.types.passport.encrypted.EncryptedElementSerializer import dev.inmo.tgbotapi.types.passport.encrypted.EncryptedElementSerializer
import dev.inmo.tgbotapi.types.files.PassportFile import dev.inmo.tgbotapi.types.passport.encrypted.PassportFile
import kotlinx.serialization.Serializable import kotlinx.serialization.Serializable
@Serializable(EncryptedElementSerializer::class) @Serializable(EncryptedElementSerializer::class)
interface EncryptedPassportElementWithFilesCollection : EncryptedPassportElement { interface EncryptedPassportElementWithFilesCollection : EncryptedPassportElement {
val files: List<PassportFile> val files: List<PassportFile>
} }

View File

@@ -1,10 +1,10 @@
package dev.inmo.tgbotapi.types.passport.encrypted.abstracts package dev.inmo.tgbotapi.types.passport.encrypted.abstracts
import dev.inmo.tgbotapi.types.passport.encrypted.EncryptedElementSerializer import dev.inmo.tgbotapi.types.passport.encrypted.EncryptedElementSerializer
import dev.inmo.tgbotapi.types.files.PassportFile import dev.inmo.tgbotapi.types.passport.encrypted.PassportFile
import kotlinx.serialization.Serializable import kotlinx.serialization.Serializable
@Serializable(EncryptedElementSerializer::class) @Serializable(EncryptedElementSerializer::class)
interface EncryptedPassportElementWithFrontSide : EncryptedPassportElement { interface EncryptedPassportElementWithFrontSide : EncryptedPassportElement {
val frontSide: PassportFile? val frontSide: PassportFile?
} }

View File

@@ -1,10 +1,10 @@
package dev.inmo.tgbotapi.types.passport.encrypted.abstracts package dev.inmo.tgbotapi.types.passport.encrypted.abstracts
import dev.inmo.tgbotapi.types.passport.encrypted.EncryptedElementSerializer import dev.inmo.tgbotapi.types.passport.encrypted.EncryptedElementSerializer
import dev.inmo.tgbotapi.types.files.PassportFile import dev.inmo.tgbotapi.types.passport.encrypted.PassportFile
import kotlinx.serialization.Serializable import kotlinx.serialization.Serializable
@Serializable(EncryptedElementSerializer::class) @Serializable(EncryptedElementSerializer::class)
interface EncryptedPassportElementWithReverseSide : EncryptedPassportElement { interface EncryptedPassportElementWithReverseSide : EncryptedPassportElement {
val reverseSide: PassportFile? val reverseSide: PassportFile?
} }

View File

@@ -1,10 +1,10 @@
package dev.inmo.tgbotapi.types.passport.encrypted.abstracts package dev.inmo.tgbotapi.types.passport.encrypted.abstracts
import dev.inmo.tgbotapi.types.passport.encrypted.EncryptedElementSerializer import dev.inmo.tgbotapi.types.passport.encrypted.EncryptedElementSerializer
import dev.inmo.tgbotapi.types.files.PassportFile import dev.inmo.tgbotapi.types.passport.encrypted.PassportFile
import kotlinx.serialization.Serializable import kotlinx.serialization.Serializable
@Serializable(EncryptedElementSerializer::class) @Serializable(EncryptedElementSerializer::class)
interface EncryptedPassportElementWithSelfie : EncryptedPassportElement { interface EncryptedPassportElementWithSelfie : EncryptedPassportElement {
val selfie: PassportFile? val selfie: PassportFile?
} }

View File

@@ -2,7 +2,7 @@ package dev.inmo.tgbotapi.types.stickers
import dev.inmo.tgbotapi.types.* import dev.inmo.tgbotapi.types.*
import dev.inmo.tgbotapi.types.files.PhotoSize import dev.inmo.tgbotapi.types.files.PhotoSize
import dev.inmo.tgbotapi.types.files.Sticker import dev.inmo.tgbotapi.types.files.sticker.Sticker
import kotlinx.serialization.SerialName import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable import kotlinx.serialization.Serializable

View File

@@ -0,0 +1,19 @@
package dev.inmo.tgbotapi.utils
import dev.inmo.micro_utils.crypto.SourceBytes
import dev.inmo.micro_utils.crypto.SourceString
internal expect fun SourceString.hmacSha256(key: String): String
private val HEX_ARRAY = "0123456789abcdef".toCharArray()
internal fun SourceBytes.hex(): String {
val hexChars = CharArray(size * 2)
for (j in indices) {
val v: Int = this[j].toInt() and 0xFF
hexChars[j * 2] = HEX_ARRAY[v ushr 4]
hexChars[j * 2 + 1] = HEX_ARRAY[v and 0x0F]
}
return hexChars.concatToString()
}
internal fun SourceString.hex(): String = encodeToByteArray().hex()

View File

@@ -16,16 +16,33 @@ private inline val String.withoutLastSlash: String
class TelegramAPIUrlsKeeper( class TelegramAPIUrlsKeeper(
token: String, token: String,
hostUrl: String = telegramBotAPIDefaultUrl hostUrl: String = telegramBotAPIDefaultUrl,
urlsSuffixes: String = ""
) { ) {
val webAppDataSecretKey by lazy {
token.hmacSha256("WebAppData")
}
val commonAPIUrl: String val commonAPIUrl: String
val fileBaseUrl: String val fileBaseUrl: String
constructor(token: String, testServer: Boolean, hostUrl: String = telegramBotAPIDefaultUrl) : this(
token,
hostUrl,
"/test".takeIf { testServer } ?: ""
)
init { init {
val correctedHost = hostUrl.withoutLastSlash val correctedHost = hostUrl.withoutLastSlash
commonAPIUrl = "$correctedHost/bot$token" commonAPIUrl = "$correctedHost/bot$token$urlsSuffixes"
fileBaseUrl = "$correctedHost/file/bot$token" fileBaseUrl = "$correctedHost/file/bot$token$urlsSuffixes"
} }
fun createFileLinkUrl(filePath: String) = "${fileBaseUrl}/$filePath" fun createFileLinkUrl(filePath: String) = "${fileBaseUrl}/$filePath"
/**
* @param rawData Data from [dev.inmo.tgbotapi.webapps.WebApp.initData]
* @param hash Data from [dev.inmo.tgbotapi.webapps.WebApp.initDataUnsafe] from the field [dev.inmo.tgbotapi.webapps.WebAppInitData.hash]
*/
fun checkWebAppLink(rawData: String, hash: String) = rawData.hmacSha256(webAppDataSecretKey).hex() == hash
} }

View File

@@ -0,0 +1,6 @@
package dev.inmo.tgbotapi.utils
import dev.inmo.micro_utils.crypto.CryptoJS
import dev.inmo.micro_utils.crypto.SourceString
actual fun SourceString.hmacSha256(key: String) = CryptoJS.asDynamic().HmacSHA256(this, key).toString().unsafeCast<String>()

View File

@@ -0,0 +1,14 @@
package dev.inmo.tgbotapi.utils
import dev.inmo.micro_utils.crypto.SourceString
import javax.crypto.Mac
import javax.crypto.spec.SecretKeySpec
actual fun SourceString.hmacSha256(key: String): String {
val mac = Mac.getInstance("HmacSHA256")
val secretKey = SecretKeySpec(key.toByteArray(), "HmacSHA256")
mac.init(secretKey)
return mac.doFinal(toByteArray()).hex()
}

View File

@@ -5,7 +5,7 @@ import dev.inmo.tgbotapi.bot.TelegramBot
import dev.inmo.tgbotapi.requests.DownloadFile import dev.inmo.tgbotapi.requests.DownloadFile
import dev.inmo.tgbotapi.requests.get.GetFile import dev.inmo.tgbotapi.requests.get.GetFile
import dev.inmo.tgbotapi.types.passport.credentials.* import dev.inmo.tgbotapi.types.passport.credentials.*
import dev.inmo.tgbotapi.types.files.PassportFile import dev.inmo.tgbotapi.types.passport.encrypted.PassportFile
fun EndDataCredentials.decryptData( fun EndDataCredentials.decryptData(
bytes: EncryptedData bytes: EncryptedData

View File

@@ -0,0 +1,56 @@
buildscript {
repositories {
mavenLocal()
mavenCentral()
}
dependencies {
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
classpath "org.jetbrains.kotlin:kotlin-serialization:$kotlin_version"
}
}
plugins {
id "org.jetbrains.kotlin.multiplatform"
id "org.jetbrains.kotlin.plugin.serialization"
}
project.version = "$library_version"
project.group = "$library_group"
project.description = "DEPRECATED, use tgbotapi.api"
apply from: "../publish.gradle"
repositories {
mavenLocal()
mavenCentral()
}
kotlin {
jvm {
compilations.main {
kotlinOptions {
jvmTarget = "1.8"
}
}
}
js(IR) {
browser()
nodejs()
}
sourceSets {
commonMain {
dependencies {
implementation kotlin('stdlib')
api project(":tgbotapi.api")
}
}
}
}
java {
sourceCompatibility = JavaVersion.VERSION_1_8
targetCompatibility = JavaVersion.VERSION_1_8
}

Some files were not shown because too many files have changed in this diff Show More