extract action command

This commit is contained in:
2025-03-05 00:31:24 +01:00
parent bc35131bfc
commit a4e83f7357
4 changed files with 83 additions and 64 deletions

View File

@@ -2,14 +2,12 @@ package eventDemo.app.command
import eventDemo.app.GameState
import eventDemo.app.command.command.GameCommand
import eventDemo.app.command.command.IWantToPlayCardCommand
import eventDemo.app.command.command.IamReadyToPlayCommand
import eventDemo.app.command.command.IwantToPlayCardCommand
import eventDemo.app.entity.Player
import eventDemo.app.event.GameEventStream
import eventDemo.app.event.buildStateFromEventStream
import eventDemo.app.event.event.CardIsPlayedEvent
import eventDemo.app.event.event.GameEvent
import eventDemo.app.event.event.PlayerReadyEvent
import io.ktor.websocket.Frame
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
@@ -29,7 +27,7 @@ class GameCommandHandler(
outgoing: SendChannel<Frame>,
) {
private val commandStream = GameCommandStream(incoming, outgoing)
private val playerNotifier = outgoing
private val playerNotifier: (String) -> Unit = { runBlocking { outgoing.send(Frame.Text(it)) } }
/**
* Init the handler
@@ -41,48 +39,20 @@ class GameCommandHandler(
nack()
}
val state = command.buildState()
val gameState = command.buildGameState()
when (command) {
is IwantToPlayCardCommand -> {
// Check the command can be executed
if (state.commandCardCanBeExecuted(command)) {
eventStream.publish(
CardIsPlayedEvent(
command.payload.gameId,
command.payload.card,
command.payload.player,
),
)
} else {
runBlocking {
playerNotifier.send(Frame.Text("Command cannot be executed"))
}
}
is IWantToPlayCardCommand -> {
command.run(gameState, playerNotifier, eventStream)
}
is IamReadyToPlayCommand -> {
if (state.playerIsAlreadyReady(command.payload.player)) {
nack()
} else {
PlayerReadyEvent(
command.payload.gameId,
command.payload.player,
)
}
command.run(gameState, playerNotifier, eventStream)
}
}
}
}
}
private fun GameState.playerIsAlreadyReady(player: Player): Boolean = readyPlayers.contains(player)
private fun GameState.commandCardCanBeExecuted(command: IwantToPlayCardCommand): Boolean =
canBePlayThisCard(
command.payload.player,
command.payload.card,
)
private fun GameCommand.buildState(): GameState = payload.gameId.buildStateFromEventStream(eventStream)
private fun GameCommand.buildGameState(): GameState = payload.gameId.buildStateFromEventStream(eventStream)
}

View File

@@ -0,0 +1,54 @@
package eventDemo.app.command.command
import eventDemo.app.GameState
import eventDemo.app.entity.Card
import eventDemo.app.entity.GameId
import eventDemo.app.entity.Player
import eventDemo.app.event.GameEventStream
import eventDemo.app.event.event.CardIsPlayedEvent
import eventDemo.libs.command.CommandId
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
/**
* A command to perform an action to play a new card
*/
@Serializable
@SerialName("PlayCard")
data class IWantToPlayCardCommand(
override val payload: Payload,
) : GameCommand {
override val name: String = "PlayCard"
override val id: CommandId = CommandId()
@Serializable
data class Payload(
override val gameId: GameId,
override val player: Player,
val card: Card,
) : GameCommand.Payload
fun run(
state: GameState,
playerNotifier: (String) -> Unit,
eventStream: GameEventStream,
) {
val commandCardCanBeExecuted: Boolean =
state.canBePlayThisCard(
payload.player,
payload.card,
)
if (commandCardCanBeExecuted) {
eventStream.publish(
CardIsPlayedEvent(
payload.gameId,
payload.card,
payload.player,
),
)
} else {
playerNotifier("Command cannot be executed")
}
}
}

View File

@@ -1,7 +1,10 @@
package eventDemo.app.command.command
import eventDemo.app.GameState
import eventDemo.app.entity.GameId
import eventDemo.app.entity.Player
import eventDemo.app.event.GameEventStream
import eventDemo.app.event.event.PlayerReadyEvent
import eventDemo.libs.command.CommandId
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
@@ -22,4 +25,23 @@ data class IamReadyToPlayCommand(
override val gameId: GameId,
override val player: Player,
) : GameCommand.Payload
fun run(
state: GameState,
playerNotifier: (String) -> Unit,
eventStream: GameEventStream,
) {
val playerIsAlreadyReady: Boolean = state.readyPlayers.contains(payload.player)
if (playerIsAlreadyReady) {
playerNotifier("You are already ready")
} else {
eventStream.publish(
PlayerReadyEvent(
payload.gameId,
payload.player,
),
)
}
}
}

View File

@@ -1,27 +0,0 @@
package eventDemo.app.command.command
import eventDemo.app.entity.Card
import eventDemo.app.entity.GameId
import eventDemo.app.entity.Player
import eventDemo.libs.command.CommandId
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
/**
* A command to perform an action to play a new card
*/
@Serializable
@SerialName("PlayCard")
data class IwantToPlayCardCommand(
override val payload: Payload,
) : GameCommand {
override val name: String = "PlayCard"
override val id: CommandId = CommandId()
@Serializable
data class Payload(
override val gameId: GameId,
override val player: Player,
val card: Card,
) : GameCommand.Payload
}