From df675a5f08072f33aea25d44569618a57adb741c Mon Sep 17 00:00:00 2001 From: LQ63 Date: Sun, 12 Apr 2026 18:50:47 +0200 Subject: [PATCH] feat(server): Http4s server Changed at how the run command starts TUI GUI and the server. This is neccessary so that TUI GUI and server start and the game from the TUI/GUI is registered in the server. --- build.gradle.kts | 4 +++ .../de/nowchess/server/ServerLauncher.scala | 25 +++++++++++++++++++ modules/ui/build.gradle.kts | 1 + .../src/main/scala/de/nowchess/ui/Main.scala | 7 +++--- 4 files changed, 34 insertions(+), 3 deletions(-) create mode 100644 modules/server/src/main/scala/de/nowchess/server/ServerLauncher.scala diff --git a/build.gradle.kts b/build.gradle.kts index 188e836..d84cd13 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -40,3 +40,7 @@ val versions = mapOf( ) extra["VERSIONS"] = versions +tasks.register("run") { + dependsOn(":modules:ui:run") +} + diff --git a/modules/server/src/main/scala/de/nowchess/server/ServerLauncher.scala b/modules/server/src/main/scala/de/nowchess/server/ServerLauncher.scala new file mode 100644 index 0000000..60e612b --- /dev/null +++ b/modules/server/src/main/scala/de/nowchess/server/ServerLauncher.scala @@ -0,0 +1,25 @@ +package de.nowchess.server + +import cats.effect.IO +import cats.effect.unsafe.implicits.global +import com.comcast.ip4s.{host, port} +import de.nowchess.api.player.{PlayerId, PlayerInfo} +import de.nowchess.chess.engine.GameEngine +import org.http4s.ember.server.EmberServerBuilder + +object ServerLauncher: + def start(engine: GameEngine): String = + val white = PlayerInfo(PlayerId("white"), "Player 1") + val black = PlayerInfo(PlayerId("black"), "Player 2") + (for + registry <- GameRegistry.make + _ <- EmberServerBuilder + .default[IO] + .withHost(host"0.0.0.0") + .withPort(port"8080") + .withHttpApp(BoardRoutes(registry).routes.orNotFound) + .build + .useForever + .start + gameId <- registry.add(GameEntry(engine, white, black)) + yield gameId).unsafeRunSync() diff --git a/modules/ui/build.gradle.kts b/modules/ui/build.gradle.kts index 71e3a5f..a6729bd 100644 --- a/modules/ui/build.gradle.kts +++ b/modules/ui/build.gradle.kts @@ -64,6 +64,7 @@ dependencies { implementation(project(":modules:rule")) implementation(project(":modules:api")) implementation(project(":modules:io")) + implementation(project(":modules:server")) // ScalaFX dependencies implementation("org.scalafx:scalafx_3:${versions["SCALAFX"]!!}") diff --git a/modules/ui/src/main/scala/de/nowchess/ui/Main.scala b/modules/ui/src/main/scala/de/nowchess/ui/Main.scala index 4313506..3f70777 100644 --- a/modules/ui/src/main/scala/de/nowchess/ui/Main.scala +++ b/modules/ui/src/main/scala/de/nowchess/ui/Main.scala @@ -1,21 +1,22 @@ package de.nowchess.ui import de.nowchess.chess.engine.GameEngine +import de.nowchess.server.ServerLauncher import de.nowchess.ui.terminal.TerminalUI import de.nowchess.ui.gui.ChessGUILauncher /** Application entry point - starts both GUI and Terminal UI for the chess game. * Both views subscribe to the same GameEngine via Observer pattern. + * The REST server shares the same engine instance, so API moves are reflected in the UI. */ object Main: def main(args: Array[String]): Unit = - // Create the core game engine (single source of truth) val engine = new GameEngine() + val gameId = ServerLauncher.start(engine) + println(s"REST API ready — game ID: $gameId → http://localhost:8080/api/board/game/$gameId") - // Launch ScalaFX GUI in separate thread ChessGUILauncher.launch(engine) - // Create and start the terminal UI (blocks on main thread) val tui = new TerminalUI(engine) tui.start()