start working with fsm

This commit is contained in:
InsanusMokrassar 2021-06-18 14:09:02 +06:00
parent 7ac8effb5f
commit f04f065ac5
10 changed files with 113 additions and 1 deletions

17
fsm/core/build.gradle Normal file
View File

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

View File

@ -0,0 +1,17 @@
package dev.inmo.tgbotapi.libraries.fsm.core
sealed interface State {
val context: Any
}
/**
* Use this state as parent of your state in case you want to avoid saving of this state in queue for [context] if this
* queue is not empty
*/
interface ImmediateOrNeverState : State
/**
* Use this state as parent of your state in case you want to keep saving of this state in queue for [context] if this
* queue is not empty
*/
interface QueueableState : State

View File

@ -0,0 +1,15 @@
package dev.inmo.tgbotapi.libraries.fsm.core
import kotlin.reflect.KClass
class StateHandlerHolder<I : State, O : State>(
private val inputKlass: KClass<I>,
private val delegateTo: StatesHandler<I, O>,
private val strict: Boolean = false
) : StatesHandler<State, O> {
fun checkHandleable(state: State) = state::class == inputKlass || (!strict && inputKlass.isInstance(state))
override suspend fun handleState(state: State): O? {
return delegateTo.handleState(state as I)
}
}

View File

@ -0,0 +1,5 @@
package dev.inmo.tgbotapi.libraries.fsm.core
fun interface StatesHandler<I : State, O : State> {
suspend fun handleState(state: I): O?
}

View File

@ -0,0 +1,37 @@
package dev.inmo.tgbotapi.libraries.fsm.core
import dev.inmo.micro_utils.coroutines.*
import kotlinx.coroutines.*
import kotlinx.coroutines.flow.asFlow
private suspend fun <I : State, O : State> launchStateHandling(
state: State,
handlers: List<StateHandlerHolder<out I, out O>>
): O? {
return handlers.firstOrNull { it.checkHandleable(state) } ?.handleState(
state
)
}
class StatesMachine<T : State, I : T, O : T>(
private val statesRepo: StatesRepo<T>,
private val statesQuotaManager: StatesQuotaManager,
private val handlers: List<StateHandlerHolder<out I, out O>>
) : StatesHandler<T, O> {
override suspend fun handleState(state: T): O? {
return statesQuotaManager.doOnQuota(
state
) {
launchStateHandling(state, handlers)
}
}
fun start(scope: CoroutineScope): Job = scope.launchSafelyWithoutExceptions {
val statesFlow = statesRepo.loadStates().asFlow() + statesRepo.onNewState
statesFlow.subscribeSafelyWithoutExceptions(this) {
val newState = handleState(it)
newState ?.also { statesRepo.saveState(newState) }
statesRepo.removeState(it)
}
}
}

View File

@ -0,0 +1,5 @@
package dev.inmo.tgbotapi.libraries.fsm.core
interface StatesQuotaManager {
suspend fun <T : State, O : State> doOnQuota(state: T, block: suspend (T) -> O?): O?
}

View File

@ -0,0 +1,12 @@
package dev.inmo.tgbotapi.libraries.fsm.core
import kotlinx.coroutines.flow.Flow
interface StatesRepo<T : State> {
val onNewState: Flow<T>
val onStateRemoved: Flow<T>
suspend fun saveState(state: T)
suspend fun removeState(state: T)
suspend fun loadStates(): List<T>
}

View File

@ -0,0 +1 @@
<manifest package="dev.inmo.tgbotapi.libraries.fsm.core"/>

View File

@ -8,6 +8,7 @@ android.enableJetifier=true
kotlin_version=1.5.10
kotlin_serialisation_core_version=1.2.1
kotlin_coroutines_version=1.5.0
github_release_plugin_version=2.2.12

View File

@ -4,7 +4,9 @@ String[] includes = [
":cache:admins:common",
":cache:admins:micro_utils",
":cache:admins:plagubot",
":cache:media"
":cache:media",
":fsm:core"
]