Skip to content

feat(network): migrate TcpTransport to ktor-network (commonMain)#5995

Merged
jamesarich merged 1 commit into
mainfrom
claude/silly-tereshkova-99f556
Jun 28, 2026
Merged

feat(network): migrate TcpTransport to ktor-network (commonMain)#5995
jamesarich merged 1 commit into
mainfrom
claude/silly-tereshkova-99f556

Conversation

@jamesarich

Copy link
Copy Markdown
Collaborator

Summary

🌟 KMP commonization of TCP radio transport

TcpTransport and TcpRadioTransport were pinned to jvmAndroidMain solely by java.net.Socket + java.io blocking I/O. Everything around them was already common: the START1/START2 framing codec, the reconnect/backoff logic, and the consumer (TcpRadioTransport). This PR replaces the platform socket layer with Ktor raw sockets (ktor-network), moving both classes to commonMain and making TCP radio connectivity available to all KMP targets.

What changed

  • TcpTransport.kt jvmAndroidMain → commonMain: java.net.Socket + blocking streams → aSocket().tcp() / openReadChannel / openWriteChannel. Atomics migrated from java.util.concurrent.atomic to atomicfu (already a commonMain dep). jvmAndroidMain transport/radio dirs now empty and removed.
  • TcpRadioTransport.kt jvmAndroidMain → commonMain: pure file move — no edits needed once TcpTransport is common.
  • StreamFrameCodec.frameAndSend lambdas widened from (ByteArray) -> Unit to suspend (ByteArray) -> Unit (Ktor writes are suspend; backward-compatible — plain function refs are assignable to suspend types).
  • build.gradle.kts: +implementation(libs.ktor.network) in commonMain.
  • TcpTransportTest.kt (new, commonTest): two tests — the inactivity-timeout spike and an end-to-end framed-packet round-trip.

The critical risk, validated

The inactivity timeout logic (18 × 5s = 90s before disconnect) relied on Socket.soTimeout throwing SocketTimeoutException on each tick while keeping the stream open. The Ktor equivalent wraps readAvailable in withTimeoutOrNull. The spike test confirms that Ktor's ByteReadChannel survives a withTimeoutOrNull cancellation and resumes cleanly on the next iteration — no watchdog fallback needed.

Not included (deliberate)

  • iOS DI wiring — this PR enables iOS TCP radio; no iOS radio service exists yet to consume it (YAGNI).

Testing Performed

  • ./gradlew :core:network:allTests — both new TcpTransportTest cases pass (JVM)
  • ./gradlew spotlessCheck detekt — clean
  • ./gradlew :core:network:assembleDebug :desktopApp:compileKotlin — both downstream consumers compile

Replaces the java.net.Socket + java.io blocking I/O in TcpTransport with
Ktor raw sockets (aSocket/openReadChannel/openWriteChannel), enabling both
TcpTransport and TcpRadioTransport to live in commonMain. They were pinned
to jvmAndroidMain solely by java.* imports — the framing codec, reconnect
logic, and consumer were already platform-agnostic.

The inactivity timeout is preserved: withTimeoutOrNull wrapping readAvailable
reproduces the old Socket.soTimeout resumable-count pattern. A new spike
test confirms that Ktor's read channel survives a timeout cancellation and
resumes cleanly on the next iteration (the assumption the whole migration
rests on).

StreamFrameCodec.frameAndSend lambdas widened to suspend (backward-compat:
plain function refs are assignable to suspend types). Atomics migrated to
atomicfu (already a commonMain dep). jvmAndroidMain transport/radio dirs
are now empty and removed.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@github-actions github-actions Bot added the enhancement New feature or request label Jun 28, 2026
@jamesarich jamesarich added this pull request to the merge queue Jun 28, 2026
Merged via the queue into main with commit 1d44fd1 Jun 28, 2026
22 checks passed
@jamesarich jamesarich deleted the claude/silly-tereshkova-99f556 branch June 28, 2026 15:25
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant