mirror of
https://github.com/InsanusMokrassar/TelegramBotAPI.git
synced 2025-12-09 15:55:51 +00:00
Compare commits
47 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| e10e257c80 | |||
| 5e7bc96b44 | |||
| 79d0eda61d | |||
| 9916b3f469 | |||
| 2bac5f0eed | |||
|
|
01eb072caa | ||
| 496af479b0 | |||
| 386e91e28b | |||
| 91dbcecefc | |||
| 2d743e4c19 | |||
| 8804a24013 | |||
| 8b5244d8df | |||
| 034901a479 | |||
| 7043647584 | |||
| acd9505a5d | |||
| 46c33d5ec4 | |||
| 89dc7a4b2a | |||
| e4f305b3ec | |||
| d56c132201 | |||
| d336e177dd | |||
| 15e29286fb | |||
| 314ceed78e | |||
| 3fa3aa50d9 | |||
| 571296b9a0 | |||
| 3f13e5d062 | |||
| 1874023c05 | |||
| dc0fda2066 | |||
| c0d4a4f01b | |||
| 603762bc22 | |||
| 4db82d6ce2 | |||
| 9bf8f56254 | |||
| 9c926a2265 | |||
| 747854f4f4 | |||
| dcfb14553d | |||
| 6eaa9d699b | |||
| 6788c4d1dd | |||
| 6420737a82 | |||
| 4c36750431 | |||
| fd022742aa | |||
| 0472e35752 | |||
| 768d00eedd | |||
| e9347075ed | |||
|
|
3da74b0c66 | ||
|
|
8b79c5c76b | ||
|
|
a1b471d2ca | ||
|
|
e2c7125f6c | ||
| ec8df3c31c |
3
.gitignore
vendored
3
.gitignore
vendored
@@ -8,3 +8,6 @@ settings.xml
|
||||
.gradle/
|
||||
build/
|
||||
out/
|
||||
|
||||
local.properties
|
||||
secret.gradle
|
||||
|
||||
83
CHANGELOG.md
83
CHANGELOG.md
@@ -2,8 +2,6 @@
|
||||
|
||||
## 0.28.0
|
||||
|
||||
### RC
|
||||
|
||||
**THIS VERSION CONTAINS BREAKING CHANGES**
|
||||
|
||||
***PROJECT PACKAGES WERE CHANGED***
|
||||
@@ -23,6 +21,87 @@
|
||||
* All deprecations from previous versions were removed
|
||||
* `TelegramBotAPI-core`:
|
||||
* Typealias `TelegramBot` was added
|
||||
* Fully rebuilt `KtorCallFactory` interface to be able to handle custom answers from telegram bot api system
|
||||
* New implementation of `KtorCallFactory` was added: `DownloadFileRequestCallFactory`
|
||||
* `DownloadFile` request was added
|
||||
* All included `KtorCallFactory` realizations (except of abstract) now are objects:
|
||||
* `MultipartRequestCallFactory`
|
||||
* `SimpleRequestCallFactory`
|
||||
* `MediaGroupMemberInputMedia` members now will not have `arguments` property due to redundancy and buggy of that
|
||||
* Field `media` now is common for all `InputMedia` objects
|
||||
* `TelegramBotAPI-extensions-api`:
|
||||
* Extensions `TelegramBot#downloadFile` were added
|
||||
* `TelegramBotAPI-extensions-utils`:
|
||||
* All extensions for media groups (except of `mediaGroupId`) have changed their context: `List<MediaGroupMessage>`
|
||||
-> `List<CommonMessage<MediaGroupContent>>`
|
||||
* `forwardInfo`
|
||||
* `replyTo`
|
||||
* `chat`
|
||||
* `createResend` (several extensions)
|
||||
* Several extensions for downloading of files:
|
||||
* `HttpClient#loadFile`
|
||||
* `PathedFile#download`
|
||||
|
||||
### 0.28.4
|
||||
|
||||
* `Common`:
|
||||
* Version updates:
|
||||
* `Ktor`: `1.4.0` -> `1.4.1`
|
||||
* `TelegramBotAPI-core`
|
||||
* Interface `GroupEventMessage` has been added ([#140](https://github.com/InsanusMokrassar/TelegramBotAPI/pull/140))
|
||||
* Old `GroupEventMessage` was renamed to `CommonGroupEventMessage` ([#140](https://github.com/InsanusMokrassar/TelegramBotAPI/pull/140))
|
||||
* Interface `SupergroupEventMessage` has been added ([#140](https://github.com/InsanusMokrassar/TelegramBotAPI/pull/140))
|
||||
* Old `SupergroupEventMessage` was renamed to `CommonSupergroupEventMessage` ([#140](https://github.com/InsanusMokrassar/TelegramBotAPI/pull/140))
|
||||
* Any `GroupEventMessage` now have `from` field ([#140](https://github.com/InsanusMokrassar/TelegramBotAPI/pull/140))
|
||||
* `TelegramBotAPI-extensions-utils`
|
||||
* Extensions `Flow<ChatEventMessage>#onlyGroupEvents` and `Flow<ChatEventMessage>#onlySupergroupEvents` now returns
|
||||
`CommonGroupEventMessage` and `CommonSupergroupEventMessage`
|
||||
|
||||
### 0.28.3
|
||||
|
||||
* Common:
|
||||
* Version updates:
|
||||
* `Klock`: `0.12.0` -> `0.12.1`
|
||||
* `Kotlin serialization`: `1.0.0-RC` -> `1.0.0-RC2` (dependency `kotlinx-serialization-core` was replaced with
|
||||
`kotlinx-serialization-json` due to [kotlinx.serialization library update](https://github.com/Kotlin/kotlinx.serialization/blob/master/CHANGELOG.md#100-rc2--2020-09-21))
|
||||
* `TelegramBotAPI-core`:
|
||||
* All `InlineQueryResult` has changed their type of id for more obvious relation between `InlineQueryResult#id` and
|
||||
`ChosenInlineResult#resultId`: `String` -> `InlineQueryIdentifier`
|
||||
* `TelegramBotAPI-extensions-utils`:
|
||||
* Several extensions for updates flows based on `InlineQueryUpdate` has been added:
|
||||
* `Flow<InlineQueryUpdate>#onlyBaseInlineQueriesWithUpdates`
|
||||
* `Flow<InlineQueryUpdate>#onlyBaseInlineQueries`
|
||||
* `Flow<InlineQueryUpdate>#onlyLocationInlineQueriesWithUpdates`
|
||||
* `Flow<InlineQueryUpdate>#onlyLocationInlineQueries`
|
||||
* Several extensions for updates flows based on `ChosenInlineResultUpdate` has been added:
|
||||
* `Flow<ChosenInlineResultUpdate>.onlyBaseChosenInlineResultsWithUpdates`
|
||||
* `Flow<ChosenInlineResultUpdate>.onlyBaseChosenInlineResults`
|
||||
* `Flow<ChosenInlineResultUpdate>.onlyLocationChosenInlineResultsWithUpdates`
|
||||
* `Flow<ChosenInlineResultUpdate>.onlyLocationChosenInlineResults`
|
||||
|
||||
### 0.28.2
|
||||
|
||||
* `TelegramBotAPI-extensions-utils`:
|
||||
* Several commands shortcuts for `Flow<ContentMessage<TextContent>>` has been added:
|
||||
* `filterExactCommands`
|
||||
* `filterCommandsInsideTextMessages`
|
||||
* `filterCommandsWithArgs`
|
||||
* Extension `Flow<BaseSentMessageUpdate>.filterCommandsWithArgs` has changed its signature: now it will also have
|
||||
original message paired with list of text sources
|
||||
* Shortcut method `commonMessages` for `onlyCommonMessages`
|
||||
* Shortcuts `onlySentViaBot` and `withoutSentViaBot` now are extensions for any `Flow` with types which implementing
|
||||
`ContentMessage`
|
||||
|
||||
### 0.28.1
|
||||
|
||||
* Common:
|
||||
* Versions updates:
|
||||
* `Kotlin`: `1.4.0` -> `1.4.10`
|
||||
* `UUID`: `0.2.1` -> `0.2.2`
|
||||
* `TelegramBotAPI-core`:
|
||||
* `ExceptionHandler` has changed its incoming type: `Exception` -> `Throwable`
|
||||
* `handleSafely` has changed its signature
|
||||
* `executeUnsafe` has changed its signature
|
||||
|
||||
## 0.27.0
|
||||
|
||||
|
||||
@@ -8,6 +8,11 @@
|
||||
| TelegramBotAPI Util Extensions status | [](https://bintray.com/insanusmokrassar/StandardRepository/TelegramBotAPI-extensions-utils/_latestVersion) [](https://maven-badges.herokuapp.com/maven-central/com.github.insanusmokrassar/TelegramBotAPI-extensions-utils) |
|
||||
| TelegramBotAPI All status | [](https://bintray.com/insanusmokrassar/StandardRepository/TelegramBotAPI/_latestVersion) [](https://maven-badges.herokuapp.com/maven-central/com.github.insanusmokrassar/TelegramBotAPI-all) |
|
||||
|
||||
**At the time of publication of version `0.28.0` there are errors in serialization plugins like
|
||||
[kotlinx.serialization#1004](https://github.com/Kotlin/kotlinx.serialization/issues/1004). It is possible, that both JVM
|
||||
and JS version may work improperly in some cases with `kotlinx.serialization` version `1.0.0-RC`**
|
||||
|
||||
|
||||
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:
|
||||
|
||||
@@ -24,6 +29,8 @@ moments are describing by official [Telegram Bot API](https://core.telegram.org/
|
||||
|
||||
## JavaScript notes
|
||||
|
||||
### Versions before `0.28.0`
|
||||
|
||||
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>
|
||||
|
||||
@@ -41,7 +41,7 @@ kotlin {
|
||||
dependencies {
|
||||
implementation kotlin('stdlib')
|
||||
api "org.jetbrains.kotlinx:kotlinx-coroutines-core:$kotlin_coroutines_version"
|
||||
api "org.jetbrains.kotlinx:kotlinx-serialization-core:$kotlin_serialisation_runtime_version"
|
||||
api "org.jetbrains.kotlinx:kotlinx-serialization-json:$kotlin_serialisation_runtime_version"
|
||||
api "org.jetbrains.kotlinx:kotlinx-serialization-properties:$kotlin_serialisation_runtime_version"
|
||||
|
||||
api "com.soywiz.korlibs.klock:klock:$klock_version"
|
||||
|
||||
@@ -1 +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 Core","description":"Library for Object-Oriented and type-safe work with Telegram Bot API","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"}
|
||||
{"bintrayConfig":{"repo":"StandardRepository","packageName":"${project.name}","packageVcs":"https://github.com/InsanusMokrassar/TelegramBotAPI","autoPublish":true},"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 Core","description":"Library for Object-Oriented and type-safe work with Telegram Bot API","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"}
|
||||
@@ -25,6 +25,9 @@ bintray {
|
||||
}
|
||||
into "${project.group}".replace(".", "/")
|
||||
}
|
||||
|
||||
publish = true
|
||||
|
||||
pkg {
|
||||
repo = "StandardRepository"
|
||||
name = "${project.name}"
|
||||
|
||||
@@ -1,13 +1,15 @@
|
||||
package com.github.insanusmokrassar.TelegramBotAPI.bot.Ktor
|
||||
|
||||
import com.github.insanusmokrassar.TelegramBotAPI.requests.abstracts.Request
|
||||
import com.github.insanusmokrassar.TelegramBotAPI.utils.TelegramAPIUrlsKeeper
|
||||
import io.ktor.client.HttpClient
|
||||
import io.ktor.client.statement.HttpStatement
|
||||
import kotlinx.serialization.json.Json
|
||||
|
||||
interface KtorCallFactory {
|
||||
suspend fun <T: Any> prepareCall(
|
||||
suspend fun <T: Any> makeCall(
|
||||
client: HttpClient,
|
||||
baseUrl: String,
|
||||
request: Request<T>
|
||||
) : HttpStatement?
|
||||
urlsKeeper: TelegramAPIUrlsKeeper,
|
||||
request: Request<T>,
|
||||
jsonFormatter: Json
|
||||
): T?
|
||||
}
|
||||
|
||||
@@ -1,21 +1,17 @@
|
||||
package com.github.insanusmokrassar.TelegramBotAPI.bot.Ktor
|
||||
|
||||
import com.github.insanusmokrassar.TelegramBotAPI.bot.BaseRequestsExecutor
|
||||
import com.github.insanusmokrassar.TelegramBotAPI.bot.Ktor.base.MultipartRequestCallFactory
|
||||
import com.github.insanusmokrassar.TelegramBotAPI.bot.Ktor.base.SimpleRequestCallFactory
|
||||
import com.github.insanusmokrassar.TelegramBotAPI.bot.Ktor.base.*
|
||||
import com.github.insanusmokrassar.TelegramBotAPI.bot.exceptions.newRequestException
|
||||
import com.github.insanusmokrassar.TelegramBotAPI.bot.settings.limiters.EmptyLimiter
|
||||
import com.github.insanusmokrassar.TelegramBotAPI.bot.settings.limiters.RequestLimiter
|
||||
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.*
|
||||
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.serialization.json.Json
|
||||
|
||||
class KtorRequestsExecutor(
|
||||
@@ -28,7 +24,7 @@ class KtorRequestsExecutor(
|
||||
) : BaseRequestsExecutor(telegramAPIUrlsKeeper) {
|
||||
private val callsFactories: List<KtorCallFactory> = callsFactories.run {
|
||||
if (!excludeDefaultFactories) {
|
||||
asSequence().plus(SimpleRequestCallFactory()).plus(MultipartRequestCallFactory()).toList()
|
||||
this + listOf(SimpleRequestCallFactory, MultipartRequestCallFactory, DownloadFileRequestCallFactory)
|
||||
} else {
|
||||
this
|
||||
}
|
||||
@@ -57,39 +53,20 @@ class KtorRequestsExecutor(
|
||||
}
|
||||
) {
|
||||
requestsLimiter.limit {
|
||||
var statement: HttpStatement? = null
|
||||
for (factory in callsFactories) {
|
||||
statement = factory.prepareCall(
|
||||
var result: T? = null
|
||||
for (potentialFactory in callsFactories) {
|
||||
result = potentialFactory.makeCall(
|
||||
client,
|
||||
telegramAPIUrlsKeeper.commonAPIUrl,
|
||||
request
|
||||
telegramAPIUrlsKeeper,
|
||||
request,
|
||||
jsonFormatter
|
||||
)
|
||||
if (statement != null) {
|
||||
if (result != null) {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
val response = statement?.execute() ?: throw IllegalArgumentException("Can't execute request: $request")
|
||||
val content = response.receive<String>()
|
||||
val responseObject = jsonFormatter.decodeFromString(Response.serializer(), content)
|
||||
|
||||
(responseObject.result?.let {
|
||||
jsonFormatter.decodeFromJsonElement(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"
|
||||
)
|
||||
})
|
||||
result ?: error("Can't execute request: $request")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,55 +1,79 @@
|
||||
package com.github.insanusmokrassar.TelegramBotAPI.bot.Ktor.base
|
||||
|
||||
import com.github.insanusmokrassar.TelegramBotAPI.bot.Ktor.KtorCallFactory
|
||||
import com.github.insanusmokrassar.TelegramBotAPI.bot.exceptions.newRequestException
|
||||
import com.github.insanusmokrassar.TelegramBotAPI.requests.GetUpdates
|
||||
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 io.ktor.client.HttpClient
|
||||
import io.ktor.client.call.receive
|
||||
import io.ktor.client.features.timeout
|
||||
import io.ktor.client.request.*
|
||||
import io.ktor.client.statement.HttpStatement
|
||||
import io.ktor.client.statement.HttpResponse
|
||||
import io.ktor.http.ContentType
|
||||
import io.ktor.http.HttpMethod
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.serialization.json.Json
|
||||
import kotlin.collections.set
|
||||
|
||||
abstract class AbstractRequestCallFactory : KtorCallFactory {
|
||||
private val methodsCache: MutableMap<String, String> = mutableMapOf()
|
||||
override suspend fun <T : Any> prepareCall(
|
||||
override suspend fun <T : Any> makeCall(
|
||||
client: HttpClient,
|
||||
baseUrl: String,
|
||||
request: Request<T>
|
||||
): HttpStatement? {
|
||||
val preparedBody = prepareCallBody(client, baseUrl, request) ?: return null
|
||||
urlsKeeper: TelegramAPIUrlsKeeper,
|
||||
request: Request<T>,
|
||||
jsonFormatter: Json
|
||||
): T? {
|
||||
val preparedBody = prepareCallBody(client, urlsKeeper, request) ?: return null
|
||||
|
||||
return HttpStatement(
|
||||
HttpRequestBuilder().apply {
|
||||
url(
|
||||
methodsCache[request.method()] ?: "$baseUrl/${request.method()}".also {
|
||||
methodsCache[request.method()] = it
|
||||
}
|
||||
)
|
||||
method = HttpMethod.Post
|
||||
accept(ContentType.Application.Json)
|
||||
client.post<HttpResponse> {
|
||||
url(
|
||||
methodsCache[request.method()] ?: "${urlsKeeper.commonAPIUrl}/${request.method()}".also {
|
||||
methodsCache[request.method()] = it
|
||||
}
|
||||
)
|
||||
accept(ContentType.Application.Json)
|
||||
|
||||
if (request is GetUpdates) {
|
||||
request.timeout ?.times(1000L) ?.let { customTimeoutMillis ->
|
||||
if (customTimeoutMillis > 0) {
|
||||
timeout {
|
||||
requestTimeoutMillis = customTimeoutMillis
|
||||
socketTimeoutMillis = customTimeoutMillis
|
||||
}
|
||||
if (request is GetUpdates) {
|
||||
request.timeout?.times(1000L)?.let { customTimeoutMillis ->
|
||||
if (customTimeoutMillis > 0) {
|
||||
timeout {
|
||||
requestTimeoutMillis = customTimeoutMillis
|
||||
socketTimeoutMillis = customTimeoutMillis
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
body = preparedBody
|
||||
},
|
||||
client
|
||||
)
|
||||
body = preparedBody
|
||||
}.let { response ->
|
||||
val content = response.receive<String>()
|
||||
val responseObject = jsonFormatter.decodeFromString(Response.serializer(), content)
|
||||
|
||||
return (responseObject.result?.let {
|
||||
jsonFormatter.decodeFromJsonElement(request.resultDeserializer, it)
|
||||
} ?: responseObject.parameters?.let {
|
||||
val error = it.error
|
||||
if (error is RetryAfterError) {
|
||||
delay(error.leftToRetry)
|
||||
makeCall(client, urlsKeeper, request, jsonFormatter)
|
||||
} else {
|
||||
null
|
||||
}
|
||||
} ?: response.let {
|
||||
throw newRequestException(
|
||||
responseObject,
|
||||
content,
|
||||
"Can't get result object from $content"
|
||||
)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
protected abstract fun <T : Any> prepareCallBody(
|
||||
client: HttpClient,
|
||||
baseUrl: String,
|
||||
urlsKeeper: TelegramAPIUrlsKeeper,
|
||||
request: Request<T>
|
||||
): Any?
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
package com.github.insanusmokrassar.TelegramBotAPI.bot.Ktor.base
|
||||
|
||||
import com.github.insanusmokrassar.TelegramBotAPI.bot.Ktor.KtorCallFactory
|
||||
import com.github.insanusmokrassar.TelegramBotAPI.bot.RequestsExecutor
|
||||
import com.github.insanusmokrassar.TelegramBotAPI.requests.DownloadFile
|
||||
import com.github.insanusmokrassar.TelegramBotAPI.requests.abstracts.Request
|
||||
import com.github.insanusmokrassar.TelegramBotAPI.utils.TelegramAPIUrlsKeeper
|
||||
import com.github.insanusmokrassar.TelegramBotAPI.utils.handleSafely
|
||||
import io.ktor.client.HttpClient
|
||||
import io.ktor.client.request.*
|
||||
import io.ktor.client.statement.*
|
||||
import io.ktor.http.HttpMethod
|
||||
import kotlinx.serialization.json.Json
|
||||
|
||||
object DownloadFileRequestCallFactory : KtorCallFactory {
|
||||
override suspend fun <T : Any> makeCall(
|
||||
client: HttpClient,
|
||||
urlsKeeper: TelegramAPIUrlsKeeper,
|
||||
request: Request<T>,
|
||||
jsonFormatter: Json
|
||||
): T? = (request as? DownloadFile) ?.let {
|
||||
val fullUrl = "${urlsKeeper.fileBaseUrl}/${it.filePath}"
|
||||
|
||||
return handleSafely {
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
client.get<ByteArray>(fullUrl) as T // always ByteArray
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
package com.github.insanusmokrassar.TelegramBotAPI.bot.Ktor.base
|
||||
|
||||
import com.github.insanusmokrassar.TelegramBotAPI.requests.abstracts.*
|
||||
import com.github.insanusmokrassar.TelegramBotAPI.utils.TelegramAPIUrlsKeeper
|
||||
import com.github.insanusmokrassar.TelegramBotAPI.utils.mapWithCommonValues
|
||||
import io.ktor.client.HttpClient
|
||||
import io.ktor.client.request.forms.MultiPartFormDataContent
|
||||
@@ -8,11 +9,10 @@ import io.ktor.client.request.forms.formData
|
||||
import io.ktor.http.Headers
|
||||
import io.ktor.http.HttpHeaders
|
||||
|
||||
class MultipartRequestCallFactory : AbstractRequestCallFactory() {
|
||||
|
||||
object MultipartRequestCallFactory : AbstractRequestCallFactory() {
|
||||
override fun <T : Any> prepareCallBody(
|
||||
client: HttpClient,
|
||||
baseUrl: String,
|
||||
urlsKeeper: TelegramAPIUrlsKeeper,
|
||||
request: Request<T>
|
||||
): Any? = (request as? MultipartRequest) ?.let { castedRequest ->
|
||||
MultiPartFormDataContent(
|
||||
|
||||
@@ -1,14 +1,15 @@
|
||||
package com.github.insanusmokrassar.TelegramBotAPI.bot.Ktor.base
|
||||
|
||||
import com.github.insanusmokrassar.TelegramBotAPI.requests.abstracts.*
|
||||
import com.github.insanusmokrassar.TelegramBotAPI.utils.TelegramAPIUrlsKeeper
|
||||
import io.ktor.client.HttpClient
|
||||
import io.ktor.http.ContentType
|
||||
import io.ktor.http.content.TextContent
|
||||
|
||||
class SimpleRequestCallFactory : AbstractRequestCallFactory() {
|
||||
object SimpleRequestCallFactory : AbstractRequestCallFactory() {
|
||||
override fun <T : Any> prepareCallBody(
|
||||
client: HttpClient,
|
||||
baseUrl: String,
|
||||
urlsKeeper: TelegramAPIUrlsKeeper,
|
||||
request: Request<T>
|
||||
): Any? = (request as? SimpleRequest<T>) ?.let { _ ->
|
||||
val content = request.json().toString()
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
package com.github.insanusmokrassar.TelegramBotAPI.requests
|
||||
|
||||
import com.github.insanusmokrassar.TelegramBotAPI.requests.abstracts.Request
|
||||
import kotlinx.serialization.DeserializationStrategy
|
||||
import kotlinx.serialization.builtins.ByteArraySerializer
|
||||
|
||||
class DownloadFile(
|
||||
val filePath: String
|
||||
) : Request<ByteArray> {
|
||||
override fun method(): String = filePath
|
||||
|
||||
override val resultDeserializer: DeserializationStrategy<ByteArray>
|
||||
get() = ByteArraySerializer()
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
package com.github.insanusmokrassar.TelegramBotAPI.requests.abstracts
|
||||
|
||||
import com.github.insanusmokrassar.TelegramBotAPI.types.InputMedia.toInputMediaFileAttachmentName
|
||||
import com.github.insanusmokrassar.TelegramBotAPI.utils.StorageFile
|
||||
import kotlinx.serialization.*
|
||||
import kotlinx.serialization.descriptors.*
|
||||
@@ -29,6 +30,12 @@ internal object InputFileSerializer : KSerializer<InputFile> {
|
||||
override fun deserialize(decoder: Decoder): FileId = FileId(decoder.decodeString())
|
||||
}
|
||||
|
||||
internal val InputFile.asMediaData: String
|
||||
get() = when (this) {
|
||||
is FileId -> fileId
|
||||
is MultipartFile -> fileId.toInputMediaFileAttachmentName()
|
||||
}
|
||||
|
||||
// TODO:: add checks for files size
|
||||
/**
|
||||
* Contains info about file for sending
|
||||
|
||||
@@ -10,7 +10,7 @@ import kotlinx.serialization.Serializable
|
||||
@Serializable
|
||||
class InlineQueryResultArticle(
|
||||
@SerialName(idField)
|
||||
override val id: String,
|
||||
override val id: InlineQueryIdentifier,
|
||||
@SerialName(titleField)
|
||||
override val title: String,
|
||||
@SerialName(inputMessageContentField)
|
||||
|
||||
@@ -14,7 +14,7 @@ import kotlinx.serialization.Serializable
|
||||
@Serializable
|
||||
data class InlineQueryResultAudioCachedImpl(
|
||||
@SerialName(idField)
|
||||
override val id: String,
|
||||
override val id: InlineQueryIdentifier,
|
||||
@SerialName(audioFileIdField)
|
||||
override val fileId: FileId,
|
||||
@SerialName(captionField)
|
||||
|
||||
@@ -13,7 +13,7 @@ import kotlinx.serialization.Serializable
|
||||
@Serializable
|
||||
data class InlineQueryResultAudioImpl(
|
||||
@SerialName(idField)
|
||||
override val id: String,
|
||||
override val id: InlineQueryIdentifier,
|
||||
@SerialName(audioUrlField)
|
||||
override val url: String,
|
||||
@SerialName(titleField)
|
||||
|
||||
@@ -11,7 +11,7 @@ import kotlinx.serialization.Serializable
|
||||
@Serializable
|
||||
data class InlineQueryResultContact(
|
||||
@SerialName(idField)
|
||||
override val id: String,
|
||||
override val id: InlineQueryIdentifier,
|
||||
@SerialName(phoneNumberField)
|
||||
override val phoneNumber: String,
|
||||
@SerialName(firstNameField)
|
||||
|
||||
@@ -14,7 +14,7 @@ import kotlinx.serialization.Serializable
|
||||
@Serializable
|
||||
data class InlineQueryResultDocumentCachedImpl(
|
||||
@SerialName(idField)
|
||||
override val id: String,
|
||||
override val id: InlineQueryIdentifier,
|
||||
@SerialName(documentFileIdField)
|
||||
override val fileId: FileId,
|
||||
@SerialName(titleField)
|
||||
|
||||
@@ -15,7 +15,7 @@ import kotlinx.serialization.Serializable
|
||||
@Serializable
|
||||
data class InlineQueryResultDocumentImpl(
|
||||
@SerialName(idField)
|
||||
override val id: String,
|
||||
override val id: InlineQueryIdentifier,
|
||||
@SerialName(documentUrlField)
|
||||
override val url: String,
|
||||
@SerialName(titleField)
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package com.github.insanusmokrassar.TelegramBotAPI.types.InlineQueries.InlineQueryResult
|
||||
|
||||
import com.github.insanusmokrassar.TelegramBotAPI.types.InlineQueries.InlineQueryResult.abstracts.InlineQueryResult
|
||||
import com.github.insanusmokrassar.TelegramBotAPI.types.InlineQueryIdentifier
|
||||
import com.github.insanusmokrassar.TelegramBotAPI.types.buttons.InlineKeyboardMarkup
|
||||
import com.github.insanusmokrassar.TelegramBotAPI.types.gameShortNameField
|
||||
import kotlinx.serialization.SerialName
|
||||
@@ -8,7 +9,7 @@ import kotlinx.serialization.Serializable
|
||||
|
||||
@Serializable
|
||||
class InlineQueryResultGame(
|
||||
override val id: String,
|
||||
override val id: InlineQueryIdentifier,
|
||||
@SerialName(gameShortNameField)
|
||||
val gameShortName: String,
|
||||
override val replyMarkup: InlineKeyboardMarkup? = null
|
||||
|
||||
@@ -14,7 +14,7 @@ import kotlinx.serialization.Serializable
|
||||
@Serializable
|
||||
data class InlineQueryResultGifCachedImpl(
|
||||
@SerialName(idField)
|
||||
override val id: String,
|
||||
override val id: InlineQueryIdentifier,
|
||||
@SerialName(gifFileIdField)
|
||||
override val fileId: FileId,
|
||||
@SerialName(titleField)
|
||||
|
||||
@@ -14,7 +14,7 @@ import kotlinx.serialization.Serializable
|
||||
@Serializable
|
||||
data class InlineQueryResultGifImpl(
|
||||
@SerialName(idField)
|
||||
override val id: String,
|
||||
override val id: InlineQueryIdentifier,
|
||||
@SerialName(gifUrlField)
|
||||
override val url: String,
|
||||
@SerialName(thumbUrlField)
|
||||
|
||||
@@ -12,7 +12,7 @@ import kotlinx.serialization.Serializable
|
||||
@Serializable
|
||||
data class InlineQueryResultLocation(
|
||||
@SerialName(idField)
|
||||
override val id: String,
|
||||
override val id: InlineQueryIdentifier,
|
||||
@SerialName(latitudeField)
|
||||
override val latitude: Double,
|
||||
@SerialName(longitudeField)
|
||||
|
||||
@@ -14,7 +14,7 @@ import kotlinx.serialization.Serializable
|
||||
@Serializable
|
||||
data class InlineQueryResultMpeg4GifCachedImpl(
|
||||
@SerialName(idField)
|
||||
override val id: String,
|
||||
override val id: InlineQueryIdentifier,
|
||||
@SerialName(mpeg4GifFileIdField)
|
||||
override val fileId: FileId,
|
||||
@SerialName(titleField)
|
||||
|
||||
@@ -14,7 +14,7 @@ import kotlinx.serialization.Serializable
|
||||
@Serializable
|
||||
data class InlineQueryResultMpeg4GifImpl(
|
||||
@SerialName(idField)
|
||||
override val id: String,
|
||||
override val id: InlineQueryIdentifier,
|
||||
@SerialName(mpeg4GifUrlField)
|
||||
override val url: String,
|
||||
@SerialName(thumbUrlField)
|
||||
|
||||
@@ -14,7 +14,7 @@ import kotlinx.serialization.Serializable
|
||||
@Serializable
|
||||
data class InlineQueryResultPhotoCachedImpl(
|
||||
@SerialName(idField)
|
||||
override val id: String,
|
||||
override val id: InlineQueryIdentifier,
|
||||
@SerialName(photoFileIdField)
|
||||
override val fileId: FileId,
|
||||
@SerialName(titleField)
|
||||
|
||||
@@ -13,7 +13,7 @@ import kotlinx.serialization.Serializable
|
||||
@Serializable
|
||||
data class InlineQueryResultPhotoImpl(
|
||||
@SerialName(idField)
|
||||
override val id: String,
|
||||
override val id: InlineQueryIdentifier,
|
||||
@SerialName(photoUrlField)
|
||||
override val url: String,
|
||||
@SerialName(thumbUrlField)
|
||||
|
||||
@@ -11,7 +11,7 @@ import kotlinx.serialization.Serializable
|
||||
@Serializable
|
||||
data class InlineQueryResultStickerCached(
|
||||
@SerialName(idField)
|
||||
override val id: String,
|
||||
override val id: InlineQueryIdentifier,
|
||||
@SerialName(stickerFileIdField)
|
||||
override val fileId: FileId,
|
||||
@SerialName(replyMarkupField)
|
||||
|
||||
@@ -12,7 +12,7 @@ import kotlinx.serialization.Serializable
|
||||
@Serializable
|
||||
data class InlineQueryResultVenue(
|
||||
@SerialName(idField)
|
||||
override val id: String,
|
||||
override val id: InlineQueryIdentifier,
|
||||
@SerialName(latitudeField)
|
||||
override val latitude: Double,
|
||||
@SerialName(longitudeField)
|
||||
|
||||
@@ -14,7 +14,7 @@ import kotlinx.serialization.Serializable
|
||||
@Serializable
|
||||
data class InlineQueryResultVideoCachedImpl(
|
||||
@SerialName(idField)
|
||||
override val id: String,
|
||||
override val id: InlineQueryIdentifier,
|
||||
@SerialName(videoFileIdField)
|
||||
override val fileId: FileId,
|
||||
@SerialName(titleField)
|
||||
|
||||
@@ -15,7 +15,7 @@ import kotlinx.serialization.Serializable
|
||||
@Serializable
|
||||
data class InlineQueryResultVideoImpl(
|
||||
@SerialName(idField)
|
||||
override val id: String,
|
||||
override val id: InlineQueryIdentifier,
|
||||
@SerialName(videoUrlField)
|
||||
override val url: String,
|
||||
@SerialName(thumbUrlField)
|
||||
|
||||
@@ -14,7 +14,7 @@ import kotlinx.serialization.Serializable
|
||||
@Serializable
|
||||
data class InlineQueryResultVoiceCachedImpl(
|
||||
@SerialName(idField)
|
||||
override val id: String,
|
||||
override val id: InlineQueryIdentifier,
|
||||
@SerialName(voiceFileIdField)
|
||||
override val fileId: FileId,
|
||||
@SerialName(titleField)
|
||||
|
||||
@@ -13,7 +13,7 @@ import kotlinx.serialization.Serializable
|
||||
@Serializable
|
||||
data class InlineQueryResultVoiceImpl(
|
||||
@SerialName(idField)
|
||||
override val id: String,
|
||||
override val id: InlineQueryIdentifier,
|
||||
@SerialName(voiceUrlField)
|
||||
override val url: String,
|
||||
@SerialName(titleField)
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
package com.github.insanusmokrassar.TelegramBotAPI.types.InlineQueries.InlineQueryResult.abstracts
|
||||
|
||||
import com.github.insanusmokrassar.TelegramBotAPI.types.InlineQueries.InlineQueryResult.serializers.InlineQueryResultSerializer
|
||||
import com.github.insanusmokrassar.TelegramBotAPI.types.InlineQueryIdentifier
|
||||
import com.github.insanusmokrassar.TelegramBotAPI.types.buttons.InlineKeyboardMarkup
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
@Serializable(InlineQueryResultSerializer::class)
|
||||
interface InlineQueryResult {
|
||||
val type: String
|
||||
val id: String
|
||||
val id: InlineQueryIdentifier
|
||||
val replyMarkup: InlineKeyboardMarkup?
|
||||
}
|
||||
@@ -9,4 +9,5 @@ fun String.toInputMediaFileAttachmentName() = "attach://$this"
|
||||
interface InputMedia {
|
||||
val type: String
|
||||
val file: InputFile
|
||||
val media: String
|
||||
}
|
||||
@@ -22,8 +22,6 @@ data class InputMediaAnimation(
|
||||
override val type: String = "animation"
|
||||
|
||||
@SerialName(mediaField)
|
||||
val media: String = when (file) {
|
||||
is FileId -> file.fileId
|
||||
is MultipartFile -> file.fileId.toInputMediaFileAttachmentName()
|
||||
}
|
||||
override val media: String
|
||||
init { media = file.fileId } // crutch until js compiling will be fixed
|
||||
}
|
||||
|
||||
@@ -23,8 +23,6 @@ data class InputMediaAudio(
|
||||
override val type: String = "audio"
|
||||
|
||||
@SerialName(mediaField)
|
||||
val media: String = when (file) {
|
||||
is FileId -> file.fileId
|
||||
is MultipartFile -> file.fileId.toInputMediaFileAttachmentName()
|
||||
}
|
||||
override val media: String
|
||||
init { media = file.fileId } // crutch until js compiling will be fixed
|
||||
}
|
||||
|
||||
@@ -19,8 +19,6 @@ data class InputMediaDocument(
|
||||
override val type: String = "document"
|
||||
|
||||
@SerialName(mediaField)
|
||||
val media: String = when (file) {
|
||||
is FileId -> file.fileId
|
||||
is MultipartFile -> file.fileId.toInputMediaFileAttachmentName()
|
||||
}
|
||||
override val media: String
|
||||
init { media = file.fileId } // crutch until js compiling will be fixed
|
||||
}
|
||||
|
||||
@@ -23,13 +23,8 @@ data class InputMediaPhoto(
|
||||
override fun serialize(format: StringFormat): String = format.encodeToString(serializer(), this)
|
||||
|
||||
@SerialName(mediaField)
|
||||
val media: String = when (file) {
|
||||
is FileId -> file.fileId
|
||||
is MultipartFile -> file.fileId.toInputMediaFileAttachmentName()
|
||||
}
|
||||
|
||||
@Transient
|
||||
override val arguments: JsonElement = buildArguments(serializer())
|
||||
override val media: String
|
||||
init { media = file.fileId } // crutch until js compiling will be fixed
|
||||
}
|
||||
|
||||
fun PhotoSize.toInputMediaPhoto(
|
||||
|
||||
@@ -24,13 +24,7 @@ data class InputMediaVideo(
|
||||
|
||||
override fun serialize(format: StringFormat): String = format.encodeToString(serializer(), this)
|
||||
|
||||
|
||||
@Transient
|
||||
override val arguments: JsonElement = buildArguments(serializer())
|
||||
|
||||
@SerialName(mediaField)
|
||||
val media: String = when (file) {
|
||||
is FileId -> file.fileId
|
||||
is MultipartFile -> file.fileId.toInputMediaFileAttachmentName()
|
||||
}
|
||||
override val media: String
|
||||
init { media = file.fileId } // crutch until js compiling will be fixed
|
||||
}
|
||||
|
||||
@@ -17,5 +17,4 @@ internal fun <T> T.buildArguments(withSerializer: SerializationStrategy<T>) = ar
|
||||
@Serializable(MediaGroupMemberInputMediaSerializer::class)
|
||||
interface MediaGroupMemberInputMedia : InputMedia, CaptionedOutput {
|
||||
fun serialize(format: StringFormat): String
|
||||
val arguments: JsonElement
|
||||
}
|
||||
|
||||
@@ -1,14 +1,19 @@
|
||||
package com.github.insanusmokrassar.TelegramBotAPI.types.message
|
||||
|
||||
import com.github.insanusmokrassar.TelegramBotAPI.types.MessageIdentifier
|
||||
import com.github.insanusmokrassar.TelegramBotAPI.types.User
|
||||
import com.github.insanusmokrassar.TelegramBotAPI.types.chat.abstracts.GroupChat
|
||||
import com.github.insanusmokrassar.TelegramBotAPI.types.message.ChatEvents.abstracts.GroupEvent
|
||||
import com.github.insanusmokrassar.TelegramBotAPI.types.message.abstracts.ChatEventMessage
|
||||
import com.github.insanusmokrassar.TelegramBotAPI.types.message.abstracts.GroupEventMessage
|
||||
import com.soywiz.klock.DateTime
|
||||
|
||||
data class GroupEventMessage(
|
||||
@Deprecated("Renamed", ReplaceWith("CommonGroupEventMessage"))
|
||||
typealias GroupEventMessage = CommonGroupEventMessage
|
||||
|
||||
data class CommonGroupEventMessage(
|
||||
override val messageId: MessageIdentifier,
|
||||
override val user: User,
|
||||
override val chat: GroupChat,
|
||||
override val chatEvent: GroupEvent,
|
||||
override val date: DateTime
|
||||
) : ChatEventMessage
|
||||
) : GroupEventMessage
|
||||
@@ -1,14 +1,19 @@
|
||||
package com.github.insanusmokrassar.TelegramBotAPI.types.message
|
||||
|
||||
import com.github.insanusmokrassar.TelegramBotAPI.types.MessageIdentifier
|
||||
import com.github.insanusmokrassar.TelegramBotAPI.types.User
|
||||
import com.github.insanusmokrassar.TelegramBotAPI.types.chat.abstracts.SupergroupChat
|
||||
import com.github.insanusmokrassar.TelegramBotAPI.types.message.ChatEvents.abstracts.SupergroupEvent
|
||||
import com.github.insanusmokrassar.TelegramBotAPI.types.message.abstracts.ChatEventMessage
|
||||
import com.github.insanusmokrassar.TelegramBotAPI.types.message.abstracts.SupergroupEventMessage
|
||||
import com.soywiz.klock.DateTime
|
||||
|
||||
data class SupergroupEventMessage(
|
||||
@Deprecated("Renamed", ReplaceWith("CommonSupergroupEventMessage"))
|
||||
typealias SupergroupEventMessage = CommonSupergroupEventMessage
|
||||
|
||||
data class CommonSupergroupEventMessage(
|
||||
override val messageId: MessageIdentifier,
|
||||
override val user: User,
|
||||
override val chat: SupergroupChat,
|
||||
override val chatEvent: SupergroupEvent,
|
||||
override val date: DateTime
|
||||
) : ChatEventMessage
|
||||
) : SupergroupEventMessage
|
||||
@@ -192,14 +192,16 @@ internal data class RawMessage(
|
||||
try {
|
||||
chatEvent?.let { chatEvent ->
|
||||
when (chat) {
|
||||
is SupergroupChat -> SupergroupEventMessage(
|
||||
is SupergroupChat -> CommonSupergroupEventMessage(
|
||||
messageId,
|
||||
from ?: error("Supergroup events are expected to contain 'from' field"),
|
||||
chat,
|
||||
chatEvent as? SupergroupEvent ?: throwWrongChatEvent(SupergroupEvent::class, chatEvent),
|
||||
date.asDate
|
||||
)
|
||||
is GroupChat -> GroupEventMessage(
|
||||
is GroupChat -> CommonGroupEventMessage(
|
||||
messageId,
|
||||
from ?: error("Supergroup events are expected to contain 'from' field"),
|
||||
chat,
|
||||
chatEvent as? GroupEvent ?: throwWrongChatEvent(GroupChat::class, chatEvent),
|
||||
date.asDate
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
package com.github.insanusmokrassar.TelegramBotAPI.types.message.abstracts
|
||||
|
||||
interface GroupEventMessage : ChatEventMessage, FromUserMessage
|
||||
@@ -0,0 +1,3 @@
|
||||
package com.github.insanusmokrassar.TelegramBotAPI.types.message.abstracts
|
||||
|
||||
interface SupergroupEventMessage : GroupEventMessage
|
||||
@@ -4,7 +4,7 @@ import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.supervisorScope
|
||||
|
||||
|
||||
typealias ExceptionHandler<T> = suspend (Exception) -> T
|
||||
typealias ExceptionHandler<T> = suspend (Throwable) -> T
|
||||
/**
|
||||
* It will run [block] inside of [supervisorScope] to avoid problems with catching of exceptions
|
||||
*
|
||||
@@ -17,7 +17,7 @@ suspend inline fun <T> handleSafely(
|
||||
): T {
|
||||
return try {
|
||||
supervisorScope(block)
|
||||
} catch (e: Exception) {
|
||||
} catch (e: Throwable) {
|
||||
onException(e)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@ internal val nonstrictJsonFormat = Json {
|
||||
ignoreUnknownKeys = true
|
||||
allowSpecialFloatingPointValues = true
|
||||
useArrayPolymorphism = true
|
||||
encodeDefaults = true
|
||||
}
|
||||
|
||||
fun <T: Any> T.toJsonWithoutNulls(serializer: SerializationStrategy<T>): JsonObject = toJson(serializer).withoutNulls()
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
package com.github.insanusmokrassar.TelegramBotAPI
|
||||
|
||||
import com.github.insanusmokrassar.TelegramBotAPI.requests.abstracts.toInputFile
|
||||
import com.github.insanusmokrassar.TelegramBotAPI.types.InputMedia.MediaGroupMemberInputMediaSerializer
|
||||
import com.github.insanusmokrassar.TelegramBotAPI.types.files.PhotoSize
|
||||
import com.github.insanusmokrassar.TelegramBotAPI.types.message.content.media.PhotoContent
|
||||
import kotlinx.serialization.json.Json
|
||||
import kotlin.test.Test
|
||||
import kotlin.test.assertEquals
|
||||
|
||||
private val nonstrictJsonFormat = Json {
|
||||
isLenient = true
|
||||
ignoreUnknownKeys = true
|
||||
allowSpecialFloatingPointValues = true
|
||||
useArrayPolymorphism = true
|
||||
encodeDefaults = true
|
||||
}
|
||||
|
||||
class SimpleInputFilesTest {
|
||||
@Test
|
||||
fun test_that_creating_of_photo_and_converting_to_input_media_working_correctly() {
|
||||
val photoContent = PhotoContent(
|
||||
listOf(
|
||||
PhotoSize("example_file_id".toInputFile(), "example_unique_file_id", 100, 100, 100)
|
||||
)
|
||||
)
|
||||
val inputMedia = photoContent.toMediaGroupMemberInputMedia()
|
||||
assertEquals(photoContent.media.fileId, inputMedia.file)
|
||||
val encoded = nonstrictJsonFormat.encodeToString(
|
||||
MediaGroupMemberInputMediaSerializer,
|
||||
inputMedia
|
||||
)
|
||||
assertEquals(
|
||||
inputMedia,
|
||||
nonstrictJsonFormat.decodeFromString(
|
||||
MediaGroupMemberInputMediaSerializer,
|
||||
encoded
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -2,4 +2,6 @@ package com.github.insanusmokrassar.TelegramBotAPI
|
||||
|
||||
import kotlinx.serialization.json.Json
|
||||
|
||||
val TestsJsonFormat = Json {}
|
||||
val TestsJsonFormat = Json {
|
||||
encodeDefaults = true
|
||||
}
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
{"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 Extensions for API","description":"API extensions which provide work with RequestsExecutor of TelegramBotAPI almost like it is described in original Telegram Bot API reference","url":"https://insanusmokrassar.github.io/TelegramBotAPI/TelegramBotAPI-extensions-api","vcsUrl":"https://github.com/insanusmokrassar/TelegramBotAPI.git","developers":[{"id":"InsanusMokrassar","name":"Ovsiannikov Aleksei","eMail":"ovsyannikov.alexey95@gmail.com"}]},"type":"Multiplatform"}
|
||||
1
TelegramBotAPI-extensions-api/mpp_publish_template.kpsb
Normal file
1
TelegramBotAPI-extensions-api/mpp_publish_template.kpsb
Normal file
@@ -0,0 +1 @@
|
||||
{"bintrayConfig":{"repo":"StandardRepository","packageName":"${project.name}","packageVcs":"https://github.com/InsanusMokrassar/TelegramBotAPI","autoPublish":true},"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 Extensions for API","description":"API extensions which provide work with RequestsExecutor of TelegramBotAPI almost like it is described in original Telegram Bot API reference","url":"https://insanusmokrassar.github.io/TelegramBotAPI/TelegramBotAPI-extensions-api","vcsUrl":"https://github.com/insanusmokrassar/TelegramBotAPI.git","developers":[{"id":"InsanusMokrassar","name":"Ovsiannikov Aleksei","eMail":"ovsyannikov.alexey95@gmail.com"}]},"type":"Multiplatform"}
|
||||
@@ -25,6 +25,9 @@ bintray {
|
||||
}
|
||||
into "${project.group}".replace(".", "/")
|
||||
}
|
||||
|
||||
publish = true
|
||||
|
||||
pkg {
|
||||
repo = "StandardRepository"
|
||||
name = "${project.name}"
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
package com.github.insanusmokrassar.TelegramBotAPI.extensions.api
|
||||
|
||||
import com.github.insanusmokrassar.TelegramBotAPI.bot.TelegramBot
|
||||
import com.github.insanusmokrassar.TelegramBotAPI.extensions.api.get.getFileAdditionalInfo
|
||||
import com.github.insanusmokrassar.TelegramBotAPI.requests.DownloadFile
|
||||
import com.github.insanusmokrassar.TelegramBotAPI.requests.abstracts.FileId
|
||||
import com.github.insanusmokrassar.TelegramBotAPI.types.files.PathedFile
|
||||
import com.github.insanusmokrassar.TelegramBotAPI.types.files.abstracts.TelegramMediaFile
|
||||
|
||||
suspend fun TelegramBot.downloadFile(
|
||||
filePath: String
|
||||
): ByteArray = execute(
|
||||
DownloadFile(filePath)
|
||||
)
|
||||
|
||||
suspend fun TelegramBot.downloadFile(
|
||||
pathedFile: PathedFile
|
||||
): ByteArray = execute(
|
||||
DownloadFile(pathedFile.filePath)
|
||||
)
|
||||
|
||||
suspend fun TelegramBot.downloadFile(
|
||||
fileId: FileId
|
||||
): ByteArray = downloadFile(
|
||||
getFileAdditionalInfo(fileId)
|
||||
)
|
||||
|
||||
suspend fun TelegramBot.downloadFile(
|
||||
file: TelegramMediaFile
|
||||
): ByteArray = downloadFile(
|
||||
getFileAdditionalInfo(file)
|
||||
)
|
||||
@@ -8,4 +8,5 @@ internal val nonstrictJsonFormat = Json {
|
||||
ignoreUnknownKeys = true
|
||||
allowSpecialFloatingPointValues = true
|
||||
useArrayPolymorphism = true
|
||||
encodeDefaults = true
|
||||
}
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
{"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/TelegramBotAPI-extensions-utils","vcsUrl":"https://github.com/insanusmokrassar/TelegramBotAPI.git","developers":[{"id":"InsanusMokrassar","name":"Ovsiannikov Aleksei","eMail":"ovsyannikov.alexey95@gmail.com"}]},"type":"Multiplatform"}
|
||||
@@ -0,0 +1 @@
|
||||
{"bintrayConfig":{"repo":"StandardRepository","packageName":"${project.name}","packageVcs":"https://github.com/InsanusMokrassar/TelegramBotAPI","autoPublish":true},"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/TelegramBotAPI-extensions-utils","vcsUrl":"https://github.com/insanusmokrassar/TelegramBotAPI.git","developers":[{"id":"InsanusMokrassar","name":"Ovsiannikov Aleksei","eMail":"ovsyannikov.alexey95@gmail.com"}]},"type":"Multiplatform"}
|
||||
@@ -25,6 +25,9 @@ bintray {
|
||||
}
|
||||
into "${project.group}".replace(".", "/")
|
||||
}
|
||||
|
||||
publish = true
|
||||
|
||||
pkg {
|
||||
repo = "StandardRepository"
|
||||
name = "${project.name}"
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package com.github.insanusmokrassar.TelegramBotAPI.extensions.utils
|
||||
|
||||
import com.github.insanusmokrassar.TelegramBotAPI.types.message.abstracts.CommonMessage
|
||||
import com.github.insanusmokrassar.TelegramBotAPI.types.message.abstracts.ContentMessage
|
||||
import com.github.insanusmokrassar.TelegramBotAPI.types.message.abstracts.*
|
||||
import com.github.insanusmokrassar.TelegramBotAPI.types.message.content.abstracts.MessageContent
|
||||
import com.github.insanusmokrassar.TelegramBotAPI.types.message.content.abstracts.PossiblySentViaBotCommonMessage
|
||||
import kotlinx.coroutines.flow.*
|
||||
@@ -11,17 +10,21 @@ import kotlinx.coroutines.flow.*
|
||||
*/
|
||||
fun <C: MessageContent, T : ContentMessage<C>> Flow<T>.onlyCommonMessages() = filterIsInstance<CommonMessage<C>>()
|
||||
|
||||
/**
|
||||
* Shortcut for [onlyCommonMessages]
|
||||
*/
|
||||
@Suppress("NOTHING_TO_INLINE")
|
||||
inline fun <C: MessageContent, T : ContentMessage<C>> Flow<T>.commonMessages() = onlyCommonMessages()
|
||||
|
||||
/**
|
||||
* Filter the messages and checking that incoming [CommonMessage] is [PossiblySentViaBotCommonMessage] and its
|
||||
* [PossiblySentViaBotCommonMessage.senderBot] is not null
|
||||
*/
|
||||
fun <T : MessageContent> Flow<CommonMessage<T>>.onlySentViaBot() = mapNotNull {
|
||||
(it as? PossiblySentViaBotCommonMessage) ?.let { possiblySentViaBot ->
|
||||
if (possiblySentViaBot.senderBot != null) {
|
||||
possiblySentViaBot
|
||||
} else {
|
||||
null
|
||||
}
|
||||
fun <MC : MessageContent, M : ContentMessage<MC>> Flow<M>.onlySentViaBot() = mapNotNull {
|
||||
if (it is PossiblySentViaBot && it.senderBot != null) {
|
||||
it
|
||||
} else {
|
||||
null
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,6 +32,6 @@ fun <T : MessageContent> Flow<CommonMessage<T>>.onlySentViaBot() = mapNotNull {
|
||||
* Filter the messages and checking that incoming [CommonMessage] not is [PossiblySentViaBotCommonMessage] or its
|
||||
* [PossiblySentViaBotCommonMessage.senderBot] is null
|
||||
*/
|
||||
fun <T : MessageContent> Flow<CommonMessage<T>>.withoutSentViaBot() = filter {
|
||||
it !is PossiblySentViaBotCommonMessage || it.senderBot == null
|
||||
fun <MC : MessageContent, M : ContentMessage<MC>> Flow<M>.withoutSentViaBot() = filter {
|
||||
it !is PossiblySentViaBot || it.senderBot == null
|
||||
}
|
||||
|
||||
@@ -8,4 +8,5 @@ internal val nonstrictJsonFormat = Json {
|
||||
ignoreUnknownKeys = true
|
||||
allowSpecialFloatingPointValues = true
|
||||
useArrayPolymorphism = true
|
||||
encodeDefaults = true
|
||||
}
|
||||
|
||||
@@ -17,5 +17,5 @@ fun <T : ChatEventMessage> Flow<ChatEventMessage>.divideBySource(contentType: KC
|
||||
}
|
||||
|
||||
fun Flow<ChatEventMessage>.onlyChannelEvents() = divideBySource(ChannelEventMessage::class)
|
||||
fun Flow<ChatEventMessage>.onlyGroupEvents() = divideBySource(GroupEventMessage::class)
|
||||
fun Flow<ChatEventMessage>.onlySupergroupEvents() = divideBySource(SupergroupEventMessage::class)
|
||||
fun Flow<ChatEventMessage>.onlyGroupEvents() = divideBySource(CommonGroupEventMessage::class)
|
||||
fun Flow<ChatEventMessage>.onlySupergroupEvents() = divideBySource(CommonSupergroupEventMessage::class)
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
package com.github.insanusmokrassar.TelegramBotAPI.extensions.utils.extensions
|
||||
|
||||
import com.github.insanusmokrassar.TelegramBotAPI.types.files.PathedFile
|
||||
import com.github.insanusmokrassar.TelegramBotAPI.utils.TelegramAPIUrlsKeeper
|
||||
import io.ktor.client.HttpClient
|
||||
import io.ktor.client.request.get
|
||||
|
||||
suspend fun HttpClient.loadFile(
|
||||
telegramAPIUrlsKeeper: TelegramAPIUrlsKeeper,
|
||||
filePath: String
|
||||
) = get<ByteArray>("${telegramAPIUrlsKeeper.fileBaseUrl}/$filePath")
|
||||
|
||||
suspend fun HttpClient.loadFile(
|
||||
telegramAPIUrlsKeeper: TelegramAPIUrlsKeeper,
|
||||
pathedFile: PathedFile
|
||||
) = loadFile(telegramAPIUrlsKeeper, pathedFile.filePath)
|
||||
|
||||
suspend fun PathedFile.download(
|
||||
telegramAPIUrlsKeeper: TelegramAPIUrlsKeeper,
|
||||
client: HttpClient = HttpClient()
|
||||
) = client.loadFile(telegramAPIUrlsKeeper, this)
|
||||
@@ -0,0 +1,16 @@
|
||||
package com.github.insanusmokrassar.TelegramBotAPI.extensions.utils.internal_utils
|
||||
|
||||
import com.github.insanusmokrassar.TelegramBotAPI.types.UpdateIdentifier
|
||||
import com.github.insanusmokrassar.TelegramBotAPI.types.update.abstracts.Update
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.mapNotNull
|
||||
|
||||
internal inline fun <reified T : Any, UT : Update> Flow<UT>.onlySpecifiedTypeOfDataWithUpdates(): Flow<Pair<UpdateIdentifier, T>> {
|
||||
return mapNotNull {
|
||||
it.updateId to (it.data as? T ?: return@mapNotNull null)
|
||||
}
|
||||
}
|
||||
|
||||
internal inline fun <reified T : Any, UT : Update> Flow<UT>.onlySpecifiedTypeOfData(): Flow<T> {
|
||||
return mapNotNull { it as? T }
|
||||
}
|
||||
@@ -0,0 +1,94 @@
|
||||
package com.github.insanusmokrassar.TelegramBotAPI.extensions.utils.shortcuts
|
||||
|
||||
import com.github.insanusmokrassar.TelegramBotAPI.CommonAbstracts.TextSource
|
||||
import com.github.insanusmokrassar.TelegramBotAPI.extensions.utils.onlyTextContentMessages
|
||||
import com.github.insanusmokrassar.TelegramBotAPI.extensions.utils.updates.asContentMessagesFlow
|
||||
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.abstracts.ContentMessage
|
||||
import com.github.insanusmokrassar.TelegramBotAPI.types.message.content.TextContent
|
||||
import com.github.insanusmokrassar.TelegramBotAPI.types.message.content.fullEntitiesList
|
||||
import kotlinx.coroutines.flow.*
|
||||
|
||||
/**
|
||||
* Convert incoming [com.github.insanusmokrassar.TelegramBotAPI.types.message.abstracts.ContentMessage.content] of
|
||||
* messages with [fullEntitiesList] and check that incoming message contains ONLY ONE [TextSource] and that is
|
||||
* [BotCommandTextSource]. Besides, it is checking that [BotCommandTextSource.command] [Regex.matches] with incoming
|
||||
* [commandRegex]
|
||||
*
|
||||
* @return The same message in case if it contains only [BotCommandTextSource] with [Regex.matches]
|
||||
* [BotCommandTextSource.command]
|
||||
*
|
||||
* @see fullEntitiesList
|
||||
* @see asContentMessagesFlow
|
||||
* @see onlyTextContentMessages
|
||||
* @see textMessages
|
||||
*/
|
||||
fun <T : ContentMessage<TextContent>> Flow<T>.filterExactCommands(
|
||||
commandRegex: Regex
|
||||
) = filter { contentMessage ->
|
||||
(contentMessage.content.fullEntitiesList().singleOrNull() as? BotCommandTextSource) ?.let { commandRegex.matches(it.command) } == true
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert incoming [com.github.insanusmokrassar.TelegramBotAPI.types.message.abstracts.ContentMessage.content] of
|
||||
* messages with [fullEntitiesList] and check that incoming message contains [BotCommandTextSource]. Besides, it is
|
||||
* checking that [BotCommandTextSource.command] [Regex.matches] with incoming [commandRegex]
|
||||
*
|
||||
* @return The same message in case if it contains somewhere in text [BotCommandTextSource] with [Regex.matches]
|
||||
* [BotCommandTextSource.command]
|
||||
*
|
||||
* @see fullEntitiesList
|
||||
* @see asContentMessagesFlow
|
||||
* @see onlyTextContentMessages
|
||||
* @see textMessages
|
||||
*/
|
||||
fun <T : ContentMessage<TextContent>> Flow<T>.filterCommandsInsideTextMessages(
|
||||
commandRegex: Regex
|
||||
) = filter { contentMessage ->
|
||||
contentMessage.content.fullEntitiesList().any {
|
||||
(it as? BotCommandTextSource) ?.let { commandRegex.matches(it.command) } == true
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert incoming [com.github.insanusmokrassar.TelegramBotAPI.types.message.abstracts.ContentMessage.content] of
|
||||
* messages with [fullEntitiesList] and check that incoming message contains first [TextSource] as
|
||||
* [BotCommandTextSource]. Besides, it is checking that [BotCommandTextSource.command] [Regex.matches] with incoming
|
||||
* [commandRegex] and for other [TextSource] objects used next rules: all incoming text sources will be passed as is,
|
||||
* [RegularTextSource] will be split by " " for several [RegularTextSource] which will contains not empty args without
|
||||
* spaces.
|
||||
*
|
||||
* @return Paired original message and converted list with first entity [BotCommandTextSource] and than all others
|
||||
* according to rules in description
|
||||
*
|
||||
* @see fullEntitiesList
|
||||
* @see asContentMessagesFlow
|
||||
* @see onlyTextContentMessages
|
||||
* @see textMessages
|
||||
*/
|
||||
fun <T : ContentMessage<TextContent>> Flow<T>.filterCommandsWithArgs(
|
||||
commandRegex: Regex
|
||||
) = mapNotNull { contentMessage ->
|
||||
val allEntities = contentMessage.content.fullEntitiesList()
|
||||
(allEntities.firstOrNull() as? BotCommandTextSource) ?.let {
|
||||
if (commandRegex.matches(it.command)) {
|
||||
contentMessage to allEntities.flatMap {
|
||||
when (it) {
|
||||
is RegularTextSource -> it.source.split(" ").mapNotNull { regularTextSourcePart ->
|
||||
if (regularTextSourcePart.isNotBlank()) {
|
||||
RegularTextSource(regularTextSourcePart)
|
||||
} else {
|
||||
null
|
||||
}
|
||||
}
|
||||
else -> listOf(it)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
null
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -4,15 +4,15 @@ import com.github.insanusmokrassar.TelegramBotAPI.requests.send.media.SendMediaG
|
||||
import com.github.insanusmokrassar.TelegramBotAPI.types.*
|
||||
import com.github.insanusmokrassar.TelegramBotAPI.types.chat.abstracts.Chat
|
||||
import com.github.insanusmokrassar.TelegramBotAPI.types.message.ForwardInfo
|
||||
import com.github.insanusmokrassar.TelegramBotAPI.types.message.abstracts.MediaGroupMessage
|
||||
import com.github.insanusmokrassar.TelegramBotAPI.types.message.abstracts.Message
|
||||
import com.github.insanusmokrassar.TelegramBotAPI.types.message.abstracts.*
|
||||
import com.github.insanusmokrassar.TelegramBotAPI.types.message.content.abstracts.MediaGroupContent
|
||||
import com.github.insanusmokrassar.TelegramBotAPI.types.update.MediaGroupUpdates.SentMediaGroupUpdate
|
||||
|
||||
val List<MediaGroupMessage>.forwardInfo: ForwardInfo?
|
||||
val List<CommonMessage<MediaGroupContent>>.forwardInfo: ForwardInfo?
|
||||
get() = firstOrNull() ?.forwardInfo
|
||||
val List<MediaGroupMessage>.replyTo: Message?
|
||||
val List<CommonMessage<MediaGroupContent>>.replyTo: Message?
|
||||
get() = firstOrNull() ?.replyTo
|
||||
val List<MediaGroupMessage>.chat: Chat?
|
||||
val List<CommonMessage<MediaGroupContent>>.chat: Chat?
|
||||
get() = firstOrNull() ?.chat
|
||||
val List<MediaGroupMessage>.mediaGroupId: MediaGroupIdentifier?
|
||||
get() = firstOrNull() ?.mediaGroupId
|
||||
@@ -26,7 +26,7 @@ val SentMediaGroupUpdate.chat: Chat
|
||||
val SentMediaGroupUpdate.mediaGroupId: MediaGroupIdentifier
|
||||
get() = data.mediaGroupId!!
|
||||
|
||||
fun List<MediaGroupMessage>.createResend(
|
||||
fun List<CommonMessage<MediaGroupContent>>.createResend(
|
||||
chatId: ChatId,
|
||||
disableNotification: Boolean = false,
|
||||
replyTo: MessageIdentifier? = null
|
||||
@@ -37,7 +37,7 @@ fun List<MediaGroupMessage>.createResend(
|
||||
replyTo
|
||||
)
|
||||
|
||||
fun List<MediaGroupMessage>.createResend(
|
||||
fun List<CommonMessage<MediaGroupContent>>.createResend(
|
||||
chat: Chat,
|
||||
disableNotification: Boolean = false,
|
||||
replyTo: MessageIdentifier? = null
|
||||
|
||||
@@ -24,10 +24,10 @@ suspend fun <T: Any> RequestsExecutor.executeUnsafe(
|
||||
request: Request<T>,
|
||||
retries: Int = 0,
|
||||
retriesDelay: Long = 1000L,
|
||||
onAllFailed: (suspend (exceptions: Array<Exception>) -> Unit)? = null
|
||||
onAllFailed: (suspend (exceptions: Array<Throwable>) -> Unit)? = null
|
||||
): T? {
|
||||
var leftRetries = retries
|
||||
val exceptions = onAllFailed ?.let { mutableListOf<Exception>() }
|
||||
val exceptions = onAllFailed ?.let { mutableListOf<Throwable>() }
|
||||
do {
|
||||
return handleSafely(
|
||||
{
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
package com.github.insanusmokrassar.TelegramBotAPI.extensions.utils.updates
|
||||
|
||||
import com.github.insanusmokrassar.TelegramBotAPI.extensions.utils.internal_utils.onlySpecifiedTypeOfData
|
||||
import com.github.insanusmokrassar.TelegramBotAPI.extensions.utils.internal_utils.onlySpecifiedTypeOfDataWithUpdates
|
||||
import com.github.insanusmokrassar.TelegramBotAPI.types.InlineQueries.ChosenInlineResult.BaseChosenInlineResult
|
||||
import com.github.insanusmokrassar.TelegramBotAPI.types.InlineQueries.ChosenInlineResult.LocationChosenInlineResult
|
||||
import com.github.insanusmokrassar.TelegramBotAPI.types.UpdateIdentifier
|
||||
import com.github.insanusmokrassar.TelegramBotAPI.types.update.ChosenInlineResultUpdate
|
||||
import com.github.insanusmokrassar.TelegramBotAPI.types.update.InlineQueryUpdate
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
|
||||
/**
|
||||
* @return Mapped [Flow] with [Pair]s. [Pair.first] in this pair will be [UpdateIdentifier]. It could be useful in
|
||||
* cases you are using [InlineQueryUpdate.updateId] for some reasons. [Pair.second] will always be [BaseChosenInlineResult].
|
||||
*/
|
||||
fun Flow<ChosenInlineResultUpdate>.onlyBaseChosenInlineResultsWithUpdates(): Flow<Pair<UpdateIdentifier, BaseChosenInlineResult>> = onlySpecifiedTypeOfDataWithUpdates()
|
||||
|
||||
/**
|
||||
* @return Filter updates only with [BaseChosenInlineResult] and map it to a [Flow] with values [BaseChosenInlineResult]
|
||||
*
|
||||
* @see onlyBaseChosenInlineResultsWithUpdates
|
||||
*/
|
||||
fun Flow<ChosenInlineResultUpdate>.onlyBaseChosenInlineResults(): Flow<BaseChosenInlineResult> = onlySpecifiedTypeOfData()
|
||||
|
||||
/**
|
||||
* @return Mapped [Flow] with [Pair]s. [Pair.first] in this pair will be [UpdateIdentifier]. It could be useful in
|
||||
* cases you are using [InlineQueryUpdate.updateId] for some reasons. [Pair.second] will always be [LocationChosenInlineResult].
|
||||
*/
|
||||
fun Flow<ChosenInlineResultUpdate>.onlyLocationChosenInlineResultsWithUpdates(): Flow<Pair<UpdateIdentifier, LocationChosenInlineResult>> = onlySpecifiedTypeOfDataWithUpdates()
|
||||
|
||||
/**
|
||||
* @return Filter updates only with [LocationChosenInlineResult] and map it to a [Flow] with values [LocationChosenInlineResult]
|
||||
*
|
||||
* @see onlyLocationChosenInlineResultsWithUpdates
|
||||
*/
|
||||
fun Flow<ChosenInlineResultUpdate>.onlyLocationChosenInlineResults(): Flow<LocationChosenInlineResult> = onlySpecifiedTypeOfData()
|
||||
@@ -2,8 +2,11 @@ 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.extensions.utils.shortcuts.*
|
||||
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.abstracts.ContentMessage
|
||||
import com.github.insanusmokrassar.TelegramBotAPI.types.message.content.TextContent
|
||||
import com.github.insanusmokrassar.TelegramBotAPI.types.message.content.fullEntitiesList
|
||||
import com.github.insanusmokrassar.TelegramBotAPI.types.update.abstracts.BaseSentMessageUpdate
|
||||
import kotlinx.coroutines.flow.*
|
||||
@@ -23,9 +26,7 @@ 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
|
||||
}
|
||||
) = textMessages().filterExactCommands(commandRegex)
|
||||
|
||||
/**
|
||||
* Convert incoming [com.github.insanusmokrassar.TelegramBotAPI.types.message.abstracts.ContentMessage.content] of
|
||||
@@ -41,11 +42,7 @@ fun <T : BaseSentMessageUpdate> Flow<T>.filterExactCommands(
|
||||
*/
|
||||
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
|
||||
}
|
||||
}
|
||||
) = textMessages().filterCommandsInsideTextMessages(commandRegex)
|
||||
|
||||
/**
|
||||
* Convert incoming [com.github.insanusmokrassar.TelegramBotAPI.types.message.abstracts.ContentMessage.content] of
|
||||
@@ -55,7 +52,8 @@ fun <T : BaseSentMessageUpdate> Flow<T>.filterCommandsInsideTextMessages(
|
||||
* [RegularTextSource] will be split by " " for several [RegularTextSource] which will contains not empty args without
|
||||
* spaces.
|
||||
*
|
||||
* @return Converted list with first entity [BotCommandTextSource] and than all others according to rules in description
|
||||
* @return Paired original message and converted list with first entity [BotCommandTextSource] and than all others
|
||||
* according to rules in description
|
||||
*
|
||||
* @see fullEntitiesList
|
||||
* @see asContentMessagesFlow
|
||||
@@ -63,24 +61,4 @@ fun <T : BaseSentMessageUpdate> Flow<T>.filterCommandsInsideTextMessages(
|
||||
*/
|
||||
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
|
||||
}
|
||||
}
|
||||
}
|
||||
): Flow<Pair<ContentMessage<TextContent>, List<TextSource>>> = textMessages().filterCommandsWithArgs(commandRegex)
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
package com.github.insanusmokrassar.TelegramBotAPI.extensions.utils.updates
|
||||
|
||||
import com.github.insanusmokrassar.TelegramBotAPI.extensions.utils.internal_utils.onlySpecifiedTypeOfData
|
||||
import com.github.insanusmokrassar.TelegramBotAPI.extensions.utils.internal_utils.onlySpecifiedTypeOfDataWithUpdates
|
||||
import com.github.insanusmokrassar.TelegramBotAPI.types.InlineQueries.query.BaseInlineQuery
|
||||
import com.github.insanusmokrassar.TelegramBotAPI.types.InlineQueries.query.LocationInlineQuery
|
||||
import com.github.insanusmokrassar.TelegramBotAPI.types.UpdateIdentifier
|
||||
import com.github.insanusmokrassar.TelegramBotAPI.types.update.InlineQueryUpdate
|
||||
import kotlinx.coroutines.flow.*
|
||||
|
||||
/**
|
||||
* @return Mapped [Flow] with [Pair]s. [Pair.first] in this pair will be [UpdateIdentifier]. It could be useful in
|
||||
* cases you are using [InlineQueryUpdate.updateId] for some reasons. [Pair.second] will always be [BaseInlineQuery].
|
||||
*/
|
||||
fun Flow<InlineQueryUpdate>.onlyBaseInlineQueriesWithUpdates(): Flow<Pair<UpdateIdentifier, BaseInlineQuery>> = onlySpecifiedTypeOfDataWithUpdates()
|
||||
|
||||
/**
|
||||
* @return Filter updates only with [BaseInlineQuery] and map it to a [Flow] with values [BaseInlineQuery]
|
||||
*
|
||||
* @see onlyBaseInlineQueriesWithUpdates
|
||||
*/
|
||||
fun Flow<InlineQueryUpdate>.onlyBaseInlineQueries(): Flow<BaseInlineQuery> = onlySpecifiedTypeOfData()
|
||||
|
||||
/**
|
||||
* @return Mapped [Flow] with [Pair]s. [Pair.first] in this pair will be [UpdateIdentifier]. It could be useful in
|
||||
* cases you are using [InlineQueryUpdate.updateId] for some reasons. [Pair.second] will always be [LocationInlineQuery].
|
||||
*/
|
||||
fun Flow<InlineQueryUpdate>.onlyLocationInlineQueriesWithUpdates(): Flow<Pair<UpdateIdentifier, LocationInlineQuery>> = onlySpecifiedTypeOfDataWithUpdates()
|
||||
|
||||
/**
|
||||
* @return Filter updates only with [LocationInlineQuery] and map it to a [Flow] with values [LocationInlineQuery]
|
||||
*
|
||||
* @see onlyLocationInlineQueriesWithUpdates
|
||||
*/
|
||||
fun Flow<InlineQueryUpdate>.onlyLocationInlineQueries(): Flow<LocationInlineQuery> = onlySpecifiedTypeOfData()
|
||||
@@ -0,0 +1,29 @@
|
||||
package com.github.insanusmokrassar.TelegramBotAPI.types.files
|
||||
|
||||
import com.github.insanusmokrassar.TelegramBotAPI.utils.TelegramAPIUrlsKeeper
|
||||
import java.io.File
|
||||
import java.io.FileOutputStream
|
||||
import java.io.InputStream
|
||||
import java.net.URL
|
||||
|
||||
fun PathedFile.asStream(
|
||||
telegramAPIUrlsKeeper: TelegramAPIUrlsKeeper
|
||||
): InputStream = URL(this.fullUrl(telegramAPIUrlsKeeper)).openStream()
|
||||
|
||||
fun PathedFile.asFile(
|
||||
telegramAPIUrlsKeeper: TelegramAPIUrlsKeeper,
|
||||
dest: File = File.createTempFile(this.fileUniqueId, this.filename),
|
||||
defaultBufferSize: Int = DEFAULT_BUFFER_SIZE
|
||||
): File {
|
||||
this.asStream(telegramAPIUrlsKeeper).use { input ->
|
||||
FileOutputStream(dest).use { out ->
|
||||
input.copyTo(out, defaultBufferSize)
|
||||
}
|
||||
}
|
||||
return dest
|
||||
}
|
||||
|
||||
fun PathedFile.asBytes(
|
||||
telegramAPIUrlsKeeper: TelegramAPIUrlsKeeper
|
||||
): ByteArray = this.asStream(telegramAPIUrlsKeeper)
|
||||
.use { input -> input.readBytes() }
|
||||
@@ -1 +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","description":"This project just include all subproject of TelegramBotAPI","url":"https://insanusmokrassar.github.io/TelegramBotAPI/TelegramBotAPI","vcsUrl":"https://github.com/insanusmokrassar/TelegramBotAPI.git","developers":[{"id":"InsanusMokrassar","name":"Ovsiannikov Aleksei","eMail":"ovsyannikov.alexey95@gmail.com"}]},"type":"Multiplatform"}
|
||||
{"bintrayConfig":{"repo":"StandardRepository","packageName":"${project.name}","packageVcs":"https://github.com/InsanusMokrassar/TelegramBotAPI","autoPublish":true},"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","description":"This project just include all subproject of TelegramBotAPI","url":"https://insanusmokrassar.github.io/TelegramBotAPI/TelegramBotAPI","vcsUrl":"https://github.com/insanusmokrassar/TelegramBotAPI.git","developers":[{"id":"InsanusMokrassar","name":"Ovsiannikov Aleksei","eMail":"ovsyannikov.alexey95@gmail.com"}]},"type":"Multiplatform"}
|
||||
@@ -25,6 +25,9 @@ bintray {
|
||||
}
|
||||
into "${project.group}".replace(".", "/")
|
||||
}
|
||||
|
||||
publish = true
|
||||
|
||||
pkg {
|
||||
repo = "StandardRepository"
|
||||
name = "${project.name}"
|
||||
|
||||
30
build.gradle
30
build.gradle
@@ -3,12 +3,14 @@ buildscript {
|
||||
mavenLocal()
|
||||
jcenter()
|
||||
mavenCentral()
|
||||
maven { url "https://plugins.gradle.org/m2/" }
|
||||
}
|
||||
|
||||
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"
|
||||
classpath "com.github.breadmoirai:github-release:$github_release_plugin_version"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,3 +18,31 @@ plugins {
|
||||
id "org.jetbrains.kotlin.multiplatform" version "$kotlin_version" apply false
|
||||
id "org.jetbrains.kotlin.plugin.serialization" version "$kotlin_version" apply false
|
||||
}
|
||||
|
||||
private String getCurrentVersionChangelog() {
|
||||
OutputStream changelogDataOS = new ByteArrayOutputStream()
|
||||
exec {
|
||||
standardOutput = changelogDataOS
|
||||
commandLine './changelog_info_retriever', "$library_version", 'CHANGELOG.md'
|
||||
}
|
||||
|
||||
return changelogDataOS.toString().trim()
|
||||
}
|
||||
|
||||
if (new File(projectDir, "secret.gradle").exists()) {
|
||||
apply from: './secret.gradle'
|
||||
apply plugin: "com.github.breadmoirai.github-release"
|
||||
|
||||
githubRelease {
|
||||
token "${project.property('GITHUB_RELEASE_TOKEN')}"
|
||||
|
||||
owner "InsanusMokrassar"
|
||||
repo "TelegramBotAPI"
|
||||
|
||||
tagName "$library_version"
|
||||
releaseName "$library_version"
|
||||
targetCommitish "$library_version"
|
||||
|
||||
body getCurrentVersionChangelog()
|
||||
}
|
||||
}
|
||||
|
||||
29
changelog_info_retriever
Executable file
29
changelog_info_retriever
Executable file
@@ -0,0 +1,29 @@
|
||||
#!/bin/bash
|
||||
|
||||
function parse() {
|
||||
version=$1
|
||||
|
||||
read -r
|
||||
while [ -z "`echo $REPLY | grep -e "^#\+ $version"`" ]
|
||||
do
|
||||
read -r
|
||||
done
|
||||
|
||||
read -r
|
||||
while [ -z "`echo $REPLY | grep -e "^#\+"`" ]
|
||||
do
|
||||
echo "$REPLY"
|
||||
read -r
|
||||
done
|
||||
}
|
||||
|
||||
version=$1
|
||||
file=$2
|
||||
|
||||
if [ -n "$file" ]; then
|
||||
parse $version < "$file"
|
||||
else
|
||||
parse $version
|
||||
fi
|
||||
|
||||
|
||||
@@ -5,16 +5,17 @@ kotlin.js.generate.externals=true
|
||||
kotlin.incremental=true
|
||||
kotlin.incremental.js=true
|
||||
|
||||
kotlin_version=1.4.0
|
||||
kotlin_version=1.4.10
|
||||
kotlin_coroutines_version=1.3.9
|
||||
kotlin_serialisation_runtime_version=1.0.0-RC
|
||||
klock_version=1.12.0
|
||||
uuid_version=0.2.1
|
||||
ktor_version=1.4.0
|
||||
kotlin_serialisation_runtime_version=1.0.0-RC2
|
||||
klock_version=1.12.1
|
||||
uuid_version=0.2.2
|
||||
ktor_version=1.4.1
|
||||
|
||||
javax_activation_version=1.1.1
|
||||
|
||||
library_group=com.github.insanusmokrassar
|
||||
library_version=0.28.0-rc
|
||||
library_version=0.28.4
|
||||
|
||||
gradle_bintray_plugin_version=1.8.5
|
||||
github_release_plugin_version=2.2.12
|
||||
|
||||
2
gradle/wrapper/gradle-wrapper.properties
vendored
2
gradle/wrapper/gradle-wrapper.properties
vendored
@@ -2,4 +2,4 @@ distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-6.6-bin.zip
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-6.6.1-bin.zip
|
||||
|
||||
Reference in New Issue
Block a user