diff --git a/PORTING_GUIDE.md b/PORTING_GUIDE.md index f9119ac..775be6e 100644 --- a/PORTING_GUIDE.md +++ b/PORTING_GUIDE.md @@ -133,29 +133,28 @@ --- -## Rust +## TypeScript ### 핵심 매핑 -| Go | Rust | -|----|------| -| `Transport` interface | `trait Transport` | -| `baseClient[Self]` | `struct BaseClient` + generic bounds | -| goroutine | `tokio::spawn` | -| `context.Context` + cancel | `tokio::select!` + `CancellationToken` (tokio-util) | -| channel (writeQueue) | `mpsc::channel(64)` (tokio) | -| `sync.Once` | `Once` (std) 또는 `OnceLock` | -| `atomic.Bool` | `AtomicBool` (std::sync::atomic) | -| `sync.RWMutex` | `RwLock` (tokio 또는 std) | +| Go | TypeScript | +|----|------------| +| `Transport` interface | `interface Transport` | +| `baseClient[Self]` | `abstract class BaseClient` | +| goroutine | `Promise` + `async/await` | +| `context.Context` | `AbortSignal` (`AbortController`) | +| channel (writeQueue) | Async Queue (배열 기반 큐 또는 async iterator) | +| `sync.Once` | `boolean` 플래그 (단일 스레드이므로 충분) | +| `atomic.Bool` | `boolean` | ### 주의사항 -- **소유권 모델**: `doClose` 클로저를 `Arc>`로 감싸지 않으면 소유권 문제가 발생한다. Go의 `self Self` 필드는 Rust에서 `Arc` 또는 `Weak`로 대응한다. Weak를 선호해서 순환 참조를 방지한다 -- **protobuf**: `prost` 크레이트 사용. typeName은 `prost::Message`의 descriptor에서 추출. PROTOCOL.md 표에서 Rust 행 확인 -- **async runtime**: tokio를 기준 런타임으로 한다. `async-std`는 혼용하지 않는다 -- **`connCloseOnce` 패턴**: `tokio::sync::OnceCell` 또는 `std::sync::Once`로 구현한다. `CancellationToken`을 함께 사용하면 readCtx/writeCtx 패턴을 자연스럽게 표현할 수 있다 -- **`Transport` trait**: `async fn`을 trait에서 사용하려면 `async-trait` 크레이트가 필요하다 (Rust 1.75 미만). 1.75 이상이면 `impl Future` 반환으로 대체 가능하다 -- **제네릭 헬퍼**: `AddListenerTyped`, `SendRequestTyped`는 Rust 제네릭으로 완전하게 구현 가능하다. trait bound를 `T: prost::Message + Default`로 잡으면 된다 +- **크로스 환경 (Browser & Node.js)**: 코어 로직(`Communicator`, `BaseClient`)은 런타임 환경에 독립적으로 작성한다. 브라우저에서는 내장 `WebSocket`을, Node.js에서는 `net.Socket`(TCP)이나 `ws` 패키지를 사용하는 Transport 구현체를 주입받도록 설계한다 +- **protobuf**: `@bufbuild/protobuf` (protobuf-es) 패키지 사용을 권장한다. `typeName`은 `MessageType.typeName`에서 추출한다. `PROTOCOL.md` 표에서 TypeScript 행을 확인한다 +- **단일 스레드 (Event Loop)**: JS/TS는 단일 스레드 기반이므로 메모리 동시 접근에 대한 Mutex/Lock(`sync.RWMutex`)은 불필요하다. 단, 비동기 컨텍스트(await) 간의 논리적 상태 오염은 주의한다 +- **바이너리 처리**: Node.js의 `Buffer` 대신 표준 웹 API인 `Uint8Array`를 기준으로 작성하여 브라우저 환경 호환성을 확보한다 +- **`connCloseOnce` 패턴**: 단순 `isClosed: boolean` 플래그로 멱등성을 보장한다. 만약 `Close()` 내에 `await`가 포함될 경우 중복 실행(re-entrancy) 방지에 유의한다 +- **제네릭 헬퍼**: TypeScript의 강력한 타입 시스템을 활용해 `addListener`, `sendRequest` 등을 완벽히 타입 안전한 API로 구현한다 --- diff --git a/PROTOCOL.md b/PROTOCOL.md index 7863f53..ffdbafa 100644 --- a/PROTOCOL.md +++ b/PROTOCOL.md @@ -113,8 +113,8 @@ On the receive side, use the same value as the registration key. | C# | `typeof(T).Name` — verify matches proto qualified name | | Kotlin | `descriptorForType.fullName` via `typeNameOf(m)` | | Swift | `String(describing: T.self)` — verify matches | +| TypeScript | `MessageType.typeName` (protobuf-es) — verify matches | | Python | `descriptor.name` from `MessageClass.DESCRIPTOR` — verify matches | -| Rust | `M::default().descriptor_dyn().name().to_string()` (protobuf crate) — verify matches | The current packet proto has no `package` declaration, so Dart, Go, and Kotlin all use simple names such as `TestData` and `HeartBeat`. If a future proto adds a `package`, `proto.MessageName` may become fully qualified, and all implementations must use the same value. @@ -177,11 +177,11 @@ Sending `HeartBeat {}`: |----------|--------|------| | Dart | Available | `dart/` | | C# (Unity) | Planned | `csharp/` | -| Kotlin | In progress | `kotlin/` | +| Kotlin | Available | `kotlin/` | | Swift | Planned | `swift/` | | Go | Available | `go/` | +| TypeScript | Planned | `typescript/` | | Python | Planned | `python/` | -| Rust | Planned | `rust/` | --- diff --git a/README.md b/README.md index ddd37b8..fc2ec8d 100644 --- a/README.md +++ b/README.md @@ -36,11 +36,11 @@ Protocol compatibility is tracked separately from language package versions. See |----------|--------|------|----------| | Dart | Available | [dart/](dart/) | Flutter, Dart server | | C# | Planned | `csharp/` | Unity, .NET | -| Kotlin | In progress | [kotlin/](kotlin/) | Android, JVM | +| Kotlin | Available | kotlin/ | Android, JVM | | Swift | Planned | `swift/` | iOS, macOS | | Go | Available | [go/](go/) | Server, tooling, scripting | +| TypeScript | Planned | `typescript/` | Browser, Node.js | | Python | Planned | `python/` | Server, tooling, scripting | -| Rust | Planned | `rust/` | High-performance server, embedded | New language implementations should start from [PORTING_GUIDE.md](PORTING_GUIDE.md) and the templates in [agent-ops/skills/project/add-toki-socket-crosstest-language/templates/](agent-ops/skills/project/add-toki-socket-crosstest-language/templates/). Mark an implementation available only after its same-language tests and cross-language tests pass. diff --git a/agent-ops/rules/project/domain/kotlin/rules.md b/agent-ops/rules/project/domain/kotlin/rules.md index 72b0f5a..1204330 100644 --- a/agent-ops/rules/project/domain/kotlin/rules.md +++ b/agent-ops/rules/project/domain/kotlin/rules.md @@ -2,7 +2,7 @@ ## 목적 / 책임 -Toki Socket의 Kotlin/Android 구현체를 담당한다. Android 및 JVM 환경을 대상으로 하며, 현재 구현 진행 중이다. +Toki Socket의 Kotlin/Android 구현체를 담당한다. Android 및 JVM 환경을 대상으로 한다. ## 포함 경로 @@ -16,13 +16,13 @@ Toki Socket의 Kotlin/Android 구현체를 담당한다. Android 및 JVM 환경 ## 주요 구성 요소 -- (구현 진행 중 — Dart/Go 구조 참고) +- `Transport`, `Communicator`, `BaseClient` 등 코어 로직 +- TCP / WebSocket 통신 클라이언트 ## 유지할 패턴 - `./gradlew test`로 테스트 실행 - `./gradlew run -PmainClass=...`으로 crosstest 실행 -- Available 표시 조건: 동일 언어 테스트 + 크로스 언어 테스트 통과 ## 다른 도메인과의 경계 @@ -32,4 +32,3 @@ Toki Socket의 Kotlin/Android 구현체를 담당한다. Android 및 JVM 환경 ## 금지 사항 - Kotlin proto 복사본에서 메시지 스키마를 변경하지 않는다 -- 아직 Available이 아니므로 README의 구현 상태를 임의로 변경하지 않는다 diff --git a/agent-ops/rules/project/rules.md b/agent-ops/rules/project/rules.md index 7fdf366..b0345f1 100644 --- a/agent-ops/rules/project/rules.md +++ b/agent-ops/rules/project/rules.md @@ -11,7 +11,7 @@ - Protocol Buffers 기반 직렬화 - TCP 4바이트 빅엔디안 길이 프리픽스 프레이밍 / WebSocket 바이너리 프레임 - 타입 기반 메시지 라우팅, 요청-응답 상관관계, 내장 하트비트 -- 현재 구현 완료: Dart, Go / 진행 중: Kotlin / 계획: C#, Swift, Python, Rust +- 현재 구현 완료: Dart, Go, Kotlin / 계획: C#, Swift, Python, TypeScript ## 주요 구조