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 = {}
|
crossinline builder: KtorRequestsExecutorBuilder.() -> Unit = {}
|
||||||
): TelegramBot = telegramBot(TelegramAPIUrlsKeeper(token, apiUrl), builder)
|
): TelegramBot = telegramBot(TelegramAPIUrlsKeeper(token, apiUrl), builder)
|
||||||
|
|
||||||
|
@RiskFeature
|
||||||
|
fun createTelegramBotDefaultKtorCallRequestsFactories() = listOf(
|
||||||
|
SimpleRequestCallFactory(),
|
||||||
|
MultipartRequestCallFactory(),
|
||||||
|
DownloadFileRequestCallFactory,
|
||||||
|
DownloadFileChannelRequestCallFactory
|
||||||
|
)
|
||||||
|
|
||||||
class KtorRequestsExecutor(
|
class KtorRequestsExecutor(
|
||||||
telegramAPIUrlsKeeper: TelegramAPIUrlsKeeper,
|
telegramAPIUrlsKeeper: TelegramAPIUrlsKeeper,
|
||||||
client: HttpClient = HttpClient(),
|
client: HttpClient = HttpClient(),
|
||||||
@ -52,7 +60,7 @@ class KtorRequestsExecutor(
|
|||||||
) : BaseRequestsExecutor(telegramAPIUrlsKeeper) {
|
) : BaseRequestsExecutor(telegramAPIUrlsKeeper) {
|
||||||
private val callsFactories: List<KtorCallFactory> = callsFactories.run {
|
private val callsFactories: List<KtorCallFactory> = callsFactories.run {
|
||||||
if (!excludeDefaultFactories) {
|
if (!excludeDefaultFactories) {
|
||||||
this + listOf(SimpleRequestCallFactory(), MultipartRequestCallFactory(), DownloadFileRequestCallFactory)
|
this + createTelegramBotDefaultKtorCallRequestsFactories()
|
||||||
} else {
|
} else {
|
||||||
this
|
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>,
|
request: Request<T>,
|
||||||
jsonFormatter: Json
|
jsonFormatter: Json
|
||||||
): T? = (request as? DownloadFile) ?.let {
|
): T? = (request as? DownloadFile) ?.let {
|
||||||
val fullUrl = "${urlsKeeper.fileBaseUrl}/${it.filePath}"
|
val fullUrl = urlsKeeper.createFileLinkUrl(it.filePath)
|
||||||
|
|
||||||
return safely {
|
return safely {
|
||||||
@Suppress("UNCHECKED_CAST")
|
@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"
|
commonAPIUrl = "$correctedHost/bot$token"
|
||||||
fileBaseUrl = "$correctedHost/file/bot$token"
|
fileBaseUrl = "$correctedHost/file/bot$token"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun createFileLinkUrl(filePath: String) = "${fileBaseUrl}/$filePath"
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user