mirror of
https://github.com/InsanusMokrassar/TelegramBotAPI.git
synced 2025-11-17 04:20:13 +00:00
Compare commits
45 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| b336b17eef | |||
| 76b25d719a | |||
| a4d077dd17 | |||
| 469712150b | |||
| fad27ede78 | |||
| 1de90412b3 | |||
| 215c8793e1 | |||
| 54835f97d1 | |||
| 923e929670 | |||
| 37488e92e6 | |||
| 830ca8122d | |||
| fbb2758bdb | |||
| a5c3e06f1c | |||
| c6fb50c4a6 | |||
| 976c0b86dc | |||
| fee5d8f925 | |||
| 808746e12d | |||
| 3fb80dd475 | |||
| db8ea0da94 | |||
| fbdfb714a3 | |||
| 1facfbc2b7 | |||
| 914a0662a9 | |||
| eda3003b7d | |||
| 459942de36 | |||
| 17f64f9b48 | |||
| 3f896c2240 | |||
| 94f8c971c5 | |||
| c43109c063 | |||
| f6058e29b4 | |||
| 3a37311331 | |||
| 9fe1472e64 | |||
| f1480c40a7 | |||
| 88eebdc448 | |||
| 8c76283db5 | |||
| 7668c48081 | |||
| 35d2135f73 | |||
| 1cb0e096be | |||
| 31f7c7f31b | |||
| 82d3b3bc48 | |||
| b3734a5c2a | |||
| 55b8736d50 | |||
| 3334fd3ca6 | |||
|
|
e2416b405a | ||
| 14f012fbfa | |||
| 1ff55057f2 |
92
CHANGELOG.md
92
CHANGELOG.md
@@ -1,5 +1,71 @@
|
||||
# TelegramBotAPI changelog
|
||||
|
||||
## 0.27.0
|
||||
|
||||
* `Common`:
|
||||
* Versions updates:
|
||||
* `Kotlin`: `1.3.71` -> `1.3.72`
|
||||
* `Klock`: `1.10.3` -> `1.10.5`
|
||||
* `TelegramBotAPI`:
|
||||
* Typealias `LongSeconds` was added for correct explanation of seconds in `Long` primitive type
|
||||
* Several new fields was added:
|
||||
* `explanationField`
|
||||
* `explanationEntitiesField`
|
||||
* `openPeriodField`
|
||||
* `closeDateField`
|
||||
* Extension `List<TextPart>#justTextSources` was added for mapping of `List<TextPart>` to `List<TextSource>`
|
||||
* Field `SendPoll#closeInfo` was added
|
||||
* Range `openPeriodPollSecondsLimit` was added and used in all `SendPoll` requests for checking income data
|
||||
* `SendQuizPoll` now able to use fields `caption` and `parseMode` for `explanation` functionality
|
||||
* `quizPollExplanationLimit` was added for checking `QuizPoll` explanation size
|
||||
* Field `TextLinkTextSource#url` was added
|
||||
* Field `TextMentionTextSource#user` was added
|
||||
* Sealed class `ScheduledCloseInfo` was added
|
||||
* Class `ExactScheduledCloseInfo` was added for cases with `close_date`
|
||||
* Class `ApproximateScheduledCloseInfo` was added for cases with `open_period`
|
||||
* Field `Poll#scheduledCloseInfo` was added
|
||||
* Sealed class `MultipleAnswersPoll` was added
|
||||
* Class `RegularPoll` now extends `MultipleAnswersPoll`
|
||||
* `Dice` class was replaced into new package
|
||||
* Sealed class `DiceAnimationType` was added
|
||||
* Field `Dice#animationType` was added as `emoji` API representation
|
||||
* `SendDice` now receive `animationType` as second parameter
|
||||
* For `List<TextSource>` was added several extensions:
|
||||
* `toMarkdownCaptions`
|
||||
* `toMarkdownTexts`
|
||||
* `toMarkdownV2Captions`
|
||||
* `toMarkdownV2Texts`
|
||||
* `toHtmlCaptions`
|
||||
* `toHtmlTexts`
|
||||
* `TelegramBotAPI-extensions-api`:
|
||||
* All `RequestsExecutor#sendDice` extensions now accept `DiceAnimationType?` as second parameter
|
||||
* All `RequestsExecutor#sendRegularPoll` extensions now accept `ScheduledCloseInfo` fourth parameter
|
||||
* All `RequestsExecutor#sendQuizPoll` extensions now accept additional parameters `caption: String` and
|
||||
`parseMode: ParseMode` for `explanation` functionality and `closeInfo: ScheduledCloseInfo?` for autoclose poll
|
||||
functionality
|
||||
* `TelegramBotAPI-extensions-utils`:
|
||||
* Several shortcuts for `ScheduledCloseInfo` was added:
|
||||
* `closePollExactAt`
|
||||
* `closePollExactAfter`
|
||||
* `closePollAfter`
|
||||
|
||||
### 0.27.1
|
||||
|
||||
* `TelegramBotAPI`:
|
||||
* Interface `Explained` and subsinterfaces `ExplainedInput` and `ExplainedOutput` was added
|
||||
* Class `QuizPoll` now implement `ExplainedInput`
|
||||
* In `QuizPoll#caption` and `QuizPoll#captionEntities` are deprecated now
|
||||
* Class `SendQuizPoll` now implement `ExplainedOutput`
|
||||
* In `SendQuizPoll#caption` is deprecated now
|
||||
* `explanationLimit` range was added as future replacement of `quizPollExplanationLimit`
|
||||
* `quizPollExplanationLimit` now is deprecated
|
||||
* Extensions `toMarkdownExplanations`, `toMarkdownV2Explanations` and `toHtmlExplanations` was added
|
||||
* Typealias `FullTextSourcesList` was added
|
||||
* All extensions `fullEntitiesList` now return `FullTextSourcesList`
|
||||
* All extensions of `List<TextSource>` now are extensions for `FullTextSourcesList`
|
||||
* `TelegramBotAPI-extensions-api`:
|
||||
* `sendQuizPoll` now is using `explanation` parameter instead of `caption`
|
||||
|
||||
## 0.26.0
|
||||
|
||||
* `Common`:
|
||||
@@ -38,6 +104,32 @@
|
||||
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`:
|
||||
|
||||
43
README.md
43
README.md
@@ -19,6 +19,47 @@ work with commands, updates and other different things
|
||||
Most part of some specific solves or unuseful
|
||||
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?
|
||||
|
||||
In most cases, the most simple way will be to implement
|
||||
@@ -31,5 +72,5 @@ Anyway, all libraries are very typical inside of them. Examples:
|
||||
|
||||
* 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 understand to use `bot` name instead of `requestsExecutor`)
|
||||
better to use `bot` name instead of `requestsExecutor`)
|
||||
* `TelegramBotAPI-extensions-utils` will look like `filter.filterBaseMessageUpdates(chatId).filterExactCommands(Regex("^.*$"))...`
|
||||
|
||||
@@ -6,19 +6,22 @@ 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
|
||||
import com.github.insanusmokrassar.TelegramBotAPI.types.dice.DiceAnimationType
|
||||
|
||||
suspend fun RequestsExecutor.sendDice(
|
||||
chatId: ChatIdentifier,
|
||||
animationType: DiceAnimationType? = null,
|
||||
disableNotification: Boolean = false,
|
||||
replyToMessageId: MessageIdentifier? = null,
|
||||
replyMarkup: KeyboardMarkup? = null
|
||||
) = execute(
|
||||
SendDice(chatId, disableNotification, replyToMessageId, replyMarkup)
|
||||
SendDice(chatId, animationType, disableNotification, replyToMessageId, replyMarkup)
|
||||
)
|
||||
|
||||
suspend fun RequestsExecutor.sendDice(
|
||||
chat: Chat,
|
||||
animationType: DiceAnimationType? = null,
|
||||
disableNotification: Boolean = false,
|
||||
replyToMessageId: MessageIdentifier? = null,
|
||||
replyMarkup: KeyboardMarkup? = null
|
||||
) = sendDice(chat.id, disableNotification, replyToMessageId, replyMarkup)
|
||||
) = sendDice(chat.id, animationType, disableNotification, replyToMessageId, replyMarkup)
|
||||
|
||||
@@ -5,10 +5,10 @@ import com.github.insanusmokrassar.TelegramBotAPI.requests.send.polls.SendQuizPo
|
||||
import com.github.insanusmokrassar.TelegramBotAPI.requests.send.polls.SendRegularPoll
|
||||
import com.github.insanusmokrassar.TelegramBotAPI.types.ChatIdentifier
|
||||
import com.github.insanusmokrassar.TelegramBotAPI.types.MessageIdentifier
|
||||
import com.github.insanusmokrassar.TelegramBotAPI.types.ParseMode.ParseMode
|
||||
import com.github.insanusmokrassar.TelegramBotAPI.types.buttons.KeyboardMarkup
|
||||
import com.github.insanusmokrassar.TelegramBotAPI.types.chat.abstracts.Chat
|
||||
import com.github.insanusmokrassar.TelegramBotAPI.types.polls.QuizPoll
|
||||
import com.github.insanusmokrassar.TelegramBotAPI.types.polls.RegularPoll
|
||||
import com.github.insanusmokrassar.TelegramBotAPI.types.polls.*
|
||||
|
||||
suspend fun RequestsExecutor.sendRegularPoll(
|
||||
chatId: ChatIdentifier,
|
||||
@@ -17,12 +17,13 @@ suspend fun RequestsExecutor.sendRegularPoll(
|
||||
isAnonymous: Boolean = true,
|
||||
isClosed: Boolean = false,
|
||||
allowMultipleAnswers: Boolean = false,
|
||||
closeInfo: ScheduledCloseInfo? = null,
|
||||
disableNotification: Boolean = false,
|
||||
replyToMessageId: MessageIdentifier? = null,
|
||||
replyMarkup: KeyboardMarkup? = null
|
||||
) = execute(
|
||||
SendRegularPoll(
|
||||
chatId, question, options, isAnonymous, isClosed, allowMultipleAnswers, disableNotification, replyToMessageId, replyMarkup
|
||||
chatId, question, options, isAnonymous, isClosed, allowMultipleAnswers, closeInfo, disableNotification, replyToMessageId, replyMarkup
|
||||
)
|
||||
)
|
||||
suspend fun RequestsExecutor.sendRegularPoll(
|
||||
@@ -33,12 +34,13 @@ suspend fun RequestsExecutor.sendRegularPoll(
|
||||
options: List<String> = poll.options.map { it.text },
|
||||
isAnonymous: Boolean = poll.isAnonymous,
|
||||
allowMultipleAnswers: Boolean = poll.allowMultipleAnswers,
|
||||
closeInfo: ScheduledCloseInfo? = null,
|
||||
disableNotification: Boolean = false,
|
||||
replyToMessageId: MessageIdentifier? = null,
|
||||
replyMarkup: KeyboardMarkup? = null
|
||||
) = execute(
|
||||
SendRegularPoll(
|
||||
chatId, question, options, isAnonymous, isClosed, allowMultipleAnswers, disableNotification, replyToMessageId, replyMarkup
|
||||
chatId, question, options, isAnonymous, isClosed, allowMultipleAnswers, closeInfo, disableNotification, replyToMessageId, replyMarkup
|
||||
)
|
||||
)
|
||||
|
||||
@@ -49,11 +51,12 @@ suspend fun RequestsExecutor.sendRegularPoll(
|
||||
isAnonymous: Boolean = true,
|
||||
isClosed: Boolean = false,
|
||||
allowMultipleAnswers: Boolean = false,
|
||||
closeInfo: ScheduledCloseInfo? = null,
|
||||
disableNotification: Boolean = false,
|
||||
replyToMessageId: MessageIdentifier? = null,
|
||||
replyMarkup: KeyboardMarkup? = null
|
||||
) = sendRegularPoll(
|
||||
chat.id, question, options, isAnonymous, isClosed, allowMultipleAnswers, disableNotification, replyToMessageId, replyMarkup
|
||||
chat.id, question, options, isAnonymous, isClosed, allowMultipleAnswers, closeInfo, disableNotification, replyToMessageId, replyMarkup
|
||||
)
|
||||
|
||||
suspend fun RequestsExecutor.sendRegularPoll(
|
||||
@@ -64,11 +67,12 @@ suspend fun RequestsExecutor.sendRegularPoll(
|
||||
options: List<String> = poll.options.map { it.text },
|
||||
isAnonymous: Boolean = poll.isAnonymous,
|
||||
allowMultipleAnswers: Boolean = poll.allowMultipleAnswers,
|
||||
closeInfo: ScheduledCloseInfo? = null,
|
||||
disableNotification: Boolean = false,
|
||||
replyToMessageId: MessageIdentifier? = null,
|
||||
replyMarkup: KeyboardMarkup? = null
|
||||
) = sendRegularPoll(
|
||||
chat.id, question, options, isAnonymous, isClosed, allowMultipleAnswers, disableNotification, replyToMessageId, replyMarkup
|
||||
chat.id, question, options, isAnonymous, isClosed, allowMultipleAnswers, closeInfo, disableNotification, replyToMessageId, replyMarkup
|
||||
)
|
||||
|
||||
|
||||
@@ -79,12 +83,15 @@ suspend fun RequestsExecutor.sendQuizPoll(
|
||||
correctOptionId: Int,
|
||||
isAnonymous: Boolean = true,
|
||||
isClosed: Boolean = false,
|
||||
explanation: String? = null,
|
||||
parseMode: ParseMode? = null,
|
||||
closeInfo: ScheduledCloseInfo? = null,
|
||||
disableNotification: Boolean = false,
|
||||
replyToMessageId: MessageIdentifier? = null,
|
||||
replyMarkup: KeyboardMarkup? = null
|
||||
) = execute(
|
||||
SendQuizPoll(
|
||||
chatId, question, options, correctOptionId, isAnonymous, isClosed, disableNotification, replyToMessageId, replyMarkup
|
||||
chatId, question, options, correctOptionId, isAnonymous, isClosed, explanation, parseMode, closeInfo, disableNotification, replyToMessageId, replyMarkup
|
||||
)
|
||||
)
|
||||
|
||||
@@ -95,11 +102,14 @@ suspend fun RequestsExecutor.sendQuizPoll(
|
||||
correctOptionId: Int,
|
||||
isAnonymous: Boolean = true,
|
||||
isClosed: Boolean = false,
|
||||
explanation: String? = null,
|
||||
parseMode: ParseMode? = null,
|
||||
closeInfo: ScheduledCloseInfo? = null,
|
||||
disableNotification: Boolean = false,
|
||||
replyToMessageId: MessageIdentifier? = null,
|
||||
replyMarkup: KeyboardMarkup? = null
|
||||
) = sendQuizPoll(
|
||||
chat.id, question, options, correctOptionId, isAnonymous, isClosed, disableNotification, replyToMessageId, replyMarkup
|
||||
chat.id, question, options, correctOptionId, isAnonymous, isClosed, explanation, parseMode, closeInfo, disableNotification, replyToMessageId, replyMarkup
|
||||
)
|
||||
|
||||
suspend fun RequestsExecutor.sendQuizPoll(
|
||||
@@ -110,12 +120,15 @@ suspend fun RequestsExecutor.sendQuizPoll(
|
||||
options: List<String> = quizPoll.options.map { it.text },
|
||||
correctOptionId: Int = quizPoll.correctOptionId ?: error("Correct option ID must be provided by income QuizPoll or by developer"),
|
||||
isAnonymous: Boolean = quizPoll.isAnonymous,
|
||||
explanation: String? = null,
|
||||
parseMode: ParseMode? = null,
|
||||
closeInfo: ScheduledCloseInfo? = null,
|
||||
disableNotification: Boolean = false,
|
||||
replyToMessageId: MessageIdentifier? = null,
|
||||
replyMarkup: KeyboardMarkup? = null
|
||||
) = execute(
|
||||
SendQuizPoll(
|
||||
chatId, question, options, correctOptionId, isAnonymous, isClosed, disableNotification, replyToMessageId, replyMarkup
|
||||
chatId, question, options, correctOptionId, isAnonymous, isClosed, explanation, parseMode, closeInfo, disableNotification, replyToMessageId, replyMarkup
|
||||
)
|
||||
)
|
||||
|
||||
@@ -127,9 +140,12 @@ suspend fun RequestsExecutor.sendQuizPoll(
|
||||
options: List<String> = quizPoll.options.map { it.text },
|
||||
correctOptionId: Int = quizPoll.correctOptionId ?: error("Correct option ID must be provided by income QuizPoll or by developer"),
|
||||
isAnonymous: Boolean = quizPoll.isAnonymous,
|
||||
explanation: String? = null,
|
||||
parseMode: ParseMode? = null,
|
||||
closeInfo: ScheduledCloseInfo? = null,
|
||||
disableNotification: Boolean = false,
|
||||
replyToMessageId: MessageIdentifier? = null,
|
||||
replyMarkup: KeyboardMarkup? = null
|
||||
) = sendQuizPoll(
|
||||
chat.id, question, options, correctOptionId, isAnonymous, isClosed, disableNotification, replyToMessageId, replyMarkup
|
||||
chat.id, question, options, correctOptionId, isAnonymous, isClosed, explanation, parseMode, closeInfo, disableNotification, replyToMessageId, replyMarkup
|
||||
)
|
||||
|
||||
@@ -11,7 +11,7 @@ import com.github.insanusmokrassar.TelegramBotAPI.types.update.MediaGroupUpdates
|
||||
import com.github.insanusmokrassar.TelegramBotAPI.types.update.abstracts.Update
|
||||
import com.github.insanusmokrassar.TelegramBotAPI.updateshandlers.*
|
||||
import com.github.insanusmokrassar.TelegramBotAPI.utils.PreviewFeature
|
||||
import io.ktor.client.features.HttpRequestTimeoutException
|
||||
import com.github.insanusmokrassar.TelegramBotAPI.utils.handleSafely
|
||||
import kotlinx.coroutines.*
|
||||
|
||||
fun RequestsExecutor.startGettingOfUpdates(
|
||||
@@ -24,42 +24,40 @@ fun RequestsExecutor.startGettingOfUpdates(
|
||||
var lastUpdateIdentifier: UpdateIdentifier? = null
|
||||
|
||||
while (isActive) {
|
||||
try {
|
||||
supervisorScope {
|
||||
val updates = getUpdates(
|
||||
offset = lastUpdateIdentifier?.plus(1),
|
||||
timeout = timeoutSeconds,
|
||||
allowed_updates = allowedUpdates
|
||||
).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
|
||||
}
|
||||
}
|
||||
|
||||
supervisorScope {
|
||||
for (update in updates) {
|
||||
updatesReceiver(update)
|
||||
|
||||
lastUpdateIdentifier = update.lastUpdateIdentifier()
|
||||
}
|
||||
handleSafely(
|
||||
{ e ->
|
||||
exceptionsHandler ?.invoke(e)
|
||||
if (e is RequestException) {
|
||||
delay(1000L)
|
||||
}
|
||||
}
|
||||
) {
|
||||
val updates = getUpdates(
|
||||
offset = lastUpdateIdentifier?.plus(1),
|
||||
timeout = timeoutSeconds,
|
||||
allowed_updates = allowedUpdates
|
||||
).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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -78,4 +78,35 @@ filter.asContentMessagesFlow().onlyTextContentMessages().onEach {
|
||||
)
|
||||
```
|
||||
|
||||
As a result, each received message which will be just text message will be printed out with full list of its internal entities
|
||||
As a result, each received message which will be just text message will be printed out with full list of its internal entities
|
||||
|
||||
## Shortcuts
|
||||
|
||||
With shortcuts you are able to use simple factories for several things.
|
||||
|
||||
### ScheduledCloseInfo
|
||||
|
||||
In case if you are creating some poll, you able to use next shortcuts.
|
||||
|
||||
Next sample will use info with closing at the 10 seconds after now:
|
||||
|
||||
```kotlin
|
||||
closePollExactAt(DateTime.now() + TimeSpan(10000.0))
|
||||
```
|
||||
|
||||
In this example we will do the same, but in another way:
|
||||
|
||||
```kotlin
|
||||
closePollExactAfter(10)
|
||||
```
|
||||
|
||||
Here we have passed `10` seconds and will get the same result object.
|
||||
|
||||
In opposite to previous shortcuts, the next one will create `approximate` closing schedule:
|
||||
|
||||
```kotlin
|
||||
closePollAfter(10)
|
||||
```
|
||||
|
||||
The main difference here is that the last one will be closed after 10 seconds since the sending. With first samples
|
||||
will be created **exact** time for closing of poll
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
package com.github.insanusmokrassar.TelegramBotAPI.extensions.utils.shortcuts
|
||||
|
||||
import com.github.insanusmokrassar.TelegramBotAPI.types.LongSeconds
|
||||
import com.github.insanusmokrassar.TelegramBotAPI.types.Seconds
|
||||
import com.github.insanusmokrassar.TelegramBotAPI.types.polls.ApproximateScheduledCloseInfo
|
||||
import com.github.insanusmokrassar.TelegramBotAPI.types.polls.ExactScheduledCloseInfo
|
||||
import com.soywiz.klock.DateTime
|
||||
import com.soywiz.klock.TimeSpan
|
||||
|
||||
fun closePollExactAt(
|
||||
dateTime: DateTime
|
||||
) = ExactScheduledCloseInfo(
|
||||
dateTime
|
||||
)
|
||||
|
||||
fun closePollExactAfter(
|
||||
seconds: LongSeconds
|
||||
) = closePollExactAt(
|
||||
DateTime.now() + TimeSpan(seconds.toDouble() * 1000L)
|
||||
)
|
||||
fun closePollExactAfter(
|
||||
seconds: Seconds
|
||||
) = closePollExactAfter(
|
||||
seconds.toLong()
|
||||
)
|
||||
|
||||
fun closePollAfter(
|
||||
seconds: LongSeconds
|
||||
) = ApproximateScheduledCloseInfo(
|
||||
TimeSpan(seconds.toDouble() * 1000L)
|
||||
)
|
||||
|
||||
fun closePollAfter(
|
||||
seconds: Seconds
|
||||
) = closePollAfter(seconds.toLong())
|
||||
@@ -2,7 +2,7 @@ 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.MediaGroupUpdates.SentMediaGroupUpdate
|
||||
import com.github.insanusmokrassar.TelegramBotAPI.types.update.abstracts.BaseMessageUpdate
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.filter
|
||||
|
||||
@@ -10,7 +10,7 @@ moments are describing by official [Telegram Bot API](https://core.telegram.org/
|
||||
|
||||
## Compatibility
|
||||
|
||||
This version compatible with [30th of March 2020 update of TelegramBotAPI (version 4.7)](https://core.telegram.org/bots/api#march-30-2020).
|
||||
This version compatible with [24th of April 2020 update of TelegramBotAPI (version 4.8)](https://core.telegram.org/bots/api#april-24-2020).
|
||||
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
|
||||
as soon as possible.
|
||||
|
||||
@@ -15,4 +15,4 @@ interface CaptionedInput : Captioned {
|
||||
val captionEntities: List<TextPart>
|
||||
}
|
||||
|
||||
fun CaptionedInput.fullEntitiesList() = caption ?.fullListOfSubSource(captionEntities) ?.map { it.source } ?: emptyList()
|
||||
fun CaptionedInput.fullEntitiesList(): FullTextSourcesList = caption ?.fullListOfSubSource(captionEntities) ?.map { it.source } ?: emptyList()
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
package com.github.insanusmokrassar.TelegramBotAPI.CommonAbstracts
|
||||
|
||||
import com.github.insanusmokrassar.TelegramBotAPI.types.ParseMode.ParseMode
|
||||
import com.github.insanusmokrassar.TelegramBotAPI.utils.fullListOfSubSource
|
||||
|
||||
interface Explained {
|
||||
val explanation: String?
|
||||
}
|
||||
|
||||
interface ExplainedOutput : Explained {
|
||||
val parseMode: ParseMode?
|
||||
}
|
||||
|
||||
interface ExplainedInput : Explained {
|
||||
val explanationEntities: List<TextPart>
|
||||
}
|
||||
|
||||
fun ExplainedInput.fullEntitiesList(): FullTextSourcesList = explanation ?.fullListOfSubSource(explanationEntities) ?.map { it.source } ?: emptyList()
|
||||
@@ -1,5 +1,8 @@
|
||||
package com.github.insanusmokrassar.TelegramBotAPI.CommonAbstracts
|
||||
|
||||
typealias FullTextSourcesList = List<TextSource>
|
||||
typealias FullTextPartsList = List<TextPart>
|
||||
|
||||
interface TextSource {
|
||||
val asMarkdownSource: String
|
||||
val asMarkdownV2Source: String
|
||||
@@ -16,3 +19,5 @@ data class TextPart(
|
||||
val range: IntRange,
|
||||
val source: TextSource
|
||||
)
|
||||
|
||||
fun List<TextPart>.justTextSources() = map { it.source }
|
||||
|
||||
@@ -9,15 +9,13 @@ import com.github.insanusmokrassar.TelegramBotAPI.bot.settings.limiters.RequestL
|
||||
import com.github.insanusmokrassar.TelegramBotAPI.requests.abstracts.Request
|
||||
import com.github.insanusmokrassar.TelegramBotAPI.types.Response
|
||||
import com.github.insanusmokrassar.TelegramBotAPI.types.RetryAfterError
|
||||
import com.github.insanusmokrassar.TelegramBotAPI.utils.TelegramAPIUrlsKeeper
|
||||
import com.github.insanusmokrassar.TelegramBotAPI.utils.nonstrictJsonFormat
|
||||
import com.github.insanusmokrassar.TelegramBotAPI.utils.*
|
||||
import io.ktor.client.HttpClient
|
||||
import io.ktor.client.call.receive
|
||||
import io.ktor.client.features.*
|
||||
import io.ktor.client.statement.HttpStatement
|
||||
import io.ktor.client.statement.readText
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.supervisorScope
|
||||
import kotlinx.serialization.json.Json
|
||||
|
||||
class KtorRequestsExecutor(
|
||||
@@ -43,54 +41,56 @@ class KtorRequestsExecutor(
|
||||
}
|
||||
|
||||
override suspend fun <T : Any> execute(request: Request<T>): T {
|
||||
return try {
|
||||
supervisorScope {
|
||||
requestsLimiter.limit {
|
||||
var statement: HttpStatement? = null
|
||||
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>()
|
||||
return handleSafely(
|
||||
{ e ->
|
||||
throw if (e is ClientRequestException) {
|
||||
val content = e.response.readText()
|
||||
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"
|
||||
)
|
||||
})
|
||||
newRequestException(
|
||||
responseObject,
|
||||
content,
|
||||
"Can't get result object from $content"
|
||||
)
|
||||
} else {
|
||||
e
|
||||
}
|
||||
}
|
||||
} catch (e: ClientRequestException) {
|
||||
val content = e.response.readText()
|
||||
val responseObject = jsonFormatter.parse(Response.serializer(), content)
|
||||
throw newRequestException(
|
||||
responseObject,
|
||||
content,
|
||||
"Can't get result object from $content"
|
||||
)
|
||||
} catch (e: Exception) {
|
||||
throw e
|
||||
) {
|
||||
requestsLimiter.limit {
|
||||
var statement: HttpStatement? = null
|
||||
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)
|
||||
|
||||
(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"
|
||||
)
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -3,12 +3,12 @@ package com.github.insanusmokrassar.TelegramBotAPI.requests
|
||||
import com.github.insanusmokrassar.TelegramBotAPI.requests.abstracts.SimpleRequest
|
||||
import com.github.insanusmokrassar.TelegramBotAPI.types.*
|
||||
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.builtins.ListSerializer
|
||||
|
||||
private val updatesListSerializer = ListSerializer(
|
||||
UpdateSerializerWithoutDeserialization
|
||||
UpdateSerializerWithoutSerialization
|
||||
)
|
||||
|
||||
@Serializable
|
||||
|
||||
@@ -5,6 +5,7 @@ import com.github.insanusmokrassar.TelegramBotAPI.CommonAbstracts.types.ReplyMes
|
||||
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.dice.DiceAnimationType
|
||||
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
|
||||
@@ -17,6 +18,8 @@ internal val DiceContentMessageResultDeserializer: DeserializationStrategy<Conte
|
||||
data class SendDice(
|
||||
@SerialName(chatIdField)
|
||||
override val chatId: ChatIdentifier,
|
||||
@SerialName(emojiField)
|
||||
val animationType: DiceAnimationType? = null,
|
||||
@SerialName(disableNotificationField)
|
||||
override val disableNotification: Boolean = false,
|
||||
@SerialName(replyToMessageIdField)
|
||||
|
||||
@@ -1,13 +1,19 @@
|
||||
package com.github.insanusmokrassar.TelegramBotAPI.requests.send.polls
|
||||
|
||||
import com.github.insanusmokrassar.TelegramBotAPI.CommonAbstracts.*
|
||||
import com.github.insanusmokrassar.TelegramBotAPI.requests.send.abstracts.ReplyingMarkupSendMessageRequest
|
||||
import com.github.insanusmokrassar.TelegramBotAPI.requests.send.abstracts.SendMessageRequest
|
||||
import com.github.insanusmokrassar.TelegramBotAPI.types.*
|
||||
import com.github.insanusmokrassar.TelegramBotAPI.types.ParseMode.MarkdownV2
|
||||
import com.github.insanusmokrassar.TelegramBotAPI.types.ParseMode.ParseMode
|
||||
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.PollContent
|
||||
import com.github.insanusmokrassar.TelegramBotAPI.types.polls.*
|
||||
import com.github.insanusmokrassar.TelegramBotAPI.utils.fullListOfSubSource
|
||||
import com.github.insanusmokrassar.TelegramBotAPI.utils.toMarkdownV2Captions
|
||||
import com.soywiz.klock.DateTime
|
||||
import kotlinx.serialization.*
|
||||
|
||||
private val commonResultDeserializer: DeserializationStrategy<ContentMessage<PollContent>> = TelegramBotAPIMessageDeserializationStrategyClass()
|
||||
@@ -66,6 +72,7 @@ fun Poll.createRequest(
|
||||
isAnonymous,
|
||||
isClosed,
|
||||
allowMultipleAnswers,
|
||||
scheduledCloseInfo,
|
||||
disableNotification,
|
||||
replyToMessageId,
|
||||
replyMarkup
|
||||
@@ -78,6 +85,9 @@ fun Poll.createRequest(
|
||||
correctOptionId,
|
||||
isAnonymous,
|
||||
isClosed,
|
||||
caption ?.fullListOfSubSource(captionEntities) ?.justTextSources() ?.toMarkdownV2Captions() ?.firstOrNull(),
|
||||
MarkdownV2,
|
||||
scheduledCloseInfo,
|
||||
disableNotification,
|
||||
replyToMessageId,
|
||||
replyMarkup
|
||||
@@ -89,6 +99,7 @@ fun Poll.createRequest(
|
||||
isAnonymous,
|
||||
isClosed,
|
||||
false,
|
||||
scheduledCloseInfo,
|
||||
disableNotification,
|
||||
replyToMessageId,
|
||||
replyMarkup
|
||||
@@ -100,20 +111,35 @@ fun Poll.createRequest(
|
||||
isAnonymous,
|
||||
isClosed,
|
||||
false,
|
||||
scheduledCloseInfo,
|
||||
disableNotification,
|
||||
replyToMessageId,
|
||||
replyMarkup
|
||||
)
|
||||
}
|
||||
|
||||
private fun ScheduledCloseInfo.checkSendData() {
|
||||
val span = when (this) {
|
||||
is ExactScheduledCloseInfo -> (closeDateTime - DateTime.now()).seconds
|
||||
is ApproximateScheduledCloseInfo -> openDuration.seconds
|
||||
}.toInt()
|
||||
if (span !in openPeriodPollSecondsLimit) {
|
||||
error("Duration of autoclose for polls must be in range $openPeriodPollSecondsLimit, but was $span")
|
||||
}
|
||||
}
|
||||
|
||||
sealed class SendPoll : SendMessageRequest<ContentMessage<PollContent>>,
|
||||
ReplyingMarkupSendMessageRequest<ContentMessage<PollContent>> {
|
||||
abstract val question: String
|
||||
abstract val options: List<String>
|
||||
abstract val isAnonymous: Boolean
|
||||
abstract val isClosed: Boolean
|
||||
abstract val closeInfo: ScheduledCloseInfo?
|
||||
abstract val type: String
|
||||
|
||||
internal abstract val openPeriod: LongSeconds?
|
||||
internal abstract val closeDate: LongSeconds?
|
||||
|
||||
override fun method(): String = "sendPoll"
|
||||
override val resultDeserializer: DeserializationStrategy<ContentMessage<PollContent>>
|
||||
get() = commonResultDeserializer
|
||||
@@ -133,6 +159,8 @@ data class SendRegularPoll(
|
||||
override val isClosed: Boolean = false,
|
||||
@SerialName(allowsMultipleAnswersField)
|
||||
val allowMultipleAnswers: Boolean = false,
|
||||
@Transient
|
||||
override val closeInfo: ScheduledCloseInfo? = null,
|
||||
@SerialName(disableNotificationField)
|
||||
override val disableNotification: Boolean = false,
|
||||
@SerialName(replyToMessageIdField)
|
||||
@@ -144,8 +172,17 @@ data class SendRegularPoll(
|
||||
override val requestSerializer: SerializationStrategy<*>
|
||||
get() = serializer()
|
||||
|
||||
@SerialName(openPeriodField)
|
||||
override val openPeriod: LongSeconds?
|
||||
= (closeInfo as? ApproximateScheduledCloseInfo) ?.openDuration ?.millisecondsLong ?.div(1000)
|
||||
|
||||
@SerialName(closeDateField)
|
||||
override val closeDate: LongSeconds?
|
||||
= (closeInfo as? ExactScheduledCloseInfo) ?.closeDateTime ?.unixMillisLong ?.div(1000)
|
||||
|
||||
init {
|
||||
checkPollInfo(question, options)
|
||||
closeInfo ?.checkSendData()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -163,23 +200,46 @@ data class SendQuizPoll(
|
||||
override val isAnonymous: Boolean = true,
|
||||
@SerialName(isClosedField)
|
||||
override val isClosed: Boolean = false,
|
||||
@SerialName(explanationField)
|
||||
override val explanation: String? = null,
|
||||
@SerialName(explanationParseModeField)
|
||||
override val parseMode: ParseMode? = null,
|
||||
@Transient
|
||||
override val closeInfo: ScheduledCloseInfo? = null,
|
||||
@SerialName(disableNotificationField)
|
||||
override val disableNotification: Boolean = false,
|
||||
@SerialName(replyToMessageIdField)
|
||||
override val replyToMessageId: MessageIdentifier? = null,
|
||||
@SerialName(replyMarkupField)
|
||||
override val replyMarkup: KeyboardMarkup? = null
|
||||
) : SendPoll() {
|
||||
) : SendPoll(), CaptionedOutput, ExplainedOutput {
|
||||
override val type: String = quizPollType
|
||||
override val requestSerializer: SerializationStrategy<*>
|
||||
get() = serializer()
|
||||
|
||||
@Deprecated("Will be removed in near updates", ReplaceWith("explanation"))
|
||||
override val caption: String?
|
||||
get() = explanation
|
||||
|
||||
@SerialName(openPeriodField)
|
||||
override val openPeriod: LongSeconds?
|
||||
= (closeInfo as? ApproximateScheduledCloseInfo) ?.openDuration ?.millisecondsLong ?.div(1000)
|
||||
|
||||
@SerialName(closeDateField)
|
||||
override val closeDate: LongSeconds?
|
||||
= (closeInfo as? ExactScheduledCloseInfo) ?.closeDateTime ?.unixMillisLong ?.div(1000)
|
||||
|
||||
init {
|
||||
checkPollInfo(question, options)
|
||||
closeInfo ?.checkSendData()
|
||||
val correctOptionIdRange = 0 .. options.size
|
||||
if (correctOptionId !in correctOptionIdRange) {
|
||||
throw IllegalArgumentException("Correct option id must be in range of $correctOptionIdRange, but actual " +
|
||||
"value is $correctOptionId")
|
||||
}
|
||||
if (explanation != null && explanation.length !in explanationLimit) {
|
||||
error("Quiz poll explanation size must be in range $explanationLimit," +
|
||||
"but actual explanation contains ${explanation.length} symbols")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,6 +22,7 @@ typealias FileUniqueId = String
|
||||
typealias DiceResult = Int
|
||||
|
||||
typealias Seconds = Int
|
||||
typealias LongSeconds = Long
|
||||
|
||||
val getUpdatesLimit = 1 .. 100
|
||||
val callbackQueryAnswerLength = 0 until 200
|
||||
@@ -54,6 +55,12 @@ val botCommandLimit = botCommandLengthLimit
|
||||
val botCommandDescriptionLimit = 3 .. 256
|
||||
val botCommandsLimit = 0 .. 100
|
||||
|
||||
val explanationLimit = 0 .. 200
|
||||
@Deprecated("Will be removed in near updates", ReplaceWith("explanationLimit"))
|
||||
val quizPollExplanationLimit = explanationLimit
|
||||
|
||||
val openPeriodPollSecondsLimit = 5 .. 600
|
||||
|
||||
const val chatIdField = "chat_id"
|
||||
const val messageIdField = "message_id"
|
||||
const val updateIdField = "update_id"
|
||||
@@ -82,6 +89,7 @@ const val containsMasksField = "contains_masks"
|
||||
const val resultIdField = "result_id"
|
||||
const val inlineMessageIdField = "inline_message_id"
|
||||
const val callbackDataField = "callback_data"
|
||||
const val callbackGameField = "callback_game"
|
||||
const val callbackQueryIdField = "callback_query_id"
|
||||
const val inlineQueryIdField = "inline_query_id"
|
||||
const val inlineKeyboardField = "inline_keyboard"
|
||||
@@ -198,6 +206,7 @@ const val tgsStickerField = "tgs_sticker"
|
||||
|
||||
const val okField = "ok"
|
||||
const val captionField = "caption"
|
||||
const val explanationField = "explanation"
|
||||
const val idField = "id"
|
||||
const val pollIdField = "poll_id"
|
||||
const val textField = "text"
|
||||
@@ -249,6 +258,10 @@ const val xShiftField = "x_shift"
|
||||
const val yShiftField = "y_shift"
|
||||
const val scaleField = "scale"
|
||||
|
||||
const val explanationEntitiesField = "explanation_entities"
|
||||
const val explanationParseModeField = "explanation_parse_mode"
|
||||
const val openPeriodField = "open_period"
|
||||
const val closeDateField = "close_date"
|
||||
|
||||
const val smallFileIdField = "small_file_id"
|
||||
const val bigFileIdField = "big_file_id"
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
package com.github.insanusmokrassar.TelegramBotAPI.types
|
||||
|
||||
import kotlinx.serialization.SerialName
|
||||
import kotlinx.serialization.Serializable
|
||||
import com.github.insanusmokrassar.TelegramBotAPI.types.dice.Dice
|
||||
|
||||
@Serializable
|
||||
data class Dice(
|
||||
@SerialName(valueField)
|
||||
val value: DiceResult
|
||||
@Deprecated(
|
||||
"Replaced",
|
||||
ReplaceWith("Dice", "com.github.insanusmokrassar.TelegramBotAPI.types.dice.Dice")
|
||||
)
|
||||
typealias Dice = Dice
|
||||
|
||||
@@ -83,6 +83,28 @@ internal fun createTextPart(from: String, entities: RawMessageEntities): List<Te
|
||||
return resultList
|
||||
}
|
||||
|
||||
internal fun List<TextPart>.asRawMessageEntities() = mapNotNull {
|
||||
val source = it.source
|
||||
when (source) {
|
||||
is MentionTextSource -> RawMessageEntity("mention", it.range.first, it.range.last - it.range.first)
|
||||
is HashTagTextSource -> RawMessageEntity("hashtag", it.range.first, it.range.last - it.range.first)
|
||||
is CashTagTextSource -> RawMessageEntity("cashtag", it.range.first, it.range.last - it.range.first)
|
||||
is BotCommandTextSource -> RawMessageEntity("bot_command", it.range.first, it.range.last - it.range.first)
|
||||
is URLTextSource -> RawMessageEntity("url", it.range.first, it.range.last - it.range.first)
|
||||
is EMailTextSource -> RawMessageEntity("email", it.range.first, it.range.last - it.range.first)
|
||||
is PhoneNumberTextSource -> RawMessageEntity("phone_number", it.range.first, it.range.last - it.range.first)
|
||||
is BoldTextSource -> RawMessageEntity("bold", it.range.first, it.range.last - it.range.first)
|
||||
is ItalicTextSource -> RawMessageEntity("italic", it.range.first, it.range.last - it.range.first)
|
||||
is CodeTextSource -> RawMessageEntity("code", it.range.first, it.range.last - it.range.first)
|
||||
is PreTextSource -> RawMessageEntity("pre", it.range.first, it.range.last - it.range.first, language = source.language)
|
||||
is TextLinkTextSource -> RawMessageEntity("text_link", it.range.first, it.range.last - it.range.first, source.url)
|
||||
is TextMentionTextSource -> RawMessageEntity("text_mention", it.range.first, it.range.last - it.range.first, user = source.user)
|
||||
is UnderlineTextSource -> RawMessageEntity("underline", it.range.first, it.range.last - it.range.first)
|
||||
is StrikethroughTextSource -> RawMessageEntity("strikethrough", it.range.first, it.range.last - it.range.first)
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
|
||||
internal fun RawMessageEntities.asTextParts(sourceString: String): List<TextPart> = createTextPart(sourceString, this)
|
||||
|
||||
internal typealias RawMessageEntities = List<RawMessageEntity>
|
||||
|
||||
@@ -5,7 +5,7 @@ import com.github.insanusmokrassar.TelegramBotAPI.utils.*
|
||||
|
||||
class TextLinkTextSource(
|
||||
override val source: String,
|
||||
url: String
|
||||
val url: String
|
||||
) : TextSource {
|
||||
override val asMarkdownSource: String by lazy { source.linkMarkdown(url) }
|
||||
override val asMarkdownV2Source: String by lazy { source.linkMarkdownV2(url) }
|
||||
|
||||
@@ -2,16 +2,16 @@ package com.github.insanusmokrassar.TelegramBotAPI.types.MessageEntity.textsourc
|
||||
|
||||
import com.github.insanusmokrassar.TelegramBotAPI.CommonAbstracts.MultilevelTextSource
|
||||
import com.github.insanusmokrassar.TelegramBotAPI.CommonAbstracts.TextPart
|
||||
import com.github.insanusmokrassar.TelegramBotAPI.types.chat.abstracts.PrivateChat
|
||||
import com.github.insanusmokrassar.TelegramBotAPI.types.User
|
||||
import com.github.insanusmokrassar.TelegramBotAPI.utils.*
|
||||
|
||||
class TextMentionTextSource(
|
||||
override val source: String,
|
||||
privateChat: PrivateChat,
|
||||
val user: User,
|
||||
textParts: List<TextPart>
|
||||
) : MultilevelTextSource {
|
||||
override val textParts: List<TextPart> by lazy { source.fullListOfSubSource(textParts) }
|
||||
override val asMarkdownSource: String by lazy { source.textMentionMarkdown(privateChat.id) }
|
||||
override val asMarkdownV2Source: String by lazy { textMentionMarkdownV2(privateChat.id) }
|
||||
override val asHtmlSource: String by lazy { textMentionHTML(privateChat.id) }
|
||||
override val asMarkdownSource: String by lazy { source.textMentionMarkdown(user.id) }
|
||||
override val asMarkdownV2Source: String by lazy { textMentionMarkdownV2(user.id) }
|
||||
override val asHtmlSource: String by lazy { textMentionHTML(user.id) }
|
||||
}
|
||||
|
||||
@@ -1,14 +1,22 @@
|
||||
package com.github.insanusmokrassar.TelegramBotAPI.types.buttons.InlineKeyboardButtons
|
||||
|
||||
import com.github.insanusmokrassar.TelegramBotAPI.types.*
|
||||
import com.github.insanusmokrassar.TelegramBotAPI.types.games.CallbackGame
|
||||
import kotlinx.serialization.SerialName
|
||||
import kotlinx.serialization.Serializable
|
||||
import kotlinx.serialization.json.JsonElement
|
||||
|
||||
@Serializable(InlineKeyboardButtonSerializer::class)
|
||||
sealed class InlineKeyboardButton {
|
||||
abstract val text: String
|
||||
}
|
||||
|
||||
@Serializable
|
||||
data class UnknownInlineKeyboardButton internal constructor(
|
||||
override val text: String,
|
||||
val rawData: JsonElement
|
||||
) : InlineKeyboardButton()
|
||||
|
||||
@Serializable
|
||||
data class PayInlineKeyboardButton(
|
||||
override val text: String,
|
||||
@@ -24,6 +32,15 @@ data class CallbackDataInlineKeyboardButton(
|
||||
val callbackData: String
|
||||
) : InlineKeyboardButton()
|
||||
|
||||
@Serializable
|
||||
data class CallbackGameInlineKeyboardButton(
|
||||
@SerialName(textField)
|
||||
override val text: String
|
||||
) : InlineKeyboardButton() {
|
||||
@SerialName(callbackGameField)
|
||||
private val callbackGame = CallbackGame
|
||||
}
|
||||
|
||||
@Serializable
|
||||
data class LoginURLInlineKeyboardButton(
|
||||
override val text: String,
|
||||
|
||||
@@ -12,22 +12,25 @@ internal object InlineKeyboardButtonSerializer : KSerializer<InlineKeyboardButto
|
||||
PolymorphicKind.SEALED
|
||||
)
|
||||
|
||||
private fun resolveSerializer(json: JsonObject): KSerializer<out InlineKeyboardButton> {
|
||||
private fun resolveSerializer(json: JsonObject): KSerializer<out InlineKeyboardButton>? {
|
||||
return when {
|
||||
json[callbackDataField] != null -> CallbackDataInlineKeyboardButton.serializer()
|
||||
json[callbackGameField] != null -> CallbackGameInlineKeyboardButton.serializer()
|
||||
json[loginUrlField] != null -> LoginURLInlineKeyboardButton.serializer()
|
||||
json[payField] != null -> PayInlineKeyboardButton.serializer()
|
||||
json[switchInlineQueryField] != null -> SwitchInlineQueryInlineKeyboardButton.serializer()
|
||||
json[switchInlineQueryCurrentChatField] != null -> SwitchInlineQueryCurrentChatInlineKeyboardButton.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 {
|
||||
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) {
|
||||
@@ -38,6 +41,8 @@ internal object InlineKeyboardButtonSerializer : KSerializer<InlineKeyboardButto
|
||||
is SwitchInlineQueryInlineKeyboardButton -> SwitchInlineQueryInlineKeyboardButton.serializer().serialize(encoder, value)
|
||||
is SwitchInlineQueryCurrentChatInlineKeyboardButton -> SwitchInlineQueryCurrentChatInlineKeyboardButton.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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
package com.github.insanusmokrassar.TelegramBotAPI.types.dice
|
||||
|
||||
import com.github.insanusmokrassar.TelegramBotAPI.types.*
|
||||
import kotlinx.serialization.SerialName
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
@Serializable
|
||||
data class Dice(
|
||||
@SerialName(valueField)
|
||||
val value: DiceResult,
|
||||
@SerialName(emojiField)
|
||||
val animationType: DiceAnimationType
|
||||
)
|
||||
@@ -0,0 +1,36 @@
|
||||
package com.github.insanusmokrassar.TelegramBotAPI.types.dice
|
||||
|
||||
import kotlinx.serialization.*
|
||||
|
||||
@Serializable(DiceAnimationTypeSerializer::class)
|
||||
sealed class DiceAnimationType {
|
||||
abstract val emoji: String
|
||||
}
|
||||
@Serializable(DiceAnimationTypeSerializer::class)
|
||||
object CubeDiceAnimationType : DiceAnimationType() {
|
||||
override val emoji: String = "\uD83C\uDFB2"
|
||||
}
|
||||
@Serializable(DiceAnimationTypeSerializer::class)
|
||||
object DartsDiceAnimationType : DiceAnimationType() {
|
||||
override val emoji: String = "\uD83C\uDFAF"
|
||||
}
|
||||
@Serializable(DiceAnimationTypeSerializer::class)
|
||||
class UnknownDiceAnimationType(
|
||||
override val emoji: String
|
||||
) : DiceAnimationType()
|
||||
|
||||
@Serializer(DiceAnimationType::class)
|
||||
internal object DiceAnimationTypeSerializer : KSerializer<DiceAnimationType> {
|
||||
override val descriptor: SerialDescriptor = PrimitiveDescriptor("DiceAnimationType", PrimitiveKind.STRING)
|
||||
override fun deserialize(decoder: Decoder): DiceAnimationType {
|
||||
return when (val type = decoder.decodeString()) {
|
||||
CubeDiceAnimationType.emoji -> CubeDiceAnimationType
|
||||
DartsDiceAnimationType.emoji -> DartsDiceAnimationType
|
||||
else -> UnknownDiceAnimationType(type)
|
||||
}
|
||||
}
|
||||
|
||||
override fun serialize(encoder: Encoder, value: DiceAnimationType) {
|
||||
encoder.encodeString(value.emoji)
|
||||
}
|
||||
}
|
||||
@@ -3,8 +3,4 @@ package com.github.insanusmokrassar.TelegramBotAPI.types.games
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
@Serializable
|
||||
class CallbackGame {
|
||||
init {
|
||||
TODO()
|
||||
}
|
||||
}
|
||||
object CallbackGame
|
||||
|
||||
@@ -5,6 +5,7 @@ import com.github.insanusmokrassar.TelegramBotAPI.types.MessageEntity.RawMessage
|
||||
import com.github.insanusmokrassar.TelegramBotAPI.types.MessageEntity.asTextParts
|
||||
import com.github.insanusmokrassar.TelegramBotAPI.types.buttons.InlineKeyboardMarkup
|
||||
import com.github.insanusmokrassar.TelegramBotAPI.types.chat.abstracts.*
|
||||
import com.github.insanusmokrassar.TelegramBotAPI.types.dice.Dice
|
||||
import com.github.insanusmokrassar.TelegramBotAPI.types.files.*
|
||||
import com.github.insanusmokrassar.TelegramBotAPI.types.games.RawGame
|
||||
import com.github.insanusmokrassar.TelegramBotAPI.types.message.ChatEvents.*
|
||||
|
||||
@@ -2,8 +2,10 @@ 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.ChatIdentifier
|
||||
import com.github.insanusmokrassar.TelegramBotAPI.types.MessageIdentifier
|
||||
import com.github.insanusmokrassar.TelegramBotAPI.types.buttons.KeyboardMarkup
|
||||
import com.github.insanusmokrassar.TelegramBotAPI.types.dice.Dice
|
||||
import com.github.insanusmokrassar.TelegramBotAPI.types.message.abstracts.ContentMessage
|
||||
import com.github.insanusmokrassar.TelegramBotAPI.types.message.content.abstracts.MessageContent
|
||||
|
||||
@@ -15,5 +17,11 @@ data class DiceContent(
|
||||
disableNotification: Boolean,
|
||||
replyToMessageId: MessageIdentifier?,
|
||||
replyMarkup: KeyboardMarkup?
|
||||
): Request<ContentMessage<DiceContent>> = SendDice(chatId, disableNotification, replyToMessageId, replyMarkup)
|
||||
): Request<ContentMessage<DiceContent>> = SendDice(
|
||||
chatId,
|
||||
dice.animationType,
|
||||
disableNotification,
|
||||
replyToMessageId,
|
||||
replyMarkup
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package com.github.insanusmokrassar.TelegramBotAPI.types.message.content
|
||||
|
||||
import com.github.insanusmokrassar.TelegramBotAPI.CommonAbstracts.FullTextSourcesList
|
||||
import com.github.insanusmokrassar.TelegramBotAPI.CommonAbstracts.TextPart
|
||||
import com.github.insanusmokrassar.TelegramBotAPI.requests.abstracts.Request
|
||||
import com.github.insanusmokrassar.TelegramBotAPI.requests.send.SendTextMessage
|
||||
@@ -66,4 +67,4 @@ data class TextContent(
|
||||
}
|
||||
}
|
||||
|
||||
fun TextContent.fullEntitiesList() = text.fullListOfSubSource(entities).map { it.source }
|
||||
fun TextContent.fullEntitiesList(): FullTextSourcesList = text.fullListOfSubSource(entities).map { it.source }
|
||||
|
||||
@@ -1,10 +1,39 @@
|
||||
package com.github.insanusmokrassar.TelegramBotAPI.types.polls
|
||||
|
||||
import com.github.insanusmokrassar.TelegramBotAPI.CommonAbstracts.*
|
||||
import com.github.insanusmokrassar.TelegramBotAPI.types.*
|
||||
import com.github.insanusmokrassar.TelegramBotAPI.types.MessageEntity.*
|
||||
import com.github.insanusmokrassar.TelegramBotAPI.utils.nonstrictJsonFormat
|
||||
import com.soywiz.klock.DateTime
|
||||
import com.soywiz.klock.TimeSpan
|
||||
import kotlinx.serialization.*
|
||||
import kotlinx.serialization.builtins.ListSerializer
|
||||
import kotlinx.serialization.json.*
|
||||
import kotlinx.serialization.json.JsonObject
|
||||
import kotlinx.serialization.json.JsonObjectSerializer
|
||||
|
||||
sealed class ScheduledCloseInfo {
|
||||
abstract val closeDateTime: DateTime
|
||||
}
|
||||
|
||||
data class ExactScheduledCloseInfo(
|
||||
override val closeDateTime: DateTime
|
||||
) : ScheduledCloseInfo()
|
||||
|
||||
data class ApproximateScheduledCloseInfo(
|
||||
val openDuration: TimeSpan,
|
||||
@Suppress("MemberVisibilityCanBePrivate")
|
||||
val startPoint: DateTime = DateTime.now()
|
||||
) : ScheduledCloseInfo() {
|
||||
override val closeDateTime: DateTime = startPoint + openDuration
|
||||
}
|
||||
|
||||
val LongSeconds.asApproximateScheduledCloseInfo
|
||||
get() = ApproximateScheduledCloseInfo(
|
||||
TimeSpan(this * 1000.0)
|
||||
)
|
||||
val LongSeconds.asExactScheduledCloseInfo
|
||||
get() = ExactScheduledCloseInfo(
|
||||
DateTime(unixMillis = this * 1000.0)
|
||||
)
|
||||
|
||||
@Serializable(PollSerializer::class)
|
||||
sealed class Poll {
|
||||
@@ -14,6 +43,44 @@ sealed class Poll {
|
||||
abstract val votesCount: Int
|
||||
abstract val isClosed: Boolean
|
||||
abstract val isAnonymous: Boolean
|
||||
abstract val scheduledCloseInfo: ScheduledCloseInfo?
|
||||
}
|
||||
|
||||
@Serializable(PollSerializer::class)
|
||||
sealed class MultipleAnswersPoll : Poll()
|
||||
|
||||
@Serializable
|
||||
private class RawPoll(
|
||||
@SerialName(idField)
|
||||
val id: PollIdentifier,
|
||||
@SerialName(questionField)
|
||||
val question: String,
|
||||
@SerialName(optionsField)
|
||||
val options: List<PollOption>,
|
||||
@SerialName(totalVoterCountField)
|
||||
val votesCount: Int,
|
||||
@SerialName(isClosedField)
|
||||
val isClosed: Boolean = false,
|
||||
@SerialName(isAnonymousField)
|
||||
val isAnonymous: Boolean = false,
|
||||
@SerialName(typeField)
|
||||
val type: String,
|
||||
@SerialName(allowsMultipleAnswersField)
|
||||
val allowMultipleAnswers: Boolean = false,
|
||||
@SerialName(correctOptionIdField)
|
||||
val correctOptionId: Int? = null,
|
||||
@SerialName(explanationField)
|
||||
val explanation: String? = null,
|
||||
@SerialName(explanationEntitiesField)
|
||||
val explanationEntities: List<RawMessageEntity> = emptyList(),
|
||||
@SerialName(openPeriodField)
|
||||
val openPeriod: LongSeconds? = null,
|
||||
@SerialName(closeDateField)
|
||||
val closeDate: LongSeconds? = null
|
||||
) {
|
||||
@Transient
|
||||
val scheduledCloseInfo: ScheduledCloseInfo?
|
||||
= closeDate ?.asExactScheduledCloseInfo ?: openPeriod ?.asApproximateScheduledCloseInfo
|
||||
}
|
||||
|
||||
@Serializable
|
||||
@@ -30,91 +97,131 @@ data class UnknownPollType internal constructor(
|
||||
override val isClosed: Boolean = false,
|
||||
@SerialName(isAnonymousField)
|
||||
override val isAnonymous: Boolean = false,
|
||||
val raw: String
|
||||
) : Poll()
|
||||
@Serializable
|
||||
val raw: JsonObject
|
||||
) : Poll() {
|
||||
@Transient
|
||||
override val scheduledCloseInfo: ScheduledCloseInfo? = raw.getPrimitiveOrNull(
|
||||
closeDateField
|
||||
) ?.longOrNull ?.asExactScheduledCloseInfo ?: raw.getPrimitiveOrNull(
|
||||
openPeriodField
|
||||
) ?.longOrNull ?.asApproximateScheduledCloseInfo
|
||||
}
|
||||
|
||||
@Serializable
|
||||
@Serializable(PollSerializer::class)
|
||||
data class RegularPoll(
|
||||
@SerialName(idField)
|
||||
override val id: PollIdentifier,
|
||||
@SerialName(questionField)
|
||||
override val question: String,
|
||||
@SerialName(optionsField)
|
||||
override val options: List<PollOption>,
|
||||
@SerialName(totalVoterCountField)
|
||||
override val votesCount: Int,
|
||||
@SerialName(isClosedField)
|
||||
override val isClosed: Boolean = false,
|
||||
@SerialName(isAnonymousField)
|
||||
override val isAnonymous: Boolean = false,
|
||||
@SerialName(allowsMultipleAnswersField)
|
||||
val allowMultipleAnswers: Boolean = false
|
||||
) : Poll()
|
||||
val allowMultipleAnswers: Boolean = false,
|
||||
override val scheduledCloseInfo: ScheduledCloseInfo? = null
|
||||
) : MultipleAnswersPoll()
|
||||
|
||||
@Serializable
|
||||
@Serializable(PollSerializer::class)
|
||||
data class QuizPoll(
|
||||
@SerialName(idField)
|
||||
override val id: PollIdentifier,
|
||||
@SerialName(questionField)
|
||||
override val question: String,
|
||||
@SerialName(optionsField)
|
||||
override val options: List<PollOption>,
|
||||
@SerialName(totalVoterCountField)
|
||||
override val votesCount: Int,
|
||||
/**
|
||||
* Nullable due to documentation (https://core.telegram.org/bots/api#poll)
|
||||
*/
|
||||
@SerialName(correctOptionIdField)
|
||||
val correctOptionId: Int? = null,
|
||||
@SerialName(isClosedField)
|
||||
override val explanation: String? = null,
|
||||
override val explanationEntities: List<TextPart> = emptyList(),
|
||||
override val isClosed: Boolean = false,
|
||||
@SerialName(isAnonymousField)
|
||||
override val isAnonymous: Boolean = false
|
||||
) : Poll()
|
||||
override val isAnonymous: Boolean = false,
|
||||
override val scheduledCloseInfo: ScheduledCloseInfo? = null
|
||||
) : Poll(), CaptionedInput, ExplainedInput {
|
||||
@Deprecated("Will be removed in near updates", ReplaceWith("explanation"))
|
||||
override val caption: String?
|
||||
get() = explanation
|
||||
@Deprecated("Will be removed in near updates", ReplaceWith("explanationEntities"))
|
||||
override val captionEntities: List<TextPart>
|
||||
get() = explanationEntities
|
||||
}
|
||||
|
||||
@Serializer(Poll::class)
|
||||
internal object PollSerializer : KSerializer<Poll> {
|
||||
private val pollOptionsSerializer = ListSerializer(PollOption.serializer())
|
||||
override val descriptor: SerialDescriptor
|
||||
get() = RawPoll.serializer().descriptor
|
||||
|
||||
override fun deserialize(decoder: Decoder): Poll {
|
||||
val asJson = JsonObjectSerializer.deserialize(decoder)
|
||||
val rawPoll = nonstrictJsonFormat.fromJson(RawPoll.serializer(), asJson)
|
||||
|
||||
return when (asJson.getPrimitive(typeField).content) {
|
||||
regularPollType -> nonstrictJsonFormat.fromJson(
|
||||
RegularPoll.serializer(),
|
||||
asJson
|
||||
return when (rawPoll.type) {
|
||||
quizPollType -> QuizPoll(
|
||||
rawPoll.id,
|
||||
rawPoll.question,
|
||||
rawPoll.options,
|
||||
rawPoll.votesCount,
|
||||
rawPoll.correctOptionId,
|
||||
rawPoll.explanation,
|
||||
rawPoll.explanation?.let { rawPoll.explanationEntities.asTextParts(it) } ?: emptyList(),
|
||||
rawPoll.isClosed,
|
||||
rawPoll.isAnonymous,
|
||||
rawPoll.scheduledCloseInfo
|
||||
)
|
||||
quizPollType -> nonstrictJsonFormat.fromJson(
|
||||
QuizPoll.serializer(),
|
||||
asJson
|
||||
regularPollType -> RegularPoll(
|
||||
rawPoll.id,
|
||||
rawPoll.question,
|
||||
rawPoll.options,
|
||||
rawPoll.votesCount,
|
||||
rawPoll.isClosed,
|
||||
rawPoll.isAnonymous,
|
||||
rawPoll.allowMultipleAnswers,
|
||||
rawPoll.scheduledCloseInfo
|
||||
)
|
||||
else -> UnknownPollType(
|
||||
asJson.getPrimitive(idField).content,
|
||||
asJson.getPrimitive(questionField).content,
|
||||
nonstrictJsonFormat.fromJson(
|
||||
pollOptionsSerializer,
|
||||
asJson.getArray(optionsField)
|
||||
),
|
||||
asJson.getPrimitive(totalVoterCountField).int,
|
||||
asJson.getPrimitiveOrNull(isClosedField) ?.booleanOrNull ?: false,
|
||||
asJson.getPrimitiveOrNull(isAnonymousField) ?.booleanOrNull ?: true,
|
||||
asJson.toString()
|
||||
rawPoll.id,
|
||||
rawPoll.question,
|
||||
rawPoll.options,
|
||||
rawPoll.votesCount,
|
||||
rawPoll.isClosed,
|
||||
rawPoll.isAnonymous,
|
||||
asJson
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
override fun serialize(encoder: Encoder, value: Poll) {
|
||||
val asJson = when (value) {
|
||||
is RegularPoll -> nonstrictJsonFormat.toJson(RegularPoll.serializer(), value)
|
||||
is QuizPoll -> nonstrictJsonFormat.toJson(QuizPoll.serializer(), value)
|
||||
is UnknownPollType -> throw IllegalArgumentException("Currently unable to correctly serialize object of poll $value")
|
||||
val closeInfo = value.scheduledCloseInfo
|
||||
val rawPoll = when (value) {
|
||||
is RegularPoll -> RawPoll(
|
||||
value.id,
|
||||
value.question,
|
||||
value.options,
|
||||
value.votesCount,
|
||||
value.isClosed,
|
||||
value.isAnonymous,
|
||||
regularPollType,
|
||||
value.allowMultipleAnswers,
|
||||
openPeriod = (closeInfo as? ApproximateScheduledCloseInfo) ?.openDuration ?.seconds ?.toLong(),
|
||||
closeDate = (closeInfo as? ExactScheduledCloseInfo) ?.closeDateTime ?.unixMillisLong ?.div(1000L)
|
||||
)
|
||||
is QuizPoll -> RawPoll(
|
||||
value.id,
|
||||
value.question,
|
||||
value.options,
|
||||
value.votesCount,
|
||||
value.isClosed,
|
||||
value.isAnonymous,
|
||||
regularPollType,
|
||||
correctOptionId = value.correctOptionId,
|
||||
explanation = value.caption,
|
||||
explanationEntities = value.captionEntities.asRawMessageEntities(),
|
||||
openPeriod = (closeInfo as? ApproximateScheduledCloseInfo) ?.openDuration ?.seconds ?.toLong(),
|
||||
closeDate = (closeInfo as? ExactScheduledCloseInfo) ?.closeDateTime ?.unixMillisLong ?.div(1000L)
|
||||
)
|
||||
is UnknownPollType -> {
|
||||
JsonObjectSerializer.serialize(encoder, value.raw)
|
||||
return
|
||||
}
|
||||
}
|
||||
val resultJson = JsonObject(
|
||||
asJson.jsonObject + (typeField to when (value) {
|
||||
is RegularPoll -> JsonPrimitive(regularPollType)
|
||||
is QuizPoll -> JsonPrimitive(quizPollType)
|
||||
is UnknownPollType -> throw IllegalArgumentException("Currently unable to correctly serialize object of poll $value")
|
||||
})
|
||||
)
|
||||
JsonObjectSerializer.serialize(encoder, resultJson)
|
||||
RawPoll.serializer().serialize(encoder, rawPoll)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
package com.github.insanusmokrassar.TelegramBotAPI.types.update
|
||||
|
||||
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
|
||||
|
||||
data class EditChannelPostUpdate(
|
||||
override val updateId: UpdateIdentifier,
|
||||
override val data: Message
|
||||
override val data: CommonMessage<*>
|
||||
) : BaseEditMessageUpdate
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
package com.github.insanusmokrassar.TelegramBotAPI.types.update
|
||||
|
||||
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
|
||||
|
||||
data class EditMessageUpdate(
|
||||
override val updateId: UpdateIdentifier,
|
||||
override val data: Message
|
||||
override val data: CommonMessage<*>
|
||||
) : BaseEditMessageUpdate
|
||||
|
||||
@@ -4,8 +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.query.RawInlineQuery
|
||||
import com.github.insanusmokrassar.TelegramBotAPI.types.UpdateIdentifier
|
||||
import com.github.insanusmokrassar.TelegramBotAPI.types.message.abstracts.Message
|
||||
import com.github.insanusmokrassar.TelegramBotAPI.types.message.abstracts.TelegramBotAPIMessageDeserializeOnlySerializer
|
||||
import com.github.insanusmokrassar.TelegramBotAPI.types.message.abstracts.*
|
||||
import com.github.insanusmokrassar.TelegramBotAPI.types.payments.PreCheckoutQuery
|
||||
import com.github.insanusmokrassar.TelegramBotAPI.types.payments.ShippingQuery
|
||||
import com.github.insanusmokrassar.TelegramBotAPI.types.polls.Poll
|
||||
@@ -13,8 +12,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.Update
|
||||
import com.github.insanusmokrassar.TelegramBotAPI.types.updateIdField
|
||||
import kotlinx.serialization.SerialName
|
||||
import kotlinx.serialization.Serializable
|
||||
import kotlinx.serialization.*
|
||||
import kotlinx.serialization.json.JsonElement
|
||||
|
||||
@Serializable
|
||||
@@ -22,11 +20,11 @@ internal data class RawUpdate constructor(
|
||||
@SerialName(updateIdField)
|
||||
val updateId: UpdateIdentifier,
|
||||
@Serializable(TelegramBotAPIMessageDeserializeOnlySerializer::class)
|
||||
private val edited_message: Message? = null,
|
||||
private val edited_message: CommonMessage<*>? = null,
|
||||
@Serializable(TelegramBotAPIMessageDeserializeOnlySerializer::class)
|
||||
private val message: Message? = null,
|
||||
@Serializable(TelegramBotAPIMessageDeserializeOnlySerializer::class)
|
||||
private val edited_channel_post: Message? = null,
|
||||
private val edited_channel_post: CommonMessage<*>? = null,
|
||||
@Serializable(TelegramBotAPIMessageDeserializeOnlySerializer::class)
|
||||
private val channel_post: Message? = null,
|
||||
private val inline_query: RawInlineQuery? = null,
|
||||
@@ -42,26 +40,39 @@ internal data class RawUpdate constructor(
|
||||
* @return One of children of [Update] interface or null in case of unknown type of update
|
||||
*/
|
||||
fun asUpdate(raw: JsonElement): Update {
|
||||
return initedUpdate ?: when {
|
||||
edited_message != null -> EditMessageUpdate(updateId, edited_message)
|
||||
message != null -> MessageUpdate(updateId, message)
|
||||
edited_channel_post != null -> EditChannelPostUpdate(updateId, edited_channel_post)
|
||||
channel_post != null -> ChannelPostUpdate(updateId, channel_post)
|
||||
return initedUpdate ?: try {
|
||||
when {
|
||||
edited_message != null -> EditMessageUpdate(updateId, edited_message)
|
||||
message != null -> MessageUpdate(updateId, message)
|
||||
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)
|
||||
inline_query != null -> InlineQueryUpdate(updateId, inline_query.asInlineQuery)
|
||||
callback_query != null -> CallbackQueryUpdate(
|
||||
updateId,
|
||||
callback_query.asCallbackQuery(raw.jsonObject["callback_query"].toString())
|
||||
)
|
||||
shipping_query != null -> ShippingQueryUpdate(updateId, shipping_query)
|
||||
pre_checkout_query != null -> PreCheckoutQueryUpdate(updateId, pre_checkout_query)
|
||||
poll != null -> PollUpdate(updateId, poll)
|
||||
poll_answer != null -> PollAnswerUpdate(updateId, poll_answer)
|
||||
else -> UnknownUpdateType(
|
||||
updateId,
|
||||
raw.toString()
|
||||
)
|
||||
chosen_inline_result != null -> ChosenInlineResultUpdate(updateId, chosen_inline_result.asChosenInlineResult)
|
||||
inline_query != null -> InlineQueryUpdate(updateId, inline_query.asInlineQuery)
|
||||
callback_query != null -> CallbackQueryUpdate(
|
||||
updateId,
|
||||
callback_query.asCallbackQuery(raw.jsonObject["callback_query"].toString())
|
||||
)
|
||||
shipping_query != null -> ShippingQueryUpdate(updateId, shipping_query)
|
||||
pre_checkout_query != null -> PreCheckoutQueryUpdate(updateId, pre_checkout_query)
|
||||
poll != null -> PollUpdate(updateId, poll)
|
||||
poll_answer != null -> PollAnswerUpdate(updateId, poll_answer)
|
||||
else -> UnknownUpdateType(
|
||||
updateId,
|
||||
raw.toString(),
|
||||
raw
|
||||
)
|
||||
}
|
||||
} catch (e: Error) {
|
||||
when (e) {
|
||||
is SerializationException,
|
||||
is NotImplementedError -> UnknownUpdateType(
|
||||
updateId,
|
||||
raw.toString(),
|
||||
raw
|
||||
)
|
||||
else -> throw e
|
||||
}
|
||||
}.also {
|
||||
initedUpdate = it
|
||||
}
|
||||
|
||||
@@ -1,3 +1,7 @@
|
||||
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<*>
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ import com.github.insanusmokrassar.TelegramBotAPI.types.UpdateIdentifier
|
||||
import com.github.insanusmokrassar.TelegramBotAPI.types.update.RawUpdate
|
||||
import com.github.insanusmokrassar.TelegramBotAPI.utils.nonstrictJsonFormat
|
||||
import kotlinx.serialization.*
|
||||
import kotlinx.serialization.json.JsonElement
|
||||
import kotlinx.serialization.json.JsonElementSerializer
|
||||
|
||||
interface Update {
|
||||
@@ -13,10 +14,11 @@ interface Update {
|
||||
|
||||
data class UnknownUpdateType(
|
||||
override val updateId: UpdateIdentifier,
|
||||
override val data: String
|
||||
override val data: String,
|
||||
val rawJson: JsonElement
|
||||
) : Update
|
||||
|
||||
internal object UpdateSerializerWithoutDeserialization : KSerializer<Update> {
|
||||
internal object UpdateSerializerWithoutSerialization : KSerializer<Update> {
|
||||
override val descriptor: SerialDescriptor = JsonElementSerializer.descriptor
|
||||
|
||||
override fun deserialize(decoder: Decoder): Update = UpdateDeserializationStrategy.deserialize(decoder)
|
||||
|
||||
@@ -1,14 +1,13 @@
|
||||
package com.github.insanusmokrassar.TelegramBotAPI.utils
|
||||
|
||||
import com.github.insanusmokrassar.TelegramBotAPI.CommonAbstracts.*
|
||||
import com.github.insanusmokrassar.TelegramBotAPI.types.*
|
||||
import com.github.insanusmokrassar.TelegramBotAPI.types.ParseMode.*
|
||||
import com.github.insanusmokrassar.TelegramBotAPI.types.captionLength
|
||||
import com.github.insanusmokrassar.TelegramBotAPI.types.message.content.TextContent
|
||||
import com.github.insanusmokrassar.TelegramBotAPI.types.message.content.fullEntitiesList
|
||||
import com.github.insanusmokrassar.TelegramBotAPI.types.textLength
|
||||
|
||||
fun createFormattedText(
|
||||
entities: List<TextSource>,
|
||||
entities: FullTextSourcesList,
|
||||
partLength: Int = 4096,
|
||||
mode: ParseMode = MarkdownParseMode
|
||||
): List<String> {
|
||||
@@ -49,50 +48,74 @@ fun createFormattedText(
|
||||
|
||||
|
||||
fun createMarkdownText(
|
||||
entities: List<TextSource>,
|
||||
entities: FullTextSourcesList,
|
||||
partLength: Int = 4096
|
||||
): List<String> = createFormattedText(entities, partLength, MarkdownParseMode)
|
||||
|
||||
fun CaptionedInput.toMarkdownCaptions(): List<String> = createMarkdownText(
|
||||
fullEntitiesList(),
|
||||
fun FullTextSourcesList.toMarkdownCaptions(): List<String> = createMarkdownText(
|
||||
this,
|
||||
captionLength.last + 1
|
||||
)
|
||||
fun CaptionedInput.toMarkdownCaptions(): List<String> = fullEntitiesList().toMarkdownCaptions()
|
||||
|
||||
fun TextContent.toMarkdownTexts(): List<String> = createMarkdownText(
|
||||
fullEntitiesList(),
|
||||
fun FullTextSourcesList.toMarkdownTexts(): List<String> = createMarkdownText(
|
||||
this,
|
||||
textLength.last + 1
|
||||
)
|
||||
fun TextContent.toMarkdownTexts(): List<String> = fullEntitiesList().toMarkdownTexts()
|
||||
|
||||
fun FullTextSourcesList.toMarkdownExplanations(): List<String> = createMarkdownText(
|
||||
this,
|
||||
explanationLimit.last + 1
|
||||
)
|
||||
fun ExplainedInput.toMarkdownExplanations(): List<String> = fullEntitiesList().toMarkdownTexts()
|
||||
|
||||
|
||||
fun createMarkdownV2Text(
|
||||
entities: List<TextSource>,
|
||||
entities: FullTextSourcesList,
|
||||
partLength: Int = 4096
|
||||
): List<String> = createFormattedText(entities, partLength, MarkdownV2ParseMode)
|
||||
|
||||
fun CaptionedInput.toMarkdownV2Captions(): List<String> = createMarkdownV2Text(
|
||||
fullEntitiesList(),
|
||||
fun FullTextSourcesList.toMarkdownV2Captions(): List<String> = createMarkdownV2Text(
|
||||
this,
|
||||
captionLength.last + 1
|
||||
)
|
||||
fun CaptionedInput.toMarkdownV2Captions(): List<String> = fullEntitiesList().toMarkdownV2Captions()
|
||||
|
||||
fun TextContent.toMarkdownV2Texts(): List<String> = createMarkdownV2Text(
|
||||
fullEntitiesList(),
|
||||
fun FullTextSourcesList.toMarkdownV2Texts(): List<String> = createMarkdownV2Text(
|
||||
this,
|
||||
textLength.last + 1
|
||||
)
|
||||
fun TextContent.toMarkdownV2Texts(): List<String> = fullEntitiesList().toMarkdownV2Texts()
|
||||
|
||||
fun FullTextSourcesList.toMarkdownV2Explanations(): List<String> = createMarkdownV2Text(
|
||||
this,
|
||||
explanationLimit.last + 1
|
||||
)
|
||||
fun ExplainedInput.toMarkdownV2Explanations(): List<String> = fullEntitiesList().toMarkdownV2Texts()
|
||||
|
||||
|
||||
fun createHtmlText(
|
||||
entities: List<TextSource>,
|
||||
entities: FullTextSourcesList,
|
||||
partLength: Int = 4096
|
||||
): List<String> = createFormattedText(entities, partLength, HTMLParseMode)
|
||||
|
||||
fun CaptionedInput.toHtmlCaptions(): List<String> = createHtmlText(
|
||||
fullEntitiesList(),
|
||||
fun FullTextSourcesList.toHtmlCaptions(): List<String> = createHtmlText(
|
||||
this,
|
||||
captionLength.last + 1
|
||||
)
|
||||
fun CaptionedInput.toHtmlCaptions(): List<String> = fullEntitiesList().toHtmlCaptions()
|
||||
|
||||
fun TextContent.toHtmlTexts(): List<String> = createHtmlText(
|
||||
fullEntitiesList(),
|
||||
fun FullTextSourcesList.toHtmlTexts(): List<String> = createHtmlText(
|
||||
this,
|
||||
textLength.last + 1
|
||||
)
|
||||
fun TextContent.toHtmlTexts(): List<String> = fullEntitiesList().toHtmlTexts()
|
||||
|
||||
fun FullTextSourcesList.toHtmlExplanations(): List<String> = createHtmlText(
|
||||
this,
|
||||
explanationLimit.last + 1
|
||||
)
|
||||
fun ExplainedInput.toHtmlExplanations(): List<String> = fullEntitiesList().toHtmlTexts()
|
||||
|
||||
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
@@ -3,7 +3,6 @@ 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
|
||||
data class StorageFileInfo(
|
||||
|
||||
@@ -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.webhook.SetWebhook
|
||||
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.RawUpdate
|
||||
import com.github.insanusmokrassar.TelegramBotAPI.types.update.abstracts.BaseMessageUpdate
|
||||
import com.github.insanusmokrassar.TelegramBotAPI.types.update.abstracts.Update
|
||||
import com.github.insanusmokrassar.TelegramBotAPI.types.update.abstracts.*
|
||||
import com.github.insanusmokrassar.TelegramBotAPI.updateshandlers.UpdateReceiver
|
||||
import com.github.insanusmokrassar.TelegramBotAPI.updateshandlers.UpdatesFilter
|
||||
import com.github.insanusmokrassar.TelegramBotAPI.updateshandlers.webhook.WebhookPrivateKeyConfig
|
||||
import com.github.insanusmokrassar.TelegramBotAPI.utils.convertWithMediaGroupUpdates
|
||||
import com.github.insanusmokrassar.TelegramBotAPI.utils.nonstrictJsonFormat
|
||||
import com.github.insanusmokrassar.TelegramBotAPI.utils.*
|
||||
import io.ktor.application.call
|
||||
import io.ktor.request.receiveText
|
||||
import io.ktor.response.respond
|
||||
@@ -45,6 +41,7 @@ suspend fun RequestsExecutor.setWebhook(
|
||||
scope: CoroutineScope = CoroutineScope(Executors.newFixedThreadPool(4).asCoroutineDispatcher()),
|
||||
allowedUpdates: List<String>? = null,
|
||||
maxAllowedConnections: Int? = null,
|
||||
exceptionsHandler: (suspend (Exception) -> Unit)? = null,
|
||||
block: UpdateReceiver<Update>
|
||||
): Job {
|
||||
val executeDeferred = certificate ?.let {
|
||||
@@ -74,12 +71,18 @@ suspend fun RequestsExecutor.setWebhook(
|
||||
module {
|
||||
routing {
|
||||
post(listenRoute) {
|
||||
val asJson = nonstrictJsonFormat.parseJson(call.receiveText())
|
||||
val update = nonstrictJsonFormat.fromJson(
|
||||
RawUpdate.serializer(),
|
||||
asJson
|
||||
)
|
||||
updatesChannel.send(update.asUpdate(asJson))
|
||||
handleSafely(
|
||||
{
|
||||
exceptionsHandler ?.invoke(it)
|
||||
}
|
||||
) {
|
||||
val asJson = nonstrictJsonFormat.parseJson(call.receiveText())
|
||||
val update = nonstrictJsonFormat.fromJson(
|
||||
UpdateDeserializationStrategy,
|
||||
asJson
|
||||
)
|
||||
updatesChannel.send(update)
|
||||
}
|
||||
call.respond("Ok")
|
||||
}
|
||||
}
|
||||
@@ -113,11 +116,6 @@ suspend fun RequestsExecutor.setWebhook(
|
||||
launch {
|
||||
for (update in updatesChannel) {
|
||||
val data = update.data
|
||||
if (data is MediaGroupUpdate) {
|
||||
|
||||
} else {
|
||||
|
||||
}
|
||||
when (data) {
|
||||
is MediaGroupMessage -> mediaGroupChannel.send("${data.mediaGroupId}${update::class.simpleName}" to update as BaseMessageUpdate)
|
||||
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(
|
||||
url: String,
|
||||
port: Int,
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
kotlin.code.style=official
|
||||
kotlin_version=1.3.71
|
||||
kotlin_version=1.3.72
|
||||
kotlin_coroutines_version=1.3.5
|
||||
kotlin_serialisation_runtime_version=0.20.0
|
||||
klock_version=1.10.3
|
||||
klock_version=1.10.5
|
||||
uuid_version=0.1.0
|
||||
ktor_version=1.3.2
|
||||
|
||||
library_group=com.github.insanusmokrassar
|
||||
library_version=0.26.2
|
||||
library_version=0.27.1
|
||||
|
||||
gradle_bintray_plugin_version=1.8.4
|
||||
|
||||
Reference in New Issue
Block a user