fix: enable official bots to connect to external tournament server (#71)
Build & Test (NowChessSystems) TeamCity build finished
Build & Test (NowChessSystems) TeamCity build finished
Two bugs prevented official bots from joining the external tournament-server: 1. JWT claim mismatch — bot tokens lacked the `isBot: true` claim the tournament server requires. Added the claim to generateBotToken() in AccountService, which covers both user-owned bots and official bots. 2. Broken join flow — TournamentBotGamePlayer.joinTournament() called registerBot() which hit POST /api/auth/register on the tournament server, an endpoint that does not exist. Removed registerBot() and updated JoinTournamentRequest to accept a botToken field so the caller supplies the pre-existing NowChessSystems token directly. --------- Co-authored-by: LQ63 <lkhermann@web.de> Reviewed-on: #71 Co-authored-by: Leon Hermann <lq@blackhole.local> Co-committed-by: Leon Hermann <lq@blackhole.local>
This commit was merged in pull request #71.
This commit is contained in:
+1
@@ -2,6 +2,7 @@ package de.nowchess.bot.resource
|
||||
|
||||
case class JoinTournamentRequest(
|
||||
tournamentId: String,
|
||||
botToken: String,
|
||||
difficulty: String,
|
||||
serverUrl: Option[String],
|
||||
)
|
||||
|
||||
+1
-1
@@ -33,7 +33,7 @@ class TournamentJoinResource:
|
||||
difficulty,
|
||||
serverUrl,
|
||||
)
|
||||
player.joinTournament(req.tournamentId, difficulty, serverUrl) match
|
||||
player.joinTournament(req.tournamentId, req.botToken, difficulty, serverUrl) match
|
||||
case Right(botId) =>
|
||||
val resp = JoinTournamentResponse(botId, difficulty, "joining")
|
||||
Response.ok(resp).build()
|
||||
|
||||
+10
-25
@@ -50,11 +50,16 @@ class TournamentBotGamePlayer:
|
||||
log.infof("Tournament bot enabled — server=%s tournament=%s bot=%s", cfg.serverUrl, cfg.tournamentId, cfg.botId)
|
||||
startAsync(cfg)
|
||||
|
||||
def joinTournament(tournamentId: String, difficulty: String, serverUrl: String): Either[String, String] =
|
||||
registerBot(serverUrl, difficulty) match
|
||||
case None => Left("Failed to register bot with tournament server")
|
||||
case Some((botId, token)) =>
|
||||
val cfg = TournamentBotConfig(serverUrl, tournamentId, token, botId, difficulty)
|
||||
def joinTournament(
|
||||
tournamentId: String,
|
||||
botToken: String,
|
||||
difficulty: String,
|
||||
serverUrl: String,
|
||||
): Either[String, String] =
|
||||
TournamentBotConfig.jwtSubject(botToken) match
|
||||
case None => Left("Invalid bot token — could not extract subject")
|
||||
case Some(botId) =>
|
||||
val cfg = TournamentBotConfig(serverUrl, tournamentId, botToken, botId, difficulty)
|
||||
if join(cfg) then
|
||||
startAsync(cfg)
|
||||
Right(botId)
|
||||
@@ -65,26 +70,6 @@ class TournamentBotGamePlayer:
|
||||
thread.setDaemon(true)
|
||||
thread.start()
|
||||
|
||||
private def registerBot(serverUrl: String, difficulty: String): Option[(String, String)] =
|
||||
Try {
|
||||
val name = s"NowChess ${difficulty.capitalize}"
|
||||
val body = s"""{"name":"$name","isBot":true}"""
|
||||
val response = client
|
||||
.target(serverUrl)
|
||||
.path("api")
|
||||
.path("auth")
|
||||
.path("register")
|
||||
.request(MediaType.APPLICATION_JSON)
|
||||
.post(Entity.entity(body, MediaType.APPLICATION_JSON))
|
||||
if response.getStatus == 201 then
|
||||
val node = objectMapper.readTree(response.readEntity(classOf[String]))
|
||||
val id = node.path("id").asText()
|
||||
val token = node.path("token").asText()
|
||||
response.close()
|
||||
if id.nonEmpty && token.nonEmpty then Some((id, token)) else None
|
||||
else { log.warnf("Bot registration returned status %d", response.getStatus); response.close(); None }
|
||||
}.getOrElse(None)
|
||||
|
||||
@PreDestroy
|
||||
def cleanup(): Unit =
|
||||
running = false
|
||||
|
||||
Reference in New Issue
Block a user