From a4e83f73578746a2af56c1a6c63e439dea6b9bc5 Mon Sep 17 00:00:00 2001 From: Fabrice Lecomte Date: Wed, 5 Mar 2025 00:31:24 +0100 Subject: [PATCH] extract action command --- .../app/command/GameCommandHandler.kt | 44 +++------------ .../command/command/IWantToPlayCardCommand.kt | 54 +++++++++++++++++++ .../command/command/IamReadyToPlayCommand.kt | 22 ++++++++ .../command/command/IwantToPlayCardCommand.kt | 27 ---------- 4 files changed, 83 insertions(+), 64 deletions(-) create mode 100644 src/main/kotlin/eventDemo/app/command/command/IWantToPlayCardCommand.kt delete mode 100644 src/main/kotlin/eventDemo/app/command/command/IwantToPlayCardCommand.kt diff --git a/src/main/kotlin/eventDemo/app/command/GameCommandHandler.kt b/src/main/kotlin/eventDemo/app/command/GameCommandHandler.kt index 4370589..3bb1dc5 100644 --- a/src/main/kotlin/eventDemo/app/command/GameCommandHandler.kt +++ b/src/main/kotlin/eventDemo/app/command/GameCommandHandler.kt @@ -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, ) { 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) } diff --git a/src/main/kotlin/eventDemo/app/command/command/IWantToPlayCardCommand.kt b/src/main/kotlin/eventDemo/app/command/command/IWantToPlayCardCommand.kt new file mode 100644 index 0000000..2001b9b --- /dev/null +++ b/src/main/kotlin/eventDemo/app/command/command/IWantToPlayCardCommand.kt @@ -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") + } + } +} diff --git a/src/main/kotlin/eventDemo/app/command/command/IamReadyToPlayCommand.kt b/src/main/kotlin/eventDemo/app/command/command/IamReadyToPlayCommand.kt index d18cafb..169baa1 100644 --- a/src/main/kotlin/eventDemo/app/command/command/IamReadyToPlayCommand.kt +++ b/src/main/kotlin/eventDemo/app/command/command/IamReadyToPlayCommand.kt @@ -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, + ), + ) + } + } } diff --git a/src/main/kotlin/eventDemo/app/command/command/IwantToPlayCardCommand.kt b/src/main/kotlin/eventDemo/app/command/command/IwantToPlayCardCommand.kt deleted file mode 100644 index 996de92..0000000 --- a/src/main/kotlin/eventDemo/app/command/command/IwantToPlayCardCommand.kt +++ /dev/null @@ -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 -}