Move file and add interface to improve Archi Hexa

This commit is contained in:
2025-03-16 02:47:08 +01:00
parent 4739495980
commit 769d104040
77 changed files with 388 additions and 337 deletions

View File

@@ -0,0 +1,11 @@
package eventDemo.adapter.infrastructureLayer.event
import eventDemo.business.entity.GameId
import eventDemo.business.event.GameEventBus
import eventDemo.business.event.event.GameEvent
import eventDemo.libs.event.EventBus
import eventDemo.libs.event.EventBusInMemory
class GameEventBusInMemory :
GameEventBus,
EventBus<GameEvent, GameId> by EventBusInMemory<GameEvent, GameId>()

View File

@@ -0,0 +1,14 @@
package eventDemo.adapter.infrastructureLayer.event
import eventDemo.business.entity.GameId
import eventDemo.business.event.GameEventStore
import eventDemo.business.event.event.GameEvent
import eventDemo.libs.event.EventStore
import eventDemo.libs.event.EventStoreInMemory
/**
* A stream to publish and read the played card event.
*/
class GameEventStoreInMemory :
GameEventStore,
EventStore<GameEvent, GameId> by EventStoreInMemory()

View File

@@ -1,15 +1,20 @@
package eventDemo.app.event.projection
package eventDemo.adapter.infrastructureLayer.event.projection
import eventDemo.app.entity.GameId
import eventDemo.app.event.GameEventHandler
import eventDemo.app.event.GameEventStore
import eventDemo.app.event.event.GameEvent
import eventDemo.business.entity.GameId
import eventDemo.business.event.GameEventHandler
import eventDemo.business.event.GameEventStore
import eventDemo.business.event.event.GameEvent
import eventDemo.business.event.projection.GameState
import eventDemo.business.event.projection.GameStateRepository
import eventDemo.business.event.projection.apply
import eventDemo.libs.event.projection.ProjectionSnapshotRepositoryInMemory
import eventDemo.libs.event.projection.SnapshotConfig
class GameStateRepository(
class GameStateRepositoryInMemory(
eventStore: GameEventStore,
eventHandler: GameEventHandler,
snapshotConfig: SnapshotConfig = SnapshotConfig(),
) {
) : GameStateRepository {
private val projectionsSnapshot =
ProjectionSnapshotRepositoryInMemory(
eventStore = eventStore,
@@ -29,7 +34,7 @@ class GameStateRepository(
*
* It fetches it from the local cache if possible, otherwise it builds it.
*/
fun getLast(gameId: GameId): GameState =
override fun getLast(gameId: GameId): GameState =
projectionsSnapshot.getLast(gameId)
/**
@@ -38,6 +43,6 @@ class GameStateRepository(
*
* It fetches it from the local cache if possible, otherwise it builds it.
*/
fun getUntil(event: GameEvent): GameState =
override fun getUntil(event: GameEvent): GameState =
projectionsSnapshot.getUntil(event)
}

View File

@@ -1,8 +1,9 @@
package eventDemo.app.command
package eventDemo.adapter.interfaceLayer
import eventDemo.app.entity.Player
import eventDemo.app.eventListener.PlayerNotificationEventListener
import eventDemo.app.notification.Notification
import eventDemo.business.command.GameCommandHandler
import eventDemo.business.entity.Player
import eventDemo.business.event.eventListener.PlayerNotificationEventListener
import eventDemo.business.notification.Notification
import eventDemo.libs.fromFrameChannel
import eventDemo.libs.toObjectChannel
import io.github.oshai.kotlinlogging.withLoggingContext
@@ -15,6 +16,7 @@ import io.ktor.server.websocket.webSocket
import kotlinx.coroutines.DelicateCoroutinesApi
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.channels.SendChannel
import kotlinx.coroutines.channels.trySendBlocking
import kotlinx.coroutines.launch
@DelicateCoroutinesApi
@@ -34,7 +36,7 @@ fun Route.gameWebSocket(
outgoingFrameChannel,
)
}
playerNotificationListener.startListening(outgoingFrameChannel, currentPlayer)
playerNotificationListener.startListening({ outgoingFrameChannel.trySendBlocking(it) }, currentPlayer)
}
}
}

View File

@@ -1,7 +1,7 @@
package eventDemo.app.query
package eventDemo.adapter.interfaceLayer
import eventDemo.app.entity.GameId
import eventDemo.app.event.projection.GameStateRepository
import eventDemo.business.entity.GameId
import eventDemo.business.event.projection.GameStateRepository
import eventDemo.configuration.GameIdSerializer
import io.ktor.http.HttpStatusCode
import io.ktor.resources.Resource

View File

@@ -1,27 +0,0 @@
package eventDemo.app.command
import eventDemo.app.command.action.ICantPlay
import eventDemo.app.command.action.IWantToJoinTheGame
import eventDemo.app.command.action.IWantToPlayCard
import eventDemo.app.command.action.IamReadyToPlay
import eventDemo.app.command.command.GameCommand
import eventDemo.app.command.command.ICantPlayCommand
import eventDemo.app.command.command.IWantToJoinTheGameCommand
import eventDemo.app.command.command.IWantToPlayCardCommand
import eventDemo.app.command.command.IamReadyToPlayCommand
import eventDemo.app.event.event.GameEvent
class GameCommandActionRunner(
private val iWantToPlayCard: IWantToPlayCard,
private val iamReadyToPlay: IamReadyToPlay,
private val iWantToJoinTheGame: IWantToJoinTheGame,
private val iCantPlay: ICantPlay,
) {
fun run(command: GameCommand): (Int) -> GameEvent =
when (command) {
is IWantToPlayCardCommand -> iWantToPlayCard.run(command)
is IamReadyToPlayCommand -> iamReadyToPlay.run(command)
is IWantToJoinTheGameCommand -> iWantToJoinTheGame.run(command)
is ICantPlayCommand -> iCantPlay.run(command)
}
}

View File

@@ -1,9 +0,0 @@
package eventDemo.app.event
import eventDemo.app.entity.GameId
import eventDemo.app.event.event.GameEvent
import eventDemo.libs.event.EventBus
class GameEventBus(
bus: EventBus<GameEvent, GameId>,
) : EventBus<GameEvent, GameId> by bus

View File

@@ -1,12 +0,0 @@
package eventDemo.app.event
import eventDemo.app.entity.GameId
import eventDemo.app.event.event.GameEvent
import eventDemo.libs.event.EventStore
/**
* A stream to publish and read the played card event.
*/
class GameEventStore(
private val eventStore: EventStore<GameEvent, GameId>,
) : EventStore<GameEvent, GameId> by eventStore

View File

@@ -1,7 +0,0 @@
package eventDemo.app.event.event
import eventDemo.app.entity.Player
sealed interface PlayerActionEvent : GameEvent {
val player: Player
}

View File

@@ -1,4 +1,4 @@
package eventDemo.app.command
package eventDemo.business.command
class CommandException(
override val message: String,

View File

@@ -0,0 +1,27 @@
package eventDemo.business.command
import eventDemo.business.command.action.ICantPlay
import eventDemo.business.command.action.IWantToJoinTheGame
import eventDemo.business.command.action.IWantToPlayCard
import eventDemo.business.command.action.IamReadyToPlay
import eventDemo.business.command.command.GameCommand
import eventDemo.business.command.command.ICantPlayCommand
import eventDemo.business.command.command.IWantToJoinTheGameCommand
import eventDemo.business.command.command.IWantToPlayCardCommand
import eventDemo.business.command.command.IamReadyToPlayCommand
import eventDemo.business.event.event.GameEvent
class GameCommandActionRunner(
private val iWantToPlayCard: IWantToPlayCard,
private val iamReadyToPlay: IamReadyToPlay,
private val iWantToJoinTheGame: IWantToJoinTheGame,
private val iCantPlay: ICantPlay,
) {
fun run(command: GameCommand): (version: Int) -> GameEvent =
when (command) {
is IWantToPlayCardCommand -> iWantToPlayCard.run(command)
is IamReadyToPlayCommand -> iamReadyToPlay.run(command)
is IWantToJoinTheGameCommand -> iWantToJoinTheGame.run(command)
is ICantPlayCommand -> iCantPlay.run(command)
}
}

View File

@@ -1,13 +1,13 @@
package eventDemo.app.command
package eventDemo.business.command
import eventDemo.app.command.command.GameCommand
import eventDemo.app.entity.Player
import eventDemo.app.event.GameEventBus
import eventDemo.app.event.GameEventHandler
import eventDemo.app.event.event.GameEvent
import eventDemo.app.notification.CommandErrorNotification
import eventDemo.app.notification.CommandSuccessNotification
import eventDemo.app.notification.Notification
import eventDemo.business.command.command.GameCommand
import eventDemo.business.entity.Player
import eventDemo.business.event.GameEventBus
import eventDemo.business.event.GameEventHandler
import eventDemo.business.event.event.GameEvent
import eventDemo.business.notification.CommandErrorNotification
import eventDemo.business.notification.CommandSuccessNotification
import eventDemo.business.notification.Notification
import eventDemo.libs.command.CommandId
import eventDemo.libs.command.CommandStreamChannel
import io.github.oshai.kotlinlogging.KotlinLogging
@@ -62,7 +62,7 @@ class GameCommandHandler(
withLoggingContext("command" to command.toString()) {
if (command.payload.player.id != player.id) {
logger.warn { "Handle command Refuse, the player of the command is not the same" }
channelNotification.sendError(command)("You are not the author of this command\n")
channelNotification.sendError(command)("You are not the author of this command")
} else {
logger.info { "Handle command" }
try {
@@ -94,7 +94,7 @@ private fun SendChannel<Notification>.sendSuccess(commandId: CommandId): suspend
}
}
private fun SendChannel<Notification>.sendError(command: GameCommand): suspend (String) -> Unit =
private fun SendChannel<Notification>.sendError(command: GameCommand): suspend (message: String) -> Unit =
{
val logger = KotlinLogging.logger { }
CommandErrorNotification(message = it, command = command)

View File

@@ -1,8 +1,8 @@
package eventDemo.app.command.action
package eventDemo.business.command.action
import eventDemo.libs.command.Command
import eventDemo.libs.event.Event
sealed interface CommandAction<C : Command, E : Event<*>> {
fun run(command: C): (Int) -> E
fun run(command: C): (version: Int) -> E
}

View File

@@ -1,9 +1,9 @@
package eventDemo.app.command.action
package eventDemo.business.command.action
import eventDemo.app.command.CommandException
import eventDemo.app.command.command.ICantPlayCommand
import eventDemo.app.event.event.PlayerHavePassEvent
import eventDemo.app.event.projection.GameStateRepository
import eventDemo.business.command.CommandException
import eventDemo.business.command.command.ICantPlayCommand
import eventDemo.business.event.event.PlayerHavePassEvent
import eventDemo.business.event.projection.GameStateRepository
/**
* A command to perform an action to play a new card
@@ -11,7 +11,7 @@ import eventDemo.app.event.projection.GameStateRepository
data class ICantPlay(
private val gameStateRepository: GameStateRepository,
) : CommandAction<ICantPlayCommand, PlayerHavePassEvent> {
override fun run(command: ICantPlayCommand): (Int) -> PlayerHavePassEvent {
override fun run(command: ICantPlayCommand): (version: Int) -> PlayerHavePassEvent {
val state = gameStateRepository.getLast(command.payload.aggregateId)
if (state.currentPlayerTurn != command.payload.player) {

View File

@@ -1,9 +1,9 @@
package eventDemo.app.command.action
package eventDemo.business.command.action
import eventDemo.app.command.CommandException
import eventDemo.app.command.command.IWantToJoinTheGameCommand
import eventDemo.app.event.event.NewPlayerEvent
import eventDemo.app.event.projection.GameStateRepository
import eventDemo.business.command.CommandException
import eventDemo.business.command.command.IWantToJoinTheGameCommand
import eventDemo.business.event.event.NewPlayerEvent
import eventDemo.business.event.projection.GameStateRepository
/**
* A command to perform an action to play a new card
@@ -11,7 +11,7 @@ import eventDemo.app.event.projection.GameStateRepository
data class IWantToJoinTheGame(
private val gameStateRepository: GameStateRepository,
) : CommandAction<IWantToJoinTheGameCommand, NewPlayerEvent> {
override fun run(command: IWantToJoinTheGameCommand): (Int) -> NewPlayerEvent {
override fun run(command: IWantToJoinTheGameCommand): (version: Int) -> NewPlayerEvent {
val state = gameStateRepository.getLast(command.payload.aggregateId)
if (!state.isStarted) {
return {

View File

@@ -1,9 +1,9 @@
package eventDemo.app.command.action
package eventDemo.business.command.action
import eventDemo.app.command.CommandException
import eventDemo.app.command.command.IWantToPlayCardCommand
import eventDemo.app.event.event.CardIsPlayedEvent
import eventDemo.app.event.projection.GameStateRepository
import eventDemo.business.command.CommandException
import eventDemo.business.command.command.IWantToPlayCardCommand
import eventDemo.business.event.event.CardIsPlayedEvent
import eventDemo.business.event.projection.GameStateRepository
/**
* A command to perform an action to play a new card
@@ -11,7 +11,7 @@ import eventDemo.app.event.projection.GameStateRepository
data class IWantToPlayCard(
private val gameStateRepository: GameStateRepository,
) : CommandAction<IWantToPlayCardCommand, CardIsPlayedEvent> {
override fun run(command: IWantToPlayCardCommand): (Int) -> CardIsPlayedEvent {
override fun run(command: IWantToPlayCardCommand): (version: Int) -> CardIsPlayedEvent {
val state = gameStateRepository.getLast(command.payload.aggregateId)
if (!state.isStarted) {

View File

@@ -1,9 +1,9 @@
package eventDemo.app.command.action
package eventDemo.business.command.action
import eventDemo.app.command.CommandException
import eventDemo.app.command.command.IamReadyToPlayCommand
import eventDemo.app.event.event.PlayerReadyEvent
import eventDemo.app.event.projection.GameStateRepository
import eventDemo.business.command.CommandException
import eventDemo.business.command.command.IamReadyToPlayCommand
import eventDemo.business.event.event.PlayerReadyEvent
import eventDemo.business.event.projection.GameStateRepository
/**
* A command to set as ready to play
@@ -12,7 +12,7 @@ class IamReadyToPlay(
private val gameStateRepository: GameStateRepository,
) : CommandAction<IamReadyToPlayCommand, PlayerReadyEvent> {
@Throws(CommandException::class)
override fun run(command: IamReadyToPlayCommand): (Int) -> PlayerReadyEvent {
override fun run(command: IamReadyToPlayCommand): (version: Int) -> PlayerReadyEvent {
val state = gameStateRepository.getLast(command.payload.aggregateId)
val playerExist: Boolean = state.players.contains(command.payload.player)
val playerIsAlreadyReady: Boolean = state.readyPlayers.contains(command.payload.player)

View File

@@ -1,7 +1,7 @@
package eventDemo.app.command.command
package eventDemo.business.command.command
import eventDemo.app.entity.GameId
import eventDemo.app.entity.Player
import eventDemo.business.entity.GameId
import eventDemo.business.entity.Player
import eventDemo.libs.command.Command
import kotlinx.serialization.Serializable

View File

@@ -1,7 +1,7 @@
package eventDemo.app.command.command
package eventDemo.business.command.command
import eventDemo.app.entity.GameId
import eventDemo.app.entity.Player
import eventDemo.business.entity.GameId
import eventDemo.business.entity.Player
import eventDemo.libs.command.CommandId
import kotlinx.serialization.Serializable

View File

@@ -1,7 +1,7 @@
package eventDemo.app.command.command
package eventDemo.business.command.command
import eventDemo.app.entity.GameId
import eventDemo.app.entity.Player
import eventDemo.business.entity.GameId
import eventDemo.business.entity.Player
import eventDemo.libs.command.CommandId
import kotlinx.serialization.Serializable

View File

@@ -1,8 +1,8 @@
package eventDemo.app.command.command
package eventDemo.business.command.command
import eventDemo.app.entity.Card
import eventDemo.app.entity.GameId
import eventDemo.app.entity.Player
import eventDemo.business.entity.Card
import eventDemo.business.entity.GameId
import eventDemo.business.entity.Player
import eventDemo.libs.command.CommandId
import kotlinx.serialization.Serializable

View File

@@ -1,7 +1,7 @@
package eventDemo.app.command.command
package eventDemo.business.command.command
import eventDemo.app.entity.GameId
import eventDemo.app.entity.Player
import eventDemo.business.entity.GameId
import eventDemo.business.entity.Player
import eventDemo.libs.command.CommandId
import kotlinx.serialization.Serializable

View File

@@ -1,4 +1,4 @@
package eventDemo.app.entity
package eventDemo.business.entity
import eventDemo.configuration.UUIDSerializer
import kotlinx.serialization.SerialName

View File

@@ -1,4 +1,4 @@
package eventDemo.app.entity
package eventDemo.business.entity
import kotlinx.serialization.Serializable

View File

@@ -1,4 +1,4 @@
package eventDemo.app.entity
package eventDemo.business.entity
import eventDemo.configuration.GameIdSerializer
import eventDemo.libs.event.AggregateId

View File

@@ -1,4 +1,4 @@
package eventDemo.app.entity
package eventDemo.business.entity
import eventDemo.configuration.PlayerIdSerializer
import eventDemo.configuration.UUIDSerializer

View File

@@ -1,4 +1,4 @@
package eventDemo.app.entity
package eventDemo.business.entity
import kotlinx.serialization.Serializable

View File

@@ -1,4 +1,4 @@
package eventDemo.app.event
package eventDemo.business.event
import eventDemo.libs.event.AggregateId
import eventDemo.libs.event.Event
@@ -7,7 +7,7 @@ import eventDemo.libs.event.Event
* A stream to publish and read the played card event.
*/
interface EventHandler<E : Event<ID>, ID : AggregateId> {
fun registerProjectionBuilder(builder: (E) -> Unit)
fun registerProjectionBuilder(builder: (event: E) -> Unit)
fun handle(
aggregateId: ID,

View File

@@ -0,0 +1,7 @@
package eventDemo.business.event
import eventDemo.business.entity.GameId
import eventDemo.business.event.event.GameEvent
import eventDemo.libs.event.EventBus
interface GameEventBus : EventBus<GameEvent, GameId>

View File

@@ -1,7 +1,7 @@
package eventDemo.app.event
package eventDemo.business.event
import eventDemo.app.entity.GameId
import eventDemo.app.event.event.GameEvent
import eventDemo.business.entity.GameId
import eventDemo.business.event.event.GameEvent
import eventDemo.libs.event.VersionBuilder
import io.github.oshai.kotlinlogging.withLoggingContext
import java.util.concurrent.ConcurrentHashMap
@@ -20,7 +20,7 @@ class GameEventHandler(
private val projectionsBuilders: ConcurrentLinkedQueue<(GameEvent) -> Unit> = ConcurrentLinkedQueue()
private val locks: ConcurrentHashMap<GameId, ReentrantLock> = ConcurrentHashMap()
override fun registerProjectionBuilder(builder: GameProjectionBuilder) {
override fun registerProjectionBuilder(builder: (event: GameEvent) -> Unit) {
projectionsBuilders.add(builder)
}
@@ -55,5 +55,3 @@ class GameEventHandler(
}
}
}
typealias GameProjectionBuilder = (GameEvent) -> Unit

View File

@@ -0,0 +1,7 @@
package eventDemo.business.event
import eventDemo.business.entity.GameId
import eventDemo.business.event.event.GameEvent
import eventDemo.libs.event.EventStore
interface GameEventStore : EventStore<GameEvent, GameId>

View File

@@ -1,8 +1,8 @@
package eventDemo.app.event.event
package eventDemo.business.event.event
import eventDemo.app.entity.Card
import eventDemo.app.entity.GameId
import eventDemo.app.entity.Player
import eventDemo.business.entity.Card
import eventDemo.business.entity.GameId
import eventDemo.business.entity.Player
import kotlinx.datetime.Clock
import kotlinx.datetime.Instant
import java.util.UUID

View File

@@ -1,6 +1,6 @@
package eventDemo.app.event.event
package eventDemo.business.event.event
import eventDemo.app.entity.GameId
import eventDemo.business.entity.GameId
import eventDemo.libs.event.Event
import kotlinx.serialization.Serializable
import java.util.UUID

View File

@@ -1,9 +1,9 @@
package eventDemo.app.event.event
package eventDemo.business.event.event
import eventDemo.app.entity.Deck
import eventDemo.app.entity.GameId
import eventDemo.app.entity.Player
import eventDemo.app.entity.initHands
import eventDemo.business.entity.Deck
import eventDemo.business.entity.GameId
import eventDemo.business.entity.Player
import eventDemo.business.entity.initHands
import kotlinx.datetime.Clock
import kotlinx.datetime.Instant
import java.util.UUID

View File

@@ -1,7 +1,7 @@
package eventDemo.app.event.event
package eventDemo.business.event.event
import eventDemo.app.entity.GameId
import eventDemo.app.entity.Player
import eventDemo.business.entity.GameId
import eventDemo.business.entity.Player
import kotlinx.datetime.Clock
import kotlinx.datetime.Instant
import java.util.UUID

View File

@@ -0,0 +1,7 @@
package eventDemo.business.event.event
import eventDemo.business.entity.Player
sealed interface PlayerActionEvent : GameEvent {
val player: Player
}

View File

@@ -1,8 +1,8 @@
package eventDemo.app.event.event
package eventDemo.business.event.event
import eventDemo.app.entity.Card
import eventDemo.app.entity.GameId
import eventDemo.app.entity.Player
import eventDemo.business.entity.Card
import eventDemo.business.entity.GameId
import eventDemo.business.entity.Player
import kotlinx.datetime.Clock
import kotlinx.datetime.Instant
import java.util.UUID

View File

@@ -1,8 +1,8 @@
package eventDemo.app.event.event
package eventDemo.business.event.event
import eventDemo.app.entity.Card
import eventDemo.app.entity.GameId
import eventDemo.app.entity.Player
import eventDemo.business.entity.Card
import eventDemo.business.entity.GameId
import eventDemo.business.entity.Player
import kotlinx.datetime.Clock
import kotlinx.datetime.Instant
import java.util.UUID

View File

@@ -1,7 +1,7 @@
package eventDemo.app.event.event
package eventDemo.business.event.event
import eventDemo.app.entity.GameId
import eventDemo.app.entity.Player
import eventDemo.business.entity.GameId
import eventDemo.business.entity.Player
import kotlinx.datetime.Clock
import kotlinx.datetime.Instant
import java.util.UUID

View File

@@ -1,7 +1,7 @@
package eventDemo.app.event.event
package eventDemo.business.event.event
import eventDemo.app.entity.GameId
import eventDemo.app.entity.Player
import eventDemo.business.entity.GameId
import eventDemo.business.entity.Player
import kotlinx.datetime.Clock
import kotlinx.datetime.Instant
import java.util.UUID

View File

@@ -1,32 +1,30 @@
package eventDemo.app.eventListener
package eventDemo.business.event.eventListener
import eventDemo.app.entity.Card
import eventDemo.app.entity.Player
import eventDemo.app.event.GameEventBus
import eventDemo.app.event.event.CardIsPlayedEvent
import eventDemo.app.event.event.GameEvent
import eventDemo.app.event.event.GameStartedEvent
import eventDemo.app.event.event.NewPlayerEvent
import eventDemo.app.event.event.PlayerChoseColorEvent
import eventDemo.app.event.event.PlayerHavePassEvent
import eventDemo.app.event.event.PlayerReadyEvent
import eventDemo.app.event.event.PlayerWinEvent
import eventDemo.app.event.projection.GameStateRepository
import eventDemo.app.notification.ItsTheTurnOfNotification
import eventDemo.app.notification.Notification
import eventDemo.app.notification.PlayerAsJoinTheGameNotification
import eventDemo.app.notification.PlayerAsPlayACardNotification
import eventDemo.app.notification.PlayerHavePassNotification
import eventDemo.app.notification.PlayerWasChoseTheCardColorNotification
import eventDemo.app.notification.PlayerWasReadyNotification
import eventDemo.app.notification.PlayerWinNotification
import eventDemo.app.notification.TheGameWasStartedNotification
import eventDemo.app.notification.WelcomeToTheGameNotification
import eventDemo.app.notification.YourNewCardNotification
import eventDemo.business.entity.Card
import eventDemo.business.entity.Player
import eventDemo.business.event.GameEventBus
import eventDemo.business.event.event.CardIsPlayedEvent
import eventDemo.business.event.event.GameEvent
import eventDemo.business.event.event.GameStartedEvent
import eventDemo.business.event.event.NewPlayerEvent
import eventDemo.business.event.event.PlayerChoseColorEvent
import eventDemo.business.event.event.PlayerHavePassEvent
import eventDemo.business.event.event.PlayerReadyEvent
import eventDemo.business.event.event.PlayerWinEvent
import eventDemo.business.event.projection.GameStateRepository
import eventDemo.business.notification.ItsTheTurnOfNotification
import eventDemo.business.notification.Notification
import eventDemo.business.notification.PlayerAsJoinTheGameNotification
import eventDemo.business.notification.PlayerAsPlayACardNotification
import eventDemo.business.notification.PlayerHavePassNotification
import eventDemo.business.notification.PlayerWasChoseTheCardColorNotification
import eventDemo.business.notification.PlayerWasReadyNotification
import eventDemo.business.notification.PlayerWinNotification
import eventDemo.business.notification.TheGameWasStartedNotification
import eventDemo.business.notification.WelcomeToTheGameNotification
import eventDemo.business.notification.YourNewCardNotification
import io.github.oshai.kotlinlogging.KotlinLogging
import io.github.oshai.kotlinlogging.withLoggingContext
import kotlinx.coroutines.channels.SendChannel
import kotlinx.coroutines.channels.trySendBlocking
class PlayerNotificationEventListener(
private val eventBus: GameEventBus,
@@ -35,7 +33,7 @@ class PlayerNotificationEventListener(
private val logger = KotlinLogging.logger {}
fun startListening(
outgoingNotificationChannel: SendChannel<Notification>,
outgoingNotification: (Notification) -> Unit,
currentPlayer: Player,
) {
eventBus.subscribe { event: GameEvent ->
@@ -46,7 +44,7 @@ class PlayerNotificationEventListener(
withLoggingContext("notification" to this.toString()) {
if (currentState.players.contains(currentPlayer)) {
// Only notify players who have already joined the game.
outgoingNotificationChannel.trySendBlocking(this)
outgoingNotification(this)
logger.info { "Notification was SEND" }
} else {
// Rare use case, when a connexion is created with the channel,

View File

@@ -1,13 +1,13 @@
package eventDemo.app.eventListener
package eventDemo.business.event.eventListener
import eventDemo.app.event.GameEventBus
import eventDemo.app.event.GameEventHandler
import eventDemo.app.event.event.GameEvent
import eventDemo.app.event.event.GameStartedEvent
import eventDemo.app.event.event.PlayerReadyEvent
import eventDemo.app.event.event.PlayerWinEvent
import eventDemo.app.event.projection.GameState
import eventDemo.app.event.projection.GameStateRepository
import eventDemo.business.event.GameEventBus
import eventDemo.business.event.GameEventHandler
import eventDemo.business.event.event.GameEvent
import eventDemo.business.event.event.GameStartedEvent
import eventDemo.business.event.event.PlayerReadyEvent
import eventDemo.business.event.event.PlayerWinEvent
import eventDemo.business.event.projection.GameState
import eventDemo.business.event.projection.GameStateRepository
import io.github.oshai.kotlinlogging.KotlinLogging
import io.github.oshai.kotlinlogging.withLoggingContext

View File

@@ -1,9 +1,9 @@
package eventDemo.app.event.projection
package eventDemo.business.event.projection
import eventDemo.app.entity.Card
import eventDemo.app.entity.Deck
import eventDemo.app.entity.GameId
import eventDemo.app.entity.Player
import eventDemo.business.entity.Card
import eventDemo.business.entity.Deck
import eventDemo.business.entity.GameId
import eventDemo.business.entity.Player
import kotlinx.serialization.Serializable
@Serializable

View File

@@ -1,15 +1,15 @@
package eventDemo.app.event.projection
package eventDemo.business.event.projection
import eventDemo.app.entity.Card
import eventDemo.app.event.event.CardIsPlayedEvent
import eventDemo.app.event.event.GameEvent
import eventDemo.app.event.event.GameStartedEvent
import eventDemo.app.event.event.NewPlayerEvent
import eventDemo.app.event.event.PlayerActionEvent
import eventDemo.app.event.event.PlayerChoseColorEvent
import eventDemo.app.event.event.PlayerHavePassEvent
import eventDemo.app.event.event.PlayerReadyEvent
import eventDemo.app.event.event.PlayerWinEvent
import eventDemo.business.entity.Card
import eventDemo.business.event.event.CardIsPlayedEvent
import eventDemo.business.event.event.GameEvent
import eventDemo.business.event.event.GameStartedEvent
import eventDemo.business.event.event.NewPlayerEvent
import eventDemo.business.event.event.PlayerActionEvent
import eventDemo.business.event.event.PlayerChoseColorEvent
import eventDemo.business.event.event.PlayerHavePassEvent
import eventDemo.business.event.event.PlayerReadyEvent
import eventDemo.business.event.event.PlayerWinEvent
import io.github.oshai.kotlinlogging.KotlinLogging
fun GameState.apply(event: GameEvent): GameState =

View File

@@ -0,0 +1,10 @@
package eventDemo.business.event.projection
import eventDemo.business.entity.GameId
import eventDemo.business.event.event.GameEvent
interface GameStateRepository {
fun getLast(gameId: GameId): GameState
fun getUntil(event: GameEvent): GameState
}

View File

@@ -1,4 +1,4 @@
package eventDemo.app.event.projection
package eventDemo.business.event.projection
import eventDemo.libs.event.AggregateId

View File

@@ -1,4 +1,4 @@
package eventDemo.app.notification
package eventDemo.business.notification
import eventDemo.configuration.UUIDSerializer
import eventDemo.libs.command.Command

View File

@@ -1,3 +1,3 @@
package eventDemo.app.notification
package eventDemo.business.notification
sealed interface CommandNotification : Notification

View File

@@ -1,4 +1,4 @@
package eventDemo.app.notification
package eventDemo.business.notification
import eventDemo.configuration.UUIDSerializer
import eventDemo.libs.command.CommandId

View File

@@ -1,6 +1,6 @@
package eventDemo.app.notification
package eventDemo.business.notification
import eventDemo.app.entity.Player
import eventDemo.business.entity.Player
import eventDemo.configuration.UUIDSerializer
import kotlinx.serialization.Serializable
import java.util.UUID

View File

@@ -1,4 +1,4 @@
package eventDemo.app.notification
package eventDemo.business.notification
import eventDemo.configuration.UUIDSerializer
import kotlinx.serialization.Serializable

View File

@@ -1,6 +1,6 @@
package eventDemo.app.notification
package eventDemo.business.notification
import eventDemo.app.entity.Player
import eventDemo.business.entity.Player
import eventDemo.configuration.UUIDSerializer
import kotlinx.serialization.Serializable
import java.util.UUID

View File

@@ -1,7 +1,7 @@
package eventDemo.app.notification
package eventDemo.business.notification
import eventDemo.app.entity.Card
import eventDemo.app.entity.Player
import eventDemo.business.entity.Card
import eventDemo.business.entity.Player
import eventDemo.configuration.UUIDSerializer
import kotlinx.serialization.Serializable
import java.util.UUID

View File

@@ -1,6 +1,6 @@
package eventDemo.app.notification
package eventDemo.business.notification
import eventDemo.app.entity.Player
import eventDemo.business.entity.Player
import eventDemo.configuration.UUIDSerializer
import kotlinx.serialization.Serializable
import java.util.UUID

View File

@@ -1,7 +1,7 @@
package eventDemo.app.notification
package eventDemo.business.notification
import eventDemo.app.entity.Card
import eventDemo.app.entity.Player
import eventDemo.business.entity.Card
import eventDemo.business.entity.Player
import eventDemo.configuration.UUIDSerializer
import kotlinx.serialization.Serializable
import java.util.UUID

View File

@@ -1,6 +1,6 @@
package eventDemo.app.notification
package eventDemo.business.notification
import eventDemo.app.entity.Player
import eventDemo.business.entity.Player
import eventDemo.configuration.UUIDSerializer
import kotlinx.serialization.Serializable
import java.util.UUID

View File

@@ -1,6 +1,6 @@
package eventDemo.app.notification
package eventDemo.business.notification
import eventDemo.app.entity.Player
import eventDemo.business.entity.Player
import eventDemo.configuration.UUIDSerializer
import kotlinx.serialization.Serializable
import java.util.UUID

View File

@@ -1,6 +1,6 @@
package eventDemo.app.notification
package eventDemo.business.notification
import eventDemo.app.entity.Card
import eventDemo.business.entity.Card
import eventDemo.configuration.UUIDSerializer
import kotlinx.serialization.Serializable
import java.util.UUID

View File

@@ -1,6 +1,6 @@
package eventDemo.app.notification
package eventDemo.business.notification
import eventDemo.app.entity.Player
import eventDemo.business.entity.Player
import eventDemo.configuration.UUIDSerializer
import kotlinx.serialization.Serializable
import java.util.UUID

View File

@@ -1,6 +1,6 @@
package eventDemo.app.notification
package eventDemo.business.notification
import eventDemo.app.entity.Card
import eventDemo.business.entity.Card
import eventDemo.configuration.UUIDSerializer
import kotlinx.serialization.Serializable
import java.util.UUID

View File

@@ -2,7 +2,7 @@ package eventDemo.configuration
import com.auth0.jwt.JWT
import com.auth0.jwt.algorithms.Algorithm
import eventDemo.app.entity.Player
import eventDemo.business.entity.Player
import io.ktor.http.HttpStatusCode
import io.ktor.server.application.Application
import io.ktor.server.application.call

View File

@@ -1,20 +1,21 @@
package eventDemo.configuration
import eventDemo.app.command.GameCommandActionRunner
import eventDemo.app.command.GameCommandHandler
import eventDemo.app.command.command.GameCommand
import eventDemo.app.event.GameEventBus
import eventDemo.app.event.GameEventHandler
import eventDemo.app.event.GameEventStore
import eventDemo.app.event.projection.GameStateRepository
import eventDemo.app.event.projection.SnapshotConfig
import eventDemo.app.eventListener.PlayerNotificationEventListener
import eventDemo.adapter.infrastructureLayer.event.GameEventBusInMemory
import eventDemo.adapter.infrastructureLayer.event.GameEventStoreInMemory
import eventDemo.adapter.infrastructureLayer.event.projection.GameStateRepositoryInMemory
import eventDemo.business.command.GameCommandActionRunner
import eventDemo.business.command.GameCommandHandler
import eventDemo.business.command.command.GameCommand
import eventDemo.business.event.GameEventBus
import eventDemo.business.event.GameEventHandler
import eventDemo.business.event.GameEventStore
import eventDemo.business.event.eventListener.PlayerNotificationEventListener
import eventDemo.business.event.projection.GameStateRepository
import eventDemo.libs.command.CommandRunnerController
import eventDemo.libs.command.CommandStreamChannel
import eventDemo.libs.event.EventBusInMemory
import eventDemo.libs.event.EventStoreInMemory
import eventDemo.libs.event.VersionBuilder
import eventDemo.libs.event.VersionBuilderLocal
import eventDemo.libs.event.projection.SnapshotConfig
import io.ktor.server.application.Application
import io.ktor.server.application.install
import org.koin.core.module.dsl.singleOf
@@ -33,14 +34,17 @@ fun Application.configureKoin() {
val appKoinModule =
module {
single {
GameEventBus(EventBusInMemory())
}
GameEventBusInMemory()
} bind GameEventBus::class
single {
GameEventStore(EventStoreInMemory())
}
GameEventStoreInMemory()
} bind GameEventStore::class
single {
GameStateRepository(get(), get(), snapshotConfig = SnapshotConfig())
}
GameStateRepositoryInMemory(get(), get(), snapshotConfig = SnapshotConfig())
} bind GameStateRepository::class
single {
CommandStreamChannel<GameCommand>(get())
}

View File

@@ -1,9 +1,9 @@
package eventDemo.configuration
import eventDemo.app.command.action.ICantPlay
import eventDemo.app.command.action.IWantToJoinTheGame
import eventDemo.app.command.action.IWantToPlayCard
import eventDemo.app.command.action.IamReadyToPlay
import eventDemo.business.command.action.ICantPlay
import eventDemo.business.command.action.IWantToJoinTheGame
import eventDemo.business.command.action.IWantToPlayCard
import eventDemo.business.command.action.IamReadyToPlay
import org.koin.core.module.Module
import org.koin.core.module.dsl.singleOf

View File

@@ -1,6 +1,6 @@
package eventDemo.configuration
import eventDemo.app.eventListener.ReactionEventListener
import eventDemo.business.event.eventListener.ReactionEventListener
import io.ktor.server.application.Application
import org.koin.ktor.ext.get

View File

@@ -1,7 +1,7 @@
package eventDemo.configuration
import eventDemo.app.entity.GameId
import eventDemo.app.entity.Player
import eventDemo.business.entity.GameId
import eventDemo.business.entity.Player
import eventDemo.libs.command.CommandId
import io.ktor.serialization.kotlinx.json.json
import io.ktor.server.application.Application

View File

@@ -1,6 +1,6 @@
package eventDemo.configuration
import eventDemo.app.query.readTheGameState
import eventDemo.adapter.interfaceLayer.readTheGameState
import io.ktor.server.application.Application
import io.ktor.server.routing.routing
import org.koin.ktor.ext.get

View File

@@ -1,8 +1,8 @@
package eventDemo.configuration
import eventDemo.app.command.GameCommandHandler
import eventDemo.app.command.gameWebSocket
import eventDemo.app.eventListener.PlayerNotificationEventListener
import eventDemo.adapter.interfaceLayer.gameWebSocket
import eventDemo.business.command.GameCommandHandler
import eventDemo.business.event.eventListener.PlayerNotificationEventListener
import io.ktor.server.application.Application
import io.ktor.server.routing.routing
import kotlinx.coroutines.DelicateCoroutinesApi

View File

@@ -1,5 +1,6 @@
package eventDemo.app.event.projection
package eventDemo.libs.event.projection
import eventDemo.business.event.projection.Projection
import eventDemo.libs.event.AggregateId
import eventDemo.libs.event.Event
import eventDemo.libs.event.EventStore
@@ -24,7 +25,7 @@ data class SnapshotConfig(
class ProjectionSnapshotRepositoryInMemory<E : Event<ID>, P : Projection<ID>, ID : AggregateId>(
private val eventStore: EventStore<E, ID>,
private val initialStateBuilder: (ID) -> P,
private val initialStateBuilder: (aggregateId: ID) -> P,
private val snapshotCacheConfig: SnapshotConfig = SnapshotConfig(),
private val applyToProjection: P.(event: E) -> P,
) {