proto-socket/agent-task/archive/2026/05/kotlin_wss_tls/plan_0.log

280 lines
11 KiB
Text

<!-- task=kotlin_wss_tls plan=0 tag=KOTLIN_WSS_TLS -->
# Kotlin WsServer TLS(WSS) 지원 추가
## 이 파일을 읽는 구현 에이전트에게
각 항목의 체크리스트를 완료 표시하고, 중간 검증 명령을 실행한 뒤 출력을 CODE_REVIEW.md `검증 결과` 섹션에 붙여 넣는다. 최종 검증까지 완료 후 CODE_REVIEW.md 각 항목을 `[x]`로 체크한다.
## 배경
Kotlin `WsServer`는 `org.java_websocket:Java-WebSocket:1.5.6` 라이브러리의 `WebSocketServer`를 상속한다. 동일 라이브러리에는 `DefaultSSLWebSocketServerFactory`가 포함되어 있으며 `WebSocketServer.setWebSocketFactory()` 호출만으로 TLS를 활성화할 수 있다. 이번 작업으로 WsServer에 `sslContext` 파라미터를 추가하고 WSS 단위 테스트를 추가한다. 또한 이 작업이 완료되면 `tls_crosstest` PLAN.md의 TLS_CROSSTEST-8 항목을 WSS phase 포함 4 phase로 확장한다.
**기준 파일:**
- 구현: `kotlin/src/main/kotlin/com/tokilabs/toki_socket/WsServer.kt`
- 테스트 참조: `kotlin/src/test/kotlin/com/tokilabs/toki_socket/TlsTcpTest.kt`, `WsTest.kt`
- 인증서: `kotlin/src/test/resources/server.crt` + `server.key`
---
## [KOTLIN_WSS_TLS-1] WsServer.kt — sslContext 파라미터 추가 및 TLS 활성화
### 문제
`kotlin/src/main/kotlin/com/tokilabs/toki_socket/WsServer.kt` line 14-20 의 `WsServer` 생성자에 `sslContext` 파라미터가 없어 WSS 서버를 생성할 방법이 없다. `TcpServer`는 line 20에 `sslContext: SSLContext? = null`을 이미 지원하지만 `WsServer`는 누락됐다.
### 해결 방법
1. `import org.java_websocket.server.DefaultSSLWebSocketServerFactory` 추가
2. `import javax.net.ssl.SSLContext` 추가
3. 생성자에 `private val sslContext: SSLContext? = null` 파라미터를 **`newClient` 앞**에 추가 (trailing lambda 호환 유지)
4. `start()` 에서 `super.start()` 호출 전 TLS factory 등록 추가
**Before** (`WsServer.kt` line 6-8 imports 이후, line 14-20):
```kotlin
class WsServer(
host: String,
port: Int,
private val path: String = "/",
private val newClient: (WebSocket) -> WsClient,
) : WebSocketServer(InetSocketAddress(host, port)) {
```
**After:**
```kotlin
class WsServer(
host: String,
port: Int,
private val path: String = "/",
private val sslContext: SSLContext? = null,
private val newClient: (WebSocket) -> WsClient,
) : WebSocketServer(InetSocketAddress(host, port)) {
```
**Before** (`WsServer.kt` line 30-33):
```kotlin
override fun start() {
startedFlag.set(true)
super.start()
}
```
**After:**
```kotlin
override fun start() {
startedFlag.set(true)
if (sslContext != null) {
setWebSocketFactory(DefaultSSLWebSocketServerFactory(sslContext))
}
super.start()
}
```
기존 호출부 (`WsTest.kt`, crosstest 파일)는 모두 trailing lambda 형식 `WsServer(host, port, path) { conn -> ... }` 을 사용하므로 파라미터 추가 후에도 재컴파일 없이 호환된다.
### 수정 파일 및 체크리스트
- `kotlin/src/main/kotlin/com/tokilabs/toki_socket/WsServer.kt`
- [x] `import org.java_websocket.server.DefaultSSLWebSocketServerFactory` 추가
- [x] `import javax.net.ssl.SSLContext` 추가
- [x] `private val sslContext: SSLContext? = null` 파라미터를 `newClient` 앞에 추가
- [x] `start()` 에 `if (sslContext != null) { setWebSocketFactory(...) }` 블록 추가
### 테스트 작성
[KOTLIN_WSS_TLS-2] 항목에서 별도 신규 파일로 작성.
### 중간 검증
```
$ cd kotlin && env JAVA_HOME=/config/opt/jdk/jdk-17.0.10+7 GRADLE_USER_HOME=/tmp/gradle \
./gradlew compileKotlin
BUILD SUCCESSFUL
```
---
## [KOTLIN_WSS_TLS-2] TlsWsTest.kt — WSS 단위 테스트 추가
### 문제
`WsServer` TLS path에 대한 테스트가 없다. `TlsTcpTest.kt`에는 TCP TLS 2개 테스트가 있지만 WS에 해당하는 파일이 없다.
### 해결 방법
`kotlin/src/test/kotlin/com/tokilabs/toki_socket/TlsWsTest.kt` 신규 파일 작성. `TlsTcpTest.kt`의 인증서 로딩 헬퍼(`createTlsContexts()`)를 동일하게 사용한다.
**구현할 테스트:**
```kotlin
package com.tokilabs.toki_socket
import com.tokilabs.toki_socket.packets.TestData
import kotlinx.coroutines.CompletableDeferred
import kotlinx.coroutines.runBlocking
import java.nio.file.Paths
import kotlin.test.Test
import kotlin.test.assertEquals
class TlsWsTest {
@Test
fun testWssSendReceive() = runBlocking {
val (serverContext, clientContext) = createTlsContexts()
val port = freePort()
val received = CompletableDeferred<TestData>()
val listenerReady = CompletableDeferred<Unit>()
val server = WsServer("127.0.0.1", port, "/", sslContext = serverContext) { conn ->
WsClient.forServer(conn, 0, 0, testParserMap())
}
server.onClientConnected = { client ->
addListenerTyped<TestData>(client.communicator) { received.complete(it) }
listenerReady.complete(Unit)
}
server.start()
val client = dialWss("127.0.0.1", port, "/", clientContext, 0, 0, testParserMap())
listenerReady.await()
client.send(TestData.newBuilder().setIndex(55).setMessage("hello wss").build())
assertEquals(55, received.await().index)
client.close()
server.stop()
}
@Test
fun testWssRequestResponse() = runBlocking {
val (serverContext, clientContext) = createTlsContexts()
val port = freePort()
val server = WsServer("127.0.0.1", port, "/", sslContext = serverContext) { conn ->
WsClient.forServer(conn, 0, 0, testParserMap())
}
server.onClientConnected = { client ->
addRequestListenerTyped<TestData, TestData>(client.communicator) { req ->
TestData.newBuilder()
.setIndex(req.index * 2)
.setMessage("wss echo: ${req.message}")
.build()
}
}
server.start()
val client = dialWss("127.0.0.1", port, "/", clientContext, 0, 0, testParserMap())
val res = sendRequestTyped<TestData, TestData>(
client.communicator,
TestData.newBuilder().setIndex(11).setMessage("wss req").build(),
timeoutMs = 2_000,
)
assertEquals(22, res.index)
assertEquals("wss echo: wss req", res.message)
client.close()
server.stop()
}
private fun createTlsContexts(): Pair<javax.net.ssl.SSLContext, javax.net.ssl.SSLContext> {
val loader = Thread.currentThread().contextClassLoader
val certPath = Paths.get(loader.getResource("server.crt")!!.toURI()).toString()
val keyPath = Paths.get(loader.getResource("server.key")!!.toURI()).toString()
return createTestSslContexts(certPath, keyPath)
}
}
```
`freePort()`, `testParserMap()`, `addListenerTyped`, `addRequestListenerTyped`, `sendRequestTyped`, `createTestSslContexts` 는 기존 `TestHelpers.kt` 및 `Communicator.kt` 에서 제공하므로 별도 import만 추가한다.
### 수정 파일 및 체크리스트
- `kotlin/src/test/kotlin/com/tokilabs/toki_socket/TlsWsTest.kt` (신규)
- [x] `testWssSendReceive()` — WsServer(sslContext) → dialWss(clientContext) send/receive 검증
- [x] `testWssRequestResponse()` — request/response index 2배, 메시지 검증
- [x] `createTlsContexts()` 헬퍼 (TlsTcpTest.kt 와 동일 구조)
### 테스트 작성
본 항목 자체가 테스트 추가.
### 중간 검증
```
$ cd kotlin && env JAVA_HOME=/config/opt/jdk/jdk-17.0.10+7 GRADLE_USER_HOME=/tmp/gradle \
./gradlew test --tests "*.TlsWsTest"
BUILD SUCCESSFUL
2 tests completed
```
---
## [KOTLIN_WSS_TLS-3] tls_crosstest PLAN.md — Kotlin WSS phase 추가
### 문제
`agent-task/tls_crosstest/PLAN.md` 의 배경 섹션이 "Kotlin WsServer는 TLS를 지원하지 않으므로 Kotlin 서버 조합은 TLS TCP 1개 phase만 추가한다"로 제한되어 있고, 포트 배정표의 kotlin_* 행에 WSS 포트가 없으며, TLS_CROSSTEST-8 항목이 2 phase(send-push, requests)만 기술하고 있다.
이번 작업으로 WSS가 가능해졌으므로 4 phase(TLS TCP send-push, TLS TCP requests, WSS send-push, WSS requests)로 확장한다.
### 해결 방법
`agent-task/tls_crosstest/PLAN.md` 수정:
1. **배경 섹션**: "Kotlin WsServer는 TLS를 지원하지 않으므로 Kotlin 서버 조합은 TLS TCP 1개 phase만 추가한다" 문장 삭제
2. **포트 배정표** — kotlin_* 행 WSS 포트 추가:
| orchestrator | TCP | WS | TLS TCP | WSS |
|---|---|---|---|---|
| kotlin_dart | 29490 | 29492 | **29494** | **29496** |
| kotlin_go | 29390 | 29392 | **29394** | **29396** |
| kotlin_python | 29394 | 29396 | **29398** | **29400** |
| kotlin_typescript | 29794 | 29796 | **29798** | **29800** |
(각 파일 내에서 기존 TCP/WS 포트와 겹치지 않음. 다른 orchestrator 파일과의 포트 중복은 허용.)
3. **TLS_CROSSTEST-8 항목**: "TLS TCP phase 1개만" 제약 삭제 → WSS phase 2개(WsServer 생성 시 `sslContext = serverCtx` 전달, 클라이언트 `--mode=wss` 호출) 추가
4. **CODE_REVIEW.md TLS_CROSSTEST-8 설명**: "TLS TCP phase 추가" → "TLS TCP + WSS phase 추가"로 갱신
5. **CODE_REVIEW.md 리뷰어 체크포인트**: "Kotlin WsServer TLS 미지원" 항목 삭제
### 수정 파일 및 체크리스트
- `agent-task/tls_crosstest/PLAN.md`
- [x] 배경 섹션 Kotlin WsServer TLS 미지원 제약 문구 삭제
- [x] 포트 배정표 kotlin_dart WSS 29496, kotlin_go WSS 29396, kotlin_python WSS 29400, kotlin_typescript WSS 29800 추가
- [x] TLS_CROSSTEST-8 항목 포트 상수, WsServer WSS server 생성, `runWssSendPush` / `runWssRequests` 함수, main 호출 추가 기술
- `agent-task/tls_crosstest/CODE_REVIEW.md`
- [x] TLS_CROSSTEST-8 행 설명 "TLS TCP + WSS phase 추가"로 갱신
- [x] 리뷰어 체크포인트 "Kotlin WsServer TLS 미지원" 항목 삭제
### 테스트 작성
스킵 — 문서 수정.
### 중간 검증
없음.
---
## 수정 파일 요약
| 파일 | 항목 |
|------|------|
| `kotlin/src/main/kotlin/com/tokilabs/toki_socket/WsServer.kt` | KOTLIN_WSS_TLS-1 |
| `kotlin/src/test/kotlin/com/tokilabs/toki_socket/TlsWsTest.kt` (신규) | KOTLIN_WSS_TLS-2 |
| `agent-task/tls_crosstest/PLAN.md` | KOTLIN_WSS_TLS-3 |
| `agent-task/tls_crosstest/CODE_REVIEW.md` | KOTLIN_WSS_TLS-3 |
## 의존 관계 및 구현 순서
**1단계**: KOTLIN_WSS_TLS-1 (WsServer.kt)
**2단계**: KOTLIN_WSS_TLS-2 (TlsWsTest.kt) — WsServer.kt 변경 후
**3단계**: KOTLIN_WSS_TLS-3 (tls_crosstest 문서) — 병렬 가능
## 최종 검증
```
$ cd kotlin && env JAVA_HOME=/config/opt/jdk/jdk-17.0.10+7 GRADLE_USER_HOME=/tmp/gradle \
./gradlew test
BUILD SUCCESSFUL
X tests completed
(기존 테스트 포함 전체 PASS, TlsWsTest 2개 포함)
```