Add Kotlin RUDP endpoint client sugar
This commit is contained in:
parent
8f50f2eece
commit
fa985255da
3 changed files with 89 additions and 9 deletions
|
|
@ -242,9 +242,11 @@ Current progress:
|
|||
max in-flight frame pressure, and latest-frame cursors.
|
||||
- Kotlin now has a branded `CultMesh` facade matching the C#/TypeScript/Python
|
||||
entrypoint pattern for local nodes, Verse catalogs, peer catalogs, authority
|
||||
lease catalogs, stream catalogs, and RUDP client/server construction. The
|
||||
facade delegates to the same owners as the top-level helpers instead of
|
||||
creating a second authority path.
|
||||
lease catalogs, stream catalogs, and RUDP client/server construction. Kotlin
|
||||
also parses advertised `rudp://host:port` endpoints and can build a RUDP
|
||||
client directly from a peer card contact hint. The facade delegates to the
|
||||
same owners as the top-level helpers instead of creating a second authority
|
||||
path.
|
||||
- The remaining parity work is to move the remaining TCP/LiteNetLib/WebSocket
|
||||
service bodies behind their shared transport ports, then broaden RUDP interop
|
||||
into automatic reconnect orchestration and the wider schema-message matrix.
|
||||
|
|
|
|||
|
|
@ -145,11 +145,16 @@ CultMesh.createRudpServer(
|
|||
connectionId = 0x10203040,
|
||||
tuning = CultNetRudpSocketTuning(maxFragmentBytes = 1024),
|
||||
).use { server ->
|
||||
CultMesh.createRudpClient(
|
||||
val peer = CultMeshPeerCard(
|
||||
peerId = "kotlin-server",
|
||||
verseId = "local",
|
||||
endpoints = listOf("rudp://127.0.0.1:${server.localPort}"),
|
||||
roles = listOf("schema"),
|
||||
)
|
||||
CultMesh.createRudpClientForPeer(
|
||||
runtimeId = "kotlin-client",
|
||||
connectionId = 0x10203040,
|
||||
remoteHost = "127.0.0.1",
|
||||
remotePort = server.localPort,
|
||||
peer = peer,
|
||||
).use { client ->
|
||||
client.connect("join")
|
||||
check(pumpRudpPairUntilConnected(client, server))
|
||||
|
|
@ -167,6 +172,10 @@ that already has its own receive loop, use `connectAndWait(...)`; for two
|
|||
same-process transports, use `pumpRudpPairUntilConnected(...)` to drive both
|
||||
sides through the handshake.
|
||||
|
||||
For lower-level code, `CultMesh.parseRudpEndpoint("rudp://127.0.0.1:4100")`
|
||||
returns the host/port pair, and `CultMesh.createRudpClient(...)` accepts either
|
||||
that parsed endpoint or the endpoint string directly.
|
||||
|
||||
Kotlin also exposes the shared reconnect-policy helper for peers that need a
|
||||
portable backoff document without inventing a JVM-only delay dialect:
|
||||
|
||||
|
|
|
|||
|
|
@ -312,6 +312,54 @@ object CultMesh {
|
|||
bindPort = bindPort,
|
||||
tuning = tuning,
|
||||
)
|
||||
|
||||
fun parseRudpEndpoint(endpoint: String): CultNetRudpEndpoint = cultNetRudpEndpoint(endpoint)
|
||||
|
||||
fun createRudpClient(
|
||||
runtimeId: String,
|
||||
connectionId: Long,
|
||||
endpoint: CultNetRudpEndpoint,
|
||||
bindHost: String = "127.0.0.1",
|
||||
bindPort: Int = 0,
|
||||
tuning: CultNetRudpSocketTuning = CultNetRudpSocketTuning(),
|
||||
): CultNetRudpSocketTransportConnection = createRudpClient(
|
||||
runtimeId = runtimeId,
|
||||
connectionId = connectionId,
|
||||
remoteHost = endpoint.host,
|
||||
remotePort = endpoint.port,
|
||||
bindHost = bindHost,
|
||||
bindPort = bindPort,
|
||||
tuning = tuning,
|
||||
)
|
||||
|
||||
fun createRudpClient(
|
||||
runtimeId: String,
|
||||
connectionId: Long,
|
||||
endpoint: String,
|
||||
bindHost: String = "127.0.0.1",
|
||||
bindPort: Int = 0,
|
||||
tuning: CultNetRudpSocketTuning = CultNetRudpSocketTuning(),
|
||||
): CultNetRudpSocketTransportConnection = createRudpClient(
|
||||
runtimeId = runtimeId,
|
||||
connectionId = connectionId,
|
||||
endpoint = parseRudpEndpoint(endpoint),
|
||||
bindHost = bindHost,
|
||||
bindPort = bindPort,
|
||||
tuning = tuning,
|
||||
)
|
||||
|
||||
fun createRudpClientForPeer(
|
||||
runtimeId: String,
|
||||
connectionId: Long,
|
||||
peer: CultMeshPeerCard,
|
||||
bindHost: String = "127.0.0.1",
|
||||
bindPort: Int = 0,
|
||||
tuning: CultNetRudpSocketTuning = CultNetRudpSocketTuning(),
|
||||
): CultNetRudpSocketTransportConnection {
|
||||
val endpoint = peer.endpoints.firstOrNull { it.startsWith("rudp://", ignoreCase = true) }
|
||||
?: throw IOException("Peer ${peer.peerId} does not advertise a RUDP endpoint")
|
||||
return createRudpClient(runtimeId, connectionId, endpoint, bindHost, bindPort, tuning)
|
||||
}
|
||||
}
|
||||
|
||||
data class CultNetFrame(val opcode: Int, val payload: ByteArray)
|
||||
|
|
@ -325,6 +373,10 @@ data class CultNetTransportStats(
|
|||
|
||||
data class CultNetTransportFrame(val channelId: String, val payload: ByteArray)
|
||||
|
||||
data class CultNetRudpEndpoint(val host: String, val port: Int) {
|
||||
val uri: String get() = "rudp://$host:$port"
|
||||
}
|
||||
|
||||
data class CultNetReconnectPolicy(
|
||||
val schemaVersion: String = "cultnet.reconnect_policy.v0",
|
||||
val policyId: String = "default",
|
||||
|
|
@ -2021,6 +2073,15 @@ data class CultNetRudpSocketTuning(
|
|||
val maxPendingReliablePackets: Int? = null,
|
||||
)
|
||||
|
||||
fun cultNetRudpEndpoint(endpoint: String): CultNetRudpEndpoint {
|
||||
val uri = URI(endpoint)
|
||||
if (!uri.scheme.equals("rudp", ignoreCase = true)) throw IOException("RUDP endpoint must use the rudp scheme")
|
||||
val host = uri.host ?: throw IOException("RUDP endpoint must include a host")
|
||||
val port = uri.port
|
||||
if (port <= 0 || port > 65535) throw IOException("RUDP endpoint must include a valid port")
|
||||
return CultNetRudpEndpoint(host, port)
|
||||
}
|
||||
|
||||
fun cultNetRudpServer(
|
||||
runtimeId: String,
|
||||
connectionId: Long,
|
||||
|
|
@ -3193,11 +3254,19 @@ private fun rudpSocketTransportErgonomicFactoriesCarrySchemaFrames() {
|
|||
connectionId = connectionId,
|
||||
tuning = CultNetRudpSocketTuning(resendDelayMs = 25, maxFragmentBytes = 8, maxPendingReliablePackets = 16),
|
||||
).use { server ->
|
||||
CultMesh.createRudpClient(
|
||||
val endpoint = CultMesh.parseRudpEndpoint("rudp://127.0.0.1:${server.localPort}")
|
||||
check(endpoint.host == "127.0.0.1")
|
||||
check(endpoint.port == server.localPort)
|
||||
val peer = CultMeshPeerCard(
|
||||
peerId = "kotlin-rudp-sugar-peer",
|
||||
verseId = "local",
|
||||
endpoints = listOf(endpoint.uri),
|
||||
roles = listOf("schema"),
|
||||
)
|
||||
CultMesh.createRudpClientForPeer(
|
||||
runtimeId = "kotlin-rudp-sugar-client",
|
||||
connectionId = connectionId,
|
||||
remoteHost = "127.0.0.1",
|
||||
remotePort = server.localPort,
|
||||
peer = peer,
|
||||
tuning = CultNetRudpSocketTuning(resendDelayMs = 25, maxFragmentBytes = 8, maxPendingReliablePackets = 16),
|
||||
).use { client ->
|
||||
client.connect("join")
|
||||
|
|
|
|||
Loading…
Reference in a new issue