mirror of
https://github.com/InsanusMokrassar/TelegramBotAPI.git
synced 2024-10-31 21:43:48 +00:00
Merge pull request #124 from sleshJdev/feature/download-pathed-file-extension
Extended PathedFile to get it as file/stream
This commit is contained in:
commit
0472e35752
15
CHANGELOG.md
15
CHANGELOG.md
@ -21,6 +21,21 @@
|
||||
* All deprecations from previous versions were removed
|
||||
* `TelegramBotAPI-core`:
|
||||
* Typealias `TelegramBot` was added
|
||||
* Fully rebuilt `KtorCallFactory` interface to be able to handle custom answers from telegram bot api system
|
||||
* New implementation of `KtorCallFactory` was added: `DownloadFileRequestCallFactory`
|
||||
* `DownloadFile` request was added
|
||||
* All included `KtorCallFactory` realizations (except of abstract) now are objects:
|
||||
* `MultipartRequestCallFactory`
|
||||
* `SimpleRequestCallFactory`
|
||||
* `TelegramBotAPI-extensions-api`:
|
||||
* Extensions `TelegramBot#downloadFile` were added
|
||||
* `TelegramBotAPI-extensions-utils`:
|
||||
* All extensions for media groups (except of `mediaGroupId`) have changed their context: `List<MediaGroupMessage>`
|
||||
-> `List<CommonMessage<MediaGroupContent>>`
|
||||
* `forwardInfo`
|
||||
* `replyTo`
|
||||
* `chat`
|
||||
* `createResend` (several extensions)
|
||||
|
||||
## 0.27.0
|
||||
|
||||
|
@ -1,13 +1,15 @@
|
||||
package com.github.insanusmokrassar.TelegramBotAPI.bot.Ktor
|
||||
|
||||
import com.github.insanusmokrassar.TelegramBotAPI.requests.abstracts.Request
|
||||
import com.github.insanusmokrassar.TelegramBotAPI.utils.TelegramAPIUrlsKeeper
|
||||
import io.ktor.client.HttpClient
|
||||
import io.ktor.client.statement.HttpStatement
|
||||
import kotlinx.serialization.json.Json
|
||||
|
||||
interface KtorCallFactory {
|
||||
suspend fun <T: Any> prepareCall(
|
||||
suspend fun <T: Any> makeCall(
|
||||
client: HttpClient,
|
||||
baseUrl: String,
|
||||
request: Request<T>
|
||||
) : HttpStatement?
|
||||
urlsKeeper: TelegramAPIUrlsKeeper,
|
||||
request: Request<T>,
|
||||
jsonFormatter: Json
|
||||
): T?
|
||||
}
|
||||
|
@ -1,21 +1,17 @@
|
||||
package com.github.insanusmokrassar.TelegramBotAPI.bot.Ktor
|
||||
|
||||
import com.github.insanusmokrassar.TelegramBotAPI.bot.BaseRequestsExecutor
|
||||
import com.github.insanusmokrassar.TelegramBotAPI.bot.Ktor.base.MultipartRequestCallFactory
|
||||
import com.github.insanusmokrassar.TelegramBotAPI.bot.Ktor.base.SimpleRequestCallFactory
|
||||
import com.github.insanusmokrassar.TelegramBotAPI.bot.Ktor.base.*
|
||||
import com.github.insanusmokrassar.TelegramBotAPI.bot.exceptions.newRequestException
|
||||
import com.github.insanusmokrassar.TelegramBotAPI.bot.settings.limiters.EmptyLimiter
|
||||
import com.github.insanusmokrassar.TelegramBotAPI.bot.settings.limiters.RequestLimiter
|
||||
import com.github.insanusmokrassar.TelegramBotAPI.requests.abstracts.Request
|
||||
import com.github.insanusmokrassar.TelegramBotAPI.types.Response
|
||||
import com.github.insanusmokrassar.TelegramBotAPI.types.RetryAfterError
|
||||
import com.github.insanusmokrassar.TelegramBotAPI.utils.*
|
||||
import io.ktor.client.HttpClient
|
||||
import io.ktor.client.call.receive
|
||||
import io.ktor.client.features.*
|
||||
import io.ktor.client.statement.HttpStatement
|
||||
import io.ktor.client.statement.readText
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.serialization.json.Json
|
||||
|
||||
class KtorRequestsExecutor(
|
||||
@ -28,7 +24,7 @@ class KtorRequestsExecutor(
|
||||
) : BaseRequestsExecutor(telegramAPIUrlsKeeper) {
|
||||
private val callsFactories: List<KtorCallFactory> = callsFactories.run {
|
||||
if (!excludeDefaultFactories) {
|
||||
asSequence().plus(SimpleRequestCallFactory()).plus(MultipartRequestCallFactory()).toList()
|
||||
this + listOf(SimpleRequestCallFactory, MultipartRequestCallFactory, DownloadFileRequestCallFactory)
|
||||
} else {
|
||||
this
|
||||
}
|
||||
@ -57,39 +53,20 @@ class KtorRequestsExecutor(
|
||||
}
|
||||
) {
|
||||
requestsLimiter.limit {
|
||||
var statement: HttpStatement? = null
|
||||
for (factory in callsFactories) {
|
||||
statement = factory.prepareCall(
|
||||
var result: T? = null
|
||||
for (potentialFactory in callsFactories) {
|
||||
result = potentialFactory.makeCall(
|
||||
client,
|
||||
telegramAPIUrlsKeeper.commonAPIUrl,
|
||||
request
|
||||
telegramAPIUrlsKeeper,
|
||||
request,
|
||||
jsonFormatter
|
||||
)
|
||||
if (statement != null) {
|
||||
if (result != null) {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
val response = statement?.execute() ?: throw IllegalArgumentException("Can't execute request: $request")
|
||||
val content = response.receive<String>()
|
||||
val responseObject = jsonFormatter.decodeFromString(Response.serializer(), content)
|
||||
|
||||
(responseObject.result?.let {
|
||||
jsonFormatter.decodeFromJsonElement(request.resultDeserializer, it)
|
||||
} ?: responseObject.parameters?.let {
|
||||
val error = it.error
|
||||
if (error is RetryAfterError) {
|
||||
delay(error.leftToRetry)
|
||||
execute(request)
|
||||
} else {
|
||||
null
|
||||
}
|
||||
} ?: response.let {
|
||||
throw newRequestException(
|
||||
responseObject,
|
||||
content,
|
||||
"Can't get result object from $content"
|
||||
)
|
||||
})
|
||||
result ?: error("Can't execute request: $request")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,55 +1,79 @@
|
||||
package com.github.insanusmokrassar.TelegramBotAPI.bot.Ktor.base
|
||||
|
||||
import com.github.insanusmokrassar.TelegramBotAPI.bot.Ktor.KtorCallFactory
|
||||
import com.github.insanusmokrassar.TelegramBotAPI.bot.exceptions.newRequestException
|
||||
import com.github.insanusmokrassar.TelegramBotAPI.requests.GetUpdates
|
||||
import com.github.insanusmokrassar.TelegramBotAPI.requests.abstracts.Request
|
||||
import com.github.insanusmokrassar.TelegramBotAPI.types.Response
|
||||
import com.github.insanusmokrassar.TelegramBotAPI.types.RetryAfterError
|
||||
import com.github.insanusmokrassar.TelegramBotAPI.utils.TelegramAPIUrlsKeeper
|
||||
import io.ktor.client.HttpClient
|
||||
import io.ktor.client.call.receive
|
||||
import io.ktor.client.features.timeout
|
||||
import io.ktor.client.request.*
|
||||
import io.ktor.client.statement.HttpStatement
|
||||
import io.ktor.client.statement.HttpResponse
|
||||
import io.ktor.http.ContentType
|
||||
import io.ktor.http.HttpMethod
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.serialization.json.Json
|
||||
import kotlin.collections.set
|
||||
|
||||
abstract class AbstractRequestCallFactory : KtorCallFactory {
|
||||
private val methodsCache: MutableMap<String, String> = mutableMapOf()
|
||||
override suspend fun <T : Any> prepareCall(
|
||||
override suspend fun <T : Any> makeCall(
|
||||
client: HttpClient,
|
||||
baseUrl: String,
|
||||
request: Request<T>
|
||||
): HttpStatement? {
|
||||
val preparedBody = prepareCallBody(client, baseUrl, request) ?: return null
|
||||
urlsKeeper: TelegramAPIUrlsKeeper,
|
||||
request: Request<T>,
|
||||
jsonFormatter: Json
|
||||
): T? {
|
||||
val preparedBody = prepareCallBody(client, urlsKeeper, request) ?: return null
|
||||
|
||||
return HttpStatement(
|
||||
HttpRequestBuilder().apply {
|
||||
url(
|
||||
methodsCache[request.method()] ?: "$baseUrl/${request.method()}".also {
|
||||
methodsCache[request.method()] = it
|
||||
}
|
||||
)
|
||||
method = HttpMethod.Post
|
||||
accept(ContentType.Application.Json)
|
||||
client.post<HttpResponse> {
|
||||
url(
|
||||
methodsCache[request.method()] ?: "${urlsKeeper.commonAPIUrl}/${request.method()}".also {
|
||||
methodsCache[request.method()] = it
|
||||
}
|
||||
)
|
||||
accept(ContentType.Application.Json)
|
||||
|
||||
if (request is GetUpdates) {
|
||||
request.timeout ?.times(1000L) ?.let { customTimeoutMillis ->
|
||||
if (customTimeoutMillis > 0) {
|
||||
timeout {
|
||||
requestTimeoutMillis = customTimeoutMillis
|
||||
socketTimeoutMillis = customTimeoutMillis
|
||||
}
|
||||
if (request is GetUpdates) {
|
||||
request.timeout?.times(1000L)?.let { customTimeoutMillis ->
|
||||
if (customTimeoutMillis > 0) {
|
||||
timeout {
|
||||
requestTimeoutMillis = customTimeoutMillis
|
||||
socketTimeoutMillis = customTimeoutMillis
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
body = preparedBody
|
||||
},
|
||||
client
|
||||
)
|
||||
body = preparedBody
|
||||
}.let { response ->
|
||||
val content = response.receive<String>()
|
||||
val responseObject = jsonFormatter.decodeFromString(Response.serializer(), content)
|
||||
|
||||
return (responseObject.result?.let {
|
||||
jsonFormatter.decodeFromJsonElement(request.resultDeserializer, it)
|
||||
} ?: responseObject.parameters?.let {
|
||||
val error = it.error
|
||||
if (error is RetryAfterError) {
|
||||
delay(error.leftToRetry)
|
||||
makeCall(client, urlsKeeper, request, jsonFormatter)
|
||||
} else {
|
||||
null
|
||||
}
|
||||
} ?: response.let {
|
||||
throw newRequestException(
|
||||
responseObject,
|
||||
content,
|
||||
"Can't get result object from $content"
|
||||
)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
protected abstract fun <T : Any> prepareCallBody(
|
||||
client: HttpClient,
|
||||
baseUrl: String,
|
||||
urlsKeeper: TelegramAPIUrlsKeeper,
|
||||
request: Request<T>
|
||||
): Any?
|
||||
}
|
@ -0,0 +1,29 @@
|
||||
package com.github.insanusmokrassar.TelegramBotAPI.bot.Ktor.base
|
||||
|
||||
import com.github.insanusmokrassar.TelegramBotAPI.bot.Ktor.KtorCallFactory
|
||||
import com.github.insanusmokrassar.TelegramBotAPI.bot.RequestsExecutor
|
||||
import com.github.insanusmokrassar.TelegramBotAPI.requests.DownloadFile
|
||||
import com.github.insanusmokrassar.TelegramBotAPI.requests.abstracts.Request
|
||||
import com.github.insanusmokrassar.TelegramBotAPI.utils.TelegramAPIUrlsKeeper
|
||||
import com.github.insanusmokrassar.TelegramBotAPI.utils.handleSafely
|
||||
import io.ktor.client.HttpClient
|
||||
import io.ktor.client.request.*
|
||||
import io.ktor.client.statement.*
|
||||
import io.ktor.http.HttpMethod
|
||||
import kotlinx.serialization.json.Json
|
||||
|
||||
object DownloadFileRequestCallFactory : KtorCallFactory {
|
||||
override suspend fun <T : Any> makeCall(
|
||||
client: HttpClient,
|
||||
urlsKeeper: TelegramAPIUrlsKeeper,
|
||||
request: Request<T>,
|
||||
jsonFormatter: Json
|
||||
): T? = (request as? DownloadFile) ?.let {
|
||||
val fullUrl = "${urlsKeeper.fileBaseUrl}/${it.filePath}"
|
||||
|
||||
return handleSafely {
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
client.get<ByteArray>(fullUrl) as T // always ByteArray
|
||||
}
|
||||
}
|
||||
}
|
@ -1,6 +1,7 @@
|
||||
package com.github.insanusmokrassar.TelegramBotAPI.bot.Ktor.base
|
||||
|
||||
import com.github.insanusmokrassar.TelegramBotAPI.requests.abstracts.*
|
||||
import com.github.insanusmokrassar.TelegramBotAPI.utils.TelegramAPIUrlsKeeper
|
||||
import com.github.insanusmokrassar.TelegramBotAPI.utils.mapWithCommonValues
|
||||
import io.ktor.client.HttpClient
|
||||
import io.ktor.client.request.forms.MultiPartFormDataContent
|
||||
@ -8,11 +9,10 @@ import io.ktor.client.request.forms.formData
|
||||
import io.ktor.http.Headers
|
||||
import io.ktor.http.HttpHeaders
|
||||
|
||||
class MultipartRequestCallFactory : AbstractRequestCallFactory() {
|
||||
|
||||
object MultipartRequestCallFactory : AbstractRequestCallFactory() {
|
||||
override fun <T : Any> prepareCallBody(
|
||||
client: HttpClient,
|
||||
baseUrl: String,
|
||||
urlsKeeper: TelegramAPIUrlsKeeper,
|
||||
request: Request<T>
|
||||
): Any? = (request as? MultipartRequest) ?.let { castedRequest ->
|
||||
MultiPartFormDataContent(
|
||||
|
@ -1,14 +1,15 @@
|
||||
package com.github.insanusmokrassar.TelegramBotAPI.bot.Ktor.base
|
||||
|
||||
import com.github.insanusmokrassar.TelegramBotAPI.requests.abstracts.*
|
||||
import com.github.insanusmokrassar.TelegramBotAPI.utils.TelegramAPIUrlsKeeper
|
||||
import io.ktor.client.HttpClient
|
||||
import io.ktor.http.ContentType
|
||||
import io.ktor.http.content.TextContent
|
||||
|
||||
class SimpleRequestCallFactory : AbstractRequestCallFactory() {
|
||||
object SimpleRequestCallFactory : AbstractRequestCallFactory() {
|
||||
override fun <T : Any> prepareCallBody(
|
||||
client: HttpClient,
|
||||
baseUrl: String,
|
||||
urlsKeeper: TelegramAPIUrlsKeeper,
|
||||
request: Request<T>
|
||||
): Any? = (request as? SimpleRequest<T>) ?.let { _ ->
|
||||
val content = request.json().toString()
|
||||
|
@ -0,0 +1,14 @@
|
||||
package com.github.insanusmokrassar.TelegramBotAPI.requests
|
||||
|
||||
import com.github.insanusmokrassar.TelegramBotAPI.requests.abstracts.Request
|
||||
import kotlinx.serialization.DeserializationStrategy
|
||||
import kotlinx.serialization.builtins.ByteArraySerializer
|
||||
|
||||
class DownloadFile(
|
||||
val filePath: String
|
||||
) : Request<ByteArray> {
|
||||
override fun method(): String = filePath
|
||||
|
||||
override val resultDeserializer: DeserializationStrategy<ByteArray>
|
||||
get() = ByteArraySerializer()
|
||||
}
|
@ -24,13 +24,12 @@ data class InputMediaVideo(
|
||||
|
||||
override fun serialize(format: StringFormat): String = format.encodeToString(serializer(), this)
|
||||
|
||||
|
||||
@Transient
|
||||
override val arguments: JsonElement = buildArguments(serializer())
|
||||
|
||||
@SerialName(mediaField)
|
||||
val media: String = when (file) {
|
||||
is FileId -> file.fileId
|
||||
is MultipartFile -> file.fileId.toInputMediaFileAttachmentName()
|
||||
}
|
||||
|
||||
@Transient
|
||||
override val arguments: JsonElement = buildArguments(serializer())
|
||||
}
|
||||
|
@ -0,0 +1,32 @@
|
||||
package com.github.insanusmokrassar.TelegramBotAPI.extensions.api
|
||||
|
||||
import com.github.insanusmokrassar.TelegramBotAPI.bot.TelegramBot
|
||||
import com.github.insanusmokrassar.TelegramBotAPI.extensions.api.get.getFileAdditionalInfo
|
||||
import com.github.insanusmokrassar.TelegramBotAPI.requests.DownloadFile
|
||||
import com.github.insanusmokrassar.TelegramBotAPI.requests.abstracts.FileId
|
||||
import com.github.insanusmokrassar.TelegramBotAPI.types.files.PathedFile
|
||||
import com.github.insanusmokrassar.TelegramBotAPI.types.files.abstracts.TelegramMediaFile
|
||||
|
||||
suspend fun TelegramBot.downloadFile(
|
||||
filePath: String
|
||||
): ByteArray = execute(
|
||||
DownloadFile(filePath)
|
||||
)
|
||||
|
||||
suspend fun TelegramBot.downloadFile(
|
||||
pathedFile: PathedFile
|
||||
): ByteArray = execute(
|
||||
DownloadFile(pathedFile.filePath)
|
||||
)
|
||||
|
||||
suspend fun TelegramBot.downloadFile(
|
||||
fileId: FileId
|
||||
): ByteArray = downloadFile(
|
||||
getFileAdditionalInfo(fileId)
|
||||
)
|
||||
|
||||
suspend fun TelegramBot.downloadFile(
|
||||
file: TelegramMediaFile
|
||||
): ByteArray = downloadFile(
|
||||
getFileAdditionalInfo(file)
|
||||
)
|
@ -4,15 +4,15 @@ import com.github.insanusmokrassar.TelegramBotAPI.requests.send.media.SendMediaG
|
||||
import com.github.insanusmokrassar.TelegramBotAPI.types.*
|
||||
import com.github.insanusmokrassar.TelegramBotAPI.types.chat.abstracts.Chat
|
||||
import com.github.insanusmokrassar.TelegramBotAPI.types.message.ForwardInfo
|
||||
import com.github.insanusmokrassar.TelegramBotAPI.types.message.abstracts.MediaGroupMessage
|
||||
import com.github.insanusmokrassar.TelegramBotAPI.types.message.abstracts.Message
|
||||
import com.github.insanusmokrassar.TelegramBotAPI.types.message.abstracts.*
|
||||
import com.github.insanusmokrassar.TelegramBotAPI.types.message.content.abstracts.MediaGroupContent
|
||||
import com.github.insanusmokrassar.TelegramBotAPI.types.update.MediaGroupUpdates.SentMediaGroupUpdate
|
||||
|
||||
val List<MediaGroupMessage>.forwardInfo: ForwardInfo?
|
||||
val List<CommonMessage<MediaGroupContent>>.forwardInfo: ForwardInfo?
|
||||
get() = firstOrNull() ?.forwardInfo
|
||||
val List<MediaGroupMessage>.replyTo: Message?
|
||||
val List<CommonMessage<MediaGroupContent>>.replyTo: Message?
|
||||
get() = firstOrNull() ?.replyTo
|
||||
val List<MediaGroupMessage>.chat: Chat?
|
||||
val List<CommonMessage<MediaGroupContent>>.chat: Chat?
|
||||
get() = firstOrNull() ?.chat
|
||||
val List<MediaGroupMessage>.mediaGroupId: MediaGroupIdentifier?
|
||||
get() = firstOrNull() ?.mediaGroupId
|
||||
@ -26,7 +26,7 @@ val SentMediaGroupUpdate.chat: Chat
|
||||
val SentMediaGroupUpdate.mediaGroupId: MediaGroupIdentifier
|
||||
get() = data.mediaGroupId!!
|
||||
|
||||
fun List<MediaGroupMessage>.createResend(
|
||||
fun List<CommonMessage<MediaGroupContent>>.createResend(
|
||||
chatId: ChatId,
|
||||
disableNotification: Boolean = false,
|
||||
replyTo: MessageIdentifier? = null
|
||||
@ -37,7 +37,7 @@ fun List<MediaGroupMessage>.createResend(
|
||||
replyTo
|
||||
)
|
||||
|
||||
fun List<MediaGroupMessage>.createResend(
|
||||
fun List<CommonMessage<MediaGroupContent>>.createResend(
|
||||
chat: Chat,
|
||||
disableNotification: Boolean = false,
|
||||
replyTo: MessageIdentifier? = null
|
||||
|
@ -0,0 +1,29 @@
|
||||
package com.github.insanusmokrassar.TelegramBotAPI.types.files
|
||||
|
||||
import com.github.insanusmokrassar.TelegramBotAPI.utils.TelegramAPIUrlsKeeper
|
||||
import java.io.File
|
||||
import java.io.FileOutputStream
|
||||
import java.io.InputStream
|
||||
import java.net.URL
|
||||
|
||||
fun PathedFile.asStream(
|
||||
telegramAPIUrlsKeeper: TelegramAPIUrlsKeeper
|
||||
): InputStream = URL(this.fullUrl(telegramAPIUrlsKeeper)).openStream()
|
||||
|
||||
fun PathedFile.asFile(
|
||||
telegramAPIUrlsKeeper: TelegramAPIUrlsKeeper,
|
||||
dest: File = File.createTempFile(this.fileUniqueId, this.filename),
|
||||
defaultBufferSize: Int = DEFAULT_BUFFER_SIZE
|
||||
): File {
|
||||
this.asStream(telegramAPIUrlsKeeper).use { input ->
|
||||
FileOutputStream(dest).use { out ->
|
||||
input.copyTo(out, defaultBufferSize)
|
||||
}
|
||||
}
|
||||
return dest
|
||||
}
|
||||
|
||||
fun PathedFile.asBytes(
|
||||
telegramAPIUrlsKeeper: TelegramAPIUrlsKeeper
|
||||
): ByteArray = this.asStream(telegramAPIUrlsKeeper)
|
||||
.use { input -> input.readBytes() }
|
Loading…
Reference in New Issue
Block a user