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:
@@ -239,6 +239,7 @@ class AccountService:
|
|||||||
.subject(botId.toString)
|
.subject(botId.toString)
|
||||||
.expiresAt(Long.MaxValue)
|
.expiresAt(Long.MaxValue)
|
||||||
.claim("type", "bot")
|
.claim("type", "bot")
|
||||||
|
.claim("isBot", true)
|
||||||
.claim("name", botName)
|
.claim("name", botName)
|
||||||
.sign()
|
.sign()
|
||||||
|
|
||||||
|
|||||||
+1
@@ -2,6 +2,7 @@ package de.nowchess.bot.resource
|
|||||||
|
|
||||||
case class JoinTournamentRequest(
|
case class JoinTournamentRequest(
|
||||||
tournamentId: String,
|
tournamentId: String,
|
||||||
|
botToken: String,
|
||||||
difficulty: String,
|
difficulty: String,
|
||||||
serverUrl: Option[String],
|
serverUrl: Option[String],
|
||||||
)
|
)
|
||||||
|
|||||||
+1
-1
@@ -33,7 +33,7 @@ class TournamentJoinResource:
|
|||||||
difficulty,
|
difficulty,
|
||||||
serverUrl,
|
serverUrl,
|
||||||
)
|
)
|
||||||
player.joinTournament(req.tournamentId, difficulty, serverUrl) match
|
player.joinTournament(req.tournamentId, req.botToken, difficulty, serverUrl) match
|
||||||
case Right(botId) =>
|
case Right(botId) =>
|
||||||
val resp = JoinTournamentResponse(botId, difficulty, "joining")
|
val resp = JoinTournamentResponse(botId, difficulty, "joining")
|
||||||
Response.ok(resp).build()
|
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)
|
log.infof("Tournament bot enabled — server=%s tournament=%s bot=%s", cfg.serverUrl, cfg.tournamentId, cfg.botId)
|
||||||
startAsync(cfg)
|
startAsync(cfg)
|
||||||
|
|
||||||
def joinTournament(tournamentId: String, difficulty: String, serverUrl: String): Either[String, String] =
|
def joinTournament(
|
||||||
registerBot(serverUrl, difficulty) match
|
tournamentId: String,
|
||||||
case None => Left("Failed to register bot with tournament server")
|
botToken: String,
|
||||||
case Some((botId, token)) =>
|
difficulty: String,
|
||||||
val cfg = TournamentBotConfig(serverUrl, tournamentId, token, botId, difficulty)
|
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
|
if join(cfg) then
|
||||||
startAsync(cfg)
|
startAsync(cfg)
|
||||||
Right(botId)
|
Right(botId)
|
||||||
@@ -65,26 +70,6 @@ class TournamentBotGamePlayer:
|
|||||||
thread.setDaemon(true)
|
thread.setDaemon(true)
|
||||||
thread.start()
|
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
|
@PreDestroy
|
||||||
def cleanup(): Unit =
|
def cleanup(): Unit =
|
||||||
running = false
|
running = false
|
||||||
|
|||||||
Reference in New Issue
Block a user