diff --git a/CHANGELOG.md b/CHANGELOG.md index 140c26d445e..1c1a5c44c16 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,8 @@ * `Repos` * `Android`: * New function `SharedPreferencesKeyValueRepo` +* `FSM` + * Add `StateHandlingErrorHandler` and opportunity to handle states handling errors ## 0.10.4 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 cc8fe265ef4..88eb9132f97 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 @@ -3,6 +3,8 @@ package dev.inmo.micro_utils.fsm.common import dev.inmo.micro_utils.common.Optional import dev.inmo.micro_utils.common.onPresented import dev.inmo.micro_utils.coroutines.* +import dev.inmo.micro_utils.fsm.common.utils.StateHandlingErrorHandler +import dev.inmo.micro_utils.fsm.common.utils.defaultStateHandlingErrorHandler import kotlinx.coroutines.* import kotlinx.coroutines.sync.Mutex import kotlinx.coroutines.sync.withLock @@ -13,13 +15,24 @@ import kotlinx.coroutines.sync.withLock * handling until [start] method will be called */ interface StatesMachine : StatesHandler { + suspend fun launchStateHandling( + state: T, + handlers: List>, + onStateHandlingErrorHandler: StateHandlingErrorHandler + ): T? { + return runCatchingSafely { + handlers.firstOrNull { it.checkHandleable(state) } ?.run { + handleState(state) + } + }.getOrElse { + onStateHandlingErrorHandler(state, it) + } + } suspend fun launchStateHandling( state: T, handlers: List> ): T? { - return handlers.firstOrNull { it.checkHandleable(state) } ?.run { - handleState(state) - } + return launchStateHandling(state, handlers, defaultStateHandlingErrorHandler()) } /** @@ -38,8 +51,9 @@ interface StatesMachine : StatesHandler { */ operator fun invoke( statesManager: StatesManager, - handlers: List> - ) = DefaultStatesMachine(statesManager, handlers) + handlers: List>, + onStateHandlingErrorHandler: StateHandlingErrorHandler = defaultStateHandlingErrorHandler() + ) = DefaultStatesMachine(statesManager, handlers, onStateHandlingErrorHandler) } } @@ -52,11 +66,12 @@ interface StatesMachine : StatesHandler { open class DefaultStatesMachine ( protected val statesManager: StatesManager, protected val handlers: List>, + protected val onStateHandlingErrorHandler: StateHandlingErrorHandler = defaultStateHandlingErrorHandler() ) : StatesMachine { /** * Will call [launchStateHandling] for state handling */ - override suspend fun StatesMachine.handleState(state: T): T? = launchStateHandling(state, handlers) + override suspend fun StatesMachine.handleState(state: T): T? = launchStateHandling(state, handlers, onStateHandlingErrorHandler) /** * This @@ -65,7 +80,7 @@ open class DefaultStatesMachine ( protected val statesJobsMutex = Mutex() protected open suspend fun performUpdate(state: T) { - val newState = launchStateHandling(state, handlers) + val newState = launchStateHandling(state, handlers, onStateHandlingErrorHandler) if (newState != null) { statesManager.update(state, newState) } else { diff --git a/fsm/common/src/commonMain/kotlin/dev/inmo/micro_utils/fsm/common/UpdatableStatesMachine.kt b/fsm/common/src/commonMain/kotlin/dev/inmo/micro_utils/fsm/common/UpdatableStatesMachine.kt index 09fc45b506f..3d2542473b2 100644 --- a/fsm/common/src/commonMain/kotlin/dev/inmo/micro_utils/fsm/common/UpdatableStatesMachine.kt +++ b/fsm/common/src/commonMain/kotlin/dev/inmo/micro_utils/fsm/common/UpdatableStatesMachine.kt @@ -1,6 +1,8 @@ package dev.inmo.micro_utils.fsm.common import dev.inmo.micro_utils.common.* +import dev.inmo.micro_utils.fsm.common.utils.StateHandlingErrorHandler +import dev.inmo.micro_utils.fsm.common.utils.defaultStateHandlingErrorHandler import kotlinx.coroutines.* import kotlinx.coroutines.sync.withLock @@ -20,9 +22,11 @@ interface UpdatableStatesMachine : StatesMachine { open class DefaultUpdatableStatesMachine( statesManager: StatesManager, handlers: List>, + onStateHandlingErrorHandler: StateHandlingErrorHandler = defaultStateHandlingErrorHandler() ) : DefaultStatesMachine( statesManager, - handlers + handlers, + onStateHandlingErrorHandler ), UpdatableStatesMachine { protected val jobsStates = mutableMapOf() @@ -34,7 +38,7 @@ open class DefaultUpdatableStatesMachine( */ override suspend fun performStateUpdate(previousState: Optional, actualState: T, scope: CoroutineScope) { statesJobsMutex.withLock { - if (compare(previousState, actualState)) { + if (shouldReplaceJob(previousState, actualState)) { statesJobs[actualState] ?.cancel() } val job = previousState.mapOnPresented { diff --git a/fsm/common/src/commonMain/kotlin/dev/inmo/micro_utils/fsm/common/utils/StateHandlingErrorHandler.kt b/fsm/common/src/commonMain/kotlin/dev/inmo/micro_utils/fsm/common/utils/StateHandlingErrorHandler.kt new file mode 100644 index 00000000000..064d27f00fc --- /dev/null +++ b/fsm/common/src/commonMain/kotlin/dev/inmo/micro_utils/fsm/common/utils/StateHandlingErrorHandler.kt @@ -0,0 +1,6 @@ +package dev.inmo.micro_utils.fsm.common.utils + +typealias StateHandlingErrorHandler = suspend (T, Throwable) -> T? +val DefaultStateHandlingErrorHandler: StateHandlingErrorHandler<*> = { _, _ -> null } +inline fun defaultStateHandlingErrorHandler(): StateHandlingErrorHandler = DefaultStateHandlingErrorHandler as StateHandlingErrorHandler +