diff --git a/CHANGELOG.md b/CHANGELOG.md index fa1b60f6fa0..36c3afd2074 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,20 @@ # Changelog +## 0.7.1 + +* `Versions`: + * `Klock`: `2.4.3` -> `2.4.5` + * `Exposed`: `0.35.1` -> `0.35.2` +* `Coroutines`: + * `Common`: + * New `Flow` - `AccumulatorFlow` +* `FSM`: + * `Common`: + * `InMemoryStatesManager` has been replaced + * `StatesMachine` became an interface + * New manager `DefaultStatesManager` with `DefaultStatesManagerRepo` for abstraction of manager and storing of + data info + ## 0.7.0 **THIS VERSION HAS MIGRATED FROM KOTLINX DATETIME TO KORLIBS KLOCK. CAREFUL** diff --git a/coroutines/src/commonMain/kotlin/dev/inmo/micro_utils/coroutines/AccumulatorFlow.kt b/coroutines/src/commonMain/kotlin/dev/inmo/micro_utils/coroutines/AccumulatorFlow.kt new file mode 100644 index 00000000000..eaee88190aa --- /dev/null +++ b/coroutines/src/commonMain/kotlin/dev/inmo/micro_utils/coroutines/AccumulatorFlow.kt @@ -0,0 +1,94 @@ +package dev.inmo.micro_utils.coroutines + +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.channels.BufferOverflow +import kotlinx.coroutines.channels.Channel +import kotlinx.coroutines.flow.* +import kotlinx.coroutines.sync.Mutex +import kotlinx.coroutines.sync.withLock + +private sealed interface AccumulatorFlowStep +private data class DataRetrievedAccumulatorFlowStep(val data: Any) : AccumulatorFlowStep +private data class SubscribeAccumulatorFlowStep(val channel: Channel) : AccumulatorFlowStep +private data class UnsubscribeAccumulatorFlowStep(val channel: Channel) : AccumulatorFlowStep + +/** + * This [Flow] will have behaviour very similar to [SharedFlow], but there are several differences: + * + * * All unhandled by [FlowCollector] data will not be removed from [AccumulatorFlow] and will be sent to new + * [FlowCollector]s until anybody will handle it + * * Here there are an [activeData] where data [T] will be stored until somebody will handle it + */ +class AccumulatorFlow( + sourceDataFlow: Flow, + scope: CoroutineScope +) : AbstractFlow() { + private val subscope = scope.LinkedSupervisorScope() + private val activeData = ArrayDeque() + private val dataMutex = Mutex() + private val channelsForBroadcast = mutableListOf>() + private val channelsMutex = Mutex() + private val steps = subscope.actor { step -> + when (step) { + is DataRetrievedAccumulatorFlowStep -> { + if (activeData.first() === step.data) { + dataMutex.withLock { + activeData.removeFirst() + } + } + } + is SubscribeAccumulatorFlowStep -> channelsMutex.withLock { + channelsForBroadcast.add(step.channel) + dataMutex.withLock { + val dataToSend = activeData.toList() + safelyWithoutExceptions { + dataToSend.forEach { step.channel.send(it as Any) } + } + } + } + is UnsubscribeAccumulatorFlowStep -> channelsMutex.withLock { + channelsForBroadcast.remove(step.channel) + } + } + } + private val subscriptionJob = sourceDataFlow.subscribeSafelyWithoutExceptions(subscope) { + dataMutex.withLock { + activeData.addLast(it) + } + channelsMutex.withLock { + channelsForBroadcast.forEach { channel -> + safelyWithResult { + channel.send(it as Any) + } + } + } + } + + override suspend fun collectSafely(collector: FlowCollector) { + val channel = Channel(Channel.UNLIMITED, BufferOverflow.SUSPEND) + steps.send(SubscribeAccumulatorFlowStep(channel)) + for (data in channel) { + try { + collector.emit(data as T) + steps.send(DataRetrievedAccumulatorFlowStep(data)) + } finally { + channel.cancel() + steps.send(UnsubscribeAccumulatorFlowStep(channel)) + } + } + } +} + +/** + * Creates [AccumulatorFlow] using [this] as base [Flow] + */ +fun Flow.accumulatorFlow(scope: CoroutineScope): Flow { + return AccumulatorFlow(this, scope) +} + +/** + * Creates [AccumulatorFlow] using [this] with [receiveAsFlow] to get + */ +fun Channel.accumulatorFlow(scope: CoroutineScope): Flow { + return receiveAsFlow().accumulatorFlow(scope) +} diff --git a/fsm/common/src/commonMain/kotlin/dev/inmo/micro_utils/fsm/common/InMemoryStatesManager.kt b/fsm/common/src/commonMain/kotlin/dev/inmo/micro_utils/fsm/common/InMemoryStatesManager.kt new file mode 100644 index 00000000000..d00bbbc42fe --- /dev/null +++ b/fsm/common/src/commonMain/kotlin/dev/inmo/micro_utils/fsm/common/InMemoryStatesManager.kt @@ -0,0 +1,6 @@ +package dev.inmo.micro_utils.fsm.common + +import dev.inmo.micro_utils.fsm.common.managers.InMemoryStatesManager + +@Deprecated("Replaced", ReplaceWith("InMemoryStatesManager", "dev.inmo.micro_utils.fsm.common.managers.InMemoryStatesManager")) +typealias InMemoryStatesManager = InMemoryStatesManager diff --git a/fsm/common/src/commonMain/kotlin/dev/inmo/micro_utils/fsm/common/StateHandlerHolder.kt b/fsm/common/src/commonMain/kotlin/dev/inmo/micro_utils/fsm/common/StateHandlerHolder.kt index 5b06f317c16..a92f9b96602 100644 --- a/fsm/common/src/commonMain/kotlin/dev/inmo/micro_utils/fsm/common/StateHandlerHolder.kt +++ b/fsm/common/src/commonMain/kotlin/dev/inmo/micro_utils/fsm/common/StateHandlerHolder.kt @@ -2,13 +2,25 @@ package dev.inmo.micro_utils.fsm.common import kotlin.reflect.KClass +/** + * Default realization of [StatesHandler]. It will incapsulate checking of [State] type in [checkHandleable] and class + * casting in [handleState] + */ class StateHandlerHolder( private val inputKlass: KClass, private val strict: Boolean = false, private val delegateTo: StatesHandler ) : StatesHandler { + /** + * Checks that [state] can be handled by [delegateTo]. Under the hood it will check exact equality of [state] + * [KClass] and use [KClass.isInstance] of [inputKlass] if [strict] == false + */ fun checkHandleable(state: State) = state::class == inputKlass || (!strict && inputKlass.isInstance(state)) + /** + * Calls [delegateTo] method [StatesHandler.handleState] with [state] casted to [I]. Use [checkHandleable] + * to be sure that this [StateHandlerHolder] will be able to handle [state] + */ override suspend fun StatesMachine.handleState(state: State): State? { return delegateTo.run { handleState(state as I) } } diff --git a/fsm/common/src/commonMain/kotlin/dev/inmo/micro_utils/fsm/common/StatesHandler.kt b/fsm/common/src/commonMain/kotlin/dev/inmo/micro_utils/fsm/common/StatesHandler.kt index b152b38dea6..a64f5133d96 100644 --- a/fsm/common/src/commonMain/kotlin/dev/inmo/micro_utils/fsm/common/StatesHandler.kt +++ b/fsm/common/src/commonMain/kotlin/dev/inmo/micro_utils/fsm/common/StatesHandler.kt @@ -1,5 +1,12 @@ package dev.inmo.micro_utils.fsm.common +/** + * Default realization of states handler + */ fun interface StatesHandler { + /** + * Main handling of [state]. In case when this [state] leads to another [State] and [handleState] returns not null + * [State] it is assumed that chain is not completed. + */ suspend fun StatesMachine.handleState(state: I): State? } diff --git a/fsm/common/src/commonMain/kotlin/dev/inmo/micro_utils/fsm/common/StatesMachine.kt b/fsm/common/src/commonMain/kotlin/dev/inmo/micro_utils/fsm/common/StatesMachine.kt index 5c2ea9592d9..11170c5b030 100644 --- a/fsm/common/src/commonMain/kotlin/dev/inmo/micro_utils/fsm/common/StatesMachine.kt +++ b/fsm/common/src/commonMain/kotlin/dev/inmo/micro_utils/fsm/common/StatesMachine.kt @@ -13,13 +13,53 @@ private suspend fun StatesMachine.launchStateHandling( } } -class StatesMachine ( +/** + * Default [StatesMachine] may [startChain] and use inside logic for handling [State]s. By default you may use + * [DefaultStatesMachine] or build it with [dev.inmo.micro_utils.fsm.common.dsl.buildFSM]. Implementers MUST NOT start + * handling until [start] method will be called + */ +interface StatesMachine : StatesHandler { + /** + * Starts handling of [State]s + */ + fun start(scope: CoroutineScope): Job + + /** + * Start chain of [State]s witn [state] + */ + suspend fun startChain(state: State) + + companion object { + /** + * Creates [DefaultStatesMachine] + */ + operator fun invoke( + statesManager: StatesManager, + handlers: List> + ) = DefaultStatesMachine(statesManager, handlers) + } +} + +/** + * Default realization of [StatesMachine]. It uses [statesManager] for incapsulation of [State]s storing and contexts + * resolving, and uses [launchStateHandling] for [State] handling + */ +class DefaultStatesMachine ( private val statesManager: StatesManager, private val handlers: List> -) : StatesHandler { +) : StatesMachine { + /** + * Will call [launchStateHandling] for state handling + */ override suspend fun StatesMachine.handleState(state: State): State? = launchStateHandling(state, handlers) - fun start(scope: CoroutineScope): Job = scope.launchSafelyWithoutExceptions { + /** + * Launch handling of states. On [statesManager] [StatesManager.onStartChain], + * [statesManager] [StatesManager.onChainStateUpdated] will be called lambda with performing of state. If + * [launchStateHandling] will returns some [State] then [statesManager] [StatesManager.update] will be used, otherwise + * [StatesManager.endChain]. + */ + override fun start(scope: CoroutineScope): Job = scope.launchSafelyWithoutExceptions { val statePerformer: suspend (State) -> Unit = { state: State -> val newState = launchStateHandling(state, handlers) if (newState != null) { @@ -40,7 +80,10 @@ class StatesMachine ( } } - suspend fun startChain(state: State) { + /** + * Just calls [StatesManager.startChain] of [statesManager] + */ + override suspend fun startChain(state: State) { statesManager.startChain(state) } } diff --git a/fsm/common/src/commonMain/kotlin/dev/inmo/micro_utils/fsm/common/StatesManager.kt b/fsm/common/src/commonMain/kotlin/dev/inmo/micro_utils/fsm/common/StatesManager.kt index ac52d84b6e8..6b341aafa60 100644 --- a/fsm/common/src/commonMain/kotlin/dev/inmo/micro_utils/fsm/common/StatesManager.kt +++ b/fsm/common/src/commonMain/kotlin/dev/inmo/micro_utils/fsm/common/StatesManager.kt @@ -1,8 +1,6 @@ package dev.inmo.micro_utils.fsm.common import kotlinx.coroutines.flow.* -import kotlinx.coroutines.sync.Mutex -import kotlinx.coroutines.sync.withLock interface StatesManager { val onChainStateUpdated: Flow> @@ -30,63 +28,3 @@ interface StatesManager { suspend fun getActiveStates(): List } -/** - * @param onContextsConflictResolver Receive old [State], new one and the state currently placed on new [State.context] - * key. In case when this callback will returns true, the state placed on [State.context] of new will be replaced by - * new state by using [endChain] with that state - */ -class InMemoryStatesManager( - private val onContextsConflictResolver: suspend (old: State, new: State, currentNew: State) -> Boolean = { _, _, _ -> true } -) : StatesManager { - private val _onChainStateUpdated = MutableSharedFlow>(0) - override val onChainStateUpdated: Flow> = _onChainStateUpdated.asSharedFlow() - private val _onStartChain = MutableSharedFlow(0) - override val onStartChain: Flow = _onStartChain.asSharedFlow() - private val _onEndChain = MutableSharedFlow(0) - override val onEndChain: Flow = _onEndChain.asSharedFlow() - - private val contextsToStates = mutableMapOf() - private val mapMutex = Mutex() - - override suspend fun update(old: State, new: State) = mapMutex.withLock { - when { - contextsToStates[old.context] != old -> return@withLock - old.context == new.context || !contextsToStates.containsKey(new.context) -> { - contextsToStates[old.context] = new - _onChainStateUpdated.emit(old to new) - } - else -> { - val stateOnNewOneContext = contextsToStates.getValue(new.context) - if (onContextsConflictResolver(old, new, stateOnNewOneContext)) { - endChainWithoutLock(stateOnNewOneContext) - contextsToStates.remove(old.context) - contextsToStates[new.context] = new - _onChainStateUpdated.emit(old to new) - } - } - } - } - - override suspend fun startChain(state: State) = mapMutex.withLock { - if (!contextsToStates.containsKey(state.context)) { - contextsToStates[state.context] = state - _onStartChain.emit(state) - } - } - - private suspend fun endChainWithoutLock(state: State) { - if (contextsToStates[state.context] == state) { - contextsToStates.remove(state.context) - _onEndChain.emit(state) - } - } - - override suspend fun endChain(state: State) { - mapMutex.withLock { - endChainWithoutLock(state) - } - } - - override suspend fun getActiveStates(): List = contextsToStates.values.toList() - -} diff --git a/fsm/common/src/commonMain/kotlin/dev/inmo/micro_utils/fsm/common/dsl/FSMBuilder.kt b/fsm/common/src/commonMain/kotlin/dev/inmo/micro_utils/fsm/common/dsl/FSMBuilder.kt index f0694f360ef..a5fd74a5ddb 100644 --- a/fsm/common/src/commonMain/kotlin/dev/inmo/micro_utils/fsm/common/dsl/FSMBuilder.kt +++ b/fsm/common/src/commonMain/kotlin/dev/inmo/micro_utils/fsm/common/dsl/FSMBuilder.kt @@ -1,10 +1,12 @@ package dev.inmo.micro_utils.fsm.common.dsl import dev.inmo.micro_utils.fsm.common.* +import dev.inmo.micro_utils.fsm.common.managers.* +import dev.inmo.micro_utils.fsm.common.managers.InMemoryStatesManager import kotlin.reflect.KClass class FSMBuilder( - var statesManager: StatesManager = InMemoryStatesManager() + var statesManager: StatesManager = DefaultStatesManager(InMemoryDefaultStatesManagerRepo()) ) { private var states = mutableListOf>() diff --git a/fsm/common/src/commonMain/kotlin/dev/inmo/micro_utils/fsm/common/managers/DefaultStatesManager.kt b/fsm/common/src/commonMain/kotlin/dev/inmo/micro_utils/fsm/common/managers/DefaultStatesManager.kt new file mode 100644 index 00000000000..3488e0ac7d3 --- /dev/null +++ b/fsm/common/src/commonMain/kotlin/dev/inmo/micro_utils/fsm/common/managers/DefaultStatesManager.kt @@ -0,0 +1,101 @@ +package dev.inmo.micro_utils.fsm.common.managers + +import dev.inmo.micro_utils.fsm.common.State +import dev.inmo.micro_utils.fsm.common.StatesManager +import kotlinx.coroutines.flow.* +import kotlinx.coroutines.sync.Mutex +import kotlinx.coroutines.sync.withLock + +/** + * Implement this repo if you want to use some custom repo for [DefaultStatesManager] + */ +interface DefaultStatesManagerRepo { + /** + * Must save [state] as current state of chain with [State.context] of [state] + */ + suspend fun set(state: State) + /** + * Remove exactly [state]. In case if internally [State.context] is busy with different [State], that [State] should + * NOT be removed + */ + suspend fun removeState(state: State) + /** + * @return Current list of available and saved states + */ + suspend fun getStates(): List + + /** + * @return Current state by [context] + */ + suspend fun getContextState(context: Any): State? + + /** + * @return Current state by [context] + */ + suspend fun contains(context: Any): Boolean = getContextState(context) != null +} + +/** + * @param repo This repo will be used as repository for storing states. All operations with this repo will happen BEFORE + * any event will be sent to [onChainStateUpdated], [onStartChain] or [onEndChain]. By default will be used + * [InMemoryDefaultStatesManagerRepo] or you may create custom [DefaultStatesManagerRepo] and pass as [repo] parameter + * @param onContextsConflictResolver Receive old [State], new one and the state currently placed on new [State.context] + * key. In case when this callback will returns true, the state placed on [State.context] of new will be replaced by + * new state by using [endChain] with that state + */ +class DefaultStatesManager( + private val repo: DefaultStatesManagerRepo = InMemoryDefaultStatesManagerRepo(), + private val onContextsConflictResolver: suspend (old: State, new: State, currentNew: State) -> Boolean = { _, _, _ -> true } +) : StatesManager { + private val _onChainStateUpdated = MutableSharedFlow>(0) + override val onChainStateUpdated: Flow> = _onChainStateUpdated.asSharedFlow() + private val _onStartChain = MutableSharedFlow(0) + override val onStartChain: Flow = _onStartChain.asSharedFlow() + private val _onEndChain = MutableSharedFlow(0) + override val onEndChain: Flow = _onEndChain.asSharedFlow() + + private val mapMutex = Mutex() + + override suspend fun update(old: State, new: State) = mapMutex.withLock { + val stateByOldContext: State? = repo.getContextState(old.context) + when { + stateByOldContext != old -> return@withLock + stateByOldContext == null || old.context == new.context -> { + repo.set(new) + _onChainStateUpdated.emit(old to new) + } + else -> { + val stateOnNewOneContext = repo.getContextState(new.context) + if (stateOnNewOneContext == null || onContextsConflictResolver(old, new, stateOnNewOneContext)) { + stateOnNewOneContext ?.let { endChainWithoutLock(it) } + repo.removeState(old) + repo.set(new) + _onChainStateUpdated.emit(old to new) + } + } + } + } + + override suspend fun startChain(state: State) = mapMutex.withLock { + if (!repo.contains(state.context)) { + repo.set(state) + _onStartChain.emit(state) + } + } + + private suspend fun endChainWithoutLock(state: State) { + if (repo.getContextState(state.context) == state) { + repo.removeState(state) + _onEndChain.emit(state) + } + } + + override suspend fun endChain(state: State) { + mapMutex.withLock { + endChainWithoutLock(state) + } + } + + override suspend fun getActiveStates(): List = repo.getStates() + +} diff --git a/fsm/common/src/commonMain/kotlin/dev/inmo/micro_utils/fsm/common/managers/InMemoryDefaultStatesManagerRepo.kt b/fsm/common/src/commonMain/kotlin/dev/inmo/micro_utils/fsm/common/managers/InMemoryDefaultStatesManagerRepo.kt new file mode 100644 index 00000000000..70051e14d07 --- /dev/null +++ b/fsm/common/src/commonMain/kotlin/dev/inmo/micro_utils/fsm/common/managers/InMemoryDefaultStatesManagerRepo.kt @@ -0,0 +1,25 @@ +package dev.inmo.micro_utils.fsm.common.managers + +import dev.inmo.micro_utils.fsm.common.State + +/** + * Simple [DefaultStatesManagerRepo] for [DefaultStatesManager] which will store data in [map] and use primitive + * functionality + */ +class InMemoryDefaultStatesManagerRepo( + private val map: MutableMap = mutableMapOf() +) : DefaultStatesManagerRepo { + override suspend fun set(state: State) { + map[state.context] = state + } + + override suspend fun removeState(state: State) { + map.remove(state.context) + } + + override suspend fun getStates(): List = map.values.toList() + + override suspend fun getContextState(context: Any): State? = map[context] + + override suspend fun contains(context: Any): Boolean = map.contains(context) +} diff --git a/fsm/common/src/commonMain/kotlin/dev/inmo/micro_utils/fsm/common/managers/InMemoryStatesManager.kt b/fsm/common/src/commonMain/kotlin/dev/inmo/micro_utils/fsm/common/managers/InMemoryStatesManager.kt new file mode 100644 index 00000000000..4d8094bd48b --- /dev/null +++ b/fsm/common/src/commonMain/kotlin/dev/inmo/micro_utils/fsm/common/managers/InMemoryStatesManager.kt @@ -0,0 +1,68 @@ +package dev.inmo.micro_utils.fsm.common.managers + +import dev.inmo.micro_utils.fsm.common.State +import dev.inmo.micro_utils.fsm.common.StatesManager +import kotlinx.coroutines.flow.* +import kotlinx.coroutines.sync.Mutex +import kotlinx.coroutines.sync.withLock + +/** + * @param onContextsConflictResolver Receive old [State], new one and the state currently placed on new [State.context] + * key. In case when this callback will returns true, the state placed on [State.context] of new will be replaced by + * new state by using [endChain] with that state + */ +class InMemoryStatesManager( + private val onContextsConflictResolver: suspend (old: State, new: State, currentNew: State) -> Boolean = { _, _, _ -> true } +) : StatesManager { + private val _onChainStateUpdated = MutableSharedFlow>(0) + override val onChainStateUpdated: Flow> = _onChainStateUpdated.asSharedFlow() + private val _onStartChain = MutableSharedFlow(0) + override val onStartChain: Flow = _onStartChain.asSharedFlow() + private val _onEndChain = MutableSharedFlow(0) + override val onEndChain: Flow = _onEndChain.asSharedFlow() + + private val contextsToStates = mutableMapOf() + private val mapMutex = Mutex() + + override suspend fun update(old: State, new: State) = mapMutex.withLock { + when { + contextsToStates[old.context] != old -> return@withLock + old.context == new.context || !contextsToStates.containsKey(new.context) -> { + contextsToStates[old.context] = new + _onChainStateUpdated.emit(old to new) + } + else -> { + val stateOnNewOneContext = contextsToStates.getValue(new.context) + if (onContextsConflictResolver(old, new, stateOnNewOneContext)) { + endChainWithoutLock(stateOnNewOneContext) + contextsToStates.remove(old.context) + contextsToStates[new.context] = new + _onChainStateUpdated.emit(old to new) + } + } + } + } + + override suspend fun startChain(state: State) = mapMutex.withLock { + if (!contextsToStates.containsKey(state.context)) { + contextsToStates[state.context] = state + _onStartChain.emit(state) + } + } + + private suspend fun endChainWithoutLock(state: State) { + if (contextsToStates[state.context] == state) { + contextsToStates.remove(state.context) + _onEndChain.emit(state) + } + } + + override suspend fun endChain(state: State) { + mapMutex.withLock { + endChainWithoutLock(state) + } + } + + override suspend fun getActiveStates(): List = contextsToStates.values.toList() + +} diff --git a/fsm/repos/common/src/commonMain/kotlin/dev/inmo/micro_utils/fsm/repos/common/KeyValueBasedDefaultStatesManagerRepo.kt b/fsm/repos/common/src/commonMain/kotlin/dev/inmo/micro_utils/fsm/repos/common/KeyValueBasedDefaultStatesManagerRepo.kt new file mode 100644 index 00000000000..68b3b687db6 --- /dev/null +++ b/fsm/repos/common/src/commonMain/kotlin/dev/inmo/micro_utils/fsm/repos/common/KeyValueBasedDefaultStatesManagerRepo.kt @@ -0,0 +1,25 @@ +package dev.inmo.micro_utils.fsm.repos.common + +import dev.inmo.micro_utils.fsm.common.State +import dev.inmo.micro_utils.fsm.common.managers.DefaultStatesManagerRepo +import dev.inmo.micro_utils.repos.* +import dev.inmo.micro_utils.repos.pagination.getAll + +class KeyValueBasedDefaultStatesManagerRepo( + private val keyValueRepo: KeyValueRepo +) : DefaultStatesManagerRepo { + override suspend fun set(state: State) { + keyValueRepo.set(state.context, state) + } + + override suspend fun removeState(state: State) { + if (keyValueRepo.get(state.context) == state) { + keyValueRepo.unset(state.context) + } + } + + override suspend fun getStates(): List = keyValueRepo.getAll { keys(it) }.map { it.second } + override suspend fun getContextState(context: Any): State? = keyValueRepo.get(context) + + override suspend fun contains(context: Any): Boolean = keyValueRepo.contains(context) +} diff --git a/fsm/repos/common/src/commonMain/kotlin/dev/inmo/micro_utils/fsm/repos/common/KeyValueBasedStatesManager.kt b/fsm/repos/common/src/commonMain/kotlin/dev/inmo/micro_utils/fsm/repos/common/KeyValueBasedStatesManager.kt index 4f6f98d536c..136bfd45c9c 100644 --- a/fsm/repos/common/src/commonMain/kotlin/dev/inmo/micro_utils/fsm/repos/common/KeyValueBasedStatesManager.kt +++ b/fsm/repos/common/src/commonMain/kotlin/dev/inmo/micro_utils/fsm/repos/common/KeyValueBasedStatesManager.kt @@ -9,6 +9,7 @@ import kotlinx.coroutines.flow.* import kotlinx.coroutines.sync.Mutex import kotlinx.coroutines.sync.withLock +@Deprecated("Replace with DefaultStatesManager and KeyValueBasedDefaultStatesManagerRepo") class KeyValueBasedStatesManager( private val keyValueRepo: KeyValueRepo, private val onContextsConflictResolver: suspend (old: State, new: State, currentNew: State) -> Boolean = { _, _, _ -> true } diff --git a/gradle.properties b/gradle.properties index 1278710500a..35c0ea75379 100644 --- a/gradle.properties +++ b/gradle.properties @@ -10,11 +10,11 @@ org.gradle.jvmargs=-Xmx2g kotlin_version=1.5.31 kotlin_coroutines_version=1.5.2 kotlin_serialisation_core_version=1.3.0 -kotlin_exposed_version=0.35.1 +kotlin_exposed_version=0.35.2 ktor_version=1.6.4 -klockVersion=2.4.3 +klockVersion=2.4.5 github_release_plugin_version=2.2.12 @@ -40,10 +40,10 @@ crypto_js_version=4.1.1 # Dokka -dokka_version=1.5.30 +dokka_version=1.5.31 # Project data group=dev.inmo -version=0.7.0 -android_code_version=74 +version=0.7.1 +android_code_version=75