mirror of
https://github.com/InsanusMokrassar/TelegramBotAPI.git
synced 2024-11-22 16:23:48 +00:00
add main webhooks functionality for using with reverse proxy
This commit is contained in:
parent
ff2b56b3a9
commit
1520271777
@ -1,11 +1,14 @@
|
|||||||
# TelegramBotAPI changelog
|
# TelegramBotAPI changelog
|
||||||
|
|
||||||
## 0.12.0
|
## 0.12.0 Webhooks
|
||||||
|
|
||||||
* Added `DataRequest` interface which replace `Data` interface
|
* Added `DataRequest` interface which replace `Data` interface
|
||||||
* `MultipartRequestImpl` now use `DataRequest`
|
* `MultipartRequestImpl` now use `DataRequest`
|
||||||
* All requests which implements `Data` now implement `DataRequest`
|
* All requests which implements `Data` now implement `DataRequest`
|
||||||
* Added class `SetWebhook` and its factory
|
* Added class `SetWebhook` and its factory
|
||||||
|
* Added class `UpdatesFilter` which can help to filter updates by categories
|
||||||
|
* Added function `accumulateByKey` which work as debounce for keys and send list of received values
|
||||||
|
* Added webhooks functions and workaround for `Reverse Proxy` mode
|
||||||
|
|
||||||
## 0.11.0
|
## 0.11.0
|
||||||
|
|
||||||
|
@ -34,9 +34,13 @@ dependencies {
|
|||||||
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:$kotlin_coroutines_version"
|
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:$kotlin_coroutines_version"
|
||||||
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-core:$ktor_version"
|
||||||
implementation "io.ktor:ktor-client-okhttp:$ktor_version"
|
implementation "io.ktor:ktor-client-okhttp:$ktor_version"
|
||||||
|
|
||||||
|
implementation "io.ktor:ktor-server-core:$ktor_version"
|
||||||
|
implementation "io.ktor:ktor-server-netty:$ktor_version"
|
||||||
|
|
||||||
// Use JUnit test framework
|
// Use JUnit test framework
|
||||||
testImplementation 'junit:junit:4.12'
|
testImplementation 'junit:junit:4.12'
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,101 @@
|
|||||||
|
package com.github.insanusmokrassar.TelegramBotAPI.utils.extensions
|
||||||
|
|
||||||
|
import kotlinx.coroutines.*
|
||||||
|
import kotlinx.coroutines.channels.Channel
|
||||||
|
import kotlinx.coroutines.channels.ReceiveChannel
|
||||||
|
|
||||||
|
private sealed class DebounceAction<T> {
|
||||||
|
abstract val value: T
|
||||||
|
}
|
||||||
|
|
||||||
|
private data class AddValue<T>(override val value: T) : DebounceAction<T>()
|
||||||
|
private data class RemoveJob<T>(override val value: T, val job: Job) : DebounceAction<T>()
|
||||||
|
|
||||||
|
fun <T> ReceiveChannel<T>.debounceByValue(
|
||||||
|
delayMillis: Long,
|
||||||
|
scope: CoroutineScope = CoroutineScope(Dispatchers.Default),
|
||||||
|
resultBroadcastChannelCapacity: Int = 32
|
||||||
|
): ReceiveChannel<T> {
|
||||||
|
val outChannel = Channel<T>(resultBroadcastChannelCapacity)
|
||||||
|
val values = HashMap<T, Job>()
|
||||||
|
|
||||||
|
val channel = Channel<DebounceAction<T>>(Channel.UNLIMITED)
|
||||||
|
scope.launch {
|
||||||
|
for (action in channel) {
|
||||||
|
when (action) {
|
||||||
|
is AddValue -> {
|
||||||
|
val msg = action.value
|
||||||
|
values[msg] ?.cancel()
|
||||||
|
lateinit var job: Job
|
||||||
|
job = launch {
|
||||||
|
delay(delayMillis)
|
||||||
|
|
||||||
|
outChannel.send(msg)
|
||||||
|
channel.send(RemoveJob(msg, job))
|
||||||
|
}
|
||||||
|
values[msg] = job
|
||||||
|
}
|
||||||
|
is RemoveJob -> if (values[action.value] == action.job) {
|
||||||
|
values.remove(action.value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
scope.launch {
|
||||||
|
for (msg in this@debounceByValue) {
|
||||||
|
channel.send(AddValue(msg))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return outChannel
|
||||||
|
}
|
||||||
|
|
||||||
|
typealias AccumulatedValues<K, V> = Pair<K, List<V>>
|
||||||
|
|
||||||
|
fun <K, V> ReceiveChannel<Pair<K, V>>.accumulateByKey(
|
||||||
|
delayMillis: Long,
|
||||||
|
scope: CoroutineScope = CoroutineScope(Dispatchers.Default),
|
||||||
|
resultBroadcastChannelCapacity: Int = 32
|
||||||
|
): ReceiveChannel<AccumulatedValues<K, V>> {
|
||||||
|
val outChannel = Channel<AccumulatedValues<K, V>>(resultBroadcastChannelCapacity)
|
||||||
|
val values = HashMap<K, MutableList<V>>()
|
||||||
|
val jobs = HashMap<K, Job>()
|
||||||
|
|
||||||
|
val channel = Channel<DebounceAction<Pair<K, V>>>(Channel.UNLIMITED)
|
||||||
|
scope.launch {
|
||||||
|
for (action in channel) {
|
||||||
|
val (key, value) = action.value
|
||||||
|
when (action) {
|
||||||
|
is AddValue -> {
|
||||||
|
jobs[key] ?.cancel()
|
||||||
|
(values[key] ?: mutableListOf<V>().also { values[key] = it }).add(value)
|
||||||
|
lateinit var job: Job
|
||||||
|
job = launch {
|
||||||
|
delay(delayMillis)
|
||||||
|
|
||||||
|
values[key] ?.let {
|
||||||
|
outChannel.send(key to it)
|
||||||
|
channel.send(RemoveJob(key to value, job))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
jobs[key] = job
|
||||||
|
}
|
||||||
|
is RemoveJob -> if (values[key] == action.job) {
|
||||||
|
values.remove(key)
|
||||||
|
jobs.remove(key)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
scope.launch {
|
||||||
|
for (msg in this@accumulateByKey) {
|
||||||
|
channel.send(AddValue(msg))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return outChannel
|
||||||
|
}
|
@ -114,63 +114,27 @@ fun RequestsExecutor.startGettingOfUpdates(
|
|||||||
requestsDelayMillis: Long = 1000,
|
requestsDelayMillis: Long = 1000,
|
||||||
scope: CoroutineScope = GlobalScope
|
scope: CoroutineScope = GlobalScope
|
||||||
): Job {
|
): Job {
|
||||||
|
val filter = UpdatesFilter(
|
||||||
|
messageCallback,
|
||||||
|
messageMediaGroupCallback,
|
||||||
|
editedMessageCallback,
|
||||||
|
editedMessageMediaGroupCallback,
|
||||||
|
channelPostCallback,
|
||||||
|
channelPostMediaGroupCallback,
|
||||||
|
editedChannelPostCallback,
|
||||||
|
editedChannelPostMediaGroupCallback,
|
||||||
|
chosenInlineResultCallback,
|
||||||
|
inlineQueryCallback,
|
||||||
|
callbackQueryCallback,
|
||||||
|
shippingQueryCallback,
|
||||||
|
preCheckoutQueryCallback
|
||||||
|
)
|
||||||
return startGettingOfUpdates(
|
return startGettingOfUpdates(
|
||||||
requestsDelayMillis,
|
requestsDelayMillis,
|
||||||
scope,
|
scope,
|
||||||
listOfNotNull(
|
filter.allowedUpdates,
|
||||||
(messageCallback ?: messageMediaGroupCallback) ?.let { UPDATE_MESSAGE },
|
filter.asUpdateReceiver
|
||||||
(editedMessageCallback ?: editedMessageMediaGroupCallback) ?.let { UPDATE_EDITED_MESSAGE },
|
|
||||||
(channelPostCallback ?: channelPostMediaGroupCallback) ?.let { UPDATE_CHANNEL_POST },
|
|
||||||
(editedChannelPostCallback ?: editedChannelPostMediaGroupCallback) ?.let { UPDATE_EDITED_CHANNEL_POST },
|
|
||||||
chosenInlineResultCallback ?.let { UPDATE_CHOSEN_INLINE_RESULT },
|
|
||||||
inlineQueryCallback ?.let { UPDATE_INLINE_QUERY },
|
|
||||||
callbackQueryCallback ?.let { UPDATE_CALLBACK_QUERY },
|
|
||||||
shippingQueryCallback ?.let { UPDATE_SHIPPING_QUERY },
|
|
||||||
preCheckoutQueryCallback ?.let { UPDATE_PRE_CHECKOUT_QUERY }
|
|
||||||
)
|
)
|
||||||
) { update ->
|
|
||||||
when (update) {
|
|
||||||
is MessageUpdate -> messageCallback ?.invoke(update)
|
|
||||||
is List<*> -> when (update.firstOrNull()) {
|
|
||||||
is MessageUpdate -> update.mapNotNull { it as? MessageUpdate }.let { mappedList ->
|
|
||||||
messageMediaGroupCallback ?.also { receiver ->
|
|
||||||
receiver(mappedList)
|
|
||||||
} ?: messageCallback ?.also { receiver ->
|
|
||||||
mappedList.forEach { receiver(it) }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
is EditMessageUpdate -> update.mapNotNull { it as? EditMessageUpdate }.let { mappedList ->
|
|
||||||
editedMessageMediaGroupCallback ?.also { receiver ->
|
|
||||||
receiver(mappedList)
|
|
||||||
} ?: editedMessageCallback ?.also { receiver ->
|
|
||||||
mappedList.forEach { receiver(it) }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
is ChannelPostUpdate -> update.mapNotNull { it as? ChannelPostUpdate }.let { mappedList ->
|
|
||||||
channelPostMediaGroupCallback ?.also { receiver ->
|
|
||||||
receiver(mappedList)
|
|
||||||
} ?: channelPostCallback ?.also { receiver ->
|
|
||||||
mappedList.forEach { receiver(it) }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
is EditChannelPostUpdate -> update.mapNotNull { it as? EditChannelPostUpdate }.let { mappedList ->
|
|
||||||
editedChannelPostMediaGroupCallback ?.also { receiver ->
|
|
||||||
receiver(mappedList)
|
|
||||||
} ?: editedChannelPostCallback ?.also { receiver ->
|
|
||||||
mappedList.forEach { receiver(it) }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
is EditMessageUpdate -> editedMessageCallback ?.invoke(update)
|
|
||||||
is ChannelPostUpdate -> channelPostCallback ?.invoke(update)
|
|
||||||
is EditChannelPostUpdate -> editedChannelPostCallback ?.invoke(update)
|
|
||||||
is ChosenInlineResultUpdate -> chosenInlineResultCallback ?.invoke(update)
|
|
||||||
is InlineQueryUpdate -> inlineQueryCallback ?.invoke(update)
|
|
||||||
is CallbackQueryUpdate -> callbackQueryCallback ?.invoke(update)
|
|
||||||
is ShippingQueryUpdate -> shippingQueryCallback ?.invoke(update)
|
|
||||||
is PreCheckoutQueryUpdate -> preCheckoutQueryCallback ?.invoke(update)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun RequestsExecutor.startGettingOfUpdates(
|
fun RequestsExecutor.startGettingOfUpdates(
|
||||||
|
@ -0,0 +1,105 @@
|
|||||||
|
package com.github.insanusmokrassar.TelegramBotAPI.utils.extensions
|
||||||
|
|
||||||
|
import com.github.insanusmokrassar.TelegramBotAPI.requests.*
|
||||||
|
import com.github.insanusmokrassar.TelegramBotAPI.types.update.*
|
||||||
|
import com.github.insanusmokrassar.TelegramBotAPI.types.update.abstracts.BaseMessageUpdate
|
||||||
|
|
||||||
|
data class UpdatesFilter(
|
||||||
|
private val messageCallback: UpdateReceiver<MessageUpdate>? = null,
|
||||||
|
private val messageMediaGroupCallback: UpdateReceiver<List<MessageUpdate>>? = null,
|
||||||
|
private val editedMessageCallback: UpdateReceiver<EditMessageUpdate>? = null,
|
||||||
|
private val editedMessageMediaGroupCallback: UpdateReceiver<List<EditMessageUpdate>>? = null,
|
||||||
|
private val channelPostCallback: UpdateReceiver<ChannelPostUpdate>? = null,
|
||||||
|
private val channelPostMediaGroupCallback: UpdateReceiver<List<ChannelPostUpdate>>? = null,
|
||||||
|
private val editedChannelPostCallback: UpdateReceiver<EditChannelPostUpdate>? = null,
|
||||||
|
private val editedChannelPostMediaGroupCallback: UpdateReceiver<List<EditChannelPostUpdate>>? = null,
|
||||||
|
private val chosenInlineResultCallback: UpdateReceiver<ChosenInlineResultUpdate>? = null,
|
||||||
|
private val inlineQueryCallback: UpdateReceiver<InlineQueryUpdate>? = null,
|
||||||
|
private val callbackQueryCallback: UpdateReceiver<CallbackQueryUpdate>? = null,
|
||||||
|
private val shippingQueryCallback: UpdateReceiver<ShippingQueryUpdate>? = null,
|
||||||
|
private val preCheckoutQueryCallback: UpdateReceiver<PreCheckoutQueryUpdate>? = null
|
||||||
|
) {
|
||||||
|
val asUpdateReceiver: UpdateReceiver<Any> = this::invoke
|
||||||
|
val allowedUpdates = listOfNotNull(
|
||||||
|
(messageCallback ?: messageMediaGroupCallback) ?.let { UPDATE_MESSAGE },
|
||||||
|
(editedMessageCallback ?: editedMessageMediaGroupCallback) ?.let { UPDATE_EDITED_MESSAGE },
|
||||||
|
(channelPostCallback ?: channelPostMediaGroupCallback) ?.let { UPDATE_CHANNEL_POST },
|
||||||
|
(editedChannelPostCallback ?: editedChannelPostMediaGroupCallback) ?.let { UPDATE_EDITED_CHANNEL_POST },
|
||||||
|
chosenInlineResultCallback ?.let { UPDATE_CHOSEN_INLINE_RESULT },
|
||||||
|
inlineQueryCallback ?.let { UPDATE_INLINE_QUERY },
|
||||||
|
callbackQueryCallback ?.let { UPDATE_CALLBACK_QUERY },
|
||||||
|
shippingQueryCallback ?.let { UPDATE_SHIPPING_QUERY },
|
||||||
|
preCheckoutQueryCallback ?.let { UPDATE_PRE_CHECKOUT_QUERY }
|
||||||
|
)
|
||||||
|
|
||||||
|
suspend fun invoke(update: Any) {
|
||||||
|
when (update) {
|
||||||
|
is MessageUpdate -> messageCallback ?.invoke(update)
|
||||||
|
is List<*> -> when (update.firstOrNull()) {
|
||||||
|
is MessageUpdate -> update.mapNotNull { it as? MessageUpdate }.let { mappedList ->
|
||||||
|
messageMediaGroupCallback ?.also { receiver ->
|
||||||
|
receiver(mappedList)
|
||||||
|
} ?: messageCallback ?.also { receiver ->
|
||||||
|
mappedList.forEach { receiver(it) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
is EditMessageUpdate -> update.mapNotNull { it as? EditMessageUpdate }.let { mappedList ->
|
||||||
|
editedMessageMediaGroupCallback ?.also { receiver ->
|
||||||
|
receiver(mappedList)
|
||||||
|
} ?: editedMessageCallback ?.also { receiver ->
|
||||||
|
mappedList.forEach { receiver(it) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
is ChannelPostUpdate -> update.mapNotNull { it as? ChannelPostUpdate }.let { mappedList ->
|
||||||
|
channelPostMediaGroupCallback ?.also { receiver ->
|
||||||
|
receiver(mappedList)
|
||||||
|
} ?: channelPostCallback ?.also { receiver ->
|
||||||
|
mappedList.forEach { receiver(it) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
is EditChannelPostUpdate -> update.mapNotNull { it as? EditChannelPostUpdate }.let { mappedList ->
|
||||||
|
editedChannelPostMediaGroupCallback ?.also { receiver ->
|
||||||
|
receiver(mappedList)
|
||||||
|
} ?: editedChannelPostCallback ?.also { receiver ->
|
||||||
|
mappedList.forEach { receiver(it) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
is EditMessageUpdate -> editedMessageCallback ?.invoke(update)
|
||||||
|
is ChannelPostUpdate -> channelPostCallback ?.invoke(update)
|
||||||
|
is EditChannelPostUpdate -> editedChannelPostCallback ?.invoke(update)
|
||||||
|
is ChosenInlineResultUpdate -> chosenInlineResultCallback ?.invoke(update)
|
||||||
|
is InlineQueryUpdate -> inlineQueryCallback ?.invoke(update)
|
||||||
|
is CallbackQueryUpdate -> callbackQueryCallback ?.invoke(update)
|
||||||
|
is ShippingQueryUpdate -> shippingQueryCallback ?.invoke(update)
|
||||||
|
is PreCheckoutQueryUpdate -> preCheckoutQueryCallback ?.invoke(update)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun createSimpleUpdateFilter(
|
||||||
|
messageCallback: UpdateReceiver<MessageUpdate>? = null,
|
||||||
|
mediaGroupCallback: UpdateReceiver<List<BaseMessageUpdate>>? = null,
|
||||||
|
editedMessageCallback: UpdateReceiver<EditMessageUpdate>? = null,
|
||||||
|
channelPostCallback: UpdateReceiver<ChannelPostUpdate>? = null,
|
||||||
|
editedChannelPostCallback: UpdateReceiver<EditChannelPostUpdate>? = null,
|
||||||
|
chosenInlineResultCallback: UpdateReceiver<ChosenInlineResultUpdate>? = null,
|
||||||
|
inlineQueryCallback: UpdateReceiver<InlineQueryUpdate>? = null,
|
||||||
|
callbackQueryCallback: UpdateReceiver<CallbackQueryUpdate>? = null,
|
||||||
|
shippingQueryCallback: UpdateReceiver<ShippingQueryUpdate>? = null,
|
||||||
|
preCheckoutQueryCallback: UpdateReceiver<PreCheckoutQueryUpdate>? = null
|
||||||
|
): UpdatesFilter = UpdatesFilter(
|
||||||
|
messageCallback = messageCallback,
|
||||||
|
messageMediaGroupCallback = mediaGroupCallback,
|
||||||
|
editedMessageCallback = editedMessageCallback,
|
||||||
|
editedMessageMediaGroupCallback = mediaGroupCallback,
|
||||||
|
channelPostCallback = channelPostCallback,
|
||||||
|
channelPostMediaGroupCallback = mediaGroupCallback,
|
||||||
|
editedChannelPostCallback = editedChannelPostCallback,
|
||||||
|
editedChannelPostMediaGroupCallback = mediaGroupCallback,
|
||||||
|
chosenInlineResultCallback = chosenInlineResultCallback,
|
||||||
|
inlineQueryCallback = inlineQueryCallback,
|
||||||
|
callbackQueryCallback = callbackQueryCallback,
|
||||||
|
shippingQueryCallback = shippingQueryCallback,
|
||||||
|
preCheckoutQueryCallback = preCheckoutQueryCallback
|
||||||
|
)
|
@ -0,0 +1,127 @@
|
|||||||
|
package com.github.insanusmokrassar.TelegramBotAPI.utils.extensions
|
||||||
|
|
||||||
|
import com.github.insanusmokrassar.TelegramBotAPI.bot.RequestsExecutor
|
||||||
|
import com.github.insanusmokrassar.TelegramBotAPI.requests.*
|
||||||
|
import com.github.insanusmokrassar.TelegramBotAPI.requests.abstracts.InputFile
|
||||||
|
import com.github.insanusmokrassar.TelegramBotAPI.types.MediaGroupIdentifier
|
||||||
|
import com.github.insanusmokrassar.TelegramBotAPI.types.message.abstracts.MediaGroupMessage
|
||||||
|
import com.github.insanusmokrassar.TelegramBotAPI.types.update.*
|
||||||
|
import com.github.insanusmokrassar.TelegramBotAPI.types.update.abstracts.Update
|
||||||
|
import io.ktor.application.Application
|
||||||
|
import io.ktor.application.call
|
||||||
|
import io.ktor.request.receiveText
|
||||||
|
import io.ktor.response.respond
|
||||||
|
import io.ktor.routing.*
|
||||||
|
import io.ktor.server.engine.*
|
||||||
|
import io.ktor.server.netty.Netty
|
||||||
|
import kotlinx.coroutines.*
|
||||||
|
import kotlinx.coroutines.channels.Channel
|
||||||
|
import kotlinx.serialization.json.Json
|
||||||
|
import java.util.concurrent.Executors
|
||||||
|
import java.util.concurrent.TimeUnit
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reverse proxy webhook.
|
||||||
|
*
|
||||||
|
* @param url URL of webhook WITHOUT including of [port]
|
||||||
|
* @param port port which will be listen by bot
|
||||||
|
* @param certificate [com.github.insanusmokrassar.TelegramBotAPI.requests.abstracts.MultipartFile] or [com.github.insanusmokrassar.TelegramBotAPI.requests.abstracts.FileId]
|
||||||
|
* which will be used by telegram to send encrypted messages
|
||||||
|
* @param scope Scope which will be used for
|
||||||
|
*/
|
||||||
|
suspend fun RequestsExecutor.setWebhook(
|
||||||
|
url: String,
|
||||||
|
port: Int,
|
||||||
|
certificate: InputFile,
|
||||||
|
scope: CoroutineScope = CoroutineScope(Executors.newFixedThreadPool(4).asCoroutineDispatcher()),
|
||||||
|
allowedUpdates: List<String>? = null,
|
||||||
|
maxAllowedConnections: Int? = null,
|
||||||
|
engineFactory: ApplicationEngineFactory<*, *> = Netty,
|
||||||
|
block: UpdateReceiver<Any>
|
||||||
|
): Job {
|
||||||
|
val executeDeferred = executeAsync(
|
||||||
|
SetWebhook(
|
||||||
|
url,
|
||||||
|
certificate,
|
||||||
|
maxAllowedConnections,
|
||||||
|
allowedUpdates
|
||||||
|
)
|
||||||
|
)
|
||||||
|
val updatesChannel = Channel<Update>(Channel.UNLIMITED)
|
||||||
|
val mediaGroupChannel = Channel<Pair<MediaGroupIdentifier, Update>>(Channel.UNLIMITED)
|
||||||
|
val mediaGroupAccumulatedChannel = mediaGroupChannel.accumulateByKey(
|
||||||
|
1000L,
|
||||||
|
scope = scope
|
||||||
|
)
|
||||||
|
val env = applicationEngineEnvironment {
|
||||||
|
module {
|
||||||
|
fun Application.main() {
|
||||||
|
routing {
|
||||||
|
post("/") {
|
||||||
|
val deserialized = call.receiveText()
|
||||||
|
val update = Json.nonstrict.parse(
|
||||||
|
RawUpdate.serializer(),
|
||||||
|
deserialized
|
||||||
|
)
|
||||||
|
updatesChannel.send(update.asUpdate)
|
||||||
|
call.respond("Ok")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
main()
|
||||||
|
}
|
||||||
|
connector {
|
||||||
|
host = "0.0.0.0"
|
||||||
|
this.port = port
|
||||||
|
}
|
||||||
|
}
|
||||||
|
val engine = embeddedServer(engineFactory, env)
|
||||||
|
|
||||||
|
try {
|
||||||
|
executeDeferred.await()
|
||||||
|
} catch (e: Exception) {
|
||||||
|
env.stop()
|
||||||
|
throw e
|
||||||
|
}
|
||||||
|
|
||||||
|
return scope.launch {
|
||||||
|
launch {
|
||||||
|
for (update in updatesChannel) {
|
||||||
|
val data = update.data
|
||||||
|
when (data) {
|
||||||
|
is MediaGroupMessage -> mediaGroupChannel.send(data.mediaGroupId to update)
|
||||||
|
else -> block(update)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
launch {
|
||||||
|
for (mediaGroupUpdate in mediaGroupAccumulatedChannel) {
|
||||||
|
block(mediaGroupUpdate.second)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
engine.start(false)
|
||||||
|
}.also {
|
||||||
|
it.invokeOnCompletion {
|
||||||
|
engine.stop(1000L, 0L, TimeUnit.MILLISECONDS)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
suspend fun RequestsExecutor.setWebhook(
|
||||||
|
url: String,
|
||||||
|
port: Int,
|
||||||
|
certificate: InputFile,
|
||||||
|
scope: CoroutineScope = CoroutineScope(Executors.newFixedThreadPool(4).asCoroutineDispatcher()),
|
||||||
|
maxAllowedConnections: Int? = null,
|
||||||
|
engineFactory: ApplicationEngineFactory<*, *> = Netty,
|
||||||
|
filter: UpdatesFilter
|
||||||
|
): Job = setWebhook(
|
||||||
|
url,
|
||||||
|
port,
|
||||||
|
certificate,
|
||||||
|
scope,
|
||||||
|
filter.allowedUpdates,
|
||||||
|
maxAllowedConnections,
|
||||||
|
engineFactory,
|
||||||
|
filter.asUpdateReceiver
|
||||||
|
)
|
Loading…
Reference in New Issue
Block a user