mirror of
https://github.com/InsanusMokrassar/TelegramBotApiLibraries.git
synced 2024-12-23 09:07:16 +00:00
state to revert
This commit is contained in:
parent
f04f065ac5
commit
6f17a53146
@ -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()
|
||||||
|
|
||||||
|
}
|
@ -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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -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>
|
|
||||||
}
|
|
@ -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
17
fsm/tgbotapi/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(":tgbotapi.libraries.fsm.core")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
1
fsm/tgbotapi/src/main/AndroidManifest.xml
Normal file
1
fsm/tgbotapi/src/main/AndroidManifest.xml
Normal file
@ -0,0 +1 @@
|
|||||||
|
<manifest package="dev.inmo.tgbotapi.libraries.fsm.tgbotapi"/>
|
@ -6,7 +6,8 @@ String[] includes = [
|
|||||||
":cache:admins:plagubot",
|
":cache:admins:plagubot",
|
||||||
":cache:media",
|
":cache:media",
|
||||||
|
|
||||||
":fsm:core"
|
":fsm:core",
|
||||||
|
":fsm:tgbotapi"
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user