1
0
mirror of https://github.com/InsanusMokrassar/TelegramBotAPI.git synced 2025-11-19 05:45:40 +00:00

Compare commits

..

39 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
49 changed files with 795 additions and 177 deletions

View File

@@ -38,6 +38,62 @@
and size of retrieved updates is equal to 100 (max count of retrieved updates) and size of retrieved updates is equal to 100 (max count of retrieved updates)
* Extensions `getUpdates` now will receive only not nullable `limit` parameter * 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 ### 0.26.1
* `TelegramBotAPI`: * `TelegramBotAPI`:

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?
@@ -99,3 +97,21 @@ filter.messageFlow.mapNotNull {
CoroutineScope(Dispatchers.Default) 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

@@ -10,6 +10,8 @@ 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.*
@@ -23,46 +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 }
).let { originalUpdates -> }
val converted = originalUpdates.convertWithMediaGroupUpdates() ) {
/** val updates = getUpdates(
* Dirty hack for cases when the media group was retrieved not fully: offset = lastUpdateIdentifier?.plus(1),
* timeout = timeoutSeconds,
* We are throw out the last media group and will reretrieve it again in the next get updates allowed_updates = allowedUpdates
* and it will guarantee that it is full ).let { originalUpdates ->
*/ val converted = originalUpdates.convertWithMediaGroupUpdates()
if (originalUpdates.size == getUpdatesLimit.last && converted.last() is SentMediaGroupUpdate) { /**
converted - converted.last() * Dirty hack for cases when the media group was retrieved not fully:
} else { *
converted * 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) {
supervisorScope { converted - converted.last()
for (update in updates) { } else {
updatesReceiver(update) converted
}
lastUpdateIdentifier = update.lastUpdateIdentifier() }
}
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?

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

@@ -3,12 +3,12 @@ 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

View File

@@ -82,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"

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

@@ -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

@@ -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

@@ -7,6 +7,6 @@ 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.26.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"