mirror of
https://github.com/InsanusMokrassar/MicroUtils.git
synced 2025-09-18 06:49:20 +00:00
Compare commits
31 Commits
Author | SHA1 | Date | |
---|---|---|---|
7cb064896a | |||
0c5e2862ca | |||
30d4507f54 | |||
b6c6d89455 | |||
9d218ee534 | |||
11116d8cab | |||
58d754bbde | |||
8f25c123dd | |||
76e214fc08 | |||
2b5380f8d6 | |||
844a129094 | |||
a3090cca9d | |||
b7b5159e9c | |||
0f8bc2c950 | |||
69f5c49f45 | |||
9b308e6fb8 | |||
3e3f91128b | |||
0d1aae0ef7 | |||
4d022f0480 | |||
153e20d00e | |||
a9a8171dd6 | |||
bf5c3b59b2 | |||
607c432bdb | |||
ae5c010770 | |||
d5e432437f | |||
9f99ebce01 | |||
64ee899b84 | |||
e0e0c1658b | |||
2c586f667c | |||
64164ef6c1 | |||
22343c0731 |
14
.github/workflows/build.yml
vendored
14
.github/workflows/build.yml
vendored
@@ -9,9 +9,6 @@ jobs:
|
|||||||
- uses: actions/setup-java@v1
|
- uses: actions/setup-java@v1
|
||||||
with:
|
with:
|
||||||
java-version: 11
|
java-version: 11
|
||||||
- name: Fix android 32.0.0 dx
|
|
||||||
continue-on-error: true
|
|
||||||
run: cd /usr/local/lib/android/sdk/build-tools/32.0.0/ && mv d8 dx && cd lib && mv d8.jar dx.jar
|
|
||||||
- name: Rewrite version
|
- name: Rewrite version
|
||||||
run: |
|
run: |
|
||||||
branch="`echo "${{ github.ref }}" | grep -o "[^/]*$"`"
|
branch="`echo "${{ github.ref }}" | grep -o "[^/]*$"`"
|
||||||
@@ -20,9 +17,8 @@ jobs:
|
|||||||
mv gradle.properties.tmp gradle.properties
|
mv gradle.properties.tmp gradle.properties
|
||||||
- name: Build
|
- name: Build
|
||||||
run: ./gradlew build
|
run: ./gradlew build
|
||||||
# - name: Publish
|
- name: Publish
|
||||||
# continue-on-error: true
|
continue-on-error: true
|
||||||
# run: ./gradlew --no-parallel publishAllPublicationsToGithubPackagesRepository
|
run: ./gradlew publishAllPublicationsToGiteaRepository
|
||||||
# env:
|
env:
|
||||||
# GITHUBPACKAGES_USER: ${{ github.actor }}
|
GITEA_TOKEN: ${{ secrets.GITEA_TOKEN }}
|
||||||
# GITHUBPACKAGES_PASSWORD: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
|
@@ -1,8 +0,0 @@
|
|||||||
job("Build and run tests") {
|
|
||||||
container(displayName = "Run gradle build", image = "openjdk:11") {
|
|
||||||
kotlinScript { api ->
|
|
||||||
// here can be your complex logic
|
|
||||||
api.gradlew("build")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
37
CHANGELOG.md
37
CHANGELOG.md
@@ -1,5 +1,42 @@
|
|||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
|
## 0.14.4
|
||||||
|
|
||||||
|
* `Common`:
|
||||||
|
* `JVM`:
|
||||||
|
* New extension `downloadToTempFile`
|
||||||
|
* `Ktor`:
|
||||||
|
* `Server`:
|
||||||
|
* Small fix in `handleUniUpload`
|
||||||
|
* `ApplicationCall#uniloadMultipartFile` now uses `uniloadMultipart`
|
||||||
|
* `Common`:
|
||||||
|
* New extension `downloadToTempFile`
|
||||||
|
* `Client`:
|
||||||
|
* New extensions on top of `uniUpload`
|
||||||
|
|
||||||
|
## 0.14.3
|
||||||
|
|
||||||
|
* `Common`:
|
||||||
|
* New type `Progress`
|
||||||
|
* `Ktor`:
|
||||||
|
* `Client`:
|
||||||
|
* New universal `uniUpload` extension for `HttpClient`
|
||||||
|
* `Server`:
|
||||||
|
* New universal `handleUniUpload` extension for `ApplicationCall`
|
||||||
|
* Add extensions `download` and `downloadToTemporalFile`
|
||||||
|
|
||||||
|
## 0.14.2
|
||||||
|
|
||||||
|
* `Versions`:
|
||||||
|
* `Exposed`: `0.40.1` -> `0.41.1`
|
||||||
|
|
||||||
|
|
||||||
|
## 0.14.1
|
||||||
|
|
||||||
|
* `Versions`:
|
||||||
|
* `Klock`: `3.3.1` -> `3.4.0`
|
||||||
|
* `UUID`: `0.5.0` -> `0.6.0`
|
||||||
|
|
||||||
## 0.14.0
|
## 0.14.0
|
||||||
|
|
||||||
**ALL DEPRECATIONS HAVE BEEN REMOVED**
|
**ALL DEPRECATIONS HAVE BEEN REMOVED**
|
||||||
|
@@ -0,0 +1,37 @@
|
|||||||
|
package dev.inmo.micro_utils.common
|
||||||
|
|
||||||
|
import kotlinx.serialization.Serializable
|
||||||
|
import kotlin.jvm.JvmInline
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
@JvmInline
|
||||||
|
value class Progress private constructor(
|
||||||
|
val of1: Double
|
||||||
|
) {
|
||||||
|
val of1Float
|
||||||
|
get() = of1.toFloat()
|
||||||
|
val of100
|
||||||
|
get() = of1 * 100
|
||||||
|
val of100Float
|
||||||
|
get() = of100.toFloat()
|
||||||
|
val of100Int
|
||||||
|
get() = of100.toInt()
|
||||||
|
|
||||||
|
init {
|
||||||
|
require(of1 in rangeOfValues) {
|
||||||
|
"Progress main value should be in $rangeOfValues, but incoming value is $of1"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
val rangeOfValues = 0.0 .. 1.0
|
||||||
|
|
||||||
|
val START = Progress(rangeOfValues.start)
|
||||||
|
val COMPLETED = Progress(rangeOfValues.endInclusive)
|
||||||
|
|
||||||
|
operator fun invoke(of1: Double) = Progress(of1.coerceIn(rangeOfValues))
|
||||||
|
operator fun invoke(part: Number, total: Number) = Progress(
|
||||||
|
part.toDouble() / total.toDouble()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,80 @@
|
|||||||
|
@file:Suppress(
|
||||||
|
"RemoveRedundantCallsOfConversionMethods",
|
||||||
|
"RedundantVisibilityModifier",
|
||||||
|
)
|
||||||
|
|
||||||
|
package dev.inmo.micro_utils.common
|
||||||
|
|
||||||
|
import kotlin.Byte
|
||||||
|
import kotlin.Double
|
||||||
|
import kotlin.Float
|
||||||
|
import kotlin.Int
|
||||||
|
import kotlin.Long
|
||||||
|
import kotlin.Short
|
||||||
|
import kotlin.Suppress
|
||||||
|
|
||||||
|
public operator fun Progress.plus(other: Progress): Progress = Progress(of1 + other.of1)
|
||||||
|
|
||||||
|
public operator fun Progress.minus(other: Progress): Progress = Progress(of1 - other.of1)
|
||||||
|
|
||||||
|
public operator fun Progress.plus(i: Byte): Progress = Progress((of1 + i).toDouble())
|
||||||
|
|
||||||
|
public operator fun Progress.minus(i: Byte): Progress = Progress((of1 - i).toDouble())
|
||||||
|
|
||||||
|
public operator fun Progress.times(i: Byte): Progress = Progress((of1 * i).toDouble())
|
||||||
|
|
||||||
|
public operator fun Progress.div(i: Byte): Progress = Progress((of1 / i).toDouble())
|
||||||
|
|
||||||
|
public operator fun Progress.rem(i: Byte): Progress = Progress((of1 % i).toDouble())
|
||||||
|
|
||||||
|
public operator fun Progress.plus(i: Short): Progress = Progress((of1 + i).toDouble())
|
||||||
|
|
||||||
|
public operator fun Progress.minus(i: Short): Progress = Progress((of1 - i).toDouble())
|
||||||
|
|
||||||
|
public operator fun Progress.times(i: Short): Progress = Progress((of1 * i).toDouble())
|
||||||
|
|
||||||
|
public operator fun Progress.div(i: Short): Progress = Progress((of1 / i).toDouble())
|
||||||
|
|
||||||
|
public operator fun Progress.rem(i: Short): Progress = Progress((of1 % i).toDouble())
|
||||||
|
|
||||||
|
public operator fun Progress.plus(i: Int): Progress = Progress((of1 + i).toDouble())
|
||||||
|
|
||||||
|
public operator fun Progress.minus(i: Int): Progress = Progress((of1 - i).toDouble())
|
||||||
|
|
||||||
|
public operator fun Progress.times(i: Int): Progress = Progress((of1 * i).toDouble())
|
||||||
|
|
||||||
|
public operator fun Progress.div(i: Int): Progress = Progress((of1 / i).toDouble())
|
||||||
|
|
||||||
|
public operator fun Progress.rem(i: Int): Progress = Progress((of1 % i).toDouble())
|
||||||
|
|
||||||
|
public operator fun Progress.plus(i: Long): Progress = Progress((of1 + i).toDouble())
|
||||||
|
|
||||||
|
public operator fun Progress.minus(i: Long): Progress = Progress((of1 - i).toDouble())
|
||||||
|
|
||||||
|
public operator fun Progress.times(i: Long): Progress = Progress((of1 * i).toDouble())
|
||||||
|
|
||||||
|
public operator fun Progress.div(i: Long): Progress = Progress((of1 / i).toDouble())
|
||||||
|
|
||||||
|
public operator fun Progress.rem(i: Long): Progress = Progress((of1 % i).toDouble())
|
||||||
|
|
||||||
|
public operator fun Progress.plus(i: Float): Progress = Progress((of1 + i).toDouble())
|
||||||
|
|
||||||
|
public operator fun Progress.minus(i: Float): Progress = Progress((of1 - i).toDouble())
|
||||||
|
|
||||||
|
public operator fun Progress.times(i: Float): Progress = Progress((of1 * i).toDouble())
|
||||||
|
|
||||||
|
public operator fun Progress.div(i: Float): Progress = Progress((of1 / i).toDouble())
|
||||||
|
|
||||||
|
public operator fun Progress.rem(i: Float): Progress = Progress((of1 % i).toDouble())
|
||||||
|
|
||||||
|
public operator fun Progress.plus(i: Double): Progress = Progress((of1 + i).toDouble())
|
||||||
|
|
||||||
|
public operator fun Progress.minus(i: Double): Progress = Progress((of1 - i).toDouble())
|
||||||
|
|
||||||
|
public operator fun Progress.times(i: Double): Progress = Progress((of1 * i).toDouble())
|
||||||
|
|
||||||
|
public operator fun Progress.div(i: Double): Progress = Progress((of1 / i).toDouble())
|
||||||
|
|
||||||
|
public operator fun Progress.rem(i: Double): Progress = Progress((of1 % i).toDouble())
|
||||||
|
|
||||||
|
public operator fun Progress.compareTo(other: Progress): Int = (of1 - other.of1).toInt()
|
@@ -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()
|
||||||
|
}
|
@@ -14,5 +14,5 @@ crypto_js_version=4.1.1
|
|||||||
# Project data
|
# Project data
|
||||||
|
|
||||||
group=dev.inmo
|
group=dev.inmo
|
||||||
version=0.14.0
|
version=0.14.4
|
||||||
android_code_version=161
|
android_code_version=165
|
||||||
|
@@ -5,11 +5,11 @@ kt-serialization = "1.4.1"
|
|||||||
kt-coroutines = "1.6.4"
|
kt-coroutines = "1.6.4"
|
||||||
|
|
||||||
jb-compose = "1.2.1"
|
jb-compose = "1.2.1"
|
||||||
jb-exposed = "0.40.1"
|
jb-exposed = "0.41.1"
|
||||||
jb-dokka = "1.7.20"
|
jb-dokka = "1.7.20"
|
||||||
|
|
||||||
klock = "3.3.1"
|
klock = "3.4.0"
|
||||||
uuid = "0.5.0"
|
uuid = "0.6.0"
|
||||||
|
|
||||||
ktor = "2.1.3"
|
ktor = "2.1.3"
|
||||||
|
|
||||||
|
@@ -15,5 +15,9 @@ kotlin {
|
|||||||
api libs.ktor.client
|
api libs.ktor.client
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
androidMain {
|
||||||
|
dependsOn jvmMain
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -0,0 +1,3 @@
|
|||||||
|
package dev.inmo.micro_utils.ktor.client
|
||||||
|
|
||||||
|
typealias OnUploadCallback = suspend (uploaded: Long, count: Long) -> Unit
|
@@ -7,5 +7,5 @@ import io.ktor.client.HttpClient
|
|||||||
expect suspend fun HttpClient.tempUpload(
|
expect suspend fun HttpClient.tempUpload(
|
||||||
fullTempUploadDraftPath: String,
|
fullTempUploadDraftPath: String,
|
||||||
file: MPPFile,
|
file: MPPFile,
|
||||||
onUpload: (uploaded: Long, count: Long) -> Unit = { _, _ -> }
|
onUpload: OnUploadCallback = { _, _ -> }
|
||||||
): TemporalFileId
|
): TemporalFileId
|
||||||
|
@@ -0,0 +1,105 @@
|
|||||||
|
package dev.inmo.micro_utils.ktor.client
|
||||||
|
|
||||||
|
import dev.inmo.micro_utils.common.FileName
|
||||||
|
import dev.inmo.micro_utils.common.MPPFile
|
||||||
|
import dev.inmo.micro_utils.ktor.common.LambdaInputProvider
|
||||||
|
import io.ktor.client.HttpClient
|
||||||
|
import io.ktor.http.Headers
|
||||||
|
import io.ktor.utils.io.core.Input
|
||||||
|
import kotlinx.serialization.DeserializationStrategy
|
||||||
|
import kotlinx.serialization.StringFormat
|
||||||
|
import kotlinx.serialization.json.Json
|
||||||
|
|
||||||
|
data class UniUploadFileInfo(
|
||||||
|
val fileName: FileName,
|
||||||
|
val mimeType: String,
|
||||||
|
val inputAllocator: LambdaInputProvider
|
||||||
|
)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Will execute submitting of multipart data request
|
||||||
|
*
|
||||||
|
* @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
|
||||||
|
* 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(
|
||||||
|
url: String,
|
||||||
|
data: Map<String, Any>,
|
||||||
|
resultDeserializer: DeserializationStrategy<T>,
|
||||||
|
headers: Headers = Headers.Empty,
|
||||||
|
stringFormat: StringFormat = Json,
|
||||||
|
onUpload: OnUploadCallback = { _, _ -> }
|
||||||
|
): 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
|
||||||
|
)
|
@@ -1,6 +1,8 @@
|
|||||||
package dev.inmo.micro_utils.ktor.client
|
package dev.inmo.micro_utils.ktor.client
|
||||||
|
|
||||||
import dev.inmo.micro_utils.common.MPPFile
|
import dev.inmo.micro_utils.common.MPPFile
|
||||||
|
import dev.inmo.micro_utils.coroutines.LinkedSupervisorJob
|
||||||
|
import dev.inmo.micro_utils.coroutines.launchSafelyWithoutExceptions
|
||||||
import dev.inmo.micro_utils.ktor.common.TemporalFileId
|
import dev.inmo.micro_utils.ktor.common.TemporalFileId
|
||||||
import io.ktor.client.HttpClient
|
import io.ktor.client.HttpClient
|
||||||
import kotlinx.coroutines.*
|
import kotlinx.coroutines.*
|
||||||
@@ -12,10 +14,11 @@ import org.w3c.xhr.XMLHttpRequest.Companion.DONE
|
|||||||
suspend fun tempUpload(
|
suspend fun tempUpload(
|
||||||
fullTempUploadDraftPath: String,
|
fullTempUploadDraftPath: String,
|
||||||
file: MPPFile,
|
file: MPPFile,
|
||||||
onUpload: (Long, Long) -> Unit
|
onUpload: OnUploadCallback
|
||||||
): TemporalFileId {
|
): TemporalFileId {
|
||||||
val formData = FormData()
|
val formData = FormData()
|
||||||
val answer = CompletableDeferred<TemporalFileId>(currentCoroutineContext().job)
|
val answer = CompletableDeferred<TemporalFileId>(currentCoroutineContext().job)
|
||||||
|
val subscope = CoroutineScope(currentCoroutineContext().LinkedSupervisorJob())
|
||||||
|
|
||||||
formData.append(
|
formData.append(
|
||||||
"data",
|
"data",
|
||||||
@@ -25,7 +28,7 @@ suspend fun tempUpload(
|
|||||||
val request = XMLHttpRequest()
|
val request = XMLHttpRequest()
|
||||||
request.responseType = XMLHttpRequestResponseType.TEXT
|
request.responseType = XMLHttpRequestResponseType.TEXT
|
||||||
request.upload.onprogress = {
|
request.upload.onprogress = {
|
||||||
onUpload(it.loaded.toLong(), it.total.toLong())
|
subscope.launchSafelyWithoutExceptions { onUpload(it.loaded.toLong(), it.total.toLong()) }
|
||||||
}
|
}
|
||||||
request.onload = {
|
request.onload = {
|
||||||
if (request.status == 200.toShort()) {
|
if (request.status == 200.toShort()) {
|
||||||
@@ -48,12 +51,14 @@ suspend fun tempUpload(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return answer.await()
|
return answer.await().also {
|
||||||
|
subscope.cancel()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
actual suspend fun HttpClient.tempUpload(
|
actual suspend fun HttpClient.tempUpload(
|
||||||
fullTempUploadDraftPath: String,
|
fullTempUploadDraftPath: String,
|
||||||
file: MPPFile,
|
file: MPPFile,
|
||||||
onUpload: (uploaded: Long, count: Long) -> Unit
|
onUpload: OnUploadCallback
|
||||||
): TemporalFileId = dev.inmo.micro_utils.ktor.client.tempUpload(fullTempUploadDraftPath, file, onUpload)
|
): TemporalFileId = dev.inmo.micro_utils.ktor.client.tempUpload(fullTempUploadDraftPath, file, onUpload)
|
||||||
|
@@ -0,0 +1,96 @@
|
|||||||
|
package dev.inmo.micro_utils.ktor.client
|
||||||
|
|
||||||
|
import dev.inmo.micro_utils.common.MPPFile
|
||||||
|
import dev.inmo.micro_utils.common.Progress
|
||||||
|
import dev.inmo.micro_utils.coroutines.LinkedSupervisorJob
|
||||||
|
import dev.inmo.micro_utils.coroutines.launchSafelyWithoutExceptions
|
||||||
|
import io.ktor.client.HttpClient
|
||||||
|
import io.ktor.http.Headers
|
||||||
|
import io.ktor.utils.io.core.readBytes
|
||||||
|
import kotlinx.coroutines.CompletableDeferred
|
||||||
|
import kotlinx.coroutines.CoroutineScope
|
||||||
|
import kotlinx.coroutines.cancel
|
||||||
|
import kotlinx.coroutines.currentCoroutineContext
|
||||||
|
import kotlinx.coroutines.job
|
||||||
|
import kotlinx.serialization.DeserializationStrategy
|
||||||
|
import kotlinx.serialization.StringFormat
|
||||||
|
import kotlinx.serialization.encodeToString
|
||||||
|
import org.khronos.webgl.Int8Array
|
||||||
|
import org.w3c.files.Blob
|
||||||
|
import org.w3c.xhr.FormData
|
||||||
|
import org.w3c.xhr.TEXT
|
||||||
|
import org.w3c.xhr.XMLHttpRequest
|
||||||
|
import org.w3c.xhr.XMLHttpRequestResponseType
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Will execute submitting of multipart data request
|
||||||
|
*
|
||||||
|
* @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
|
||||||
|
* in case you wish to pass other source of multipart binary data than regular file
|
||||||
|
*/
|
||||||
|
actual suspend fun <T> HttpClient.uniUpload(
|
||||||
|
url: String,
|
||||||
|
data: Map<String, Any>,
|
||||||
|
resultDeserializer: DeserializationStrategy<T>,
|
||||||
|
headers: Headers,
|
||||||
|
stringFormat: StringFormat,
|
||||||
|
onUpload: OnUploadCallback
|
||||||
|
): T? {
|
||||||
|
val formData = FormData()
|
||||||
|
val answer = CompletableDeferred<T?>(currentCoroutineContext().job)
|
||||||
|
val subscope = CoroutineScope(currentCoroutineContext().LinkedSupervisorJob())
|
||||||
|
|
||||||
|
data.forEach { (k, v) ->
|
||||||
|
when (v) {
|
||||||
|
is MPPFile -> formData.append(
|
||||||
|
k,
|
||||||
|
v
|
||||||
|
)
|
||||||
|
is UniUploadFileInfo -> formData.append(
|
||||||
|
k,
|
||||||
|
Blob(arrayOf(Int8Array(v.inputAllocator().readBytes().toTypedArray()))),
|
||||||
|
v.fileName.name
|
||||||
|
)
|
||||||
|
else -> formData.append(
|
||||||
|
k,
|
||||||
|
stringFormat.encodeToString(v)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val request = XMLHttpRequest()
|
||||||
|
headers.forEach { s, strings ->
|
||||||
|
request.setRequestHeader(s, strings.joinToString())
|
||||||
|
}
|
||||||
|
request.responseType = XMLHttpRequestResponseType.TEXT
|
||||||
|
request.upload.onprogress = {
|
||||||
|
subscope.launchSafelyWithoutExceptions { onUpload(it.loaded.toLong(), it.total.toLong()) }
|
||||||
|
}
|
||||||
|
request.onload = {
|
||||||
|
if (request.status == 200.toShort()) {
|
||||||
|
answer.complete(
|
||||||
|
stringFormat.decodeFromString(resultDeserializer, request.responseText)
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
answer.completeExceptionally(Exception("Something went wrong: $it"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
request.onerror = {
|
||||||
|
answer.completeExceptionally(Exception("Something went wrong: $it"))
|
||||||
|
}
|
||||||
|
request.open("POST", url, true)
|
||||||
|
request.send(formData)
|
||||||
|
|
||||||
|
answer.invokeOnCompletion {
|
||||||
|
runCatching {
|
||||||
|
if (request.readyState != XMLHttpRequest.DONE) {
|
||||||
|
request.abort()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return answer.await().also {
|
||||||
|
subscope.cancel()
|
||||||
|
}
|
||||||
|
}
|
@@ -4,6 +4,8 @@ import dev.inmo.micro_utils.common.MPPFile
|
|||||||
import io.ktor.client.request.forms.InputProvider
|
import io.ktor.client.request.forms.InputProvider
|
||||||
import io.ktor.utils.io.streams.asInput
|
import io.ktor.utils.io.streams.asInput
|
||||||
|
|
||||||
actual suspend fun MPPFile.inputProvider(): InputProvider = InputProvider(length()) {
|
fun MPPFile.inputProviderSync(): InputProvider = InputProvider(length()) {
|
||||||
inputStream().asInput()
|
inputStream().asInput()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
actual suspend fun MPPFile.inputProvider(): InputProvider = inputProviderSync()
|
||||||
|
@@ -18,7 +18,7 @@ internal val MPPFile.mimeType: String
|
|||||||
actual suspend fun HttpClient.tempUpload(
|
actual suspend fun HttpClient.tempUpload(
|
||||||
fullTempUploadDraftPath: String,
|
fullTempUploadDraftPath: String,
|
||||||
file: MPPFile,
|
file: MPPFile,
|
||||||
onUpload: (Long, Long) -> Unit
|
onUpload: OnUploadCallback
|
||||||
): TemporalFileId {
|
): TemporalFileId {
|
||||||
val inputProvider = file.inputProvider()
|
val inputProvider = file.inputProvider()
|
||||||
val fileId = submitFormWithBinaryData(
|
val fileId = submitFormWithBinaryData(
|
||||||
|
@@ -0,0 +1,101 @@
|
|||||||
|
package dev.inmo.micro_utils.ktor.client
|
||||||
|
|
||||||
|
import dev.inmo.micro_utils.common.Progress
|
||||||
|
import io.ktor.client.HttpClient
|
||||||
|
import io.ktor.client.engine.mergeHeaders
|
||||||
|
import io.ktor.client.plugins.onUpload
|
||||||
|
import io.ktor.client.request.HttpRequestBuilder
|
||||||
|
import io.ktor.client.request.forms.InputProvider
|
||||||
|
import io.ktor.client.request.forms.formData
|
||||||
|
import io.ktor.client.request.forms.submitForm
|
||||||
|
import io.ktor.client.request.forms.submitFormWithBinaryData
|
||||||
|
import io.ktor.client.request.headers
|
||||||
|
import io.ktor.client.statement.bodyAsText
|
||||||
|
import io.ktor.http.Headers
|
||||||
|
import io.ktor.http.HttpHeaders
|
||||||
|
import io.ktor.http.HttpStatusCode
|
||||||
|
import io.ktor.http.Parameters
|
||||||
|
import io.ktor.http.content.PartData
|
||||||
|
import kotlinx.serialization.DeserializationStrategy
|
||||||
|
import kotlinx.serialization.StringFormat
|
||||||
|
import kotlinx.serialization.encodeToString
|
||||||
|
import java.io.File
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Will execute submitting of multipart data request
|
||||||
|
*
|
||||||
|
* @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
|
||||||
|
* in case you wish to pass other source of multipart binary data than regular file
|
||||||
|
*/
|
||||||
|
actual suspend fun <T> HttpClient.uniUpload(
|
||||||
|
url: String,
|
||||||
|
data: Map<String, Any>,
|
||||||
|
resultDeserializer: DeserializationStrategy<T>,
|
||||||
|
headers: Headers,
|
||||||
|
stringFormat: StringFormat,
|
||||||
|
onUpload: OnUploadCallback
|
||||||
|
): T? {
|
||||||
|
val withBinary = data.values.any { it is File || it is UniUploadFileInfo }
|
||||||
|
|
||||||
|
val formData = formData {
|
||||||
|
data.forEach { (k, v) ->
|
||||||
|
when (v) {
|
||||||
|
is File -> append(
|
||||||
|
k,
|
||||||
|
v.inputProviderSync(),
|
||||||
|
Headers.build {
|
||||||
|
append(HttpHeaders.ContentType, v.mimeType)
|
||||||
|
append(HttpHeaders.ContentDisposition, "filename=\"${v.name}\"")
|
||||||
|
}
|
||||||
|
)
|
||||||
|
is UniUploadFileInfo -> append(
|
||||||
|
k,
|
||||||
|
InputProvider(block = v.inputAllocator),
|
||||||
|
Headers.build {
|
||||||
|
append(HttpHeaders.ContentType, v.mimeType)
|
||||||
|
append(HttpHeaders.ContentDisposition, "filename=\"${v.fileName.name}\"")
|
||||||
|
}
|
||||||
|
)
|
||||||
|
else -> append(
|
||||||
|
k,
|
||||||
|
stringFormat.encodeToString(v)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val requestBuilder: HttpRequestBuilder.() -> Unit = {
|
||||||
|
headers {
|
||||||
|
appendAll(headers)
|
||||||
|
}
|
||||||
|
onUpload { bytesSentTotal, contentLength ->
|
||||||
|
onUpload(bytesSentTotal, contentLength)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val response = if (withBinary) {
|
||||||
|
submitFormWithBinaryData(
|
||||||
|
url,
|
||||||
|
formData,
|
||||||
|
block = requestBuilder
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
submitForm(
|
||||||
|
url,
|
||||||
|
Parameters.build {
|
||||||
|
formData.forEach {
|
||||||
|
val formItem = (it as PartData.FormItem)
|
||||||
|
append(it.name!!, it.value)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
block = requestBuilder
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
return if (response.status == HttpStatusCode.OK) {
|
||||||
|
stringFormat.decodeFromString(resultDeserializer, response.bodyAsText())
|
||||||
|
} else {
|
||||||
|
null
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,5 @@
|
|||||||
|
package dev.inmo.micro_utils.ktor.common
|
||||||
|
|
||||||
|
import io.ktor.utils.io.core.Input
|
||||||
|
|
||||||
|
typealias LambdaInputProvider = () -> Input
|
@@ -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()
|
||||||
|
}
|
@@ -0,0 +1,56 @@
|
|||||||
|
package dev.inmo.micro_utils.ktor.server
|
||||||
|
|
||||||
|
import com.benasher44.uuid.uuid4
|
||||||
|
import io.ktor.http.content.PartData
|
||||||
|
import io.ktor.utils.io.copyTo
|
||||||
|
import io.ktor.utils.io.core.copyTo
|
||||||
|
import io.ktor.utils.io.jvm.javaio.copyTo
|
||||||
|
import io.ktor.utils.io.streams.asOutput
|
||||||
|
import java.io.File
|
||||||
|
|
||||||
|
fun PartData.FileItem.download(target: File) {
|
||||||
|
provider().use { input ->
|
||||||
|
target.outputStream().use {
|
||||||
|
input.copyTo(it.asOutput())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun PartData.FileItem.downloadToTemporalFile(): File {
|
||||||
|
val outputFile = File.createTempFile(uuid4().toString(), ".temp").apply {
|
||||||
|
deleteOnExit()
|
||||||
|
}
|
||||||
|
download(outputFile)
|
||||||
|
return outputFile
|
||||||
|
}
|
||||||
|
|
||||||
|
fun PartData.BinaryItem.download(target: File) {
|
||||||
|
provider().use { input ->
|
||||||
|
target.outputStream().use {
|
||||||
|
input.copyTo(it.asOutput())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun PartData.BinaryItem.downloadToTemporalFile(): File {
|
||||||
|
val outputFile = File.createTempFile(uuid4().toString(), ".temp").apply {
|
||||||
|
deleteOnExit()
|
||||||
|
}
|
||||||
|
download(outputFile)
|
||||||
|
return outputFile
|
||||||
|
}
|
||||||
|
|
||||||
|
suspend fun PartData.BinaryChannelItem.download(target: File) {
|
||||||
|
val input = provider()
|
||||||
|
target.outputStream().use {
|
||||||
|
input.copyTo(it)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
suspend fun PartData.BinaryChannelItem.downloadToTemporalFile(): File {
|
||||||
|
val outputFile = File.createTempFile(uuid4().toString(), ".temp").apply {
|
||||||
|
deleteOnExit()
|
||||||
|
}
|
||||||
|
download(outputFile)
|
||||||
|
return outputFile
|
||||||
|
}
|
@@ -0,0 +1,25 @@
|
|||||||
|
package dev.inmo.micro_utils.ktor.server
|
||||||
|
|
||||||
|
import io.ktor.http.HttpStatusCode
|
||||||
|
import io.ktor.server.application.ApplicationCall
|
||||||
|
import io.ktor.server.response.respond
|
||||||
|
|
||||||
|
suspend fun ApplicationCall.getParameterOrSendError(
|
||||||
|
field: String
|
||||||
|
) = parameters[field].also {
|
||||||
|
if (it == null) {
|
||||||
|
respond(HttpStatusCode.BadRequest, "Request must contains $field")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun ApplicationCall.getQueryParameter(
|
||||||
|
field: String
|
||||||
|
) = request.queryParameters[field]
|
||||||
|
|
||||||
|
suspend fun ApplicationCall.getQueryParameterOrSendError(
|
||||||
|
field: String
|
||||||
|
) = getQueryParameter(field).also {
|
||||||
|
if (it == null) {
|
||||||
|
respond(HttpStatusCode.BadRequest, "Request query parameters must contains $field")
|
||||||
|
}
|
||||||
|
}
|
@@ -1,111 +0,0 @@
|
|||||||
package dev.inmo.micro_utils.ktor.server
|
|
||||||
|
|
||||||
import dev.inmo.micro_utils.common.*
|
|
||||||
import dev.inmo.micro_utils.coroutines.safely
|
|
||||||
import dev.inmo.micro_utils.ktor.common.*
|
|
||||||
import io.ktor.http.*
|
|
||||||
import io.ktor.http.content.*
|
|
||||||
import io.ktor.server.application.ApplicationCall
|
|
||||||
import io.ktor.server.application.call
|
|
||||||
import io.ktor.server.request.receive
|
|
||||||
import io.ktor.server.request.receiveMultipart
|
|
||||||
import io.ktor.server.response.respond
|
|
||||||
import io.ktor.server.response.respondBytes
|
|
||||||
import io.ktor.server.routing.Route
|
|
||||||
import io.ktor.server.websocket.WebSocketServerSession
|
|
||||||
import io.ktor.util.pipeline.PipelineContext
|
|
||||||
import io.ktor.utils.io.core.*
|
|
||||||
import kotlinx.coroutines.flow.Flow
|
|
||||||
import kotlinx.serialization.DeserializationStrategy
|
|
||||||
import kotlinx.serialization.SerializationStrategy
|
|
||||||
|
|
||||||
suspend fun ApplicationCall.uniloadMultipart(
|
|
||||||
onFormItem: (PartData.FormItem) -> Unit = {},
|
|
||||||
onCustomFileItem: (PartData.FileItem) -> Unit = {},
|
|
||||||
onBinaryChannelItem: (PartData.BinaryChannelItem) -> Unit = {},
|
|
||||||
onBinaryContent: (PartData.BinaryItem) -> Unit = {}
|
|
||||||
) = safely {
|
|
||||||
val multipartData = receiveMultipart()
|
|
||||||
|
|
||||||
var resultInput: Input? = null
|
|
||||||
|
|
||||||
multipartData.forEachPart {
|
|
||||||
when (it) {
|
|
||||||
is PartData.FormItem -> onFormItem(it)
|
|
||||||
is PartData.FileItem -> {
|
|
||||||
when (it.name) {
|
|
||||||
"bytes" -> resultInput = it.provider()
|
|
||||||
else -> onCustomFileItem(it)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
is PartData.BinaryItem -> onBinaryContent(it)
|
|
||||||
is PartData.BinaryChannelItem -> onBinaryChannelItem(it)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
resultInput ?: error("Bytes has not been received")
|
|
||||||
}
|
|
||||||
|
|
||||||
suspend fun ApplicationCall.uniloadMultipartFile(
|
|
||||||
onFormItem: (PartData.FormItem) -> Unit = {},
|
|
||||||
onCustomFileItem: (PartData.FileItem) -> Unit = {},
|
|
||||||
onBinaryChannelItem: (PartData.BinaryChannelItem) -> Unit = {},
|
|
||||||
onBinaryContent: (PartData.BinaryItem) -> Unit = {},
|
|
||||||
) = safely {
|
|
||||||
val multipartData = receiveMultipart()
|
|
||||||
|
|
||||||
var resultInput: MPPFile? = null
|
|
||||||
|
|
||||||
multipartData.forEachPart {
|
|
||||||
when (it) {
|
|
||||||
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")
|
|
||||||
}
|
|
||||||
|
|
||||||
suspend fun ApplicationCall.getParameterOrSendError(
|
|
||||||
field: String
|
|
||||||
) = parameters[field].also {
|
|
||||||
if (it == null) {
|
|
||||||
respond(HttpStatusCode.BadRequest, "Request must contains $field")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun ApplicationCall.getQueryParameter(
|
|
||||||
field: String
|
|
||||||
) = request.queryParameters[field]
|
|
||||||
|
|
||||||
suspend fun ApplicationCall.getQueryParameterOrSendError(
|
|
||||||
field: String
|
|
||||||
) = getQueryParameter(field).also {
|
|
||||||
if (it == null) {
|
|
||||||
respond(HttpStatusCode.BadRequest, "Request query parameters must contains $field")
|
|
||||||
}
|
|
||||||
}
|
|
@@ -0,0 +1,70 @@
|
|||||||
|
package dev.inmo.micro_utils.ktor.server
|
||||||
|
|
||||||
|
import dev.inmo.micro_utils.common.*
|
||||||
|
import dev.inmo.micro_utils.coroutines.safely
|
||||||
|
import dev.inmo.micro_utils.ktor.common.downloadToTempFile
|
||||||
|
import io.ktor.http.content.*
|
||||||
|
import io.ktor.server.application.ApplicationCall
|
||||||
|
import io.ktor.server.request.receiveMultipart
|
||||||
|
import io.ktor.utils.io.core.*
|
||||||
|
import kotlinx.coroutines.currentCoroutineContext
|
||||||
|
import kotlinx.coroutines.isActive
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Server-side part which receives [dev.inmo.micro_utils.ktor.client.uniUpload] request
|
||||||
|
*/
|
||||||
|
suspend inline fun ApplicationCall.handleUniUpload(
|
||||||
|
onFormItem: (PartData.FormItem) -> Unit = {},
|
||||||
|
onBinaryContent: (PartData.BinaryItem) -> Unit = {},
|
||||||
|
onBinaryChannelItem: (PartData.BinaryChannelItem) -> Unit = {},
|
||||||
|
onFileItem: (PartData.FileItem) -> Unit = {}
|
||||||
|
) {
|
||||||
|
val multipartData = receiveMultipart()
|
||||||
|
|
||||||
|
while (currentCoroutineContext().isActive) {
|
||||||
|
val partData = multipartData.readPart() ?: break
|
||||||
|
when (partData) {
|
||||||
|
is PartData.FormItem -> onFormItem(partData)
|
||||||
|
is PartData.FileItem -> onFileItem(partData)
|
||||||
|
is PartData.BinaryItem -> onBinaryContent(partData)
|
||||||
|
is PartData.BinaryChannelItem -> onBinaryChannelItem(partData)
|
||||||
|
}
|
||||||
|
partData.dispose()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
suspend fun ApplicationCall.uniloadMultipart(
|
||||||
|
onFormItem: (PartData.FormItem) -> Unit = {},
|
||||||
|
onCustomFileItem: (PartData.FileItem) -> Unit = {},
|
||||||
|
onBinaryChannelItem: (PartData.BinaryChannelItem) -> Unit = {},
|
||||||
|
onBinaryContent: (PartData.BinaryItem) -> Unit = {}
|
||||||
|
): Input = safely {
|
||||||
|
var resultInput: Input? = null
|
||||||
|
|
||||||
|
handleUniUpload(
|
||||||
|
onFormItem,
|
||||||
|
onBinaryContent,
|
||||||
|
onBinaryChannelItem
|
||||||
|
) {
|
||||||
|
when (it.name) {
|
||||||
|
"bytes" -> resultInput = it.provider()
|
||||||
|
else -> onCustomFileItem(it)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
resultInput ?: error("Bytes has not been received")
|
||||||
|
}
|
||||||
|
|
||||||
|
suspend fun ApplicationCall.uniloadMultipartFile(
|
||||||
|
onFormItem: (PartData.FormItem) -> Unit = {},
|
||||||
|
onCustomFileItem: (PartData.FileItem) -> Unit = {},
|
||||||
|
onBinaryChannelItem: (PartData.BinaryChannelItem) -> Unit = {},
|
||||||
|
onBinaryContent: (PartData.BinaryItem) -> Unit = {},
|
||||||
|
): MPPFile = safely {
|
||||||
|
uniloadMultipart(
|
||||||
|
onFormItem,
|
||||||
|
onCustomFileItem,
|
||||||
|
onBinaryChannelItem,
|
||||||
|
onBinaryContent
|
||||||
|
).downloadToTempFile()
|
||||||
|
}
|
@@ -19,29 +19,29 @@ publishing {
|
|||||||
}
|
}
|
||||||
|
|
||||||
developers {
|
developers {
|
||||||
|
|
||||||
developer {
|
developer {
|
||||||
id = "InsanusMokrassar"
|
id = "InsanusMokrassar"
|
||||||
name = "Aleksei Ovsiannikov"
|
name = "Aleksei Ovsiannikov"
|
||||||
email = "ovsyannikov.alexey95@gmail.com"
|
email = "ovsyannikov.alexey95@gmail.com"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
developer {
|
developer {
|
||||||
id = "000Sanya"
|
id = "000Sanya"
|
||||||
name = "Syrov Aleksandr"
|
name = "Syrov Aleksandr"
|
||||||
email = "000sanya.000sanya@gmail.com"
|
email = "000sanya.000sanya@gmail.com"
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
licenses {
|
licenses {
|
||||||
|
|
||||||
license {
|
license {
|
||||||
name = "Apache Software License 2.0"
|
name = "Apache Software License 2.0"
|
||||||
url = "https://github.com/InsanusMokrassar/MicroUtils/blob/master/LICENSE"
|
url = "https://github.com/InsanusMokrassar/MicroUtils/blob/master/LICENSE"
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
repositories {
|
repositories {
|
||||||
@@ -49,35 +49,54 @@ publishing {
|
|||||||
maven {
|
maven {
|
||||||
name = "GithubPackages"
|
name = "GithubPackages"
|
||||||
url = uri("https://maven.pkg.github.com/InsanusMokrassar/MicroUtils")
|
url = uri("https://maven.pkg.github.com/InsanusMokrassar/MicroUtils")
|
||||||
|
|
||||||
credentials {
|
credentials {
|
||||||
username = project.hasProperty('GITHUBPACKAGES_USER') ? project.property('GITHUBPACKAGES_USER') : System.getenv('GITHUBPACKAGES_USER')
|
username = project.hasProperty('GITHUBPACKAGES_USER') ? project.property('GITHUBPACKAGES_USER') : System.getenv('GITHUBPACKAGES_USER')
|
||||||
password = project.hasProperty('GITHUBPACKAGES_PASSWORD') ? project.property('GITHUBPACKAGES_PASSWORD') : System.getenv('GITHUBPACKAGES_PASSWORD')
|
password = project.hasProperty('GITHUBPACKAGES_PASSWORD') ? project.property('GITHUBPACKAGES_PASSWORD') : System.getenv('GITHUBPACKAGES_PASSWORD')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (project.hasProperty('GITEA_TOKEN') || System.getenv('GITEA_TOKEN') != null) {
|
||||||
|
maven {
|
||||||
|
name = "Gitea"
|
||||||
|
url = uri("https://git.inmo.dev/api/packages/InsanusMokrassar/maven")
|
||||||
|
|
||||||
|
credentials(HttpHeaderCredentials) {
|
||||||
|
name = "Authorization"
|
||||||
|
value = project.hasProperty('GITEA_TOKEN') ? project.property('GITEA_TOKEN') : System.getenv('GITEA_TOKEN')
|
||||||
|
}
|
||||||
|
|
||||||
|
authentication {
|
||||||
|
header(HttpHeaderAuthentication)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ((project.hasProperty('SONATYPE_USER') || System.getenv('SONATYPE_USER') != null) && (project.hasProperty('SONATYPE_PASSWORD') || System.getenv('SONATYPE_PASSWORD') != null)) {
|
if ((project.hasProperty('SONATYPE_USER') || System.getenv('SONATYPE_USER') != null) && (project.hasProperty('SONATYPE_PASSWORD') || System.getenv('SONATYPE_PASSWORD') != null)) {
|
||||||
maven {
|
maven {
|
||||||
name = "sonatype"
|
name = "sonatype"
|
||||||
url = uri("https://oss.sonatype.org/service/local/staging/deploy/maven2/")
|
url = uri("https://oss.sonatype.org/service/local/staging/deploy/maven2/")
|
||||||
|
|
||||||
credentials {
|
credentials {
|
||||||
username = project.hasProperty('SONATYPE_USER') ? project.property('SONATYPE_USER') : System.getenv('SONATYPE_USER')
|
username = project.hasProperty('SONATYPE_USER') ? project.property('SONATYPE_USER') : System.getenv('SONATYPE_USER')
|
||||||
password = project.hasProperty('SONATYPE_PASSWORD') ? project.property('SONATYPE_PASSWORD') : System.getenv('SONATYPE_PASSWORD')
|
password = project.hasProperty('SONATYPE_PASSWORD') ? project.property('SONATYPE_PASSWORD') : System.getenv('SONATYPE_PASSWORD')
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (project.hasProperty("signing.gnupg.keyName")) {
|
if (project.hasProperty("signing.gnupg.keyName")) {
|
||||||
apply plugin: 'signing'
|
apply plugin: 'signing'
|
||||||
|
|
||||||
signing {
|
signing {
|
||||||
useGpgCmd()
|
useGpgCmd()
|
||||||
|
|
||||||
sign publishing.publications
|
sign publishing.publications
|
||||||
}
|
}
|
||||||
|
|
||||||
task signAll {
|
task signAll {
|
||||||
tasks.withType(Sign).forEach {
|
tasks.withType(Sign).forEach {
|
||||||
dependsOn(it)
|
dependsOn(it)
|
||||||
|
@@ -1 +1 @@
|
|||||||
{"licenses":[{"id":"Apache-2.0","title":"Apache Software License 2.0","url":"https://github.com/InsanusMokrassar/MicroUtils/blob/master/LICENSE"}],"mavenConfig":{"name":"${project.name}","description":"It is set of projects with micro tools for avoiding of routines coding","url":"https://github.com/InsanusMokrassar/MicroUtils/","vcsUrl":"https://github.com/InsanusMokrassar/MicroUtils.git","developers":[{"id":"InsanusMokrassar","name":"Aleksei Ovsiannikov","eMail":"ovsyannikov.alexey95@gmail.com"},{"id":"000Sanya","name":"Syrov Aleksandr","eMail":"000sanya.000sanya@gmail.com"}],"repositories":[{"name":"GithubPackages","url":"https://maven.pkg.github.com/InsanusMokrassar/MicroUtils"},{"name":"sonatype","url":"https://oss.sonatype.org/service/local/staging/deploy/maven2/"}],"gpgSigning":{"type":"dev.inmo.kmppscriptbuilder.core.models.GpgSigning.Optional"}}}
|
{"licenses":[{"id":"Apache-2.0","title":"Apache Software License 2.0","url":"https://github.com/InsanusMokrassar/MicroUtils/blob/master/LICENSE"}],"mavenConfig":{"name":"${project.name}","description":"It is set of projects with micro tools for avoiding of routines coding","url":"https://github.com/InsanusMokrassar/MicroUtils/","vcsUrl":"https://github.com/InsanusMokrassar/MicroUtils.git","developers":[{"id":"InsanusMokrassar","name":"Aleksei Ovsiannikov","eMail":"ovsyannikov.alexey95@gmail.com"},{"id":"000Sanya","name":"Syrov Aleksandr","eMail":"000sanya.000sanya@gmail.com"}],"repositories":[{"name":"GithubPackages","url":"https://maven.pkg.github.com/InsanusMokrassar/MicroUtils"},{"name":"Gitea","url":"https://git.inmo.dev/api/packages/InsanusMokrassar/maven","credsType":{"type":"dev.inmo.kmppscriptbuilder.core.models.MavenPublishingRepository.CredentialsType.HttpHeaderCredentials","headerName":"Authorization","headerValueProperty":"GITEA_TOKEN"}},{"name":"sonatype","url":"https://oss.sonatype.org/service/local/staging/deploy/maven2/"}],"gpgSigning":{"type":"dev.inmo.kmppscriptbuilder.core.models.GpgSigning.Optional"}}}
|
@@ -28,6 +28,7 @@ kotlin {
|
|||||||
api internalProject("micro_utils.common")
|
api internalProject("micro_utils.common")
|
||||||
api internalProject("micro_utils.coroutines")
|
api internalProject("micro_utils.coroutines")
|
||||||
}
|
}
|
||||||
|
dependsOn jvmMain
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user