com.github.insanusmokrassar.AutoPostTelegramBot.utils.extensions.TelegramBot.kt Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of AutoPostTelegramBot Show documentation
Show all versions of AutoPostTelegramBot Show documentation
It is base library for creating smart bot for simple management of channels posts
package com.github.insanusmokrassar.AutoPostTelegramBot.utils.extensions
import com.github.insanusmokrassar.AutoPostTelegramBot.utils.SemaphoreK
import com.pengrad.telegrambot.Callback
import com.pengrad.telegrambot.TelegramBot
import com.pengrad.telegrambot.request.AnswerCallbackQuery
import com.pengrad.telegrambot.request.BaseRequest
import com.pengrad.telegrambot.response.BaseResponse
import kotlinx.coroutines.experimental.*
import org.slf4j.LoggerFactory
import java.io.IOException
import java.lang.ref.WeakReference
import kotlin.coroutines.experimental.suspendCoroutine
private val logger = LoggerFactory.getLogger("TelegramAsyncExecutions")
private val semaphores: MutableMap = HashMap()
fun initSemaphore(
bot: TelegramBot,
maxCount: Int = 30,
regenDelay: Long = 1000L,
regenCount: Int = 1
) {
semaphores[bot] ?.also {
throw IllegalStateException("Semaphore for bot was initiated, but was initiated again")
} ?: bot.also {
semaphores[it] = SemaphoreK(maxCount).also {
launch {
while (isActive) {
it.free(regenCount)
delay(regenDelay)
}
}
}
}
}
private class DefaultCallback, R: BaseResponse>(
private val onFailureCallback: ((T, IOException?) -> Unit)?,
private val onResponseCallback: ((T, R) -> Unit)?,
bot: TelegramBot,
private var retries: Int = 0,
private val retriesDelay: Long = 1000L
) : Callback {
private val bot = WeakReference(bot)
override fun onFailure(request: T, e: IOException?) {
logger.warn("Request failure: {}; Error: {}", request, e)
onFailureCallback ?. invoke(request, e)
if (retries > 0) {
async {
delay(retriesDelay)
bot.get() ?. executeAsync(
request,
onFailureCallback,
onResponseCallback,
retries - 1,
retriesDelay
)
}
}
}
override fun onResponse(request: T, response: R) {
logger.info("Request success: {}\nResponse: {}", request, response)
if (response.isOk) {
onResponseCallback ?. invoke(request, response)
} else {
onFailure(request, IOException(response.description()))
}
}
}
fun , R: BaseResponse> TelegramBot.executeAsync(
request: T,
onFailure: ((T, IOException?) -> Unit)? = null,
onResponse: ((T, R) -> Unit)? = null,
retries: Int = 0,
retriesDelay: Long = 1000L
) {
if (onFailure == null && onResponse == null) {
launch {
executeBlocking(request, retries, retriesDelay)
}
} else {
launch {
try {
val result = executeBlocking(request, retries, retriesDelay)
onResponse ?.invoke(request, result)
} catch (e: IOException) {
onFailure ?.invoke(request, e)
}
}
}
}
@Throws(IOException::class)
suspend fun , R: BaseResponse> TelegramBot.executeBlocking(
request: T,
retries: Int = 0,
retriesDelay: Long = 1000L
): R {
semaphores[this@executeBlocking] ?.lock()
logger.info("Try to put request for executing: {}", request)
return suspendCoroutine {
continuation ->
execute(
request,
DefaultCallback(
{
_, ioException ->
continuation.resumeWithException(
ioException ?: IllegalStateException("Something went wrong")
)
},
{
_, r ->
continuation.resume(r)
},
this@executeBlocking,
retries,
retriesDelay
)
)
}
}
fun TelegramBot.queryAnswer(
id: String,
answerText: String,
asAlert: Boolean = false
) {
executeAsync(
AnswerCallbackQuery(
id
)
.text(answerText)
.showAlert(asAlert)
)
}