This commit is contained in:
@@ -117,6 +117,16 @@ class GameRedisSubscriberManager:
|
||||
log.debugf("Subscribed to game %s", gameId)
|
||||
catch case ex: Exception => log.warnf(ex, "Redis subscription failed for game %s", gameId)
|
||||
|
||||
// Notify the official-bots service to start playing a side of a game. Mirrors
|
||||
// the event the tournament service publishes; official-bots subscribes to
|
||||
// "<prefix>:bot:*:events".
|
||||
def publishBotGameStart(gameId: String, botId: String, playingAs: String): Unit =
|
||||
val channel = s"${redisConfig.prefix}:bot:$botId:events"
|
||||
val payload = s"""{"type":"gameStart","gameId":"$gameId","playingAs":"$playingAs","botAccountId":"$botId"}"""
|
||||
Try(redis.pubsub(classOf[String]).publish(channel, payload)) match
|
||||
case scala.util.Failure(ex) => log.warnf(ex, "Failed to publish bot gameStart for game %s", gameId)
|
||||
case scala.util.Success(_) => ()
|
||||
|
||||
def unsubscribeGame(gameId: String): Unit =
|
||||
Option(c2sListeners.remove(gameId)).foreach { subscriber =>
|
||||
subscriber.unsubscribe(c2sTopic(gameId)).subscribe().`with`(_ => (), _ => ())
|
||||
|
||||
@@ -25,6 +25,7 @@ import de.nowchess.chess.observer.*
|
||||
import de.nowchess.chess.redis.GameRedisSubscriberManager
|
||||
import de.nowchess.chess.registry.{GameEntry, GameRegistry}
|
||||
import de.nowchess.security.InternalOnly
|
||||
import jakarta.annotation.security.PermitAll
|
||||
import jakarta.enterprise.context.ApplicationScoped
|
||||
import jakarta.inject.Inject
|
||||
import jakarta.ws.rs.*
|
||||
@@ -179,6 +180,32 @@ class GameResource:
|
||||
)
|
||||
created(GameDtoMapper.toGameFullDto(entry, ioClient))
|
||||
|
||||
// Player-facing game creation for "play vs bot". Unlike createGame this is not
|
||||
// internal-only: a logged-in (or anonymous) player creates the game directly,
|
||||
// and core notifies the official-bots service to play the bot side.
|
||||
@POST
|
||||
@Path("/vs-bot")
|
||||
@PermitAll
|
||||
@Consumes(Array(MediaType.APPLICATION_JSON))
|
||||
@Produces(Array(MediaType.APPLICATION_JSON))
|
||||
def createBotGame(body: CreateGameRequestDto): Response =
|
||||
val req = Option(body).getOrElse(CreateGameRequestDto(None, None, None, None))
|
||||
val white = playerInfoFrom(req.white, DefaultWhite)
|
||||
val black = playerInfoFrom(req.black, DefaultBlack)
|
||||
val tc = toTimeControl(req.timeControl)
|
||||
val entry = newEntry(GameContext.initial, white, black, tc, GameMode.Open)
|
||||
registry.store(entry)
|
||||
subscriberManager.subscribeGame(entry.gameId)
|
||||
notifyBotSide(entry)
|
||||
log.infof("Bot game %s created — white=%s black=%s", entry.gameId, white.displayName, black.displayName)
|
||||
created(GameDtoMapper.toGameFullDto(entry, ioClient))
|
||||
|
||||
private def notifyBotSide(entry: GameEntry): Unit =
|
||||
if entry.black.id.value.startsWith("bot-") then
|
||||
subscriberManager.publishBotGameStart(entry.gameId, entry.black.id.value, "black")
|
||||
else if entry.white.id.value.startsWith("bot-") then
|
||||
subscriberManager.publishBotGameStart(entry.gameId, entry.white.id.value, "white")
|
||||
|
||||
@GET
|
||||
@Path("/{gameId}")
|
||||
@Produces(Array(MediaType.APPLICATION_JSON))
|
||||
|
||||
Reference in New Issue
Block a user