From e600544531764f67a5917483526d8d1941454640 Mon Sep 17 00:00:00 2001 From: Joffrey Bion Date: Thu, 26 Mar 2020 20:50:25 +0100 Subject: Rework sagas and router to sub/unsubscribe properly --- .../sevenwonders/ui/components/Application.kt | 19 ++++------ .../ui/redux/sagas/GameBrowserSagas.kt | 3 ++ .../sevenwonders/ui/redux/sagas/LobbySagas.kt | 40 ++++++++++++---------- .../luxons/sevenwonders/ui/redux/sagas/Sagas.kt | 26 ++++++++++---- .../org/luxons/sevenwonders/ui/router/Router.kt | 38 ++++++++++++-------- 5 files changed, 75 insertions(+), 51 deletions(-) (limited to 'sw-ui-kt') diff --git a/sw-ui-kt/src/main/kotlin/org/luxons/sevenwonders/ui/components/Application.kt b/sw-ui-kt/src/main/kotlin/org/luxons/sevenwonders/ui/components/Application.kt index d692c256..b1244b5c 100644 --- a/sw-ui-kt/src/main/kotlin/org/luxons/sevenwonders/ui/components/Application.kt +++ b/sw-ui-kt/src/main/kotlin/org/luxons/sevenwonders/ui/components/Application.kt @@ -2,26 +2,21 @@ package org.luxons.sevenwonders.ui.components import org.luxons.sevenwonders.ui.components.game.gameScene import org.luxons.sevenwonders.ui.components.gameBrowser.gameBrowser +import org.luxons.sevenwonders.ui.components.home.home +import org.luxons.sevenwonders.ui.components.lobby.lobby +import org.luxons.sevenwonders.ui.router.Route import react.RBuilder import react.router.dom.hashRouter import react.router.dom.redirect import react.router.dom.route import react.router.dom.switch -import org.luxons.sevenwonders.ui.components.home.home -import org.luxons.sevenwonders.ui.components.lobby.lobby -import react.RProps - -interface IdProps : RProps { - val id: Long -} - fun RBuilder.application() = hashRouter { switch { - route("/games") { gameBrowser() } - route("/game") { gameScene() } - route("/lobby") { lobby() } - route("/", exact = true) { home() } + route(Route.GAME_BROWSER.path) { gameBrowser() } + route(Route.GAME.path) { gameScene() } + route(Route.LOBBY.path) { lobby() } + route(Route.HOME.path, exact = true) { home() } redirect(from = "*", to = "/") } } diff --git a/sw-ui-kt/src/main/kotlin/org/luxons/sevenwonders/ui/redux/sagas/GameBrowserSagas.kt b/sw-ui-kt/src/main/kotlin/org/luxons/sevenwonders/ui/redux/sagas/GameBrowserSagas.kt index c5e3bdb8..38c3e60a 100644 --- a/sw-ui-kt/src/main/kotlin/org/luxons/sevenwonders/ui/redux/sagas/GameBrowserSagas.kt +++ b/sw-ui-kt/src/main/kotlin/org/luxons/sevenwonders/ui/redux/sagas/GameBrowserSagas.kt @@ -10,6 +10,8 @@ import org.luxons.sevenwonders.ui.redux.EnterLobbyAction import org.luxons.sevenwonders.ui.redux.RequestCreateGameAction import org.luxons.sevenwonders.ui.redux.RequestJoinGameAction import org.luxons.sevenwonders.ui.redux.UpdateGameListAction +import org.luxons.sevenwonders.ui.router.Navigate +import org.luxons.sevenwonders.ui.router.Route suspend fun SwSagaContext.gameBrowserSaga(session: SevenWondersSession) { GameBrowserSaga(session, this).run() @@ -26,6 +28,7 @@ private class GameBrowserSaga( val lobby = awaitCreateOrJoinGame() gamesSubscription.unsubscribe() sagaContext.dispatch(EnterLobbyAction(lobby)) + sagaContext.dispatch(Navigate(Route.LOBBY)) } } diff --git a/sw-ui-kt/src/main/kotlin/org/luxons/sevenwonders/ui/redux/sagas/LobbySagas.kt b/sw-ui-kt/src/main/kotlin/org/luxons/sevenwonders/ui/redux/sagas/LobbySagas.kt index b2d83416..143fecd8 100644 --- a/sw-ui-kt/src/main/kotlin/org/luxons/sevenwonders/ui/redux/sagas/LobbySagas.kt +++ b/sw-ui-kt/src/main/kotlin/org/luxons/sevenwonders/ui/redux/sagas/LobbySagas.kt @@ -2,38 +2,40 @@ package org.luxons.sevenwonders.ui.redux.sagas import kotlinx.coroutines.coroutineScope import kotlinx.coroutines.launch +import org.hildan.krossbow.stomp.StompSubscription import org.luxons.sevenwonders.client.SevenWondersSession +import org.luxons.sevenwonders.model.api.LobbyDTO import org.luxons.sevenwonders.ui.redux.EnterGameAction import org.luxons.sevenwonders.ui.redux.RequestStartGameAction import org.luxons.sevenwonders.ui.redux.UpdateLobbyAction -import org.luxons.sevenwonders.ui.router.Router +import org.luxons.sevenwonders.ui.router.Navigate +import org.luxons.sevenwonders.ui.router.Route -suspend fun SwSagaContext.lobbySaga(session: SevenWondersSession, lobbyId: Long) { +suspend fun SwSagaContext.lobbySaga(session: SevenWondersSession) { + val lobbyId = getState().currentLobbyId ?: error("Lobby saga run without a current lobby") coroutineScope { - launch { watchLobbyUpdates(session, lobbyId) } - launch { handleGameStart(session, lobbyId) } - launch { watchStartGame(session) } + val lobbyUpdatesSubscription = session.watchLobbyUpdates(lobbyId) + launch { watchLobbyUpdates(lobbyUpdatesSubscription) } + val startGameJob = launch { awaitStartGame(session) } + + awaitGameStart(session, lobbyId) + + lobbyUpdatesSubscription.unsubscribe() + startGameJob.cancel() + dispatch(Navigate(Route.GAME)) } } -private suspend fun SwSagaContext.watchLobbyUpdates(session: SevenWondersSession, lobbyId: Long) { - val lobbyUpdates = session.watchLobbyUpdates(lobbyId) - for (lobby in lobbyUpdates.messages) { - dispatch(UpdateLobbyAction(lobby)) - } +private suspend fun SwSagaContext.watchLobbyUpdates(lobbyUpdatesSubscription: StompSubscription) { + dispatchAll(lobbyUpdatesSubscription.messages) { UpdateLobbyAction(it) } } -private suspend fun SwSagaContext.handleGameStart(session: SevenWondersSession, lobbyId: Long) { - val gameStartSubscription = session.watchGameStart(lobbyId) - gameStartSubscription.messages.receive() +private suspend fun SwSagaContext.awaitGameStart(session: SevenWondersSession, lobbyId: Long) { + session.awaitGameStart(lobbyId) dispatch(EnterGameAction(lobbyId)) - - coroutineScope { - launch { gameSaga(session) } - Router.game() - } } -private suspend fun SwSagaContext.watchStartGame(session: SevenWondersSession) = onEach { +private suspend fun SwSagaContext.awaitStartGame(session: SevenWondersSession) { + next() session.startGame() } diff --git a/sw-ui-kt/src/main/kotlin/org/luxons/sevenwonders/ui/redux/sagas/Sagas.kt b/sw-ui-kt/src/main/kotlin/org/luxons/sevenwonders/ui/redux/sagas/Sagas.kt index ded0bc89..a0cd6f3c 100644 --- a/sw-ui-kt/src/main/kotlin/org/luxons/sevenwonders/ui/redux/sagas/Sagas.kt +++ b/sw-ui-kt/src/main/kotlin/org/luxons/sevenwonders/ui/redux/sagas/Sagas.kt @@ -1,16 +1,19 @@ package org.luxons.sevenwonders.ui.redux.sagas +import kotlinx.coroutines.coroutineScope import org.luxons.sevenwonders.client.SevenWondersClient +import org.luxons.sevenwonders.client.SevenWondersSession import org.luxons.sevenwonders.ui.redux.RequestChooseName import org.luxons.sevenwonders.ui.redux.SetCurrentPlayerAction import org.luxons.sevenwonders.ui.redux.SwState -import org.luxons.sevenwonders.ui.router.Router +import org.luxons.sevenwonders.ui.router.Route +import org.luxons.sevenwonders.ui.router.routerSaga import redux.RAction import redux.WrapperAction typealias SwSagaContext = SagaContext -suspend fun SwSagaContext.rootSaga() { +suspend fun SwSagaContext.rootSaga() = coroutineScope { val action = next() val session = SevenWondersClient().connect("localhost:8000") console.info("Connected to Seven Wonders web socket API") @@ -18,8 +21,19 @@ suspend fun SwSagaContext.rootSaga() { val player = session.chooseName(action.playerName) dispatch(SetCurrentPlayerAction(player)) - Router.games() - gameBrowserSaga(session) - Router.lobby() - lobbySaga(session) + routerSaga(Route.GAME_BROWSER) { + when (it) { + Route.HOME -> homeSaga(session) + Route.LOBBY -> lobbySaga(session) + Route.GAME_BROWSER -> gameBrowserSaga(session) + Route.GAME -> gameSaga(session) + } + } +} + +private suspend fun SwSagaContext.homeSaga(session: SevenWondersSession): SevenWondersSession { + val action = next() + val player = session.chooseName(action.playerName) + dispatch(SetCurrentPlayerAction(player)) + return session } diff --git a/sw-ui-kt/src/main/kotlin/org/luxons/sevenwonders/ui/router/Router.kt b/sw-ui-kt/src/main/kotlin/org/luxons/sevenwonders/ui/router/Router.kt index 09789ee1..19e8bd94 100644 --- a/sw-ui-kt/src/main/kotlin/org/luxons/sevenwonders/ui/router/Router.kt +++ b/sw-ui-kt/src/main/kotlin/org/luxons/sevenwonders/ui/router/Router.kt @@ -1,22 +1,32 @@ package org.luxons.sevenwonders.ui.router +import kotlinx.coroutines.Job +import kotlinx.coroutines.coroutineScope +import kotlinx.coroutines.launch +import org.luxons.sevenwonders.ui.redux.sagas.SwSagaContext +import redux.RAction import kotlin.browser.window -object Router { - - fun games() { - push("/games") - } - - fun game() { - push("/game") - } +enum class Route(val path: String) { + HOME("/"), + GAME_BROWSER("/games"), + LOBBY("/lobby"), + GAME("/game"), +} - fun lobby() { - push("/lobby") - } +data class Navigate(val route: Route): RAction - private fun push(path: String) { - window.location.hash = path +suspend fun SwSagaContext.routerSaga( + startRoute: Route, + runRouteSaga: suspend SwSagaContext.(Route) -> Unit +) { + coroutineScope { + window.location.hash = startRoute.path + var currentSaga: Job = launch { runRouteSaga(startRoute) } + onEach { + currentSaga.cancel() + window.location.hash = it.route.path + currentSaga = launch { runRouteSaga(it.route) } + } } } -- cgit