Create route to list all the games

This commit is contained in:
2025-03-17 22:36:08 +01:00
parent 8074881d57
commit c3155da23c
14 changed files with 304 additions and 18 deletions

View File

@@ -0,0 +1,39 @@
package eventDemo.adapter.infrastructureLayer.event.projection
import eventDemo.business.entity.GameId
import eventDemo.business.event.GameEventHandler
import eventDemo.business.event.GameEventStore
import eventDemo.business.event.projection.gameList.GameList
import eventDemo.business.event.projection.gameList.GameListRepository
import eventDemo.business.event.projection.gameList.apply
import eventDemo.business.event.projection.gameState.GameState
import eventDemo.libs.event.projection.ProjectionSnapshotRepositoryInMemory
import eventDemo.libs.event.projection.SnapshotConfig
class GameListRepositoryInMemory(
eventStore: GameEventStore,
eventHandler: GameEventHandler,
snapshotConfig: SnapshotConfig = SnapshotConfig(),
) : GameListRepository {
private val projectionsSnapshot =
ProjectionSnapshotRepositoryInMemory(
eventStore = eventStore,
snapshotCacheConfig = snapshotConfig,
applyToProjection = GameList::apply,
initialStateBuilder = { aggregateId: GameId -> GameList(aggregateId) },
)
init {
eventHandler.registerProjectionBuilder { event ->
projectionsSnapshot.applyAndPutToCache(event)
}
}
/**
* Get the last version of the [GameState] from the all eventStream.
*
* It fetches it from the local cache if possible, otherwise it builds it.
*/
override fun getList(): List<GameList> =
projectionsSnapshot.getList()
}

View File

@@ -0,0 +1,28 @@
package eventDemo.adapter.interfaceLayer
import eventDemo.business.event.projection.gameList.GameListRepository
import io.ktor.resources.Resource
import io.ktor.server.application.call
import io.ktor.server.auth.authenticate
import io.ktor.server.resources.get
import io.ktor.server.response.respond
import io.ktor.server.routing.Route
import io.ktor.server.routing.get
import kotlinx.serialization.Serializable
@Serializable
@Resource("/games")
class Games
/**
* API routes to show all games.
*/
fun Route.readGamesList(gameListRepository: GameListRepository) {
authenticate {
// Read the last played card on the game.
get<Games> {
val gameList = gameListRepository.getList()
call.respond(gameList)
}
}
}

View File

@@ -13,7 +13,7 @@ import io.ktor.server.routing.Route
import kotlinx.serialization.Serializable
@Serializable
@Resource("/game/{id}")
@Resource("/games/{id}")
class Game(
@Serializable(with = GameIdSerializer::class)
val id: GameId,

View File

@@ -0,0 +1,22 @@
package eventDemo.business.event.projection.gameList
import eventDemo.business.entity.GameId
import eventDemo.business.entity.Player
import eventDemo.business.event.projection.Projection
import kotlinx.serialization.Serializable
@Serializable
data class GameList(
override val aggregateId: GameId,
override val lastEventVersion: Int = 0,
val status: Status = Status.OPENING,
val players: Set<Player> = emptySet(),
val winners: Set<Player> = emptySet(),
) : Projection<GameId> {
enum class Status {
OPENING,
IS_STARTED,
FINISH,
CANCELED,
}
}

View File

@@ -0,0 +1,51 @@
package eventDemo.business.event.projection.gameList
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
fun GameList.apply(event: GameEvent): GameList =
when (event) {
is NewPlayerEvent -> {
copy(
players = players + event.player,
status = GameList.Status.OPENING,
)
}
is GameStartedEvent -> {
copy(
status = GameList.Status.IS_STARTED,
)
}
is PlayerWinEvent -> {
copy(
winners = winners + event.player,
status = GameList.Status.FINISH,
)
}
is CardIsPlayedEvent -> {
this
}
is PlayerChoseColorEvent -> {
this
}
is PlayerHavePassEvent -> {
this
}
is PlayerReadyEvent -> {
this
}
}.copy(
lastEventVersion = event.version,
)

View File

@@ -0,0 +1,5 @@
package eventDemo.business.event.projection.gameList
interface GameListRepository {
fun getList(): List<GameList>
}

View File

@@ -2,9 +2,11 @@ package eventDemo.configuration.injection
import eventDemo.adapter.infrastructureLayer.event.GameEventBusInMemory
import eventDemo.adapter.infrastructureLayer.event.GameEventStoreInMemory
import eventDemo.adapter.infrastructureLayer.event.projection.GameListRepositoryInMemory
import eventDemo.adapter.infrastructureLayer.event.projection.GameStateRepositoryInMemory
import eventDemo.business.event.GameEventBus
import eventDemo.business.event.GameEventStore
import eventDemo.business.event.projection.gameList.GameListRepository
import eventDemo.business.event.projection.gameState.GameStateRepository
import eventDemo.libs.event.projection.SnapshotConfig
import org.koin.core.module.Module
@@ -22,4 +24,8 @@ fun Module.configureDIInfrastructure() {
single {
GameStateRepositoryInMemory(get(), get(), snapshotConfig = SnapshotConfig())
} bind GameStateRepository::class
single {
GameListRepositoryInMemory(get(), get(), snapshotConfig = SnapshotConfig())
} bind GameListRepository::class
}

View File

@@ -1,5 +1,6 @@
package eventDemo.configuration.route
import eventDemo.adapter.interfaceLayer.readGamesList
import eventDemo.adapter.interfaceLayer.readTheGameState
import io.ktor.server.application.Application
import io.ktor.server.routing.routing
@@ -8,5 +9,6 @@ import org.koin.ktor.ext.get
fun Application.declareHttpGameRoute() {
routing {
readTheGameState(get())
readGamesList(get())
}
}

View File

@@ -42,7 +42,7 @@ class ProjectionSnapshotRepositoryInMemory<E : Event<ID>, P : Projection<ID>, ID
* 6. remove old one
*/
fun applyAndPutToCache(event: E) {
if ((event.version % snapshotCacheConfig.modulo) == 0) {
if ((event.version % snapshotCacheConfig.modulo) == 1) {
getUntil(event)
.also {
save(it)
@@ -51,6 +51,14 @@ class ProjectionSnapshotRepositoryInMemory<E : Event<ID>, P : Projection<ID>, ID
}
}
/**
* Build the list of all [Projections][Projection]
*/
fun getList(): List<P> =
projectionsSnapshot.map { (id, b) ->
getLast(id)
}
/**
* Build the last version of the [Projection] from the cache.
*