Compare commits

..

81 Commits

Author SHA1 Message Date
03f527d83e Update CHANGELOG.md 2022-12-09 19:46:58 +06:00
ced05a4586 improve default runCatchingSafely/safelyWithResult and add suspend variances of safe/unsafe SafeWrapper interface 2022-12-09 12:14:24 +06:00
43fe06206a add safe wrapper 2022-12-09 11:09:32 +06:00
023657558e start 0.16.1 2022-12-09 10:52:53 +06:00
9b0b726c80 Merge pull request #210 from InsanusMokrassar/0.16.0
0.16.0
2022-12-08 09:29:12 +06:00
4ee67321c4 fill changelog and update android dependencies 2022-12-08 09:26:59 +06:00
59f1f2e59b Update libs.versions.toml 2022-12-08 08:53:37 +06:00
0766d48b7c Update libs.versions.toml 2022-12-08 07:56:04 +06:00
e18903b9e9 Update gradle.properties 2022-12-08 07:54:53 +06:00
d0eecdead2 Update gradle.properties 2022-12-08 07:53:59 +06:00
cc4a83a033 Update gradle.properties 2022-12-08 07:53:08 +06:00
1cf911bbde Update build.gradle 2022-12-07 19:40:30 +06:00
36d73d5023 Update StartupLaunchingTests.kt 2022-12-07 11:39:45 +06:00
c395242e3e fixes in StartupLauncingTests 2022-12-07 10:50:51 +06:00
cd9cd7cc5d Merge pull request #208 from InsanusMokrassar/0.15.1
0.15.1
2022-12-07 09:43:48 +06:00
acbb8a0c07 complete prepare startup module 2022-12-06 13:15:08 +06:00
b9d8528599 complete kdocs for the startup module 2022-12-06 13:14:05 +06:00
4971326eca add kdocs for the config of startup 2022-12-06 13:08:37 +06:00
09d1047260 add kdocs to the startup module 2022-12-06 13:06:21 +06:00
02dbd493c2 add tests and make several replacements/improvements 2022-12-06 12:38:24 +06:00
b17931e7bd complete startup module 2022-12-05 22:31:15 +06:00
2a4570eafc Update ServerLauncher.kt 2022-12-05 21:52:36 +06:00
c9514d3a6d Create DefaultJson.kt 2022-12-05 21:47:00 +06:00
072805efc7 Update ServerLauncher.kt 2022-12-05 21:45:30 +06:00
369ff26627 initialize startup module 2022-12-05 21:19:38 +06:00
c5abbbbd2d start 0.15.1 2022-12-05 20:04:50 +06:00
d974639f1e fixes in source roots of dokka 2022-12-05 07:47:35 +06:00
26efde316b remove redundant fix of android 32 dx files from worflows 2022-12-05 07:09:31 +06:00
fafe50f80a suppress kdocs of uniupload in actual realizations 2022-12-05 07:00:31 +06:00
41504469db Revert "potential fix of dokka"
This reverts commit 31022733ac.
2022-12-05 06:57:29 +06:00
03b3ddd98b Revert "remove redundant dokka println"
This reverts commit b53cfd5504.
2022-12-05 06:57:27 +06:00
89d919f2be Merge pull request #207 from InsanusMokrassar/0.15.0
0.15.0
2022-12-04 19:26:14 +06:00
b53cfd5504 remove redundant dokka println 2022-12-04 19:03:44 +06:00
31022733ac potential fix of dokka 2022-12-04 19:00:16 +06:00
f9a8c39879 updates and fixes in mime types 2022-12-02 21:07:32 +06:00
a812c2dd2f refresh language codes 2022-12-02 20:03:29 +06:00
217e977f0d ids in crud repos 2022-12-02 13:46:06 +06:00
04c301d1ac upgrade version up to 0.15.0 2022-12-02 13:31:11 +06:00
7f0c425389 start 0.14.5 2022-12-02 13:04:44 +06:00
1ede1c423b Merge pull request #206 from InsanusMokrassar/0.14.4
0.14.4
2022-11-27 17:34:07 +06:00
7cb064896a fill changelog 2022-11-27 14:44:03 +06:00
0c5e2862ca improvements in ktor client-server files handling 2022-11-27 14:38:35 +06:00
30d4507f54 hotfix in handleUniUpload 2022-11-26 12:12:01 +06:00
b6c6d89455 Update gradle.properties 2022-11-25 10:16:31 +06:00
9d218ee534 Update UniloadMultipart.kt 2022-11-25 10:15:59 +06:00
11116d8cab Merge pull request #205 from InsanusMokrassar/0.14.3
0.14.3
2022-11-24 13:15:08 +06:00
58d754bbde handleUniUpload now is inline 2022-11-24 12:29:48 +06:00
8f25c123dd add download and downloadToTemporalFile extensions 2022-11-24 11:27:30 +06:00
76e214fc08 upfixes 2022-11-22 14:39:31 +06:00
2b5380f8d6 add server part of uniUpload, fill changelog 2022-11-22 13:38:36 +06:00
844a129094 complete universal uniupload 2022-11-22 12:57:43 +06:00
a3090cca9d add uniupload for JVM 2022-11-22 10:36:15 +06:00
b7b5159e9c Revert "Revert "start adding uniupload""
This reverts commit 0d1aae0ef7.
2022-11-22 09:51:10 +06:00
0f8bc2c950 fix in workflow build 2022-11-21 20:50:28 +06:00
69f5c49f45 small update of build workflows 2022-11-21 20:49:04 +06:00
9b308e6fb8 update workflow 2022-11-21 20:32:48 +06:00
3e3f91128b add dependency of common android repos onto jvm 2022-11-21 20:23:05 +06:00
0d1aae0ef7 Revert "start adding uniupload"
This reverts commit 4d022f0480.
2022-11-21 20:20:37 +06:00
4d022f0480 start adding uniupload 2022-11-21 13:39:11 +06:00
153e20d00e start 0.14.3 2022-11-21 12:49:04 +06:00
a9a8171dd6 add gitea repo 2022-11-16 21:35:18 +06:00
bf5c3b59b2 Merge pull request #204 from InsanusMokrassar/0.14.2
0.14.2
2022-11-15 10:02:11 +06:00
607c432bdb Update CHANGELOG.md 2022-11-15 10:01:58 +06:00
ae5c010770 Update libs.versions.toml 2022-11-15 09:54:18 +06:00
d5e432437f Update gradle.properties 2022-11-15 09:53:28 +06:00
9f99ebce01 Merge pull request #203 from InsanusMokrassar/0.14.1
0.14.1
2022-11-10 17:19:17 +06:00
64ee899b84 revert koin version change 2022-11-10 17:13:25 +06:00
e0e0c1658b revert kotlin versin version change 2022-11-10 17:11:45 +06:00
2c586f667c update version 2022-11-10 17:09:12 +06:00
64164ef6c1 update dependencies 2022-11-10 17:06:20 +06:00
22343c0731 Merge pull request #202 from InsanusMokrassar/0.14.0
0.14.0
2022-11-08 14:20:12 +06:00
f4ec1a4c60 add deprecations removing note 2022-11-08 14:19:48 +06:00
c1c33cceb1 remove deprecations 2022-11-08 14:17:45 +06:00
a3e975b2ba Update CHANGELOG.md 2022-11-08 14:13:36 +06:00
06e705a687 update klock 2022-11-08 13:12:39 +06:00
d56eb6c867 fixes 2022-11-08 12:47:59 +06:00
9cbca864e3 Update CHANGELOG.md 2022-11-08 08:00:18 +06:00
abb4378694 Update libs.versions.toml 2022-11-08 07:59:50 +06:00
0eb698d9a4 start 0.14.0 2022-11-08 07:57:31 +06:00
15ea9f2093 add documentation for KeyValue repo 2022-11-03 13:01:51 +06:00
d47aca0923 Merge pull request #201 from InsanusMokrassar/0.13.2
0.13.2
2022-10-30 22:35:07 +06:00
78 changed files with 3753 additions and 2258 deletions

View File

@@ -9,9 +9,6 @@ jobs:
- uses: actions/setup-java@v1
with:
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
run: |
branch="`echo "${{ github.ref }}" | grep -o "[^/]*$"`"
@@ -20,9 +17,8 @@ jobs:
mv gradle.properties.tmp gradle.properties
- name: Build
run: ./gradlew build
# - name: Publish
# continue-on-error: true
# run: ./gradlew --no-parallel publishAllPublicationsToGithubPackagesRepository
# env:
# GITHUBPACKAGES_USER: ${{ github.actor }}
# GITHUBPACKAGES_PASSWORD: ${{ secrets.GITHUB_TOKEN }}
- name: Publish
continue-on-error: true
run: ./gradlew publishAllPublicationsToGiteaRepository
env:
GITEA_TOKEN: ${{ secrets.GITEA_TOKEN }}

View File

@@ -11,9 +11,6 @@ jobs:
- uses: actions/setup-java@v1
with:
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: Build
run: ./gradlew build && ./gradlew dokkaHtml
- name: Publish KDocs

View File

@@ -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")
}
}
}

View File

@@ -1,5 +1,92 @@
# Changelog
## 0.16.1
* `Coroutines`:
* New `runCatchingSafely`/`safelyWithResult` with receivers
* `SafeWrapper`:
* Module inited
## 0.16.0
* `Versions`:
* `Ktor`: `2.1.3` -> `2.2.1`
* `Android Fragment`: `1.5.3` -> `1.5.5`
## 0.15.1
* `Startup`:
* Inited :)
* `Plugin`:
* Inited :)
* `Launcher`:
* Inited :)
## 0.15.0
* `Repos`:
* `CRUD`:
* `Common`:
* New method `ReadCRUDRepo#getIdsByPagination`
* `Android`:
* `AbstractAndroidCRUDRepo` got new abstract method `toId`
* `Exposed`:
* `CommonExposedRepo` new abstract property `asId`
* `Ktor`:
* `Client`:
* `KtorReadCRUDRepoClient` now requires `paginationIdType`
* `LanguageCodes`:
* Updates and fixes in generation
* `MimeTypes`:
* Updates and fixes in generation
## 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
**ALL DEPRECATIONS HAVE BEEN REMOVED**
* `Versions`:
* `Kotlin`: `1.7.10` -> `1.7.20`
* `Klock`: `3.3.0` -> `3.3.1`
* `Compose`: `1.2.0` -> `1.2.1`
* `Exposed`: `0.39.2` -> `0.40.1`
## 0.13.2
* `Versions`:

View File

@@ -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()
)
}
}

View File

@@ -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()

View File

@@ -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()
}

View File

@@ -115,10 +115,21 @@ suspend inline fun <T> runCatchingSafely(
safely(onException, block)
}
suspend inline fun <T, R> T.runCatchingSafely(
noinline onException: ExceptionHandler<R> = defaultSafelyExceptionHandler,
noinline block: suspend T.() -> R
): Result<R> = runCatching {
safely(onException) { block() }
}
suspend inline fun <T> safelyWithResult(
noinline block: suspend CoroutineScope.() -> T
): Result<T> = runCatchingSafely(defaultSafelyExceptionHandler, block)
suspend inline fun <T, R> T.safelyWithResult(
noinline block: suspend T.() -> R
): Result<R> = runCatchingSafely(defaultSafelyExceptionHandler, block)
/**
* Use this handler in cases you wish to include handling of exceptions by [defaultSafelyWithoutExceptionHandler] and
* returning null at one time

View File

@@ -121,11 +121,11 @@ tasks.dokkaHtml {
// }
named("jvmMain") {
sourceRoots.setFrom(findSourcesWithName("jvmMain", "commonMain"))
sourceRoots.setFrom(findSourcesWithName("jvmMain"))
}
named("androidMain") {
sourceRoots.setFrom(findSourcesWithName("androidMain", "commonMain"))
sourceRoots.setFrom(findSourcesWithName("androidMain"))
}
}
}

View File

@@ -14,5 +14,5 @@ crypto_js_version=4.1.1
# Project data
group=dev.inmo
version=0.13.2
android_code_version=160
version=0.16.1
android_code_version=169

View File

@@ -1,29 +1,31 @@
[versions]
kt = "1.7.10"
kt = "1.7.20"
kt-serialization = "1.4.1"
kt-coroutines = "1.6.4"
jb-compose = "1.2.0"
jb-exposed = "0.39.2"
jb-dokka = "1.7.10"
kslog = "0.5.4"
klock = "3.3.0"
uuid = "0.5.0"
jb-compose = "1.2.1"
jb-exposed = "0.41.1"
jb-dokka = "1.7.20"
ktor = "2.1.3"
klock = "3.4.0"
uuid = "0.6.0"
ktor = "2.2.1"
gh-release = "2.4.1"
koin = "3.2.2"
android-gradle = "7.2.2"
android-gradle = "7.3.0"
dexcount = "3.1.0"
android-coreKtx = "1.9.0"
android-recyclerView = "1.2.1"
android-appCompat = "1.5.1"
android-fragment = "1.5.3"
android-fragment = "1.5.5"
android-espresso = "3.4.0"
android-test = "1.1.3"
@@ -60,6 +62,7 @@ ktor-server-websockets = { module = "io.ktor:ktor-server-websockets", version.re
ktor-server-statusPages = { module = "io.ktor:ktor-server-status-pages", version.ref = "ktor" }
ktor-server-content-negotiation = { module = "io.ktor:ktor-server-content-negotiation", version.ref = "ktor" }
kslog = { module = "dev.inmo:kslog", version.ref = "kslog" }
klock = { module = "com.soywiz.korlibs.klock:klock", version.ref = "klock" }
uuid = { module = "com.benasher44:uuid", version.ref = "uuid" }

View File

@@ -15,5 +15,9 @@ kotlin {
api libs.ktor.client
}
}
androidMain {
dependsOn jvmMain
}
}
}

View File

@@ -0,0 +1,3 @@
package dev.inmo.micro_utils.ktor.client
typealias OnUploadCallback = suspend (uploaded: Long, count: Long) -> Unit

View File

@@ -7,5 +7,5 @@ import io.ktor.client.HttpClient
expect suspend fun HttpClient.tempUpload(
fullTempUploadDraftPath: String,
file: MPPFile,
onUpload: (uploaded: Long, count: Long) -> Unit = { _, _ -> }
onUpload: OnUploadCallback = { _, _ -> }
): TemporalFileId

View File

@@ -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
)

View File

@@ -1,6 +1,8 @@
package dev.inmo.micro_utils.ktor.client
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 io.ktor.client.HttpClient
import kotlinx.coroutines.*
@@ -12,10 +14,11 @@ import org.w3c.xhr.XMLHttpRequest.Companion.DONE
suspend fun tempUpload(
fullTempUploadDraftPath: String,
file: MPPFile,
onUpload: (Long, Long) -> Unit
onUpload: OnUploadCallback
): TemporalFileId {
val formData = FormData()
val answer = CompletableDeferred<TemporalFileId>(currentCoroutineContext().job)
val subscope = CoroutineScope(currentCoroutineContext().LinkedSupervisorJob())
formData.append(
"data",
@@ -25,7 +28,7 @@ suspend fun tempUpload(
val request = XMLHttpRequest()
request.responseType = XMLHttpRequestResponseType.TEXT
request.upload.onprogress = {
onUpload(it.loaded.toLong(), it.total.toLong())
subscope.launchSafelyWithoutExceptions { onUpload(it.loaded.toLong(), it.total.toLong()) }
}
request.onload = {
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(
fullTempUploadDraftPath: String,
file: MPPFile,
onUpload: (uploaded: Long, count: Long) -> Unit
onUpload: OnUploadCallback
): TemporalFileId = dev.inmo.micro_utils.ktor.client.tempUpload(fullTempUploadDraftPath, file, onUpload)

View File

@@ -0,0 +1,97 @@
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
* @suppress
*/
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()
}
}

View File

@@ -4,6 +4,8 @@ import dev.inmo.micro_utils.common.MPPFile
import io.ktor.client.request.forms.InputProvider
import io.ktor.utils.io.streams.asInput
actual suspend fun MPPFile.inputProvider(): InputProvider = InputProvider(length()) {
fun MPPFile.inputProviderSync(): InputProvider = InputProvider(length()) {
inputStream().asInput()
}
actual suspend fun MPPFile.inputProvider(): InputProvider = inputProviderSync()

View File

@@ -18,7 +18,7 @@ internal val MPPFile.mimeType: String
actual suspend fun HttpClient.tempUpload(
fullTempUploadDraftPath: String,
file: MPPFile,
onUpload: (Long, Long) -> Unit
onUpload: OnUploadCallback
): TemporalFileId {
val inputProvider = file.inputProvider()
val fileId = submitFormWithBinaryData(

View File

@@ -0,0 +1,102 @@
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
* @suppress
*/
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
}
}

View File

@@ -0,0 +1,5 @@
package dev.inmo.micro_utils.ktor.common
import io.ktor.utils.io.core.Input
typealias LambdaInputProvider = () -> Input

View File

@@ -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()
}

View File

@@ -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
}

View File

@@ -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")
}
}

View File

@@ -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")
}
}

View File

@@ -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()
}

View File

@@ -78,12 +78,14 @@ private fun printLanguageCodeAndTags(
indents: String = " "
): String = if (tag.subtags.isEmpty()) {
"""${indents}${baseClassSerializerAnnotationName}
${indents}object ${tag.title} : ${parent ?.title ?: baseClassName}() { override val code: String = "${tag.tag}" }"""
${indents}object ${tag.title} : ${parent ?.title ?: baseClassName}() { override val code: String = "${tag.tag}"; override val withoutDialect: String get() = ${parent ?.title ?.let { "$it.code" } ?: "code"} }"""
} else {
"""
${indents}${baseClassSerializerAnnotationName}
${indents}sealed class ${tag.title} : ${parent ?.title ?: baseClassName}() {
${indents} override val code: String = "${tag.tag}"
${indents} override val withoutDialect: String
${indents} get() = code
${tag.subtags.joinToString("\n") { printLanguageCodeAndTags(it, tag, "${indents} ") }}
@@ -104,11 +106,14 @@ import kotlinx.serialization.Serializable
${baseClassSerializerAnnotationName}
sealed class $baseClassName {
abstract val code: String
abstract val withoutDialect: String
${tags.joinToString("\n") { printLanguageCodeAndTags(it, indents = " ") } }
$baseClassSerializerAnnotationName
data class $unknownBaseClassName (override val code: String) : $baseClassName()
data class $unknownBaseClassName (override val code: String) : $baseClassName() {
override val withoutDialect: String = code.takeWhile { it != '-' }
}
override fun toString() = code
}

View File

@@ -17,10 +17,11 @@ def fix_name(category, raw_name):
result += out1
return result
# https://www.freeformatter.com/mime-types-list.html
if __name__ == '__main__':
df = pd.read_html(open('table.html', 'r'))
mimes = []
for row in df[0].iterrows():
for row in df[0].drop_duplicates(subset=['MIME Type / Internet Media Type'], keep='first').iterrows():
mime = row[1][1]
mime_category = mime.split('/', 1)[0]
mime_name = mime.split('/', 1)[1]
@@ -37,7 +38,7 @@ if __name__ == '__main__':
code2 = 'internal val knownMimeTypes: Set<MimeType> = setOf(\n'
code2 += ' KnownMimeTypes.Any,\n'
for key, group in grouped:
group_name = key.capitalize()
group_name = fix_name(group, key)
code += '@Serializable(MimeTypeSerializer::class)\nsealed class %s(raw: String) : MimeType, KnownMimeTypes(raw) {\n' % group_name
code += ' @Serializable(MimeTypeSerializer::class)\n object Any: %s ("%s/*")\n' % (group_name, key)
for mime in group:

View File

@@ -0,0 +1,3 @@
package dev.inmo.micro_utils.mime_types
data class CustomMimeType(override val raw: String) : MimeType

View File

@@ -0,0 +1,705 @@
package dev.inmo.micro_utils.mime_types
internal val knownMimeTypes: Set<MimeType> = setOf(
KnownMimeTypes.Any,
KnownMimeTypes.Application.VndHzn3dCrossword,
KnownMimeTypes.Application.VndMseq,
KnownMimeTypes.Application.Vnd3mPostItNotes,
KnownMimeTypes.Application.Vnd3gppPicBwLarge,
KnownMimeTypes.Application.Vnd3gppPicBwSmall,
KnownMimeTypes.Application.Vnd3gppPicBwVar,
KnownMimeTypes.Application.Vnd3gpp2Tcap,
KnownMimeTypes.Application.X7zCompressed,
KnownMimeTypes.Application.XAbiword,
KnownMimeTypes.Application.XAceCompressed,
KnownMimeTypes.Application.VndAmericandynamicsAcc,
KnownMimeTypes.Application.VndAcucobol,
KnownMimeTypes.Application.VndAcucorp,
KnownMimeTypes.Application.XAuthorwareBin,
KnownMimeTypes.Application.XAuthorwareMap,
KnownMimeTypes.Application.XAuthorwareSeg,
KnownMimeTypes.Application.VndAdobeAirApplicationInstallerPackageZip,
KnownMimeTypes.Application.XShockwaveFlash,
KnownMimeTypes.Application.VndAdobeFxp,
KnownMimeTypes.Application.Pdf,
KnownMimeTypes.Application.VndCupsPpd,
KnownMimeTypes.Application.XDirector,
KnownMimeTypes.Application.VndAdobeXdpXml,
KnownMimeTypes.Application.VndAdobeXfdf,
KnownMimeTypes.Application.VndAheadSpace,
KnownMimeTypes.Application.VndAirzipFilesecureAzf,
KnownMimeTypes.Application.VndAirzipFilesecureAzs,
KnownMimeTypes.Application.VndAmazonEbook,
KnownMimeTypes.Application.VndAmigaAmi,
KnownMimeTypes.Application.AndrewInset,
KnownMimeTypes.Application.VndAndroidPackageArchive,
KnownMimeTypes.Application.VndAnserWebCertificateIssueInitiation,
KnownMimeTypes.Application.VndAnserWebFundsTransferInitiation,
KnownMimeTypes.Application.VndAntixGameComponent,
KnownMimeTypes.Application.XAppleDiskimage,
KnownMimeTypes.Application.VndAppleInstallerXml,
KnownMimeTypes.Application.Applixware,
KnownMimeTypes.Application.VndHheLessonPlayer,
KnownMimeTypes.Application.XFreearc,
KnownMimeTypes.Application.VndAristanetworksSwi,
KnownMimeTypes.Application.AtomcatXml,
KnownMimeTypes.Application.AtomsvcXml,
KnownMimeTypes.Application.AtomXml,
KnownMimeTypes.Application.PkixAttrCert,
KnownMimeTypes.Application.VndAudiograph,
KnownMimeTypes.Application.XBcpio,
KnownMimeTypes.Application.OctetStream,
KnownMimeTypes.Application.XBittorrent,
KnownMimeTypes.Application.VndRimCod,
KnownMimeTypes.Application.VndBlueiceMultipass,
KnownMimeTypes.Application.VndBmi,
KnownMimeTypes.Application.XSh,
KnownMimeTypes.Application.VndBusinessobjects,
KnownMimeTypes.Application.XBzip,
KnownMimeTypes.Application.XBzip2,
KnownMimeTypes.Application.XCsh,
KnownMimeTypes.Application.VndChemdrawXml,
KnownMimeTypes.Application.XCdf,
KnownMimeTypes.Application.VndContactCmsg,
KnownMimeTypes.Application.VndClaymore,
KnownMimeTypes.Application.VndClonkC4group,
KnownMimeTypes.Application.CdmiCapability,
KnownMimeTypes.Application.CdmiContainer,
KnownMimeTypes.Application.CdmiDomain,
KnownMimeTypes.Application.CdmiObject,
KnownMimeTypes.Application.CdmiQueue,
KnownMimeTypes.Application.VndCluetrustCartomobileConfig,
KnownMimeTypes.Application.VndCluetrustCartomobileConfigPkg,
KnownMimeTypes.Application.MacCompactpro,
KnownMimeTypes.Application.VndWapWmlc,
KnownMimeTypes.Application.VndXara,
KnownMimeTypes.Application.VndCosmocaller,
KnownMimeTypes.Application.XCpio,
KnownMimeTypes.Application.VndCrickClicker,
KnownMimeTypes.Application.VndCrickClickerKeyboard,
KnownMimeTypes.Application.VndCrickClickerPalette,
KnownMimeTypes.Application.VndCrickClickerTemplate,
KnownMimeTypes.Application.VndCrickClickerWordbank,
KnownMimeTypes.Application.VndCriticaltoolsWbsXml,
KnownMimeTypes.Application.VndRigCryptonote,
KnownMimeTypes.Application.CuSeeme,
KnownMimeTypes.Application.PrsCww,
KnownMimeTypes.Application.VndCurlCar,
KnownMimeTypes.Application.VndCurlPcurl,
KnownMimeTypes.Application.VndYellowriverCustomMenu,
KnownMimeTypes.Application.DsscDer,
KnownMimeTypes.Application.DsscXml,
KnownMimeTypes.Application.XDebianPackage,
KnownMimeTypes.Application.XDvi,
KnownMimeTypes.Application.VndFdsnSeed,
KnownMimeTypes.Application.XDtbookXml,
KnownMimeTypes.Application.XDtbresourceXml,
KnownMimeTypes.Application.VndDvbAit,
KnownMimeTypes.Application.VndDvbService,
KnownMimeTypes.Application.XmlDtd,
KnownMimeTypes.Application.VndDolbyMlp,
KnownMimeTypes.Application.XDoom,
KnownMimeTypes.Application.VndDpgraph,
KnownMimeTypes.Application.VndDreamfactory,
KnownMimeTypes.Application.VndDynageo,
KnownMimeTypes.Application.Ecmascript,
KnownMimeTypes.Application.VndEcowinChart,
KnownMimeTypes.Application.Exi,
KnownMimeTypes.Application.VndProteusMagazine,
KnownMimeTypes.Application.EpubZip,
KnownMimeTypes.Application.VndEnliven,
KnownMimeTypes.Application.VndIsXpr,
KnownMimeTypes.Application.VndXfdl,
KnownMimeTypes.Application.EmmaXml,
KnownMimeTypes.Application.VndEzpixAlbum,
KnownMimeTypes.Application.VndEzpixPackage,
KnownMimeTypes.Application.VndDenovoFcselayoutLink,
KnownMimeTypes.Application.VndFluxtimeClip,
KnownMimeTypes.Application.VndFdf,
KnownMimeTypes.Application.VndMif,
KnownMimeTypes.Application.VndFramemaker,
KnownMimeTypes.Application.VndFscWeblaunch,
KnownMimeTypes.Application.VndFrogansFnc,
KnownMimeTypes.Application.VndFrogansLtf,
KnownMimeTypes.Application.VndFujixeroxDdd,
KnownMimeTypes.Application.VndFujixeroxDocuworks,
KnownMimeTypes.Application.VndFujixeroxDocuworksBinder,
KnownMimeTypes.Application.VndFujitsuOasys,
KnownMimeTypes.Application.VndFujitsuOasys2,
KnownMimeTypes.Application.VndFujitsuOasys3,
KnownMimeTypes.Application.VndFujitsuOasysgp,
KnownMimeTypes.Application.VndFujitsuOasysprs,
KnownMimeTypes.Application.XFuturesplash,
KnownMimeTypes.Application.VndFuzzysheet,
KnownMimeTypes.Application.VndGmx,
KnownMimeTypes.Application.VndGenomatixTuxedo,
KnownMimeTypes.Application.VndGeogebraFile,
KnownMimeTypes.Application.VndGeogebraTool,
KnownMimeTypes.Application.VndGeometryExplorer,
KnownMimeTypes.Application.VndGeonext,
KnownMimeTypes.Application.VndGeoplan,
KnownMimeTypes.Application.VndGeospace,
KnownMimeTypes.Application.XFontGhostscript,
KnownMimeTypes.Application.XFontBdf,
KnownMimeTypes.Application.XGtar,
KnownMimeTypes.Application.XTexinfo,
KnownMimeTypes.Application.XGnumeric,
KnownMimeTypes.Application.VndGoogleEarthKmlXml,
KnownMimeTypes.Application.VndGoogleEarthKmz,
KnownMimeTypes.Application.GpxXml,
KnownMimeTypes.Application.VndGrafeq,
KnownMimeTypes.Application.VndGrooveAccount,
KnownMimeTypes.Application.VndGrooveHelp,
KnownMimeTypes.Application.VndGrooveIdentityMessage,
KnownMimeTypes.Application.VndGrooveInjector,
KnownMimeTypes.Application.VndGrooveToolMessage,
KnownMimeTypes.Application.VndGrooveToolTemplate,
KnownMimeTypes.Application.VndGrooveVcard,
KnownMimeTypes.Application.Gzip,
KnownMimeTypes.Application.VndHpHpid,
KnownMimeTypes.Application.VndHpHps,
KnownMimeTypes.Application.XHdf,
KnownMimeTypes.Application.VndHbci,
KnownMimeTypes.Application.VndHpJlyt,
KnownMimeTypes.Application.VndHpPcl,
KnownMimeTypes.Application.VndHpHpgl,
KnownMimeTypes.Application.VndYamahaHvScript,
KnownMimeTypes.Application.VndYamahaHvDic,
KnownMimeTypes.Application.VndYamahaHvVoice,
KnownMimeTypes.Application.VndHydrostatixSofData,
KnownMimeTypes.Application.Hyperstudio,
KnownMimeTypes.Application.VndHalXml,
KnownMimeTypes.Application.VndIbmRightsManagement,
KnownMimeTypes.Application.VndIbmSecureContainer,
KnownMimeTypes.Application.VndIccprofile,
KnownMimeTypes.Application.VndIgloader,
KnownMimeTypes.Application.VndImmervisionIvp,
KnownMimeTypes.Application.VndImmervisionIvu,
KnownMimeTypes.Application.ReginfoXml,
KnownMimeTypes.Application.VndIntergeo,
KnownMimeTypes.Application.VndCinderella,
KnownMimeTypes.Application.VndInterconFormnet,
KnownMimeTypes.Application.VndIsacFcs,
KnownMimeTypes.Application.Ipfix,
KnownMimeTypes.Application.PkixCert,
KnownMimeTypes.Application.Pkixcmp,
KnownMimeTypes.Application.PkixCrl,
KnownMimeTypes.Application.PkixPkipath,
KnownMimeTypes.Application.VndInsorsIgm,
KnownMimeTypes.Application.VndIpunpluggedRcprofile,
KnownMimeTypes.Application.VndIrepositoryPackageXml,
KnownMimeTypes.Application.JavaArchive,
KnownMimeTypes.Application.JavaVm,
KnownMimeTypes.Application.XJavaJnlpFile,
KnownMimeTypes.Application.JavaSerializedObject,
KnownMimeTypes.Application.Javascript,
KnownMimeTypes.Application.Json,
KnownMimeTypes.Application.VndJoostJodaArchive,
KnownMimeTypes.Application.LdJson,
KnownMimeTypes.Application.VndKahootz,
KnownMimeTypes.Application.VndChipnutsKaraokeMmd,
KnownMimeTypes.Application.VndKdeKarbon,
KnownMimeTypes.Application.VndKdeKchart,
KnownMimeTypes.Application.VndKdeKformula,
KnownMimeTypes.Application.VndKdeKivio,
KnownMimeTypes.Application.VndKdeKontour,
KnownMimeTypes.Application.VndKdeKpresenter,
KnownMimeTypes.Application.VndKdeKspread,
KnownMimeTypes.Application.VndKdeKword,
KnownMimeTypes.Application.VndKenameaapp,
KnownMimeTypes.Application.VndKidspiration,
KnownMimeTypes.Application.VndKinar,
KnownMimeTypes.Application.VndKodakDescriptor,
KnownMimeTypes.Application.VndLasLasXml,
KnownMimeTypes.Application.XLatex,
KnownMimeTypes.Application.VndLlamagraphicsLifeBalanceDesktop,
KnownMimeTypes.Application.VndLlamagraphicsLifeBalanceExchangeXml,
KnownMimeTypes.Application.VndJam,
KnownMimeTypes.Application.VndLotus123,
KnownMimeTypes.Application.VndLotusApproach,
KnownMimeTypes.Application.VndLotusFreelance,
KnownMimeTypes.Application.VndLotusNotes,
KnownMimeTypes.Application.VndLotusOrganizer,
KnownMimeTypes.Application.VndLotusScreencam,
KnownMimeTypes.Application.VndLotusWordpro,
KnownMimeTypes.Application.MacBinhex40,
KnownMimeTypes.Application.VndMacportsPortpkg,
KnownMimeTypes.Application.VndOsgeoMapguidePackage,
KnownMimeTypes.Application.Marc,
KnownMimeTypes.Application.MarcxmlXml,
KnownMimeTypes.Application.Mxf,
KnownMimeTypes.Application.VndWolframPlayer,
KnownMimeTypes.Application.Mathematica,
KnownMimeTypes.Application.MathmlXml,
KnownMimeTypes.Application.Mbox,
KnownMimeTypes.Application.VndMedcalcdata,
KnownMimeTypes.Application.MediaservercontrolXml,
KnownMimeTypes.Application.VndMediastationCdkey,
KnownMimeTypes.Application.VndMfer,
KnownMimeTypes.Application.VndMfmp,
KnownMimeTypes.Application.MadsXml,
KnownMimeTypes.Application.MetsXml,
KnownMimeTypes.Application.ModsXml,
KnownMimeTypes.Application.Metalink4Xml,
KnownMimeTypes.Application.VndMcd,
KnownMimeTypes.Application.VndMicrografxFlo,
KnownMimeTypes.Application.VndMicrografxIgx,
KnownMimeTypes.Application.VndEszigno3Xml,
KnownMimeTypes.Application.XMsaccess,
KnownMimeTypes.Application.XMsdownload,
KnownMimeTypes.Application.VndMsArtgalry,
KnownMimeTypes.Application.VndMsCabCompressed,
KnownMimeTypes.Application.VndMsIms,
KnownMimeTypes.Application.XMsApplication,
KnownMimeTypes.Application.XMsclip,
KnownMimeTypes.Application.VndMsFontobject,
KnownMimeTypes.Application.VndMsExcel,
KnownMimeTypes.Application.VndMsExcelAddinMacroenabled12,
KnownMimeTypes.Application.VndMsExcelSheetBinaryMacroenabled12,
KnownMimeTypes.Application.VndMsExcelTemplateMacroenabled12,
KnownMimeTypes.Application.VndMsExcelSheetMacroenabled12,
KnownMimeTypes.Application.VndMsHtmlhelp,
KnownMimeTypes.Application.XMscardfile,
KnownMimeTypes.Application.VndMsLrm,
KnownMimeTypes.Application.XMsmediaview,
KnownMimeTypes.Application.XMsmoney,
KnownMimeTypes.Application.VndOpenxmlformatsOfficedocumentPresentationmlPresentation,
KnownMimeTypes.Application.VndOpenxmlformatsOfficedocumentPresentationmlSlide,
KnownMimeTypes.Application.VndOpenxmlformatsOfficedocumentPresentationmlSlideshow,
KnownMimeTypes.Application.VndOpenxmlformatsOfficedocumentPresentationmlTemplate,
KnownMimeTypes.Application.VndOpenxmlformatsOfficedocumentSpreadsheetmlSheet,
KnownMimeTypes.Application.VndOpenxmlformatsOfficedocumentSpreadsheetmlTemplate,
KnownMimeTypes.Application.VndOpenxmlformatsOfficedocumentWordprocessingmlDocument,
KnownMimeTypes.Application.VndOpenxmlformatsOfficedocumentWordprocessingmlTemplate,
KnownMimeTypes.Application.XMsbinder,
KnownMimeTypes.Application.VndMsOfficetheme,
KnownMimeTypes.Application.Onenote,
KnownMimeTypes.Application.VndMsPowerpoint,
KnownMimeTypes.Application.VndMsPowerpointAddinMacroenabled12,
KnownMimeTypes.Application.VndMsPowerpointSlideMacroenabled12,
KnownMimeTypes.Application.VndMsPowerpointPresentationMacroenabled12,
KnownMimeTypes.Application.VndMsPowerpointSlideshowMacroenabled12,
KnownMimeTypes.Application.VndMsPowerpointTemplateMacroenabled12,
KnownMimeTypes.Application.VndMsProject,
KnownMimeTypes.Application.XMspublisher,
KnownMimeTypes.Application.XMsschedule,
KnownMimeTypes.Application.XSilverlightApp,
KnownMimeTypes.Application.VndMsPkiStl,
KnownMimeTypes.Application.VndMsPkiSeccat,
KnownMimeTypes.Application.VndVisio,
KnownMimeTypes.Application.VndVisio2013,
KnownMimeTypes.Application.XMsWmd,
KnownMimeTypes.Application.VndMsWpl,
KnownMimeTypes.Application.XMsWmz,
KnownMimeTypes.Application.XMsmetafile,
KnownMimeTypes.Application.XMsterminal,
KnownMimeTypes.Application.Msword,
KnownMimeTypes.Application.VndMsWordDocumentMacroenabled12,
KnownMimeTypes.Application.VndMsWordTemplateMacroenabled12,
KnownMimeTypes.Application.XMswrite,
KnownMimeTypes.Application.VndMsWorks,
KnownMimeTypes.Application.XMsXbap,
KnownMimeTypes.Application.VndMsXpsdocument,
KnownMimeTypes.Application.VndIbmMinipay,
KnownMimeTypes.Application.VndIbmModcap,
KnownMimeTypes.Application.VndJcpJavameMidletRms,
KnownMimeTypes.Application.VndTmobileLivetv,
KnownMimeTypes.Application.XMobipocketEbook,
KnownMimeTypes.Application.VndMobiusMbk,
KnownMimeTypes.Application.VndMobiusDis,
KnownMimeTypes.Application.VndMobiusPlc,
KnownMimeTypes.Application.VndMobiusMqy,
KnownMimeTypes.Application.VndMobiusMsl,
KnownMimeTypes.Application.VndMobiusTxf,
KnownMimeTypes.Application.VndMobiusDaf,
KnownMimeTypes.Application.VndMophunCertificate,
KnownMimeTypes.Application.VndMophunApplication,
KnownMimeTypes.Application.Mp21,
KnownMimeTypes.Application.Mp4,
KnownMimeTypes.Application.VndAppleMpegurl,
KnownMimeTypes.Application.VndMusician,
KnownMimeTypes.Application.VndMuveeStyle,
KnownMimeTypes.Application.XvXml,
KnownMimeTypes.Application.VndNokiaNGageData,
KnownMimeTypes.Application.VndNokiaNGageSymbianInstall,
KnownMimeTypes.Application.XDtbncxXml,
KnownMimeTypes.Application.XNetcdf,
KnownMimeTypes.Application.VndNeurolanguageNlu,
KnownMimeTypes.Application.VndDna,
KnownMimeTypes.Application.VndNoblenetDirectory,
KnownMimeTypes.Application.VndNoblenetSealer,
KnownMimeTypes.Application.VndNoblenetWeb,
KnownMimeTypes.Application.VndNokiaRadioPreset,
KnownMimeTypes.Application.VndNokiaRadioPresets,
KnownMimeTypes.Application.VndNovadigmEdm,
KnownMimeTypes.Application.VndNovadigmEdx,
KnownMimeTypes.Application.VndNovadigmExt,
KnownMimeTypes.Application.VndFlographit,
KnownMimeTypes.Application.Oda,
KnownMimeTypes.Application.Ogg,
KnownMimeTypes.Application.VndOmaDd2Xml,
KnownMimeTypes.Application.VndOasisOpendocumentTextWeb,
KnownMimeTypes.Application.OebpsPackageXml,
KnownMimeTypes.Application.VndIntuQbo,
KnownMimeTypes.Application.VndOpenofficeorgExtension,
KnownMimeTypes.Application.VndYamahaOpenscoreformat,
KnownMimeTypes.Application.VndOasisOpendocumentChart,
KnownMimeTypes.Application.VndOasisOpendocumentChartTemplate,
KnownMimeTypes.Application.VndOasisOpendocumentDatabase,
KnownMimeTypes.Application.VndOasisOpendocumentFormula,
KnownMimeTypes.Application.VndOasisOpendocumentFormulaTemplate,
KnownMimeTypes.Application.VndOasisOpendocumentGraphics,
KnownMimeTypes.Application.VndOasisOpendocumentGraphicsTemplate,
KnownMimeTypes.Application.VndOasisOpendocumentImage,
KnownMimeTypes.Application.VndOasisOpendocumentImageTemplate,
KnownMimeTypes.Application.VndOasisOpendocumentPresentation,
KnownMimeTypes.Application.VndOasisOpendocumentPresentationTemplate,
KnownMimeTypes.Application.VndOasisOpendocumentSpreadsheet,
KnownMimeTypes.Application.VndOasisOpendocumentSpreadsheetTemplate,
KnownMimeTypes.Application.VndOasisOpendocumentText,
KnownMimeTypes.Application.VndOasisOpendocumentTextMaster,
KnownMimeTypes.Application.VndOasisOpendocumentTextTemplate,
KnownMimeTypes.Application.VndSunXmlCalc,
KnownMimeTypes.Application.VndSunXmlCalcTemplate,
KnownMimeTypes.Application.VndSunXmlDraw,
KnownMimeTypes.Application.VndSunXmlDrawTemplate,
KnownMimeTypes.Application.VndSunXmlImpress,
KnownMimeTypes.Application.VndSunXmlImpressTemplate,
KnownMimeTypes.Application.VndSunXmlMath,
KnownMimeTypes.Application.VndSunXmlWriter,
KnownMimeTypes.Application.VndSunXmlWriterGlobal,
KnownMimeTypes.Application.VndSunXmlWriterTemplate,
KnownMimeTypes.Application.XFontOtf,
KnownMimeTypes.Application.VndYamahaOpenscoreformatOsfpvgXml,
KnownMimeTypes.Application.VndOsgiDp,
KnownMimeTypes.Application.VndPalm,
KnownMimeTypes.Application.VndPawaafile,
KnownMimeTypes.Application.VndHpPclxl,
KnownMimeTypes.Application.VndPicsel,
KnownMimeTypes.Application.PicsRules,
KnownMimeTypes.Application.XChat,
KnownMimeTypes.Application.Pkcs10,
KnownMimeTypes.Application.XPkcs12,
KnownMimeTypes.Application.Pkcs7Mime,
KnownMimeTypes.Application.Pkcs7Signature,
KnownMimeTypes.Application.XPkcs7Certreqresp,
KnownMimeTypes.Application.XPkcs7Certificates,
KnownMimeTypes.Application.Pkcs8,
KnownMimeTypes.Application.VndPocketlearn,
KnownMimeTypes.Application.XFontPcf,
KnownMimeTypes.Application.FontTdpfr,
KnownMimeTypes.Application.XChessPgn,
KnownMimeTypes.Application.PskcXml,
KnownMimeTypes.Application.VndCtcPosml,
KnownMimeTypes.Application.Postscript,
KnownMimeTypes.Application.XFontType1,
KnownMimeTypes.Application.VndPowerbuilder6,
KnownMimeTypes.Application.PgpEncrypted,
KnownMimeTypes.Application.PgpSignature,
KnownMimeTypes.Application.VndPreviewsystemsBox,
KnownMimeTypes.Application.VndPviPtid1,
KnownMimeTypes.Application.PlsXml,
KnownMimeTypes.Application.VndPgFormat,
KnownMimeTypes.Application.VndPgOsasli,
KnownMimeTypes.Application.XFontLinuxPsf,
KnownMimeTypes.Application.VndPublishareDeltaTree,
KnownMimeTypes.Application.VndPmiWidget,
KnownMimeTypes.Application.VndQuarkQuarkxpress,
KnownMimeTypes.Application.VndEpsonEsf,
KnownMimeTypes.Application.VndEpsonMsf,
KnownMimeTypes.Application.VndEpsonSsf,
KnownMimeTypes.Application.VndEpsonQuickanime,
KnownMimeTypes.Application.VndIntuQfx,
KnownMimeTypes.Application.XRarCompressed,
KnownMimeTypes.Application.RsdXml,
KnownMimeTypes.Application.VndRnRealmedia,
KnownMimeTypes.Application.VndRealvncBed,
KnownMimeTypes.Application.VndRecordareMusicxml,
KnownMimeTypes.Application.VndRecordareMusicxmlXml,
KnownMimeTypes.Application.RelaxNgCompactSyntax,
KnownMimeTypes.Application.VndDataVisionRdz,
KnownMimeTypes.Application.RdfXml,
KnownMimeTypes.Application.VndCloantoRp9,
KnownMimeTypes.Application.VndJisp,
KnownMimeTypes.Application.Rtf,
KnownMimeTypes.Application.VndRoute66Link66Xml,
KnownMimeTypes.Application.RssXml,
KnownMimeTypes.Application.ShfXml,
KnownMimeTypes.Application.VndSailingtrackerTrack,
KnownMimeTypes.Application.VndSusCalendar,
KnownMimeTypes.Application.SruXml,
KnownMimeTypes.Application.SetPaymentInitiation,
KnownMimeTypes.Application.SetRegistrationInitiation,
KnownMimeTypes.Application.VndSema,
KnownMimeTypes.Application.VndSemd,
KnownMimeTypes.Application.VndSemf,
KnownMimeTypes.Application.VndSeemail,
KnownMimeTypes.Application.XFontSnf,
KnownMimeTypes.Application.ScvpVpRequest,
KnownMimeTypes.Application.ScvpVpResponse,
KnownMimeTypes.Application.ScvpCvRequest,
KnownMimeTypes.Application.ScvpCvResponse,
KnownMimeTypes.Application.Sdp,
KnownMimeTypes.Application.VndShanaInformedFormdata,
KnownMimeTypes.Application.VndShanaInformedFormtemplate,
KnownMimeTypes.Application.VndShanaInformedInterchange,
KnownMimeTypes.Application.VndShanaInformedPackage,
KnownMimeTypes.Application.ThraudXml,
KnownMimeTypes.Application.XShar,
KnownMimeTypes.Application.VndEpsonSalt,
KnownMimeTypes.Application.VndAccpacSimplyAso,
KnownMimeTypes.Application.VndAccpacSimplyImp,
KnownMimeTypes.Application.VndSimtechMindmapper,
KnownMimeTypes.Application.VndCommonspace,
KnownMimeTypes.Application.VndYamahaSmafAudio,
KnownMimeTypes.Application.VndSmaf,
KnownMimeTypes.Application.VndYamahaSmafPhrase,
KnownMimeTypes.Application.VndSmartTeacher,
KnownMimeTypes.Application.VndSvd,
KnownMimeTypes.Application.SparqlQuery,
KnownMimeTypes.Application.SparqlResultsXml,
KnownMimeTypes.Application.Srgs,
KnownMimeTypes.Application.SrgsXml,
KnownMimeTypes.Application.SsmlXml,
KnownMimeTypes.Application.VndKoan,
KnownMimeTypes.Application.VndStardivisionCalc,
KnownMimeTypes.Application.VndStardivisionDraw,
KnownMimeTypes.Application.VndStardivisionImpress,
KnownMimeTypes.Application.VndStardivisionMath,
KnownMimeTypes.Application.VndStardivisionWriter,
KnownMimeTypes.Application.VndStardivisionWriterGlobal,
KnownMimeTypes.Application.VndStepmaniaStepchart,
KnownMimeTypes.Application.XStuffit,
KnownMimeTypes.Application.XStuffitx,
KnownMimeTypes.Application.VndSolentSdkmXml,
KnownMimeTypes.Application.VndOlpcSugar,
KnownMimeTypes.Application.VndWqd,
KnownMimeTypes.Application.VndSymbianInstall,
KnownMimeTypes.Application.SmilXml,
KnownMimeTypes.Application.VndSyncmlXml,
KnownMimeTypes.Application.VndSyncmlDmWbxml,
KnownMimeTypes.Application.VndSyncmlDmXml,
KnownMimeTypes.Application.XSv4cpio,
KnownMimeTypes.Application.XSv4crc,
KnownMimeTypes.Application.SbmlXml,
KnownMimeTypes.Application.VndTaoIntentModuleArchive,
KnownMimeTypes.Application.XTar,
KnownMimeTypes.Application.XTcl,
KnownMimeTypes.Application.XTex,
KnownMimeTypes.Application.XTexTfm,
KnownMimeTypes.Application.TeiXml,
KnownMimeTypes.Application.VndSpotfireDxp,
KnownMimeTypes.Application.VndSpotfireSfs,
KnownMimeTypes.Application.TimestampedData,
KnownMimeTypes.Application.VndTridTpt,
KnownMimeTypes.Application.VndTriscapeMxs,
KnownMimeTypes.Application.VndTrueapp,
KnownMimeTypes.Application.XFontTtf,
KnownMimeTypes.Application.VndUmajin,
KnownMimeTypes.Application.VndUomlXml,
KnownMimeTypes.Application.VndUnity,
KnownMimeTypes.Application.VndUfdl,
KnownMimeTypes.Application.VndUiqTheme,
KnownMimeTypes.Application.XUstar,
KnownMimeTypes.Application.XCdlink,
KnownMimeTypes.Application.VndVsf,
KnownMimeTypes.Application.VndVcx,
KnownMimeTypes.Application.VndVisionary,
KnownMimeTypes.Application.CcxmlXml,
KnownMimeTypes.Application.VoicexmlXml,
KnownMimeTypes.Application.XWaisSource,
KnownMimeTypes.Application.VndWapWbxml,
KnownMimeTypes.Application.DavmountXml,
KnownMimeTypes.Application.XFontWoff,
KnownMimeTypes.Application.WspolicyXml,
KnownMimeTypes.Application.VndWebturbo,
KnownMimeTypes.Application.Widget,
KnownMimeTypes.Application.Winhlp,
KnownMimeTypes.Application.VndWapWmlscriptc,
KnownMimeTypes.Application.VndWordperfect,
KnownMimeTypes.Application.VndWtStf,
KnownMimeTypes.Application.WsdlXml,
KnownMimeTypes.Application.XX509CaCert,
KnownMimeTypes.Application.XXfig,
KnownMimeTypes.Application.XhtmlXml,
KnownMimeTypes.Application.Xml,
KnownMimeTypes.Application.XcapDiffXml,
KnownMimeTypes.Application.XencXml,
KnownMimeTypes.Application.PatchOpsErrorXml,
KnownMimeTypes.Application.ResourceListsXml,
KnownMimeTypes.Application.RlsServicesXml,
KnownMimeTypes.Application.ResourceListsDiffXml,
KnownMimeTypes.Application.XsltXml,
KnownMimeTypes.Application.XopXml,
KnownMimeTypes.Application.XXpinstall,
KnownMimeTypes.Application.XspfXml,
KnownMimeTypes.Application.VndMozillaXulXml,
KnownMimeTypes.Application.Yang,
KnownMimeTypes.Application.YinXml,
KnownMimeTypes.Application.VndZul,
KnownMimeTypes.Application.Zip,
KnownMimeTypes.Application.VndHandheldEntertainmentXml,
KnownMimeTypes.Application.VndZzazzDeckXml,
KnownMimeTypes.Audio.Adpcm,
KnownMimeTypes.Audio.XAac,
KnownMimeTypes.Audio.XAiff,
KnownMimeTypes.Audio.VndDeceAudio,
KnownMimeTypes.Audio.VndDigitalWinds,
KnownMimeTypes.Audio.VndDra,
KnownMimeTypes.Audio.VndDts,
KnownMimeTypes.Audio.VndDtsHd,
KnownMimeTypes.Audio.VndRip,
KnownMimeTypes.Audio.VndLucentVoice,
KnownMimeTypes.Audio.XMpegurl,
KnownMimeTypes.Audio.VndMsPlayreadyMediaPya,
KnownMimeTypes.Audio.XMsWma,
KnownMimeTypes.Audio.XMsWax,
KnownMimeTypes.Audio.Midi,
KnownMimeTypes.Audio.Mpeg,
KnownMimeTypes.Audio.Mp4,
KnownMimeTypes.Audio.VndNueraEcelp4800,
KnownMimeTypes.Audio.VndNueraEcelp7470,
KnownMimeTypes.Audio.VndNueraEcelp9600,
KnownMimeTypes.Audio.Ogg,
KnownMimeTypes.Audio.Webm,
KnownMimeTypes.Audio.Opus,
KnownMimeTypes.Audio.XPnRealaudio,
KnownMimeTypes.Audio.XPnRealaudioPlugin,
KnownMimeTypes.Audio.Basic,
KnownMimeTypes.Audio.XWav,
KnownMimeTypes.Chemical.XCdx,
KnownMimeTypes.Chemical.XCml,
KnownMimeTypes.Chemical.XCsml,
KnownMimeTypes.Chemical.XCif,
KnownMimeTypes.Chemical.XCmdf,
KnownMimeTypes.Chemical.XXyz,
KnownMimeTypes.Image.VndDxf,
KnownMimeTypes.Image.Avif,
KnownMimeTypes.Image.Bmp,
KnownMimeTypes.Image.PrsBtif,
KnownMimeTypes.Image.VndDvbSubtitle,
KnownMimeTypes.Image.XCmuRaster,
KnownMimeTypes.Image.Cgm,
KnownMimeTypes.Image.XCmx,
KnownMimeTypes.Image.VndDeceGraphic,
KnownMimeTypes.Image.VndDjvu,
KnownMimeTypes.Image.VndDwg,
KnownMimeTypes.Image.VndFujixeroxEdmicsMmr,
KnownMimeTypes.Image.VndFujixeroxEdmicsRlc,
KnownMimeTypes.Image.VndXiff,
KnownMimeTypes.Image.VndFst,
KnownMimeTypes.Image.VndFastbidsheet,
KnownMimeTypes.Image.VndFpx,
KnownMimeTypes.Image.VndNetFpx,
KnownMimeTypes.Image.XFreehand,
KnownMimeTypes.Image.G3fax,
KnownMimeTypes.Image.Gif,
KnownMimeTypes.Image.XIcon,
KnownMimeTypes.Image.Ief,
KnownMimeTypes.Image.Jpeg,
KnownMimeTypes.Image.XCitrixJpeg,
KnownMimeTypes.Image.Pjpeg,
KnownMimeTypes.Image.VndMsModi,
KnownMimeTypes.Image.Ktx,
KnownMimeTypes.Image.XPcx,
KnownMimeTypes.Image.VndAdobePhotoshop,
KnownMimeTypes.Image.XPict,
KnownMimeTypes.Image.XPortableAnymap,
KnownMimeTypes.Image.XPortableBitmap,
KnownMimeTypes.Image.XPortableGraymap,
KnownMimeTypes.Image.Png,
KnownMimeTypes.Image.XCitrixPng,
KnownMimeTypes.Image.XPng,
KnownMimeTypes.Image.XPortablePixmap,
KnownMimeTypes.Image.SvgXml,
KnownMimeTypes.Image.XRgb,
KnownMimeTypes.Image.Tiff,
KnownMimeTypes.Image.VndWapWbmp,
KnownMimeTypes.Image.Webp,
KnownMimeTypes.Image.XXbitmap,
KnownMimeTypes.Image.XXpixmap,
KnownMimeTypes.Image.XXwindowdump,
KnownMimeTypes.Message.Rfc822,
KnownMimeTypes.Model.VndDwf,
KnownMimeTypes.Model.VndColladaXml,
KnownMimeTypes.Model.VndGtw,
KnownMimeTypes.Model.VndGdl,
KnownMimeTypes.Model.Iges,
KnownMimeTypes.Model.Mesh,
KnownMimeTypes.Model.Vrml,
KnownMimeTypes.Model.VndMts,
KnownMimeTypes.Model.VndVtu,
KnownMimeTypes.Text.XAsm,
KnownMimeTypes.Text.PlainBas,
KnownMimeTypes.Text.XC,
KnownMimeTypes.Text.Css,
KnownMimeTypes.Text.Csv,
KnownMimeTypes.Text.VndCurl,
KnownMimeTypes.Text.VndCurlDcurl,
KnownMimeTypes.Text.VndCurlMcurl,
KnownMimeTypes.Text.VndCurlScurl,
KnownMimeTypes.Text.VndFmiFlexstor,
KnownMimeTypes.Text.XFortran,
KnownMimeTypes.Text.VndGraphviz,
KnownMimeTypes.Text.Html,
KnownMimeTypes.Text.Calendar,
KnownMimeTypes.Text.VndIn3d3dml,
KnownMimeTypes.Text.VndIn3dSpot,
KnownMimeTypes.Text.VndSunJ2meAppDescriptor,
KnownMimeTypes.Text.XJavaSourceJava,
KnownMimeTypes.Text.Javascript,
KnownMimeTypes.Text.VndFly,
KnownMimeTypes.Text.N3,
KnownMimeTypes.Text.XPascal,
KnownMimeTypes.Text.PrsLinesTag,
KnownMimeTypes.Text.Richtext,
KnownMimeTypes.Text.XSetext,
KnownMimeTypes.Text.Sgml,
KnownMimeTypes.Text.TabSeparatedValues,
KnownMimeTypes.Text.Plain,
KnownMimeTypes.Text.Troff,
KnownMimeTypes.Text.Turtle,
KnownMimeTypes.Text.UriList,
KnownMimeTypes.Text.XUuencode,
KnownMimeTypes.Text.XVcalendar,
KnownMimeTypes.Text.XVcard,
KnownMimeTypes.Text.VndWapWml,
KnownMimeTypes.Text.VndWapWmlscript,
KnownMimeTypes.Text.Yaml,
KnownMimeTypes.Video.V3gpp,
KnownMimeTypes.Video.V3gpp2,
KnownMimeTypes.Video.XMsvideo,
KnownMimeTypes.Video.VndDeceHd,
KnownMimeTypes.Video.VndDeceMobile,
KnownMimeTypes.Video.VndUvvuMp4,
KnownMimeTypes.Video.VndDecePd,
KnownMimeTypes.Video.VndDeceSd,
KnownMimeTypes.Video.VndDeceVideo,
KnownMimeTypes.Video.VndFvt,
KnownMimeTypes.Video.XF4v,
KnownMimeTypes.Video.XFlv,
KnownMimeTypes.Video.XFli,
KnownMimeTypes.Video.H261,
KnownMimeTypes.Video.H263,
KnownMimeTypes.Video.H264,
KnownMimeTypes.Video.Jpm,
KnownMimeTypes.Video.Jpeg,
KnownMimeTypes.Video.XM4v,
KnownMimeTypes.Video.XMsAsf,
KnownMimeTypes.Video.VndMsPlayreadyMediaPyv,
KnownMimeTypes.Video.XMsWm,
KnownMimeTypes.Video.XMsWmx,
KnownMimeTypes.Video.XMsWmv,
KnownMimeTypes.Video.XMsWvx,
KnownMimeTypes.Video.Mj2,
KnownMimeTypes.Video.Mp2t,
KnownMimeTypes.Video.VndMpegurl,
KnownMimeTypes.Video.Mpeg,
KnownMimeTypes.Video.Mp4,
KnownMimeTypes.Video.Ogg,
KnownMimeTypes.Video.Webm,
KnownMimeTypes.Video.Quicktime,
KnownMimeTypes.Video.XSgiMovie,
KnownMimeTypes.Video.VndVivo,
KnownMimeTypes.XConference.XCooltalk,
)

View File

@@ -0,0 +1,8 @@
package dev.inmo.micro_utils.mime_types
import kotlinx.serialization.Serializable
@Serializable(MimeTypeSerializer::class)
interface MimeType {
val raw: String
}

View File

@@ -0,0 +1,24 @@
package dev.inmo.micro_utils.mime_types
import kotlinx.serialization.KSerializer
import kotlinx.serialization.Serializer
import kotlinx.serialization.descriptors.PrimitiveKind
import kotlinx.serialization.descriptors.PrimitiveSerialDescriptor
import kotlinx.serialization.descriptors.SerialDescriptor
import kotlinx.serialization.encoding.Decoder
import kotlinx.serialization.encoding.Encoder
@Suppress("OPT_IN_USAGE")
@Serializer(MimeType::class)
object MimeTypeSerializer : KSerializer<MimeType> {
override val descriptor: SerialDescriptor = PrimitiveSerialDescriptor("mimeType", PrimitiveKind.STRING)
override fun deserialize(decoder: Decoder): MimeType {
val mimeType = decoder.decodeString()
return mimeType(mimeType)
}
override fun serialize(encoder: Encoder, value: MimeType) {
encoder.encodeString(value.raw)
}
}

View File

@@ -1,10 +1,5 @@
package dev.inmo.micro_utils.mime_types
import kotlinx.serialization.*
import kotlinx.serialization.descriptors.*
import kotlinx.serialization.encoding.Decoder
import kotlinx.serialization.encoding.Encoder
private val mimesCache = mutableMapOf<String, MimeType>().also {
knownMimeTypes.forEach { mimeType -> it[mimeType.raw] = mimeType }
}
@@ -15,17 +10,3 @@ fun mimeType(raw: String) = mimesCache.getOrPut(raw) {
internal fun parseMimeType(raw: String): MimeType = CustomMimeType(raw)
@Suppress("OPT_IN_USAGE")
@Serializer(MimeType::class)
object MimeTypeSerializer : KSerializer<MimeType> {
override val descriptor: SerialDescriptor = PrimitiveSerialDescriptor("mimeType", PrimitiveKind.STRING)
override fun deserialize(decoder: Decoder): MimeType {
val mimeType = decoder.decodeString()
return mimeType(mimeType)
}
override fun serialize(encoder: Encoder, value: MimeType) {
encoder.encodeString(value.raw)
}
}

View File

@@ -23,7 +23,7 @@ kotlin {
commonMain {
dependencies {
implementation kotlin('stdlib')
implementation libs.kt.serialization
api libs.kt.serialization
}
}
commonTest {

View File

@@ -23,7 +23,7 @@ kotlin {
commonMain {
dependencies {
implementation kotlin('stdlib')
implementation libs.kt.serialization
api libs.kt.serialization
implementation compose.runtime
}
}

View File

@@ -19,29 +19,29 @@ publishing {
}
developers {
developer {
id = "InsanusMokrassar"
name = "Aleksei Ovsiannikov"
email = "ovsyannikov.alexey95@gmail.com"
}
developer {
id = "000Sanya"
name = "Syrov Aleksandr"
email = "000sanya.000sanya@gmail.com"
}
}
licenses {
license {
name = "Apache Software License 2.0"
url = "https://github.com/InsanusMokrassar/MicroUtils/blob/master/LICENSE"
}
}
}
repositories {
@@ -49,35 +49,54 @@ publishing {
maven {
name = "GithubPackages"
url = uri("https://maven.pkg.github.com/InsanusMokrassar/MicroUtils")
credentials {
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')
}
}
}
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)) {
maven {
name = "sonatype"
url = uri("https://oss.sonatype.org/service/local/staging/deploy/maven2/")
credentials {
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')
}
}
}
}
}
}
if (project.hasProperty("signing.gnupg.keyName")) {
apply plugin: 'signing'
signing {
useGpgCmd()
sign publishing.publications
}
task signAll {
tasks.withType(Sign).forEach {
dependsOn(it)

View File

@@ -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"}}}

View File

@@ -46,6 +46,12 @@ open class FullReadCRUDCacheRepo<ObjectType, IdType>(
{ if (it.results.isNotEmpty()) actualizeAll() }
)
override suspend fun getIdsByPagination(pagination: Pagination): PaginationResult<IdType> = doOrTakeAndActualize(
{ keys(pagination).takeIf { it.results.isNotEmpty() }.optionalOrAbsentIfNull },
{ getIdsByPagination(pagination) },
{ if (it.results.isNotEmpty()) actualizeAll() }
)
override suspend fun count(): Long = doOrTakeAndActualize(
{ count().takeIf { it != 0L }.optionalOrAbsentIfNull },
{ count() },

View File

@@ -28,6 +28,7 @@ kotlin {
api internalProject("micro_utils.common")
api internalProject("micro_utils.coroutines")
}
dependsOn jvmMain
}
}
}

View File

@@ -0,0 +1,138 @@
package dev.inmo.micro_utils.repos
import dev.inmo.micro_utils.pagination.*
import dev.inmo.micro_utils.pagination.utils.doAllWithCurrentPaging
import kotlinx.coroutines.flow.Flow
/**
* Read part of [KeyValueRepo]
*
* @param Key This type will be used as key in all operations related to searches of data
* @param Value This type will be used as returning data in most "get" operations
*/
interface ReadKeyValueRepo<Key, Value> : Repo {
/**
* @return Result [Value] in case when it is presented in repo by its [k] or null otherwise
*/
suspend fun get(k: Key): Value?
/**
* This method should use sorted by [Key]s search and take the [PaginationResult]. By default, it should use
* ascending sort for [Key]s
*/
suspend fun values(pagination: Pagination, reversed: Boolean = false): PaginationResult<Value>
/**
* This method should use sorted by [Key]s search and take the [PaginationResult]. By default, it should use
* ascending sort for [Key]s
*/
suspend fun keys(pagination: Pagination, reversed: Boolean = false): PaginationResult<Key>
/**
* This method should use sorted by [Key]s search and take the [PaginationResult]. By default, it should use
* ascending sort for [Key]s
*
* @param v This value should be used to exclude from search the items with different [Value]s
*/
suspend fun keys(v: Value, pagination: Pagination, reversed: Boolean = false): PaginationResult<Key>
/**
* @return true if [key] is presented in current collection or false otherwise
*/
suspend fun contains(key: Key): Boolean
/**
* @return count of all collection objects
*/
suspend fun count(): Long
}
typealias ReadStandardKeyValueRepo<Key,Value> = ReadKeyValueRepo<Key, Value>
/**
* Write part of [KeyValueRepo]
*
* @param Key This type will be used as key in all operations related to changes of data
* @param Value This type will be used as incoming data in most operations
*/
interface WriteKeyValueRepo<Key, Value> : Repo {
/**
* This flow must emit data each time when data by [Key] has been changed with [set] method or in any other way
* excluding cases of data removing
*
* @see onValueRemoved
*/
val onNewValue: Flow<Pair<Key, Value>>
/**
* This flow must emit data each time when data by [Key] has been removed with [unset]/[unsetWithValues] methods or
* in any other way
*
* @see onNewValue
*/
val onValueRemoved: Flow<Key>
/**
* Will set as batch [toSet] data in current repo. Must pass the data which were successfully updated in repo to
* [onNewValue]
*/
suspend fun set(toSet: Map<Key, Value>)
/**
* Will unset as batch data with keys from [toUnset]. Must pass the [Key]s which were successfully removed in repo to
* [onValueRemoved]
*/
suspend fun unset(toUnset: List<Key>)
/**
* Will unset as batch data with values from [toUnset]. Must pass the [Key]s which were successfully removed in repo
* to [onValueRemoved]
*/
suspend fun unsetWithValues(toUnset: List<Value>)
}
typealias WriteStandardKeyValueRepo<Key,Value> = WriteKeyValueRepo<Key, Value>
suspend inline fun <Key, Value> WriteKeyValueRepo<Key, Value>.set(
vararg toSet: Pair<Key, Value>
) = set(toSet.toMap())
suspend inline fun <Key, Value> WriteKeyValueRepo<Key, Value>.set(
k: Key, v: Value
) = set(k to v)
suspend inline fun <Key, Value> WriteKeyValueRepo<Key, Value>.unset(
vararg k: Key
) = unset(k.toList())
suspend inline fun <Key, Value> WriteKeyValueRepo<Key, Value>.unsetWithValues(
vararg v: Value
) = unsetWithValues(v.toList())
/**
* Full version of standard key-value repository with all set/unset/clear/get methods
*/
interface KeyValueRepo<Key, Value> : ReadKeyValueRepo<Key, Value>, WriteKeyValueRepo<Key, Value> {
/**
* By default, will walk throw all the [keys] with [Value]s from [toUnset] and run [doAllWithCurrentPaging] with
* [unset] of found data [Key]s
*/
override suspend fun unsetWithValues(toUnset: List<Value>) = toUnset.forEach { v ->
doAllWithCurrentPaging {
keys(v, it).also {
unset(it.results)
}
}
}
/**
* By default, will remove all the data of current repo using [doAllWithCurrentPaging], [keys] and [unset]
*/
suspend fun clear() {
doAllWithCurrentPaging { keys(it).also { unset(it.results) } }
}
}
typealias StandardKeyValueRepo<Key,Value> = KeyValueRepo<Key, Value>
class DelegateBasedKeyValueRepo<Key, Value>(
readDelegate: ReadKeyValueRepo<Key, Value>,
writeDelegate: WriteKeyValueRepo<Key, Value>
) : KeyValueRepo<Key, Value>,
ReadKeyValueRepo<Key, Value> by readDelegate,
WriteKeyValueRepo<Key, Value> by writeDelegate

View File

@@ -6,6 +6,7 @@ import kotlinx.coroutines.flow.Flow
interface ReadCRUDRepo<ObjectType, IdType> : Repo {
suspend fun getByPagination(pagination: Pagination): PaginationResult<ObjectType>
suspend fun getIdsByPagination(pagination: Pagination): PaginationResult<IdType>
suspend fun getById(id: IdType): ObjectType?
suspend fun contains(id: IdType): Boolean
suspend fun count(): Long

View File

@@ -1,63 +0,0 @@
package dev.inmo.micro_utils.repos
import dev.inmo.micro_utils.pagination.*
import dev.inmo.micro_utils.pagination.utils.doAllWithCurrentPaging
import kotlinx.coroutines.flow.Flow
interface ReadKeyValueRepo<Key, Value> : Repo {
suspend fun get(k: Key): Value?
suspend fun values(pagination: Pagination, reversed: Boolean = false): PaginationResult<Value>
suspend fun keys(pagination: Pagination, reversed: Boolean = false): PaginationResult<Key>
suspend fun keys(v: Value, pagination: Pagination, reversed: Boolean = false): PaginationResult<Key>
suspend fun contains(key: Key): Boolean
suspend fun count(): Long
}
typealias ReadStandardKeyValueRepo<Key,Value> = ReadKeyValueRepo<Key, Value>
interface WriteKeyValueRepo<Key, Value> : Repo {
val onNewValue: Flow<Pair<Key, Value>>
val onValueRemoved: Flow<Key>
suspend fun set(toSet: Map<Key, Value>)
suspend fun unset(toUnset: List<Key>)
suspend fun unsetWithValues(toUnset: List<Value>)
}
typealias WriteStandardKeyValueRepo<Key,Value> = WriteKeyValueRepo<Key, Value>
suspend inline fun <Key, Value> WriteKeyValueRepo<Key, Value>.set(
vararg toSet: Pair<Key, Value>
) = set(toSet.toMap())
suspend inline fun <Key, Value> WriteKeyValueRepo<Key, Value>.set(
k: Key, v: Value
) = set(k to v)
suspend inline fun <Key, Value> WriteKeyValueRepo<Key, Value>.unset(
vararg k: Key
) = unset(k.toList())
suspend inline fun <Key, Value> WriteKeyValueRepo<Key, Value>.unsetWithValues(
vararg v: Value
) = unsetWithValues(v.toList())
interface KeyValueRepo<Key, Value> : ReadKeyValueRepo<Key, Value>, WriteKeyValueRepo<Key, Value> {
override suspend fun unsetWithValues(toUnset: List<Value>) = toUnset.forEach { v ->
doAllWithCurrentPaging {
keys(v, it).also {
unset(it.results)
}
}
}
suspend fun clear() {
doAllWithCurrentPaging { keys(it).also { unset(it.results) } }
}
}
typealias StandardKeyValueRepo<Key,Value> = KeyValueRepo<Key, Value>
class DelegateBasedKeyValueRepo<Key, Value>(
readDelegate: ReadKeyValueRepo<Key, Value>,
writeDelegate: WriteKeyValueRepo<Key, Value>
) : KeyValueRepo<Key, Value>,
ReadKeyValueRepo<Key, Value> by readDelegate,
WriteKeyValueRepo<Key, Value> by writeDelegate

View File

@@ -20,6 +20,14 @@ open class MapperReadCRUDRepo<FromId, FromRegistered, ToId, ToRegistered>(
)
}
override suspend fun getIdsByPagination(pagination: Pagination): PaginationResult<FromId> = to.getIdsByPagination(
pagination
).let {
it.changeResultsUnchecked(
it.results.map { it.toInnerKey() }
)
}
override suspend fun count(): Long = to.count()
override suspend fun contains(id: FromId): Boolean = to.contains(id.toOutKey())

View File

@@ -16,6 +16,7 @@ abstract class AbstractAndroidCRUDRepo<ObjectType, IdType>(
protected abstract val tableName: String
protected abstract val idColumnName: String
protected abstract suspend fun Cursor.toObject(): ObjectType
protected abstract suspend fun Cursor.toId(): IdType
protected fun SQLiteDatabase.count(): Long = select(tableName).use {
it.count
}.toLong()
@@ -64,4 +65,23 @@ abstract class AbstractAndroidCRUDRepo<ObjectType, IdType>(
}
}
}
override suspend fun getIdsByPagination(pagination: Pagination): PaginationResult<IdType> {
return helper.readableTransaction {
select(
tableName,
limit = pagination.limitClause()
).use {
if (it.moveToFirst()) {
val resultList = mutableListOf(it.toId())
while (it.moveToNext()) {
resultList.add(it.toId())
}
resultList.createPaginationResult(pagination, count())
} else {
emptyList<IdType>().createPaginationResult(pagination, 0)
}
}
}
}
}

View File

@@ -22,6 +22,17 @@ abstract class AbstractExposedReadCRUDRepo<ObjectType, IdType>(
)
}
}
override suspend fun getIdsByPagination(pagination: Pagination): PaginationResult<IdType> {
return transaction(db = database) {
selectAll().paginate(pagination).map {
it.asId
}.createPaginationResult(
pagination,
selectAll().count()
)
}
}
override suspend fun getById(id: IdType): ObjectType? {
return transaction(db = database) {
select {

View File

@@ -50,14 +50,6 @@ abstract class AbstractExposedWriteCRUDRepo<ObjectType, IdType, InputValueType>(
val id = createAndInsertId(value, it)
update(id, value, it as UpdateBuilder<Int>)
}
@Deprecated(
"Replace its \"it\" parameter type with \"UpdateBuilder<Int>\" to actualize method signature. Method with current signature will be removed soon and do not recommended to override anymore"
)
protected open fun update(id: IdType, value: InputValueType, it: UpdateStatement) = update(
id,
value,
it as UpdateBuilder<Int>
)
protected open suspend fun onBeforeCreate(value: List<InputValueType>) {}
@@ -137,9 +129,7 @@ abstract class AbstractExposedWriteCRUDRepo<ObjectType, IdType, InputValueType>(
override suspend fun deleteById(ids: List<IdType>) {
onBeforeDelete(ids)
transaction(db = database) {
val deleted = deleteWhere(null, null) {
selectByIds(ids)
}
val deleted = deleteWhere(null, null) { selectByIds(it, ids) }
if (deleted == ids.size) {
ids
} else {

View File

@@ -4,8 +4,9 @@ import org.jetbrains.exposed.sql.*
interface CommonExposedRepo<IdType, ObjectType> : ExposedRepo {
val ResultRow.asObject: ObjectType
val selectById: SqlExpressionBuilder.(IdType) -> Op<Boolean>
val selectByIds: SqlExpressionBuilder.(List<IdType>) -> Op<Boolean>
val ResultRow.asId: IdType
val selectById: ISqlExpressionBuilder.(IdType) -> Op<Boolean>
val selectByIds: ISqlExpressionBuilder.(List<IdType>) -> Op<Boolean>
get() = { list ->
if (list.isEmpty()) {
Op.FALSE

View File

@@ -27,15 +27,6 @@ abstract class AbstractExposedKeyValueRepo<Key, Value>(
update(k, v, it as UpdateBuilder<Int>)
}
@Deprecated(
"Replace its \"it\" parameter type with \"UpdateBuilder<Int>\" to actualize method signature. Method with current signature will be removed soon and do not recommended to override anymore"
)
protected open fun update(k: Key, v: Value, it: UpdateStatement) = update(
k,
v,
it as UpdateBuilder<Int>
)
override suspend fun set(toSet: Map<Key, Value>) {
transaction(database) {
toSet.mapNotNull { (k, v) ->
@@ -59,9 +50,9 @@ abstract class AbstractExposedKeyValueRepo<Key, Value>(
override suspend fun unset(toUnset: List<Key>) {
transaction(database) {
toUnset.mapNotNull {
if (deleteWhere { selectById(it) } > 0) {
it
toUnset.mapNotNull { item ->
if (deleteWhere { selectById(it, item) } > 0) {
item
} else {
null
}
@@ -75,7 +66,7 @@ abstract class AbstractExposedKeyValueRepo<Key, Value>(
transaction(database) {
toUnset.flatMap {
val keys = select { selectByValue(it) }.mapNotNull { it.asKey }
deleteWhere { selectByIds(keys) }
deleteWhere { selectByIds(it, keys) }
keys
}
}.distinct().forEach {

View File

@@ -15,8 +15,14 @@ abstract class AbstractExposedReadKeyValueRepo<Key, Value>(
CommonExposedRepo<Key, Value>,
Table(tableName ?: "") {
abstract val keyColumn: Column<*>
/**
* Same as [asId] in context of KeyValue repo
*/
abstract val ResultRow.asKey: Key
abstract val selectByValue: SqlExpressionBuilder.(Value) -> Op<Boolean>
override val ResultRow.asId: Key
get() = asKey
abstract val selectByValue: ISqlExpressionBuilder.(Value) -> Op<Boolean>
override suspend fun get(k: Key): Value? = transaction(database) {
select { selectById(k) }.limit(1).firstOrNull() ?.asObject

View File

@@ -4,6 +4,8 @@ import dev.inmo.micro_utils.repos.KeyValueRepo
import dev.inmo.micro_utils.repos.exposed.ColumnAllocator
import kotlinx.coroutines.flow.*
import org.jetbrains.exposed.sql.*
import org.jetbrains.exposed.sql.SqlExpressionBuilder.eq
import org.jetbrains.exposed.sql.SqlExpressionBuilder.inList
import org.jetbrains.exposed.sql.transactions.transaction
open class ExposedKeyValueRepo<Key, Value>(
@@ -47,9 +49,9 @@ open class ExposedKeyValueRepo<Key, Value>(
override suspend fun unset(toUnset: List<Key>) {
transaction(database) {
toUnset.mapNotNull {
if (deleteWhere { keyColumn.eq(it) } > 0) {
it
toUnset.mapNotNull { item ->
if (deleteWhere { keyColumn.eq(item) } > 0) {
item
} else {
null
}

View File

@@ -20,10 +20,10 @@ open class ExposedReadKeyValueRepo<Key, Value>(
val valueColumn: Column<Value> = valueColumnAllocator()
override val ResultRow.asKey: Key
get() = get(keyColumn)
override val selectByValue: SqlExpressionBuilder.(Value) -> Op<Boolean> = { valueColumn.eq(it) }
override val selectByValue: ISqlExpressionBuilder.(Value) -> Op<Boolean> = { valueColumn.eq(it) }
override val ResultRow.asObject: Value
get() = get(valueColumn)
override val selectById: SqlExpressionBuilder.(Key) -> Op<Boolean> = { keyColumn.eq(it) }
override val selectById: ISqlExpressionBuilder.(Key) -> Op<Boolean> = { keyColumn.eq(it) }
override val primaryKey: Table.PrimaryKey
get() = PrimaryKey(keyColumn, valueColumn)

View File

@@ -49,7 +49,7 @@ abstract class AbstractExposedKeyValuesRepo<Key, Value>(
transaction(database) {
toRemove.keys.flatMap { k ->
toRemove[k] ?.mapNotNull { v ->
if (deleteWhere { selectById(k).and(selectByValue(v)) } > 0 ) {
if (deleteWhere { selectById(it, k).and(SqlExpressionBuilder.selectByValue(v)) } > 0 ) {
k to v
} else {
null
@@ -63,7 +63,7 @@ abstract class AbstractExposedKeyValuesRepo<Key, Value>(
override suspend fun clear(k: Key) {
transaction(database) {
deleteWhere { selectById(k) }
deleteWhere { selectById(it, k) }
}.also { _onDataCleared.emit(k) }
}
}

View File

@@ -17,7 +17,9 @@ abstract class AbstractExposedReadKeyValuesRepo<Key, Value>(
Table(tableName ?: "") {
abstract val keyColumn: Column<*>
abstract val ResultRow.asKey: Key
abstract val selectByValue: SqlExpressionBuilder.(Value) -> Op<Boolean>
override val ResultRow.asId: Key
get() = asKey
abstract val selectByValue: ISqlExpressionBuilder.(Value) -> Op<Boolean>
override suspend fun count(k: Key): Long = transaction(database) { select { selectById(k) }.count() }

View File

@@ -4,6 +4,7 @@ import dev.inmo.micro_utils.repos.KeyValuesRepo
import dev.inmo.micro_utils.repos.exposed.ColumnAllocator
import kotlinx.coroutines.flow.*
import org.jetbrains.exposed.sql.*
import org.jetbrains.exposed.sql.SqlExpressionBuilder.eq
import org.jetbrains.exposed.sql.transactions.transaction
typealias ExposedOneToManyKeyValueRepo1<Key, Value> = ExposedKeyValuesRepo<Key, Value>

View File

@@ -15,10 +15,10 @@ open class ExposedReadKeyValuesRepo<Key, Value>(
override val keyColumn: Column<Key> = keyColumnAllocator()
override val ResultRow.asKey: Key
get() = get(keyColumn)
override val selectByValue: SqlExpressionBuilder.(Value) -> Op<Boolean> = { valueColumn.eq(it) }
override val selectByValue: ISqlExpressionBuilder.(Value) -> Op<Boolean> = { valueColumn.eq(it) }
override val ResultRow.asObject: Value
get() = get(valueColumn)
override val selectById: SqlExpressionBuilder.(Key) -> Op<Boolean> = { keyColumn.eq(it) }
override val selectById: ISqlExpressionBuilder.(Key) -> Op<Boolean> = { keyColumn.eq(it) }
val valueColumn: Column<Value> = valueColumnAllocator()
init { initTable() }

View File

@@ -15,6 +15,13 @@ class ReadMapCRUDRepo<ObjectType, IdType>(
)
}
override suspend fun getIdsByPagination(pagination: Pagination): PaginationResult<IdType> {
return map.keys.drop(pagination.firstIndex).take(pagination.size).createPaginationResult(
pagination,
count()
)
}
override suspend fun getById(id: IdType): ObjectType? = map[id]
override suspend fun contains(id: IdType): Boolean = map.containsKey(id)

View File

@@ -28,6 +28,7 @@ class KtorCRUDRepoClient<ObjectType, IdType, InputValue> (
httpClient,
typeInfo<ObjectType>(),
typeInfo<PaginationResult<ObjectType>>(),
typeInfo<PaginationResult<IdType>>(),
contentType,
idSerializer
),

View File

@@ -19,6 +19,7 @@ class KtorReadCRUDRepoClient<ObjectType, IdType> (
private val httpClient: HttpClient,
private val objectType: TypeInfo,
private val paginationObjectType: TypeInfo,
private val paginationIdType: TypeInfo,
private val contentType: ContentType,
private val idSerializer: suspend (IdType) -> String
) : ReadCRUDRepo<ObjectType, IdType> {
@@ -27,6 +28,11 @@ class KtorReadCRUDRepoClient<ObjectType, IdType> (
) {
contentType(contentType)
}.body(paginationObjectType)
override suspend fun getIdsByPagination(pagination: Pagination): PaginationResult<IdType> = httpClient.get(
buildStandardUrl(baseUrl, getIdsByPaginationRouting, pagination.asUrlQueryParts)
) {
contentType(contentType)
}.body(paginationIdType)
override suspend fun getById(id: IdType): ObjectType? = httpClient.get(
buildStandardUrl(
@@ -72,6 +78,7 @@ inline fun <reified ObjectType, IdType> KtorReadCRUDRepoClient(
httpClient,
typeInfo<ObjectType>(),
typeInfo<PaginationResult<ObjectType>>(),
typeInfo<PaginationResult<IdType>>(),
contentType,
idSerializer
)

View File

@@ -1,5 +1,6 @@
package dev.inmo.micro_utils.repos.ktor.common.crud
const val getByPaginationRouting = "getByPagination"
const val getIdsByPaginationRouting = "getIdsByPagination"
const val getByIdRouting = "getById"
const val containsRouting = "contains"

View File

@@ -23,6 +23,11 @@ inline fun <reified ObjectType, reified IdType> Route.configureReadCRUDRepoRoute
call.respond(originalRepo.getByPagination(pagination))
}
get(getIdsByPaginationRouting) {
val pagination = call.request.queryParameters.extractPagination
call.respond(originalRepo.getIdsByPagination(pagination))
}
get(getByIdRouting) {
val id = idDeserializer(

17
safe_wrapper/build.gradle Normal file
View File

@@ -0,0 +1,17 @@
plugins {
id "org.jetbrains.kotlin.multiplatform"
id "org.jetbrains.kotlin.plugin.serialization"
id "com.android.library"
}
apply from: "$mppProjectWithSerializationPresetPath"
kotlin {
sourceSets {
commonMain {
dependencies {
api project(":micro_utils.coroutines")
}
}
}
}

View File

@@ -0,0 +1,17 @@
package dev.inmo.micro_utils.safe_wrapper
import dev.inmo.micro_utils.coroutines.runCatchingSafely
interface SafeWrapper<T> {
fun <R> safe(block: T.() -> R): Result<R> = unsafeTarget().runCatching(block)
fun <R> unsafe(block: T.() -> R): R = unsafeTarget().block()
suspend fun <R> safeS(block: suspend T.() -> R): Result<R> = unsafeTarget().runCatchingSafely(block = block)
suspend fun <R> unsafeS(block: suspend T.() -> R): R = unsafeTarget().block()
fun unsafeTarget(): T
class Default<T>(private val t: T) : SafeWrapper<T> { override fun unsafeTarget(): T = t }
companion object {
operator fun <T> invoke(t: T) = Default(t)
}
}

View File

@@ -0,0 +1 @@
<manifest package="dev.inmo.micro_utils.safe_wrapper"/>

View File

@@ -4,6 +4,7 @@ String[] includes = [
":common",
":common:compose",
":matrix",
":safe_wrapper",
":crypto",
":koin",
":selector:common",
@@ -32,6 +33,8 @@ String[] includes = [
":serialization:base64",
":serialization:encapsulator",
":serialization:typed_serializer",
":startup:plugin",
":startup:launcher",
":fsm:common",
":fsm:repos:common",

View File

@@ -0,0 +1,31 @@
plugins {
id "org.jetbrains.kotlin.multiplatform"
id "org.jetbrains.kotlin.plugin.serialization"
id "application"
}
apply from: "$mppJavaProjectPresetPath"
kotlin {
sourceSets {
commonMain {
dependencies {
api internalProject("micro_utils.startup.plugin")
}
}
jvmTest {
dependencies {
implementation libs.kt.coroutines.test
}
}
}
}
application {
mainClassName = "dev.inmo.micro_utils.startup.launcher.MainKt"
}
java {
sourceCompatibility = JavaVersion.VERSION_1_8
targetCompatibility = JavaVersion.VERSION_1_8
}

View File

@@ -0,0 +1,22 @@
package dev.inmo.micro_utils.startup.launcher
import dev.inmo.micro_utils.startup.plugin.StartPlugin
import kotlinx.serialization.Serializable
/**
* Contains just [List] of [StartPlugin]s. In json this config should look like:
*
* ```json
* {
* "plugins": [
* "dev.inmo.micro_utils.startup.launcher.HelloWorldPlugin"
* ]
* }
* ```
*
* In the sample above [HelloWorldPlugin] will be loaded during startup of application
*/
@Serializable
data class Config(
val plugins: List<StartPlugin>
)

View File

@@ -0,0 +1,7 @@
package dev.inmo.micro_utils.startup.launcher
import kotlinx.serialization.json.Json
val defaultJson = Json {
ignoreUnknownKeys = true
}

View File

@@ -0,0 +1,13 @@
package dev.inmo.micro_utils.startup.launcher
import dev.inmo.kslog.common.i
import dev.inmo.kslog.common.logger
import dev.inmo.micro_utils.startup.plugin.StartPlugin
import org.koin.core.Koin
object HelloWorldPlugin : StartPlugin {
override suspend fun startPlugin(koin: Koin) {
super.startPlugin(koin)
logger.i("Hello world")
}
}

View File

@@ -0,0 +1,31 @@
package dev.inmo.micro_utils.startup.launcher
import dev.inmo.kslog.common.i
import kotlinx.serialization.json.JsonObject
import org.koin.core.KoinApplication
import org.koin.core.context.GlobalContext
import org.koin.dsl.module
/**
* Will create [KoinApplication], init, load modules using [StartLauncherPlugin] and start plugins using the same base
* plugin
*
* @param rawConfig It is expected that this [JsonObject] will contain serialized [Config] ([StartLauncherPlugin] will
* deserialize it in its [StartLauncherPlugin.setupDI]
*/
suspend fun start(rawConfig: JsonObject) {
with(StartLauncherPlugin) {
logger.i("Start initialization")
val koinApp = KoinApplication.init()
koinApp.modules(
module {
setupDI(rawConfig)
}
)
logger.i("Modules loaded")
GlobalContext.startKoin(koinApp)
logger.i("Koin started")
startPlugin(koinApp.koin)
logger.i("App has been setup")
}
}

View File

@@ -0,0 +1,76 @@
package dev.inmo.micro_utils.startup.launcher
import dev.inmo.kslog.common.i
import dev.inmo.kslog.common.taggedLogger
import dev.inmo.kslog.common.w
import dev.inmo.micro_utils.coroutines.runCatchingSafely
import dev.inmo.micro_utils.startup.plugin.StartPlugin
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.joinAll
import kotlinx.coroutines.launch
import kotlinx.serialization.SerialFormat
import kotlinx.serialization.StringFormat
import kotlinx.serialization.json.JsonObject
import org.koin.core.Koin
import org.koin.core.module.Module
import org.koin.dsl.binds
import org.koin.dsl.module
/**
* Default startup plugin. See [setupDI] and [startPlugin] for more info
*/
object StartLauncherPlugin : StartPlugin {
internal val logger = taggedLogger(this)
/**
* Will deserialize [Config] from [config], register it in receiver [Module] (as well as [CoroutineScope] and
* [kotlinx.serialization.json.Json])
*
* Besides, in this method will be called [StartPlugin.setupDI] on each plugin from [Config.plugins]. In case when
* some plugin will not be loaded correctly it will be reported throw the [logger]
*/
override fun Module.setupDI(config: JsonObject) {
val pluginsConfig = defaultJson.decodeFromJsonElement(Config.serializer(), config)
single { pluginsConfig }
single { CoroutineScope(Dispatchers.Default) }
single { defaultJson } binds arrayOf(StringFormat::class, SerialFormat::class)
includes(
pluginsConfig.plugins.mapNotNull {
runCatching {
module {
with(it) {
setupDI(config)
}
}
}.onFailure { e ->
logger.w("Unable to load DI part of $it", e)
}.getOrNull()
}
)
}
/**
* Takes [CoroutineScope] and [Config] from the [koin], and call starting of each plugin from [Config.plugins]
* ASYNCHRONOUSLY. Just like in [setupDI], in case of fail in some plugin it will be reported using [logger]
*/
override suspend fun startPlugin(koin: Koin) {
val scope = koin.get<CoroutineScope>()
koin.get<Config>().plugins.map { plugin ->
scope.launch {
runCatchingSafely {
logger.i("Start loading of $plugin")
with(plugin) {
startPlugin(koin)
}
}.onFailure { e ->
logger.w("Unable to load bot part of $plugin", e)
}.onSuccess {
logger.i("Complete loading of $plugin")
}
}
}.joinAll()
}
}

View File

@@ -0,0 +1,37 @@
package dev.inmo.micro_utils.startup.launcher
import dev.inmo.kslog.common.KSLog
import dev.inmo.kslog.common.i
import kotlinx.serialization.json.jsonObject
import java.io.File
/**
* It is expected, that [args] will contain ONE argument with path to the config json. Sample of launching:
*
* ```bash
* ./gradlew run --args="sample.config.json"
* ```
*
* Content of `sample.config.json` described in [Config] KDocs.
*
* You may build runnable app using:
*
* ```bash
* ./gradlew assembleDist
* ```
*
* In that case in `build/distributions` folder you will be able to find zip and tar files with all required
* tools for application running (via their `bin/app_name` binary). In that case yoy will not need to pass
* `--args=...` and launch will look like `./bin/app_name sample.config.json`
*/
suspend fun main(args: Array<String>) {
KSLog.default = KSLog("ServerLauncher")
val (configPath) = args
val file = File(configPath)
KSLog.i("Start read config from ${file.absolutePath}")
val json = defaultJson.parseToJsonElement(file.readText()).jsonObject
KSLog.i("Config has been read")
start(json)
}

View File

@@ -0,0 +1,46 @@
import dev.inmo.micro_utils.coroutines.launchSynchronously
import dev.inmo.micro_utils.startup.launcher.Config
import dev.inmo.micro_utils.startup.launcher.HelloWorldPlugin
import dev.inmo.micro_utils.startup.launcher.defaultJson
import dev.inmo.micro_utils.startup.launcher.start
import kotlinx.coroutines.launch
import kotlinx.coroutines.test.runTest
import kotlinx.serialization.json.jsonObject
import org.koin.core.context.GlobalContext
import kotlin.test.BeforeTest
import kotlin.test.Test
class StartupLaunchingTests {
@BeforeTest
fun resetGlobalKoinContext() {
kotlin.runCatching { GlobalContext.stopKoin() }
}
@Test(timeout = 60000L)
fun CheckThatEmptyPluginsListLeadsToEndOfMain() {
val emptyJson = defaultJson.encodeToJsonElement(
Config.serializer(),
Config(emptyList())
).jsonObject
runTest {
val job = launch {
start(emptyJson)
}
job.join()
}
}
@Test(timeout = 60000L)
fun CheckThatHelloWorldPluginsListLeadsToEndOfMain() {
val emptyJson = defaultJson.encodeToJsonElement(
Config.serializer(),
Config(listOf(HelloWorldPlugin))
).jsonObject
runTest {
val job = launch {
start(emptyJson)
}
job.join()
}
}
}

View File

@@ -0,0 +1,20 @@
plugins {
id "org.jetbrains.kotlin.multiplatform"
id "org.jetbrains.kotlin.plugin.serialization"
}
apply from: "$mppJavaProjectPresetPath"
kotlin {
sourceSets {
commonMain {
dependencies {
api libs.koin
api libs.kt.serialization
api libs.kslog
api libs.kt.reflect
api project(":micro_utils.coroutines")
}
}
}
}

View File

@@ -0,0 +1,31 @@
package dev.inmo.micro_utils.startup.plugin
import kotlinx.serialization.Serializable
import kotlinx.serialization.json.JsonObject
import org.koin.core.Koin
import org.koin.core.module.Module
/**
* Default plugin for start of your app
*/
@Serializable(StartPluginSerializer::class)
interface StartPlugin {
/**
* This method will be called first to configure [Koin] [Module] related to this plugin. You may use
* [org.koin.core.scope.Scope.get] in your koin definitions like [Module.single] to retrieve
* [kotlinx.coroutines.CoroutineScope], [kotlinx.serialization.json.Json] or [dev.inmo.micro_utils.startup.launcher.Config]
*/
fun Module.setupDI(config: JsonObject) {}
/**
* This method will be called after all other [StartPlugin] will [setupDI]
*
* It is allowed to lock end of this method in case you require to prevent application to end its run (for example,
* you are starting some web server)
*
* @param koin Will contains everything you will register in [setupDI] (as well as other [StartPlugin]s) and
* [kotlinx.coroutines.CoroutineScope], [kotlinx.serialization.json.Json] and [dev.inmo.micro_utils.startup.launcher.Config]
* by their types
*/
suspend fun startPlugin(koin: Koin) {}
}

View File

@@ -0,0 +1,5 @@
package dev.inmo.micro_utils.startup.plugin
import kotlinx.serialization.KSerializer
expect object StartPluginSerializer : KSerializer<StartPlugin>

View File

@@ -0,0 +1,23 @@
package dev.inmo.micro_utils.startup.plugin
import kotlinx.serialization.KSerializer
import kotlinx.serialization.builtins.serializer
import kotlinx.serialization.descriptors.SerialDescriptor
import kotlinx.serialization.encoding.Decoder
import kotlinx.serialization.encoding.Encoder
actual object StartPluginSerializer : KSerializer<StartPlugin> {
override val descriptor: SerialDescriptor
get() = String.serializer().descriptor
override fun deserialize(decoder: Decoder): StartPlugin {
val kclass = Class.forName(decoder.decodeString()).kotlin
return (kclass.objectInstance ?: kclass.constructors.first { it.parameters.isEmpty() }.call()) as StartPlugin
}
override fun serialize(encoder: Encoder, value: StartPlugin) {
encoder.encodeString(
value::class.java.canonicalName
)
}
}