From 4c7c19bb997ebe37cc79bf6b49f71ccd5002a70e Mon Sep 17 00:00:00 2001 From: Yoseph Date: Mon, 11 May 2026 05:24:23 +0700 Subject: [PATCH] Prepare clients for localized lobby notices The server change introduces optional notice localization metadata while preserving legacy text. This updates the shared lobby contract first so downstream clients can adopt the fields without raw JSON handling. Constraint: FAF server PR 1083 adds optional notice localization fields while keeping legacy text for existing clients. Rejected: Client-only parsing workaround | shared lobby API should model the server contract first. Confidence: high Scope-risk: narrow Directive: Keep the two-argument NoticeInfo constructor available for Java callers until client consumers migrate. Tested: JAVA_HOME=/Users/yoseph/Codexperiment/.deps/jdk21/Contents/Home ./gradlew :lobby:test --tests com.faforever.commons.lobby.ServerMessageTest Tested: git diff --check Not-tested: Full Gradle suite. Co-authored-by: OmX --- .../faforever/commons/lobby/ConnectionApi.kt | 10 +++++-- .../commons/lobby/ServerMessageTest.kt | 27 +++++++++++++++++++ 2 files changed, 35 insertions(+), 2 deletions(-) diff --git a/lobby/src/main/kotlin/com/faforever/commons/lobby/ConnectionApi.kt b/lobby/src/main/kotlin/com/faforever/commons/lobby/ConnectionApi.kt index b35627a8..b63dd83e 100644 --- a/lobby/src/main/kotlin/com/faforever/commons/lobby/ConnectionApi.kt +++ b/lobby/src/main/kotlin/com/faforever/commons/lobby/ConnectionApi.kt @@ -6,6 +6,7 @@ import com.fasterxml.jackson.annotation.JsonProperty import com.fasterxml.jackson.annotation.JsonValue import reactor.core.publisher.Flux import reactor.core.publisher.Mono +import java.time.OffsetDateTime /** * API to manage connection to the Lobby server @@ -49,9 +50,15 @@ internal class InvalidResponse : ServerMessage * A general message from the server (automated or broadcast from admin) to display to the user. * FIXME: Should maybe offer event codes for translations in case of automated responses. */ -data class NoticeInfo( +data class NoticeInfo @JvmOverloads constructor( val style: String?, val text: String?, + @JsonProperty("i18n_key") + val i18nKey: String? = null, + @JsonProperty("i18n_args") + val i18nArgs: List = emptyList(), + @JsonProperty("expires_at") + val expiresAt: OffsetDateTime? = null, ) : ServerMessage /** @@ -210,4 +217,3 @@ internal class ClientPingMessage : ClientMessage * Holds no data, just checks if the connection is still alive */ internal class ClientPongMessage : ClientMessage - diff --git a/lobby/src/test/kotlin/com/faforever/commons/lobby/ServerMessageTest.kt b/lobby/src/test/kotlin/com/faforever/commons/lobby/ServerMessageTest.kt index 508f713f..c16824df 100644 --- a/lobby/src/test/kotlin/com/faforever/commons/lobby/ServerMessageTest.kt +++ b/lobby/src/test/kotlin/com/faforever/commons/lobby/ServerMessageTest.kt @@ -101,6 +101,33 @@ class ServerMessageTest { assertEquals(NoticeInfo("kill", "boo"), result) } + @Test + fun deserializeLocalizableNoticeInfo() { + val result = objectMapper.readValue( + """ + { + "command": "notice", + "style": "error", + "text": "You are banned from FAF until 2026-05-10T22:00:00+00:00. Reason: test", + "i18n_key": "login.error.banned", + "i18n_args": ["2026-05-10T22:00:00+00:00", "test"], + "expires_at": "2026-05-10T22:00:00+00:00" + } + """.trimIndent() + ) + + assertEquals( + NoticeInfo( + "error", + "You are banned from FAF until 2026-05-10T22:00:00+00:00. Reason: test", + "login.error.banned", + listOf("2026-05-10T22:00:00+00:00", "test"), + OffsetDateTime.parse("2026-05-10T22:00:00+00:00") + ), + result + ) + } + @Test fun deserializeGameJoinFailed() { val result = objectMapper.readValue(