diff --git a/.gitignore b/.gitignore index 8008e56f..c28ffd55 100644 --- a/.gitignore +++ b/.gitignore @@ -86,3 +86,5 @@ buildNumber.properties .classpath # End of https://www.toptal.com/developers/gitignore/api/intellij,maven + +.env \ No newline at end of file diff --git a/application/src/main/kotlin/tw/waterballsa/gaas/application/usecases/StartGameUseCase.kt b/application/src/main/kotlin/tw/waterballsa/gaas/application/usecases/StartGameUseCase.kt index fd96a07f..6516ab15 100644 --- a/application/src/main/kotlin/tw/waterballsa/gaas/application/usecases/StartGameUseCase.kt +++ b/application/src/main/kotlin/tw/waterballsa/gaas/application/usecases/StartGameUseCase.kt @@ -71,7 +71,7 @@ class StartGameUseCase( val startGameRequest = StartGameRequest(roomId!!.value, players.map { it.toGamePlayer() }) val startGameResponse = gameService.startGame(gameServerHost, jwtToken, startGameRequest) - return StartedGameEvent(GAME_STARTED, Data(startGameResponse.url, roomId!!)) + return StartedGameEvent(GAME_STARTED, Data(startGameResponse.url, roomId!!, game.id!!)) } private fun Room.Player.toGamePlayer(): StartGameRequest.GamePlayer = diff --git a/domain/src/main/kotlin/tw/waterballsa/gaas/events/StartedGameEvent.kt b/domain/src/main/kotlin/tw/waterballsa/gaas/events/StartedGameEvent.kt index 3ec61bd8..b6d8e29d 100644 --- a/domain/src/main/kotlin/tw/waterballsa/gaas/events/StartedGameEvent.kt +++ b/domain/src/main/kotlin/tw/waterballsa/gaas/events/StartedGameEvent.kt @@ -1,5 +1,6 @@ package tw.waterballsa.gaas.events +import tw.waterballsa.gaas.domain.GameRegistration import tw.waterballsa.gaas.domain.Room import tw.waterballsa.gaas.events.enums.EventMessageType @@ -10,6 +11,7 @@ class StartedGameEvent( data class Data( val gameUrl: String, val roomId: Room.Id, + val gameId: GameRegistration.Id, ) override fun getEventData(): Any = data diff --git a/spring/src/main/kotlin/tw/waterballsa/gaas/spring/eventbus/DispatcherEventBus.kt b/spring/src/main/kotlin/tw/waterballsa/gaas/spring/eventbus/DispatcherEventBus.kt new file mode 100644 index 00000000..772458f8 --- /dev/null +++ b/spring/src/main/kotlin/tw/waterballsa/gaas/spring/eventbus/DispatcherEventBus.kt @@ -0,0 +1,20 @@ +package tw.waterballsa.gaas.spring.eventbus + +import org.springframework.stereotype.Component +import tw.waterballsa.gaas.application.eventbus.EventBus +import tw.waterballsa.gaas.events.DomainEvent +import kotlin.reflect.safeCast + +@Component +class DispatcherEventBus( + private val listeners: List>, +) : EventBus { + + override fun broadcast(events: Collection) { + listeners.forEach { listener -> + events.mapNotNull { listener.eventType.safeCast(it) } + .takeIf { it.isNotEmpty() } + ?.run { (listener as EventListener).onEvents(this) } + } + } +} diff --git a/spring/src/main/kotlin/tw/waterballsa/gaas/spring/eventbus/EventListener.kt b/spring/src/main/kotlin/tw/waterballsa/gaas/spring/eventbus/EventListener.kt new file mode 100644 index 00000000..6dac0c8a --- /dev/null +++ b/spring/src/main/kotlin/tw/waterballsa/gaas/spring/eventbus/EventListener.kt @@ -0,0 +1,9 @@ +package tw.waterballsa.gaas.spring.eventbus + +import tw.waterballsa.gaas.events.DomainEvent +import kotlin.reflect.KClass + +interface EventListener { + val eventType: KClass + fun onEvents(events: List) +} \ No newline at end of file diff --git a/spring/src/main/kotlin/tw/waterballsa/gaas/spring/eventbus/RoomEventListener.kt b/spring/src/main/kotlin/tw/waterballsa/gaas/spring/eventbus/RoomEventListener.kt new file mode 100644 index 00000000..b44a0e8c --- /dev/null +++ b/spring/src/main/kotlin/tw/waterballsa/gaas/spring/eventbus/RoomEventListener.kt @@ -0,0 +1,25 @@ +package tw.waterballsa.gaas.spring.eventbus + +import com.corundumstudio.socketio.SocketIOServer +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.stereotype.Component +import tw.waterballsa.gaas.events.RoomEvent +import kotlin.reflect.KClass + +@Component +class RoomEventListener( + override val eventType: KClass, + val socketIOServer: SocketIOServer, +): EventListener { + + @Autowired + constructor(socketIOServer: SocketIOServer): this(RoomEvent::class, socketIOServer) + + override fun onEvents(events: List) { + events + .forEach { + socketIOServer.getRoomOperations("ROOM_${it.getRoomId().value}") + .sendEvent(it.type.eventName, it.getEventData()) + } + } +} \ No newline at end of file diff --git a/spring/src/main/kotlin/tw/waterballsa/gaas/spring/eventbus/StartedGameEventListener.kt b/spring/src/main/kotlin/tw/waterballsa/gaas/spring/eventbus/StartedGameEventListener.kt new file mode 100644 index 00000000..5bb6a6d5 --- /dev/null +++ b/spring/src/main/kotlin/tw/waterballsa/gaas/spring/eventbus/StartedGameEventListener.kt @@ -0,0 +1,23 @@ +package tw.waterballsa.gaas.spring.eventbus + +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.stereotype.Component +import tw.waterballsa.gaas.events.StartedGameEvent +import tw.waterballsa.gaas.spring.repositories.dao.GameRegistrationDAO +import kotlin.reflect.KClass + +@Component +class StartedGameEventListener( + override val eventType: KClass, + private val gameRegistrationDAO: GameRegistrationDAO, +) : EventListener { + + @Autowired + constructor(gameRegistrationDAO: GameRegistrationDAO): this(StartedGameEvent::class, gameRegistrationDAO) + + override fun onEvents(events: List) { + events.forEach { + gameRegistrationDAO.incrementTimesPlayedById(it.data.gameId.value) + } + } +} \ No newline at end of file diff --git a/spring/src/main/kotlin/tw/waterballsa/gaas/spring/eventbus/WebSocketEventBus.kt b/spring/src/main/kotlin/tw/waterballsa/gaas/spring/eventbus/WebSocketEventBus.kt deleted file mode 100644 index 2a7f93f5..00000000 --- a/spring/src/main/kotlin/tw/waterballsa/gaas/spring/eventbus/WebSocketEventBus.kt +++ /dev/null @@ -1,27 +0,0 @@ -package tw.waterballsa.gaas.spring.eventbus - -import com.corundumstudio.socketio.SocketIOServer -import org.slf4j.Logger -import org.slf4j.LoggerFactory -import org.springframework.stereotype.Component -import tw.waterballsa.gaas.application.eventbus.EventBus -import tw.waterballsa.gaas.events.DomainEvent -import tw.waterballsa.gaas.events.RoomEvent -import kotlin.reflect.safeCast - -@Component -class WebSocketEventBus( - val socketIOServer: SocketIOServer -) : EventBus { - - private val logger: Logger = LoggerFactory.getLogger(WebSocketEventBus::class.java) - - override fun broadcast(events: Collection) { - events.asSequence() - .mapNotNull { RoomEvent::class.safeCast(it) } - .forEach { - socketIOServer.getRoomOperations("ROOM_${it.getRoomId().value}") - .sendEvent(it.type.eventName, it.getEventData()) - } - } -} diff --git a/spring/src/main/kotlin/tw/waterballsa/gaas/spring/repositories/SpringGameRegistrationRepository.kt b/spring/src/main/kotlin/tw/waterballsa/gaas/spring/repositories/SpringGameRegistrationRepository.kt index 3d3372ac..c2bcc316 100644 --- a/spring/src/main/kotlin/tw/waterballsa/gaas/spring/repositories/SpringGameRegistrationRepository.kt +++ b/spring/src/main/kotlin/tw/waterballsa/gaas/spring/repositories/SpringGameRegistrationRepository.kt @@ -2,6 +2,7 @@ package tw.waterballsa.gaas.spring.repositories import org.springframework.data.domain.Sort import org.springframework.data.domain.Sort.Order +import org.springframework.data.mongodb.core.query.Update import org.springframework.stereotype.Component import tw.waterballsa.gaas.application.repositories.GameRegistrationRepository import tw.waterballsa.gaas.domain.GameRegistration @@ -43,7 +44,9 @@ class SpringGameRegistrationRepository( gameRegistrationDAO.save(gameRegistration.toData()).toDomain() enum class SortBy(val value: String, val orders: List) { - CREATED_ON("createdOn", listOf(Order.desc("createdOn"), Order.desc("_id"))); + CREATED_ON("createdOn", listOf(Order.desc("createdOn"), Order.desc("_id"))), + TIMES_PLAYED("timesPlayed", listOf(Order.desc("timesPlayed"), Order.desc("_id"))) + ; companion object { private val map = SortBy.values().associateBy { it.value } diff --git a/spring/src/main/kotlin/tw/waterballsa/gaas/spring/repositories/dao/GameRegistrationDAO.kt b/spring/src/main/kotlin/tw/waterballsa/gaas/spring/repositories/dao/GameRegistrationDAO.kt index ae2cd565..ded3ef43 100644 --- a/spring/src/main/kotlin/tw/waterballsa/gaas/spring/repositories/dao/GameRegistrationDAO.kt +++ b/spring/src/main/kotlin/tw/waterballsa/gaas/spring/repositories/dao/GameRegistrationDAO.kt @@ -1,6 +1,8 @@ package tw.waterballsa.gaas.spring.repositories.dao import org.springframework.data.mongodb.repository.MongoRepository +import org.springframework.data.mongodb.repository.Query +import org.springframework.data.mongodb.repository.Update import org.springframework.stereotype.Repository import tw.waterballsa.gaas.spring.repositories.data.GameRegistrationData @@ -8,4 +10,8 @@ import tw.waterballsa.gaas.spring.repositories.data.GameRegistrationData interface GameRegistrationDAO : MongoRepository { fun findByUniqueName(uniqueName: String): GameRegistrationData? fun existsByUniqueName(uniqueName: String): Boolean + + @Query("{ '_id' : ?0 }") + @Update("{ '\$inc' : { 'timesPlayed' : ?1 } }") + fun incrementTimesPlayedById(id: String, increment: Long = 1) } diff --git a/spring/src/main/kotlin/tw/waterballsa/gaas/spring/repositories/data/GameRegistrationData.kt b/spring/src/main/kotlin/tw/waterballsa/gaas/spring/repositories/data/GameRegistrationData.kt index 6ef8e23e..bec1611c 100644 --- a/spring/src/main/kotlin/tw/waterballsa/gaas/spring/repositories/data/GameRegistrationData.kt +++ b/spring/src/main/kotlin/tw/waterballsa/gaas/spring/repositories/data/GameRegistrationData.kt @@ -22,6 +22,7 @@ class GameRegistrationData( var frontEndUrl: String?, var backEndUrl: String?, val createdOn: Instant?, + var timesPlayed: Long? = null, ) { @DBRef var logs: MutableList = mutableListOf()