Clean and fix

This commit is contained in:
2025-03-05 22:11:24 +01:00
parent d84e8359c9
commit 99f0760d3c
11 changed files with 110 additions and 92 deletions

View File

@@ -10,10 +10,15 @@ import eventDemo.app.entity.Player
import eventDemo.app.event.GameEventStream
import eventDemo.app.event.buildStateFromEventStream
import eventDemo.app.event.event.GameEvent
import eventDemo.libs.command.CommandBlock
import io.ktor.websocket.Frame
import kotlinx.coroutines.DelicateCoroutinesApi
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.Job
import kotlinx.coroutines.channels.ReceiveChannel
import kotlinx.coroutines.channels.SendChannel
import kotlinx.coroutines.runBlocking
import kotlinx.coroutines.channels.trySendBlocking
import kotlinx.coroutines.launch
/**
* Listen [GameCommand] on [GameCommandStream], check the validity and execute an action.
@@ -22,21 +27,31 @@ import kotlinx.coroutines.runBlocking
*/
class GameCommandHandler(
private val eventStream: GameEventStream,
incoming: ReceiveChannel<Frame>,
outgoing: SendChannel<Frame>,
) {
private val commandStream = GameCommandStream(incoming, outgoing)
private val playerNotifier: (String) -> Unit = { runBlocking { outgoing.send(Frame.Text(it)) } }
/**
* Init the handler
*/
suspend fun init(player: Player) {
@OptIn(DelicateCoroutinesApi::class)
fun handle(
player: Player,
incoming: ReceiveChannel<Frame>,
outgoing: SendChannel<Frame>,
): Job {
val commandStream = GameCommandStream(incoming, outgoing)
val playerNotifier: (String) -> Unit = { outgoing.trySendBlocking(Frame.Text(it)) }
return GlobalScope.launch {
init(player, commandStream, playerNotifier)
}
}
private suspend fun init(
player: Player,
commandStream: GameCommandStream,
playerNotifier: (String) -> Unit,
) {
commandStream.process { command ->
if (command.payload.player.id != player.id) {
runBlocking {
nack()
}
nack()
}
val gameState = command.buildGameState()
@@ -47,7 +62,7 @@ class GameCommandHandler(
is IWantToJoinTheGameCommand -> command.run(gameState, playerNotifier, eventStream)
is ICantPlayCommand -> command.run(gameState, playerNotifier, eventStream)
}
}
} as CommandBlock<GameCommand>
}
private fun GameCommand.buildGameState(): GameState = payload.gameId.buildStateFromEventStream(eventStream)

View File

@@ -1,8 +1,6 @@
package eventDemo.app.command
import eventDemo.app.entity.Player
import eventDemo.app.event.GameEventBus
import eventDemo.app.event.GameEventStream
import eventDemo.app.eventListener.GameEventPlayerNotificationListener
import io.ktor.server.application.ApplicationCall
import io.ktor.server.auth.authenticate
@@ -10,18 +8,15 @@ import io.ktor.server.auth.jwt.JWTPrincipal
import io.ktor.server.auth.principal
import io.ktor.server.routing.Route
import io.ktor.server.websocket.webSocket
import kotlinx.coroutines.launch
fun Route.gameSocket(
eventStream: GameEventStream,
eventBus: GameEventBus,
playerNotificationListener: GameEventPlayerNotificationListener,
commandHandler: GameCommandHandler,
) {
authenticate {
webSocket("/game") {
launch {
GameCommandHandler(eventStream, incoming, outgoing).init(call.getPlayer())
}
GameEventPlayerNotificationListener(eventBus, outgoing).init()
commandHandler.handle(call.getPlayer(), incoming, outgoing)
playerNotificationListener.startListening(outgoing)
}
}
}

View File

@@ -2,18 +2,17 @@ package eventDemo.app.event
import eventDemo.app.entity.GameId
import eventDemo.app.event.event.GameEvent
import eventDemo.libs.event.EventBus
import eventDemo.libs.event.EventStream
/**
* A stream to publish and read the played card event.
*/
class GameEventStream(
private val eventBus: EventBus<GameEvent, GameId>,
private val m: EventStream<GameEvent, GameId>,
) : EventStream<GameEvent, GameId> by m {
private val eventBus: GameEventBus,
private val eventStream: EventStream<GameEvent, GameId>,
) : EventStream<GameEvent, GameId> by eventStream {
override fun publish(event: GameEvent) {
m.publish(event)
eventStream.publish(event)
eventBus.publish(event)
}
}

View File

@@ -1,22 +1,18 @@
package eventDemo.app.eventListener
import eventDemo.app.entity.GameId
import eventDemo.app.event.GameEventBus
import eventDemo.app.event.event.GameEvent
import eventDemo.libs.event.EventBus
import eventDemo.shared.toFrame
import io.ktor.websocket.Frame
import kotlinx.coroutines.channels.SendChannel
import kotlinx.coroutines.runBlocking
import kotlinx.coroutines.channels.trySendBlocking
class GameEventPlayerNotificationListener(
private val eventBus: EventBus<GameEvent, GameId>,
private val outgoing: SendChannel<Frame>,
private val eventBus: GameEventBus,
) {
fun init() {
fun startListening(outgoing: SendChannel<Frame>) {
eventBus.subscribe { event: GameEvent ->
runBlocking {
outgoing.send(event.toFrame())
}
outgoing.trySendBlocking(event.toFrame())
}
}
}

View File

@@ -1,15 +1,14 @@
package eventDemo.app.eventListener
import eventDemo.app.entity.GameId
import eventDemo.app.event.GameEventBus
import eventDemo.app.event.GameEventStream
import eventDemo.app.event.buildStateFromEventStream
import eventDemo.app.event.event.GameEvent
import eventDemo.app.event.event.GameStartedEvent
import eventDemo.libs.event.EventBus
import eventDemo.libs.event.EventStream
class GameEventReactionListener(
private val eventBus: EventBus<GameEvent, GameId>,
private val eventStream: EventStream<GameEvent, GameId>,
private val eventBus: GameEventBus,
private val eventStream: GameEventStream,
) {
fun init() {
eventBus.subscribe { event: GameEvent ->