state to revert

This commit is contained in:
InsanusMokrassar 2021-06-19 01:16:39 +06:00
parent f04f065ac5
commit 6f17a53146
8 changed files with 121 additions and 20 deletions

View File

@ -0,0 +1,48 @@
package dev.inmo.tgbotapi.libraries.fsm.core
import kotlinx.coroutines.channels.BufferOverflow
import kotlinx.coroutines.flow.*
interface StatesHolder<T : State> {
val onNewState: Flow<T>
val onStateRemoved: Flow<T>
/**
* Must always save [state] inside of [this] [StatesHolder] AND send event in [onNewState]
*/
suspend fun saveState(state: T)
/**
* Must always remove [state] in case it is stored AND send event in [onStateRemoved] if it was removed
*/
suspend fun removeState(state: T)
/**
* Must returns currently stored states
*/
suspend fun loadStates(): List<T>
}
class ListBasedStatesHolder<T : State>(
base: List<T> = emptyList()
) : StatesHolder<T> {
private val data: MutableList<T> = base.toMutableList()
private val _onNewState = MutableSharedFlow<T>(0, onBufferOverflow = BufferOverflow.SUSPEND)
override val onNewState: Flow<T> = _onNewState.asSharedFlow()
private val _onStateRemoved = MutableSharedFlow<T>(0, onBufferOverflow = BufferOverflow.SUSPEND)
override val onStateRemoved: Flow<T> = _onStateRemoved.asSharedFlow()
override suspend fun saveState(state: T) {
data.add(state)
_onNewState.emit(state)
}
override suspend fun removeState(state: T) {
if (data.remove(state)) {
_onStateRemoved.emit(state)
}
}
override suspend fun loadStates(): List<T> = data.toList()
}

View File

@ -14,24 +14,22 @@ private suspend fun <I : State, O : State> launchStateHandling(
} }
class StatesMachine<T : State, I : T, O : T>( class StatesMachine<T : State, I : T, O : T>(
private val statesRepo: StatesRepo<T>, private val statesHolder: StatesHolder<T>,
private val statesQuotaManager: StatesQuotaManager, private val statesQuotaManager: StatesQuotaManager,
private val handlers: List<StateHandlerHolder<out I, out O>> private val handlers: List<StateHandlerHolder<out I, out O>>
) : StatesHandler<T, O> { ) : StatesHandler<T, O> {
override suspend fun handleState(state: T): O? { override suspend fun handleState(state: T): O? {
return statesQuotaManager.doOnQuota( return statesQuotaManager.doOnQuota(state) {
state
) {
launchStateHandling(state, handlers) launchStateHandling(state, handlers)
} }
} }
fun start(scope: CoroutineScope): Job = scope.launchSafelyWithoutExceptions { fun start(scope: CoroutineScope): Job = scope.launchSafelyWithoutExceptions {
val statesFlow = statesRepo.loadStates().asFlow() + statesRepo.onNewState val statesFlow = statesHolder.loadStates().asFlow() + statesHolder.onNewState
statesFlow.subscribeSafelyWithoutExceptions(this) { statesFlow.subscribeSafelyWithoutExceptions(this) {
val newState = handleState(it) val newState = handleState(it)
newState ?.also { statesRepo.saveState(newState) } newState ?.also { statesHolder.saveState(newState) }
statesRepo.removeState(it) statesHolder.removeState(it)
} }
} }
} }

View File

@ -1,5 +1,23 @@
package dev.inmo.tgbotapi.libraries.fsm.core package dev.inmo.tgbotapi.libraries.fsm.core
import kotlinx.coroutines.sync.Mutex
interface StatesQuotaManager { interface StatesQuotaManager {
suspend fun <T : State, O : State> doOnQuota(state: T, block: suspend (T) -> O?): O? suspend fun <T : State, O : State> doOnQuota(state: T, block: suspend (T) -> O?): O?
suspend fun transitQuota(from: State, to: State?)
}
class InMemoryStatesQuotaManager : StatesQuotaManager {
private val currentContextsAndStates = mutableMapOf<Any, State>()
private val mutex = Mutex()
override suspend fun <T : State, O : State> doOnQuota(state: T, block: suspend (T) -> O?): O? {
}
override suspend fun transitQuota(state: State) {
TODO("Not yet implemented")
}
} }

View File

@ -1,12 +0,0 @@
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,30 @@
package dev.inmo.tgbotapi.libraries.fsm.core
import kotlin.random.Random
sealed interface TrafficLightState : ImmediateOrNeverState {
val trafficLightNumber: Int
override val context: Int
get() = trafficLightNumber
}
data class GreenCommon(override val trafficLightNumber: Int) : TrafficLightState
data class YellowCommon(override val trafficLightNumber: Int) : TrafficLightState
data class RedCommon(override val trafficLightNumber: Int) : TrafficLightState
suspend fun main() {
val countOfTrafficLights = 10
val initialStates = (0 until countOfTrafficLights).map {
when (Random.nextInt(3)) {
0 -> GreenCommon(it)
1 -> YellowCommon(it)
else -> RedCommon(it)
}
}
val statesHolder = ListBasedStatesHolder(initialStates)
val machine = StatesMachine(
statesHolder,
)
}

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

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

View File

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

View File

@ -6,7 +6,8 @@ String[] includes = [
":cache:admins:plagubot", ":cache:admins:plagubot",
":cache:media", ":cache:media",
":fsm:core" ":fsm:core",
":fsm:tgbotapi"
] ]