mirror of
https://github.com/InsanusMokrassar/MicroUtils.git
synced 2025-09-18 06:49:20 +00:00
Compare commits
84 Commits
Author | SHA1 | Date | |
---|---|---|---|
fc48446ec4 | |||
3644b83ac6 | |||
cd73791b6f | |||
03de71df2e | |||
83d5d3faf4 | |||
0c8bec4c89 | |||
7fc93817c1 | |||
d0a00031a1 | |||
6ebc5aa0c2 | |||
8a6b4bb49e | |||
20799b9a3e | |||
ec3afc615c | |||
da692ccfc3 | |||
53b89f3a18 | |||
58cded28d3 | |||
592c5f3732 | |||
f44a78a5f5 | |||
e0bdd5dfdc | |||
99c0f06b72 | |||
66fc6df3d7 | |||
a36425a905 | |||
d920fee6d4 | |||
23590be5de | |||
94acc3c93b | |||
5616326a3b | |||
7601860c5c | |||
8b43d785cc | |||
b62d3a0b7d | |||
fad73c7213 | |||
2403c7c2b0 | |||
fa090bf920 | |||
a83ee86340 | |||
204955bcce | |||
ee56e9543a | |||
96fdff6ffd | |||
58b007cbb3 | |||
4f0c139889 | |||
c584c24fce | |||
85e5cee154 | |||
5af91981f1 | |||
2fe4f08059 | |||
83796f345a | |||
c1e21364a6 | |||
067d9d0d3b | |||
03f527d83e | |||
ced05a4586 | |||
43fe06206a | |||
023657558e | |||
9b0b726c80 | |||
4ee67321c4 | |||
59f1f2e59b | |||
0766d48b7c | |||
e18903b9e9 | |||
d0eecdead2 | |||
cc4a83a033 | |||
1cf911bbde | |||
36d73d5023 | |||
c395242e3e | |||
cd9cd7cc5d | |||
acbb8a0c07 | |||
b9d8528599 | |||
4971326eca | |||
09d1047260 | |||
02dbd493c2 | |||
b17931e7bd | |||
2a4570eafc | |||
c9514d3a6d | |||
072805efc7 | |||
369ff26627 | |||
c5abbbbd2d | |||
d974639f1e | |||
26efde316b | |||
fafe50f80a | |||
41504469db | |||
03b3ddd98b | |||
89d919f2be | |||
b53cfd5504 | |||
31022733ac | |||
f9a8c39879 | |||
a812c2dd2f | |||
217e977f0d | |||
04c301d1ac | |||
7f0c425389 | |||
1ede1c423b |
3
.github/workflows/dokka_push.yml
vendored
3
.github/workflows/dokka_push.yml
vendored
@@ -11,9 +11,6 @@ jobs:
|
|||||||
- uses: actions/setup-java@v1
|
- uses: actions/setup-java@v1
|
||||||
with:
|
with:
|
||||||
java-version: 11
|
java-version: 11
|
||||||
- name: Fix android 32.0.0 dx
|
|
||||||
continue-on-error: true
|
|
||||||
run: cd /usr/local/lib/android/sdk/build-tools/32.0.0/ && mv d8 dx && cd lib && mv d8.jar dx.jar
|
|
||||||
- name: Build
|
- name: Build
|
||||||
run: ./gradlew build && ./gradlew dokkaHtml
|
run: ./gradlew build && ./gradlew dokkaHtml
|
||||||
- name: Publish KDocs
|
- name: Publish KDocs
|
||||||
|
97
CHANGELOG.md
97
CHANGELOG.md
@@ -1,5 +1,102 @@
|
|||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
|
## 0.16.7
|
||||||
|
|
||||||
|
* `Common`:
|
||||||
|
* New extensions `ifTrue`/`ifFalse`/`alsoIfTrue`/`alsoIfFalse`/`letIfTrue`/`letIfFalse`
|
||||||
|
* `Diff` now is serializable
|
||||||
|
* Add `IndexedValue` serializer
|
||||||
|
* `repeatOnFailure` extending: now you may pass any lambda to check if continue to try/do something
|
||||||
|
* `Compose`:
|
||||||
|
* New extension `MutableState.asState`
|
||||||
|
* `Coroutines`:
|
||||||
|
* `Compose`:
|
||||||
|
* All the `Flow` conversations to compose `State`/`MutableState`/`SnapshotStateList`/`List` got several new
|
||||||
|
parameters
|
||||||
|
* `Flow.toMutableState` now is deprecated in favor to `asMutableComposeState`
|
||||||
|
* `Repos`:
|
||||||
|
* `Cache`:
|
||||||
|
* New type `FullCacheRepo`
|
||||||
|
* New type `CommonCacheRepo`
|
||||||
|
* `CacheRepo` got `invalidate` method. It will fully reload `FullCacheRepo` and just clear `CommonCacheRepo`
|
||||||
|
* New extensions `KVCache.actualizeAll`
|
||||||
|
|
||||||
|
## 0.16.6
|
||||||
|
|
||||||
|
* `Startup`:
|
||||||
|
* `Launcher`:
|
||||||
|
* Improvements in `StartLauncherPlugin#start` methods
|
||||||
|
* Add opportunity to pass second argument on `JVM` platform as log level
|
||||||
|
* `Repos`:
|
||||||
|
* `Ktor`:
|
||||||
|
* `Client`:
|
||||||
|
* All clients repos got opportunity to customize their flows
|
||||||
|
* `Exposed`:
|
||||||
|
* Extensions `eqOrIsNull` and `neqOrIsNotNull` for `Column`
|
||||||
|
|
||||||
|
## 0.16.5
|
||||||
|
|
||||||
|
* `Versions`:
|
||||||
|
* `Ktor`: `2.2.1` -> `2.2.2`
|
||||||
|
|
||||||
|
## 0.16.4
|
||||||
|
|
||||||
|
* `Coroutines`:
|
||||||
|
* Create `launchInCurrentThread`
|
||||||
|
|
||||||
|
## 0.16.3
|
||||||
|
|
||||||
|
* `Startup`:
|
||||||
|
* `Launcher`:
|
||||||
|
* All starting API have been moved into `StartLauncherPlugin` and do not require serialize/deserialize cycle for now
|
||||||
|
|
||||||
|
## 0.16.2
|
||||||
|
|
||||||
|
* `Versions`:
|
||||||
|
* `Compose`: `1.2.1` -> `1.2.2`
|
||||||
|
* `Startup`:
|
||||||
|
* Module become available on `JS` target
|
||||||
|
|
||||||
|
## 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
|
## 0.14.4
|
||||||
|
|
||||||
* `Common`:
|
* `Common`:
|
||||||
|
@@ -0,0 +1,10 @@
|
|||||||
|
package dev.inmo.micro_utils.common.compose
|
||||||
|
|
||||||
|
import androidx.compose.runtime.MutableState
|
||||||
|
import androidx.compose.runtime.State
|
||||||
|
import androidx.compose.runtime.derivedStateOf
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts current [MutableState] to immutable [State] using [derivedStateOf]
|
||||||
|
*/
|
||||||
|
fun <T> MutableState<T>.asState(): State<T> = derivedStateOf { this.value }
|
@@ -2,6 +2,8 @@
|
|||||||
|
|
||||||
package dev.inmo.micro_utils.common
|
package dev.inmo.micro_utils.common
|
||||||
|
|
||||||
|
import kotlinx.serialization.Serializable
|
||||||
|
|
||||||
private inline fun <T> getObject(
|
private inline fun <T> getObject(
|
||||||
additional: MutableList<T>,
|
additional: MutableList<T>,
|
||||||
iterator: Iterator<T>
|
iterator: Iterator<T>
|
||||||
@@ -24,13 +26,14 @@ private inline fun <T> getObject(
|
|||||||
*
|
*
|
||||||
* @see calculateDiff
|
* @see calculateDiff
|
||||||
*/
|
*/
|
||||||
|
@Serializable
|
||||||
data class Diff<T> internal constructor(
|
data class Diff<T> internal constructor(
|
||||||
val removed: List<IndexedValue<T>>,
|
val removed: List<@Serializable(IndexedValueSerializer::class) IndexedValue<T>>,
|
||||||
/**
|
/**
|
||||||
* Old-New values pairs
|
* Old-New values pairs
|
||||||
*/
|
*/
|
||||||
val replaced: List<Pair<IndexedValue<T>, IndexedValue<T>>>,
|
val replaced: List<Pair<@Serializable(IndexedValueSerializer::class) IndexedValue<T>, @Serializable(IndexedValueSerializer::class) IndexedValue<T>>>,
|
||||||
val added: List<IndexedValue<T>>
|
val added: List<@Serializable(IndexedValueSerializer::class) IndexedValue<T>>
|
||||||
)
|
)
|
||||||
|
|
||||||
private inline fun <T> performChanges(
|
private inline fun <T> performChanges(
|
||||||
|
@@ -0,0 +1,43 @@
|
|||||||
|
package dev.inmo.micro_utils.common
|
||||||
|
|
||||||
|
inline fun <T> Boolean.letIfTrue(block: () -> T): T? {
|
||||||
|
return if (this) {
|
||||||
|
block()
|
||||||
|
} else {
|
||||||
|
null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
inline fun <T> Boolean.letIfFalse(block: () -> T): T? {
|
||||||
|
return if (this) {
|
||||||
|
null
|
||||||
|
} else {
|
||||||
|
block()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
inline fun Boolean.alsoIfTrue(block: () -> Unit): Boolean {
|
||||||
|
letIfTrue(block)
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
|
||||||
|
inline fun Boolean.alsoIfFalse(block: () -> Unit): Boolean {
|
||||||
|
letIfFalse(block)
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
|
||||||
|
inline fun <T> Boolean.ifTrue(block: () -> T): T? {
|
||||||
|
return if (this) {
|
||||||
|
block()
|
||||||
|
} else {
|
||||||
|
null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
inline fun <T> Boolean.ifFalse(block: () -> T): T? {
|
||||||
|
return if (this) {
|
||||||
|
null
|
||||||
|
} else {
|
||||||
|
block()
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,30 @@
|
|||||||
|
package dev.inmo.micro_utils.common
|
||||||
|
|
||||||
|
import kotlinx.serialization.KSerializer
|
||||||
|
import kotlinx.serialization.Serializer
|
||||||
|
import kotlinx.serialization.builtins.PairSerializer
|
||||||
|
import kotlinx.serialization.builtins.serializer
|
||||||
|
import kotlinx.serialization.descriptors.SerialDescriptor
|
||||||
|
import kotlinx.serialization.encoding.Decoder
|
||||||
|
import kotlinx.serialization.encoding.Encoder
|
||||||
|
|
||||||
|
class IndexedValueSerializer<T>(private val subSerializer: KSerializer<T>) : KSerializer<IndexedValue<T>> {
|
||||||
|
private val originalSerializer = PairSerializer(Int.serializer(), subSerializer)
|
||||||
|
override val descriptor: SerialDescriptor
|
||||||
|
get() = originalSerializer.descriptor
|
||||||
|
|
||||||
|
override fun deserialize(decoder: Decoder): IndexedValue<T> {
|
||||||
|
val pair = originalSerializer.deserialize(decoder)
|
||||||
|
return IndexedValue(
|
||||||
|
pair.first,
|
||||||
|
pair.second
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun serialize(encoder: Encoder, value: IndexedValue<T>) {
|
||||||
|
originalSerializer.serialize(
|
||||||
|
encoder,
|
||||||
|
Pair(value.index, value.value)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
@@ -1,5 +1,27 @@
|
|||||||
package dev.inmo.micro_utils.common
|
package dev.inmo.micro_utils.common
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Executes the given [action] until getting of successful result specified number of [times].
|
||||||
|
*
|
||||||
|
* A zero-based index of current iteration is passed as a parameter to [action].
|
||||||
|
*/
|
||||||
|
inline fun <R> repeatOnFailure(
|
||||||
|
onFailure: (Throwable) -> Boolean,
|
||||||
|
action: () -> R
|
||||||
|
): Result<R> {
|
||||||
|
do {
|
||||||
|
runCatching {
|
||||||
|
action()
|
||||||
|
}.onFailure {
|
||||||
|
if (!onFailure(it)) {
|
||||||
|
return Result.failure(it)
|
||||||
|
}
|
||||||
|
}.onSuccess {
|
||||||
|
return Result.success(it)
|
||||||
|
}
|
||||||
|
} while (true)
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Executes the given [action] until getting of successful result specified number of [times].
|
* Executes the given [action] until getting of successful result specified number of [times].
|
||||||
*
|
*
|
||||||
@@ -10,12 +32,23 @@ inline fun <R> repeatOnFailure(
|
|||||||
onEachFailure: (Throwable) -> Unit = {},
|
onEachFailure: (Throwable) -> Unit = {},
|
||||||
action: (Int) -> R
|
action: (Int) -> R
|
||||||
): Optional<R> {
|
): Optional<R> {
|
||||||
repeat(times) {
|
var i = 0
|
||||||
runCatching {
|
val result = repeatOnFailure(
|
||||||
action(it)
|
{
|
||||||
}.onFailure(onEachFailure).onSuccess {
|
onEachFailure(it)
|
||||||
return Optional.presented(it)
|
if (i < times) {
|
||||||
|
i++
|
||||||
|
true
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
) {
|
||||||
|
action(i)
|
||||||
|
}
|
||||||
|
return if (result.isSuccess) {
|
||||||
|
Optional.presented(result.getOrThrow())
|
||||||
|
} else {
|
||||||
|
Optional.absent()
|
||||||
}
|
}
|
||||||
return Optional.absent()
|
|
||||||
}
|
}
|
||||||
|
@@ -22,6 +22,7 @@ kotlin {
|
|||||||
dependencies {
|
dependencies {
|
||||||
api libs.kt.coroutines.android
|
api libs.kt.coroutines.android
|
||||||
}
|
}
|
||||||
|
dependsOn(jvmMain)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -3,24 +3,58 @@ package dev.inmo.micro_utils.coroutines.compose
|
|||||||
import androidx.compose.runtime.*
|
import androidx.compose.runtime.*
|
||||||
import androidx.compose.runtime.snapshots.SnapshotStateList
|
import androidx.compose.runtime.snapshots.SnapshotStateList
|
||||||
import dev.inmo.micro_utils.common.applyDiff
|
import dev.inmo.micro_utils.common.applyDiff
|
||||||
|
import dev.inmo.micro_utils.coroutines.ExceptionHandler
|
||||||
|
import dev.inmo.micro_utils.coroutines.defaultSafelyWithoutExceptionHandlerWithNull
|
||||||
import dev.inmo.micro_utils.coroutines.subscribeSafelyWithoutExceptions
|
import dev.inmo.micro_utils.coroutines.subscribeSafelyWithoutExceptions
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.flow.Flow
|
import kotlinx.coroutines.flow.Flow
|
||||||
import kotlinx.coroutines.flow.StateFlow
|
import kotlinx.coroutines.flow.StateFlow
|
||||||
|
import kotlinx.coroutines.withContext
|
||||||
|
import kotlin.coroutines.CoroutineContext
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Each value of [this] [Flow] will trigger [applyDiff] to the result [SnapshotStateList]
|
||||||
|
*
|
||||||
|
* @param scope Will be used to [subscribeSafelyWithoutExceptions] on [this] to update returned [SnapshotStateList]
|
||||||
|
* @param useContextOnChange Will be used to change context inside of [subscribeSafelyWithoutExceptions] to ensure that
|
||||||
|
* change will happen in the required [CoroutineContext]. [Dispatchers.Main] by default
|
||||||
|
* @param onException Will be passed to the [subscribeSafelyWithoutExceptions] as uncaught exceptions handler
|
||||||
|
*/
|
||||||
@Suppress("NOTHING_TO_INLINE")
|
@Suppress("NOTHING_TO_INLINE")
|
||||||
inline fun <reified T> Flow<List<T>>.asMutableComposeListState(
|
inline fun <reified T> Flow<List<T>>.asMutableComposeListState(
|
||||||
scope: CoroutineScope
|
scope: CoroutineScope,
|
||||||
|
useContextOnChange: CoroutineContext? = Dispatchers.Main,
|
||||||
|
noinline onException: ExceptionHandler<List<T>?> = defaultSafelyWithoutExceptionHandlerWithNull,
|
||||||
): SnapshotStateList<T> {
|
): SnapshotStateList<T> {
|
||||||
val state = mutableStateListOf<T>()
|
val state = mutableStateListOf<T>()
|
||||||
subscribeSafelyWithoutExceptions(scope) {
|
val changeBlock: suspend (List<T>) -> Unit = useContextOnChange ?.let {
|
||||||
|
{
|
||||||
|
withContext(useContextOnChange) {
|
||||||
|
state.applyDiff(it)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} ?: {
|
||||||
state.applyDiff(it)
|
state.applyDiff(it)
|
||||||
}
|
}
|
||||||
|
subscribeSafelyWithoutExceptions(scope, onException, changeBlock)
|
||||||
return state
|
return state
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* In fact, it is just classcast of [asMutableComposeListState] to [List]
|
||||||
|
*
|
||||||
|
* @param scope Will be used to [subscribeSafelyWithoutExceptions] on [this] to update returned [List]
|
||||||
|
* @param useContextOnChange Will be used to change context inside of [subscribeSafelyWithoutExceptions] to ensure that
|
||||||
|
* change will happen in the required [CoroutineContext]. [Dispatchers.Main] by default
|
||||||
|
* @param onException Will be passed to the [subscribeSafelyWithoutExceptions] as uncaught exceptions handler
|
||||||
|
*
|
||||||
|
* @return Changing in time [List] which follow [Flow] values
|
||||||
|
*/
|
||||||
@Suppress("NOTHING_TO_INLINE")
|
@Suppress("NOTHING_TO_INLINE")
|
||||||
inline fun <reified T> Flow<List<T>>.asComposeList(
|
inline fun <reified T> Flow<List<T>>.asComposeList(
|
||||||
scope: CoroutineScope
|
scope: CoroutineScope,
|
||||||
): List<T> = asMutableComposeListState(scope)
|
useContextOnChange: CoroutineContext? = Dispatchers.Main,
|
||||||
|
noinline onException: ExceptionHandler<List<T>?> = defaultSafelyWithoutExceptionHandlerWithNull,
|
||||||
|
): List<T> = asMutableComposeListState(scope, useContextOnChange, onException)
|
||||||
|
|
||||||
|
@@ -1,35 +1,94 @@
|
|||||||
package dev.inmo.micro_utils.coroutines.compose
|
package dev.inmo.micro_utils.coroutines.compose
|
||||||
|
|
||||||
import androidx.compose.runtime.*
|
import androidx.compose.runtime.*
|
||||||
|
import dev.inmo.micro_utils.common.compose.asState
|
||||||
|
import dev.inmo.micro_utils.coroutines.ExceptionHandler
|
||||||
|
import dev.inmo.micro_utils.coroutines.defaultSafelyWithoutExceptionHandlerWithNull
|
||||||
|
import dev.inmo.micro_utils.coroutines.doInUI
|
||||||
import dev.inmo.micro_utils.coroutines.subscribeSafelyWithoutExceptions
|
import dev.inmo.micro_utils.coroutines.subscribeSafelyWithoutExceptions
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.flow.Flow
|
import kotlinx.coroutines.flow.Flow
|
||||||
import kotlinx.coroutines.flow.StateFlow
|
import kotlinx.coroutines.flow.StateFlow
|
||||||
|
import kotlinx.coroutines.withContext
|
||||||
|
import kotlin.coroutines.CoroutineContext
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Will map [this] [Flow] as [MutableState]. Returned [MutableState] WILL NOT change source [Flow]
|
||||||
|
*
|
||||||
|
* @param initial First value which will be passed to the result [MutableState]
|
||||||
|
* @param scope Will be used to [subscribeSafelyWithoutExceptions] on [this] to update returned [MutableState]
|
||||||
|
* @param useContextOnChange Will be used to change context inside of [subscribeSafelyWithoutExceptions] to ensure that
|
||||||
|
* change will happen in the required [CoroutineContext]. [Dispatchers.Main] by default
|
||||||
|
* @param onException Will be passed to the [subscribeSafelyWithoutExceptions] as uncaught exceptions handler
|
||||||
|
*/
|
||||||
fun <T> Flow<T>.asMutableComposeState(
|
fun <T> Flow<T>.asMutableComposeState(
|
||||||
initial: T,
|
initial: T,
|
||||||
scope: CoroutineScope
|
scope: CoroutineScope,
|
||||||
|
useContextOnChange: CoroutineContext? = Dispatchers.Main,
|
||||||
|
onException: ExceptionHandler<T?> = defaultSafelyWithoutExceptionHandlerWithNull,
|
||||||
): MutableState<T> {
|
): MutableState<T> {
|
||||||
val state = mutableStateOf(initial)
|
val state = mutableStateOf(initial)
|
||||||
subscribeSafelyWithoutExceptions(scope) { state.value = it }
|
val changeBlock: suspend (T) -> Unit = useContextOnChange ?.let {
|
||||||
|
{
|
||||||
|
withContext(useContextOnChange) {
|
||||||
|
state.value = it
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} ?: {
|
||||||
|
state.value = it
|
||||||
|
}
|
||||||
|
subscribeSafelyWithoutExceptions(scope, onException, block = changeBlock)
|
||||||
return state
|
return state
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Will map [this] [StateFlow] as [MutableState]. Returned [MutableState] WILL NOT change source [StateFlow].
|
||||||
|
* This conversation will pass its [StateFlow.value] as the first value
|
||||||
|
*
|
||||||
|
* @param scope Will be used to [subscribeSafelyWithoutExceptions] on [this] to update returned [MutableState]
|
||||||
|
* @param useContextOnChange Will be used to change context inside of [subscribeSafelyWithoutExceptions] to ensure that
|
||||||
|
* change will happen in the required [CoroutineContext]. [Dispatchers.Main] by default
|
||||||
|
* @param onException Will be passed to the [subscribeSafelyWithoutExceptions] as uncaught exceptions handler
|
||||||
|
*/
|
||||||
@Suppress("NOTHING_TO_INLINE")
|
@Suppress("NOTHING_TO_INLINE")
|
||||||
inline fun <T> StateFlow<T>.asMutableComposeState(
|
inline fun <T> StateFlow<T>.asMutableComposeState(
|
||||||
scope: CoroutineScope
|
scope: CoroutineScope,
|
||||||
): MutableState<T> = asMutableComposeState(value, scope)
|
useContextOnChange: CoroutineContext? = Dispatchers.Main,
|
||||||
|
noinline onException: ExceptionHandler<T?> = defaultSafelyWithoutExceptionHandlerWithNull,
|
||||||
|
): MutableState<T> = asMutableComposeState(value, scope, useContextOnChange, onException)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Will create [MutableState] using [asMutableComposeState] and use [asState] to convert it as immutable state
|
||||||
|
*
|
||||||
|
* @param initial First value which will be passed to the result [State]
|
||||||
|
* @param scope Will be used to [subscribeSafelyWithoutExceptions] on [this] to update returned [State]
|
||||||
|
* @param useContextOnChange Will be used to change context inside of [subscribeSafelyWithoutExceptions] to ensure that
|
||||||
|
* change will happen in the required [CoroutineContext]. [Dispatchers.Main] by default
|
||||||
|
* @param onException Will be passed to the [subscribeSafelyWithoutExceptions] as uncaught exceptions handler
|
||||||
|
*/
|
||||||
fun <T> Flow<T>.asComposeState(
|
fun <T> Flow<T>.asComposeState(
|
||||||
initial: T,
|
initial: T,
|
||||||
scope: CoroutineScope
|
scope: CoroutineScope,
|
||||||
|
useContextOnChange: CoroutineContext? = Dispatchers.Main,
|
||||||
|
onException: ExceptionHandler<T?> = defaultSafelyWithoutExceptionHandlerWithNull,
|
||||||
): State<T> {
|
): State<T> {
|
||||||
val state = asMutableComposeState(initial, scope)
|
val state = asMutableComposeState(initial, scope, useContextOnChange, onException)
|
||||||
return derivedStateOf { state.value }
|
return state.asState()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Will map [this] [StateFlow] as [State]. This conversation will pass its [StateFlow.value] as the first value
|
||||||
|
*
|
||||||
|
* @param scope Will be used to [subscribeSafelyWithoutExceptions] on [this] to update returned [State]
|
||||||
|
* @param useContextOnChange Will be used to change context inside of [subscribeSafelyWithoutExceptions] to ensure that
|
||||||
|
* change will happen in the required [CoroutineContext]. [Dispatchers.Main] by default
|
||||||
|
* @param onException Will be passed to the [subscribeSafelyWithoutExceptions] as uncaught exceptions handler
|
||||||
|
*/
|
||||||
@Suppress("NOTHING_TO_INLINE")
|
@Suppress("NOTHING_TO_INLINE")
|
||||||
inline fun <T> StateFlow<T>.asComposeState(
|
inline fun <T> StateFlow<T>.asComposeState(
|
||||||
scope: CoroutineScope
|
scope: CoroutineScope,
|
||||||
): State<T> = asComposeState(value, scope)
|
useContextOnChange: CoroutineContext? = Dispatchers.Main,
|
||||||
|
noinline onException: ExceptionHandler<T?> = defaultSafelyWithoutExceptionHandlerWithNull,
|
||||||
|
): State<T> = asComposeState(value, scope, useContextOnChange, onException)
|
||||||
|
|
||||||
|
@@ -7,17 +7,15 @@ import kotlinx.coroutines.CoroutineScope
|
|||||||
import kotlinx.coroutines.flow.Flow
|
import kotlinx.coroutines.flow.Flow
|
||||||
import kotlinx.coroutines.flow.StateFlow
|
import kotlinx.coroutines.flow.StateFlow
|
||||||
|
|
||||||
|
@Deprecated("Duplicated functionality", ReplaceWith("asMutableComposeState(initial, scope)", "dev.inmo.micro_utils.coroutines.compose.asMutableComposeState"))
|
||||||
fun <T> Flow<T>.toMutableState(
|
fun <T> Flow<T>.toMutableState(
|
||||||
initial: T,
|
initial: T,
|
||||||
scope: CoroutineScope
|
scope: CoroutineScope
|
||||||
): MutableState<T> {
|
): MutableState<T> = asMutableComposeState(initial, scope)
|
||||||
val state = mutableStateOf(initial)
|
|
||||||
subscribeSafelyWithoutExceptions(scope) { state.value = it }
|
|
||||||
return state
|
|
||||||
}
|
|
||||||
|
|
||||||
|
@Deprecated("Duplicated functionality", ReplaceWith("asMutableComposeState(scope)", "dev.inmo.micro_utils.coroutines.compose.asMutableComposeState"))
|
||||||
@Suppress("NOTHING_TO_INLINE")
|
@Suppress("NOTHING_TO_INLINE")
|
||||||
inline fun <T> StateFlow<T>.toMutableState(
|
inline fun <T> StateFlow<T>.toMutableState(
|
||||||
scope: CoroutineScope
|
scope: CoroutineScope
|
||||||
): MutableState<T> = toMutableState(value, scope)
|
): MutableState<T> = asMutableComposeState(scope)
|
||||||
|
|
||||||
|
@@ -115,10 +115,21 @@ suspend inline fun <T> runCatchingSafely(
|
|||||||
safely(onException, block)
|
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(
|
suspend inline fun <T> safelyWithResult(
|
||||||
noinline block: suspend CoroutineScope.() -> T
|
noinline block: suspend CoroutineScope.() -> T
|
||||||
): Result<T> = runCatchingSafely(defaultSafelyExceptionHandler, block)
|
): 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
|
* Use this handler in cases you wish to include handling of exceptions by [defaultSafelyWithoutExceptionHandler] and
|
||||||
* returning null at one time
|
* returning null at one time
|
||||||
|
@@ -0,0 +1,9 @@
|
|||||||
|
package dev.inmo.micro_utils.coroutines
|
||||||
|
|
||||||
|
import kotlinx.coroutines.CoroutineScope
|
||||||
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
|
||||||
|
fun <T> launchInCurrentThread(block: suspend CoroutineScope.() -> T): T {
|
||||||
|
val scope = CoroutineScope(Dispatchers.Unconfined)
|
||||||
|
return scope.launchSynchronously(block)
|
||||||
|
}
|
@@ -6,7 +6,7 @@ fun <T> CoroutineScope.launchSynchronously(block: suspend CoroutineScope.() -> T
|
|||||||
var result: Result<T>? = null
|
var result: Result<T>? = null
|
||||||
val objectToSynchronize = Object()
|
val objectToSynchronize = Object()
|
||||||
synchronized(objectToSynchronize) {
|
synchronized(objectToSynchronize) {
|
||||||
launch {
|
launch(start = CoroutineStart.UNDISPATCHED) {
|
||||||
result = safelyWithResult(block)
|
result = safelyWithResult(block)
|
||||||
}.invokeOnCompletion {
|
}.invokeOnCompletion {
|
||||||
synchronized(objectToSynchronize) {
|
synchronized(objectToSynchronize) {
|
||||||
|
@@ -0,0 +1,47 @@
|
|||||||
|
package dev.inmo.micro_utils.coroutines
|
||||||
|
|
||||||
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
import kotlinx.coroutines.delay
|
||||||
|
import kotlinx.coroutines.withContext
|
||||||
|
import kotlin.test.Test
|
||||||
|
import kotlin.test.assertEquals
|
||||||
|
|
||||||
|
class LaunchInCurrentThreadTests {
|
||||||
|
@Test
|
||||||
|
fun simpleTestThatLaunchInCurrentThreadWorks() {
|
||||||
|
val expectedResult = 10
|
||||||
|
val result = launchInCurrentThread {
|
||||||
|
expectedResult
|
||||||
|
}
|
||||||
|
assertEquals(expectedResult, result)
|
||||||
|
}
|
||||||
|
@Test
|
||||||
|
fun simpleTestThatSeveralLaunchInCurrentThreadWorks() {
|
||||||
|
val testData = 0 until 100
|
||||||
|
|
||||||
|
testData.forEach {
|
||||||
|
val result = launchInCurrentThread {
|
||||||
|
it
|
||||||
|
}
|
||||||
|
assertEquals(it, result)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@Test
|
||||||
|
fun simpleTestThatLaunchInCurrentThreadWillCorrectlyHandleSuspensionsWorks() {
|
||||||
|
val testData = 0 until 100
|
||||||
|
|
||||||
|
suspend fun test(data: Any): Any {
|
||||||
|
return withContext(Dispatchers.Default) {
|
||||||
|
delay(1)
|
||||||
|
data
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
testData.forEach {
|
||||||
|
val result = launchInCurrentThread {
|
||||||
|
test(it)
|
||||||
|
}
|
||||||
|
assertEquals(it, result)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -121,11 +121,11 @@ tasks.dokkaHtml {
|
|||||||
// }
|
// }
|
||||||
|
|
||||||
named("jvmMain") {
|
named("jvmMain") {
|
||||||
sourceRoots.setFrom(findSourcesWithName("jvmMain", "commonMain"))
|
sourceRoots.setFrom(findSourcesWithName("jvmMain"))
|
||||||
}
|
}
|
||||||
|
|
||||||
named("androidMain") {
|
named("androidMain") {
|
||||||
sourceRoots.setFrom(findSourcesWithName("androidMain", "commonMain"))
|
sourceRoots.setFrom(findSourcesWithName("androidMain"))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -23,6 +23,7 @@ allprojects {
|
|||||||
mppProjectWithSerializationPresetPath = "${rootProject.projectDir.absolutePath}/mppProjectWithSerialization.gradle"
|
mppProjectWithSerializationPresetPath = "${rootProject.projectDir.absolutePath}/mppProjectWithSerialization.gradle"
|
||||||
mppProjectWithSerializationAndComposePresetPath = "${rootProject.projectDir.absolutePath}/mppProjectWithSerializationAndCompose.gradle"
|
mppProjectWithSerializationAndComposePresetPath = "${rootProject.projectDir.absolutePath}/mppProjectWithSerializationAndCompose.gradle"
|
||||||
mppJavaProjectPresetPath = "${rootProject.projectDir.absolutePath}/mppJavaProject.gradle"
|
mppJavaProjectPresetPath = "${rootProject.projectDir.absolutePath}/mppJavaProject.gradle"
|
||||||
|
mppJsAndJavaProjectPresetPath = "${rootProject.projectDir.absolutePath}/mppJsAndJavaProject.gradle"
|
||||||
mppAndroidProjectPresetPath = "${rootProject.projectDir.absolutePath}/mppAndroidProject.gradle"
|
mppAndroidProjectPresetPath = "${rootProject.projectDir.absolutePath}/mppAndroidProject.gradle"
|
||||||
|
|
||||||
defaultAndroidSettingsPresetPath = "${rootProject.projectDir.absolutePath}/defaultAndroidSettings.gradle"
|
defaultAndroidSettingsPresetPath = "${rootProject.projectDir.absolutePath}/defaultAndroidSettings.gradle"
|
||||||
|
@@ -14,5 +14,5 @@ crypto_js_version=4.1.1
|
|||||||
# Project data
|
# Project data
|
||||||
|
|
||||||
group=dev.inmo
|
group=dev.inmo
|
||||||
version=0.14.4
|
version=0.16.7
|
||||||
android_code_version=165
|
android_code_version=175
|
||||||
|
@@ -4,26 +4,28 @@ kt = "1.7.20"
|
|||||||
kt-serialization = "1.4.1"
|
kt-serialization = "1.4.1"
|
||||||
kt-coroutines = "1.6.4"
|
kt-coroutines = "1.6.4"
|
||||||
|
|
||||||
jb-compose = "1.2.1"
|
kslog = "0.5.4"
|
||||||
|
|
||||||
|
jb-compose = "1.2.2"
|
||||||
jb-exposed = "0.41.1"
|
jb-exposed = "0.41.1"
|
||||||
jb-dokka = "1.7.20"
|
jb-dokka = "1.7.20"
|
||||||
|
|
||||||
klock = "3.4.0"
|
klock = "3.4.0"
|
||||||
uuid = "0.6.0"
|
uuid = "0.6.0"
|
||||||
|
|
||||||
ktor = "2.1.3"
|
ktor = "2.2.2"
|
||||||
|
|
||||||
gh-release = "2.4.1"
|
gh-release = "2.4.1"
|
||||||
|
|
||||||
koin = "3.2.2"
|
koin = "3.2.2"
|
||||||
|
|
||||||
android-gradle = "7.2.2"
|
android-gradle = "7.3.0"
|
||||||
dexcount = "3.1.0"
|
dexcount = "3.1.0"
|
||||||
|
|
||||||
android-coreKtx = "1.9.0"
|
android-coreKtx = "1.9.0"
|
||||||
android-recyclerView = "1.2.1"
|
android-recyclerView = "1.2.1"
|
||||||
android-appCompat = "1.5.1"
|
android-appCompat = "1.5.1"
|
||||||
android-fragment = "1.5.3"
|
android-fragment = "1.5.5"
|
||||||
android-espresso = "3.4.0"
|
android-espresso = "3.4.0"
|
||||||
android-test = "1.1.3"
|
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-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" }
|
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" }
|
klock = { module = "com.soywiz.korlibs.klock:klock", version.ref = "klock" }
|
||||||
uuid = { module = "com.benasher44:uuid", version.ref = "uuid" }
|
uuid = { module = "com.benasher44:uuid", version.ref = "uuid" }
|
||||||
|
@@ -19,7 +19,7 @@ import kotlinx.coroutines.isActive
|
|||||||
* connection. Must return true in case if must be reconnected. By default always reconnecting
|
* connection. Must return true in case if must be reconnected. By default always reconnecting
|
||||||
*/
|
*/
|
||||||
@Warning("This feature is internal and should not be used directly. It is can be changed without any notification and warranty on compile-time or other guaranties")
|
@Warning("This feature is internal and should not be used directly. It is can be changed without any notification and warranty on compile-time or other guaranties")
|
||||||
inline fun <reified T : Any> openBaseWebSocketFlow(
|
inline fun <T : Any> openBaseWebSocketFlow(
|
||||||
noinline checkReconnection: suspend (Throwable?) -> Boolean = { true },
|
noinline checkReconnection: suspend (Throwable?) -> Boolean = { true },
|
||||||
noinline webSocketSessionRequest: suspend SendChannel<T>.() -> Unit
|
noinline webSocketSessionRequest: suspend SendChannel<T>.() -> Unit
|
||||||
): Flow<T> {
|
): Flow<T> {
|
||||||
@@ -57,7 +57,7 @@ inline fun <reified T : Any> HttpClient.openWebSocketFlow(
|
|||||||
): Flow<T> {
|
): Flow<T> {
|
||||||
pluginOrNull(WebSockets) ?: error("Plugin $WebSockets must be installed for using createStandardWebsocketFlow")
|
pluginOrNull(WebSockets) ?: error("Plugin $WebSockets must be installed for using createStandardWebsocketFlow")
|
||||||
|
|
||||||
return openBaseWebSocketFlow<T>(checkReconnection) {
|
return openBaseWebSocketFlow(checkReconnection) {
|
||||||
val block: suspend DefaultClientWebSocketSession.() -> Unit = {
|
val block: suspend DefaultClientWebSocketSession.() -> Unit = {
|
||||||
while (isActive) {
|
while (isActive) {
|
||||||
send(receiveDeserialized<T>())
|
send(receiveDeserialized<T>())
|
||||||
|
@@ -28,6 +28,7 @@ import org.w3c.xhr.XMLHttpRequestResponseType
|
|||||||
* @param data [Map] where keys will be used as names for multipart parts and values as values. If you will pass
|
* @param data [Map] where keys will be used as names for multipart parts and values as values. If you will pass
|
||||||
* [dev.inmo.micro_utils.common.MPPFile] (File from JS or JVM platform). Also you may pass [UniUploadFileInfo] as value
|
* [dev.inmo.micro_utils.common.MPPFile] (File from JS or JVM platform). Also you may pass [UniUploadFileInfo] as value
|
||||||
* in case you wish to pass other source of multipart binary data than regular file
|
* in case you wish to pass other source of multipart binary data than regular file
|
||||||
|
* @suppress
|
||||||
*/
|
*/
|
||||||
actual suspend fun <T> HttpClient.uniUpload(
|
actual suspend fun <T> HttpClient.uniUpload(
|
||||||
url: String,
|
url: String,
|
||||||
|
@@ -27,6 +27,7 @@ import java.io.File
|
|||||||
* @param data [Map] where keys will be used as names for multipart parts and values as values. If you will pass
|
* @param data [Map] where keys will be used as names for multipart parts and values as values. If you will pass
|
||||||
* [dev.inmo.micro_utils.common.MPPFile] (File from JS or JVM platform). Also you may pass [UniUploadFileInfo] as value
|
* [dev.inmo.micro_utils.common.MPPFile] (File from JS or JVM platform). Also you may pass [UniUploadFileInfo] as value
|
||||||
* in case you wish to pass other source of multipart binary data than regular file
|
* in case you wish to pass other source of multipart binary data than regular file
|
||||||
|
* @suppress
|
||||||
*/
|
*/
|
||||||
actual suspend fun <T> HttpClient.uniUpload(
|
actual suspend fun <T> HttpClient.uniUpload(
|
||||||
url: String,
|
url: String,
|
||||||
|
@@ -78,12 +78,14 @@ private fun printLanguageCodeAndTags(
|
|||||||
indents: String = " "
|
indents: String = " "
|
||||||
): String = if (tag.subtags.isEmpty()) {
|
): String = if (tag.subtags.isEmpty()) {
|
||||||
"""${indents}${baseClassSerializerAnnotationName}
|
"""${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 {
|
} else {
|
||||||
"""
|
"""
|
||||||
${indents}${baseClassSerializerAnnotationName}
|
${indents}${baseClassSerializerAnnotationName}
|
||||||
${indents}sealed class ${tag.title} : ${parent ?.title ?: baseClassName}() {
|
${indents}sealed class ${tag.title} : ${parent ?.title ?: baseClassName}() {
|
||||||
${indents} override val code: String = "${tag.tag}"
|
${indents} override val code: String = "${tag.tag}"
|
||||||
|
${indents} override val withoutDialect: String
|
||||||
|
${indents} get() = code
|
||||||
|
|
||||||
${tag.subtags.joinToString("\n") { printLanguageCodeAndTags(it, tag, "${indents} ") }}
|
${tag.subtags.joinToString("\n") { printLanguageCodeAndTags(it, tag, "${indents} ") }}
|
||||||
|
|
||||||
@@ -104,11 +106,14 @@ import kotlinx.serialization.Serializable
|
|||||||
${baseClassSerializerAnnotationName}
|
${baseClassSerializerAnnotationName}
|
||||||
sealed class $baseClassName {
|
sealed class $baseClassName {
|
||||||
abstract val code: String
|
abstract val code: String
|
||||||
|
abstract val withoutDialect: String
|
||||||
|
|
||||||
${tags.joinToString("\n") { printLanguageCodeAndTags(it, indents = " ") } }
|
${tags.joinToString("\n") { printLanguageCodeAndTags(it, indents = " ") } }
|
||||||
|
|
||||||
$baseClassSerializerAnnotationName
|
$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
|
override fun toString() = code
|
||||||
}
|
}
|
||||||
|
File diff suppressed because it is too large
Load Diff
@@ -17,10 +17,11 @@ def fix_name(category, raw_name):
|
|||||||
result += out1
|
result += out1
|
||||||
return result
|
return result
|
||||||
|
|
||||||
|
# https://www.freeformatter.com/mime-types-list.html
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
df = pd.read_html(open('table.html', 'r'))
|
df = pd.read_html(open('table.html', 'r'))
|
||||||
mimes = []
|
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 = row[1][1]
|
||||||
mime_category = mime.split('/', 1)[0]
|
mime_category = mime.split('/', 1)[0]
|
||||||
mime_name = mime.split('/', 1)[1]
|
mime_name = mime.split('/', 1)[1]
|
||||||
@@ -37,7 +38,7 @@ if __name__ == '__main__':
|
|||||||
code2 = 'internal val knownMimeTypes: Set<MimeType> = setOf(\n'
|
code2 = 'internal val knownMimeTypes: Set<MimeType> = setOf(\n'
|
||||||
code2 += ' KnownMimeTypes.Any,\n'
|
code2 += ' KnownMimeTypes.Any,\n'
|
||||||
for key, group in grouped:
|
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)\nsealed class %s(raw: String) : MimeType, KnownMimeTypes(raw) {\n' % group_name
|
||||||
code += ' @Serializable(MimeTypeSerializer::class)\n object Any: %s ("%s/*")\n' % (group_name, key)
|
code += ' @Serializable(MimeTypeSerializer::class)\n object Any: %s ("%s/*")\n' % (group_name, key)
|
||||||
for mime in group:
|
for mime in group:
|
||||||
|
@@ -0,0 +1,3 @@
|
|||||||
|
package dev.inmo.micro_utils.mime_types
|
||||||
|
|
||||||
|
data class CustomMimeType(override val raw: String) : MimeType
|
File diff suppressed because it is too large
Load Diff
@@ -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,
|
||||||
|
)
|
@@ -0,0 +1,8 @@
|
|||||||
|
package dev.inmo.micro_utils.mime_types
|
||||||
|
|
||||||
|
import kotlinx.serialization.Serializable
|
||||||
|
|
||||||
|
@Serializable(MimeTypeSerializer::class)
|
||||||
|
interface MimeType {
|
||||||
|
val raw: String
|
||||||
|
}
|
@@ -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)
|
||||||
|
}
|
||||||
|
}
|
@@ -1,10 +1,5 @@
|
|||||||
package dev.inmo.micro_utils.mime_types
|
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 {
|
private val mimesCache = mutableMapOf<String, MimeType>().also {
|
||||||
knownMimeTypes.forEach { mimeType -> it[mimeType.raw] = mimeType }
|
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)
|
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)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
49
mppJsAndJavaProject.gradle
Normal file
49
mppJsAndJavaProject.gradle
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
project.version = "$version"
|
||||||
|
project.group = "$group"
|
||||||
|
|
||||||
|
apply from: "$publishGradlePath"
|
||||||
|
|
||||||
|
kotlin {
|
||||||
|
jvm {
|
||||||
|
compilations.main {
|
||||||
|
kotlinOptions {
|
||||||
|
jvmTarget = "1.8"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
js (IR) {
|
||||||
|
browser()
|
||||||
|
nodejs()
|
||||||
|
}
|
||||||
|
|
||||||
|
sourceSets {
|
||||||
|
commonMain {
|
||||||
|
dependencies {
|
||||||
|
implementation kotlin('stdlib')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
commonTest {
|
||||||
|
dependencies {
|
||||||
|
implementation kotlin('test-common')
|
||||||
|
implementation kotlin('test-annotations-common')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
jvmTest {
|
||||||
|
dependencies {
|
||||||
|
implementation kotlin('test-junit')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
jsTest {
|
||||||
|
dependencies {
|
||||||
|
implementation kotlin('test-js')
|
||||||
|
implementation kotlin('test-junit')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
java {
|
||||||
|
sourceCompatibility = JavaVersion.VERSION_1_8
|
||||||
|
targetCompatibility = JavaVersion.VERSION_1_8
|
||||||
|
}
|
@@ -23,7 +23,7 @@ kotlin {
|
|||||||
commonMain {
|
commonMain {
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation kotlin('stdlib')
|
implementation kotlin('stdlib')
|
||||||
implementation libs.kt.serialization
|
api libs.kt.serialization
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
commonTest {
|
commonTest {
|
||||||
|
@@ -23,7 +23,7 @@ kotlin {
|
|||||||
commonMain {
|
commonMain {
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation kotlin('stdlib')
|
implementation kotlin('stdlib')
|
||||||
implementation libs.kt.serialization
|
api libs.kt.serialization
|
||||||
implementation compose.runtime
|
implementation compose.runtime
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -10,12 +10,14 @@ open class ReadCRUDCacheRepo<ObjectType, IdType>(
|
|||||||
protected open val parentRepo: ReadCRUDRepo<ObjectType, IdType>,
|
protected open val parentRepo: ReadCRUDRepo<ObjectType, IdType>,
|
||||||
protected open val kvCache: KVCache<IdType, ObjectType>,
|
protected open val kvCache: KVCache<IdType, ObjectType>,
|
||||||
protected open val idGetter: (ObjectType) -> IdType
|
protected open val idGetter: (ObjectType) -> IdType
|
||||||
) : ReadCRUDRepo<ObjectType, IdType> by parentRepo, CacheRepo {
|
) : ReadCRUDRepo<ObjectType, IdType> by parentRepo, CommonCacheRepo {
|
||||||
override suspend fun getById(id: IdType): ObjectType? = kvCache.get(id) ?: (parentRepo.getById(id) ?.also {
|
override suspend fun getById(id: IdType): ObjectType? = kvCache.get(id) ?: (parentRepo.getById(id) ?.also {
|
||||||
kvCache.set(id, it)
|
kvCache.set(id, it)
|
||||||
})
|
})
|
||||||
|
|
||||||
override suspend fun contains(id: IdType): Boolean = kvCache.contains(id) || parentRepo.contains(id)
|
override suspend fun contains(id: IdType): Boolean = kvCache.contains(id) || parentRepo.contains(id)
|
||||||
|
|
||||||
|
override suspend fun invalidate() = kvCache.clear()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun <ObjectType, IdType> ReadCRUDRepo<ObjectType, IdType>.cached(
|
fun <ObjectType, IdType> ReadCRUDRepo<ObjectType, IdType>.cached(
|
||||||
@@ -28,7 +30,7 @@ open class WriteCRUDCacheRepo<ObjectType, IdType, InputValueType>(
|
|||||||
protected open val kvCache: KVCache<IdType, ObjectType>,
|
protected open val kvCache: KVCache<IdType, ObjectType>,
|
||||||
protected open val scope: CoroutineScope = CoroutineScope(Dispatchers.Default),
|
protected open val scope: CoroutineScope = CoroutineScope(Dispatchers.Default),
|
||||||
protected open val idGetter: (ObjectType) -> IdType
|
protected open val idGetter: (ObjectType) -> IdType
|
||||||
) : WriteCRUDRepo<ObjectType, IdType, InputValueType>, CacheRepo {
|
) : WriteCRUDRepo<ObjectType, IdType, InputValueType>, CommonCacheRepo {
|
||||||
override val newObjectsFlow: Flow<ObjectType> by parentRepo::newObjectsFlow
|
override val newObjectsFlow: Flow<ObjectType> by parentRepo::newObjectsFlow
|
||||||
override val updatedObjectsFlow: Flow<ObjectType> by parentRepo::updatedObjectsFlow
|
override val updatedObjectsFlow: Flow<ObjectType> by parentRepo::updatedObjectsFlow
|
||||||
override val deletedObjectsIdsFlow: Flow<IdType> by parentRepo::deletedObjectsIdsFlow
|
override val deletedObjectsIdsFlow: Flow<IdType> by parentRepo::deletedObjectsIdsFlow
|
||||||
@@ -72,6 +74,8 @@ open class WriteCRUDCacheRepo<ObjectType, IdType, InputValueType>(
|
|||||||
|
|
||||||
return created
|
return created
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override suspend fun invalidate() = kvCache.clear()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun <ObjectType, IdType, InputType> WriteCRUDRepo<ObjectType, IdType, InputType>.caching(
|
fun <ObjectType, IdType, InputType> WriteCRUDRepo<ObjectType, IdType, InputType>.caching(
|
||||||
|
@@ -1,3 +1,5 @@
|
|||||||
package dev.inmo.micro_utils.repos.cache
|
package dev.inmo.micro_utils.repos.cache
|
||||||
|
|
||||||
interface CacheRepo
|
interface CacheRepo {
|
||||||
|
suspend fun invalidate()
|
||||||
|
}
|
||||||
|
7
repos/cache/src/commonMain/kotlin/dev/inmo/micro_utils/repos/cache/CommonCacheRepo.kt
vendored
Normal file
7
repos/cache/src/commonMain/kotlin/dev/inmo/micro_utils/repos/cache/CommonCacheRepo.kt
vendored
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
package dev.inmo.micro_utils.repos.cache
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Any inheritor of this should work with next logic: try to take data from some [dev.inmo.micro_utils.repos.cache.cache.KVCache] and,
|
||||||
|
* if not exists, take from origin and save to the cache for future reuse
|
||||||
|
*/
|
||||||
|
interface CommonCacheRepo : CacheRepo
|
@@ -10,7 +10,7 @@ import kotlinx.coroutines.flow.*
|
|||||||
open class ReadKeyValueCacheRepo<Key,Value>(
|
open class ReadKeyValueCacheRepo<Key,Value>(
|
||||||
protected open val parentRepo: ReadKeyValueRepo<Key, Value>,
|
protected open val parentRepo: ReadKeyValueRepo<Key, Value>,
|
||||||
protected open val kvCache: KVCache<Key, Value>,
|
protected open val kvCache: KVCache<Key, Value>,
|
||||||
) : ReadKeyValueRepo<Key,Value> by parentRepo, CacheRepo {
|
) : ReadKeyValueRepo<Key,Value> by parentRepo, CommonCacheRepo {
|
||||||
override suspend fun get(k: Key): Value? = kvCache.get(k) ?: parentRepo.get(k) ?.also { kvCache.set(k, it) }
|
override suspend fun get(k: Key): Value? = kvCache.get(k) ?: parentRepo.get(k) ?.also { kvCache.set(k, it) }
|
||||||
override suspend fun contains(key: Key): Boolean = kvCache.contains(key) || parentRepo.contains(key)
|
override suspend fun contains(key: Key): Boolean = kvCache.contains(key) || parentRepo.contains(key)
|
||||||
|
|
||||||
@@ -23,6 +23,8 @@ open class ReadKeyValueCacheRepo<Key,Value>(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override suspend fun invalidate() = kvCache.clear()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun <Key, Value> ReadKeyValueRepo<Key, Value>.cached(
|
fun <Key, Value> ReadKeyValueRepo<Key, Value>.cached(
|
||||||
@@ -33,9 +35,11 @@ open class KeyValueCacheRepo<Key,Value>(
|
|||||||
parentRepo: KeyValueRepo<Key, Value>,
|
parentRepo: KeyValueRepo<Key, Value>,
|
||||||
kvCache: KVCache<Key, Value>,
|
kvCache: KVCache<Key, Value>,
|
||||||
scope: CoroutineScope = CoroutineScope(Dispatchers.Default)
|
scope: CoroutineScope = CoroutineScope(Dispatchers.Default)
|
||||||
) : ReadKeyValueCacheRepo<Key,Value>(parentRepo, kvCache), KeyValueRepo<Key,Value>, WriteKeyValueRepo<Key, Value> by parentRepo, CacheRepo {
|
) : ReadKeyValueCacheRepo<Key,Value>(parentRepo, kvCache), KeyValueRepo<Key,Value>, WriteKeyValueRepo<Key, Value> by parentRepo, CommonCacheRepo {
|
||||||
protected val onNewJob = parentRepo.onNewValue.onEach { kvCache.set(it.first, it.second) }.launchIn(scope)
|
protected val onNewJob = parentRepo.onNewValue.onEach { kvCache.set(it.first, it.second) }.launchIn(scope)
|
||||||
protected val onRemoveJob = parentRepo.onValueRemoved.onEach { kvCache.unset(it) }.launchIn(scope)
|
protected val onRemoveJob = parentRepo.onValueRemoved.onEach { kvCache.unset(it) }.launchIn(scope)
|
||||||
|
|
||||||
|
override suspend fun invalidate() = kvCache.clear()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun <Key, Value> KeyValueRepo<Key, Value>.cached(
|
fun <Key, Value> KeyValueRepo<Key, Value>.cached(
|
||||||
|
@@ -11,7 +11,7 @@ import kotlinx.coroutines.flow.*
|
|||||||
open class ReadKeyValuesCacheRepo<Key,Value>(
|
open class ReadKeyValuesCacheRepo<Key,Value>(
|
||||||
protected open val parentRepo: ReadKeyValuesRepo<Key, Value>,
|
protected open val parentRepo: ReadKeyValuesRepo<Key, Value>,
|
||||||
protected open val kvCache: KVCache<Key, List<Value>>
|
protected open val kvCache: KVCache<Key, List<Value>>
|
||||||
) : ReadKeyValuesRepo<Key,Value> by parentRepo, CacheRepo {
|
) : ReadKeyValuesRepo<Key,Value> by parentRepo, CommonCacheRepo {
|
||||||
override suspend fun get(k: Key, pagination: Pagination, reversed: Boolean): PaginationResult<Value> {
|
override suspend fun get(k: Key, pagination: Pagination, reversed: Boolean): PaginationResult<Value> {
|
||||||
return getAll(k, reversed).paginate(
|
return getAll(k, reversed).paginate(
|
||||||
pagination
|
pagination
|
||||||
@@ -30,6 +30,8 @@ open class ReadKeyValuesCacheRepo<Key,Value>(
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
override suspend fun contains(k: Key): Boolean = kvCache.contains(k) || parentRepo.contains(k)
|
override suspend fun contains(k: Key): Boolean = kvCache.contains(k) || parentRepo.contains(k)
|
||||||
|
|
||||||
|
override suspend fun invalidate() = kvCache.clear()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun <Key, Value> ReadKeyValuesRepo<Key, Value>.cached(
|
fun <Key, Value> ReadKeyValuesRepo<Key, Value>.cached(
|
||||||
@@ -40,7 +42,7 @@ open class KeyValuesCacheRepo<Key,Value>(
|
|||||||
parentRepo: KeyValuesRepo<Key, Value>,
|
parentRepo: KeyValuesRepo<Key, Value>,
|
||||||
kvCache: KVCache<Key, List<Value>>,
|
kvCache: KVCache<Key, List<Value>>,
|
||||||
scope: CoroutineScope = CoroutineScope(Dispatchers.Default)
|
scope: CoroutineScope = CoroutineScope(Dispatchers.Default)
|
||||||
) : ReadKeyValuesCacheRepo<Key,Value>(parentRepo, kvCache), KeyValuesRepo<Key,Value>, WriteKeyValuesRepo<Key,Value> by parentRepo, CacheRepo {
|
) : ReadKeyValuesCacheRepo<Key,Value>(parentRepo, kvCache), KeyValuesRepo<Key,Value>, WriteKeyValuesRepo<Key,Value> by parentRepo, CommonCacheRepo {
|
||||||
protected val onNewJob = parentRepo.onNewValue.onEach { (k, v) ->
|
protected val onNewJob = parentRepo.onNewValue.onEach { (k, v) ->
|
||||||
kvCache.set(
|
kvCache.set(
|
||||||
k,
|
k,
|
||||||
@@ -56,6 +58,8 @@ open class KeyValuesCacheRepo<Key,Value>(
|
|||||||
protected val onDataClearedJob = parentRepo.onDataCleared.onEach {
|
protected val onDataClearedJob = parentRepo.onDataCleared.onEach {
|
||||||
kvCache.unset(it)
|
kvCache.unset(it)
|
||||||
}.launchIn(scope)
|
}.launchIn(scope)
|
||||||
|
|
||||||
|
override suspend fun invalidate() = kvCache.clear()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun <Key, Value> KeyValuesRepo<Key, Value>.cached(
|
fun <Key, Value> KeyValuesRepo<Key, Value>.cached(
|
||||||
|
@@ -8,6 +8,7 @@ import dev.inmo.micro_utils.repos.*
|
|||||||
import dev.inmo.micro_utils.repos.cache.*
|
import dev.inmo.micro_utils.repos.cache.*
|
||||||
import dev.inmo.micro_utils.repos.cache.cache.FullKVCache
|
import dev.inmo.micro_utils.repos.cache.cache.FullKVCache
|
||||||
import dev.inmo.micro_utils.repos.cache.cache.KVCache
|
import dev.inmo.micro_utils.repos.cache.cache.KVCache
|
||||||
|
import dev.inmo.micro_utils.repos.cache.util.actualizeAll
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
|
||||||
@@ -32,12 +33,7 @@ open class FullReadCRUDCacheRepo<ObjectType, IdType>(
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected open suspend fun actualizeAll() {
|
protected open suspend fun actualizeAll() {
|
||||||
kvCache.clear()
|
kvCache.actualizeAll(parentRepo)
|
||||||
doForAllWithNextPaging {
|
|
||||||
parentRepo.getByPagination(it).also {
|
|
||||||
kvCache.set(it.results.associateBy { idGetter(it) })
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun getByPagination(pagination: Pagination): PaginationResult<ObjectType> = doOrTakeAndActualize(
|
override suspend fun getByPagination(pagination: Pagination): PaginationResult<ObjectType> = doOrTakeAndActualize(
|
||||||
@@ -46,6 +42,12 @@ open class FullReadCRUDCacheRepo<ObjectType, IdType>(
|
|||||||
{ if (it.results.isNotEmpty()) actualizeAll() }
|
{ 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(
|
override suspend fun count(): Long = doOrTakeAndActualize(
|
||||||
{ count().takeIf { it != 0L }.optionalOrAbsentIfNull },
|
{ count().takeIf { it != 0L }.optionalOrAbsentIfNull },
|
||||||
{ count() },
|
{ count() },
|
||||||
@@ -63,6 +65,10 @@ open class FullReadCRUDCacheRepo<ObjectType, IdType>(
|
|||||||
{ getById(id) },
|
{ getById(id) },
|
||||||
{ it ?.let { set(idGetter(it), it) } }
|
{ it ?.let { set(idGetter(it), it) } }
|
||||||
)
|
)
|
||||||
|
|
||||||
|
override suspend fun invalidate() {
|
||||||
|
actualizeAll()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun <ObjectType, IdType> ReadCRUDRepo<ObjectType, IdType>.cached(
|
fun <ObjectType, IdType> ReadCRUDRepo<ObjectType, IdType>.cached(
|
||||||
@@ -86,7 +92,11 @@ open class FullCRUDCacheRepo<ObjectType, IdType, InputValueType>(
|
|||||||
scope,
|
scope,
|
||||||
idGetter
|
idGetter
|
||||||
),
|
),
|
||||||
CRUDRepo<ObjectType, IdType, InputValueType>
|
CRUDRepo<ObjectType, IdType, InputValueType> {
|
||||||
|
override suspend fun invalidate() {
|
||||||
|
actualizeAll()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fun <ObjectType, IdType, InputType> CRUDRepo<ObjectType, IdType, InputType>.cached(
|
fun <ObjectType, IdType, InputType> CRUDRepo<ObjectType, IdType, InputType>.cached(
|
||||||
kvCache: FullKVCache<IdType, ObjectType>,
|
kvCache: FullKVCache<IdType, ObjectType>,
|
||||||
|
@@ -5,6 +5,7 @@ import dev.inmo.micro_utils.pagination.Pagination
|
|||||||
import dev.inmo.micro_utils.pagination.PaginationResult
|
import dev.inmo.micro_utils.pagination.PaginationResult
|
||||||
import dev.inmo.micro_utils.repos.*
|
import dev.inmo.micro_utils.repos.*
|
||||||
import dev.inmo.micro_utils.repos.cache.cache.FullKVCache
|
import dev.inmo.micro_utils.repos.cache.cache.FullKVCache
|
||||||
|
import dev.inmo.micro_utils.repos.cache.util.actualizeAll
|
||||||
import dev.inmo.micro_utils.repos.pagination.getAll
|
import dev.inmo.micro_utils.repos.pagination.getAll
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
@@ -68,6 +69,10 @@ open class FullReadKeyValueCacheRepo<Key,Value>(
|
|||||||
{ parentRepo.keys(v, pagination, reversed) },
|
{ parentRepo.keys(v, pagination, reversed) },
|
||||||
{ if (it.results.isNotEmpty()) actualizeAll() }
|
{ if (it.results.isNotEmpty()) actualizeAll() }
|
||||||
)
|
)
|
||||||
|
|
||||||
|
override suspend fun invalidate() {
|
||||||
|
actualizeAll()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun <Key, Value> ReadKeyValueRepo<Key, Value>.cached(
|
fun <Key, Value> ReadKeyValueRepo<Key, Value>.cached(
|
||||||
@@ -81,6 +86,10 @@ open class FullWriteKeyValueCacheRepo<Key,Value>(
|
|||||||
) : WriteKeyValueRepo<Key, Value> by parentRepo, FullCacheRepo {
|
) : WriteKeyValueRepo<Key, Value> by parentRepo, FullCacheRepo {
|
||||||
protected val onNewJob = parentRepo.onNewValue.onEach { kvCache.set(it.first, it.second) }.launchIn(scope)
|
protected val onNewJob = parentRepo.onNewValue.onEach { kvCache.set(it.first, it.second) }.launchIn(scope)
|
||||||
protected val onRemoveJob = parentRepo.onValueRemoved.onEach { kvCache.unset(it) }.launchIn(scope)
|
protected val onRemoveJob = parentRepo.onValueRemoved.onEach { kvCache.unset(it) }.launchIn(scope)
|
||||||
|
|
||||||
|
override suspend fun invalidate() {
|
||||||
|
kvCache.clear()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun <Key, Value> WriteKeyValueRepo<Key, Value>.caching(
|
fun <Key, Value> WriteKeyValueRepo<Key, Value>.caching(
|
||||||
@@ -89,13 +98,17 @@ fun <Key, Value> WriteKeyValueRepo<Key, Value>.caching(
|
|||||||
) = FullWriteKeyValueCacheRepo(this, kvCache, scope)
|
) = FullWriteKeyValueCacheRepo(this, kvCache, scope)
|
||||||
|
|
||||||
open class FullKeyValueCacheRepo<Key,Value>(
|
open class FullKeyValueCacheRepo<Key,Value>(
|
||||||
parentRepo: KeyValueRepo<Key, Value>,
|
override val parentRepo: KeyValueRepo<Key, Value>,
|
||||||
kvCache: FullKVCache<Key, Value>,
|
kvCache: FullKVCache<Key, Value>,
|
||||||
scope: CoroutineScope = CoroutineScope(Dispatchers.Default)
|
scope: CoroutineScope = CoroutineScope(Dispatchers.Default)
|
||||||
) : FullWriteKeyValueCacheRepo<Key,Value>(parentRepo, kvCache, scope),
|
) : FullWriteKeyValueCacheRepo<Key,Value>(parentRepo, kvCache, scope),
|
||||||
KeyValueRepo<Key,Value>,
|
KeyValueRepo<Key,Value>,
|
||||||
ReadKeyValueRepo<Key, Value> by FullReadKeyValueCacheRepo(parentRepo, kvCache) {
|
ReadKeyValueRepo<Key, Value> by FullReadKeyValueCacheRepo(parentRepo, kvCache) {
|
||||||
override suspend fun unsetWithValues(toUnset: List<Value>) = parentRepo.unsetWithValues(toUnset)
|
override suspend fun unsetWithValues(toUnset: List<Value>) = parentRepo.unsetWithValues(toUnset)
|
||||||
|
|
||||||
|
override suspend fun invalidate() {
|
||||||
|
kvCache.actualizeAll(parentRepo)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun <Key, Value> KeyValueRepo<Key, Value>.cached(
|
fun <Key, Value> KeyValueRepo<Key, Value>.cached(
|
||||||
|
@@ -5,6 +5,7 @@ import dev.inmo.micro_utils.pagination.*
|
|||||||
import dev.inmo.micro_utils.pagination.utils.*
|
import dev.inmo.micro_utils.pagination.utils.*
|
||||||
import dev.inmo.micro_utils.repos.*
|
import dev.inmo.micro_utils.repos.*
|
||||||
import dev.inmo.micro_utils.repos.cache.cache.FullKVCache
|
import dev.inmo.micro_utils.repos.cache.cache.FullKVCache
|
||||||
|
import dev.inmo.micro_utils.repos.cache.util.actualizeAll
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.flow.*
|
import kotlinx.coroutines.flow.*
|
||||||
@@ -33,8 +34,7 @@ open class FullReadKeyValuesCacheRepo<Key,Value>(
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected open suspend fun actualizeAll() {
|
protected open suspend fun actualizeAll() {
|
||||||
doAllWithCurrentPaging { kvCache.keys(it).also { kvCache.unset(it.results) } }
|
kvCache.actualizeAll(parentRepo)
|
||||||
kvCache.set(parentRepo.getAll())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun get(k: Key, pagination: Pagination, reversed: Boolean): PaginationResult<Value> {
|
override suspend fun get(k: Key, pagination: Pagination, reversed: Boolean): PaginationResult<Value> {
|
||||||
@@ -102,6 +102,9 @@ open class FullReadKeyValuesCacheRepo<Key,Value>(
|
|||||||
{ if (it.results.isNotEmpty()) actualizeAll() }
|
{ if (it.results.isNotEmpty()) actualizeAll() }
|
||||||
)
|
)
|
||||||
|
|
||||||
|
override suspend fun invalidate() {
|
||||||
|
actualizeAll()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun <Key, Value> ReadKeyValuesRepo<Key, Value>.cached(
|
fun <Key, Value> ReadKeyValuesRepo<Key, Value>.cached(
|
||||||
@@ -125,6 +128,10 @@ open class FullWriteKeyValuesCacheRepo<Key,Value>(
|
|||||||
kvCache.get(it.first) ?.minus(it.second) ?: return@onEach
|
kvCache.get(it.first) ?.minus(it.second) ?: return@onEach
|
||||||
)
|
)
|
||||||
}.launchIn(scope)
|
}.launchIn(scope)
|
||||||
|
|
||||||
|
override suspend fun invalidate() {
|
||||||
|
kvCache.clear()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun <Key, Value> WriteKeyValuesRepo<Key, Value>.caching(
|
fun <Key, Value> WriteKeyValuesRepo<Key, Value>.caching(
|
||||||
@@ -133,7 +140,7 @@ fun <Key, Value> WriteKeyValuesRepo<Key, Value>.caching(
|
|||||||
) = FullWriteKeyValuesCacheRepo(this, kvCache, scope)
|
) = FullWriteKeyValuesCacheRepo(this, kvCache, scope)
|
||||||
|
|
||||||
open class FullKeyValuesCacheRepo<Key,Value>(
|
open class FullKeyValuesCacheRepo<Key,Value>(
|
||||||
parentRepo: KeyValuesRepo<Key, Value>,
|
override val parentRepo: KeyValuesRepo<Key, Value>,
|
||||||
kvCache: FullKVCache<Key, List<Value>>,
|
kvCache: FullKVCache<Key, List<Value>>,
|
||||||
scope: CoroutineScope = CoroutineScope(Dispatchers.Default)
|
scope: CoroutineScope = CoroutineScope(Dispatchers.Default)
|
||||||
) : FullWriteKeyValuesCacheRepo<Key, Value>(parentRepo, kvCache, scope),
|
) : FullWriteKeyValuesCacheRepo<Key, Value>(parentRepo, kvCache, scope),
|
||||||
@@ -146,6 +153,10 @@ open class FullKeyValuesCacheRepo<Key,Value>(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override suspend fun invalidate() {
|
||||||
|
kvCache.actualizeAll(parentRepo)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun <Key, Value> KeyValuesRepo<Key, Value>.caching(
|
fun <Key, Value> KeyValuesRepo<Key, Value>.caching(
|
||||||
|
61
repos/cache/src/commonMain/kotlin/dev/inmo/micro_utils/repos/cache/util/ActualizeAll.kt
vendored
Normal file
61
repos/cache/src/commonMain/kotlin/dev/inmo/micro_utils/repos/cache/util/ActualizeAll.kt
vendored
Normal file
@@ -0,0 +1,61 @@
|
|||||||
|
package dev.inmo.micro_utils.repos.cache.util
|
||||||
|
|
||||||
|
import dev.inmo.micro_utils.pagination.FirstPagePagination
|
||||||
|
import dev.inmo.micro_utils.pagination.utils.doForAllWithNextPaging
|
||||||
|
import dev.inmo.micro_utils.repos.ReadCRUDRepo
|
||||||
|
import dev.inmo.micro_utils.repos.ReadKeyValueRepo
|
||||||
|
import dev.inmo.micro_utils.repos.ReadKeyValuesRepo
|
||||||
|
import dev.inmo.micro_utils.repos.cache.cache.KVCache
|
||||||
|
import dev.inmo.micro_utils.repos.set
|
||||||
|
|
||||||
|
suspend inline fun <K, V> KVCache<K, V>.actualizeAll(
|
||||||
|
getAll: () -> Map<K, V>
|
||||||
|
) {
|
||||||
|
clear()
|
||||||
|
set(getAll())
|
||||||
|
}
|
||||||
|
|
||||||
|
suspend inline fun <K, V> KVCache<K, V>.actualizeAll(
|
||||||
|
repo: ReadKeyValueRepo<K, V>
|
||||||
|
) {
|
||||||
|
clear()
|
||||||
|
val count = repo.count().takeIf { it < Int.MAX_VALUE } ?.toInt() ?: Int.MAX_VALUE
|
||||||
|
val initPagination = FirstPagePagination(count)
|
||||||
|
doForAllWithNextPaging(initPagination) {
|
||||||
|
keys(it).also {
|
||||||
|
set(
|
||||||
|
it.results.mapNotNull { k -> repo.get(k) ?.let { k to it } }
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
suspend inline fun <K, V> KVCache<K, List<V>>.actualizeAll(
|
||||||
|
repo: ReadKeyValuesRepo<K, V>
|
||||||
|
) {
|
||||||
|
clear()
|
||||||
|
val count = repo.count().takeIf { it < Int.MAX_VALUE } ?.toInt() ?: Int.MAX_VALUE
|
||||||
|
val initPagination = FirstPagePagination(count)
|
||||||
|
doForAllWithNextPaging(initPagination) {
|
||||||
|
keys(it).also {
|
||||||
|
set(
|
||||||
|
it.results.associateWith { k -> repo.getAll(k) }
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
suspend inline fun <K, V> KVCache<K, V>.actualizeAll(
|
||||||
|
repo: ReadCRUDRepo<V, K>
|
||||||
|
) {
|
||||||
|
clear()
|
||||||
|
val count = repo.count().takeIf { it < Int.MAX_VALUE } ?.toInt() ?: Int.MAX_VALUE
|
||||||
|
val initPagination = FirstPagePagination(count)
|
||||||
|
doForAllWithNextPaging(initPagination) {
|
||||||
|
keys(it).also {
|
||||||
|
set(
|
||||||
|
it.results.mapNotNull { k -> repo.getById(k) ?.let { k to it } }
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -93,6 +93,10 @@ suspend inline fun <Key, Value> WriteKeyValueRepo<Key, Value>.set(
|
|||||||
vararg toSet: Pair<Key, Value>
|
vararg toSet: Pair<Key, Value>
|
||||||
) = set(toSet.toMap())
|
) = set(toSet.toMap())
|
||||||
|
|
||||||
|
suspend inline fun <Key, Value> WriteKeyValueRepo<Key, Value>.set(
|
||||||
|
toSet: List<Pair<Key, Value>>
|
||||||
|
) = set(toSet.toMap())
|
||||||
|
|
||||||
suspend inline fun <Key, Value> WriteKeyValueRepo<Key, Value>.set(
|
suspend inline fun <Key, Value> WriteKeyValueRepo<Key, Value>.set(
|
||||||
k: Key, v: Value
|
k: Key, v: Value
|
||||||
) = set(k to v)
|
) = set(k to v)
|
||||||
@@ -125,7 +129,11 @@ interface KeyValueRepo<Key, Value> : ReadKeyValueRepo<Key, Value>, WriteKeyValue
|
|||||||
* By default, will remove all the data of current repo using [doAllWithCurrentPaging], [keys] and [unset]
|
* By default, will remove all the data of current repo using [doAllWithCurrentPaging], [keys] and [unset]
|
||||||
*/
|
*/
|
||||||
suspend fun clear() {
|
suspend fun clear() {
|
||||||
doAllWithCurrentPaging { keys(it).also { unset(it.results) } }
|
var count: Int
|
||||||
|
do {
|
||||||
|
count = count().takeIf { it < Int.MAX_VALUE } ?.toInt() ?: Int.MAX_VALUE
|
||||||
|
keys(FirstPagePagination(count)).also { unset(it.results) }
|
||||||
|
} while(count > 0)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
typealias StandardKeyValueRepo<Key,Value> = KeyValueRepo<Key, Value>
|
typealias StandardKeyValueRepo<Key,Value> = KeyValueRepo<Key, Value>
|
||||||
|
@@ -6,6 +6,7 @@ import kotlinx.coroutines.flow.Flow
|
|||||||
|
|
||||||
interface ReadCRUDRepo<ObjectType, IdType> : Repo {
|
interface ReadCRUDRepo<ObjectType, IdType> : Repo {
|
||||||
suspend fun getByPagination(pagination: Pagination): PaginationResult<ObjectType>
|
suspend fun getByPagination(pagination: Pagination): PaginationResult<ObjectType>
|
||||||
|
suspend fun getIdsByPagination(pagination: Pagination): PaginationResult<IdType>
|
||||||
suspend fun getById(id: IdType): ObjectType?
|
suspend fun getById(id: IdType): ObjectType?
|
||||||
suspend fun contains(id: IdType): Boolean
|
suspend fun contains(id: IdType): Boolean
|
||||||
suspend fun count(): Long
|
suspend fun count(): Long
|
||||||
|
@@ -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 count(): Long = to.count()
|
||||||
|
|
||||||
override suspend fun contains(id: FromId): Boolean = to.contains(id.toOutKey())
|
override suspend fun contains(id: FromId): Boolean = to.contains(id.toOutKey())
|
||||||
|
@@ -16,6 +16,7 @@ abstract class AbstractAndroidCRUDRepo<ObjectType, IdType>(
|
|||||||
protected abstract val tableName: String
|
protected abstract val tableName: String
|
||||||
protected abstract val idColumnName: String
|
protected abstract val idColumnName: String
|
||||||
protected abstract suspend fun Cursor.toObject(): ObjectType
|
protected abstract suspend fun Cursor.toObject(): ObjectType
|
||||||
|
protected abstract suspend fun Cursor.toId(): IdType
|
||||||
protected fun SQLiteDatabase.count(): Long = select(tableName).use {
|
protected fun SQLiteDatabase.count(): Long = select(tableName).use {
|
||||||
it.count
|
it.count
|
||||||
}.toLong()
|
}.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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -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? {
|
override suspend fun getById(id: IdType): ObjectType? {
|
||||||
return transaction(db = database) {
|
return transaction(db = database) {
|
||||||
select {
|
select {
|
||||||
|
@@ -0,0 +1,23 @@
|
|||||||
|
package dev.inmo.micro_utils.repos.exposed
|
||||||
|
|
||||||
|
import org.jetbrains.exposed.sql.Column
|
||||||
|
import org.jetbrains.exposed.sql.SqlExpressionBuilder.eq
|
||||||
|
import org.jetbrains.exposed.sql.SqlExpressionBuilder.isNotNull
|
||||||
|
import org.jetbrains.exposed.sql.SqlExpressionBuilder.isNull
|
||||||
|
import org.jetbrains.exposed.sql.SqlExpressionBuilder.neq
|
||||||
|
|
||||||
|
fun <T> Column<T?>.eqOrIsNull(
|
||||||
|
value: T?
|
||||||
|
) = if (value == null) {
|
||||||
|
isNull()
|
||||||
|
} else {
|
||||||
|
eq(value)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun <T> Column<T?>.neqOrIsNotNull(
|
||||||
|
value: T?
|
||||||
|
) = if (value == null) {
|
||||||
|
isNotNull()
|
||||||
|
} else {
|
||||||
|
neq(value)
|
||||||
|
}
|
@@ -4,6 +4,7 @@ import org.jetbrains.exposed.sql.*
|
|||||||
|
|
||||||
interface CommonExposedRepo<IdType, ObjectType> : ExposedRepo {
|
interface CommonExposedRepo<IdType, ObjectType> : ExposedRepo {
|
||||||
val ResultRow.asObject: ObjectType
|
val ResultRow.asObject: ObjectType
|
||||||
|
val ResultRow.asId: IdType
|
||||||
val selectById: ISqlExpressionBuilder.(IdType) -> Op<Boolean>
|
val selectById: ISqlExpressionBuilder.(IdType) -> Op<Boolean>
|
||||||
val selectByIds: ISqlExpressionBuilder.(List<IdType>) -> Op<Boolean>
|
val selectByIds: ISqlExpressionBuilder.(List<IdType>) -> Op<Boolean>
|
||||||
get() = { list ->
|
get() = { list ->
|
||||||
|
@@ -15,7 +15,13 @@ abstract class AbstractExposedReadKeyValueRepo<Key, Value>(
|
|||||||
CommonExposedRepo<Key, Value>,
|
CommonExposedRepo<Key, Value>,
|
||||||
Table(tableName ?: "") {
|
Table(tableName ?: "") {
|
||||||
abstract val keyColumn: Column<*>
|
abstract val keyColumn: Column<*>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Same as [asId] in context of KeyValue repo
|
||||||
|
*/
|
||||||
abstract val ResultRow.asKey: Key
|
abstract val ResultRow.asKey: Key
|
||||||
|
override val ResultRow.asId: Key
|
||||||
|
get() = asKey
|
||||||
abstract val selectByValue: ISqlExpressionBuilder.(Value) -> Op<Boolean>
|
abstract val selectByValue: ISqlExpressionBuilder.(Value) -> Op<Boolean>
|
||||||
|
|
||||||
override suspend fun get(k: Key): Value? = transaction(database) {
|
override suspend fun get(k: Key): Value? = transaction(database) {
|
||||||
|
@@ -17,6 +17,8 @@ abstract class AbstractExposedReadKeyValuesRepo<Key, Value>(
|
|||||||
Table(tableName ?: "") {
|
Table(tableName ?: "") {
|
||||||
abstract val keyColumn: Column<*>
|
abstract val keyColumn: Column<*>
|
||||||
abstract val ResultRow.asKey: Key
|
abstract val ResultRow.asKey: Key
|
||||||
|
override val ResultRow.asId: Key
|
||||||
|
get() = asKey
|
||||||
abstract val selectByValue: ISqlExpressionBuilder.(Value) -> Op<Boolean>
|
abstract val selectByValue: ISqlExpressionBuilder.(Value) -> Op<Boolean>
|
||||||
|
|
||||||
override suspend fun count(k: Key): Long = transaction(database) { select { selectById(k) }.count() }
|
override suspend fun count(k: Key): Long = transaction(database) { select { selectById(k) }.count() }
|
||||||
|
@@ -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 getById(id: IdType): ObjectType? = map[id]
|
||||||
|
|
||||||
override suspend fun contains(id: IdType): Boolean = map.containsKey(id)
|
override suspend fun contains(id: IdType): Boolean = map.containsKey(id)
|
||||||
|
@@ -1,12 +1,17 @@
|
|||||||
package dev.inmo.micro_utils.repos.ktor.client.crud
|
package dev.inmo.micro_utils.repos.ktor.client.crud
|
||||||
|
|
||||||
|
import dev.inmo.micro_utils.ktor.client.createStandardWebsocketFlow
|
||||||
import dev.inmo.micro_utils.ktor.common.*
|
import dev.inmo.micro_utils.ktor.common.*
|
||||||
import dev.inmo.micro_utils.pagination.PaginationResult
|
import dev.inmo.micro_utils.pagination.PaginationResult
|
||||||
import dev.inmo.micro_utils.repos.*
|
import dev.inmo.micro_utils.repos.*
|
||||||
|
import dev.inmo.micro_utils.repos.ktor.common.crud.deletedObjectsIdsFlowRouting
|
||||||
|
import dev.inmo.micro_utils.repos.ktor.common.crud.newObjectsFlowRouting
|
||||||
|
import dev.inmo.micro_utils.repos.ktor.common.crud.updatedObjectsFlowRouting
|
||||||
import io.ktor.client.HttpClient
|
import io.ktor.client.HttpClient
|
||||||
import io.ktor.http.ContentType
|
import io.ktor.http.ContentType
|
||||||
import io.ktor.util.reflect.TypeInfo
|
import io.ktor.util.reflect.TypeInfo
|
||||||
import io.ktor.util.reflect.typeInfo
|
import io.ktor.util.reflect.typeInfo
|
||||||
|
import kotlinx.coroutines.flow.Flow
|
||||||
import kotlinx.serialization.*
|
import kotlinx.serialization.*
|
||||||
|
|
||||||
class KtorCRUDRepoClient<ObjectType, IdType, InputValue> (
|
class KtorCRUDRepoClient<ObjectType, IdType, InputValue> (
|
||||||
@@ -21,6 +26,15 @@ class KtorCRUDRepoClient<ObjectType, IdType, InputValue> (
|
|||||||
baseUrl: String,
|
baseUrl: String,
|
||||||
httpClient: HttpClient,
|
httpClient: HttpClient,
|
||||||
contentType: ContentType,
|
contentType: ContentType,
|
||||||
|
newObjectsFlow: Flow<ObjectType> = httpClient.createStandardWebsocketFlow(
|
||||||
|
buildStandardUrl(baseUrl, newObjectsFlowRouting),
|
||||||
|
),
|
||||||
|
updatedObjectsFlow: Flow<ObjectType> = httpClient.createStandardWebsocketFlow(
|
||||||
|
buildStandardUrl(baseUrl, updatedObjectsFlowRouting),
|
||||||
|
),
|
||||||
|
deletedObjectsIdsFlow: Flow<IdType> = httpClient.createStandardWebsocketFlow(
|
||||||
|
buildStandardUrl(baseUrl, deletedObjectsIdsFlowRouting),
|
||||||
|
),
|
||||||
noinline idSerializer: suspend (IdType) -> String
|
noinline idSerializer: suspend (IdType) -> String
|
||||||
) = KtorCRUDRepoClient(
|
) = KtorCRUDRepoClient(
|
||||||
KtorReadCRUDRepoClient(
|
KtorReadCRUDRepoClient(
|
||||||
@@ -28,13 +42,17 @@ class KtorCRUDRepoClient<ObjectType, IdType, InputValue> (
|
|||||||
httpClient,
|
httpClient,
|
||||||
typeInfo<ObjectType>(),
|
typeInfo<ObjectType>(),
|
||||||
typeInfo<PaginationResult<ObjectType>>(),
|
typeInfo<PaginationResult<ObjectType>>(),
|
||||||
|
typeInfo<PaginationResult<IdType>>(),
|
||||||
contentType,
|
contentType,
|
||||||
idSerializer
|
idSerializer
|
||||||
),
|
),
|
||||||
KtorWriteCrudRepoClient<ObjectType, IdType, InputValue>(
|
KtorWriteCrudRepoClient<ObjectType, IdType, InputValue>(
|
||||||
baseUrl,
|
baseUrl,
|
||||||
httpClient,
|
httpClient,
|
||||||
contentType
|
contentType,
|
||||||
|
newObjectsFlow,
|
||||||
|
updatedObjectsFlow,
|
||||||
|
deletedObjectsIdsFlow
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -43,11 +61,23 @@ class KtorCRUDRepoClient<ObjectType, IdType, InputValue> (
|
|||||||
subpart: String,
|
subpart: String,
|
||||||
httpClient: HttpClient,
|
httpClient: HttpClient,
|
||||||
contentType: ContentType,
|
contentType: ContentType,
|
||||||
|
newObjectsFlow: Flow<ObjectType> = httpClient.createStandardWebsocketFlow(
|
||||||
|
buildStandardUrl(baseUrl, newObjectsFlowRouting),
|
||||||
|
),
|
||||||
|
updatedObjectsFlow: Flow<ObjectType> = httpClient.createStandardWebsocketFlow(
|
||||||
|
buildStandardUrl(baseUrl, updatedObjectsFlowRouting),
|
||||||
|
),
|
||||||
|
deletedObjectsIdsFlow: Flow<IdType> = httpClient.createStandardWebsocketFlow(
|
||||||
|
buildStandardUrl(baseUrl, deletedObjectsIdsFlowRouting),
|
||||||
|
),
|
||||||
noinline idSerializer: suspend (IdType) -> String
|
noinline idSerializer: suspend (IdType) -> String
|
||||||
) = KtorCRUDRepoClient<ObjectType, IdType, InputValue>(
|
) = KtorCRUDRepoClient<ObjectType, IdType, InputValue>(
|
||||||
buildStandardUrl(baseUrl, subpart),
|
buildStandardUrl(baseUrl, subpart),
|
||||||
httpClient,
|
httpClient,
|
||||||
contentType,
|
contentType,
|
||||||
|
newObjectsFlow,
|
||||||
|
updatedObjectsFlow,
|
||||||
|
deletedObjectsIdsFlow,
|
||||||
idSerializer
|
idSerializer
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -79,11 +109,23 @@ inline fun <reified ObjectType, reified IdType, reified InputValue> KtorCRUDRepo
|
|||||||
subpart: String,
|
subpart: String,
|
||||||
httpClient: HttpClient,
|
httpClient: HttpClient,
|
||||||
contentType: ContentType,
|
contentType: ContentType,
|
||||||
|
newObjectsFlow: Flow<ObjectType> = httpClient.createStandardWebsocketFlow(
|
||||||
|
buildStandardUrl(baseUrl, newObjectsFlowRouting),
|
||||||
|
),
|
||||||
|
updatedObjectsFlow: Flow<ObjectType> = httpClient.createStandardWebsocketFlow(
|
||||||
|
buildStandardUrl(baseUrl, updatedObjectsFlowRouting),
|
||||||
|
),
|
||||||
|
deletedObjectsIdsFlow: Flow<IdType> = httpClient.createStandardWebsocketFlow(
|
||||||
|
buildStandardUrl(baseUrl, deletedObjectsIdsFlowRouting),
|
||||||
|
),
|
||||||
noinline idSerializer: suspend (IdType) -> String
|
noinline idSerializer: suspend (IdType) -> String
|
||||||
) = KtorCRUDRepoClient<ObjectType, IdType, InputValue>(
|
) = KtorCRUDRepoClient<ObjectType, IdType, InputValue>(
|
||||||
buildStandardUrl(baseUrl, subpart),
|
buildStandardUrl(baseUrl, subpart),
|
||||||
httpClient,
|
httpClient,
|
||||||
contentType,
|
contentType,
|
||||||
|
newObjectsFlow,
|
||||||
|
updatedObjectsFlow,
|
||||||
|
deletedObjectsIdsFlow,
|
||||||
idSerializer
|
idSerializer
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@@ -19,6 +19,7 @@ class KtorReadCRUDRepoClient<ObjectType, IdType> (
|
|||||||
private val httpClient: HttpClient,
|
private val httpClient: HttpClient,
|
||||||
private val objectType: TypeInfo,
|
private val objectType: TypeInfo,
|
||||||
private val paginationObjectType: TypeInfo,
|
private val paginationObjectType: TypeInfo,
|
||||||
|
private val paginationIdType: TypeInfo,
|
||||||
private val contentType: ContentType,
|
private val contentType: ContentType,
|
||||||
private val idSerializer: suspend (IdType) -> String
|
private val idSerializer: suspend (IdType) -> String
|
||||||
) : ReadCRUDRepo<ObjectType, IdType> {
|
) : ReadCRUDRepo<ObjectType, IdType> {
|
||||||
@@ -27,6 +28,11 @@ class KtorReadCRUDRepoClient<ObjectType, IdType> (
|
|||||||
) {
|
) {
|
||||||
contentType(contentType)
|
contentType(contentType)
|
||||||
}.body(paginationObjectType)
|
}.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(
|
override suspend fun getById(id: IdType): ObjectType? = httpClient.get(
|
||||||
buildStandardUrl(
|
buildStandardUrl(
|
||||||
@@ -72,6 +78,7 @@ inline fun <reified ObjectType, IdType> KtorReadCRUDRepoClient(
|
|||||||
httpClient,
|
httpClient,
|
||||||
typeInfo<ObjectType>(),
|
typeInfo<ObjectType>(),
|
||||||
typeInfo<PaginationResult<ObjectType>>(),
|
typeInfo<PaginationResult<ObjectType>>(),
|
||||||
|
typeInfo<PaginationResult<IdType>>(),
|
||||||
contentType,
|
contentType,
|
||||||
idSerializer
|
idSerializer
|
||||||
)
|
)
|
||||||
|
@@ -53,19 +53,22 @@ class KtorWriteCrudRepoClient<ObjectType, IdType, InputValue> (
|
|||||||
inline operator fun <reified ObjectType, reified IdType, reified InputValue> invoke(
|
inline operator fun <reified ObjectType, reified IdType, reified InputValue> invoke(
|
||||||
baseUrl: String,
|
baseUrl: String,
|
||||||
httpClient: HttpClient,
|
httpClient: HttpClient,
|
||||||
contentType: ContentType
|
contentType: ContentType,
|
||||||
|
newObjectsFlow: Flow<ObjectType> = httpClient.createStandardWebsocketFlow(
|
||||||
|
buildStandardUrl(baseUrl, newObjectsFlowRouting),
|
||||||
|
),
|
||||||
|
updatedObjectsFlow: Flow<ObjectType> = httpClient.createStandardWebsocketFlow(
|
||||||
|
buildStandardUrl(baseUrl, updatedObjectsFlowRouting),
|
||||||
|
),
|
||||||
|
deletedObjectsIdsFlow: Flow<IdType> = httpClient.createStandardWebsocketFlow(
|
||||||
|
buildStandardUrl(baseUrl, deletedObjectsIdsFlowRouting),
|
||||||
|
),
|
||||||
) = KtorWriteCrudRepoClient<ObjectType, IdType, InputValue>(
|
) = KtorWriteCrudRepoClient<ObjectType, IdType, InputValue>(
|
||||||
baseUrl,
|
baseUrl,
|
||||||
httpClient,
|
httpClient,
|
||||||
httpClient.createStandardWebsocketFlow(
|
newObjectsFlow,
|
||||||
buildStandardUrl(baseUrl, newObjectsFlowRouting),
|
updatedObjectsFlow,
|
||||||
),
|
deletedObjectsIdsFlow,
|
||||||
httpClient.createStandardWebsocketFlow(
|
|
||||||
buildStandardUrl(baseUrl, updatedObjectsFlowRouting),
|
|
||||||
),
|
|
||||||
httpClient.createStandardWebsocketFlow(
|
|
||||||
buildStandardUrl(baseUrl, deletedObjectsIdsFlowRouting),
|
|
||||||
),
|
|
||||||
{
|
{
|
||||||
contentType(contentType)
|
contentType(contentType)
|
||||||
setBody(it)
|
setBody(it)
|
||||||
|
@@ -1,10 +1,14 @@
|
|||||||
package dev.inmo.micro_utils.repos.ktor.client.key.value
|
package dev.inmo.micro_utils.repos.ktor.client.key.value
|
||||||
|
|
||||||
|
import dev.inmo.micro_utils.ktor.client.createStandardWebsocketFlow
|
||||||
import dev.inmo.micro_utils.ktor.common.*
|
import dev.inmo.micro_utils.ktor.common.*
|
||||||
import dev.inmo.micro_utils.repos.*
|
import dev.inmo.micro_utils.repos.*
|
||||||
|
import dev.inmo.micro_utils.repos.ktor.common.key_value.onNewValueRoute
|
||||||
|
import dev.inmo.micro_utils.repos.ktor.common.key_value.onValueRemovedRoute
|
||||||
import io.ktor.client.HttpClient
|
import io.ktor.client.HttpClient
|
||||||
import io.ktor.http.ContentType
|
import io.ktor.http.ContentType
|
||||||
import io.ktor.http.encodeURLQueryComponent
|
import io.ktor.http.encodeURLQueryComponent
|
||||||
|
import kotlinx.coroutines.flow.Flow
|
||||||
import kotlinx.serialization.*
|
import kotlinx.serialization.*
|
||||||
|
|
||||||
class KtorKeyValueRepoClient<Key, Value> (
|
class KtorKeyValueRepoClient<Key, Value> (
|
||||||
@@ -20,6 +24,12 @@ class KtorKeyValueRepoClient<Key, Value> (
|
|||||||
httpClient: HttpClient,
|
httpClient: HttpClient,
|
||||||
contentType: ContentType,
|
contentType: ContentType,
|
||||||
noinline idSerializer: suspend (Key) -> String,
|
noinline idSerializer: suspend (Key) -> String,
|
||||||
|
onNewValue: Flow<Pair<Key, Value>> = httpClient.createStandardWebsocketFlow(
|
||||||
|
buildStandardUrl(baseUrl, onNewValueRoute),
|
||||||
|
),
|
||||||
|
onValueRemoved: Flow<Key> = httpClient.createStandardWebsocketFlow(
|
||||||
|
buildStandardUrl(baseUrl, onValueRemovedRoute),
|
||||||
|
),
|
||||||
noinline valueSerializer: suspend (Value) -> String
|
noinline valueSerializer: suspend (Value) -> String
|
||||||
) = KtorKeyValueRepoClient(
|
) = KtorKeyValueRepoClient(
|
||||||
KtorReadKeyValueRepoClient(
|
KtorReadKeyValueRepoClient(
|
||||||
@@ -28,7 +38,9 @@ class KtorKeyValueRepoClient<Key, Value> (
|
|||||||
KtorWriteKeyValueRepoClient(
|
KtorWriteKeyValueRepoClient(
|
||||||
baseUrl,
|
baseUrl,
|
||||||
httpClient,
|
httpClient,
|
||||||
contentType
|
contentType,
|
||||||
|
onNewValue,
|
||||||
|
onValueRemoved
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
inline operator fun <reified Key, reified Value> invoke(
|
inline operator fun <reified Key, reified Value> invoke(
|
||||||
@@ -37,12 +49,20 @@ class KtorKeyValueRepoClient<Key, Value> (
|
|||||||
httpClient: HttpClient,
|
httpClient: HttpClient,
|
||||||
contentType: ContentType,
|
contentType: ContentType,
|
||||||
noinline idSerializer: suspend (Key) -> String,
|
noinline idSerializer: suspend (Key) -> String,
|
||||||
|
onNewValue: Flow<Pair<Key, Value>> = httpClient.createStandardWebsocketFlow(
|
||||||
|
buildStandardUrl(baseUrl, onNewValueRoute),
|
||||||
|
),
|
||||||
|
onValueRemoved: Flow<Key> = httpClient.createStandardWebsocketFlow(
|
||||||
|
buildStandardUrl(baseUrl, onValueRemovedRoute),
|
||||||
|
),
|
||||||
noinline valueSerializer: suspend (Value) -> String
|
noinline valueSerializer: suspend (Value) -> String
|
||||||
) = KtorKeyValueRepoClient(
|
) = KtorKeyValueRepoClient(
|
||||||
buildStandardUrl(baseUrl, subpart),
|
buildStandardUrl(baseUrl, subpart),
|
||||||
httpClient,
|
httpClient,
|
||||||
contentType,
|
contentType,
|
||||||
idSerializer,
|
idSerializer,
|
||||||
|
onNewValue,
|
||||||
|
onValueRemoved,
|
||||||
valueSerializer
|
valueSerializer
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@@ -60,17 +60,19 @@ class KtorWriteKeyValueRepoClient<Key, Value>(
|
|||||||
inline operator fun <reified Key, reified Value> invoke(
|
inline operator fun <reified Key, reified Value> invoke(
|
||||||
baseUrl: String,
|
baseUrl: String,
|
||||||
httpClient: HttpClient,
|
httpClient: HttpClient,
|
||||||
contentType: ContentType
|
contentType: ContentType,
|
||||||
|
onNewValue: Flow<Pair<Key, Value>> = httpClient.createStandardWebsocketFlow(
|
||||||
|
buildStandardUrl(baseUrl, onNewValueRoute),
|
||||||
|
),
|
||||||
|
onValueRemoved: Flow<Key> = httpClient.createStandardWebsocketFlow(
|
||||||
|
buildStandardUrl(baseUrl, onValueRemovedRoute),
|
||||||
|
),
|
||||||
) = KtorWriteKeyValueRepoClient<Key, Value>(
|
) = KtorWriteKeyValueRepoClient<Key, Value>(
|
||||||
baseUrl,
|
baseUrl,
|
||||||
httpClient,
|
httpClient,
|
||||||
contentType,
|
contentType,
|
||||||
httpClient.createStandardWebsocketFlow(
|
onNewValue,
|
||||||
buildStandardUrl(baseUrl, onNewValueRoute),
|
onValueRemoved,
|
||||||
),
|
|
||||||
httpClient.createStandardWebsocketFlow(
|
|
||||||
buildStandardUrl(baseUrl, onValueRemovedRoute),
|
|
||||||
),
|
|
||||||
typeInfo<List<Key>>(),
|
typeInfo<List<Key>>(),
|
||||||
typeInfo<List<Value>>(),
|
typeInfo<List<Value>>(),
|
||||||
typeInfo<Map<Key, Value>>()
|
typeInfo<Map<Key, Value>>()
|
||||||
|
@@ -1,10 +1,15 @@
|
|||||||
package dev.inmo.micro_utils.repos.ktor.client.key.values
|
package dev.inmo.micro_utils.repos.ktor.client.key.values
|
||||||
|
|
||||||
|
import dev.inmo.micro_utils.ktor.client.createStandardWebsocketFlow
|
||||||
import dev.inmo.micro_utils.ktor.common.*
|
import dev.inmo.micro_utils.ktor.common.*
|
||||||
import dev.inmo.micro_utils.repos.*
|
import dev.inmo.micro_utils.repos.*
|
||||||
|
import dev.inmo.micro_utils.repos.ktor.common.one_to_many.onDataClearedRoute
|
||||||
|
import dev.inmo.micro_utils.repos.ktor.common.one_to_many.onNewValueRoute
|
||||||
|
import dev.inmo.micro_utils.repos.ktor.common.one_to_many.onValueRemovedRoute
|
||||||
import io.ktor.client.HttpClient
|
import io.ktor.client.HttpClient
|
||||||
import io.ktor.http.ContentType
|
import io.ktor.http.ContentType
|
||||||
import io.ktor.http.encodeURLQueryComponent
|
import io.ktor.http.encodeURLQueryComponent
|
||||||
|
import kotlinx.coroutines.flow.Flow
|
||||||
import kotlinx.serialization.*
|
import kotlinx.serialization.*
|
||||||
|
|
||||||
class KtorKeyValuesRepoClient<Key, Value> (
|
class KtorKeyValuesRepoClient<Key, Value> (
|
||||||
@@ -20,6 +25,15 @@ class KtorKeyValuesRepoClient<Key, Value> (
|
|||||||
httpClient: HttpClient,
|
httpClient: HttpClient,
|
||||||
contentType: ContentType,
|
contentType: ContentType,
|
||||||
noinline keySerializer: suspend (Key) -> String,
|
noinline keySerializer: suspend (Key) -> String,
|
||||||
|
onNewValue: Flow<Pair<Key, Value>> = httpClient.createStandardWebsocketFlow(
|
||||||
|
buildStandardUrl(baseUrl, onNewValueRoute),
|
||||||
|
),
|
||||||
|
onValueRemoved: Flow<Pair<Key, Value>> = httpClient.createStandardWebsocketFlow(
|
||||||
|
buildStandardUrl(baseUrl, onValueRemovedRoute),
|
||||||
|
),
|
||||||
|
onDataCleared: Flow<Key> = httpClient.createStandardWebsocketFlow(
|
||||||
|
buildStandardUrl(baseUrl, onDataClearedRoute),
|
||||||
|
),
|
||||||
noinline valueSerializer: suspend (Value) -> String
|
noinline valueSerializer: suspend (Value) -> String
|
||||||
) = KtorKeyValuesRepoClient(
|
) = KtorKeyValuesRepoClient(
|
||||||
KtorReadKeyValuesRepoClient(
|
KtorReadKeyValuesRepoClient(
|
||||||
@@ -32,7 +46,10 @@ class KtorKeyValuesRepoClient<Key, Value> (
|
|||||||
KtorWriteKeyValuesRepoClient(
|
KtorWriteKeyValuesRepoClient(
|
||||||
baseUrl,
|
baseUrl,
|
||||||
httpClient,
|
httpClient,
|
||||||
contentType
|
contentType,
|
||||||
|
onNewValue,
|
||||||
|
onValueRemoved,
|
||||||
|
onDataCleared
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
inline operator fun <reified Key : Any, reified Value : Any> invoke(
|
inline operator fun <reified Key : Any, reified Value : Any> invoke(
|
||||||
@@ -41,12 +58,24 @@ class KtorKeyValuesRepoClient<Key, Value> (
|
|||||||
httpClient: HttpClient,
|
httpClient: HttpClient,
|
||||||
contentType: ContentType,
|
contentType: ContentType,
|
||||||
noinline keySerializer: suspend (Key) -> String,
|
noinline keySerializer: suspend (Key) -> String,
|
||||||
|
onNewValue: Flow<Pair<Key, Value>> = httpClient.createStandardWebsocketFlow(
|
||||||
|
buildStandardUrl(baseUrl, onNewValueRoute),
|
||||||
|
),
|
||||||
|
onValueRemoved: Flow<Pair<Key, Value>> = httpClient.createStandardWebsocketFlow(
|
||||||
|
buildStandardUrl(baseUrl, onValueRemovedRoute),
|
||||||
|
),
|
||||||
|
onDataCleared: Flow<Key> = httpClient.createStandardWebsocketFlow(
|
||||||
|
buildStandardUrl(baseUrl, onDataClearedRoute),
|
||||||
|
),
|
||||||
noinline valueSerializer: suspend (Value) -> String
|
noinline valueSerializer: suspend (Value) -> String
|
||||||
) = KtorKeyValuesRepoClient(
|
) = KtorKeyValuesRepoClient(
|
||||||
buildStandardUrl(baseUrl, subpart),
|
buildStandardUrl(baseUrl, subpart),
|
||||||
httpClient,
|
httpClient,
|
||||||
contentType,
|
contentType,
|
||||||
keySerializer,
|
keySerializer,
|
||||||
|
onNewValue,
|
||||||
|
onValueRemoved,
|
||||||
|
onDataCleared,
|
||||||
valueSerializer
|
valueSerializer
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -59,13 +88,25 @@ inline fun <reified Key : Any, reified Value : Any> KtorKeyValuesRepoClient(
|
|||||||
keySerializer: SerializationStrategy<Key>,
|
keySerializer: SerializationStrategy<Key>,
|
||||||
valueSerializer: SerializationStrategy<Value>,
|
valueSerializer: SerializationStrategy<Value>,
|
||||||
serialFormat: StringFormat,
|
serialFormat: StringFormat,
|
||||||
|
onNewValue: Flow<Pair<Key, Value>> = httpClient.createStandardWebsocketFlow(
|
||||||
|
buildStandardUrl(baseUrl, onNewValueRoute),
|
||||||
|
),
|
||||||
|
onValueRemoved: Flow<Pair<Key, Value>> = httpClient.createStandardWebsocketFlow(
|
||||||
|
buildStandardUrl(baseUrl, onValueRemovedRoute),
|
||||||
|
),
|
||||||
|
onDataCleared: Flow<Key> = httpClient.createStandardWebsocketFlow(
|
||||||
|
buildStandardUrl(baseUrl, onDataClearedRoute),
|
||||||
|
),
|
||||||
) = KtorKeyValuesRepoClient<Key, Value>(
|
) = KtorKeyValuesRepoClient<Key, Value>(
|
||||||
baseUrl,
|
baseUrl,
|
||||||
httpClient,
|
httpClient,
|
||||||
contentType,
|
contentType,
|
||||||
{
|
{
|
||||||
serialFormat.encodeToString(keySerializer, it).encodeURLQueryComponent()
|
serialFormat.encodeToString(keySerializer, it).encodeURLQueryComponent()
|
||||||
}
|
},
|
||||||
|
onNewValue,
|
||||||
|
onValueRemoved,
|
||||||
|
onDataCleared
|
||||||
) {
|
) {
|
||||||
serialFormat.encodeToString(valueSerializer, it).encodeURLQueryComponent()
|
serialFormat.encodeToString(valueSerializer, it).encodeURLQueryComponent()
|
||||||
}
|
}
|
||||||
@@ -77,13 +118,25 @@ inline fun <reified Key : Any, reified Value : Any> KtorKeyValuesRepoClient(
|
|||||||
keySerializer: SerializationStrategy<Key>,
|
keySerializer: SerializationStrategy<Key>,
|
||||||
valueSerializer: SerializationStrategy<Value>,
|
valueSerializer: SerializationStrategy<Value>,
|
||||||
serialFormat: BinaryFormat,
|
serialFormat: BinaryFormat,
|
||||||
|
onNewValue: Flow<Pair<Key, Value>> = httpClient.createStandardWebsocketFlow(
|
||||||
|
buildStandardUrl(baseUrl, onNewValueRoute),
|
||||||
|
),
|
||||||
|
onValueRemoved: Flow<Pair<Key, Value>> = httpClient.createStandardWebsocketFlow(
|
||||||
|
buildStandardUrl(baseUrl, onValueRemovedRoute),
|
||||||
|
),
|
||||||
|
onDataCleared: Flow<Key> = httpClient.createStandardWebsocketFlow(
|
||||||
|
buildStandardUrl(baseUrl, onDataClearedRoute),
|
||||||
|
),
|
||||||
) = KtorKeyValuesRepoClient<Key, Value>(
|
) = KtorKeyValuesRepoClient<Key, Value>(
|
||||||
baseUrl,
|
baseUrl,
|
||||||
httpClient,
|
httpClient,
|
||||||
contentType,
|
contentType,
|
||||||
{
|
{
|
||||||
serialFormat.encodeHex(keySerializer, it)
|
serialFormat.encodeHex(keySerializer, it)
|
||||||
}
|
},
|
||||||
|
onNewValue,
|
||||||
|
onValueRemoved,
|
||||||
|
onDataCleared
|
||||||
) {
|
) {
|
||||||
serialFormat.encodeHex(valueSerializer, it)
|
serialFormat.encodeHex(valueSerializer, it)
|
||||||
}
|
}
|
||||||
|
@@ -84,20 +84,23 @@ class KtorWriteKeyValuesRepoClient<Key : Any, Value : Any>(
|
|||||||
inline operator fun <reified Key : Any, reified Value : Any> invoke(
|
inline operator fun <reified Key : Any, reified Value : Any> invoke(
|
||||||
baseUrl: String,
|
baseUrl: String,
|
||||||
httpClient: HttpClient,
|
httpClient: HttpClient,
|
||||||
contentType: ContentType
|
contentType: ContentType,
|
||||||
|
onNewValue: Flow<Pair<Key, Value>> = httpClient.createStandardWebsocketFlow(
|
||||||
|
buildStandardUrl(baseUrl, onNewValueRoute),
|
||||||
|
),
|
||||||
|
onValueRemoved: Flow<Pair<Key, Value>> = httpClient.createStandardWebsocketFlow(
|
||||||
|
buildStandardUrl(baseUrl, onValueRemovedRoute),
|
||||||
|
),
|
||||||
|
onDataCleared: Flow<Key> = httpClient.createStandardWebsocketFlow(
|
||||||
|
buildStandardUrl(baseUrl, onDataClearedRoute),
|
||||||
|
),
|
||||||
) = KtorWriteKeyValuesRepoClient<Key, Value>(
|
) = KtorWriteKeyValuesRepoClient<Key, Value>(
|
||||||
baseUrl,
|
baseUrl,
|
||||||
httpClient,
|
httpClient,
|
||||||
contentType,
|
contentType,
|
||||||
httpClient.createStandardWebsocketFlow(
|
onNewValue,
|
||||||
buildStandardUrl(baseUrl, onNewValueRoute),
|
onValueRemoved,
|
||||||
),
|
onDataCleared,
|
||||||
httpClient.createStandardWebsocketFlow(
|
|
||||||
buildStandardUrl(baseUrl, onValueRemovedRoute),
|
|
||||||
),
|
|
||||||
httpClient.createStandardWebsocketFlow(
|
|
||||||
buildStandardUrl(baseUrl, onDataClearedRoute),
|
|
||||||
),
|
|
||||||
typeInfo<Key>(),
|
typeInfo<Key>(),
|
||||||
typeInfo<Value>(),
|
typeInfo<Value>(),
|
||||||
typeInfo<Map<Key, List<Value>>>()
|
typeInfo<Map<Key, List<Value>>>()
|
||||||
|
@@ -1,5 +1,6 @@
|
|||||||
package dev.inmo.micro_utils.repos.ktor.common.crud
|
package dev.inmo.micro_utils.repos.ktor.common.crud
|
||||||
|
|
||||||
const val getByPaginationRouting = "getByPagination"
|
const val getByPaginationRouting = "getByPagination"
|
||||||
|
const val getIdsByPaginationRouting = "getIdsByPagination"
|
||||||
const val getByIdRouting = "getById"
|
const val getByIdRouting = "getById"
|
||||||
const val containsRouting = "contains"
|
const val containsRouting = "contains"
|
||||||
|
@@ -23,6 +23,11 @@ inline fun <reified ObjectType, reified IdType> Route.configureReadCRUDRepoRoute
|
|||||||
|
|
||||||
call.respond(originalRepo.getByPagination(pagination))
|
call.respond(originalRepo.getByPagination(pagination))
|
||||||
}
|
}
|
||||||
|
get(getIdsByPaginationRouting) {
|
||||||
|
val pagination = call.request.queryParameters.extractPagination
|
||||||
|
|
||||||
|
call.respond(originalRepo.getIdsByPagination(pagination))
|
||||||
|
}
|
||||||
|
|
||||||
get(getByIdRouting) {
|
get(getByIdRouting) {
|
||||||
val id = idDeserializer(
|
val id = idDeserializer(
|
||||||
|
17
safe_wrapper/build.gradle
Normal file
17
safe_wrapper/build.gradle
Normal 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")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
17
safe_wrapper/src/commonMain/kotlin/SafeWrapper.kt
Normal file
17
safe_wrapper/src/commonMain/kotlin/SafeWrapper.kt
Normal 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)
|
||||||
|
}
|
||||||
|
}
|
1
safe_wrapper/src/main/AndroidManifest.xml
Normal file
1
safe_wrapper/src/main/AndroidManifest.xml
Normal file
@@ -0,0 +1 @@
|
|||||||
|
<manifest package="dev.inmo.micro_utils.safe_wrapper"/>
|
@@ -4,6 +4,7 @@ String[] includes = [
|
|||||||
":common",
|
":common",
|
||||||
":common:compose",
|
":common:compose",
|
||||||
":matrix",
|
":matrix",
|
||||||
|
":safe_wrapper",
|
||||||
":crypto",
|
":crypto",
|
||||||
":koin",
|
":koin",
|
||||||
":selector:common",
|
":selector:common",
|
||||||
@@ -32,6 +33,8 @@ String[] includes = [
|
|||||||
":serialization:base64",
|
":serialization:base64",
|
||||||
":serialization:encapsulator",
|
":serialization:encapsulator",
|
||||||
":serialization:typed_serializer",
|
":serialization:typed_serializer",
|
||||||
|
":startup:plugin",
|
||||||
|
":startup:launcher",
|
||||||
|
|
||||||
":fsm:common",
|
":fsm:common",
|
||||||
":fsm:repos:common",
|
":fsm:repos:common",
|
||||||
|
92
startup/launcher/README.md
Normal file
92
startup/launcher/README.md
Normal file
@@ -0,0 +1,92 @@
|
|||||||
|
# Startup Plugin Launcher
|
||||||
|
|
||||||
|
This module contains tools to start your plugin system.
|
||||||
|
|
||||||
|
## Config
|
||||||
|
|
||||||
|
Base config is pretty simple:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"plugins": [
|
||||||
|
"dev.inmo.micro_utils.startup.launcher.HelloWorldPlugin"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
So, `"dev.inmo.micro_utils.startup.launcher.HelloWorldPlugin"` is the fully qualified name of plugin you wish to be
|
||||||
|
included in the server.
|
||||||
|
|
||||||
|
> JS note: In JS there are no opportunity to determine object type by its full name. Because of it, in JS developers
|
||||||
|
> should prefer to use `Config` in their kotlin code directly instead of json config passing. More info see in [JS](#js)
|
||||||
|
> section
|
||||||
|
|
||||||
|
## JVM
|
||||||
|
|
||||||
|
For JVM target you may use main class by path: `dev.inmo.micro_utils.startup.launcher.MainKt`
|
||||||
|
|
||||||
|
It is expected, that you will pass the main 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](#config) section.
|
||||||
|
|
||||||
|
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`
|
||||||
|
|
||||||
|
## JS
|
||||||
|
|
||||||
|
In JS for starting of your plugins app, you should use `PluginsStarter` in your code:
|
||||||
|
|
||||||
|
```kotlin
|
||||||
|
PluginsStarter.startPlugins(
|
||||||
|
Config(HelloWorldPlugin)
|
||||||
|
)
|
||||||
|
```
|
||||||
|
|
||||||
|
`Config` here is deserialized variant from [Config](#config) section. As was said in [Config](#config) section, in JS
|
||||||
|
there is no way to find classes/objects by their full qualifiers. Because of it you should use some way to register your
|
||||||
|
plugins in `StartPluginSerializer` or use the code like in the snippet above: there plugins will be registered
|
||||||
|
automatically.
|
||||||
|
|
||||||
|
In case you wish to register your plugins manually and run server from config, you should use one of the ways to register
|
||||||
|
plugin on start.
|
||||||
|
|
||||||
|
Sample with `EagerInitialization`: [Kotlin JS doc about lazy initialization](https://kotlinlang.org/docs/js-ir-compiler.html#incremental-compilation-for-development-binaries),
|
||||||
|
[@EagerInitialization docs](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.js/-eager-initialization/):
|
||||||
|
|
||||||
|
```kotlin
|
||||||
|
@ExperimentalStdlibApi
|
||||||
|
@EagerInitialization
|
||||||
|
val plugin = createStartupPluginAndRegister("PluginNameToUseInConfig") {
|
||||||
|
// Your plugin creation. For example:
|
||||||
|
HelloWorldPlugin
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
So, in that case you will be able to load plugins list as `JsonObject` from anywhere and start plugins app with it:
|
||||||
|
|
||||||
|
```kotlin
|
||||||
|
PluginsStarter.startPlugins(
|
||||||
|
jsonObject
|
||||||
|
)
|
||||||
|
```
|
||||||
|
|
||||||
|
It will load `HelloWorldPlugin` if `jsonObject` have next content:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"plugins": [
|
||||||
|
"PluginNameToUseInConfig"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
```
|
31
startup/launcher/build.gradle
Normal file
31
startup/launcher/build.gradle
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
plugins {
|
||||||
|
id "org.jetbrains.kotlin.multiplatform"
|
||||||
|
id "org.jetbrains.kotlin.plugin.serialization"
|
||||||
|
id "application"
|
||||||
|
}
|
||||||
|
|
||||||
|
apply from: "$mppJsAndJavaProjectPresetPath"
|
||||||
|
|
||||||
|
kotlin {
|
||||||
|
sourceSets {
|
||||||
|
commonMain {
|
||||||
|
dependencies {
|
||||||
|
api internalProject("micro_utils.startup.plugin")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
commonTest {
|
||||||
|
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
|
||||||
|
}
|
22
startup/launcher/src/commonMain/kotlin/Config.kt
Normal file
22
startup/launcher/src/commonMain/kotlin/Config.kt
Normal 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>
|
||||||
|
)
|
7
startup/launcher/src/commonMain/kotlin/DefaultJson.kt
Normal file
7
startup/launcher/src/commonMain/kotlin/DefaultJson.kt
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
package dev.inmo.micro_utils.startup.launcher
|
||||||
|
|
||||||
|
import kotlinx.serialization.json.Json
|
||||||
|
|
||||||
|
val defaultJson = Json {
|
||||||
|
ignoreUnknownKeys = true
|
||||||
|
}
|
13
startup/launcher/src/commonMain/kotlin/HelloWorldPlugin.kt
Normal file
13
startup/launcher/src/commonMain/kotlin/HelloWorldPlugin.kt
Normal 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")
|
||||||
|
}
|
||||||
|
}
|
17
startup/launcher/src/commonMain/kotlin/Start.kt
Normal file
17
startup/launcher/src/commonMain/kotlin/Start.kt
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
package dev.inmo.micro_utils.startup.launcher
|
||||||
|
|
||||||
|
import dev.inmo.micro_utils.startup.launcher.StartLauncherPlugin.setupDI
|
||||||
|
import kotlinx.serialization.json.JsonObject
|
||||||
|
import org.koin.core.KoinApplication
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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]
|
||||||
|
*/
|
||||||
|
@Deprecated("Fully replaced with StartLauncherPlugin#start", ReplaceWith("StartLauncherPlugin.start(rawConfig)", "dev.inmo.micro_utils.startup.launcher.StartLauncherPlugin"))
|
||||||
|
suspend fun start(rawConfig: JsonObject) {
|
||||||
|
StartLauncherPlugin.start(rawConfig)
|
||||||
|
}
|
143
startup/launcher/src/commonMain/kotlin/StartLauncherPlugin.kt
Normal file
143
startup/launcher/src/commonMain/kotlin/StartLauncherPlugin.kt
Normal file
@@ -0,0 +1,143 @@
|
|||||||
|
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.launcher.StartLauncherPlugin.setupDI
|
||||||
|
import dev.inmo.micro_utils.startup.launcher.StartLauncherPlugin.startPlugin
|
||||||
|
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 kotlinx.serialization.json.decodeFromJsonElement
|
||||||
|
import kotlinx.serialization.json.jsonObject
|
||||||
|
import org.koin.core.Koin
|
||||||
|
import org.koin.core.KoinApplication
|
||||||
|
import org.koin.core.context.startKoin
|
||||||
|
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)
|
||||||
|
|
||||||
|
fun Module.setupDI(config: Config, rawJsonObject: JsonObject? = null) {
|
||||||
|
val rawJsonObject = rawJsonObject ?: defaultJson.encodeToJsonElement(Config.serializer(), config).jsonObject
|
||||||
|
|
||||||
|
single { rawJsonObject }
|
||||||
|
single { config }
|
||||||
|
single { CoroutineScope(Dispatchers.Default) }
|
||||||
|
single { defaultJson } binds arrayOf(StringFormat::class, SerialFormat::class)
|
||||||
|
|
||||||
|
includes(
|
||||||
|
config.plugins.mapNotNull {
|
||||||
|
runCatching {
|
||||||
|
module {
|
||||||
|
with(it) {
|
||||||
|
setupDI(rawJsonObject)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}.onFailure { e ->
|
||||||
|
logger.w("Unable to load DI part of $it", e)
|
||||||
|
}.getOrNull()
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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) {
|
||||||
|
logger.i("Koin for current module has started setup")
|
||||||
|
setupDI(
|
||||||
|
defaultJson.decodeFromJsonElement(Config.serializer(), config),
|
||||||
|
config
|
||||||
|
)
|
||||||
|
logger.i("Koin for current module has been setup")
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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) {
|
||||||
|
logger.i("Start starting of subplugins")
|
||||||
|
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 start plugin $plugin", e)
|
||||||
|
}.onSuccess {
|
||||||
|
logger.i("Complete loading of $plugin")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}.joinAll()
|
||||||
|
logger.i("Complete subplugins start")
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Will create [KoinApplication], init, load modules using [StartLauncherPlugin] and start plugins using the same base
|
||||||
|
* plugin. It is basic [start] method which accepts both [config] and [rawConfig] which suppose to be the same or
|
||||||
|
* at least [rawConfig] must contain serialized variant of [config]
|
||||||
|
*
|
||||||
|
* @param rawConfig It is expected that this [JsonObject] will contain serialized [Config] ([StartLauncherPlugin] will
|
||||||
|
* deserialize it in its [StartLauncherPlugin.setupDI]
|
||||||
|
*/
|
||||||
|
suspend fun start(config: Config, rawConfig: JsonObject) {
|
||||||
|
|
||||||
|
logger.i("Start initialization")
|
||||||
|
val koinApp = KoinApplication.init()
|
||||||
|
koinApp.modules(
|
||||||
|
module {
|
||||||
|
setupDI(config, rawConfig)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
logger.i("Modules loaded")
|
||||||
|
startKoin(koinApp)
|
||||||
|
logger.i("Koin started")
|
||||||
|
startPlugin(koinApp.koin)
|
||||||
|
logger.i("App has been setup")
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Call [start] with deserialized [Config] as config and [rawConfig] as is
|
||||||
|
*
|
||||||
|
* @param rawConfig It is expected that this [JsonObject] will contain serialized [Config]
|
||||||
|
*/
|
||||||
|
suspend fun start(rawConfig: JsonObject) {
|
||||||
|
|
||||||
|
start(defaultJson.decodeFromJsonElement(Config.serializer(), rawConfig), rawConfig)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Call [start] with deserialized [Config] as is and serialize it to [JsonObject] to pass as the first parameter
|
||||||
|
* to the basic [start] method
|
||||||
|
*
|
||||||
|
* @param config Will be converted to [JsonObject] as raw config. That means that all plugins from [config] will
|
||||||
|
* receive serialized version of [config] in [StartPlugin.setupDI] method
|
||||||
|
*/
|
||||||
|
suspend fun start(config: Config) {
|
||||||
|
|
||||||
|
start(config, defaultJson.encodeToJsonElement(Config.serializer(), config).jsonObject)
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,45 @@
|
|||||||
|
import dev.inmo.micro_utils.startup.launcher.Config
|
||||||
|
import dev.inmo.micro_utils.startup.launcher.HelloWorldPlugin
|
||||||
|
import dev.inmo.micro_utils.startup.launcher.StartLauncherPlugin
|
||||||
|
import dev.inmo.micro_utils.startup.launcher.defaultJson
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
import kotlinx.coroutines.test.runTest
|
||||||
|
import kotlinx.serialization.json.jsonObject
|
||||||
|
import org.koin.core.context.stopKoin
|
||||||
|
import kotlin.test.BeforeTest
|
||||||
|
import kotlin.test.Test
|
||||||
|
|
||||||
|
class StartupLaunchingTests {
|
||||||
|
@BeforeTest
|
||||||
|
fun resetGlobalKoinContext() {
|
||||||
|
runCatching { stopKoin() }
|
||||||
|
}
|
||||||
|
@Test
|
||||||
|
fun CheckThatEmptyPluginsListLeadsToEndOfMain() {
|
||||||
|
val emptyJson = defaultJson.encodeToJsonElement(
|
||||||
|
Config.serializer(),
|
||||||
|
Config(emptyList())
|
||||||
|
).jsonObject
|
||||||
|
|
||||||
|
runTest {
|
||||||
|
val job = launch {
|
||||||
|
StartLauncherPlugin.start(emptyJson)
|
||||||
|
}
|
||||||
|
job.join()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@Test
|
||||||
|
fun CheckThatHelloWorldPluginsListLeadsToEndOfMain() {
|
||||||
|
val emptyJson = defaultJson.encodeToJsonElement(
|
||||||
|
Config.serializer(),
|
||||||
|
Config(listOf(HelloWorldPlugin))
|
||||||
|
).jsonObject
|
||||||
|
|
||||||
|
runTest {
|
||||||
|
val job = launch {
|
||||||
|
StartLauncherPlugin.start(emptyJson)
|
||||||
|
}
|
||||||
|
job.join()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
25
startup/launcher/src/jsMain/kotlin/PluginsStarter.kt
Normal file
25
startup/launcher/src/jsMain/kotlin/PluginsStarter.kt
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
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 kotlinx.serialization.json.jsonObject
|
||||||
|
|
||||||
|
@Deprecated("Useless due to including of the same functionality in StrtLauncherPlugin")
|
||||||
|
object PluginsStarter {
|
||||||
|
init {
|
||||||
|
KSLog.default = KSLog("Launcher")
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* It is expected that you have registered all the [dev.inmo.micro_utils.startup.plugin.StartPlugin]s of your JS
|
||||||
|
* app inside of [dev.inmo.micro_utils.startup.plugin.StartPluginSerializer] using its
|
||||||
|
* [dev.inmo.micro_utils.startup.plugin.StartPluginSerializer.registerPlugin] method
|
||||||
|
*/
|
||||||
|
suspend fun startPlugins(json: JsonObject) = StartLauncherPlugin.start(json)
|
||||||
|
/**
|
||||||
|
* Will convert [config] to [JsonObject] with auto registration of [dev.inmo.micro_utils.startup.plugin.StartPlugin]s
|
||||||
|
* in [dev.inmo.micro_utils.startup.plugin.StartPluginSerializer]
|
||||||
|
*/
|
||||||
|
suspend fun startPlugins(config: Config) = StartLauncherPlugin.start(config)
|
||||||
|
}
|
53
startup/launcher/src/jvmMain/kotlin/Main.kt
Normal file
53
startup/launcher/src/jvmMain/kotlin/Main.kt
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
package dev.inmo.micro_utils.startup.launcher
|
||||||
|
|
||||||
|
import dev.inmo.kslog.common.KSLog
|
||||||
|
import dev.inmo.kslog.common.LogLevel
|
||||||
|
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`
|
||||||
|
*
|
||||||
|
* ## Debug mode
|
||||||
|
*
|
||||||
|
* You may pass the second parameter, one of [LogLevel] enum variants to setup [KSLog] minimal logging level. Sample:
|
||||||
|
*
|
||||||
|
* ```bash
|
||||||
|
* ./gradlew run --args="sample.config.json DEBUG" // enable debugging output
|
||||||
|
* ```
|
||||||
|
*
|
||||||
|
* OR
|
||||||
|
* ```bash
|
||||||
|
* ./gradlew run --args="sample.config.json WARNING" // enable logging since WARNING
|
||||||
|
* ```
|
||||||
|
*
|
||||||
|
* **Default level is [LogLevel.INFO]**
|
||||||
|
*/
|
||||||
|
suspend fun main(args: Array<String>) {
|
||||||
|
|
||||||
|
KSLog.default = KSLog("Launcher", args.getOrNull(1) ?.let { LogLevel.valueOf(it) } ?: LogLevel.INFO)
|
||||||
|
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")
|
||||||
|
|
||||||
|
StartLauncherPlugin.start(json)
|
||||||
|
}
|
25
startup/plugin/build.gradle
Normal file
25
startup/plugin/build.gradle
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
plugins {
|
||||||
|
id "org.jetbrains.kotlin.multiplatform"
|
||||||
|
id "org.jetbrains.kotlin.plugin.serialization"
|
||||||
|
}
|
||||||
|
|
||||||
|
apply from: "$mppJsAndJavaProjectPresetPath"
|
||||||
|
|
||||||
|
kotlin {
|
||||||
|
sourceSets {
|
||||||
|
commonMain {
|
||||||
|
dependencies {
|
||||||
|
api libs.koin
|
||||||
|
api libs.kt.serialization
|
||||||
|
api libs.kslog
|
||||||
|
api libs.kt.reflect
|
||||||
|
api project(":micro_utils.coroutines")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
jsMain {
|
||||||
|
dependencies {
|
||||||
|
api libs.uuid
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
31
startup/plugin/src/commonMain/kotlin/StartPlugin.kt
Normal file
31
startup/plugin/src/commonMain/kotlin/StartPlugin.kt
Normal 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) {}
|
||||||
|
}
|
@@ -0,0 +1,5 @@
|
|||||||
|
package dev.inmo.micro_utils.startup.plugin
|
||||||
|
|
||||||
|
import kotlinx.serialization.KSerializer
|
||||||
|
|
||||||
|
expect object StartPluginSerializer : KSerializer<StartPlugin>
|
@@ -0,0 +1,38 @@
|
|||||||
|
package dev.inmo.micro_utils.startup.plugin
|
||||||
|
|
||||||
|
import com.benasher44.uuid.uuid4
|
||||||
|
import kotlin.reflect.KClass
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates [T] using [block], register it in [StartPluginSerializer] using its [StartPluginSerializer.registerPlugin]
|
||||||
|
* and returns created by [block] plugin
|
||||||
|
*
|
||||||
|
* @param name Will be used as a key for registration in [StartPluginSerializer] and will be passed to the [block] as
|
||||||
|
* parameter
|
||||||
|
*/
|
||||||
|
inline fun <T : StartPlugin> createStartupPluginAndRegister(
|
||||||
|
name: String = uuid4().toString(),
|
||||||
|
block: (String) -> T
|
||||||
|
): T {
|
||||||
|
val plugin = block(name)
|
||||||
|
StartPluginSerializer.registerPlugin(name, plugin)
|
||||||
|
return plugin
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates [T] using [block], register it in [StartPluginSerializer] using its [StartPluginSerializer.registerPlugin]
|
||||||
|
* and returns created by [block] plugin
|
||||||
|
*/
|
||||||
|
inline fun <T : StartPlugin> createStartupPluginAndRegister(
|
||||||
|
kClass: KClass<T>,
|
||||||
|
name: String = uuid4().toString(),
|
||||||
|
block: (String) -> T
|
||||||
|
): T = createStartupPluginAndRegister("${kClass.simpleName}_$name", block)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates [T] using [block], register it in [StartPluginSerializer] using its [StartPluginSerializer.registerPlugin]
|
||||||
|
* and returns created by [block] plugin
|
||||||
|
*/
|
||||||
|
inline fun <reified T : StartPlugin> createStartupPluginAndRegister(
|
||||||
|
block: (String) -> T
|
||||||
|
): T = createStartupPluginAndRegister(T::class, uuid4().toString(), block)
|
35
startup/plugin/src/jsMain/kotlin/StartPluginSerializer.kt
Normal file
35
startup/plugin/src/jsMain/kotlin/StartPluginSerializer.kt
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
package dev.inmo.micro_utils.startup.plugin
|
||||||
|
|
||||||
|
import com.benasher44.uuid.uuid4
|
||||||
|
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> {
|
||||||
|
private val registeredPlugins = mutableMapOf<String, StartPlugin>()
|
||||||
|
private val registeredPluginsByPlugin = mutableMapOf<StartPlugin, String>()
|
||||||
|
override val descriptor: SerialDescriptor = String.serializer().descriptor
|
||||||
|
|
||||||
|
override fun deserialize(decoder: Decoder): StartPlugin {
|
||||||
|
val name = decoder.decodeString()
|
||||||
|
return registeredPlugins[name] ?: error("Unable to find startup plugin for $name")
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun serialize(encoder: Encoder, value: StartPlugin) {
|
||||||
|
val name = registeredPluginsByPlugin[value] ?: uuid4().toString().also {
|
||||||
|
registeredPlugins[it] = value
|
||||||
|
registeredPluginsByPlugin[value] = it
|
||||||
|
}
|
||||||
|
encoder.encodeString(name)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Register plugin inside of this [KSerializer]. Since plugin has been registered, you may use its [name] in any
|
||||||
|
* serialized [dev.inmo.micro_utils.startup.launcher.Config] to retrieve [plugin] you passed here
|
||||||
|
*/
|
||||||
|
fun registerPlugin(name: String, plugin: StartPlugin) {
|
||||||
|
registeredPlugins[name] = plugin
|
||||||
|
}
|
||||||
|
}
|
23
startup/plugin/src/jvmMain/kotlin/StartPluginSerializer.kt
Normal file
23
startup/plugin/src/jvmMain/kotlin/StartPluginSerializer.kt
Normal 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
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
10
startup/template/README.md
Normal file
10
startup/template/README.md
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
# How to use
|
||||||
|
|
||||||
|
In case you have multiplatform project and wish to use startup plugin, this template may help you to create new modules.
|
||||||
|
|
||||||
|
1. Copy-paste whole template folder (you may clone this folder to your project and actualize some data to copy your prepared template)
|
||||||
|
2. Replace `group_name` by your project (or root module) group name
|
||||||
|
3. Replace `module_name` by the name of your new module name
|
||||||
|
|
||||||
|
You may read about the `build.gradle` structure in these templates in project
|
||||||
|
[KotlinMultiplatformProjectTemplate](https://github.com/InsanusMokrassar/KotlinMultiplatformProjectTemplate).
|
18
startup/template/client/build.gradle
Normal file
18
startup/template/client/build.gradle
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
plugins {
|
||||||
|
id "org.jetbrains.kotlin.multiplatform"
|
||||||
|
id "org.jetbrains.kotlin.plugin.serialization"
|
||||||
|
id "com.android.library"
|
||||||
|
alias(libs.plugins.compose)
|
||||||
|
}
|
||||||
|
|
||||||
|
apply from: "$mppProjectWithSerializationPresetPath"
|
||||||
|
|
||||||
|
kotlin {
|
||||||
|
sourceSets {
|
||||||
|
commonMain {
|
||||||
|
dependencies {
|
||||||
|
api project(":${rootProject.name}.module_name.common")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,15 @@
|
|||||||
|
package group_name.module_name.client
|
||||||
|
|
||||||
|
import dev.inmo.micro_utils.startup.plugin.StartPlugin
|
||||||
|
import kotlinx.serialization.json.JsonObject
|
||||||
|
import org.koin.core.Koin
|
||||||
|
import org.koin.core.module.Module
|
||||||
|
|
||||||
|
object ClientPlugin : StartPlugin {
|
||||||
|
override fun Module.setupDI(config: JsonObject) {
|
||||||
|
}
|
||||||
|
|
||||||
|
override suspend fun startPlugin(koin: Koin) {
|
||||||
|
super.startPlugin(koin)
|
||||||
|
}
|
||||||
|
}
|
20
startup/template/client/src/jsMain/kotlin/ClientJSPlugin.kt
Normal file
20
startup/template/client/src/jsMain/kotlin/ClientJSPlugin.kt
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
package group_name.module_name.client
|
||||||
|
|
||||||
|
import group_name.module_name.common.CommonJSPlugin
|
||||||
|
import dev.inmo.micro_utils.startup.plugin.StartPlugin
|
||||||
|
import kotlinx.serialization.json.JsonObject
|
||||||
|
import org.koin.core.Koin
|
||||||
|
import org.koin.core.module.Module
|
||||||
|
|
||||||
|
object ClientJSPlugin : StartPlugin {
|
||||||
|
override fun Module.setupDI(config: JsonObject) {
|
||||||
|
with(CommonJSPlugin) { setupDI(config) }
|
||||||
|
with(ClientPlugin) { setupDI(config) }
|
||||||
|
}
|
||||||
|
|
||||||
|
override suspend fun startPlugin(koin: Koin) {
|
||||||
|
super.startPlugin(koin)
|
||||||
|
CommonJSPlugin.startPlugin(koin)
|
||||||
|
ClientPlugin.startPlugin(koin)
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,9 @@
|
|||||||
|
package group_name.module_name.client
|
||||||
|
|
||||||
|
import dev.inmo.micro_utils.startup.plugin.createStartupPluginAndRegister
|
||||||
|
|
||||||
|
@ExperimentalStdlibApi
|
||||||
|
@EagerInitialization
|
||||||
|
@JsExport
|
||||||
|
@ExperimentalJsExport
|
||||||
|
private val jsModuleLoader = createStartupPluginAndRegister("template.ClientJSPlugin") { ClientJSPlugin }
|
@@ -0,0 +1,21 @@
|
|||||||
|
package group_name.module_name.client
|
||||||
|
|
||||||
|
import group_name.module_name.common.CommonJVMPlugin
|
||||||
|
import group_name.module_name.common.CommonJVMPlugin.setupDI
|
||||||
|
import dev.inmo.micro_utils.startup.plugin.StartPlugin
|
||||||
|
import kotlinx.serialization.json.JsonObject
|
||||||
|
import org.koin.core.Koin
|
||||||
|
import org.koin.core.module.Module
|
||||||
|
|
||||||
|
object ClientJVMPlugin : StartPlugin {
|
||||||
|
override fun Module.setupDI(config: JsonObject) {
|
||||||
|
with(CommonJVMPlugin) { setupDI(config) }
|
||||||
|
with(ClientPlugin) { setupDI(config) }
|
||||||
|
}
|
||||||
|
|
||||||
|
override suspend fun startPlugin(koin: Koin) {
|
||||||
|
super.startPlugin(koin)
|
||||||
|
CommonJVMPlugin.startPlugin(koin)
|
||||||
|
ClientPlugin.startPlugin(koin)
|
||||||
|
}
|
||||||
|
}
|
1
startup/template/client/src/main/AndroidManifest.xml
Normal file
1
startup/template/client/src/main/AndroidManifest.xml
Normal file
@@ -0,0 +1 @@
|
|||||||
|
<manifest package="group_name.module_name.client"/>
|
@@ -0,0 +1,21 @@
|
|||||||
|
package group_name.module_name.client
|
||||||
|
|
||||||
|
import group_name.module_name.common.CommonAndroidPlugin
|
||||||
|
import group_name.module_name.common.CommonAndroidPlugin.setupDI
|
||||||
|
import dev.inmo.micro_utils.startup.plugin.StartPlugin
|
||||||
|
import kotlinx.serialization.json.JsonObject
|
||||||
|
import org.koin.core.Koin
|
||||||
|
import org.koin.core.module.Module
|
||||||
|
|
||||||
|
object ClientAndroidPlugin : StartPlugin {
|
||||||
|
override fun Module.setupDI(config: JsonObject) {
|
||||||
|
with(CommonAndroidPlugin) { setupDI(config) }
|
||||||
|
with(ClientPlugin) { setupDI(config) }
|
||||||
|
}
|
||||||
|
|
||||||
|
override suspend fun startPlugin(koin: Koin) {
|
||||||
|
super.startPlugin(koin)
|
||||||
|
CommonAndroidPlugin.startPlugin(koin)
|
||||||
|
ClientPlugin.startPlugin(koin)
|
||||||
|
}
|
||||||
|
}
|
7
startup/template/common/build.gradle
Normal file
7
startup/template/common/build.gradle
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
plugins {
|
||||||
|
id "org.jetbrains.kotlin.multiplatform"
|
||||||
|
id "org.jetbrains.kotlin.plugin.serialization"
|
||||||
|
id "com.android.library"
|
||||||
|
}
|
||||||
|
|
||||||
|
apply from: "$mppProjectWithSerializationPresetPath"
|
@@ -0,0 +1,11 @@
|
|||||||
|
package group_name.module_name.common
|
||||||
|
|
||||||
|
import dev.inmo.micro_utils.startup.plugin.StartPlugin
|
||||||
|
import kotlinx.serialization.json.JsonObject
|
||||||
|
import org.koin.core.module.Module
|
||||||
|
|
||||||
|
object CommonPlugin : StartPlugin {
|
||||||
|
override fun Module.setupDI(config: JsonObject) {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1 @@
|
|||||||
|
package group_name.module_name.common
|
17
startup/template/common/src/jsMain/kotlin/CommonJSPlugin.kt
Normal file
17
startup/template/common/src/jsMain/kotlin/CommonJSPlugin.kt
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
package group_name.module_name.common
|
||||||
|
|
||||||
|
import dev.inmo.micro_utils.startup.plugin.StartPlugin
|
||||||
|
import kotlinx.serialization.json.JsonObject
|
||||||
|
import org.koin.core.Koin
|
||||||
|
import org.koin.core.module.Module
|
||||||
|
|
||||||
|
object CommonJSPlugin : StartPlugin {
|
||||||
|
override fun Module.setupDI(config: JsonObject) {
|
||||||
|
with (CommonPlugin) { setupDI(config) }
|
||||||
|
}
|
||||||
|
|
||||||
|
override suspend fun startPlugin(koin: Koin) {
|
||||||
|
super.startPlugin(koin)
|
||||||
|
CommonPlugin.startPlugin(koin)
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,9 @@
|
|||||||
|
package group_name.module_name.common
|
||||||
|
|
||||||
|
import dev.inmo.micro_utils.startup.plugin.createStartupPluginAndRegister
|
||||||
|
|
||||||
|
@ExperimentalStdlibApi
|
||||||
|
@EagerInitialization
|
||||||
|
@JsExport
|
||||||
|
@ExperimentalJsExport
|
||||||
|
private val jsModuleLoader = createStartupPluginAndRegister("template.CommonJSPlugin") { CommonJSPlugin }
|
@@ -0,0 +1,17 @@
|
|||||||
|
package group_name.module_name.common
|
||||||
|
|
||||||
|
import dev.inmo.micro_utils.startup.plugin.StartPlugin
|
||||||
|
import kotlinx.serialization.json.JsonObject
|
||||||
|
import org.koin.core.Koin
|
||||||
|
import org.koin.core.module.Module
|
||||||
|
|
||||||
|
object CommonJVMPlugin : StartPlugin {
|
||||||
|
override fun Module.setupDI(config: JsonObject) {
|
||||||
|
with (CommonPlugin) { setupDI(config) }
|
||||||
|
}
|
||||||
|
|
||||||
|
override suspend fun startPlugin(koin: Koin) {
|
||||||
|
super.startPlugin(koin)
|
||||||
|
CommonPlugin.startPlugin(koin)
|
||||||
|
}
|
||||||
|
}
|
1
startup/template/common/src/main/AndroidManifest.xml
Normal file
1
startup/template/common/src/main/AndroidManifest.xml
Normal file
@@ -0,0 +1 @@
|
|||||||
|
<manifest package="group_name.module_name.common"/>
|
@@ -0,0 +1,17 @@
|
|||||||
|
package group_name.module_name.common
|
||||||
|
|
||||||
|
import dev.inmo.micro_utils.startup.plugin.StartPlugin
|
||||||
|
import kotlinx.serialization.json.JsonObject
|
||||||
|
import org.koin.core.Koin
|
||||||
|
import org.koin.core.module.Module
|
||||||
|
|
||||||
|
object CommonAndroidPlugin : StartPlugin {
|
||||||
|
override fun Module.setupDI(config: JsonObject) {
|
||||||
|
with (CommonPlugin) { setupDI(config) }
|
||||||
|
}
|
||||||
|
|
||||||
|
override suspend fun startPlugin(koin: Koin) {
|
||||||
|
super.startPlugin(koin)
|
||||||
|
CommonPlugin.startPlugin(koin)
|
||||||
|
}
|
||||||
|
}
|
16
startup/template/server/build.gradle
Normal file
16
startup/template/server/build.gradle
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
plugins {
|
||||||
|
id "org.jetbrains.kotlin.multiplatform"
|
||||||
|
id "org.jetbrains.kotlin.plugin.serialization"
|
||||||
|
}
|
||||||
|
|
||||||
|
apply from: "$mppJavaProjectPresetPath"
|
||||||
|
|
||||||
|
kotlin {
|
||||||
|
sourceSets {
|
||||||
|
commonMain {
|
||||||
|
dependencies {
|
||||||
|
api project(":${rootProject.name}.module_name.common")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,15 @@
|
|||||||
|
package group_name.module_name.server
|
||||||
|
|
||||||
|
import dev.inmo.micro_utils.startup.plugin.StartPlugin
|
||||||
|
import kotlinx.serialization.json.JsonObject
|
||||||
|
import org.koin.core.Koin
|
||||||
|
import org.koin.core.module.Module
|
||||||
|
|
||||||
|
object ServerPlugin : StartPlugin {
|
||||||
|
override fun Module.setupDI(config: JsonObject) {
|
||||||
|
}
|
||||||
|
|
||||||
|
override suspend fun startPlugin(koin: Koin) {
|
||||||
|
super.startPlugin(koin)
|
||||||
|
}
|
||||||
|
}
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user