1
0
mirror of https://github.com/InsanusMokrassar/TelegramBotAPI.git synced 2025-11-18 13:00:18 +00:00

Compare commits

..

70 Commits

Author SHA1 Message Date
914a0662a9 CallbackGameInlineKeyboardButton now have only one income parameter 2020-04-22 14:11:46 +06:00
eda3003b7d change the way how we are deserializing updates in webhooks 2020-04-22 13:20:15 +06:00
459942de36 webhook update handling enhancement 2020-04-22 13:16:46 +06:00
17f64f9b48 CallbackGame update 2020-04-22 13:08:05 +06:00
3f896c2240 fix not implemented error thrown 2020-04-22 13:05:57 +06:00
94f8c971c5 started 0.26.4 2020-04-22 13:01:17 +06:00
c43109c063 Update README.md 2020-04-17 15:52:47 +06:00
f6058e29b4 Update README.md 2020-04-17 15:52:28 +06:00
3a37311331 Update README.md 2020-04-17 15:52:03 +06:00
9fe1472e64 update readme for help on JS platform 2020-04-17 15:43:43 +06:00
f1480c40a7 Merge pull request #81 from InsanusMokrassar/0.26.3
0.26.3
2020-04-13 12:55:48 +06:00
88eebdc448 small optimization of updates polling exception handling 2020-04-13 12:53:02 +06:00
8c76283db5 suspend inline function handleSafely was added 2020-04-13 12:40:14 +06:00
7668c48081 BaseEditMessageUpdate#data now is CommonMessage 2020-04-13 12:09:59 +06:00
35d2135f73 update serialization of InlineKeyboardButton 2020-04-13 11:31:36 +06:00
1cb0e096be fixes in InlineKeyboardButtonSerializer 2020-04-13 11:20:39 +06:00
31f7c7f31b UnknownUpdateType even if serialization exception 2020-04-13 11:17:15 +06:00
82d3b3bc48 add UnknownInlineKeyboardButton 2020-04-13 11:11:09 +06:00
b3734a5c2a fix of changelog 2020-04-13 01:46:58 +06:00
55b8736d50 Merge pull request #80 from Djaler/inline-keyboard-button-callback-game
Add support for inline keyboard buttons with callback_game field
2020-04-13 01:40:52 +06:00
3334fd3ca6 started 0.26.3 2020-04-13 01:39:31 +06:00
Kirill Romanov
e2416b405a add support for inline keyboard buttons with callback_game field 2020-04-12 22:30:37 +03:00
14f012fbfa Update README.md 2020-04-09 01:24:55 +06:00
1ff55057f2 Merge pull request #78 from InsanusMokrassar/0.26.2
0.26.2
2020-04-08 16:48:00 +06:00
71b5e33dbc update common README 2020-04-08 15:28:03 +06:00
08d9d183f4 add filterCommandsWithArgs 2020-04-08 15:23:12 +06:00
7183634fd6 experimentally make source string available inside of text sources 2020-04-08 15:17:13 +06:00
cf9f270651 rename new getting updates extension to avoid JVM signature collisions 2020-04-08 14:56:56 +06:00
bd87938e9c fixes in UpdatesChatFilters 2020-04-08 14:51:26 +06:00
ba76eaeb90 update readmes 2020-04-08 14:34:55 +06:00
d8492ae168 fixes, new readme 2020-04-08 14:02:55 +06:00
0db85232d3 fixes in changelog 2020-04-08 13:20:48 +06:00
bcf2325be8 make new startGettingOfUpdates more useful 2020-04-08 13:19:19 +06:00
51174a13de added some of extensions in TelegramBotAPI-extensions-utils 2020-04-08 11:50:47 +06:00
dfc1fa4d7e refill of changelog 2020-04-08 11:11:31 +06:00
10a1d1cb38 add TelegramBotAPI-extensions-utils 2020-04-08 11:05:48 +06:00
6c39dc4d06 new startGettingOfUpdates extension 2020-04-08 10:44:44 +06:00
4877b8958e start 0.26.2 2020-04-08 10:37:05 +06:00
db9c460e66 Merge pull request #75 from InsanusMokrassar/0.26.1
0.26.1
2020-04-06 12:15:27 +06:00
2bd5d53b2a fill changelog 2020-04-06 12:11:14 +06:00
577436843d fixes 2020-04-06 12:09:59 +06:00
048aa93044 InvalidPhotoDimensionsException 2020-04-05 14:06:40 +06:00
4e49de0dd7 fix in hashtag 2020-04-04 12:12:12 +06:00
9dc5a7624d complete CHANGELOG 2020-04-03 14:26:32 +06:00
21a15db031 StorageFile improvement 2020-04-03 14:22:34 +06:00
a6aa4b8758 BotCommand checks 2020-04-01 10:08:44 +06:00
e85d5df03e started 0.26.1 2020-04-01 10:05:30 +06:00
6833640c48 Create write-good.yml 2020-03-31 19:13:48 +06:00
c22c1bb144 Merge pull request #74 from InsanusMokrassar/0.26.0
0.26.0
2020-03-31 11:45:47 +06:00
8293d6683c optimize imports 2020-03-31 11:41:58 +06:00
7e6e892c45 libraries updates 2020-03-31 11:31:24 +06:00
43ac09a79b fixes in startGettingUpdates 2020-03-31 11:28:48 +06:00
ee1f115d77 refill TelegramBotAPI-extensions-api 2020-03-31 11:11:37 +06:00
7d85b6fb88 update readme of telegram bot api 2020-03-31 11:00:22 +06:00
013944c5c9 real fix:) 2020-03-30 22:52:57 +06:00
55ed3e165b resolve compiling errors 2020-03-30 22:47:20 +06:00
9c0106d229 StickerSetAction -> StandardStickerSetAction 2020-03-30 22:31:54 +06:00
9cd2a6220c add setStickerSetThumb 2020-03-30 22:29:34 +06:00
033ec8f2da update version 2020-03-30 22:18:59 +06:00
274afe8efc addAnimatedStickerToSet 2020-03-30 22:12:31 +06:00
e60630b331 add StickerSet#thumb 2020-03-30 22:07:13 +06:00
f6692a22d1 create new animated sticker set 2020-03-30 22:03:59 +06:00
53257ff131 hotfix for setMyCommands request 2020-03-30 21:53:36 +06:00
ec70813e49 commands handling added 2020-03-30 21:52:00 +06:00
54589ed17b BotCommand 2020-03-30 21:40:36 +06:00
1d3736c44e add realisation of DiceContent#createResend 2020-03-30 21:37:30 +06:00
8ef7acab2d sendDice in extensions api 2020-03-30 21:33:17 +06:00
c3fca5c6c4 include dice in TelegramBotAPI 2020-03-30 21:30:22 +06:00
84d2c88032 started 0.25.2 2020-03-30 21:16:04 +06:00
b7ec2f2b86 Merge pull request #71 from InsanusMokrassar/0.25.1
0.25.1
2020-03-26 14:36:00 +06:00
86 changed files with 1588 additions and 283 deletions

1
.github/write-good.yml vendored Normal file
View File

@@ -0,0 +1 @@
spellchecker: true

View File

@@ -1,5 +1,112 @@
# TelegramBotAPI changelog # TelegramBotAPI changelog
## 0.26.0
* `Common`:
* Versions updates:
* `Klock`: `1.10.0` -> `1.10.3`
* `TelegramBotAPI`:
* Request `SendDice` was added (calling [sendDice](https://core.telegram.org/bots/api#senddice))
* Class `Dice` was added (type [dice](https://core.telegram.org/bots/api#dice))
* Class `DiceContent` was added (for including it in [message](https://core.telegram.org/bots/api#message) object)
* `BotCommand` was added
* `GetMyCommands` request was added
* `SetMyCommands` request was added
* `GetMe` now is object instead of class
* `GetMe` was replaced into package `com.github.insanusmokrassar.TelegramBotAPI.requests.bot.GetMe`
* `CreateNewStickerSet` renamed to `CreateStaticNewStickerSet`
* `CreateNewAnimatedStickerSet` request was added (it handle work with `tgs_sticker`)
* `StickerSet#thumb` was added
* `AddStickerToSet` renamed to `AddStaticStickerToSet`
* `AddAnimatedStickerToSet` request was added
* `SetStickerSetThumb` request was added
* Most of sticker actions now implements `StandardStickerSetAction` instead of `StickerSetAction`
* `getUpdatesLimit` was added to be ensure in get updates limit
* `GetUpdates` now will check count of requesting updates and throw exception if it is not in range `1 .. 100`
* `GetUpdates#limit` now is not nullable and by default set up to 100
* `TelegramBotAPI-extensions-api`:
* Extensions `sendDice` was added
* Extension `getMyCommands` request was added
* Extension `setMyCommands` request was added
* Extension `getMe` was replaced into package `com.github.insanusmokrassar.TelegramBotAPI.extensions.api.bot.GetMeKt.getMe`
* **All extensions `createNewStickerSet` was renamed to `createNewStaticStickerSet`**
* Extensions `createNewAnimatedStickerSet` was added
* **All extensions `addStickerToSet` was renamed to `addStaticStickerToSet`**
* Extensions `addAnimatedStickerToSet` was added
* Extensions `setStickerSetThumb` was added
* Extension `startGettingUpdates` now will drop `SentMediaGroupUpdate` in case if it is the last in updates group
and size of retrieved updates is equal to 100 (max count of retrieved updates)
* Extensions `getUpdates` now will receive only not nullable `limit` parameter
### 0.26.4
* `TelegramBotAPI`:
* Now any getting of updates will return `UnknownUpdateType` when inside of deserialization will be
`SerializationException` or `NotImplemented` error
* `CallbackGame` currently is an object
* It is possible to use `CallbackGame` for now
* `CallbackGameInlineKeyboardButton` now will not accept `callbackGame` as income object
* Now it is possible to pass exception handler in webhook
### 0.26.3
* `TelegramBotAPI`:
* `CallbackGameInlineKeyboardButton` was added
([Issue-79](https://github.com/InsanusMokrassar/TelegramBotAPI/issues/79),
[PR-80](https://github.com/InsanusMokrassar/TelegramBotAPI/pull/80))
* `UnknownInlineKeyboardButton` was added. It is unavailable for creating, but you can receive it, for example, in
`InlineQueryResult`
* `Update` now will be created even if was `SerializationException` inside of creating the update instance - in this
case will be created `UnknownUpdateType`
* `UnknownUpdateType$rawJson` value now is included (`JsonElement`)
* **EXPERIMENTALLY** `BaseEditMessageUpdate#data` now is `CommonMessage<*>`
* Suspend inline function `handleSafely` was added
* `KtorRequestsExecutor` now use `handleSafely` instead of `try` with `supervisorScope`
* `UpdatesPolling` now use `handleSafely` instead of `try` with `supervisorScope`
### 0.26.2
* `TelegramBotAPI`:
* Now `EditMediaGroupUpdate` also extends `BaseEditMessageUpdate`
* **EXPERIMENTALLY** Now all `TextSource` realisations will contain `source` field as a property inside of them
* `TelegramBotAPI-extensions-api`:
* `startGettingFlowsUpdates` extension which do not require filter (but return a new one) was added
* `TelegramBotAPI-extensions-utils`:
* Subproject was added
* `filterBaseMessageUpdates`, `filterSentMediaGroupUpdates` and `filterEditMediaGroupUpdates` extensions was added
* `filterCommandsWithArgs`, `filterExactCommands` and `filterCommandsInsideTextMessages` extensions was added
* `asContentMessagesFlow`, `asChatEventsFlow` and `asUnknownMessagesFlow` extensions was added
* `withContentType` extension was added
* `onlyAnimationContentMessages` extension was added
* `onlyAudioContentMessages` extension was added
* `onlyContactContentMessages` extension was added
* `onlyDiceContentMessages` extension was added
* `onlyDocumentContentMessages` extension was added
* `onlyGameContentMessages` extension was added
* `onlyInvoiceContentMessages` extension was added
* `onlyLocationContentMessages` extension was added
* `onlyPhotoContentMessages` extension was added
* `onlyPollContentMessages` extension was added
* `onlyStickerContentMessages` extension was added
* `onlyTextContentMessages` extension was added
* `onlyVenueContentMessages` extension was added
* `onlyVideoContentMessages` extension was added
* `onlyVideoNoteContentMessages` extension was added
* `onlyVoiceContentMessages` extension was added
### 0.26.1
* `TelegramBotAPI`:
* `BotCommand` now will check and throw error in case when command or description lengths is/are incorrect
* `StorageFile` now is common for all platforms
* JavaScript realization was removed due to its redundancy
* JVM realization was replaced with `fun` factory
* `StorageFile` now able to accept any factory of `Input`
* `StorageFileInfo` was added to avoid strange collisions with throws in `StorageFile`
* Fixes issue with `hashTag` for markdown
* `InvalidPhotoDimensionsException` was added for cases when `PHOTO_INVALID_DIMENSION` answer received
* Other fixes
## 0.25.0 ## 0.25.0
* Common: * Common:

View File

@@ -1,27 +1,76 @@
# TelegramBotAPI # TelegramBotAPI
| Common info | [![Awesome Kotlin Badge](https://kotlin.link/awesome-kotlin.svg)](https://github.com/KotlinBy/awesome-kotlin) [![Chat in Telegram](badges/chat.svg)](https://t.me/InMoTelegramBotAPI) [![Build Status](https://travis-ci.com/InsanusMokrassar/TelegramBotAPI.svg?branch=master)](https://travis-ci.com/InsanusMokrassar/TelegramBotAPI) | | Common info | [![Awesome Kotlin Badge](https://kotlin.link/awesome-kotlin.svg)](https://github.com/KotlinBy/awesome-kotlin) [![Chat in Telegram](badges/chat.svg)](https://t.me/InMoTelegramBotAPI) [![Build Status](https://travis-ci.com/InsanusMokrassar/TelegramBotAPI.svg?branch=master)](https://travis-ci.com/InsanusMokrassar/TelegramBotAPI) |
| -----------:|:--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | -------------------------------------:|:------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| TelegramBotAPI status | [![Download](https://api.bintray.com/packages/insanusmokrassar/StandardRepository/TelegramBotAPI/images/download.svg)](https://bintray.com/insanusmokrassar/StandardRepository/TelegramBotAPI/_latestVersion) [![Maven Central](https://maven-badges.herokuapp.com/maven-central/com.github.insanusmokrassar/TelegramBotAPI/badge.svg)](https://maven-badges.herokuapp.com/maven-central/com.github.insanusmokrassar/TelegramBotAPI) | | TelegramBotAPI status | [![Download](https://api.bintray.com/packages/insanusmokrassar/StandardRepository/TelegramBotAPI/images/download.svg)](https://bintray.com/insanusmokrassar/StandardRepository/TelegramBotAPI/_latestVersion) [![Maven Central](https://maven-badges.herokuapp.com/maven-central/com.github.insanusmokrassar/TelegramBotAPI/badge.svg)](https://maven-badges.herokuapp.com/maven-central/com.github.insanusmokrassar/TelegramBotAPI) |
| TelegramBotAPI Extensions status | [![Download](https://api.bintray.com/packages/insanusmokrassar/StandardRepository/TelegramBotAPI-extensions-api/images/download.svg)](https://bintray.com/insanusmokrassar/StandardRepository/TelegramBotAPI-extensions-api/_latestVersion) [![Maven Central](https://maven-badges.herokuapp.com/maven-central/com.github.insanusmokrassar/TelegramBotAPI-extensions-api/badge.svg)](https://maven-badges.herokuapp.com/maven-central/com.github.insanusmokrassar/TelegramBotAPI-extensions-api) | | TelegramBotAPI Extensions status | [![Download](https://api.bintray.com/packages/insanusmokrassar/StandardRepository/TelegramBotAPI-extensions-api/images/download.svg)](https://bintray.com/insanusmokrassar/StandardRepository/TelegramBotAPI-extensions-api/_latestVersion) [![Maven Central](https://maven-badges.herokuapp.com/maven-central/com.github.insanusmokrassar/TelegramBotAPI-extensions-api/badge.svg)](https://maven-badges.herokuapp.com/maven-central/com.github.insanusmokrassar/TelegramBotAPI-extensions-api) |
| TelegramBotAPI Util Extensions status | [![Download](https://api.bintray.com/packages/insanusmokrassar/StandardRepository/TelegramBotAPI-extensions-utils/images/download.svg)](https://bintray.com/insanusmokrassar/StandardRepository/TelegramBotAPI-extensions-utils/_latestVersion) [![Maven Central](https://maven-badges.herokuapp.com/maven-central/com.github.insanusmokrassar/TelegramBotAPI-extensions-utils/badge.svg)](https://maven-badges.herokuapp.com/maven-central/com.github.insanusmokrassar/TelegramBotAPI-extensions-utils) |
It is a complex of libraries for working with `TelegramBotAPI` in type-safe and strict way as much as it possible. In It is a complex of libraries for working with `TelegramBotAPI` in type-safe and strict way as much as it possible. In
the list of this complex currently next projects: the list of this complex currently next projects:
* [TelegramBotAPI](TelegramBotAPI/README.md) - core of library. In fact it is independent library and can be used alone * [TelegramBotAPI](TelegramBotAPI/README.md) - core of library. In fact it is independent library and can be used alone
without any additional library without any additional library
* [TelegramBotAPI Extensions](TelegramBotAPI-extensions-api/README.md) - contains extensions (mostly for * [TelegramBotAPI Extensions](TelegramBotAPI-extensions-api/README.md) - contains extensions (mostly for
`RequestsExecutor`), which allows to use the core library in more pleasant way `RequestsExecutor`), which allows to use the core library in more pleasant way
* [TelegramBotAPI Util Extensions](TelegramBotAPI-extensions-utils/README.md) - contains extensions for more comfortable
work with commands, updates and other different things
Most part of some specific solves or unuseful Most part of some specific solves or unuseful
moments are describing by official [Telegram Bot API](https://core.telegram.org/bots/api). moments are describing by official [Telegram Bot API](https://core.telegram.org/bots/api).
## JavaScript notes
In case if you are want to use this library inside of browser, you will need additional settings (thanks for help to [Alexander Nozik](https://research.jetbrains.org/researchers/altavir)):
<details>
<summary>Gradle build script help</summary>
```groovy
dependencies {
/* ... */
implementation "com.github.insanusmokrassar:TelegramBotAPI:$tgbot_api_version"
implementation "com.github.insanusmokrassar:TelegramBotAPI-extensions-api:$tgbot_api_version" // optional
implementation "com.github.insanusmokrassar:TelegramBotAPI-extensions-utils:$tgbot_api_version" // optional
/* Block of dependencies for correct building in browser */
implementation(npm("fs"))
implementation(npm("bufferutil"))
implementation(npm("utf-8-validate"))
implementation(npm("abort-controller"))
implementation(npm("text-encoding"))
}
/* ... */
kotlin {
target {
browser {
/* Block for fix of exception in absence of some functionality, https://github.com/ktorio/ktor/issues/1339 */
dceTask {
dceOptions {
keep("ktor-ktor-io.\$\$importsForInline\$\$.ktor-ktor-io.io.ktor.utils.io")
}
}
}
}
}
```
</details>
## Ok, where should I start? ## Ok, where should I start?
Firstly, look at the [TelegramBotAPI](TelegramBotAPI/README.md). Here you can find all information about currently In most cases, the most simple way will be to implement
covered Telegram Bot API and other things. After this you can look at the [TelegramBotAPI Extensions](TelegramBotAPI-extensions-api/README.md) and
[TelegramBotAPI Extensions](TelegramBotAPI-extensions-api/README.md). [TelegramBotAPI Util Extensions](TelegramBotAPI-extensions-utils/README.md) for the reason that they contains more
simple tools. If you want to dive deeper in the core of library or develop something for it - welcome to
[TelegramBotAPI](TelegramBotAPI/README.md).
Anyway, all libraries are very typical inside of them. For example, any request in TelegramBotAPI look like Anyway, all libraries are very typical inside of them. Examples:
`requestsExecutor.execute(SomeRequest())`.
* In `TelegramBotAPI` common request look like `requestsExecutor.execute(SomeRequest())`
* `TelegramBotAPI-extensions-api` typical syntax look like `requestsExecutor.someRequest()` (in most cases it would be
better to use `bot` name instead of `requestsExecutor`)
* `TelegramBotAPI-extensions-utils` will look like `filter.filterBaseMessageUpdates(chatId).filterExactCommands(Regex("^.*$"))...`

View File

@@ -1,9 +1,7 @@
# TelegramBotAPI extensions # TelegramBotAPI extensions
[![Awesome Kotlin Badge](https://kotlin.link/awesome-kotlin.svg)](https://github.com/KotlinBy/awesome-kotlin)
[![Download](https://api.bintray.com/packages/insanusmokrassar/StandardRepository/TelegramBotAPI-extensions-api/images/download.svg) ](https://bintray.com/insanusmokrassar/StandardRepository/TelegramBotAPI-extensions-api/_latestVersion) [![Download](https://api.bintray.com/packages/insanusmokrassar/StandardRepository/TelegramBotAPI-extensions-api/images/download.svg) ](https://bintray.com/insanusmokrassar/StandardRepository/TelegramBotAPI-extensions-api/_latestVersion)
[![Maven Central](https://maven-badges.herokuapp.com/maven-central/com.github.insanusmokrassar/TelegramBotAPI-extensions-api/badge.svg)](https://maven-badges.herokuapp.com/maven-central/com.github.insanusmokrassar/TelegramBotAPI-extensions-api) [![Maven Central](https://maven-badges.herokuapp.com/maven-central/com.github.insanusmokrassar/TelegramBotAPI-extensions-api/badge.svg)](https://maven-badges.herokuapp.com/maven-central/com.github.insanusmokrassar/TelegramBotAPI-extensions-api)
[![Build Status](https://jenkins.insanusmokrassar.com/buildStatus/icon?job=TelegramBotAPI-extensions-api_master__publishing)](https://jenkins.insanusmokrassar.com/job/TelegramBotAPI-extensions-api_master__publishing/)
## What is it? ## What is it?
@@ -56,20 +54,64 @@ compile "com.github.insanusmokrassar:TelegramBotAPI-extensions-api:$telegrambota
## Example of usage and comparison with `TelegramBotAPI` ## Example of usage and comparison with `TelegramBotAPI`
As said in [TelegramBotAPI](../TelegramBotAPI/README.md#Requests), it is possible to use next syntax for requests: Here presented review table for comparison of api from original [TelegramBotAPI](../TelegramBotAPI/README.md#Requests)
and extensions-api library:
```kotlin In all examples supposed that you have created bot with next approximate lines:
val requestsExecutor: RequestsExecutor = ...
requestsExecutor.execute(GetMe())
```
This library offer a little bit another way for this:
```kotlin ```kotlin
val bot: RequestsExecutor = ... val bot: RequestsExecutor = ...
bot.getMe()
``` ```
The result type of [GetMe (and getMe extension)](https://github.com/InsanusMokrassar/TelegramBotAPI/blob/master/TelegramBotAPI/src/commonMain/kotlin/com/github/insanusmokrassar/TelegramBotAPI/requests/GetMe.kt) | TelegramBotAPI | TelegramBotAPI-extensions-api |
request is |----------------|-------------------------------|
[ExtendedBot](https://github.com/InsanusMokrassar/TelegramBotAPI/blob/master/TelegramBotAPI/src/commonMain/kotlin/com/github/insanusmokrassar/TelegramBotAPI/types/User.kt). | bot.execute(GetMe) | bot.getMe() |
| bot.execute(SendTextMessage(someChatId, text)) | bot.sendTextMessage(chat, text) |
## Updates
Usually, it is more comfortable to use filter object to get separated types of updates:
```kotlin
val filter = FlowsUpdatesFilter(100)
```
In this case you will be able:
* Separate types of incoming updates (even media groups)
* Simplify launch of getting updates:
```kotlin
bot.startGettingOfUpdates(
filter,
scope = CoroutineScope(Dispatchers.Default)
)
```
* Use `filter` flows to comfortable filter, map and do other operations with the whole
getting updates process:
```kotlin
filter.messageFlow.mapNotNull {
it.data as? ContentMessage<*>
}.onEach {
println(it)
}.launchIn(
CoroutineScope(Dispatchers.Default)
)
```
### Alternative way
There is an alternative way to get updates. In fact it is almost the same, but could be more useful for some cases:
```kotlin
val filter = bot.startGettingOfUpdates(
scope = CoroutineScope(Dispatchers.Default)
) { // Here as reveiver will be FlowsUpdatesFilter
messageFlow.mapNotNull {
it.data as? ContentMessage<*>
}.onEach {
println(it)
}.launchIn(
CoroutineScope(Dispatchers.Default)
)
}
```

View File

@@ -1,6 +1,10 @@
package com.github.insanusmokrassar.TelegramBotAPI.extensions.api package com.github.insanusmokrassar.TelegramBotAPI.extensions.api
import com.github.insanusmokrassar.TelegramBotAPI.bot.RequestsExecutor import com.github.insanusmokrassar.TelegramBotAPI.bot.RequestsExecutor
import com.github.insanusmokrassar.TelegramBotAPI.requests.GetMe import com.github.insanusmokrassar.TelegramBotAPI.extensions.api.bot.getMe
suspend fun RequestsExecutor.getMe() = execute(GetMe()) @Deprecated(
"Replaced",
ReplaceWith("getMe", "com.github.insanusmokrassar.TelegramBotAPI.extensions.api.bot.GetMeKt.getMe")
)
suspend fun RequestsExecutor.getMe() = getMe()

View File

@@ -7,7 +7,7 @@ import com.github.insanusmokrassar.TelegramBotAPI.types.update.abstracts.Update
suspend fun RequestsExecutor.getUpdates( suspend fun RequestsExecutor.getUpdates(
offset: UpdateIdentifier? = null, offset: UpdateIdentifier? = null,
limit: Int? = null, limit: Int = getUpdatesLimit.last,
timeout: Seconds? = null, timeout: Seconds? = null,
allowed_updates: List<String>? = ALL_UPDATES_LIST allowed_updates: List<String>? = ALL_UPDATES_LIST
) = execute( ) = execute(
@@ -18,7 +18,7 @@ suspend fun RequestsExecutor.getUpdates(
suspend fun RequestsExecutor.getUpdates( suspend fun RequestsExecutor.getUpdates(
lastUpdate: Update, lastUpdate: Update,
limit: Int? = null, limit: Int = getUpdatesLimit.last,
timeout: Seconds? = null, timeout: Seconds? = null,
allowed_updates: List<String>? = ALL_UPDATES_LIST allowed_updates: List<String>? = ALL_UPDATES_LIST
) = getUpdates( ) = getUpdates(

View File

@@ -0,0 +1,6 @@
package com.github.insanusmokrassar.TelegramBotAPI.extensions.api.bot
import com.github.insanusmokrassar.TelegramBotAPI.bot.RequestsExecutor
import com.github.insanusmokrassar.TelegramBotAPI.requests.bot.GetMe
suspend fun RequestsExecutor.getMe() = execute(GetMe)

View File

@@ -0,0 +1,6 @@
package com.github.insanusmokrassar.TelegramBotAPI.extensions.api.bot
import com.github.insanusmokrassar.TelegramBotAPI.bot.RequestsExecutor
import com.github.insanusmokrassar.TelegramBotAPI.requests.bot.GetMyCommands
suspend fun RequestsExecutor.getMyCommands() = execute(GetMyCommands)

View File

@@ -0,0 +1,9 @@
package com.github.insanusmokrassar.TelegramBotAPI.extensions.api.bot
import com.github.insanusmokrassar.TelegramBotAPI.bot.RequestsExecutor
import com.github.insanusmokrassar.TelegramBotAPI.requests.bot.SetMyCommands
import com.github.insanusmokrassar.TelegramBotAPI.types.BotCommand
suspend fun RequestsExecutor.setMyCommands(
commands: List<BotCommand>
) = execute(SetMyCommands(commands))

View File

@@ -0,0 +1,24 @@
package com.github.insanusmokrassar.TelegramBotAPI.extensions.api.send
import com.github.insanusmokrassar.TelegramBotAPI.bot.RequestsExecutor
import com.github.insanusmokrassar.TelegramBotAPI.requests.send.SendDice
import com.github.insanusmokrassar.TelegramBotAPI.types.ChatIdentifier
import com.github.insanusmokrassar.TelegramBotAPI.types.MessageIdentifier
import com.github.insanusmokrassar.TelegramBotAPI.types.buttons.KeyboardMarkup
import com.github.insanusmokrassar.TelegramBotAPI.types.chat.abstracts.Chat
suspend fun RequestsExecutor.sendDice(
chatId: ChatIdentifier,
disableNotification: Boolean = false,
replyToMessageId: MessageIdentifier? = null,
replyMarkup: KeyboardMarkup? = null
) = execute(
SendDice(chatId, disableNotification, replyToMessageId, replyMarkup)
)
suspend fun RequestsExecutor.sendDice(
chat: Chat,
disableNotification: Boolean = false,
replyToMessageId: MessageIdentifier? = null,
replyMarkup: KeyboardMarkup? = null
) = sendDice(chat.id, disableNotification, replyToMessageId, replyMarkup)

View File

@@ -0,0 +1,90 @@
package com.github.insanusmokrassar.TelegramBotAPI.extensions.api.stickers
import com.github.insanusmokrassar.TelegramBotAPI.bot.RequestsExecutor
import com.github.insanusmokrassar.TelegramBotAPI.requests.abstracts.FileId
import com.github.insanusmokrassar.TelegramBotAPI.requests.abstracts.MultipartFile
import com.github.insanusmokrassar.TelegramBotAPI.requests.stickers.AddAnimatedStickerToSet
import com.github.insanusmokrassar.TelegramBotAPI.types.CommonUser
import com.github.insanusmokrassar.TelegramBotAPI.types.UserId
import com.github.insanusmokrassar.TelegramBotAPI.types.stickers.MaskPosition
import com.github.insanusmokrassar.TelegramBotAPI.types.stickers.StickerSet
suspend fun RequestsExecutor.addAnimatedStickerToSet(
userId: UserId,
stickerSetName: String,
sticker: FileId,
emojis: String,
maskPosition: MaskPosition? = null
) = execute(
AddAnimatedStickerToSet(userId, stickerSetName, sticker, emojis, maskPosition)
)
suspend fun RequestsExecutor.addAnimatedStickerToSet(
userId: UserId,
stickerSetName: String,
sticker: MultipartFile,
emojis: String,
maskPosition: MaskPosition? = null
) = execute(
AddAnimatedStickerToSet(userId, stickerSetName, sticker, emojis, maskPosition)
)
suspend fun RequestsExecutor.addAnimatedStickerToSet(
user: CommonUser,
stickerSetName: String,
sticker: FileId,
emojis: String,
maskPosition: MaskPosition? = null
) = addAnimatedStickerToSet(
user.id, stickerSetName, sticker, emojis, maskPosition
)
suspend fun RequestsExecutor.addAnimatedStickerToSet(
user: CommonUser,
stickerSetName: String,
sticker: MultipartFile,
emojis: String,
maskPosition: MaskPosition? = null
) = addAnimatedStickerToSet(
user.id, stickerSetName, sticker, emojis, maskPosition
)
suspend fun RequestsExecutor.addAnimatedStickerToSet(
userId: UserId,
stickerSet: StickerSet,
sticker: FileId,
emojis: String,
maskPosition: MaskPosition? = null
) = addAnimatedStickerToSet(
userId, stickerSet.name, sticker, emojis, maskPosition
)
suspend fun RequestsExecutor.addAnimatedStickerToSet(
userId: UserId,
stickerSet: StickerSet,
sticker: MultipartFile,
emojis: String,
maskPosition: MaskPosition? = null
) = addAnimatedStickerToSet(
userId, stickerSet.name, sticker, emojis, maskPosition
)
suspend fun RequestsExecutor.addAnimatedStickerToSet(
user: CommonUser,
stickerSet: StickerSet,
sticker: FileId,
emojis: String,
maskPosition: MaskPosition? = null
) = addAnimatedStickerToSet(
user.id, stickerSet.name, sticker, emojis, maskPosition
)
suspend fun RequestsExecutor.addAnimatedStickerToSet(
user: CommonUser,
stickerSet: StickerSet,
sticker: MultipartFile,
emojis: String,
maskPosition: MaskPosition? = null
) = addAnimatedStickerToSet(
user.id, stickerSet.name, sticker, emojis, maskPosition
)

View File

@@ -3,88 +3,88 @@ package com.github.insanusmokrassar.TelegramBotAPI.extensions.api.stickers
import com.github.insanusmokrassar.TelegramBotAPI.bot.RequestsExecutor import com.github.insanusmokrassar.TelegramBotAPI.bot.RequestsExecutor
import com.github.insanusmokrassar.TelegramBotAPI.requests.abstracts.FileId import com.github.insanusmokrassar.TelegramBotAPI.requests.abstracts.FileId
import com.github.insanusmokrassar.TelegramBotAPI.requests.abstracts.MultipartFile import com.github.insanusmokrassar.TelegramBotAPI.requests.abstracts.MultipartFile
import com.github.insanusmokrassar.TelegramBotAPI.requests.stickers.AddStickerToSet import com.github.insanusmokrassar.TelegramBotAPI.requests.stickers.AddStaticStickerToSet
import com.github.insanusmokrassar.TelegramBotAPI.types.CommonUser import com.github.insanusmokrassar.TelegramBotAPI.types.CommonUser
import com.github.insanusmokrassar.TelegramBotAPI.types.UserId import com.github.insanusmokrassar.TelegramBotAPI.types.UserId
import com.github.insanusmokrassar.TelegramBotAPI.types.stickers.MaskPosition import com.github.insanusmokrassar.TelegramBotAPI.types.stickers.MaskPosition
import com.github.insanusmokrassar.TelegramBotAPI.types.stickers.StickerSet import com.github.insanusmokrassar.TelegramBotAPI.types.stickers.StickerSet
suspend fun RequestsExecutor.addStickerToSet( suspend fun RequestsExecutor.addStaticStickerToSet(
userId: UserId, userId: UserId,
stickerSetName: String, stickerSetName: String,
sticker: FileId, sticker: FileId,
emojis: String, emojis: String,
maskPosition: MaskPosition? = null maskPosition: MaskPosition? = null
) = execute( ) = execute(
AddStickerToSet(userId, stickerSetName, sticker, emojis, maskPosition) AddStaticStickerToSet(userId, stickerSetName, sticker, emojis, maskPosition)
) )
suspend fun RequestsExecutor.addStickerToSet( suspend fun RequestsExecutor.addStaticStickerToSet(
userId: UserId, userId: UserId,
stickerSetName: String, stickerSetName: String,
sticker: MultipartFile, sticker: MultipartFile,
emojis: String, emojis: String,
maskPosition: MaskPosition? = null maskPosition: MaskPosition? = null
) = execute( ) = execute(
AddStickerToSet(userId, stickerSetName, sticker, emojis, maskPosition) AddStaticStickerToSet(userId, stickerSetName, sticker, emojis, maskPosition)
) )
suspend fun RequestsExecutor.addStickerToSet( suspend fun RequestsExecutor.addStaticStickerToSet(
user: CommonUser, user: CommonUser,
stickerSetName: String, stickerSetName: String,
sticker: FileId, sticker: FileId,
emojis: String, emojis: String,
maskPosition: MaskPosition? = null maskPosition: MaskPosition? = null
) = addStickerToSet( ) = addStaticStickerToSet(
user.id, stickerSetName, sticker, emojis, maskPosition user.id, stickerSetName, sticker, emojis, maskPosition
) )
suspend fun RequestsExecutor.addStickerToSet( suspend fun RequestsExecutor.addStaticStickerToSet(
user: CommonUser, user: CommonUser,
stickerSetName: String, stickerSetName: String,
sticker: MultipartFile, sticker: MultipartFile,
emojis: String, emojis: String,
maskPosition: MaskPosition? = null maskPosition: MaskPosition? = null
) = addStickerToSet( ) = addStaticStickerToSet(
user.id, stickerSetName, sticker, emojis, maskPosition user.id, stickerSetName, sticker, emojis, maskPosition
) )
suspend fun RequestsExecutor.addStickerToSet( suspend fun RequestsExecutor.addStaticStickerToSet(
userId: UserId, userId: UserId,
stickerSet: StickerSet, stickerSet: StickerSet,
sticker: FileId, sticker: FileId,
emojis: String, emojis: String,
maskPosition: MaskPosition? = null maskPosition: MaskPosition? = null
) = addStickerToSet( ) = addStaticStickerToSet(
userId, stickerSet.name, sticker, emojis, maskPosition userId, stickerSet.name, sticker, emojis, maskPosition
) )
suspend fun RequestsExecutor.addStickerToSet( suspend fun RequestsExecutor.addStaticStickerToSet(
userId: UserId, userId: UserId,
stickerSet: StickerSet, stickerSet: StickerSet,
sticker: MultipartFile, sticker: MultipartFile,
emojis: String, emojis: String,
maskPosition: MaskPosition? = null maskPosition: MaskPosition? = null
) = addStickerToSet( ) = addStaticStickerToSet(
userId, stickerSet.name, sticker, emojis, maskPosition userId, stickerSet.name, sticker, emojis, maskPosition
) )
suspend fun RequestsExecutor.addStickerToSet( suspend fun RequestsExecutor.addStaticStickerToSet(
user: CommonUser, user: CommonUser,
stickerSet: StickerSet, stickerSet: StickerSet,
sticker: FileId, sticker: FileId,
emojis: String, emojis: String,
maskPosition: MaskPosition? = null maskPosition: MaskPosition? = null
) = addStickerToSet( ) = addStaticStickerToSet(
user.id, stickerSet.name, sticker, emojis, maskPosition user.id, stickerSet.name, sticker, emojis, maskPosition
) )
suspend fun RequestsExecutor.addStickerToSet( suspend fun RequestsExecutor.addStaticStickerToSet(
user: CommonUser, user: CommonUser,
stickerSet: StickerSet, stickerSet: StickerSet,
sticker: MultipartFile, sticker: MultipartFile,
emojis: String, emojis: String,
maskPosition: MaskPosition? = null maskPosition: MaskPosition? = null
) = addStickerToSet( ) = addStaticStickerToSet(
user.id, stickerSet.name, sticker, emojis, maskPosition user.id, stickerSet.name, sticker, emojis, maskPosition
) )

View File

@@ -0,0 +1,54 @@
package com.github.insanusmokrassar.TelegramBotAPI.extensions.api.stickers
import com.github.insanusmokrassar.TelegramBotAPI.bot.RequestsExecutor
import com.github.insanusmokrassar.TelegramBotAPI.requests.abstracts.FileId
import com.github.insanusmokrassar.TelegramBotAPI.requests.abstracts.MultipartFile
import com.github.insanusmokrassar.TelegramBotAPI.requests.stickers.CreateNewAnimatedStickerSet
import com.github.insanusmokrassar.TelegramBotAPI.types.CommonUser
import com.github.insanusmokrassar.TelegramBotAPI.types.UserId
import com.github.insanusmokrassar.TelegramBotAPI.types.stickers.MaskPosition
suspend fun RequestsExecutor.createNewAnimatedStickerSet(
userId: UserId,
name: String,
sticker: FileId,
emojis: String,
containsMasks: Boolean? = null,
maskPosition: MaskPosition? = null
) = execute(
CreateNewAnimatedStickerSet(userId, name, sticker, emojis, containsMasks, maskPosition)
)
suspend fun RequestsExecutor.createNewAnimatedStickerSet(
userId: UserId,
name: String,
sticker: MultipartFile,
emojis: String,
containsMasks: Boolean? = null,
maskPosition: MaskPosition? = null
) = execute(
CreateNewAnimatedStickerSet(userId, name, sticker, emojis, containsMasks, maskPosition)
)
suspend fun RequestsExecutor.createNewAnimatedStickerSet(
user: CommonUser,
name: String,
sticker: FileId,
emojis: String,
containsMasks: Boolean? = null,
maskPosition: MaskPosition? = null
) = createNewAnimatedStickerSet(
user.id, name, sticker, emojis, containsMasks, maskPosition
)
suspend fun RequestsExecutor.createNewAnimatedStickerSet(
user: CommonUser,
name: String,
sticker: MultipartFile,
emojis: String,
containsMasks: Boolean? = null,
maskPosition: MaskPosition? = null
) = createNewAnimatedStickerSet(
user.id, name, sticker, emojis, containsMasks, maskPosition
)

View File

@@ -3,12 +3,12 @@ package com.github.insanusmokrassar.TelegramBotAPI.extensions.api.stickers
import com.github.insanusmokrassar.TelegramBotAPI.bot.RequestsExecutor import com.github.insanusmokrassar.TelegramBotAPI.bot.RequestsExecutor
import com.github.insanusmokrassar.TelegramBotAPI.requests.abstracts.FileId import com.github.insanusmokrassar.TelegramBotAPI.requests.abstracts.FileId
import com.github.insanusmokrassar.TelegramBotAPI.requests.abstracts.MultipartFile import com.github.insanusmokrassar.TelegramBotAPI.requests.abstracts.MultipartFile
import com.github.insanusmokrassar.TelegramBotAPI.requests.stickers.CreateNewStickerSet import com.github.insanusmokrassar.TelegramBotAPI.requests.stickers.CreateNewStaticStickerSet
import com.github.insanusmokrassar.TelegramBotAPI.types.CommonUser import com.github.insanusmokrassar.TelegramBotAPI.types.CommonUser
import com.github.insanusmokrassar.TelegramBotAPI.types.UserId import com.github.insanusmokrassar.TelegramBotAPI.types.UserId
import com.github.insanusmokrassar.TelegramBotAPI.types.stickers.MaskPosition import com.github.insanusmokrassar.TelegramBotAPI.types.stickers.MaskPosition
suspend fun RequestsExecutor.createNewStickerSet( suspend fun RequestsExecutor.createNewStaticStickerSet(
userId: UserId, userId: UserId,
name: String, name: String,
sticker: FileId, sticker: FileId,
@@ -16,10 +16,10 @@ suspend fun RequestsExecutor.createNewStickerSet(
containsMasks: Boolean? = null, containsMasks: Boolean? = null,
maskPosition: MaskPosition? = null maskPosition: MaskPosition? = null
) = execute( ) = execute(
CreateNewStickerSet(userId, name, sticker, emojis, containsMasks, maskPosition) CreateNewStaticStickerSet(userId, name, sticker, emojis, containsMasks, maskPosition)
) )
suspend fun RequestsExecutor.createNewStickerSet( suspend fun RequestsExecutor.createNewStaticStickerSet(
userId: UserId, userId: UserId,
name: String, name: String,
sticker: MultipartFile, sticker: MultipartFile,
@@ -27,28 +27,28 @@ suspend fun RequestsExecutor.createNewStickerSet(
containsMasks: Boolean? = null, containsMasks: Boolean? = null,
maskPosition: MaskPosition? = null maskPosition: MaskPosition? = null
) = execute( ) = execute(
CreateNewStickerSet(userId, name, sticker, emojis, containsMasks, maskPosition) CreateNewStaticStickerSet(userId, name, sticker, emojis, containsMasks, maskPosition)
) )
suspend fun RequestsExecutor.createNewStickerSet( suspend fun RequestsExecutor.createNewStaticStickerSet(
user: CommonUser, user: CommonUser,
name: String, name: String,
sticker: FileId, sticker: FileId,
emojis: String, emojis: String,
containsMasks: Boolean? = null, containsMasks: Boolean? = null,
maskPosition: MaskPosition? = null maskPosition: MaskPosition? = null
) = createNewStickerSet( ) = createNewStaticStickerSet(
user.id, name, sticker, emojis, containsMasks, maskPosition user.id, name, sticker, emojis, containsMasks, maskPosition
) )
suspend fun RequestsExecutor.createNewStickerSet( suspend fun RequestsExecutor.createNewStaticStickerSet(
user: CommonUser, user: CommonUser,
name: String, name: String,
sticker: MultipartFile, sticker: MultipartFile,
emojis: String, emojis: String,
containsMasks: Boolean? = null, containsMasks: Boolean? = null,
maskPosition: MaskPosition? = null maskPosition: MaskPosition? = null
) = createNewStickerSet( ) = createNewStaticStickerSet(
user.id, name, sticker, emojis, containsMasks, maskPosition user.id, name, sticker, emojis, containsMasks, maskPosition
) )

View File

@@ -0,0 +1,74 @@
package com.github.insanusmokrassar.TelegramBotAPI.extensions.api.thumbs
import com.github.insanusmokrassar.TelegramBotAPI.bot.RequestsExecutor
import com.github.insanusmokrassar.TelegramBotAPI.requests.abstracts.FileId
import com.github.insanusmokrassar.TelegramBotAPI.requests.abstracts.MultipartFile
import com.github.insanusmokrassar.TelegramBotAPI.requests.stickers.SetStickerSetThumb
import com.github.insanusmokrassar.TelegramBotAPI.types.CommonUser
import com.github.insanusmokrassar.TelegramBotAPI.types.UserId
import com.github.insanusmokrassar.TelegramBotAPI.types.stickers.StickerSet
suspend fun RequestsExecutor.setStickerSetThumb(
userId: UserId,
thumbSetName: String,
thumb: FileId
) = execute(
SetStickerSetThumb(userId, thumbSetName, thumb)
)
suspend fun RequestsExecutor.setStickerSetThumb(
userId: UserId,
thumbSetName: String,
thumb: MultipartFile
) = execute(
SetStickerSetThumb(userId, thumbSetName, thumb)
)
suspend fun RequestsExecutor.setStickerSetThumb(
user: CommonUser,
thumbSetName: String,
thumb: FileId
) = setStickerSetThumb(
user.id, thumbSetName, thumb
)
suspend fun RequestsExecutor.setStickerSetThumb(
user: CommonUser,
thumbSetName: String,
thumb: MultipartFile
) = setStickerSetThumb(
user.id, thumbSetName, thumb
)
suspend fun RequestsExecutor.setStickerSetThumb(
userId: UserId,
thumbSet: StickerSet,
thumb: FileId
) = setStickerSetThumb(
userId, thumbSet.name, thumb
)
suspend fun RequestsExecutor.setStickerSetThumb(
userId: UserId,
thumbSet: StickerSet,
thumb: MultipartFile
) = setStickerSetThumb(
userId, thumbSet.name, thumb
)
suspend fun RequestsExecutor.setStickerSetThumb(
user: CommonUser,
thumbSet: StickerSet,
thumb: FileId
) = setStickerSetThumb(
user.id, thumbSet.name, thumb
)
suspend fun RequestsExecutor.setStickerSetThumb(
user: CommonUser,
thumbSet: StickerSet,
thumb: MultipartFile
) = setStickerSetThumb(
user.id, thumbSet.name, thumb
)

View File

@@ -5,12 +5,13 @@ import com.github.insanusmokrassar.TelegramBotAPI.bot.exceptions.RequestExceptio
import com.github.insanusmokrassar.TelegramBotAPI.extensions.api.InternalUtils.convertWithMediaGroupUpdates import com.github.insanusmokrassar.TelegramBotAPI.extensions.api.InternalUtils.convertWithMediaGroupUpdates
import com.github.insanusmokrassar.TelegramBotAPI.extensions.api.InternalUtils.lastUpdateIdentifier import com.github.insanusmokrassar.TelegramBotAPI.extensions.api.InternalUtils.lastUpdateIdentifier
import com.github.insanusmokrassar.TelegramBotAPI.extensions.api.getUpdates import com.github.insanusmokrassar.TelegramBotAPI.extensions.api.getUpdates
import com.github.insanusmokrassar.TelegramBotAPI.types.Seconds import com.github.insanusmokrassar.TelegramBotAPI.types.*
import com.github.insanusmokrassar.TelegramBotAPI.types.UpdateIdentifier
import com.github.insanusmokrassar.TelegramBotAPI.types.update.* import com.github.insanusmokrassar.TelegramBotAPI.types.update.*
import com.github.insanusmokrassar.TelegramBotAPI.types.update.MediaGroupUpdates.* import com.github.insanusmokrassar.TelegramBotAPI.types.update.MediaGroupUpdates.*
import com.github.insanusmokrassar.TelegramBotAPI.types.update.abstracts.Update import com.github.insanusmokrassar.TelegramBotAPI.types.update.abstracts.Update
import com.github.insanusmokrassar.TelegramBotAPI.updateshandlers.* import com.github.insanusmokrassar.TelegramBotAPI.updateshandlers.*
import com.github.insanusmokrassar.TelegramBotAPI.utils.PreviewFeature
import com.github.insanusmokrassar.TelegramBotAPI.utils.handleSafely
import io.ktor.client.features.HttpRequestTimeoutException import io.ktor.client.features.HttpRequestTimeoutException
import kotlinx.coroutines.* import kotlinx.coroutines.*
@@ -24,33 +25,62 @@ fun RequestsExecutor.startGettingOfUpdates(
var lastUpdateIdentifier: UpdateIdentifier? = null var lastUpdateIdentifier: UpdateIdentifier? = null
while (isActive) { while (isActive) {
try { handleSafely(
supervisorScope { { e ->
val updates = getUpdates( exceptionsHandler ?.invoke(e)
offset = lastUpdateIdentifier?.plus(1), if (e is RequestException) {
timeout = timeoutSeconds, delay(1000L)
allowed_updates = allowedUpdates }
).convertWithMediaGroupUpdates() }
) {
supervisorScope { val updates = getUpdates(
for (update in updates) { offset = lastUpdateIdentifier?.plus(1),
updatesReceiver(update) timeout = timeoutSeconds,
allowed_updates = allowedUpdates
lastUpdateIdentifier = update.lastUpdateIdentifier() ).let { originalUpdates ->
} val converted = originalUpdates.convertWithMediaGroupUpdates()
/**
* Dirty hack for cases when the media group was retrieved not fully:
*
* We are throw out the last media group and will reretrieve it again in the next get updates
* and it will guarantee that it is full
*/
if (originalUpdates.size == getUpdatesLimit.last && converted.last() is SentMediaGroupUpdate) {
converted - converted.last()
} else {
converted
}
}
handleSafely {
for (update in updates) {
updatesReceiver(update)
lastUpdateIdentifier = update.lastUpdateIdentifier()
} }
} }
} catch (e: HttpRequestTimeoutException) {
exceptionsHandler ?.invoke(e) // it is ok due to mechanism of long polling
} catch (e: RequestException) {
exceptionsHandler ?.invoke(e) // it is not ok, but in most cases it will mean that there is some limit for requests count
delay(1000L)
} catch (e: Exception) {
exceptionsHandler ?.invoke(e)
} }
} }
} }
/**
* This method will create a new one [FlowsUpdatesFilter]. This method could be unsafe due to the fact that it will start
* getting updates IMMEDIATELY. That means that your bot will be able to skip some of them until you will call
* [kotlinx.coroutines.flow.Flow.collect] on one of [FlowsUpdatesFilter] flows. To avoid it, you can pass
* [flowUpdatesPreset] lambda - it will be called BEFORE starting updates getting
*/
@PreviewFeature
fun RequestsExecutor.startGettingFlowsUpdates(
timeoutSeconds: Seconds = 30,
scope: CoroutineScope = CoroutineScope(Dispatchers.Default),
exceptionsHandler: (suspend (Exception) -> Unit)? = null,
flowsUpdatesFilterUpdatesKeeperCount: Int = 64,
flowUpdatesPreset: FlowsUpdatesFilter.() -> Unit = {}
): FlowsUpdatesFilter = FlowsUpdatesFilter(flowsUpdatesFilterUpdatesKeeperCount).apply {
flowUpdatesPreset()
startGettingOfUpdates(timeoutSeconds, scope, exceptionsHandler, allowedUpdates, asUpdateReceiver)
}
fun RequestsExecutor.startGettingOfUpdates( fun RequestsExecutor.startGettingOfUpdates(
updatesFilter: UpdatesFilter, updatesFilter: UpdatesFilter,
timeoutSeconds: Seconds = 30, timeoutSeconds: Seconds = 30,

View File

@@ -0,0 +1,81 @@
# TelegramBotAPI Util Extensions
[![Download](https://api.bintray.com/packages/insanusmokrassar/StandardRepository/TelegramBotAPI-extensions-utils/images/download.svg) ](https://bintray.com/insanusmokrassar/StandardRepository/TelegramBotAPI-extensions-utils/_latestVersion)
[![Maven Central](https://maven-badges.herokuapp.com/maven-central/com.github.insanusmokrassar/TelegramBotAPI-extensions-utils/badge.svg)](https://maven-badges.herokuapp.com/maven-central/com.github.insanusmokrassar/TelegramBotAPI-extensions-utils)
## What is it?
It is wrapper library for [TelegramBotAPI](../TelegramBotAPI/README.md). Currently, this library contains some usefull filters for commands, updates types and different others.
## How to implement library?
Common ways to implement this library are presented here. In some cases it will require additional steps
like inserting of additional libraries (like `kotlin stdlib`). In the examples will be used variable
`telegrambotapi-extensions-utils_version`, which must be set up by developer. Available versions are presented on
[bintray](https://bintray.com/insanusmokrassar/StandardRepository/TelegramBotAPI-extensions-utils), next version is last published:
[![Download](https://api.bintray.com/packages/insanusmokrassar/StandardRepository/TelegramBotAPI-extensions-utils/images/download.svg) ](https://bintray.com/insanusmokrassar/StandardRepository/TelegramBotAPI-extensions-utils/_latestVersion)
### Maven
Dependency config presented here:
```xml
<dependency>
<groupId>com.github.insanusmokrassar</groupId>
<artifactId>TelegramBotAPI-extensions-utils</artifactId>
<version>${telegrambotapi-extensions-utils_version}</version>
</dependency>
```
### Gradle
To use last versions you will need to add one line in repositories block of your `build.gradle`:
`jcenter()` or `mavenCentral()`
And add next line to your dependencies block:
```groovy
implementation "com.github.insanusmokrassar:TelegramBotAPI-extensions-utils:$telegrambotapi-extensions-utils_version"
```
or for old gradle:
```groovy
compile "com.github.insanusmokrassar:TelegramBotAPI-extensions-utils:$telegrambotapi-extensions-utils_version"
```
## How to use?
Here will be presented several examples of usage. In all cases it is expected that you have created your bot and filter:
```kotlin
val bot: RequestsExecutor = KtorRequestsExecutor(
TelegramAPIUrlsKeeper(BOT_TOKEN)
)
val filter = FlowsUpdatesFilter(64)
```
Alternative way to use the things below:
```kotlin
val filter = bot.startGettingUpdates(
scope = CoroutineScope(Dispatchers.Default)
) {
// place code from examples here with replacing of `filter` by `this`
}
```
### Getting of only text incoming messages
```kotlin
filter.asContentMessagesFlow().onlyTextContentMessages().onEach {
println(it.content)
println(it.fullEntitiesList())
}.launchIn(
CoroutineScope(Dispatchers.Default)
)
```
As a result, each received message which will be just text message will be printed out with full list of its internal entities

View File

@@ -0,0 +1,48 @@
buildscript {
repositories {
mavenLocal()
jcenter()
mavenCentral()
}
dependencies {
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
classpath "org.jetbrains.kotlin:kotlin-serialization:$kotlin_version"
classpath "com.jfrog.bintray.gradle:gradle-bintray-plugin:$gradle_bintray_plugin_version"
}
}
plugins {
id "org.jetbrains.kotlin.multiplatform" version "$kotlin_version"
id "org.jetbrains.kotlin.plugin.serialization" version "$kotlin_version"
}
project.version = "$library_version"
project.group = "$library_group"
apply from: "publish.gradle"
repositories {
mavenLocal()
jcenter()
mavenCentral()
maven { url "https://kotlin.bintray.com/kotlinx" }
}
kotlin {
jvm()
js()
sourceSets {
commonMain {
dependencies {
implementation kotlin('stdlib')
if ((project.hasProperty('RELEASE_MODE') && project.property('RELEASE_MODE') == "true") || System.getenv('RELEASE_MODE') == "true") {
api "${project.group}:TelegramBotAPI:$library_version"
} else {
implementation project(":TelegramBotAPI")
}
}
}
}
}

View File

@@ -0,0 +1,57 @@
apply plugin: 'maven-publish'
task javadocsJar(type: Jar) {
classifier = 'javadoc'
}
afterEvaluate {
project.publishing.publications.all {
// rename artifacts
groupId "${project.group}"
if (it.name.contains('kotlinMultiplatform')) {
artifactId = "${project.name}"
} else {
artifactId = "${project.name}-$name"
}
}
}
publishing {
publications.all {
artifact javadocsJar
pom.withXml {
asNode().children().last() + {
resolveStrategy = Closure.DELEGATE_FIRST
description "Util extensions for more useful work with updates and other things"
name "Telegram Bot API Utility Extensions"
url "https://insanusmokrassar.github.io/TelegramBotAPI"
scm {
developerConnection "scm:git:[fetch=]https://github.com/insanusmokrassar/TelegramBotAPI.git[push=]https://github.com/insanusmokrassar/TelegramBotAPI.git"
url "https://github.com/insanusmokrassar/TelegramBotAPI.git"
}
developers {
developer {
id "InsanusMokrassar"
name "Ovsiannikov Aleksei"
email "ovsyannikov.alexey95@gmail.com"
}
}
licenses {
license {
name "Apache Software License 2.0"
url "https://github.com/InsanusMokrassar/TelegramBotAPI/blob/master/LICENSE"
}
}
}
}
}
}

View File

@@ -0,0 +1 @@
{"bintrayConfig":{"repo":"StandardRepository","packageName":"${project.name}","packageVcs":"https://github.com/InsanusMokrassar/TelegramBotAPI"},"licenses":[{"id":"Apache-2.0","title":"Apache Software License 2.0","url":"https://github.com/InsanusMokrassar/TelegramBotAPI/blob/master/LICENSE"}],"mavenConfig":{"name":"Telegram Bot API Utility Extensions","description":"Util extensions for more useful work with updates and other things","url":"https://insanusmokrassar.github.io/TelegramBotAPI","vcsUrl":"https://github.com/insanusmokrassar/TelegramBotAPI.git","developers":[{"id":"InsanusMokrassar","name":"Ovsiannikov Aleksei","eMail":"ovsyannikov.alexey95@gmail.com"}]},"type":"Multiplatform"}

View File

@@ -0,0 +1,55 @@
apply plugin: 'com.jfrog.bintray'
apply from: "maven.publish.gradle"
bintray {
user = project.hasProperty('BINTRAY_USER') ? project.property('BINTRAY_USER') : System.getenv('BINTRAY_USER')
key = project.hasProperty('BINTRAY_KEY') ? project.property('BINTRAY_KEY') : System.getenv('BINTRAY_KEY')
filesSpec {
from "${buildDir}/publications/"
eachFile {
String directorySubname = it.getFile().parentFile.name
if (it.getName() == "module.json") {
if (directorySubname == "kotlinMultiplatform") {
it.setPath("${project.name}/${project.version}/${project.name}-${project.version}.module")
} else {
it.setPath("${project.name}-${directorySubname}/${project.version}/${project.name}-${directorySubname}-${project.version}.module")
}
} else {
if (directorySubname == "kotlinMultiplatform" && it.getName() == "pom-default.xml") {
it.setPath("${project.name}/${project.version}/${project.name}-${project.version}.pom")
} else {
it.exclude()
}
}
}
into "${project.group}".replace(".", "/")
}
pkg {
repo = "StandardRepository"
name = "${project.name}"
vcsUrl = "https://github.com/InsanusMokrassar/TelegramBotAPI"
licenses = ["Apache-2.0"]
version {
name = "${project.version}"
released = new Date()
vcsTag = "${project.version}"
gpg {
sign = true
passphrase = project.hasProperty('signing.gnupg.passphrase') ? project.property('signing.gnupg.passphrase') : System.getenv('signing.gnupg.passphrase')
}
}
}
}
bintrayUpload.doFirst {
publications = publishing.publications.collect {
if (it.name.contains('kotlinMultiplatform')) {
null
} else {
it.name
}
} - null
}
bintrayUpload.dependsOn publishToMavenLocal

View File

@@ -0,0 +1,12 @@
package com.github.insanusmokrassar.TelegramBotAPI.extensions.utils
import com.github.insanusmokrassar.TelegramBotAPI.types.CallbackQuery.*
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.mapNotNull
fun <T : CallbackQuery> Flow<T>.onlyMessageDataCallbackQueries() = mapNotNull {
it as? MessageDataCallbackQuery
}
fun <T : CallbackQuery> Flow<T>.onlyInlineMessageIdDataCallbackQueries() = mapNotNull {
it as? InlineMessageIdDataCallbackQuery
}

View File

@@ -0,0 +1,36 @@
package com.github.insanusmokrassar.TelegramBotAPI.extensions.utils
import com.github.insanusmokrassar.TelegramBotAPI.types.message.abstracts.ContentMessage
import com.github.insanusmokrassar.TelegramBotAPI.types.message.content.*
import com.github.insanusmokrassar.TelegramBotAPI.types.message.content.abstracts.MessageContent
import com.github.insanusmokrassar.TelegramBotAPI.types.message.content.media.*
import com.github.insanusmokrassar.TelegramBotAPI.types.message.payments.InvoiceContent
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.mapNotNull
import kotlin.reflect.KClass
fun <T : MessageContent> Flow<ContentMessage<*>>.withContentType(contentType: KClass<T>) = mapNotNull {
if (contentType.isInstance(it.content)) {
@Suppress("UNCHECKED_CAST")
it as ContentMessage<T>
} else {
null
}
}
fun Flow<ContentMessage<*>>.onlyAnimationContentMessages() = withContentType(AnimationContent::class)
fun Flow<ContentMessage<*>>.onlyAudioContentMessages() = withContentType(AudioContent::class)
fun Flow<ContentMessage<*>>.onlyContactContentMessages() = withContentType(ContactContent::class)
fun Flow<ContentMessage<*>>.onlyDiceContentMessages() = withContentType(DiceContent::class)
fun Flow<ContentMessage<*>>.onlyDocumentContentMessages() = withContentType(DocumentContent::class)
fun Flow<ContentMessage<*>>.onlyGameContentMessages() = withContentType(GameContent::class)
fun Flow<ContentMessage<*>>.onlyInvoiceContentMessages() = withContentType(InvoiceContent::class)
fun Flow<ContentMessage<*>>.onlyLocationContentMessages() = withContentType(LocationContent::class)
fun Flow<ContentMessage<*>>.onlyPhotoContentMessages() = withContentType(PhotoContent::class)
fun Flow<ContentMessage<*>>.onlyPollContentMessages() = withContentType(PollContent::class)
fun Flow<ContentMessage<*>>.onlyStickerContentMessages() = withContentType(StickerContent::class)
fun Flow<ContentMessage<*>>.onlyTextContentMessages() = withContentType(TextContent::class)
fun Flow<ContentMessage<*>>.onlyVenueContentMessages() = withContentType(VenueContent::class)
fun Flow<ContentMessage<*>>.onlyVideoContentMessages() = withContentType(VideoContent::class)
fun Flow<ContentMessage<*>>.onlyVideoNoteContentMessages() = withContentType(VideoNoteContent::class)
fun Flow<ContentMessage<*>>.onlyVoiceContentMessages() = withContentType(VoiceContent::class)

View File

@@ -0,0 +1,16 @@
package com.github.insanusmokrassar.TelegramBotAPI.extensions.utils.updates
import com.github.insanusmokrassar.TelegramBotAPI.types.CallbackQuery.*
import com.github.insanusmokrassar.TelegramBotAPI.types.update.CallbackQueryUpdate
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.mapNotNull
fun Flow<CallbackQueryUpdate>.asDataCallbackQueryFlow() = mapNotNull {
it.data as? DataCallbackQuery
}
fun Flow<CallbackQueryUpdate>.asGameShortNameCallbackQueryFlow() = mapNotNull {
it.data as? GameShortNameCallbackQuery
}
fun Flow<CallbackQueryUpdate>.asUnknownCallbackQueryFlow() = mapNotNull {
it.data as? UnknownCallbackQueryType
}

View File

@@ -0,0 +1,53 @@
package com.github.insanusmokrassar.TelegramBotAPI.extensions.utils.updates
import com.github.insanusmokrassar.TelegramBotAPI.CommonAbstracts.TextSource
import com.github.insanusmokrassar.TelegramBotAPI.extensions.utils.onlyTextContentMessages
import com.github.insanusmokrassar.TelegramBotAPI.types.MessageEntity.textsources.BotCommandTextSource
import com.github.insanusmokrassar.TelegramBotAPI.types.MessageEntity.textsources.RegularTextSource
import com.github.insanusmokrassar.TelegramBotAPI.types.message.content.fullEntitiesList
import com.github.insanusmokrassar.TelegramBotAPI.types.update.abstracts.BaseSentMessageUpdate
import kotlinx.coroutines.flow.*
fun <T : BaseSentMessageUpdate> Flow<T>.filterExactCommands(
commandRegex: Regex
) = asContentMessagesFlow().onlyTextContentMessages().filter { contentMessage ->
(contentMessage.content.fullEntitiesList().singleOrNull() as? BotCommandTextSource) ?.let { commandRegex.matches(it.command) } == true
}
fun <T : BaseSentMessageUpdate> Flow<T>.filterCommandsInsideTextMessages(
commandRegex: Regex
) = asContentMessagesFlow().onlyTextContentMessages().filter { contentMessage ->
contentMessage.content.fullEntitiesList().any {
(it as? BotCommandTextSource) ?.let { commandRegex.matches(it.command) } == true
}
}
/**
* @return Result [Flow] will emit all [TextSource]s to the collector ONLY IN CASE if first [TextSource] is
* [BotCommandTextSource] and its [BotCommandTextSource.command] is [Regex.matches] to incoming [commandRegex]. Internal
* behaviour contains next rules: all incoming text sources will be passed as is, [RegularTextSource] will be divided
* by " " for several [RegularTextSource] which will contains not empty args without spaces
*/
fun <T : BaseSentMessageUpdate> Flow<T>.filterCommandsWithArgs(
commandRegex: Regex
): Flow<List<TextSource>> = asContentMessagesFlow().onlyTextContentMessages().mapNotNull { contentMessage ->
val allEntities = contentMessage.content.fullEntitiesList()
(allEntities.firstOrNull() as? BotCommandTextSource) ?.let {
if (commandRegex.matches(it.command)) {
allEntities.flatMap {
when (it) {
is RegularTextSource -> it.source.split(" ").mapNotNull { regularTextSourcePart ->
if (regularTextSourcePart.isNotBlank()) {
RegularTextSource(regularTextSourcePart)
} else {
null
}
}
else -> listOf(it)
}
}
} else {
null
}
}
}

View File

@@ -0,0 +1,18 @@
package com.github.insanusmokrassar.TelegramBotAPI.extensions.utils.updates
import com.github.insanusmokrassar.TelegramBotAPI.types.message.abstracts.*
import com.github.insanusmokrassar.TelegramBotAPI.types.update.abstracts.BaseSentMessageUpdate
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.mapNotNull
fun <T : BaseSentMessageUpdate> Flow<T>.asContentMessagesFlow() = mapNotNull {
it.data as? ContentMessage<*>
}
fun <T : BaseSentMessageUpdate> Flow<T>.asChatEventsFlow() = mapNotNull {
it.data as? ChatEventMessage
}
fun <T : BaseSentMessageUpdate> Flow<T>.asUnknownMessagesFlow() = mapNotNull {
it.data as? UnknownMessageType
}

View File

@@ -0,0 +1,19 @@
package com.github.insanusmokrassar.TelegramBotAPI.extensions.utils.updates
import com.github.insanusmokrassar.TelegramBotAPI.types.ChatId
import com.github.insanusmokrassar.TelegramBotAPI.types.chat.abstracts.Chat
import com.github.insanusmokrassar.TelegramBotAPI.types.update.MediaGroupUpdates.*
import com.github.insanusmokrassar.TelegramBotAPI.types.update.abstracts.BaseMessageUpdate
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.filter
fun <T : BaseMessageUpdate> Flow<T>.filterBaseMessageUpdates(chatId: ChatId): Flow<T> = filter {
it.data.chat.id == chatId
}
fun <T : BaseMessageUpdate> Flow<T>.filterBaseMessageUpdates(chat: Chat): Flow<T> = filterBaseMessageUpdates(chat.id)
fun <T : SentMediaGroupUpdate> Flow<T>.filterSentMediaGroupUpdates(chatId: ChatId): Flow<T> = filter {
it.data.first().chat.id == chatId
}
fun <T : SentMediaGroupUpdate> Flow<T>.filterSentMediaGroupUpdates(chat: Chat): Flow<T> = filterSentMediaGroupUpdates(chat.id)

View File

@@ -1,9 +1,7 @@
# TelegramBotAPI # TelegramBotAPI
[![Awesome Kotlin Badge](https://kotlin.link/awesome-kotlin.svg)](https://github.com/KotlinBy/awesome-kotlin)
[![Download](https://api.bintray.com/packages/insanusmokrassar/StandardRepository/TelegramBotAPI/images/download.svg) ](https://bintray.com/insanusmokrassar/StandardRepository/TelegramBotAPI/_latestVersion) [![Download](https://api.bintray.com/packages/insanusmokrassar/StandardRepository/TelegramBotAPI/images/download.svg) ](https://bintray.com/insanusmokrassar/StandardRepository/TelegramBotAPI/_latestVersion)
[![Maven Central](https://maven-badges.herokuapp.com/maven-central/com.github.insanusmokrassar/TelegramBotAPI/badge.svg)](https://maven-badges.herokuapp.com/maven-central/com.github.insanusmokrassar/TelegramBotAPI) [![Maven Central](https://maven-badges.herokuapp.com/maven-central/com.github.insanusmokrassar/TelegramBotAPI/badge.svg)](https://maven-badges.herokuapp.com/maven-central/com.github.insanusmokrassar/TelegramBotAPI)
[![Build Status](https://jenkins.insanusmokrassar.com/buildStatus/icon?job=TelegramBotAPI_master__publishing)](https://jenkins.insanusmokrassar.com/job/TelegramBotAPI_master__publishing/)
## What is it? ## What is it?
@@ -12,11 +10,10 @@ moments are describing by official [Telegram Bot API](https://core.telegram.org/
## Compatibility ## Compatibility
This version compatible with [23th of January 2020 update of TelegramBotAPI (version 4.6)](https://core.telegram.org/bots/api#january-23-2020). This version compatible with [30th of March 2020 update of TelegramBotAPI (version 4.7)](https://core.telegram.org/bots/api#march-30-2020).
There is Telegram Passport API exception of implemented functionality, which was presented in There is only one exception of implemented functionality - Telegram Passport API, which was presented in
[August 2018 update of TelegramBotAPI](https://core.telegram.org/bots/api-changelog#august-27-2018) update. It will be implemented [August 2018 update of TelegramBotAPI](https://core.telegram.org/bots/api-changelog#august-27-2018) update. It will be implemented
as soon as possible. All APIs that are not included are presented as soon as possible.
[wiki](https://github.com/InsanusMokrassar/TelegramBotAPI/wiki/Not-included-API).
## How to implement library? ## How to implement library?

View File

@@ -4,6 +4,7 @@ interface TextSource {
val asMarkdownSource: String val asMarkdownSource: String
val asMarkdownV2Source: String val asMarkdownV2Source: String
val asHtmlSource: String val asHtmlSource: String
val source: String
} }

View File

@@ -9,7 +9,7 @@ import com.github.insanusmokrassar.TelegramBotAPI.bot.settings.limiters.RequestL
import com.github.insanusmokrassar.TelegramBotAPI.requests.abstracts.Request import com.github.insanusmokrassar.TelegramBotAPI.requests.abstracts.Request
import com.github.insanusmokrassar.TelegramBotAPI.types.Response import com.github.insanusmokrassar.TelegramBotAPI.types.Response
import com.github.insanusmokrassar.TelegramBotAPI.types.RetryAfterError import com.github.insanusmokrassar.TelegramBotAPI.types.RetryAfterError
import com.github.insanusmokrassar.TelegramBotAPI.utils.TelegramAPIUrlsKeeper import com.github.insanusmokrassar.TelegramBotAPI.utils.*
import com.github.insanusmokrassar.TelegramBotAPI.utils.nonstrictJsonFormat import com.github.insanusmokrassar.TelegramBotAPI.utils.nonstrictJsonFormat
import io.ktor.client.HttpClient import io.ktor.client.HttpClient
import io.ktor.client.call.receive import io.ktor.client.call.receive
@@ -17,7 +17,6 @@ import io.ktor.client.features.*
import io.ktor.client.statement.HttpStatement import io.ktor.client.statement.HttpStatement
import io.ktor.client.statement.readText import io.ktor.client.statement.readText
import kotlinx.coroutines.delay import kotlinx.coroutines.delay
import kotlinx.coroutines.supervisorScope
import kotlinx.serialization.json.Json import kotlinx.serialization.json.Json
class KtorRequestsExecutor( class KtorRequestsExecutor(
@@ -43,54 +42,56 @@ class KtorRequestsExecutor(
} }
override suspend fun <T : Any> execute(request: Request<T>): T { override suspend fun <T : Any> execute(request: Request<T>): T {
return try { return handleSafely(
supervisorScope { { e ->
requestsLimiter.limit { throw if (e is ClientRequestException) {
var statement: HttpStatement? = null val content = e.response.readText()
for (factory in callsFactories) {
statement = factory.prepareCall(
client,
telegramAPIUrlsKeeper.commonAPIUrl,
request
)
if (statement != null) {
break
}
}
val response = statement?.execute() ?: throw IllegalArgumentException("Can't execute request: $request")
val content = response.receive<String>()
val responseObject = jsonFormatter.parse(Response.serializer(), content) val responseObject = jsonFormatter.parse(Response.serializer(), content)
newRequestException(
(responseObject.result?.let { responseObject,
jsonFormatter.fromJson(request.resultDeserializer, it) content,
} ?: responseObject.parameters?.let { "Can't get result object from $content"
val error = it.error )
if (error is RetryAfterError) { } else {
delay(error.leftToRetry) e
execute(request)
} else {
null
}
} ?: response.let {
throw newRequestException(
responseObject,
content,
"Can't get result object from $content"
)
})
} }
} }
} catch (e: ClientRequestException) { ) {
val content = e.response.readText() requestsLimiter.limit {
val responseObject = jsonFormatter.parse(Response.serializer(), content) var statement: HttpStatement? = null
throw newRequestException( for (factory in callsFactories) {
responseObject, statement = factory.prepareCall(
content, client,
"Can't get result object from $content" telegramAPIUrlsKeeper.commonAPIUrl,
) request
} catch (e: Exception) { )
throw e if (statement != null) {
break
}
}
val response = statement?.execute() ?: throw IllegalArgumentException("Can't execute request: $request")
val content = response.receive<String>()
val responseObject = jsonFormatter.parse(Response.serializer(), content)
(responseObject.result?.let {
jsonFormatter.fromJson(request.resultDeserializer, it)
} ?: responseObject.parameters?.let {
val error = it.error
if (error is RetryAfterError) {
delay(error.leftToRetry)
execute(request)
} else {
null
}
} ?: response.let {
throw newRequestException(
responseObject,
content,
"Can't get result object from $content"
)
})
}
} }
} }

View File

@@ -14,6 +14,7 @@ fun newRequestException(
description == "Bad Request: message to edit not found" -> MessageToEditNotFoundException(response, plainAnswer, message, cause) description == "Bad Request: message to edit not found" -> MessageToEditNotFoundException(response, plainAnswer, message, cause)
description.contains("Bad Request: message is not modified") -> MessageIsNotModifiedException(response, plainAnswer, message, cause) description.contains("Bad Request: message is not modified") -> MessageIsNotModifiedException(response, plainAnswer, message, cause)
description == "Unauthorized" -> UnauthorizedException(response, plainAnswer, message, cause) description == "Unauthorized" -> UnauthorizedException(response, plainAnswer, message, cause)
description.contains("PHOTO_INVALID_DIMENSIONS") -> InvalidPhotoDimensionsException(response, plainAnswer, message, cause)
else -> null else -> null
} }
} ?: CommonRequestException(response, plainAnswer, message, cause) } ?: CommonRequestException(response, plainAnswer, message, cause)
@@ -41,3 +42,6 @@ class MessageIsNotModifiedException(response: Response, plainAnswer: String, mes
class MessageToEditNotFoundException(response: Response, plainAnswer: String, message: String?, cause: Throwable?) : class MessageToEditNotFoundException(response: Response, plainAnswer: String, message: String?, cause: Throwable?) :
RequestException(response, plainAnswer, message, cause) RequestException(response, plainAnswer, message, cause)
class InvalidPhotoDimensionsException(response: Response, plainAnswer: String, message: String?, cause: Throwable?) :
RequestException(response, plainAnswer, message, cause)

View File

@@ -1,14 +1,11 @@
package com.github.insanusmokrassar.TelegramBotAPI.requests package com.github.insanusmokrassar.TelegramBotAPI.requests
import com.github.insanusmokrassar.TelegramBotAPI.requests.abstracts.SimpleRequest import com.github.insanusmokrassar.TelegramBotAPI.requests.bot.GetMe
import com.github.insanusmokrassar.TelegramBotAPI.types.ExtendedBot
import kotlinx.serialization.*
@Serializable @Deprecated(
class GetMe : SimpleRequest<ExtendedBot> { "Replaced",
override fun method(): String = "getMe" ReplaceWith(
override val resultDeserializer: DeserializationStrategy<ExtendedBot> "GetMe", "com.github.insanusmokrassar.TelegramBotAPI.requests.bot.GetMe"
get() = ExtendedBot.serializer() )
override val requestSerializer: SerializationStrategy<*> )
get() = serializer() typealias GetMe = GetMe
}

View File

@@ -3,18 +3,18 @@ package com.github.insanusmokrassar.TelegramBotAPI.requests
import com.github.insanusmokrassar.TelegramBotAPI.requests.abstracts.SimpleRequest import com.github.insanusmokrassar.TelegramBotAPI.requests.abstracts.SimpleRequest
import com.github.insanusmokrassar.TelegramBotAPI.types.* import com.github.insanusmokrassar.TelegramBotAPI.types.*
import com.github.insanusmokrassar.TelegramBotAPI.types.update.abstracts.Update import com.github.insanusmokrassar.TelegramBotAPI.types.update.abstracts.Update
import com.github.insanusmokrassar.TelegramBotAPI.types.update.abstracts.UpdateSerializerWithoutDeserialization import com.github.insanusmokrassar.TelegramBotAPI.types.update.abstracts.UpdateSerializerWithoutSerialization
import kotlinx.serialization.* import kotlinx.serialization.*
import kotlinx.serialization.builtins.ListSerializer import kotlinx.serialization.builtins.ListSerializer
private val updatesListSerializer = ListSerializer( private val updatesListSerializer = ListSerializer(
UpdateSerializerWithoutDeserialization UpdateSerializerWithoutSerialization
) )
@Serializable @Serializable
data class GetUpdates( data class GetUpdates(
val offset: UpdateIdentifier? = null,// set `last update id + 1` to receive next part of updates val offset: UpdateIdentifier? = null,// set `last update id + 1` to receive next part of updates
val limit: Int? = null, val limit: Int = getUpdatesLimit.last,
val timeout: Seconds? = null, val timeout: Seconds? = null,
val allowed_updates: List<String>? = ALL_UPDATES_LIST val allowed_updates: List<String>? = ALL_UPDATES_LIST
): SimpleRequest<List<Update>> { ): SimpleRequest<List<Update>> {
@@ -25,4 +25,10 @@ data class GetUpdates(
override val requestSerializer: SerializationStrategy<*> override val requestSerializer: SerializationStrategy<*>
get() = serializer() get() = serializer()
init {
if (limit !in getUpdatesLimit) {
error("GetUpdates request can be called only with limit in range $getUpdatesLimit (actual value is $limit)")
}
}
} }

View File

@@ -33,8 +33,8 @@ internal object InputFileSerializer : KSerializer<InputFile> {
@Serializable(InputFileSerializer::class) @Serializable(InputFileSerializer::class)
data class MultipartFile ( data class MultipartFile (
val file: StorageFile, val file: StorageFile,
val mimeType: String = file.contentType, val mimeType: String = file.storageFileInfo.contentType,
val filename: String = file.fileName val filename: String = file.storageFileInfo.fileName
) : InputFile() { ) : InputFile() {
override val fileId: String = file.generateCustomName() override val fileId: String = file.storageFileInfo.generateCustomName()
} }

View File

@@ -0,0 +1,14 @@
package com.github.insanusmokrassar.TelegramBotAPI.requests.bot
import com.github.insanusmokrassar.TelegramBotAPI.requests.abstracts.SimpleRequest
import com.github.insanusmokrassar.TelegramBotAPI.types.ExtendedBot
import kotlinx.serialization.*
@Serializable
object GetMe : SimpleRequest<ExtendedBot> {
override fun method(): String = "getMe"
override val resultDeserializer: DeserializationStrategy<ExtendedBot>
get() = ExtendedBot.serializer()
override val requestSerializer: SerializationStrategy<*>
get() = serializer()
}

View File

@@ -0,0 +1,17 @@
package com.github.insanusmokrassar.TelegramBotAPI.requests.bot
import com.github.insanusmokrassar.TelegramBotAPI.requests.abstracts.SimpleRequest
import com.github.insanusmokrassar.TelegramBotAPI.types.BotCommand
import kotlinx.serialization.*
import kotlinx.serialization.builtins.ListSerializer
private val getMyCommandsSerializer = ListSerializer(BotCommand.serializer())
@Serializable
object GetMyCommands : SimpleRequest<List<BotCommand>> {
override fun method(): String = "getMyCommands"
override val resultDeserializer: DeserializationStrategy<List<BotCommand>>
get() = getMyCommandsSerializer
override val requestSerializer: SerializationStrategy<*>
get() = serializer()
}

View File

@@ -0,0 +1,24 @@
package com.github.insanusmokrassar.TelegramBotAPI.requests.bot
import com.github.insanusmokrassar.TelegramBotAPI.requests.abstracts.SimpleRequest
import com.github.insanusmokrassar.TelegramBotAPI.types.*
import kotlinx.serialization.*
import kotlinx.serialization.builtins.serializer
@Serializable
class SetMyCommands(
@SerialName(botCommandsField)
val commands: List<BotCommand>
) : SimpleRequest<Boolean> {
override fun method(): String = "setMyCommands"
override val resultDeserializer: DeserializationStrategy<Boolean>
get() = Boolean.serializer()
override val requestSerializer: SerializationStrategy<*>
get() = serializer()
init {
if (commands.size !in botCommandsLimit) {
error("Bot commands list size able to be in range $botCommandsLimit, but incoming size is ${commands.size}")
}
}
}

View File

@@ -0,0 +1,34 @@
package com.github.insanusmokrassar.TelegramBotAPI.requests.send
import com.github.insanusmokrassar.TelegramBotAPI.CommonAbstracts.types.DisableNotification
import com.github.insanusmokrassar.TelegramBotAPI.CommonAbstracts.types.ReplyMessageId
import com.github.insanusmokrassar.TelegramBotAPI.requests.send.abstracts.ReplyingMarkupSendMessageRequest
import com.github.insanusmokrassar.TelegramBotAPI.types.*
import com.github.insanusmokrassar.TelegramBotAPI.types.buttons.KeyboardMarkup
import com.github.insanusmokrassar.TelegramBotAPI.types.message.abstracts.ContentMessage
import com.github.insanusmokrassar.TelegramBotAPI.types.message.abstracts.TelegramBotAPIMessageDeserializationStrategyClass
import com.github.insanusmokrassar.TelegramBotAPI.types.message.content.DiceContent
import kotlinx.serialization.*
internal val DiceContentMessageResultDeserializer: DeserializationStrategy<ContentMessage<DiceContent>>
= TelegramBotAPIMessageDeserializationStrategyClass()
@Serializable
data class SendDice(
@SerialName(chatIdField)
override val chatId: ChatIdentifier,
@SerialName(disableNotificationField)
override val disableNotification: Boolean = false,
@SerialName(replyToMessageIdField)
override val replyToMessageId: MessageIdentifier? = null,
@SerialName(replyMarkupField)
override val replyMarkup: KeyboardMarkup? = null
) : ReplyingMarkupSendMessageRequest<ContentMessage<DiceContent>>, ReplyMessageId, DisableNotification {
override val requestSerializer: SerializationStrategy<*>
get() = serializer()
override fun method(): String = "sendDice"
override val resultDeserializer: DeserializationStrategy<ContentMessage<DiceContent>>
get() = DiceContentMessageResultDeserializer
}

View File

@@ -2,19 +2,19 @@ package com.github.insanusmokrassar.TelegramBotAPI.requests.stickers
import com.github.insanusmokrassar.TelegramBotAPI.requests.abstracts.* import com.github.insanusmokrassar.TelegramBotAPI.requests.abstracts.*
import com.github.insanusmokrassar.TelegramBotAPI.requests.common.CommonMultipartFileRequest import com.github.insanusmokrassar.TelegramBotAPI.requests.common.CommonMultipartFileRequest
import com.github.insanusmokrassar.TelegramBotAPI.requests.stickers.abstracts.StickerSetAction import com.github.insanusmokrassar.TelegramBotAPI.requests.stickers.abstracts.StandardStickerSetAction
import com.github.insanusmokrassar.TelegramBotAPI.types.* import com.github.insanusmokrassar.TelegramBotAPI.types.*
import com.github.insanusmokrassar.TelegramBotAPI.types.stickers.MaskPosition import com.github.insanusmokrassar.TelegramBotAPI.types.stickers.MaskPosition
import kotlinx.serialization.* import kotlinx.serialization.*
fun AddStickerToSet( fun AddAnimatedStickerToSet(
userId: UserId, userId: UserId,
stickerSetName: String, stickerSetName: String,
sticker: InputFile, sticker: InputFile,
emojis: String, emojis: String,
maskPosition: MaskPosition? = null maskPosition: MaskPosition? = null
): Request<Boolean> { ): Request<Boolean> {
val data = AddStickerToSet(userId, stickerSetName, emojis, sticker as? FileId, maskPosition) val data = AddAnimatedStickerToSet(userId, stickerSetName, emojis, sticker as? FileId, maskPosition)
return when (sticker) { return when (sticker) {
is MultipartFile -> CommonMultipartFileRequest( is MultipartFile -> CommonMultipartFileRequest(
data, data,
@@ -25,18 +25,18 @@ fun AddStickerToSet(
} }
@Serializable @Serializable
data class AddStickerToSet internal constructor( data class AddAnimatedStickerToSet internal constructor(
@SerialName(userIdField) @SerialName(userIdField)
override val userId: UserId, override val userId: UserId,
@SerialName(nameField) @SerialName(nameField)
override val name: String, override val name: String,
@SerialName(emojisField) @SerialName(emojisField)
override val emojis: String, override val emojis: String,
@SerialName(pngStickerField) @SerialName(tgsStickerField)
val sticker: FileId? = null, val sticker: FileId? = null,
@SerialName(maskPositionField) @SerialName(maskPositionField)
override val maskPosition: MaskPosition? = null override val maskPosition: MaskPosition? = null
) : StickerSetAction { ) : StandardStickerSetAction {
init { init {
if(emojis.isEmpty()) { if(emojis.isEmpty()) {
throw IllegalArgumentException("Emojis must not be empty") throw IllegalArgumentException("Emojis must not be empty")

View File

@@ -0,0 +1,68 @@
package com.github.insanusmokrassar.TelegramBotAPI.requests.stickers
import com.github.insanusmokrassar.TelegramBotAPI.requests.abstracts.*
import com.github.insanusmokrassar.TelegramBotAPI.requests.common.CommonMultipartFileRequest
import com.github.insanusmokrassar.TelegramBotAPI.requests.stickers.abstracts.StandardStickerSetAction
import com.github.insanusmokrassar.TelegramBotAPI.types.*
import com.github.insanusmokrassar.TelegramBotAPI.types.stickers.MaskPosition
import kotlinx.serialization.*
fun AddStaticStickerToSet(
userId: UserId,
stickerSetName: String,
sticker: InputFile,
emojis: String,
maskPosition: MaskPosition? = null
): Request<Boolean> {
val data = AddStaticStickerToSet(userId, stickerSetName, emojis, sticker as? FileId, maskPosition)
return when (sticker) {
is MultipartFile -> CommonMultipartFileRequest(
data,
mapOf(pngStickerField to sticker)
)
is FileId -> data
}
}
@Deprecated(
"Renamed",
ReplaceWith("AddStaticStickerToSet", "com.github.insanusmokrassar.TelegramBotAPI.requests.stickers.AddStaticStickerToSet")
)
fun AddStickerToSet(
userId: UserId,
stickerSetName: String,
sticker: InputFile,
emojis: String,
maskPosition: MaskPosition? = null
) = AddStaticStickerToSet(userId, stickerSetName, sticker, emojis, maskPosition)
@Deprecated(
"Renamed",
ReplaceWith("AddStaticStickerToSet", "com.github.insanusmokrassar.TelegramBotAPI.requests.stickers.AddStaticStickerToSet")
)
typealias AddStickerToSet = AddStaticStickerToSet
@Serializable
data class AddStaticStickerToSet internal constructor(
@SerialName(userIdField)
override val userId: UserId,
@SerialName(nameField)
override val name: String,
@SerialName(emojisField)
override val emojis: String,
@SerialName(pngStickerField)
val sticker: FileId? = null,
@SerialName(maskPositionField)
override val maskPosition: MaskPosition? = null
) : StandardStickerSetAction {
init {
if(emojis.isEmpty()) {
throw IllegalArgumentException("Emojis must not be empty")
}
}
override val requestSerializer: SerializationStrategy<*>
get() = serializer()
override fun method(): String = "addStickerToSet"
}

View File

@@ -2,12 +2,12 @@ package com.github.insanusmokrassar.TelegramBotAPI.requests.stickers
import com.github.insanusmokrassar.TelegramBotAPI.requests.abstracts.* import com.github.insanusmokrassar.TelegramBotAPI.requests.abstracts.*
import com.github.insanusmokrassar.TelegramBotAPI.requests.common.CommonMultipartFileRequest import com.github.insanusmokrassar.TelegramBotAPI.requests.common.CommonMultipartFileRequest
import com.github.insanusmokrassar.TelegramBotAPI.requests.stickers.abstracts.StickerSetAction import com.github.insanusmokrassar.TelegramBotAPI.requests.stickers.abstracts.StandardStickerSetAction
import com.github.insanusmokrassar.TelegramBotAPI.types.* import com.github.insanusmokrassar.TelegramBotAPI.types.*
import com.github.insanusmokrassar.TelegramBotAPI.types.stickers.MaskPosition import com.github.insanusmokrassar.TelegramBotAPI.types.stickers.MaskPosition
import kotlinx.serialization.* import kotlinx.serialization.*
fun CreateNewStickerSet( fun CreateNewAnimatedStickerSet(
userId: UserId, userId: UserId,
name: String, name: String,
sticker: InputFile, sticker: InputFile,
@@ -15,7 +15,7 @@ fun CreateNewStickerSet(
containsMasks: Boolean? = null, containsMasks: Boolean? = null,
maskPosition: MaskPosition? = null maskPosition: MaskPosition? = null
): Request<Boolean> { ): Request<Boolean> {
val data = CreateNewStickerSet(userId, name, emojis, sticker as? FileId, containsMasks, maskPosition) val data = CreateNewAnimatedStickerSet(userId, name, emojis, sticker as? FileId, containsMasks, maskPosition)
return when (sticker) { return when (sticker) {
is MultipartFile -> CommonMultipartFileRequest( is MultipartFile -> CommonMultipartFileRequest(
data, data,
@@ -26,20 +26,20 @@ fun CreateNewStickerSet(
} }
@Serializable @Serializable
data class CreateNewStickerSet internal constructor( data class CreateNewAnimatedStickerSet internal constructor(
@SerialName(userIdField) @SerialName(userIdField)
override val userId: UserId, override val userId: UserId,
@SerialName(nameField) @SerialName(nameField)
override val name: String, override val name: String,
@SerialName(emojisField) @SerialName(emojisField)
override val emojis: String, override val emojis: String,
@SerialName(pngStickerField) @SerialName(tgsStickerField)
val sticker: FileId? = null, val sticker: FileId? = null,
@SerialName(containsMasksField) @SerialName(containsMasksField)
val containsMasks: Boolean? = null, val containsMasks: Boolean? = null,
@SerialName(maskPositionField) @SerialName(maskPositionField)
override val maskPosition: MaskPosition? = null override val maskPosition: MaskPosition? = null
) : StickerSetAction { ) : StandardStickerSetAction {
init { init {
if(emojis.isEmpty()) { if(emojis.isEmpty()) {
throw IllegalArgumentException("Emojis must not be empty") throw IllegalArgumentException("Emojis must not be empty")

View File

@@ -0,0 +1,68 @@
package com.github.insanusmokrassar.TelegramBotAPI.requests.stickers
import com.github.insanusmokrassar.TelegramBotAPI.requests.abstracts.*
import com.github.insanusmokrassar.TelegramBotAPI.requests.common.CommonMultipartFileRequest
import com.github.insanusmokrassar.TelegramBotAPI.requests.stickers.abstracts.StandardStickerSetAction
import com.github.insanusmokrassar.TelegramBotAPI.types.*
import com.github.insanusmokrassar.TelegramBotAPI.types.stickers.MaskPosition
import kotlinx.serialization.*
fun CreateNewStaticStickerSet(
userId: UserId,
name: String,
sticker: InputFile,
emojis: String,
containsMasks: Boolean? = null,
maskPosition: MaskPosition? = null
): Request<Boolean> {
val data = CreateNewStaticStickerSet(userId, name, emojis, sticker as? FileId, containsMasks, maskPosition)
return when (sticker) {
is MultipartFile -> CommonMultipartFileRequest(
data,
mapOf(pngStickerField to sticker)
)
is FileId -> data
}
}
fun CreateNewStickerSet(
userId: UserId,
name: String,
sticker: InputFile,
emojis: String,
containsMasks: Boolean? = null,
maskPosition: MaskPosition? = null
): Request<Boolean> = CreateNewStaticStickerSet(userId, name, sticker, emojis, containsMasks, maskPosition)
@Deprecated(
"Renamed",
ReplaceWith("CreateNewStaticStickerSet", "com.github.insanusmokrassar.TelegramBotAPI.requests.stickers.CreateNewStaticStickerSet")
)
typealias CreateNewStickerSet = CreateNewStaticStickerSet
@Serializable
data class CreateNewStaticStickerSet internal constructor(
@SerialName(userIdField)
override val userId: UserId,
@SerialName(nameField)
override val name: String,
@SerialName(emojisField)
override val emojis: String,
@SerialName(pngStickerField)
val sticker: FileId? = null,
@SerialName(containsMasksField)
val containsMasks: Boolean? = null,
@SerialName(maskPositionField)
override val maskPosition: MaskPosition? = null
) : StandardStickerSetAction {
init {
if(emojis.isEmpty()) {
throw IllegalArgumentException("Emojis must not be empty")
}
}
override val requestSerializer: SerializationStrategy<*>
get() = serializer()
override fun method(): String = "createNewStickerSet"
}

View File

@@ -0,0 +1,33 @@
package com.github.insanusmokrassar.TelegramBotAPI.requests.stickers
import com.github.insanusmokrassar.TelegramBotAPI.requests.abstracts.*
import com.github.insanusmokrassar.TelegramBotAPI.requests.common.CommonMultipartFileRequest
import com.github.insanusmokrassar.TelegramBotAPI.requests.stickers.abstracts.StickerSetAction
import com.github.insanusmokrassar.TelegramBotAPI.types.*
import kotlinx.serialization.*
fun SetStickerSetThumb(
userId: UserId,
stickerSetName: String,
thumb: MultipartFile
): Request<Boolean> {
return CommonMultipartFileRequest(
SetStickerSetThumb(userId, stickerSetName),
mapOf(thumbField to thumb)
)
}
@Serializable
data class SetStickerSetThumb (
@SerialName(userIdField)
override val userId: UserId,
@SerialName(nameField)
override val name: StickerSetName,
@SerialName(thumbField)
val thumb: FileId? = null
) : StickerSetAction {
override val requestSerializer: SerializationStrategy<*>
get() = serializer()
override fun method(): String = "setStickerSetThumb"
}

View File

@@ -0,0 +1,8 @@
package com.github.insanusmokrassar.TelegramBotAPI.requests.stickers.abstracts
import com.github.insanusmokrassar.TelegramBotAPI.types.stickers.MaskPosition
interface StandardStickerSetAction : StickerSetAction {
val emojis: String // must be more than one
val maskPosition: MaskPosition?
}

View File

@@ -2,15 +2,12 @@ package com.github.insanusmokrassar.TelegramBotAPI.requests.stickers.abstracts
import com.github.insanusmokrassar.TelegramBotAPI.requests.abstracts.SimpleRequest import com.github.insanusmokrassar.TelegramBotAPI.requests.abstracts.SimpleRequest
import com.github.insanusmokrassar.TelegramBotAPI.types.UserId import com.github.insanusmokrassar.TelegramBotAPI.types.UserId
import com.github.insanusmokrassar.TelegramBotAPI.types.stickers.MaskPosition
import kotlinx.serialization.KSerializer import kotlinx.serialization.KSerializer
import kotlinx.serialization.builtins.serializer import kotlinx.serialization.builtins.serializer
interface StickerSetAction : SimpleRequest<Boolean> { interface StickerSetAction : SimpleRequest<Boolean> {
val userId: UserId val userId: UserId
val name: String val name: String
val emojis: String // must be more than one
val maskPosition: MaskPosition?
override val resultDeserializer: KSerializer<Boolean> override val resultDeserializer: KSerializer<Boolean>
get() = Boolean.serializer() get() = Boolean.serializer()

View File

@@ -0,0 +1,21 @@
package com.github.insanusmokrassar.TelegramBotAPI.types
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
@Serializable
data class BotCommand(
@SerialName(botCommandField)
val command: String,
@SerialName(descriptionField)
val description: String
) {
init {
if (command.length !in botCommandLengthLimit) {
error("Command size must be in range $botCommandLengthLimit, but actually have length ${command.length}")
}
if (description.length !in botCommandDescriptionLimit) {
error("Command description size must be in range $botCommandDescriptionLimit, but actually have length ${description.length}")
}
}
}

View File

@@ -19,9 +19,11 @@ typealias InlineMessageIdentifier = String
typealias PollIdentifier = String typealias PollIdentifier = String
typealias StickerSetName = String typealias StickerSetName = String
typealias FileUniqueId = String typealias FileUniqueId = String
typealias DiceResult = Int
typealias Seconds = Int typealias Seconds = Int
val getUpdatesLimit = 1 .. 100
val callbackQueryAnswerLength = 0 until 200 val callbackQueryAnswerLength = 0 until 200
val captionLength = 0 until 1024 val captionLength = 0 until 1024
val textLength = 0 until 4096 val textLength = 0 until 4096
@@ -45,6 +47,13 @@ val inlineQueryAnswerResultsLimit = 0 .. 50
val customTitleLength = 0 .. 16 val customTitleLength = 0 .. 16
val diceResultLimit = 1 .. 6
val botCommandLengthLimit = 1 .. 32
val botCommandLimit = botCommandLengthLimit
val botCommandDescriptionLimit = 3 .. 256
val botCommandsLimit = 0 .. 100
const val chatIdField = "chat_id" const val chatIdField = "chat_id"
const val messageIdField = "message_id" const val messageIdField = "message_id"
const val updateIdField = "update_id" const val updateIdField = "update_id"
@@ -73,6 +82,7 @@ const val containsMasksField = "contains_masks"
const val resultIdField = "result_id" const val resultIdField = "result_id"
const val inlineMessageIdField = "inline_message_id" const val inlineMessageIdField = "inline_message_id"
const val callbackDataField = "callback_data" const val callbackDataField = "callback_data"
const val callbackGameField = "callback_game"
const val callbackQueryIdField = "callback_query_id" const val callbackQueryIdField = "callback_query_id"
const val inlineQueryIdField = "inline_query_id" const val inlineQueryIdField = "inline_query_id"
const val inlineKeyboardField = "inline_keyboard" const val inlineKeyboardField = "inline_keyboard"
@@ -164,6 +174,8 @@ const val thumbHeightField = "thumb_height"
const val inputMessageContentField = "input_message_content" const val inputMessageContentField = "input_message_content"
const val hideUrlField = "hide_url" const val hideUrlField = "hide_url"
const val botCommandField = "command"
const val botCommandsField = "commands"
const val isMemberField = "is_member" const val isMemberField = "is_member"
const val canSendMessagesField = "can_send_messages" const val canSendMessagesField = "can_send_messages"
@@ -183,6 +195,7 @@ const val canRestrictMembersField = "can_restrict_members"
const val canPinMessagesField = "can_pin_messages" const val canPinMessagesField = "can_pin_messages"
const val canPromoteMembersField = "can_promote_members" const val canPromoteMembersField = "can_promote_members"
const val pngStickerField = "png_sticker" const val pngStickerField = "png_sticker"
const val tgsStickerField = "tgs_sticker"
const val okField = "ok" const val okField = "ok"
const val captionField = "caption" const val captionField = "caption"
@@ -230,6 +243,7 @@ const val optionsField = "options"
const val payField = "pay" const val payField = "pay"
const val permissionsField = "permissions" const val permissionsField = "permissions"
const val typeField = "type" const val typeField = "type"
const val valueField = "value"
const val pointField = "point" const val pointField = "point"
const val xShiftField = "x_shift" const val xShiftField = "x_shift"

View File

@@ -0,0 +1,10 @@
package com.github.insanusmokrassar.TelegramBotAPI.types
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
@Serializable
data class Dice(
@SerialName(valueField)
val value: DiceResult
)

View File

@@ -5,7 +5,7 @@ import com.github.insanusmokrassar.TelegramBotAPI.CommonAbstracts.TextPart
import com.github.insanusmokrassar.TelegramBotAPI.utils.* import com.github.insanusmokrassar.TelegramBotAPI.utils.*
class BoldTextSource( class BoldTextSource(
source: String, override val source: String,
textParts: List<TextPart> textParts: List<TextPart>
) : MultilevelTextSource { ) : MultilevelTextSource {
override val textParts: List<TextPart> by lazy { source.fullListOfSubSource(textParts) } override val textParts: List<TextPart> by lazy { source.fullListOfSubSource(textParts) }

View File

@@ -7,7 +7,7 @@ import com.github.insanusmokrassar.TelegramBotAPI.utils.*
private val commandRegex = Regex("[/!][^@\\s]*") private val commandRegex = Regex("[/!][^@\\s]*")
class BotCommandTextSource( class BotCommandTextSource(
source: String, override val source: String,
textParts: List<TextPart> textParts: List<TextPart>
) : MultilevelTextSource { ) : MultilevelTextSource {
val command: String by lazy { val command: String by lazy {

View File

@@ -5,7 +5,7 @@ import com.github.insanusmokrassar.TelegramBotAPI.CommonAbstracts.TextPart
import com.github.insanusmokrassar.TelegramBotAPI.utils.* import com.github.insanusmokrassar.TelegramBotAPI.utils.*
class CashTagTextSource( class CashTagTextSource(
source: String, override val source: String,
textParts: List<TextPart> textParts: List<TextPart>
) : MultilevelTextSource { ) : MultilevelTextSource {
override val textParts: List<TextPart> by lazy { source.fullListOfSubSource(textParts) } override val textParts: List<TextPart> by lazy { source.fullListOfSubSource(textParts) }

View File

@@ -4,7 +4,7 @@ import com.github.insanusmokrassar.TelegramBotAPI.CommonAbstracts.TextSource
import com.github.insanusmokrassar.TelegramBotAPI.utils.* import com.github.insanusmokrassar.TelegramBotAPI.utils.*
class CodeTextSource( class CodeTextSource(
source: String override val source: String
) : TextSource { ) : TextSource {
override val asMarkdownSource: String by lazy { source.codeMarkdown() } override val asMarkdownSource: String by lazy { source.codeMarkdown() }
override val asMarkdownV2Source: String by lazy { source.codeMarkdownV2() } override val asMarkdownV2Source: String by lazy { source.codeMarkdownV2() }

View File

@@ -5,7 +5,7 @@ import com.github.insanusmokrassar.TelegramBotAPI.CommonAbstracts.TextPart
import com.github.insanusmokrassar.TelegramBotAPI.utils.* import com.github.insanusmokrassar.TelegramBotAPI.utils.*
class EMailTextSource( class EMailTextSource(
source: String, override val source: String,
textParts: List<TextPart> textParts: List<TextPart>
) : MultilevelTextSource { ) : MultilevelTextSource {
override val textParts: List<TextPart> by lazy { source.fullListOfSubSource(textParts) } override val textParts: List<TextPart> by lazy { source.fullListOfSubSource(textParts) }

View File

@@ -12,7 +12,7 @@ private val String.withoutSharp
} }
class HashTagTextSource( class HashTagTextSource(
source: String, override val source: String,
textParts: List<TextPart> textParts: List<TextPart>
) : MultilevelTextSource { ) : MultilevelTextSource {
override val textParts: List<TextPart> by lazy { override val textParts: List<TextPart> by lazy {

View File

@@ -5,7 +5,7 @@ import com.github.insanusmokrassar.TelegramBotAPI.CommonAbstracts.TextPart
import com.github.insanusmokrassar.TelegramBotAPI.utils.* import com.github.insanusmokrassar.TelegramBotAPI.utils.*
class ItalicTextSource( class ItalicTextSource(
source: String, override val source: String,
textParts: List<TextPart> textParts: List<TextPart>
) : MultilevelTextSource { ) : MultilevelTextSource {
override val textParts: List<TextPart> by lazy { source.fullListOfSubSource(textParts) } override val textParts: List<TextPart> by lazy { source.fullListOfSubSource(textParts) }

View File

@@ -12,7 +12,7 @@ private val String.withoutCommercialAt
} }
class MentionTextSource( class MentionTextSource(
source: String, override val source: String,
textParts: List<TextPart> textParts: List<TextPart>
) : MultilevelTextSource { ) : MultilevelTextSource {
override val textParts: List<TextPart> by lazy { override val textParts: List<TextPart> by lazy {

View File

@@ -5,7 +5,7 @@ import com.github.insanusmokrassar.TelegramBotAPI.CommonAbstracts.TextPart
import com.github.insanusmokrassar.TelegramBotAPI.utils.* import com.github.insanusmokrassar.TelegramBotAPI.utils.*
class PhoneNumberTextSource( class PhoneNumberTextSource(
source: String, override val source: String,
textParts: List<TextPart> textParts: List<TextPart>
) : MultilevelTextSource { ) : MultilevelTextSource {
override val textParts: List<TextPart> by lazy { source.fullListOfSubSource(textParts) } override val textParts: List<TextPart> by lazy { source.fullListOfSubSource(textParts) }

View File

@@ -4,7 +4,7 @@ import com.github.insanusmokrassar.TelegramBotAPI.CommonAbstracts.TextSource
import com.github.insanusmokrassar.TelegramBotAPI.utils.* import com.github.insanusmokrassar.TelegramBotAPI.utils.*
class PreTextSource( class PreTextSource(
source: String, override val source: String,
val language: String? = null val language: String? = null
) : TextSource { ) : TextSource {
override val asMarkdownSource: String by lazy { source.preMarkdown(language) } override val asMarkdownSource: String by lazy { source.preMarkdown(language) }

View File

@@ -4,7 +4,7 @@ import com.github.insanusmokrassar.TelegramBotAPI.CommonAbstracts.TextSource
import com.github.insanusmokrassar.TelegramBotAPI.utils.* import com.github.insanusmokrassar.TelegramBotAPI.utils.*
class RegularTextSource( class RegularTextSource(
source: String override val source: String
) : TextSource { ) : TextSource {
override val asMarkdownSource: String by lazy { source.regularMarkdown() } override val asMarkdownSource: String by lazy { source.regularMarkdown() }
override val asMarkdownV2Source: String by lazy { source.regularMarkdownV2() } override val asMarkdownV2Source: String by lazy { source.regularMarkdownV2() }

View File

@@ -5,7 +5,7 @@ import com.github.insanusmokrassar.TelegramBotAPI.CommonAbstracts.TextPart
import com.github.insanusmokrassar.TelegramBotAPI.utils.* import com.github.insanusmokrassar.TelegramBotAPI.utils.*
class StrikethroughTextSource( class StrikethroughTextSource(
source: String, override val source: String,
textParts: List<TextPart> textParts: List<TextPart>
) : MultilevelTextSource { ) : MultilevelTextSource {
override val textParts: List<TextPart> by lazy { source.fullListOfSubSource(textParts) } override val textParts: List<TextPart> by lazy { source.fullListOfSubSource(textParts) }

View File

@@ -4,7 +4,7 @@ import com.github.insanusmokrassar.TelegramBotAPI.CommonAbstracts.TextSource
import com.github.insanusmokrassar.TelegramBotAPI.utils.* import com.github.insanusmokrassar.TelegramBotAPI.utils.*
class TextLinkTextSource( class TextLinkTextSource(
source: String, override val source: String,
url: String url: String
) : TextSource { ) : TextSource {
override val asMarkdownSource: String by lazy { source.linkMarkdown(url) } override val asMarkdownSource: String by lazy { source.linkMarkdown(url) }

View File

@@ -6,7 +6,7 @@ import com.github.insanusmokrassar.TelegramBotAPI.types.chat.abstracts.PrivateCh
import com.github.insanusmokrassar.TelegramBotAPI.utils.* import com.github.insanusmokrassar.TelegramBotAPI.utils.*
class TextMentionTextSource( class TextMentionTextSource(
source: String, override val source: String,
privateChat: PrivateChat, privateChat: PrivateChat,
textParts: List<TextPart> textParts: List<TextPart>
) : MultilevelTextSource { ) : MultilevelTextSource {

View File

@@ -4,7 +4,7 @@ import com.github.insanusmokrassar.TelegramBotAPI.CommonAbstracts.TextSource
import com.github.insanusmokrassar.TelegramBotAPI.utils.* import com.github.insanusmokrassar.TelegramBotAPI.utils.*
class URLTextSource( class URLTextSource(
source: String override val source: String
) : TextSource { ) : TextSource {
override val asMarkdownSource: String by lazy { source.linkMarkdown(source) } override val asMarkdownSource: String by lazy { source.linkMarkdown(source) }
override val asMarkdownV2Source: String by lazy { source.linkMarkdownV2(source) } override val asMarkdownV2Source: String by lazy { source.linkMarkdownV2(source) }

View File

@@ -5,7 +5,7 @@ import com.github.insanusmokrassar.TelegramBotAPI.CommonAbstracts.TextPart
import com.github.insanusmokrassar.TelegramBotAPI.utils.* import com.github.insanusmokrassar.TelegramBotAPI.utils.*
class UnderlineTextSource( class UnderlineTextSource(
source: String, override val source: String,
textParts: List<TextPart> textParts: List<TextPart>
) : MultilevelTextSource { ) : MultilevelTextSource {
override val textParts: List<TextPart> by lazy { source.fullListOfSubSource(textParts) } override val textParts: List<TextPart> by lazy { source.fullListOfSubSource(textParts) }

View File

@@ -1,14 +1,23 @@
package com.github.insanusmokrassar.TelegramBotAPI.types.buttons.InlineKeyboardButtons package com.github.insanusmokrassar.TelegramBotAPI.types.buttons.InlineKeyboardButtons
import com.github.insanusmokrassar.TelegramBotAPI.types.* import com.github.insanusmokrassar.TelegramBotAPI.types.*
import com.github.insanusmokrassar.TelegramBotAPI.types.games.CallbackGame
import kotlinx.serialization.SerialName import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable import kotlinx.serialization.Serializable
import kotlinx.serialization.json.JsonElement
import kotlinx.serialization.json.JsonObject
@Serializable(InlineKeyboardButtonSerializer::class) @Serializable(InlineKeyboardButtonSerializer::class)
sealed class InlineKeyboardButton { sealed class InlineKeyboardButton {
abstract val text: String abstract val text: String
} }
@Serializable
data class UnknownInlineKeyboardButton internal constructor(
override val text: String,
val rawData: JsonElement
) : InlineKeyboardButton()
@Serializable @Serializable
data class PayInlineKeyboardButton( data class PayInlineKeyboardButton(
override val text: String, override val text: String,
@@ -24,6 +33,15 @@ data class CallbackDataInlineKeyboardButton(
val callbackData: String val callbackData: String
) : InlineKeyboardButton() ) : InlineKeyboardButton()
@Serializable
data class CallbackGameInlineKeyboardButton(
@SerialName(textField)
override val text: String
) : InlineKeyboardButton() {
@SerialName(callbackGameField)
private val callbackGame = CallbackGame
}
@Serializable @Serializable
data class LoginURLInlineKeyboardButton( data class LoginURLInlineKeyboardButton(
override val text: String, override val text: String,

View File

@@ -3,8 +3,7 @@ package com.github.insanusmokrassar.TelegramBotAPI.types.buttons.InlineKeyboardB
import com.github.insanusmokrassar.TelegramBotAPI.types.* import com.github.insanusmokrassar.TelegramBotAPI.types.*
import com.github.insanusmokrassar.TelegramBotAPI.utils.nonstrictJsonFormat import com.github.insanusmokrassar.TelegramBotAPI.utils.nonstrictJsonFormat
import kotlinx.serialization.* import kotlinx.serialization.*
import kotlinx.serialization.json.JsonElementSerializer import kotlinx.serialization.json.*
import kotlinx.serialization.json.JsonObject
internal object InlineKeyboardButtonSerializer : KSerializer<InlineKeyboardButton> { internal object InlineKeyboardButtonSerializer : KSerializer<InlineKeyboardButton> {
override val descriptor: SerialDescriptor = SerialDescriptor( override val descriptor: SerialDescriptor = SerialDescriptor(
@@ -12,22 +11,25 @@ internal object InlineKeyboardButtonSerializer : KSerializer<InlineKeyboardButto
PolymorphicKind.SEALED PolymorphicKind.SEALED
) )
private fun resolveSerializer(json: JsonObject): KSerializer<out InlineKeyboardButton> { private fun resolveSerializer(json: JsonObject): KSerializer<out InlineKeyboardButton>? {
return when { return when {
json[callbackDataField] != null -> CallbackDataInlineKeyboardButton.serializer() json[callbackDataField] != null -> CallbackDataInlineKeyboardButton.serializer()
json[callbackGameField] != null -> CallbackGameInlineKeyboardButton.serializer()
json[loginUrlField] != null -> LoginURLInlineKeyboardButton.serializer() json[loginUrlField] != null -> LoginURLInlineKeyboardButton.serializer()
json[payField] != null -> PayInlineKeyboardButton.serializer() json[payField] != null -> PayInlineKeyboardButton.serializer()
json[switchInlineQueryField] != null -> SwitchInlineQueryInlineKeyboardButton.serializer() json[switchInlineQueryField] != null -> SwitchInlineQueryInlineKeyboardButton.serializer()
json[switchInlineQueryCurrentChatField] != null -> SwitchInlineQueryCurrentChatInlineKeyboardButton.serializer() json[switchInlineQueryCurrentChatField] != null -> SwitchInlineQueryCurrentChatInlineKeyboardButton.serializer()
json[urlField] != null -> URLInlineKeyboardButton.serializer() json[urlField] != null -> URLInlineKeyboardButton.serializer()
else -> throw IllegalArgumentException("Can't find correct serializer for inline button serialized as $json") else -> null
} }
} }
override fun deserialize(decoder: Decoder): InlineKeyboardButton { override fun deserialize(decoder: Decoder): InlineKeyboardButton {
val json = JsonElementSerializer.deserialize(decoder) val json = JsonElementSerializer.deserialize(decoder)
return nonstrictJsonFormat.fromJson(resolveSerializer(json.jsonObject), json) return (json as? JsonObject) ?.let { resolveSerializer(it) } ?.let {
nonstrictJsonFormat.fromJson(it, json)
} ?: UnknownInlineKeyboardButton("", json)
} }
override fun serialize(encoder: Encoder, value: InlineKeyboardButton) { override fun serialize(encoder: Encoder, value: InlineKeyboardButton) {
@@ -38,6 +40,8 @@ internal object InlineKeyboardButtonSerializer : KSerializer<InlineKeyboardButto
is SwitchInlineQueryInlineKeyboardButton -> SwitchInlineQueryInlineKeyboardButton.serializer().serialize(encoder, value) is SwitchInlineQueryInlineKeyboardButton -> SwitchInlineQueryInlineKeyboardButton.serializer().serialize(encoder, value)
is SwitchInlineQueryCurrentChatInlineKeyboardButton -> SwitchInlineQueryCurrentChatInlineKeyboardButton.serializer().serialize(encoder, value) is SwitchInlineQueryCurrentChatInlineKeyboardButton -> SwitchInlineQueryCurrentChatInlineKeyboardButton.serializer().serialize(encoder, value)
is URLInlineKeyboardButton -> URLInlineKeyboardButton.serializer().serialize(encoder, value) is URLInlineKeyboardButton -> URLInlineKeyboardButton.serializer().serialize(encoder, value)
is CallbackGameInlineKeyboardButton -> CallbackGameInlineKeyboardButton.serializer().serialize(encoder, value)
is UnknownInlineKeyboardButton -> JsonElementSerializer.serialize(encoder, value.rawData)
} }
} }
} }

View File

@@ -3,8 +3,4 @@ package com.github.insanusmokrassar.TelegramBotAPI.types.games
import kotlinx.serialization.Serializable import kotlinx.serialization.Serializable
@Serializable @Serializable
class CallbackGame { object CallbackGame
init {
TODO()
}
}

View File

@@ -19,7 +19,8 @@ import com.github.insanusmokrassar.TelegramBotAPI.types.message.payments.Success
import com.github.insanusmokrassar.TelegramBotAPI.types.payments.Invoice import com.github.insanusmokrassar.TelegramBotAPI.types.payments.Invoice
import com.github.insanusmokrassar.TelegramBotAPI.types.payments.SuccessfulPayment import com.github.insanusmokrassar.TelegramBotAPI.types.payments.SuccessfulPayment
import com.github.insanusmokrassar.TelegramBotAPI.types.polls.Poll import com.github.insanusmokrassar.TelegramBotAPI.types.polls.Poll
import kotlinx.serialization.* import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
import kotlin.reflect.KClass import kotlin.reflect.KClass
// TODO:: add PassportData type // TODO:: add PassportData type
@@ -74,6 +75,7 @@ internal data class RawMessage(
private val migrate_from_chat_id: ChatIdentifier? = null, private val migrate_from_chat_id: ChatIdentifier? = null,
private val pinned_message: RawMessage? = null, private val pinned_message: RawMessage? = null,
private val invoice: Invoice? = null, private val invoice: Invoice? = null,
private val dice: Dice? = null,
private val successful_payment: SuccessfulPayment? = null, private val successful_payment: SuccessfulPayment? = null,
// login property // login property
@@ -123,6 +125,7 @@ internal data class RawMessage(
adaptedCaptionEntities adaptedCaptionEntities
) )
sticker != null -> StickerContent(sticker) sticker != null -> StickerContent(sticker)
dice != null -> DiceContent(dice)
game != null -> GameContent(game.asGame) game != null -> GameContent(game.asGame)
video_note != null -> VideoNoteContent(video_note) video_note != null -> VideoNoteContent(video_note)
contact != null -> ContactContent(contact) contact != null -> ContactContent(contact)

View File

@@ -0,0 +1,19 @@
package com.github.insanusmokrassar.TelegramBotAPI.types.message.content
import com.github.insanusmokrassar.TelegramBotAPI.requests.abstracts.Request
import com.github.insanusmokrassar.TelegramBotAPI.requests.send.SendDice
import com.github.insanusmokrassar.TelegramBotAPI.types.*
import com.github.insanusmokrassar.TelegramBotAPI.types.buttons.KeyboardMarkup
import com.github.insanusmokrassar.TelegramBotAPI.types.message.abstracts.ContentMessage
import com.github.insanusmokrassar.TelegramBotAPI.types.message.content.abstracts.MessageContent
data class DiceContent(
val dice: Dice
) : MessageContent {
override fun createResend(
chatId: ChatIdentifier,
disableNotification: Boolean,
replyToMessageId: MessageIdentifier?,
replyMarkup: KeyboardMarkup?
): Request<ContentMessage<DiceContent>> = SendDice(chatId, disableNotification, replyToMessageId, replyMarkup)
}

View File

@@ -1,6 +1,7 @@
package com.github.insanusmokrassar.TelegramBotAPI.types.stickers package com.github.insanusmokrassar.TelegramBotAPI.types.stickers
import com.github.insanusmokrassar.TelegramBotAPI.types.* import com.github.insanusmokrassar.TelegramBotAPI.types.*
import com.github.insanusmokrassar.TelegramBotAPI.types.files.PhotoSize
import com.github.insanusmokrassar.TelegramBotAPI.types.files.Sticker import com.github.insanusmokrassar.TelegramBotAPI.types.files.Sticker
import kotlinx.serialization.SerialName import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable import kotlinx.serialization.Serializable
@@ -16,5 +17,7 @@ data class StickerSet(
@SerialName(isAnimatedField) @SerialName(isAnimatedField)
val isAnimated: Boolean = false, val isAnimated: Boolean = false,
@SerialName(containsMasksField) @SerialName(containsMasksField)
val containsMasks: Boolean = false val containsMasks: Boolean = false,
@SerialName(thumbField)
val thumb: PhotoSize? = null
) )

View File

@@ -1,10 +1,10 @@
package com.github.insanusmokrassar.TelegramBotAPI.types.update package com.github.insanusmokrassar.TelegramBotAPI.types.update
import com.github.insanusmokrassar.TelegramBotAPI.types.UpdateIdentifier import com.github.insanusmokrassar.TelegramBotAPI.types.UpdateIdentifier
import com.github.insanusmokrassar.TelegramBotAPI.types.message.abstracts.Message import com.github.insanusmokrassar.TelegramBotAPI.types.message.abstracts.CommonMessage
import com.github.insanusmokrassar.TelegramBotAPI.types.update.abstracts.BaseEditMessageUpdate import com.github.insanusmokrassar.TelegramBotAPI.types.update.abstracts.BaseEditMessageUpdate
data class EditChannelPostUpdate( data class EditChannelPostUpdate(
override val updateId: UpdateIdentifier, override val updateId: UpdateIdentifier,
override val data: Message override val data: CommonMessage<*>
) : BaseEditMessageUpdate ) : BaseEditMessageUpdate

View File

@@ -1,10 +1,10 @@
package com.github.insanusmokrassar.TelegramBotAPI.types.update package com.github.insanusmokrassar.TelegramBotAPI.types.update
import com.github.insanusmokrassar.TelegramBotAPI.types.UpdateIdentifier import com.github.insanusmokrassar.TelegramBotAPI.types.UpdateIdentifier
import com.github.insanusmokrassar.TelegramBotAPI.types.message.abstracts.Message import com.github.insanusmokrassar.TelegramBotAPI.types.message.abstracts.CommonMessage
import com.github.insanusmokrassar.TelegramBotAPI.types.update.abstracts.BaseEditMessageUpdate import com.github.insanusmokrassar.TelegramBotAPI.types.update.abstracts.BaseEditMessageUpdate
data class EditMessageUpdate( data class EditMessageUpdate(
override val updateId: UpdateIdentifier, override val updateId: UpdateIdentifier,
override val data: Message override val data: CommonMessage<*>
) : BaseEditMessageUpdate ) : BaseEditMessageUpdate

View File

@@ -1,8 +1,7 @@
package com.github.insanusmokrassar.TelegramBotAPI.types.update.MediaGroupUpdates package com.github.insanusmokrassar.TelegramBotAPI.types.update.MediaGroupUpdates
import com.github.insanusmokrassar.TelegramBotAPI.types.message.abstracts.MediaGroupMessage import com.github.insanusmokrassar.TelegramBotAPI.types.message.abstracts.MediaGroupMessage
import com.github.insanusmokrassar.TelegramBotAPI.types.update.abstracts.BaseMessageUpdate import com.github.insanusmokrassar.TelegramBotAPI.types.update.abstracts.*
import com.github.insanusmokrassar.TelegramBotAPI.types.update.abstracts.Update
interface MediaGroupUpdate : Update interface MediaGroupUpdate : Update
@@ -11,7 +10,7 @@ interface SentMediaGroupUpdate: MediaGroupUpdate {
val origins: List<BaseMessageUpdate> val origins: List<BaseMessageUpdate>
} }
interface EditMediaGroupUpdate : MediaGroupUpdate { interface EditMediaGroupUpdate : BaseEditMessageUpdate, MediaGroupUpdate {
override val data: MediaGroupMessage override val data: MediaGroupMessage
val origin: BaseMessageUpdate val origin: BaseMessageUpdate
} }

View File

@@ -4,7 +4,7 @@ import com.github.insanusmokrassar.TelegramBotAPI.types.CallbackQuery.RawCallbac
import com.github.insanusmokrassar.TelegramBotAPI.types.InlineQueries.ChosenInlineResult.RawChosenInlineResult import com.github.insanusmokrassar.TelegramBotAPI.types.InlineQueries.ChosenInlineResult.RawChosenInlineResult
import com.github.insanusmokrassar.TelegramBotAPI.types.InlineQueries.query.RawInlineQuery import com.github.insanusmokrassar.TelegramBotAPI.types.InlineQueries.query.RawInlineQuery
import com.github.insanusmokrassar.TelegramBotAPI.types.UpdateIdentifier import com.github.insanusmokrassar.TelegramBotAPI.types.UpdateIdentifier
import com.github.insanusmokrassar.TelegramBotAPI.types.message.abstracts.Message import com.github.insanusmokrassar.TelegramBotAPI.types.message.abstracts.*
import com.github.insanusmokrassar.TelegramBotAPI.types.message.abstracts.TelegramBotAPIMessageDeserializeOnlySerializer import com.github.insanusmokrassar.TelegramBotAPI.types.message.abstracts.TelegramBotAPIMessageDeserializeOnlySerializer
import com.github.insanusmokrassar.TelegramBotAPI.types.payments.PreCheckoutQuery import com.github.insanusmokrassar.TelegramBotAPI.types.payments.PreCheckoutQuery
import com.github.insanusmokrassar.TelegramBotAPI.types.payments.ShippingQuery import com.github.insanusmokrassar.TelegramBotAPI.types.payments.ShippingQuery
@@ -13,8 +13,7 @@ import com.github.insanusmokrassar.TelegramBotAPI.types.polls.PollAnswer
import com.github.insanusmokrassar.TelegramBotAPI.types.update.abstracts.UnknownUpdateType import com.github.insanusmokrassar.TelegramBotAPI.types.update.abstracts.UnknownUpdateType
import com.github.insanusmokrassar.TelegramBotAPI.types.update.abstracts.Update import com.github.insanusmokrassar.TelegramBotAPI.types.update.abstracts.Update
import com.github.insanusmokrassar.TelegramBotAPI.types.updateIdField import com.github.insanusmokrassar.TelegramBotAPI.types.updateIdField
import kotlinx.serialization.SerialName import kotlinx.serialization.*
import kotlinx.serialization.Serializable
import kotlinx.serialization.json.JsonElement import kotlinx.serialization.json.JsonElement
@Serializable @Serializable
@@ -22,11 +21,11 @@ internal data class RawUpdate constructor(
@SerialName(updateIdField) @SerialName(updateIdField)
val updateId: UpdateIdentifier, val updateId: UpdateIdentifier,
@Serializable(TelegramBotAPIMessageDeserializeOnlySerializer::class) @Serializable(TelegramBotAPIMessageDeserializeOnlySerializer::class)
private val edited_message: Message? = null, private val edited_message: CommonMessage<*>? = null,
@Serializable(TelegramBotAPIMessageDeserializeOnlySerializer::class) @Serializable(TelegramBotAPIMessageDeserializeOnlySerializer::class)
private val message: Message? = null, private val message: Message? = null,
@Serializable(TelegramBotAPIMessageDeserializeOnlySerializer::class) @Serializable(TelegramBotAPIMessageDeserializeOnlySerializer::class)
private val edited_channel_post: Message? = null, private val edited_channel_post: CommonMessage<*>? = null,
@Serializable(TelegramBotAPIMessageDeserializeOnlySerializer::class) @Serializable(TelegramBotAPIMessageDeserializeOnlySerializer::class)
private val channel_post: Message? = null, private val channel_post: Message? = null,
private val inline_query: RawInlineQuery? = null, private val inline_query: RawInlineQuery? = null,
@@ -42,26 +41,39 @@ internal data class RawUpdate constructor(
* @return One of children of [Update] interface or null in case of unknown type of update * @return One of children of [Update] interface or null in case of unknown type of update
*/ */
fun asUpdate(raw: JsonElement): Update { fun asUpdate(raw: JsonElement): Update {
return initedUpdate ?: when { return initedUpdate ?: try {
edited_message != null -> EditMessageUpdate(updateId, edited_message) when {
message != null -> MessageUpdate(updateId, message) edited_message != null -> EditMessageUpdate(updateId, edited_message)
edited_channel_post != null -> EditChannelPostUpdate(updateId, edited_channel_post) message != null -> MessageUpdate(updateId, message)
channel_post != null -> ChannelPostUpdate(updateId, channel_post) edited_channel_post != null -> EditChannelPostUpdate(updateId, edited_channel_post)
channel_post != null -> ChannelPostUpdate(updateId, channel_post)
chosen_inline_result != null -> ChosenInlineResultUpdate(updateId, chosen_inline_result.asChosenInlineResult) chosen_inline_result != null -> ChosenInlineResultUpdate(updateId, chosen_inline_result.asChosenInlineResult)
inline_query != null -> InlineQueryUpdate(updateId, inline_query.asInlineQuery) inline_query != null -> InlineQueryUpdate(updateId, inline_query.asInlineQuery)
callback_query != null -> CallbackQueryUpdate( callback_query != null -> CallbackQueryUpdate(
updateId, updateId,
callback_query.asCallbackQuery(raw.jsonObject["callback_query"].toString()) callback_query.asCallbackQuery(raw.jsonObject["callback_query"].toString())
) )
shipping_query != null -> ShippingQueryUpdate(updateId, shipping_query) shipping_query != null -> ShippingQueryUpdate(updateId, shipping_query)
pre_checkout_query != null -> PreCheckoutQueryUpdate(updateId, pre_checkout_query) pre_checkout_query != null -> PreCheckoutQueryUpdate(updateId, pre_checkout_query)
poll != null -> PollUpdate(updateId, poll) poll != null -> PollUpdate(updateId, poll)
poll_answer != null -> PollAnswerUpdate(updateId, poll_answer) poll_answer != null -> PollAnswerUpdate(updateId, poll_answer)
else -> UnknownUpdateType( else -> UnknownUpdateType(
updateId, updateId,
raw.toString() raw.toString(),
) raw
)
}
} catch (e: Error) {
when (e) {
is SerializationException,
is NotImplementedError -> UnknownUpdateType(
updateId,
raw.toString(),
raw
)
else -> throw e
}
}.also { }.also {
initedUpdate = it initedUpdate = it
} }

View File

@@ -1,3 +1,7 @@
package com.github.insanusmokrassar.TelegramBotAPI.types.update.abstracts package com.github.insanusmokrassar.TelegramBotAPI.types.update.abstracts
interface BaseEditMessageUpdate : BaseMessageUpdate import com.github.insanusmokrassar.TelegramBotAPI.types.message.abstracts.CommonMessage
interface BaseEditMessageUpdate : BaseMessageUpdate {
override val data: CommonMessage<*>
}

View File

@@ -4,6 +4,7 @@ import com.github.insanusmokrassar.TelegramBotAPI.types.UpdateIdentifier
import com.github.insanusmokrassar.TelegramBotAPI.types.update.RawUpdate import com.github.insanusmokrassar.TelegramBotAPI.types.update.RawUpdate
import com.github.insanusmokrassar.TelegramBotAPI.utils.nonstrictJsonFormat import com.github.insanusmokrassar.TelegramBotAPI.utils.nonstrictJsonFormat
import kotlinx.serialization.* import kotlinx.serialization.*
import kotlinx.serialization.json.JsonElement
import kotlinx.serialization.json.JsonElementSerializer import kotlinx.serialization.json.JsonElementSerializer
interface Update { interface Update {
@@ -13,10 +14,11 @@ interface Update {
data class UnknownUpdateType( data class UnknownUpdateType(
override val updateId: UpdateIdentifier, override val updateId: UpdateIdentifier,
override val data: String override val data: String,
val rawJson: JsonElement
) : Update ) : Update
internal object UpdateSerializerWithoutDeserialization : KSerializer<Update> { internal object UpdateSerializerWithoutSerialization : KSerializer<Update> {
override val descriptor: SerialDescriptor = JsonElementSerializer.descriptor override val descriptor: SerialDescriptor = JsonElementSerializer.descriptor
override fun deserialize(decoder: Decoder): Update = UpdateDeserializationStrategy.deserialize(decoder) override fun deserialize(decoder: Decoder): Update = UpdateDeserializationStrategy.deserialize(decoder)

View File

@@ -0,0 +1,21 @@
package com.github.insanusmokrassar.TelegramBotAPI.utils
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.supervisorScope
/**
* It will run [block] inside of [supervisorScope] to avoid problems with catching of exceptions
*
* @param [onException] Will be called when happen exception inside of [block]. By default will throw exception - this
* exception will be available for catching
*/
suspend inline fun <T> handleSafely(
noinline onException: suspend (Exception) -> T = { throw it },
noinline block: suspend CoroutineScope.() -> T
): T {
return try {
supervisorScope(block)
} catch (e: Exception) {
onException(e)
}
}

View File

@@ -1,12 +1,21 @@
package com.github.insanusmokrassar.TelegramBotAPI.utils package com.github.insanusmokrassar.TelegramBotAPI.utils
import com.benasher44.uuid.uuid4
import io.ktor.utils.io.core.Input import io.ktor.utils.io.core.Input
import kotlinx.serialization.Serializable import kotlinx.serialization.Serializable
import kotlinx.serialization.Transient
@Serializable @Serializable
expect class StorageFile { data class StorageFileInfo(
val contentType: String val contentType: String,
val fileName: String val fileName: String
fun generateCustomName(): String ) {
fun asInput(): Input fun generateCustomName() = "${uuid4()}.${fileName.fileExtension}"
}
data class StorageFile(
val storageFileInfo: StorageFileInfo,
private val inputSource: () -> Input
) {
fun asInput() = inputSource()
} }

View File

@@ -0,0 +1,6 @@
package com.github.insanusmokrassar.TelegramBotAPI.utils
private val extensionRegex = Regex("[^.]*$")
val String.fileExtension
get() = extensionRegex.find(this) ?.value ?: ""

View File

@@ -120,7 +120,7 @@ fun String.mentionHTML(): String = mention(String::toHtml)
fun String.hashTagMarkdown(): String = hashTag(String::toMarkdown) fun String.hashTagMarkdown(): String = hashTag(String::toMarkdown)
fun String.hashTagMarkdownV2(): String = hashTag(String::escapeMarkdownV2Common) fun String.hashTagMarkdownV2(): String = hashTag(String::escapeMarkdownV2Common).escapeMarkdownV2Common()
fun String.hashTagHTML(): String = hashTag(String::toHtml) fun String.hashTagHTML(): String = hashTag(String::toHtml)

View File

@@ -16,9 +16,9 @@ fun String.toMarkdown(): String {
) )
} }
private val markdownV2LinkEscapes = mutableSetOf(')', '\\') private val markdownV2LinkEscapes = setOf(')', '\\')
private val markdownV2PreAndCodeEscapes = mutableSetOf('`', '\\') private val markdownV2PreAndCodeEscapes = setOf('`', '\\')
private val markdownV2CommonEscapes = mutableSetOf( private val markdownV2CommonEscapes = setOf(
'_', '_',
'*', '*',
'[', ']', '[', ']',

View File

@@ -1,19 +0,0 @@
package com.github.insanusmokrassar.TelegramBotAPI.utils
import com.benasher44.uuid.uuid4
import io.ktor.utils.io.core.Input
import kotlinx.serialization.Serializable
import kotlinx.serialization.Transient
@Serializable
actual data class StorageFile(
actual val contentType: String,
actual val fileName: String,
@Transient
val inputGetter: () -> Input = throw IllegalStateException("Can't create object without input"),
@Transient
val extension: String = throw IllegalStateException("Can't create object without extension")
) {
actual fun asInput(): Input = inputGetter()
actual fun generateCustomName(): String = "${uuid4()}.$extension"
}

View File

@@ -1,20 +1,16 @@
package com.github.insanusmokrassar.TelegramBotAPI.utils package com.github.insanusmokrassar.TelegramBotAPI.utils
import com.benasher44.uuid.uuid4
import io.ktor.utils.io.core.Input
import io.ktor.utils.io.streams.asInput import io.ktor.utils.io.streams.asInput
import kotlinx.serialization.Serializable
import kotlinx.serialization.Transient
import java.io.File import java.io.File
import java.nio.file.Files import java.nio.file.Files
@Serializable fun StorageFile(
actual class StorageFile( file: File
@Transient ) = StorageFile(
private val file: File = throw IllegalStateException("Can't create object without file") StorageFileInfo(
Files.probeContentType(file.toPath()),
file.name
)
) { ) {
actual val contentType: String = Files.probeContentType(file.toPath()) file.inputStream().asInput()
actual val fileName: String = file.name
actual fun generateCustomName(): String = "${uuid4()}.${file.extension}"
actual fun asInput(): Input = Files.newInputStream(file.toPath()).asInput()
} }

View File

@@ -4,15 +4,11 @@ import com.github.insanusmokrassar.TelegramBotAPI.bot.RequestsExecutor
import com.github.insanusmokrassar.TelegramBotAPI.requests.abstracts.InputFile import com.github.insanusmokrassar.TelegramBotAPI.requests.abstracts.InputFile
import com.github.insanusmokrassar.TelegramBotAPI.requests.webhook.SetWebhook import com.github.insanusmokrassar.TelegramBotAPI.requests.webhook.SetWebhook
import com.github.insanusmokrassar.TelegramBotAPI.types.message.abstracts.MediaGroupMessage import com.github.insanusmokrassar.TelegramBotAPI.types.message.abstracts.MediaGroupMessage
import com.github.insanusmokrassar.TelegramBotAPI.types.update.MediaGroupUpdates.MediaGroupUpdate import com.github.insanusmokrassar.TelegramBotAPI.types.update.abstracts.*
import com.github.insanusmokrassar.TelegramBotAPI.types.update.RawUpdate
import com.github.insanusmokrassar.TelegramBotAPI.types.update.abstracts.BaseMessageUpdate
import com.github.insanusmokrassar.TelegramBotAPI.types.update.abstracts.Update
import com.github.insanusmokrassar.TelegramBotAPI.updateshandlers.UpdateReceiver import com.github.insanusmokrassar.TelegramBotAPI.updateshandlers.UpdateReceiver
import com.github.insanusmokrassar.TelegramBotAPI.updateshandlers.UpdatesFilter import com.github.insanusmokrassar.TelegramBotAPI.updateshandlers.UpdatesFilter
import com.github.insanusmokrassar.TelegramBotAPI.updateshandlers.webhook.WebhookPrivateKeyConfig import com.github.insanusmokrassar.TelegramBotAPI.updateshandlers.webhook.WebhookPrivateKeyConfig
import com.github.insanusmokrassar.TelegramBotAPI.utils.convertWithMediaGroupUpdates import com.github.insanusmokrassar.TelegramBotAPI.utils.*
import com.github.insanusmokrassar.TelegramBotAPI.utils.nonstrictJsonFormat
import io.ktor.application.call import io.ktor.application.call
import io.ktor.request.receiveText import io.ktor.request.receiveText
import io.ktor.response.respond import io.ktor.response.respond
@@ -45,6 +41,7 @@ suspend fun RequestsExecutor.setWebhook(
scope: CoroutineScope = CoroutineScope(Executors.newFixedThreadPool(4).asCoroutineDispatcher()), scope: CoroutineScope = CoroutineScope(Executors.newFixedThreadPool(4).asCoroutineDispatcher()),
allowedUpdates: List<String>? = null, allowedUpdates: List<String>? = null,
maxAllowedConnections: Int? = null, maxAllowedConnections: Int? = null,
exceptionsHandler: (suspend (Exception) -> Unit)? = null,
block: UpdateReceiver<Update> block: UpdateReceiver<Update>
): Job { ): Job {
val executeDeferred = certificate ?.let { val executeDeferred = certificate ?.let {
@@ -74,12 +71,18 @@ suspend fun RequestsExecutor.setWebhook(
module { module {
routing { routing {
post(listenRoute) { post(listenRoute) {
val asJson = nonstrictJsonFormat.parseJson(call.receiveText()) handleSafely(
val update = nonstrictJsonFormat.fromJson( {
RawUpdate.serializer(), exceptionsHandler ?.invoke(it)
asJson }
) ) {
updatesChannel.send(update.asUpdate(asJson)) val asJson = nonstrictJsonFormat.parseJson(call.receiveText())
val update = nonstrictJsonFormat.fromJson(
UpdateDeserializationStrategy,
asJson
)
updatesChannel.send(update)
}
call.respond("Ok") call.respond("Ok")
} }
} }
@@ -113,11 +116,6 @@ suspend fun RequestsExecutor.setWebhook(
launch { launch {
for (update in updatesChannel) { for (update in updatesChannel) {
val data = update.data val data = update.data
if (data is MediaGroupUpdate) {
} else {
}
when (data) { when (data) {
is MediaGroupMessage -> mediaGroupChannel.send("${data.mediaGroupId}${update::class.simpleName}" to update as BaseMessageUpdate) is MediaGroupMessage -> mediaGroupChannel.send("${data.mediaGroupId}${update::class.simpleName}" to update as BaseMessageUpdate)
else -> block(update) else -> block(update)
@@ -139,6 +137,33 @@ suspend fun RequestsExecutor.setWebhook(
} }
} }
suspend fun RequestsExecutor.setWebhook(
url: String,
port: Int,
engineFactory: ApplicationEngineFactory<*, *>,
listenHost: String = "0.0.0.0",
listenRoute: String = "/",
certificate: InputFile? = null,
privateKeyConfig: WebhookPrivateKeyConfig? = null,
scope: CoroutineScope = CoroutineScope(Executors.newFixedThreadPool(4).asCoroutineDispatcher()),
allowedUpdates: List<String>? = null,
maxAllowedConnections: Int? = null,
block: UpdateReceiver<Update>
) = setWebhook(
url,
port,
engineFactory,
listenHost,
listenRoute,
certificate,
privateKeyConfig,
scope,
allowedUpdates,
maxAllowedConnections,
null,
block
)
suspend fun RequestsExecutor.setWebhook( suspend fun RequestsExecutor.setWebhook(
url: String, url: String,
port: Int, port: Int,

View File

@@ -2,11 +2,11 @@ kotlin.code.style=official
kotlin_version=1.3.71 kotlin_version=1.3.71
kotlin_coroutines_version=1.3.5 kotlin_coroutines_version=1.3.5
kotlin_serialisation_runtime_version=0.20.0 kotlin_serialisation_runtime_version=0.20.0
klock_version=1.10.0 klock_version=1.10.3
uuid_version=0.1.0 uuid_version=0.1.0
ktor_version=1.3.2 ktor_version=1.3.2
library_group=com.github.insanusmokrassar library_group=com.github.insanusmokrassar
library_version=0.25.1 library_version=0.26.4
gradle_bintray_plugin_version=1.8.4 gradle_bintray_plugin_version=1.8.4

View File

@@ -1,2 +1,3 @@
include ":TelegramBotAPI" include ":TelegramBotAPI"
include ":TelegramBotAPI-extensions-api" include ":TelegramBotAPI-extensions-api"
include ":TelegramBotAPI-extensions-utils"