mirror of
https://github.com/InsanusMokrassar/TelegramBotAPI.git
synced 2024-11-22 16:23:48 +00:00
commit
59680439fa
18
CHANGELOG.md
18
CHANGELOG.md
@ -1,5 +1,23 @@
|
|||||||
# TelegramBotAPI changelog
|
# TelegramBotAPI changelog
|
||||||
|
|
||||||
|
## 0.14.0
|
||||||
|
|
||||||
|
* Now library have no default engine for both webhooks and requests executor. It is required for clients to set
|
||||||
|
some default library
|
||||||
|
* All proxy help methods was removed . They are will be replaced in separated project
|
||||||
|
* `Ktor` version `1.1.3` -> `1.1.4`
|
||||||
|
* Requests results now always decoding as `UTF-8`
|
||||||
|
* `AbstractRequestCallFactory` was added with cache of methods urls to avoid memory leaks
|
||||||
|
* Small refactoring of work with response in `KtorRequestsExecutor`
|
||||||
|
* Kotlin version `1.3.30` -> `1.3.31`
|
||||||
|
* Kotlin coroutines `1.2.0` -> `1.2.1`
|
||||||
|
* `CommonForwardedMessage` was renamed to `UserForwardedMessage`
|
||||||
|
* All forwarded messages are now just childs of `ForwardedMessage`:
|
||||||
|
* `AnonymousForwardedMessage` - for messages without forwarded info
|
||||||
|
* `UserForwardedMessage` - for messages from users and groups (contains not message id)
|
||||||
|
* `ForwardedFromChannelMessage` - for messages from channels
|
||||||
|
* Changed logic of forwarded messages preparing
|
||||||
|
|
||||||
## 0.13.0 Telegram Polls
|
## 0.13.0 Telegram Polls
|
||||||
|
|
||||||
* Type `PollOption` and `AnonymousPollOption` added
|
* Type `PollOption` and `AnonymousPollOption` added
|
||||||
|
98
README.md
98
README.md
@ -46,23 +46,82 @@ compile "com.github.insanusmokrassar:TelegramBotAPI:${telegrambotapi.version}"
|
|||||||
|
|
||||||
## How to work with library?
|
## How to work with library?
|
||||||
|
|
||||||
By default in any documentation will be meaning that you have variable in scope with names
|
For now, this library have no some API god-object. Instead of this, this library has several
|
||||||
|
important objects:
|
||||||
|
|
||||||
| Name of variable | Description | Where to get? (Examples) |
|
* [RequestsExecutor](src/main/kotlin/com/github/insanusmokrassar/TelegramBotAPI/bot/RequestsExecutor.kt)
|
||||||
|:----------------:|:-----------:|:------------------------:|
|
* [Requests](src/main/kotlin/com/github/insanusmokrassar/TelegramBotAPI/requests)
|
||||||
| executor | [RequestsExecutor](src/main/kotlin/com/github/insanusmokrassar/TelegramBotAPI/bot/RequestsExecutor.kt) | [Ktor RequestExecutor realisation](src/main/kotlin/com/github/insanusmokrassar/TelegramBotAPI/bot/Ktor/KtorRequestsExecutor.kt) |
|
* [Types](src/main/kotlin/com/github/insanusmokrassar/TelegramBotAPI/types)
|
||||||
|
|
||||||
## Requests Examples
|
### Types
|
||||||
|
|
||||||
### Get Me
|
Types declare different objects representation. For example, `Chat` for now represented as
|
||||||
|
interface and has several realisations:
|
||||||
|
|
||||||
|
* PrivateChat
|
||||||
|
* GroupChat
|
||||||
|
* SupergroupChat
|
||||||
|
* ChannelChat
|
||||||
|
|
||||||
|
Instead of common garbage with all information as in original [Chat](https://core.telegram.org/bots/api#chat),
|
||||||
|
here it was separated for more obvious difference between chats types and their possible content.
|
||||||
|
|
||||||
|
The same principle work with a lot of others things in this Telegram bot API.
|
||||||
|
|
||||||
|
### Requests
|
||||||
|
|
||||||
|
Requests usually are very simple objects, but some of them are using their own
|
||||||
|
build factories. For example, the next code show, how to get information about bot:
|
||||||
|
|
||||||
```kotlin
|
```kotlin
|
||||||
executor.execute(GetMe())
|
val requestsExecutor: RequestsExecutor = ...
|
||||||
|
requestsExecutor.execute(GetMe())
|
||||||
```
|
```
|
||||||
|
|
||||||
As a result you will receive `User` object. This object used as is now (as in API documentation), but it is possible
|
The result type of [GetMe](src/main/kotlin/com/github/insanusmokrassar/TelegramBotAPI/requests/GetMe) request is
|
||||||
that this class will be renamed to `RawUser` and you will be able to get real realisation of this object like `Bot` (in
|
[User](src/main/kotlin/com/github/insanusmokrassar/TelegramBotAPI/types/User). In fact, in this result must contain
|
||||||
cases when `isBot` == `true`) or `User` (otherwise)
|
`isBot` equal to `true` always.
|
||||||
|
|
||||||
|
|
||||||
|
### RequestsExecutor
|
||||||
|
|
||||||
|
It is base object which can be used to execute requests in API. For now by default included Ktor
|
||||||
|
realisation of `RequestsExecutor`, but it is possible, that in future it will be extracted in separated
|
||||||
|
project. How to create `RequestsExecutor`:
|
||||||
|
|
||||||
|
```kotlin
|
||||||
|
val requestsExecutor = KtorRequestsExecutor(TOKEN)
|
||||||
|
```
|
||||||
|
|
||||||
|
Here `KtorRequestsExecutor` - default realisation with Ktor. `TOKEN` is just a token of bot which was retrieved
|
||||||
|
according to [instruction](https://core.telegram.org/bots#3-how-do-i-create-a-bot).
|
||||||
|
|
||||||
|
Besides, for correct usage of this, you must implement in your project both one of engines for client and server
|
||||||
|
Ktor libraries:
|
||||||
|
|
||||||
|
```groovy
|
||||||
|
dependencies {
|
||||||
|
// ...
|
||||||
|
implementation "io.ktor:ktor-server-cio:$ktor_version"
|
||||||
|
implementation "io.ktor:ktor-client-okhttp:$ktor_version"
|
||||||
|
// ...
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
It is able to avoid using of `server` dependency in case if will not be used `Webhook`s. In this case,
|
||||||
|
dependencies list will be simplify:
|
||||||
|
|
||||||
|
```groovy
|
||||||
|
dependencies {
|
||||||
|
// ...
|
||||||
|
implementation "io.ktor:ktor-client-okhttp:$ktor_version"
|
||||||
|
// ...
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Here was used `okhttp` realisation of client, but there are several others engines for Ktor. More information
|
||||||
|
available on ktor.io site for [client](https://ktor.io/clients/http-client/engines.html) and [server](https://ktor.io/quickstart/artifacts.html)
|
||||||
|
engines.
|
||||||
|
|
||||||
## Getting updates
|
## Getting updates
|
||||||
|
|
||||||
@ -95,3 +154,22 @@ Template for Nginx server config you can find in [this gist](https://gist.github
|
|||||||
For webhook you can provide `File` with public part of certificate, `URL` where bot will be available and inner `PORT` which
|
For webhook you can provide `File` with public part of certificate, `URL` where bot will be available and inner `PORT` which
|
||||||
will be used to start receiving of updates. Actually, you can skip passing of `File` when you have something like
|
will be used to start receiving of updates. Actually, you can skip passing of `File` when you have something like
|
||||||
nginx for proxy forwarding.
|
nginx for proxy forwarding.
|
||||||
|
|
||||||
|
In case of using `nginx` with reverse-proxy config, setting up of Webhook will look like:
|
||||||
|
|
||||||
|
```kotlin
|
||||||
|
requestsExecutor.setWebhook(
|
||||||
|
WEBHOOK_URL,
|
||||||
|
INTERNAL_PORT,
|
||||||
|
filter,
|
||||||
|
ENGINE_FACTORY
|
||||||
|
)
|
||||||
|
```
|
||||||
|
|
||||||
|
Here:
|
||||||
|
|
||||||
|
* `WEBHOOK_URL` - the url which will be used by Telegram system to send updates
|
||||||
|
* `INTERNAL_PORT` - the port which will be used in bot for listening of updates
|
||||||
|
* `filter` - instance of [UpdatesFilter](src/main/kotlin/com/github/insanusmokrassar/TelegramBotAPI/utils/extensions/UpdatesFilter.kt),
|
||||||
|
which will be used to filter incoming updates
|
||||||
|
* `ENGINE_FACTORY` - used factory name, for example, `CIO` in case of usage `io.ktor:ktor-server-cio` as server engine
|
||||||
|
13
build.gradle
13
build.gradle
@ -1,4 +1,4 @@
|
|||||||
project.version = "0.13.0"
|
project.version = "0.14.0"
|
||||||
project.group = "com.github.insanusmokrassar"
|
project.group = "com.github.insanusmokrassar"
|
||||||
|
|
||||||
buildscript {
|
buildscript {
|
||||||
@ -26,7 +26,6 @@ repositories {
|
|||||||
jcenter()
|
jcenter()
|
||||||
mavenCentral()
|
mavenCentral()
|
||||||
maven { url "https://kotlin.bintray.com/kotlinx" }
|
maven { url "https://kotlin.bintray.com/kotlinx" }
|
||||||
maven { url "https://dl.bintray.com/kotlin/ktor" }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
@ -35,14 +34,10 @@ dependencies {
|
|||||||
implementation "org.jetbrains.kotlinx:kotlinx-serialization-runtime:$kotlin_serialisation_runtime_version"
|
implementation "org.jetbrains.kotlinx:kotlinx-serialization-runtime:$kotlin_serialisation_runtime_version"
|
||||||
implementation "joda-time:joda-time:$joda_time_version"
|
implementation "joda-time:joda-time:$joda_time_version"
|
||||||
|
|
||||||
implementation "io.ktor:ktor-client-core:$ktor_version"
|
implementation "io.ktor:ktor-client:$ktor_version"
|
||||||
implementation "io.ktor:ktor-client-okhttp:$ktor_version"
|
|
||||||
|
|
||||||
implementation "io.ktor:ktor-server-core:$ktor_version"
|
implementation "io.ktor:ktor-server:$ktor_version"
|
||||||
implementation "io.ktor:ktor-server-netty:$ktor_version"
|
implementation "io.ktor:ktor-server-host-common:$ktor_version"
|
||||||
|
|
||||||
// Use JUnit test framework
|
|
||||||
testImplementation 'junit:junit:4.12'
|
|
||||||
}
|
}
|
||||||
|
|
||||||
compileKotlin {
|
compileKotlin {
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
kotlin.code.style=official
|
kotlin.code.style=official
|
||||||
kotlin_version=1.3.30
|
kotlin_version=1.3.31
|
||||||
kotlin_coroutines_version=1.2.0
|
kotlin_coroutines_version=1.2.1
|
||||||
kotlin_serialisation_runtime_version=0.11.0
|
kotlin_serialisation_runtime_version=0.11.0
|
||||||
joda_time_version=2.10.1
|
joda_time_version=2.10.1
|
||||||
ktor_version=1.1.3
|
ktor_version=1.1.4
|
||||||
|
|
||||||
gradle_bintray_plugin_version=1.8.4
|
gradle_bintray_plugin_version=1.8.4
|
||||||
|
|
||||||
|
@ -1,16 +0,0 @@
|
|||||||
package com.github.insanusmokrassar.TelegramBotAPI
|
|
||||||
|
|
||||||
import com.github.insanusmokrassar.TelegramBotAPI.bot.Ktor.KtorRequestsExecutor
|
|
||||||
import io.ktor.client.engine.okhttp.OkHttp
|
|
||||||
import kotlinx.coroutines.runBlocking
|
|
||||||
|
|
||||||
fun main(args: Array<String>) {
|
|
||||||
runBlocking {
|
|
||||||
KtorRequestsExecutor(
|
|
||||||
args[0],
|
|
||||||
OkHttp.create()
|
|
||||||
).apply {
|
|
||||||
// It is just template of creating requests executor
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -12,7 +12,6 @@ import com.github.insanusmokrassar.TelegramBotAPI.types.RetryAfterError
|
|||||||
import io.ktor.client.HttpClient
|
import io.ktor.client.HttpClient
|
||||||
import io.ktor.client.call.HttpClientCall
|
import io.ktor.client.call.HttpClientCall
|
||||||
import io.ktor.client.engine.HttpClientEngine
|
import io.ktor.client.engine.HttpClientEngine
|
||||||
import io.ktor.client.engine.okhttp.OkHttp
|
|
||||||
import io.ktor.util.cio.toByteArray
|
import io.ktor.util.cio.toByteArray
|
||||||
import kotlinx.coroutines.delay
|
import kotlinx.coroutines.delay
|
||||||
import kotlinx.io.charsets.Charset
|
import kotlinx.io.charsets.Charset
|
||||||
@ -20,7 +19,7 @@ import kotlinx.serialization.json.Json
|
|||||||
|
|
||||||
class KtorRequestsExecutor(
|
class KtorRequestsExecutor(
|
||||||
token: String,
|
token: String,
|
||||||
private val client: HttpClient = HttpClient(OkHttp),
|
private val client: HttpClient = HttpClient(),
|
||||||
hostUrl: String = "https://api.telegram.org",
|
hostUrl: String = "https://api.telegram.org",
|
||||||
callsFactories: List<KtorCallFactory> = emptyList(),
|
callsFactories: List<KtorCallFactory> = emptyList(),
|
||||||
excludeDefaultFactories: Boolean = false,
|
excludeDefaultFactories: Boolean = false,
|
||||||
@ -29,11 +28,11 @@ class KtorRequestsExecutor(
|
|||||||
) : BaseRequestsExecutor(token, hostUrl) {
|
) : BaseRequestsExecutor(token, hostUrl) {
|
||||||
constructor(
|
constructor(
|
||||||
token: String,
|
token: String,
|
||||||
engine: HttpClientEngine = OkHttp.create(),
|
engine: HttpClientEngine? = null,
|
||||||
hostUrl: String = "https://api.telegram.org"
|
hostUrl: String = "https://api.telegram.org"
|
||||||
) : this(
|
) : this(
|
||||||
token,
|
token,
|
||||||
HttpClient(engine),
|
engine ?.let { HttpClient(engine) } ?: HttpClient(),
|
||||||
hostUrl
|
hostUrl
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -61,7 +60,9 @@ class KtorRequestsExecutor(
|
|||||||
if (call == null) {
|
if (call == null) {
|
||||||
throw IllegalArgumentException("Can't execute request: $request")
|
throw IllegalArgumentException("Can't execute request: $request")
|
||||||
}
|
}
|
||||||
val content = call.response.content.toByteArray().toString(Charset.defaultCharset())
|
val content = call.response.use {
|
||||||
|
it.content.toByteArray().toString(Charsets.UTF_8)
|
||||||
|
}
|
||||||
val responseObject = jsonFormatter.parse(
|
val responseObject = jsonFormatter.parse(
|
||||||
Response.serializer(request.resultSerializer()),
|
Response.serializer(request.resultSerializer()),
|
||||||
content
|
content
|
||||||
|
@ -1,32 +0,0 @@
|
|||||||
package com.github.insanusmokrassar.TelegramBotAPI.bot.Ktor
|
|
||||||
|
|
||||||
import com.github.insanusmokrassar.TelegramBotAPI.bot.settings.ProxySettings
|
|
||||||
import io.ktor.http.HttpHeaders
|
|
||||||
import okhttp3.Credentials
|
|
||||||
import okhttp3.OkHttpClient
|
|
||||||
import java.net.InetSocketAddress
|
|
||||||
import java.net.Proxy
|
|
||||||
|
|
||||||
fun OkHttpClient.Builder.useWith(proxySettings: ProxySettings) {
|
|
||||||
proxy(
|
|
||||||
Proxy(
|
|
||||||
Proxy.Type.SOCKS,
|
|
||||||
InetSocketAddress(
|
|
||||||
proxySettings.host,
|
|
||||||
proxySettings.port
|
|
||||||
)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
proxySettings.password ?.let {
|
|
||||||
password ->
|
|
||||||
proxyAuthenticator {
|
|
||||||
_, response ->
|
|
||||||
response.request().newBuilder().apply {
|
|
||||||
addHeader(
|
|
||||||
HttpHeaders.ProxyAuthorization,
|
|
||||||
Credentials.basic(proxySettings.username ?: "", password)
|
|
||||||
)
|
|
||||||
}.build()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -0,0 +1,41 @@
|
|||||||
|
package com.github.insanusmokrassar.TelegramBotAPI.bot.Ktor.base
|
||||||
|
|
||||||
|
import com.github.insanusmokrassar.TelegramBotAPI.bot.Ktor.KtorCallFactory
|
||||||
|
import com.github.insanusmokrassar.TelegramBotAPI.requests.abstracts.Request
|
||||||
|
import io.ktor.client.HttpClient
|
||||||
|
import io.ktor.client.call.HttpClientCall
|
||||||
|
import io.ktor.client.call.call
|
||||||
|
import io.ktor.client.request.accept
|
||||||
|
import io.ktor.client.request.url
|
||||||
|
import io.ktor.http.ContentType
|
||||||
|
import io.ktor.http.HttpMethod
|
||||||
|
|
||||||
|
abstract class AbstractRequestCallFactory : KtorCallFactory {
|
||||||
|
private val methodsCache: MutableMap<String, String> = mutableMapOf()
|
||||||
|
override suspend fun <T : Any> prepareCall(
|
||||||
|
client: HttpClient,
|
||||||
|
baseUrl: String,
|
||||||
|
request: Request<T>
|
||||||
|
): HttpClientCall? {
|
||||||
|
val preparedBody = prepareCallBody(client, baseUrl, request) ?: return null
|
||||||
|
|
||||||
|
return client.call {
|
||||||
|
url(
|
||||||
|
methodsCache[request.method()] ?: "$baseUrl/${request.method()}".also {
|
||||||
|
methodsCache[request.method()] = it
|
||||||
|
}
|
||||||
|
)
|
||||||
|
method = HttpMethod.Post
|
||||||
|
accept(ContentType.Application.Json)
|
||||||
|
|
||||||
|
body = preparedBody
|
||||||
|
build()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected abstract fun <T : Any> prepareCallBody(
|
||||||
|
client: HttpClient,
|
||||||
|
baseUrl: String,
|
||||||
|
request: Request<T>
|
||||||
|
): Any?
|
||||||
|
}
|
@ -1,48 +1,37 @@
|
|||||||
package com.github.insanusmokrassar.TelegramBotAPI.bot.Ktor.base
|
package com.github.insanusmokrassar.TelegramBotAPI.bot.Ktor.base
|
||||||
|
|
||||||
import com.github.insanusmokrassar.TelegramBotAPI.bot.Ktor.KtorCallFactory
|
|
||||||
import com.github.insanusmokrassar.TelegramBotAPI.requests.abstracts.*
|
import com.github.insanusmokrassar.TelegramBotAPI.requests.abstracts.*
|
||||||
import com.github.insanusmokrassar.TelegramBotAPI.utils.mapWithCommonValues
|
import com.github.insanusmokrassar.TelegramBotAPI.utils.mapWithCommonValues
|
||||||
import io.ktor.client.HttpClient
|
import io.ktor.client.HttpClient
|
||||||
import io.ktor.client.call.HttpClientCall
|
|
||||||
import io.ktor.client.call.call
|
|
||||||
import io.ktor.client.request.accept
|
|
||||||
import io.ktor.client.request.forms.MultiPartFormDataContent
|
import io.ktor.client.request.forms.MultiPartFormDataContent
|
||||||
import io.ktor.client.request.forms.formData
|
import io.ktor.client.request.forms.formData
|
||||||
import io.ktor.client.request.url
|
|
||||||
import io.ktor.http.*
|
import io.ktor.http.*
|
||||||
|
|
||||||
class MultipartRequestCallFactory : KtorCallFactory {
|
class MultipartRequestCallFactory : AbstractRequestCallFactory() {
|
||||||
override suspend fun <T: Any> prepareCall(
|
|
||||||
|
override fun <T : Any> prepareCallBody(
|
||||||
client: HttpClient,
|
client: HttpClient,
|
||||||
baseUrl: String,
|
baseUrl: String,
|
||||||
request: Request<T>
|
request: Request<T>
|
||||||
): HttpClientCall? = (request as? MultipartRequest) ?.let {
|
): Any? = (request as? MultipartRequest) ?.let { castedRequest ->
|
||||||
castedRequest ->
|
MultiPartFormDataContent(
|
||||||
client.call {
|
formData {
|
||||||
url("$baseUrl/${castedRequest.method()}")
|
val params = castedRequest.paramsJson.mapWithCommonValues()
|
||||||
method = HttpMethod.Post
|
for ((key, value) in castedRequest.mediaMap + params) {
|
||||||
accept(ContentType.Application.Json)
|
when (value) {
|
||||||
body = MultiPartFormDataContent(
|
is MultipartFile -> append(
|
||||||
formData {
|
key,
|
||||||
val params = castedRequest.paramsJson.mapWithCommonValues()
|
value.file.asInput(),
|
||||||
for ((key, value) in castedRequest.mediaMap + params) {
|
Headers.build {
|
||||||
when (value) {
|
append(HttpHeaders.ContentType, value.mimeType)
|
||||||
is MultipartFile -> append(
|
append(HttpHeaders.ContentDisposition, "filename=${value.fileId}")
|
||||||
key,
|
}
|
||||||
value.file.asInput(),
|
)
|
||||||
Headers.build {
|
is FileId -> append(key, value.fileId)
|
||||||
append(HttpHeaders.ContentType, value.mimeType)
|
else -> append(key, value.toString())
|
||||||
append(HttpHeaders.ContentDisposition, "filename=${value.fileId}")
|
|
||||||
}
|
|
||||||
)
|
|
||||||
is FileId -> append(key, value.fileId)
|
|
||||||
else -> append(key, value.toString())
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
)
|
}
|
||||||
build()
|
)
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,36 +1,23 @@
|
|||||||
package com.github.insanusmokrassar.TelegramBotAPI.bot.Ktor.base
|
package com.github.insanusmokrassar.TelegramBotAPI.bot.Ktor.base
|
||||||
|
|
||||||
import com.github.insanusmokrassar.TelegramBotAPI.bot.Ktor.KtorCallFactory
|
|
||||||
import com.github.insanusmokrassar.TelegramBotAPI.requests.abstracts.*
|
import com.github.insanusmokrassar.TelegramBotAPI.requests.abstracts.*
|
||||||
import com.github.insanusmokrassar.TelegramBotAPI.utils.toJsonWithoutNulls
|
import com.github.insanusmokrassar.TelegramBotAPI.utils.toJsonWithoutNulls
|
||||||
import io.ktor.client.HttpClient
|
import io.ktor.client.HttpClient
|
||||||
import io.ktor.client.call.HttpClientCall
|
|
||||||
import io.ktor.client.call.call
|
|
||||||
import io.ktor.client.request.accept
|
|
||||||
import io.ktor.client.request.url
|
|
||||||
import io.ktor.http.ContentType
|
import io.ktor.http.ContentType
|
||||||
import io.ktor.http.HttpMethod
|
|
||||||
import io.ktor.http.content.TextContent
|
import io.ktor.http.content.TextContent
|
||||||
|
|
||||||
class SimpleRequestCallFactory : KtorCallFactory {
|
class SimpleRequestCallFactory : AbstractRequestCallFactory() {
|
||||||
override suspend fun <T: Any> prepareCall(
|
override fun <T : Any> prepareCallBody(
|
||||||
client: HttpClient,
|
client: HttpClient,
|
||||||
baseUrl: String,
|
baseUrl: String,
|
||||||
request: Request<T>
|
request: Request<T>
|
||||||
): HttpClientCall? = (request as? SimpleRequest<T>) ?.let {
|
): Any? = (request as? SimpleRequest<T>) ?.let { _ ->
|
||||||
castedRequest ->
|
val content = request.toJsonWithoutNulls(SimpleRequestSerializer).toString()
|
||||||
client.call {
|
|
||||||
url("$baseUrl/${castedRequest.method()}")
|
|
||||||
method = HttpMethod.Post
|
|
||||||
accept(ContentType.Application.Json)
|
|
||||||
|
|
||||||
val content = request.toJsonWithoutNulls(SimpleRequestSerializer).toString()
|
TextContent(
|
||||||
|
content,
|
||||||
body = TextContent(
|
ContentType.Application.Json
|
||||||
content,
|
)
|
||||||
ContentType.Application.Json
|
|
||||||
)
|
|
||||||
build()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
@ -1,18 +0,0 @@
|
|||||||
package com.github.insanusmokrassar.TelegramBotAPI.bot
|
|
||||||
|
|
||||||
import com.github.insanusmokrassar.TelegramBotAPI.bot.Ktor.useWith
|
|
||||||
import com.github.insanusmokrassar.TelegramBotAPI.bot.settings.ProxySettings
|
|
||||||
import okhttp3.OkHttpClient
|
|
||||||
|
|
||||||
@Deprecated(
|
|
||||||
"Replaced in settings package",
|
|
||||||
ReplaceWith("ProxySettings", "com.github.insanusmokrassar.TelegramBotAPI.bot.settings.ProxySettings")
|
|
||||||
)
|
|
||||||
typealias ProxySettings = com.github.insanusmokrassar.TelegramBotAPI.bot.settings.ProxySettings
|
|
||||||
|
|
||||||
|
|
||||||
@Deprecated(
|
|
||||||
"Replaced in Ktor package",
|
|
||||||
ReplaceWith("useWith", "com.github.insanusmokrassar.TelegramBotAPI.bot.Ktor.useWith")
|
|
||||||
)
|
|
||||||
fun OkHttpClient.Builder.useWith(proxySettings: ProxySettings) = useWith(proxySettings)
|
|
@ -64,6 +64,7 @@ const val inlineMessageIdField = "inline_message_id"
|
|||||||
const val callbackDataField = "callback_data"
|
const val callbackDataField = "callback_data"
|
||||||
const val callbackQueryIdField = "callback_query_id"
|
const val callbackQueryIdField = "callback_query_id"
|
||||||
const val inlineQueryIdField = "inline_query_id"
|
const val inlineQueryIdField = "inline_query_id"
|
||||||
|
const val inlineKeyboardField = "inline_keyboard"
|
||||||
const val showAlertField = "show_alert"
|
const val showAlertField = "show_alert"
|
||||||
const val cachedTimeField = "cached_time"
|
const val cachedTimeField = "cached_time"
|
||||||
const val foursquareIdField = "foursquare_id"
|
const val foursquareIdField = "foursquare_id"
|
||||||
|
@ -1,5 +1,10 @@
|
|||||||
package com.github.insanusmokrassar.TelegramBotAPI.types.buttons.InlineKeyboardButtons
|
package com.github.insanusmokrassar.TelegramBotAPI.types.buttons.InlineKeyboardButtons
|
||||||
|
|
||||||
|
import kotlinx.serialization.*
|
||||||
|
|
||||||
|
@Serializable(InlineKeyboardButtonSerializer::class)
|
||||||
interface InlineKeyboardButton {
|
interface InlineKeyboardButton {
|
||||||
val text: String
|
val text: String
|
||||||
}
|
}
|
||||||
|
|
||||||
|
object InlineKeyboardButtonSerializer : KSerializer<InlineKeyboardButton> by ContextSerializer(InlineKeyboardButton::class)
|
||||||
|
@ -1,16 +1,12 @@
|
|||||||
package com.github.insanusmokrassar.TelegramBotAPI.types.buttons
|
package com.github.insanusmokrassar.TelegramBotAPI.types.buttons
|
||||||
|
|
||||||
import com.github.insanusmokrassar.TelegramBotAPI.types.buttons.InlineKeyboardButtons.InlineKeyboardButton
|
import com.github.insanusmokrassar.TelegramBotAPI.types.buttons.InlineKeyboardButtons.InlineKeyboardButton
|
||||||
|
import com.github.insanusmokrassar.TelegramBotAPI.types.inlineKeyboardField
|
||||||
import kotlinx.serialization.*
|
import kotlinx.serialization.*
|
||||||
import kotlinx.serialization.internal.ArrayListSerializer
|
import kotlinx.serialization.internal.ArrayListSerializer
|
||||||
|
|
||||||
@Serializable
|
@Serializable
|
||||||
data class InlineKeyboardMarkup(
|
data class InlineKeyboardMarkup(
|
||||||
@SerialName("inline_keyboard")
|
@SerialName(inlineKeyboardField)
|
||||||
@Serializable(with = KeyboardSerializer::class)
|
|
||||||
val keyboard: Matrix<InlineKeyboardButton>
|
val keyboard: Matrix<InlineKeyboardButton>
|
||||||
) : KeyboardMarkup
|
) : KeyboardMarkup
|
||||||
|
|
||||||
object KeyboardSerializer : KSerializer<Matrix<InlineKeyboardButton>> by ArrayListSerializer(
|
|
||||||
ArrayListSerializer(ContextSerializer(InlineKeyboardButton::class))
|
|
||||||
)
|
|
||||||
|
@ -12,21 +12,20 @@ data class AnonymousForwardedMessage(
|
|||||||
val senderName: String
|
val senderName: String
|
||||||
) : ForwardedMessage()
|
) : ForwardedMessage()
|
||||||
|
|
||||||
sealed class PublicForwardedMessage : ForwardedMessage() {
|
data class UserForwardedMessage(
|
||||||
abstract val messageId: MessageIdentifier
|
|
||||||
abstract val from: User?
|
|
||||||
}
|
|
||||||
|
|
||||||
data class CommonForwardedMessage(
|
|
||||||
override val messageId: MessageIdentifier,
|
|
||||||
override val dateOfOriginal: TelegramDate,
|
override val dateOfOriginal: TelegramDate,
|
||||||
override val from: User
|
val from: User
|
||||||
) : PublicForwardedMessage()
|
) : ForwardedMessage()
|
||||||
|
|
||||||
|
@Deprecated(
|
||||||
|
"Renamed according to correct meaning",
|
||||||
|
ReplaceWith("UserForwardedMessage", "com.github.insanusmokrassar.TelegramBotAPI.types.message.UserForwardedMessage")
|
||||||
|
)
|
||||||
|
typealias CommonForwardedMessage = UserForwardedMessage
|
||||||
|
|
||||||
data class ForwardedFromChannelMessage(
|
data class ForwardedFromChannelMessage(
|
||||||
override val messageId: MessageIdentifier,
|
|
||||||
override val dateOfOriginal: TelegramDate,
|
override val dateOfOriginal: TelegramDate,
|
||||||
override val from: User?,
|
val messageId: MessageIdentifier,
|
||||||
val channelChat: Chat,
|
val channelChat: Chat,
|
||||||
val signature: String? = null
|
val signature: String? = null
|
||||||
) : PublicForwardedMessage()
|
) : ForwardedMessage()
|
||||||
|
@ -134,26 +134,22 @@ data class RawMessage(
|
|||||||
@Transient
|
@Transient
|
||||||
private val forwarded: ForwardedMessage? by lazy {
|
private val forwarded: ForwardedMessage? by lazy {
|
||||||
forward_date ?: return@lazy null // According to the documentation, now any forwarded message contains this field
|
forward_date ?: return@lazy null // According to the documentation, now any forwarded message contains this field
|
||||||
forward_from_message_id ?.let {
|
when {
|
||||||
forward_from ?: throw IllegalStateException("For common forwarded messages author of original message declared as set up required")
|
forward_sender_name != null -> AnonymousForwardedMessage(
|
||||||
forward_from_chat ?.let {
|
|
||||||
ForwardedFromChannelMessage(
|
|
||||||
forward_from_message_id,
|
|
||||||
forward_date,
|
|
||||||
forward_from,
|
|
||||||
forward_from_chat.extractChat(),
|
|
||||||
forward_signature
|
|
||||||
)
|
|
||||||
} ?: CommonForwardedMessage(
|
|
||||||
forward_from_message_id,
|
|
||||||
forward_date,
|
|
||||||
forward_from
|
|
||||||
)
|
|
||||||
} ?: forward_sender_name ?.let {
|
|
||||||
AnonymousForwardedMessage(
|
|
||||||
forward_date,
|
forward_date,
|
||||||
forward_sender_name
|
forward_sender_name
|
||||||
)
|
)
|
||||||
|
forward_from_chat != null -> ForwardedFromChannelMessage(
|
||||||
|
forward_date,
|
||||||
|
forward_from_message_id ?: throw IllegalStateException("Channel forwarded message must contain message id, but was not"),
|
||||||
|
forward_from_chat.extractChat(),
|
||||||
|
forward_signature
|
||||||
|
)
|
||||||
|
forward_from != null -> UserForwardedMessage(
|
||||||
|
forward_date,
|
||||||
|
forward_from
|
||||||
|
)
|
||||||
|
else -> null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -16,7 +16,6 @@ import io.ktor.response.respond
|
|||||||
import io.ktor.routing.post
|
import io.ktor.routing.post
|
||||||
import io.ktor.routing.routing
|
import io.ktor.routing.routing
|
||||||
import io.ktor.server.engine.*
|
import io.ktor.server.engine.*
|
||||||
import io.ktor.server.netty.Netty
|
|
||||||
import kotlinx.coroutines.*
|
import kotlinx.coroutines.*
|
||||||
import kotlinx.coroutines.channels.Channel
|
import kotlinx.coroutines.channels.Channel
|
||||||
import kotlinx.serialization.json.Json
|
import kotlinx.serialization.json.Json
|
||||||
@ -36,12 +35,12 @@ import java.util.concurrent.TimeUnit
|
|||||||
suspend fun RequestsExecutor.setWebhook(
|
suspend fun RequestsExecutor.setWebhook(
|
||||||
url: String,
|
url: String,
|
||||||
port: Int,
|
port: Int,
|
||||||
|
engineFactory: ApplicationEngineFactory<*, *>,
|
||||||
certificate: InputFile? = null,
|
certificate: InputFile? = null,
|
||||||
privateKeyConfig: WebhookPrivateKeyConfig? = null,
|
privateKeyConfig: WebhookPrivateKeyConfig? = null,
|
||||||
scope: CoroutineScope = CoroutineScope(Executors.newFixedThreadPool(4).asCoroutineDispatcher()),
|
scope: CoroutineScope = CoroutineScope(Executors.newFixedThreadPool(4).asCoroutineDispatcher()),
|
||||||
allowedUpdates: List<String>? = null,
|
allowedUpdates: List<String>? = null,
|
||||||
maxAllowedConnections: Int? = null,
|
maxAllowedConnections: Int? = null,
|
||||||
engineFactory: ApplicationEngineFactory<*, *> = Netty,
|
|
||||||
block: UpdateReceiver<Update>
|
block: UpdateReceiver<Update>
|
||||||
): Job {
|
): Job {
|
||||||
val executeDeferred = certificate ?.let {
|
val executeDeferred = certificate ?.let {
|
||||||
@ -69,20 +68,17 @@ suspend fun RequestsExecutor.setWebhook(
|
|||||||
val env = applicationEngineEnvironment {
|
val env = applicationEngineEnvironment {
|
||||||
|
|
||||||
module {
|
module {
|
||||||
fun Application.main() {
|
routing {
|
||||||
routing {
|
post {
|
||||||
post {
|
val deserialized = call.receiveText()
|
||||||
val deserialized = call.receiveText()
|
val update = Json.nonstrict.parse(
|
||||||
val update = Json.nonstrict.parse(
|
RawUpdate.serializer(),
|
||||||
RawUpdate.serializer(),
|
deserialized
|
||||||
deserialized
|
)
|
||||||
)
|
updatesChannel.send(update.asUpdate)
|
||||||
updatesChannel.send(update.asUpdate)
|
call.respond("Ok")
|
||||||
call.respond("Ok")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
main()
|
|
||||||
}
|
}
|
||||||
privateKeyConfig ?.let {
|
privateKeyConfig ?.let {
|
||||||
sslConnector(
|
sslConnector(
|
||||||
@ -140,19 +136,19 @@ suspend fun RequestsExecutor.setWebhook(
|
|||||||
url: String,
|
url: String,
|
||||||
port: Int,
|
port: Int,
|
||||||
filter: UpdatesFilter,
|
filter: UpdatesFilter,
|
||||||
|
engineFactory: ApplicationEngineFactory<*, *>,
|
||||||
certificate: InputFile? = null,
|
certificate: InputFile? = null,
|
||||||
privateKeyConfig: WebhookPrivateKeyConfig? = null,
|
privateKeyConfig: WebhookPrivateKeyConfig? = null,
|
||||||
scope: CoroutineScope = CoroutineScope(Executors.newFixedThreadPool(4).asCoroutineDispatcher()),
|
scope: CoroutineScope = CoroutineScope(Executors.newFixedThreadPool(4).asCoroutineDispatcher()),
|
||||||
maxAllowedConnections: Int? = null,
|
maxAllowedConnections: Int? = null
|
||||||
engineFactory: ApplicationEngineFactory<*, *> = Netty
|
|
||||||
): Job = setWebhook(
|
): Job = setWebhook(
|
||||||
url,
|
url,
|
||||||
port,
|
port,
|
||||||
|
engineFactory,
|
||||||
certificate,
|
certificate,
|
||||||
privateKeyConfig,
|
privateKeyConfig,
|
||||||
scope,
|
scope,
|
||||||
filter.allowedUpdates,
|
filter.allowedUpdates,
|
||||||
maxAllowedConnections,
|
maxAllowedConnections,
|
||||||
engineFactory,
|
|
||||||
filter.asUpdateReceiver
|
filter.asUpdateReceiver
|
||||||
)
|
)
|
||||||
|
Loading…
Reference in New Issue
Block a user