diff --git a/build.gradle b/build.gradle index 866b267a73ed144d559a5e7c556312fca158dac5..c2925e038b4a7f26c0b9ae9d9a8774d68873ee0b 100644 --- a/build.gradle +++ b/build.gradle @@ -24,10 +24,13 @@ dependencies { implementation 'org.springframework.boot:spring-boot-starter-websocket' implementation 'com.fasterxml.jackson.module:jackson-module-kotlin' implementation 'org.jetbrains.kotlin:kotlin-reflect' + implementation 'org.springframework.boot:spring-boot-starter-data-jpa' developmentOnly 'org.springframework.boot:spring-boot-devtools' testImplementation 'org.springframework.boot:spring-boot-starter-test' testImplementation 'org.jetbrains.kotlin:kotlin-test-junit5' + runtimeOnly 'com.h2database:h2' testRuntimeOnly 'org.junit.platform:junit-platform-launcher' + implementation 'org.json:org.json:chargebee-1.0' } kotlin { diff --git a/src/main/kotlin/de/thk/gm/remotecontrol/configs/WebSocketsConfig.kt b/src/main/kotlin/de/thk/gm/remotecontrol/configs/WebSocketsConfig.kt index 4fd3d90be9217549ab35504fb19e4450545d02a2..59b3b2e268fe067b46af9489df83c2d1e6431446 100644 --- a/src/main/kotlin/de/thk/gm/remotecontrol/configs/WebSocketsConfig.kt +++ b/src/main/kotlin/de/thk/gm/remotecontrol/configs/WebSocketsConfig.kt @@ -1,6 +1,6 @@ package de.thk.gm.remotecontrol.configs -import de.thk.gm.remotecontrol.handlers.ColorGameHandler +import de.thk.gm.remotecontrol.handlers.GameHandler import org.springframework.context.annotation.Configuration import org.springframework.web.socket.config.annotation.EnableWebSocket import org.springframework.web.socket.config.annotation.WebSocketConfigurer @@ -10,6 +10,6 @@ import org.springframework.web.socket.config.annotation.WebSocketHandlerRegistry @EnableWebSocket class WebSocketsConfig : WebSocketConfigurer { override fun registerWebSocketHandlers(registry: WebSocketHandlerRegistry) { - registry.addHandler(ColorGameHandler(), "/ws/s") + registry.addHandler(GameHandler(), "/game") } } \ No newline at end of file diff --git a/src/main/kotlin/de/thk/gm/remotecontrol/controllers/GameController.kt b/src/main/kotlin/de/thk/gm/remotecontrol/controllers/GameController.kt new file mode 100644 index 0000000000000000000000000000000000000000..6aab8a8a73bdd28295b54cdc7ae32be303afa3aa --- /dev/null +++ b/src/main/kotlin/de/thk/gm/remotecontrol/controllers/GameController.kt @@ -0,0 +1,38 @@ +package de.thk.gm.remotecontrol.controllers + +import de.thk.gm.remotecontrol.models.Game +import de.thk.gm.remotecontrol.services.GamesService +import org.springframework.stereotype.Controller +import org.springframework.ui.Model +import org.springframework.web.bind.annotation.GetMapping +import org.springframework.web.bind.annotation.PathVariable +import org.springframework.web.bind.annotation.PostMapping +import java.util.* + +@Controller +class GameController (private val gamesService: GamesService) { + @GetMapping("/") + fun index(model: Model): String { + model.addAttribute("games",gamesService.getAllGames()) + return "index" + } + + @GetMapping("/games/{id}") + fun game(model: Model, @PathVariable id: UUID): String { + model.addAttribute("id", id) + return "game" + } + + @PostMapping("/games") + fun createGame(): String { + var game = Game() + gamesService.saveGame(game) + return "redirect:/" + } + + @GetMapping("/controller/{id}") + fun controller(model: Model, @PathVariable id: String): String { + model.addAttribute("id", id) + return "controller" + } +} \ No newline at end of file diff --git a/src/main/kotlin/de/thk/gm/remotecontrol/controllers/WelcomeController.kt b/src/main/kotlin/de/thk/gm/remotecontrol/controllers/WelcomeController.kt deleted file mode 100644 index ef9a47fe62beaaa895851bbe1ac2f4d20e7e2de8..0000000000000000000000000000000000000000 --- a/src/main/kotlin/de/thk/gm/remotecontrol/controllers/WelcomeController.kt +++ /dev/null @@ -1,18 +0,0 @@ -package de.thk.gm.remotecontrol.controllers - -import org.springframework.stereotype.Controller -import org.springframework.ui.Model -import org.springframework.web.bind.annotation.GetMapping - -@Controller -class WelcomeController { - @GetMapping("/") - fun index(model: Model): String { - return "index" - } - - @GetMapping("/colorgame") - fun colorgame(model: Model): String { - return "colorgame" - } -} \ No newline at end of file diff --git a/src/main/kotlin/de/thk/gm/remotecontrol/handlers/ColorGameHandler.kt b/src/main/kotlin/de/thk/gm/remotecontrol/handlers/ColorGameHandler.kt deleted file mode 100644 index 7b8d6c087fa1ed5e4d61211947d01591ed45091c..0000000000000000000000000000000000000000 --- a/src/main/kotlin/de/thk/gm/remotecontrol/handlers/ColorGameHandler.kt +++ /dev/null @@ -1,12 +0,0 @@ -package de.thk.gm.remotecontrol.handlers - -import org.springframework.web.socket.CloseStatus -import org.springframework.web.socket.TextMessage -import org.springframework.web.socket.WebSocketSession -import org.springframework.web.socket.handler.TextWebSocketHandler - -class ColorGameHandler : TextWebSocketHandler() { - override fun afterConnectionEstablished(session: WebSocketSession) { - session.sendMessage(TextMessage(session.id)) - } -} \ No newline at end of file diff --git a/src/main/kotlin/de/thk/gm/remotecontrol/handlers/GameHandler.kt b/src/main/kotlin/de/thk/gm/remotecontrol/handlers/GameHandler.kt new file mode 100644 index 0000000000000000000000000000000000000000..f0d118559c4d2f6a27b683d481a2c350853da539 --- /dev/null +++ b/src/main/kotlin/de/thk/gm/remotecontrol/handlers/GameHandler.kt @@ -0,0 +1,54 @@ +package de.thk.gm.remotecontrol.handlers + +import org.json.JSONObject +import org.springframework.web.socket.CloseStatus +import org.springframework.web.socket.TextMessage +import org.springframework.web.socket.WebSocketSession +import org.springframework.web.socket.handler.TextWebSocketHandler +import org.springframework.web.util.UriComponents +import org.springframework.web.util.UriComponentsBuilder + +class GameHandler : TextWebSocketHandler() { + private val hashMapOfSessions : HashMap<String, ArrayList<WebSocketSession>> = HashMap() + + override fun afterConnectionEstablished(session: WebSocketSession) { + var uri : UriComponents = UriComponentsBuilder.fromUri(session.uri!!).build() + var side = uri.queryParams.getFirst("side") + if(side != null && side == "game") { + var id = uri.queryParams.getFirst("id") + if(id != null) { + var sessions = hashMapOfSessions[id] + if(sessions == null) { + sessions = ArrayList() + } + sessions.add(session) + hashMapOfSessions[id] = sessions + } + } + + } + + override fun handleTextMessage(session: WebSocketSession, message: TextMessage) { + var uri : UriComponents = UriComponentsBuilder.fromUri(session.uri!!).build() + var side = uri.queryParams.getFirst("side") + if(side != null && side == "controller") { + var id = uri.queryParams.getFirst("id") + var sessions = hashMapOfSessions[id] + if(sessions != null) { + for (gameSession in sessions) { + gameSession.sendMessage(message) + } + } + } + } + + override fun afterConnectionClosed(session: WebSocketSession, status: CloseStatus) { + var uri : UriComponents = UriComponentsBuilder.fromUri(session.uri!!).build() + var side = uri.queryParams.getFirst("side") + if(side != null && side == "game") { + var id = uri.queryParams.getFirst("id") + var sessions = hashMapOfSessions[id] + sessions?.remove(session) + } + } +} \ No newline at end of file diff --git a/src/main/kotlin/de/thk/gm/remotecontrol/models/Game.kt b/src/main/kotlin/de/thk/gm/remotecontrol/models/Game.kt new file mode 100644 index 0000000000000000000000000000000000000000..b3fb6bcb5b443f5c7e8c0feed80a709bbe3de210 --- /dev/null +++ b/src/main/kotlin/de/thk/gm/remotecontrol/models/Game.kt @@ -0,0 +1,12 @@ +package de.thk.gm.remotecontrol.models + +import jakarta.persistence.Entity +import jakarta.persistence.Id +import java.util.* + + +@Entity +class Game { + @Id + var id: UUID = UUID.randomUUID() +} \ No newline at end of file diff --git a/src/main/kotlin/de/thk/gm/remotecontrol/repositories/GamesRepository.kt b/src/main/kotlin/de/thk/gm/remotecontrol/repositories/GamesRepository.kt new file mode 100644 index 0000000000000000000000000000000000000000..6d96525c148317421c9e0912b18f639bcbab3279 --- /dev/null +++ b/src/main/kotlin/de/thk/gm/remotecontrol/repositories/GamesRepository.kt @@ -0,0 +1,9 @@ +package de.thk.gm.remotecontrol.repositories + +import de.thk.gm.remotecontrol.models.Game +import org.springframework.data.repository.CrudRepository +import org.springframework.stereotype.Repository +import java.util.* + +@Repository +interface GamesRepository : CrudRepository<Game, UUID> \ No newline at end of file diff --git a/src/main/kotlin/de/thk/gm/remotecontrol/services/GamesService.kt b/src/main/kotlin/de/thk/gm/remotecontrol/services/GamesService.kt new file mode 100644 index 0000000000000000000000000000000000000000..0034e54cfa2650f908fdf2e45c37f7f5b72d5d21 --- /dev/null +++ b/src/main/kotlin/de/thk/gm/remotecontrol/services/GamesService.kt @@ -0,0 +1,8 @@ +package de.thk.gm.remotecontrol.services + +import de.thk.gm.remotecontrol.models.Game + +interface GamesService { + fun getAllGames() : List<Game> + fun saveGame(game: Game) +} \ No newline at end of file diff --git a/src/main/kotlin/de/thk/gm/remotecontrol/services/GamesServiceImpl.kt b/src/main/kotlin/de/thk/gm/remotecontrol/services/GamesServiceImpl.kt new file mode 100644 index 0000000000000000000000000000000000000000..cd71a9099e2f3a2c88a19aa3e68dd1261ea082f5 --- /dev/null +++ b/src/main/kotlin/de/thk/gm/remotecontrol/services/GamesServiceImpl.kt @@ -0,0 +1,16 @@ +package de.thk.gm.remotecontrol.services + +import de.thk.gm.remotecontrol.models.Game +import de.thk.gm.remotecontrol.repositories.GamesRepository +import org.springframework.stereotype.Service + +@Service +class GamesServiceImpl (private val gamesRepository: GamesRepository) : GamesService { + override fun getAllGames(): List<Game> { + return gamesRepository.findAll().toList() + } + + override fun saveGame(game: Game) { + gamesRepository.save(game) + } +} \ No newline at end of file diff --git a/src/main/resources/templates/controller.ftlh b/src/main/resources/templates/controller.ftlh index eb8d9ed1143429de2bcf1dde247cca29042f3ff0..29caaf684b9f89358e7333ecf2aac3fbd5f3c119 100644 --- a/src/main/resources/templates/controller.ftlh +++ b/src/main/resources/templates/controller.ftlh @@ -8,9 +8,15 @@ <title>Controller</title> </head> <body> - + <button onclick="sendBackgroundColor('red')" type="button">Red</button> + <button onclick="sendBackgroundColor('blue')" type="button">Blue</button> + <button onclick="sendBackgroundColor('yellow')" type="button">Yellow</button> + <button onclick="sendBackgroundColor('green')" type="button">Green</button> </body> <script> - + function sendBackgroundColor(color){ + ws.send(color) + } + var ws = new WebSocket("/game?id=${id}&side=controller") </script> </html> \ No newline at end of file diff --git a/src/main/resources/templates/colorgame.ftlh b/src/main/resources/templates/game.ftlh similarity index 54% rename from src/main/resources/templates/colorgame.ftlh rename to src/main/resources/templates/game.ftlh index 0a0afcb41f4196147b782b05656896e0eb0a3aaa..420bc53e76461b4da308dac5df1a257f7a06ddad 100644 --- a/src/main/resources/templates/colorgame.ftlh +++ b/src/main/resources/templates/game.ftlh @@ -8,13 +8,18 @@ <title>Color Game</title> </head> <body> - + <a href="/controller/${id}" id="linkToController" target="_blank">Link to Controller: <b>/controller/${id}</b></a><br> + <a href="/">Back</a> </body> <script> function setBackgroundColor(color){ - document.getElementsByTagName("body")[0].setAttribute("style","background-color:" + color) + document.body.style.background = color; + } + + var ws = new WebSocket("/game?id=${id}&side=game") + ws.onmessage = function(msg){ + setBackgroundColor(msg.data) } - var ws = new WebSocket("/game") </script> </html> \ No newline at end of file diff --git a/src/main/resources/templates/index.ftlh b/src/main/resources/templates/index.ftlh index bf8ece8e22d2272d95e1fd587adc90fb16fd8be1..5cf043afdbcf1cdae95bbd5bda0b0cfa27989ca0 100644 --- a/src/main/resources/templates/index.ftlh +++ b/src/main/resources/templates/index.ftlh @@ -8,6 +8,14 @@ <title>Document</title> </head> <body> - <a href="/colorgame">Start game</a> + <ul> + <#list games as game> + <li><a href="/games/${game.id}">${game.id}</a></li> + </#list> + </ul> + <form action="/games" method="post"> + <button>Create game</button> + </form> + </body> </html> \ No newline at end of file