mirror of
https://github.com/InsanusMokrassar/MicroUtils.git
synced 2024-12-18 14:47:15 +00:00
improvements in ktor client-server files handling
This commit is contained in:
parent
30d4507f54
commit
0c5e2862ca
@ -5,6 +5,9 @@
|
|||||||
* `Ktor`:
|
* `Ktor`:
|
||||||
* `Server`:
|
* `Server`:
|
||||||
* Small fix in `handleUniUpload`
|
* Small fix in `handleUniUpload`
|
||||||
|
* `ApplicationCall#uniloadMultipartFile` now uses `uniloadMultipart`
|
||||||
|
* `Client`:
|
||||||
|
* New extensions on top of `uniUpload`
|
||||||
|
|
||||||
## 0.14.3
|
## 0.14.3
|
||||||
|
|
||||||
|
@ -0,0 +1,20 @@
|
|||||||
|
package dev.inmo.micro_utils.common
|
||||||
|
|
||||||
|
import java.io.File
|
||||||
|
import java.io.InputStream
|
||||||
|
import java.util.UUID
|
||||||
|
|
||||||
|
fun InputStream.downloadToTempFile(
|
||||||
|
fileName: String = UUID.randomUUID().toString(),
|
||||||
|
fileExtension: String? = ".temp",
|
||||||
|
folder: File? = null
|
||||||
|
) = File.createTempFile(
|
||||||
|
fileName,
|
||||||
|
fileExtension,
|
||||||
|
folder
|
||||||
|
).apply {
|
||||||
|
outputStream().use {
|
||||||
|
copyTo(it)
|
||||||
|
}
|
||||||
|
deleteOnExit()
|
||||||
|
}
|
@ -1,9 +1,11 @@
|
|||||||
package dev.inmo.micro_utils.ktor.client
|
package dev.inmo.micro_utils.ktor.client
|
||||||
|
|
||||||
import dev.inmo.micro_utils.common.FileName
|
import dev.inmo.micro_utils.common.FileName
|
||||||
|
import dev.inmo.micro_utils.common.MPPFile
|
||||||
import dev.inmo.micro_utils.ktor.common.LambdaInputProvider
|
import dev.inmo.micro_utils.ktor.common.LambdaInputProvider
|
||||||
import io.ktor.client.HttpClient
|
import io.ktor.client.HttpClient
|
||||||
import io.ktor.http.Headers
|
import io.ktor.http.Headers
|
||||||
|
import io.ktor.utils.io.core.Input
|
||||||
import kotlinx.serialization.DeserializationStrategy
|
import kotlinx.serialization.DeserializationStrategy
|
||||||
import kotlinx.serialization.StringFormat
|
import kotlinx.serialization.StringFormat
|
||||||
import kotlinx.serialization.json.Json
|
import kotlinx.serialization.json.Json
|
||||||
@ -20,6 +22,8 @@ data class UniUploadFileInfo(
|
|||||||
* @param data [Map] where keys will be used as names for multipart parts and values as values. If you will pass
|
* @param data [Map] where keys will be used as names for multipart parts and values as values. If you will pass
|
||||||
* [dev.inmo.micro_utils.common.MPPFile] (File from JS or JVM platform). Also you may pass [UniUploadFileInfo] as value
|
* [dev.inmo.micro_utils.common.MPPFile] (File from JS or JVM platform). Also you may pass [UniUploadFileInfo] as value
|
||||||
* in case you wish to pass other source of multipart binary data than regular file
|
* in case you wish to pass other source of multipart binary data than regular file
|
||||||
|
*
|
||||||
|
* @see dev.inmo.micro_utils.ktor.server.handleUniUpload
|
||||||
*/
|
*/
|
||||||
expect suspend fun <T> HttpClient.uniUpload(
|
expect suspend fun <T> HttpClient.uniUpload(
|
||||||
url: String,
|
url: String,
|
||||||
@ -29,3 +33,73 @@ expect suspend fun <T> HttpClient.uniUpload(
|
|||||||
stringFormat: StringFormat = Json,
|
stringFormat: StringFormat = Json,
|
||||||
onUpload: OnUploadCallback = { _, _ -> }
|
onUpload: OnUploadCallback = { _, _ -> }
|
||||||
): T?
|
): T?
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Additional variant of [uniUpload] which will unify sending of some [MPPFile] with the server
|
||||||
|
*
|
||||||
|
* @see dev.inmo.micro_utils.ktor.server.uniloadMultipartFile
|
||||||
|
*/
|
||||||
|
suspend fun <T> HttpClient.uniUpload(
|
||||||
|
url: String,
|
||||||
|
file: MPPFile,
|
||||||
|
resultDeserializer: DeserializationStrategy<T>,
|
||||||
|
additionalData: Map<String, Any> = emptyMap(),
|
||||||
|
headers: Headers = Headers.Empty,
|
||||||
|
stringFormat: StringFormat = Json,
|
||||||
|
onUpload: OnUploadCallback = { _, _ -> }
|
||||||
|
): T? = uniUpload(
|
||||||
|
url,
|
||||||
|
additionalData + ("bytes" to file),
|
||||||
|
resultDeserializer,
|
||||||
|
headers,
|
||||||
|
stringFormat,
|
||||||
|
onUpload
|
||||||
|
)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Additional variant of [uniUpload] which will unify sending of some [UniUploadFileInfo] with the server
|
||||||
|
*
|
||||||
|
* @see dev.inmo.micro_utils.ktor.server.uniloadMultipartFile
|
||||||
|
*/
|
||||||
|
suspend fun <T> HttpClient.uniUpload(
|
||||||
|
url: String,
|
||||||
|
info: UniUploadFileInfo,
|
||||||
|
resultDeserializer: DeserializationStrategy<T>,
|
||||||
|
additionalData: Map<String, Any> = emptyMap(),
|
||||||
|
headers: Headers = Headers.Empty,
|
||||||
|
stringFormat: StringFormat = Json,
|
||||||
|
onUpload: OnUploadCallback = { _, _ -> }
|
||||||
|
): T? = uniUpload(
|
||||||
|
url,
|
||||||
|
additionalData + ("bytes" to info),
|
||||||
|
resultDeserializer,
|
||||||
|
headers,
|
||||||
|
stringFormat,
|
||||||
|
onUpload
|
||||||
|
)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Additional variant of [uniUpload] which will unify sending of some [UniUploadFileInfo] (built from [fileName],
|
||||||
|
* [mimeType] and [inputAllocator]) with the server
|
||||||
|
*
|
||||||
|
* @see dev.inmo.micro_utils.ktor.server.uniloadMultipartFile
|
||||||
|
*/
|
||||||
|
suspend fun <T> HttpClient.uniUpload(
|
||||||
|
url: String,
|
||||||
|
fileName: FileName,
|
||||||
|
mimeType: String,
|
||||||
|
inputAllocator: LambdaInputProvider,
|
||||||
|
resultDeserializer: DeserializationStrategy<T>,
|
||||||
|
additionalData: Map<String, Any> = emptyMap(),
|
||||||
|
headers: Headers = Headers.Empty,
|
||||||
|
stringFormat: StringFormat = Json,
|
||||||
|
onUpload: OnUploadCallback = { _, _ -> }
|
||||||
|
): T? = uniUpload(
|
||||||
|
url,
|
||||||
|
UniUploadFileInfo(fileName, mimeType, inputAllocator),
|
||||||
|
resultDeserializer,
|
||||||
|
additionalData,
|
||||||
|
headers,
|
||||||
|
stringFormat,
|
||||||
|
onUpload
|
||||||
|
)
|
||||||
|
@ -0,0 +1,23 @@
|
|||||||
|
package dev.inmo.micro_utils.ktor.common
|
||||||
|
|
||||||
|
import io.ktor.utils.io.core.Input
|
||||||
|
import io.ktor.utils.io.core.copyTo
|
||||||
|
import io.ktor.utils.io.streams.asOutput
|
||||||
|
import java.io.File
|
||||||
|
import java.io.InputStream
|
||||||
|
import java.util.UUID
|
||||||
|
|
||||||
|
fun Input.downloadToTempFile(
|
||||||
|
fileName: String = UUID.randomUUID().toString(),
|
||||||
|
fileExtension: String? = ".temp",
|
||||||
|
folder: File? = null
|
||||||
|
) = File.createTempFile(
|
||||||
|
fileName,
|
||||||
|
fileExtension,
|
||||||
|
folder
|
||||||
|
).apply {
|
||||||
|
outputStream().use {
|
||||||
|
copyTo(it.asOutput())
|
||||||
|
}
|
||||||
|
deleteOnExit()
|
||||||
|
}
|
@ -2,6 +2,7 @@ package dev.inmo.micro_utils.ktor.server
|
|||||||
|
|
||||||
import dev.inmo.micro_utils.common.*
|
import dev.inmo.micro_utils.common.*
|
||||||
import dev.inmo.micro_utils.coroutines.safely
|
import dev.inmo.micro_utils.coroutines.safely
|
||||||
|
import dev.inmo.micro_utils.ktor.common.downloadToTempFile
|
||||||
import io.ktor.http.content.*
|
import io.ktor.http.content.*
|
||||||
import io.ktor.server.application.ApplicationCall
|
import io.ktor.server.application.ApplicationCall
|
||||||
import io.ktor.server.request.receiveMultipart
|
import io.ktor.server.request.receiveMultipart
|
||||||
@ -37,7 +38,7 @@ suspend fun ApplicationCall.uniloadMultipart(
|
|||||||
onCustomFileItem: (PartData.FileItem) -> Unit = {},
|
onCustomFileItem: (PartData.FileItem) -> Unit = {},
|
||||||
onBinaryChannelItem: (PartData.BinaryChannelItem) -> Unit = {},
|
onBinaryChannelItem: (PartData.BinaryChannelItem) -> Unit = {},
|
||||||
onBinaryContent: (PartData.BinaryItem) -> Unit = {}
|
onBinaryContent: (PartData.BinaryItem) -> Unit = {}
|
||||||
) = safely {
|
): Input = safely {
|
||||||
var resultInput: Input? = null
|
var resultInput: Input? = null
|
||||||
|
|
||||||
handleUniUpload(
|
handleUniUpload(
|
||||||
@ -59,41 +60,11 @@ suspend fun ApplicationCall.uniloadMultipartFile(
|
|||||||
onCustomFileItem: (PartData.FileItem) -> Unit = {},
|
onCustomFileItem: (PartData.FileItem) -> Unit = {},
|
||||||
onBinaryChannelItem: (PartData.BinaryChannelItem) -> Unit = {},
|
onBinaryChannelItem: (PartData.BinaryChannelItem) -> Unit = {},
|
||||||
onBinaryContent: (PartData.BinaryItem) -> Unit = {},
|
onBinaryContent: (PartData.BinaryItem) -> Unit = {},
|
||||||
) = safely {
|
): MPPFile = safely {
|
||||||
val multipartData = receiveMultipart()
|
uniloadMultipart(
|
||||||
|
onFormItem,
|
||||||
var resultInput: MPPFile? = null
|
onCustomFileItem,
|
||||||
|
onBinaryChannelItem,
|
||||||
multipartData.forEachPart {
|
onBinaryContent
|
||||||
when (it) {
|
).downloadToTempFile()
|
||||||
is PartData.FormItem -> onFormItem(it)
|
|
||||||
is PartData.FileItem -> {
|
|
||||||
if (it.name == "bytes") {
|
|
||||||
val name = FileName(it.originalFileName ?: error("File name is unknown for default part"))
|
|
||||||
resultInput = MPPFile.createTempFile(
|
|
||||||
name.nameWithoutExtension.let {
|
|
||||||
var resultName = it
|
|
||||||
while (resultName.length < 3) {
|
|
||||||
resultName += "_"
|
|
||||||
}
|
|
||||||
resultName
|
|
||||||
},
|
|
||||||
".${name.extension}"
|
|
||||||
).apply {
|
|
||||||
outputStream().use { fileStream ->
|
|
||||||
it.streamProvider().use {
|
|
||||||
it.copyTo(fileStream)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
onCustomFileItem(it)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
is PartData.BinaryItem -> onBinaryContent(it)
|
|
||||||
is PartData.BinaryChannelItem -> onBinaryChannelItem(it)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
resultInput ?: error("Bytes has not been received")
|
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user