mirror of
https://github.com/InsanusMokrassar/TelegramBotAPI.git
synced 2024-11-26 12:08:43 +00:00
add streaming file downloading feature
This commit is contained in:
parent
ea8db5b851
commit
b475976ff1
@ -42,6 +42,14 @@ inline fun telegramBot(
|
||||
crossinline builder: KtorRequestsExecutorBuilder.() -> Unit = {}
|
||||
): TelegramBot = telegramBot(TelegramAPIUrlsKeeper(token, apiUrl), builder)
|
||||
|
||||
@RiskFeature
|
||||
fun createTelegramBotDefaultKtorCallRequestsFactories() = listOf(
|
||||
SimpleRequestCallFactory(),
|
||||
MultipartRequestCallFactory(),
|
||||
DownloadFileRequestCallFactory,
|
||||
DownloadFileChannelRequestCallFactory
|
||||
)
|
||||
|
||||
class KtorRequestsExecutor(
|
||||
telegramAPIUrlsKeeper: TelegramAPIUrlsKeeper,
|
||||
client: HttpClient = HttpClient(),
|
||||
@ -52,7 +60,7 @@ class KtorRequestsExecutor(
|
||||
) : BaseRequestsExecutor(telegramAPIUrlsKeeper) {
|
||||
private val callsFactories: List<KtorCallFactory> = callsFactories.run {
|
||||
if (!excludeDefaultFactories) {
|
||||
this + listOf(SimpleRequestCallFactory(), MultipartRequestCallFactory(), DownloadFileRequestCallFactory)
|
||||
this + createTelegramBotDefaultKtorCallRequestsFactories()
|
||||
} else {
|
||||
this
|
||||
}
|
||||
|
@ -0,0 +1,38 @@
|
||||
package dev.inmo.tgbotapi.bot.Ktor.base
|
||||
|
||||
import dev.inmo.tgbotapi.bot.Ktor.KtorCallFactory
|
||||
import dev.inmo.tgbotapi.requests.DownloadFileStream
|
||||
import dev.inmo.tgbotapi.requests.abstracts.Request
|
||||
import dev.inmo.tgbotapi.utils.InputStreamAllocator
|
||||
import dev.inmo.tgbotapi.utils.TelegramAPIUrlsKeeper
|
||||
import io.ktor.client.HttpClient
|
||||
import io.ktor.client.call.receive
|
||||
import io.ktor.client.request.get
|
||||
import io.ktor.client.statement.HttpStatement
|
||||
import io.ktor.utils.io.*
|
||||
import kotlinx.coroutines.*
|
||||
import kotlinx.serialization.json.Json
|
||||
import kotlin.coroutines.coroutineContext
|
||||
|
||||
object DownloadFileChannelRequestCallFactory : KtorCallFactory {
|
||||
override suspend fun <T : Any> makeCall(
|
||||
client: HttpClient,
|
||||
urlsKeeper: TelegramAPIUrlsKeeper,
|
||||
request: Request<T>,
|
||||
jsonFormatter: Json
|
||||
): T? = (request as? DownloadFileStream) ?.let {
|
||||
val fullUrl = urlsKeeper.createFileLinkUrl(it.filePath)
|
||||
|
||||
return InputStreamAllocator {
|
||||
val scope = CoroutineScope(coroutineContext)
|
||||
val outChannel = ByteChannel()
|
||||
scope.launch {
|
||||
client.get<HttpStatement>(fullUrl).execute { httpResponse ->
|
||||
val channel: ByteReadChannel = httpResponse.receive()
|
||||
channel.copyTo(outChannel)
|
||||
}
|
||||
}
|
||||
outChannel
|
||||
} as T
|
||||
}
|
||||
}
|
@ -16,7 +16,7 @@ object DownloadFileRequestCallFactory : KtorCallFactory {
|
||||
request: Request<T>,
|
||||
jsonFormatter: Json
|
||||
): T? = (request as? DownloadFile) ?.let {
|
||||
val fullUrl = "${urlsKeeper.fileBaseUrl}/${it.filePath}"
|
||||
val fullUrl = urlsKeeper.createFileLinkUrl(it.filePath)
|
||||
|
||||
return safely {
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
|
@ -0,0 +1,15 @@
|
||||
package dev.inmo.tgbotapi.requests
|
||||
|
||||
import dev.inmo.tgbotapi.requests.abstracts.Request
|
||||
import dev.inmo.tgbotapi.utils.InputStreamAllocator
|
||||
import dev.inmo.tgbotapi.utils.InputStreamAllocatorSerializer
|
||||
import kotlinx.serialization.DeserializationStrategy
|
||||
|
||||
class DownloadFileStream(
|
||||
val filePath: String
|
||||
) : Request<InputStreamAllocator> {
|
||||
override fun method(): String = filePath
|
||||
override val resultDeserializer: DeserializationStrategy<InputStreamAllocator>
|
||||
get() = InputStreamAllocatorSerializer
|
||||
|
||||
}
|
@ -0,0 +1,31 @@
|
||||
package dev.inmo.tgbotapi.utils
|
||||
|
||||
import dev.inmo.micro_utils.common.ByteArrayAllocatorSerializer
|
||||
import io.ktor.util.toByteArray
|
||||
import io.ktor.utils.io.ByteReadChannel
|
||||
import kotlinx.coroutines.*
|
||||
import kotlinx.serialization.KSerializer
|
||||
import kotlinx.serialization.descriptors.SerialDescriptor
|
||||
import kotlinx.serialization.encoding.Decoder
|
||||
import kotlinx.serialization.encoding.Encoder
|
||||
|
||||
fun interface InputStreamAllocator {
|
||||
suspend operator fun invoke(): ByteReadChannel
|
||||
}
|
||||
|
||||
object InputStreamAllocatorSerializer : KSerializer<InputStreamAllocator> {
|
||||
override val descriptor: SerialDescriptor = ByteArrayAllocatorSerializer.descriptor
|
||||
|
||||
override fun serialize(encoder: Encoder, value: InputStreamAllocator) {
|
||||
TODO("Not yet implemented")
|
||||
// ByteArrayAllocatorSerializer.serialize(
|
||||
// encoder
|
||||
// ) {
|
||||
// }
|
||||
}
|
||||
|
||||
override fun deserialize(decoder: Decoder): InputStreamAllocator {
|
||||
val byteArrayAllocator = ByteArrayAllocatorSerializer.deserialize(decoder)
|
||||
return InputStreamAllocator { ByteReadChannel(byteArrayAllocator()) }
|
||||
}
|
||||
}
|
@ -26,4 +26,6 @@ class TelegramAPIUrlsKeeper(
|
||||
commonAPIUrl = "$correctedHost/bot$token"
|
||||
fileBaseUrl = "$correctedHost/file/bot$token"
|
||||
}
|
||||
|
||||
fun createFileLinkUrl(filePath: String) = "${fileBaseUrl}/$filePath"
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user