From 9feca2779e18e498b2f499110b1da04b8e7179eb Mon Sep 17 00:00:00 2001 From: Oleg Yukhnevich Date: Mon, 11 Nov 2024 23:10:15 +0200 Subject: [PATCH] Migrate to kotlinx-io and ktor 3.0 --- README.md | 14 +- gradle/libs.versions.toml | 4 +- .../server/WebSocketConnectionTest.kt | 6 +- rsocket-core/api/rsocket-core.api | 171 ++++++++---------- rsocket-core/build.gradle.kts | 2 +- .../kotlin/io/rsocket/kotlin/Connection.kt | 6 +- .../kotlin/io/rsocket/kotlin/RSocket.kt | 12 +- .../rsocket/kotlin/RSocketRequestHandler.kt | 12 +- .../rsocket/kotlin/connection/Connection.kt | 14 +- .../ConnectionEstablishmentContext.kt | 8 +- .../kotlin/connection/ConnectionInbound.kt | 8 +- .../kotlin/connection/LoggingConnection.kt | 38 ++-- .../connection/MultiplexedConnection.kt | 14 +- .../kotlin/connection/OldConnection.kt | 6 +- .../kotlin/connection/SequentialConnection.kt | 14 +- .../rsocket/kotlin/core/RSocketConnector.kt | 6 +- .../kotlin/core/RSocketConnectorBuilder.kt | 5 - .../io/rsocket/kotlin/core/RSocketServer.kt | 6 +- .../kotlin/core/RSocketServerBuilder.kt | 5 - .../kotlin/core/ReconnectableRSocket.kt | 17 +- .../io/rsocket/kotlin/frame/CancelFrame.kt | 6 +- .../io/rsocket/kotlin/frame/ErrorFrame.kt | 12 +- .../io/rsocket/kotlin/frame/ExtensionFrame.kt | 9 +- .../kotlin/io/rsocket/kotlin/frame/Frame.kt | 29 ++- .../io/rsocket/kotlin/frame/FrameCodec.kt | 10 +- .../io/rsocket/kotlin/frame/KeepAliveFrame.kt | 15 +- .../io/rsocket/kotlin/frame/LeaseFrame.kt | 13 +- .../rsocket/kotlin/frame/MetadataPushFrame.kt | 15 +- .../io/rsocket/kotlin/frame/RequestFrame.kt | 10 +- .../io/rsocket/kotlin/frame/RequestNFrame.kt | 8 +- .../io/rsocket/kotlin/frame/ResumeFrame.kt | 13 +- .../io/rsocket/kotlin/frame/ResumeOkFrame.kt | 8 +- .../io/rsocket/kotlin/frame/SetupFrame.kt | 23 ++- .../kotlin/io/rsocket/kotlin/frame/io/Dump.kt | 22 +-- .../io/rsocket/kotlin/frame/io/Version.kt | 8 +- .../io/rsocket/kotlin/frame/io/mimeType.kt | 26 +-- .../io/rsocket/kotlin/frame/io/payload.kt | 23 ++- .../kotlin/io/rsocket/kotlin/frame/io/util.kt | 32 ++-- .../io/rsocket/kotlin/internal/BufferPool.kt | 44 ----- .../kotlin/internal/PayloadAssembler.kt | 60 ++---- .../kotlin/keepalive/KeepAliveHandler.kt | 7 +- .../kotlin/metadata/CompositeMetadata.kt | 21 +-- .../metadata/CompositeMetadataBuilder.kt | 10 +- .../metadata/CompositeMetadataExtensions.kt | 15 +- .../io/rsocket/kotlin/metadata/Metadata.kt | 19 +- ...erStreamAcceptableDataMimeTypesMetadata.kt | 9 +- .../metadata/PerStreamDataMimeTypeMetadata.kt | 7 +- .../io/rsocket/kotlin/metadata/RawMetadata.kt | 13 +- .../kotlin/metadata/RoutingMetadata.kt | 15 +- .../kotlin/metadata/ZipkinTracingMetadata.kt | 7 +- .../kotlin/metadata/security/AuthMetadata.kt | 13 +- .../metadata/security/BearerAuthMetadata.kt | 11 +- .../metadata/security/RawAuthMetadata.kt | 19 +- .../metadata/security/SimpleAuthMetadata.kt | 17 +- .../kotlin/operation/OperationOutbound.kt | 24 +-- .../io/rsocket/kotlin/payload/Payload.kt | 25 +-- .../rsocket/kotlin/payload/PayloadBuilder.kt | 32 ++-- .../kotlin/transport/RSocketConnection.kt | 12 +- .../internal/PrioritizationFrameQueue.kt | 16 +- .../kotlin/ConnectionEstablishmentTest.kt | 9 +- .../io/rsocket/kotlin/TestConnection.kt | 16 +- .../io/rsocket/kotlin/core/RSocketTest.kt | 12 +- .../kotlin/core/ReconnectableRSocketTest.kt | 7 +- .../rsocket/kotlin/frame/CancelFrameTest.kt | 5 +- .../io/rsocket/kotlin/frame/ErrorFrameTest.kt | 6 +- .../kotlin/frame/ExtensionFrameTest.kt | 19 +- .../kotlin/frame/KeepAliveFrameTest.kt | 8 +- .../io/rsocket/kotlin/frame/LeaseFrameTest.kt | 7 +- .../kotlin/frame/MetadataPushFrameTest.kt | 8 +- .../rsocket/kotlin/frame/PayloadFrameTest.kt | 31 ++-- .../frame/RequestFireAndForgetFrameTest.kt | 11 +- .../rsocket/kotlin/frame/RequestNFrameTest.kt | 6 +- .../kotlin/frame/RequestResponseFrameTest.kt | 16 +- .../kotlin/frame/RequestStreamFrameTest.kt | 39 ++-- .../rsocket/kotlin/frame/ResumeFrameTest.kt | 12 +- .../rsocket/kotlin/frame/ResumeOkFrameTest.kt | 5 +- .../io/rsocket/kotlin/frame/SetupFrameTest.kt | 22 +-- .../kotlin/io/rsocket/kotlin/frame/Util.kt | 19 +- .../rsocket/kotlin/frame/io/MimeTypeTest.kt | 4 +- .../kotlin/internal/RSocketRequesterTest.kt | 5 +- .../internal/RSocketResponderRequestNTest.kt | 2 +- .../rsocket/kotlin/keepalive/KeepAliveTest.kt | 8 +- .../kotlin/metadata/CompositeMetadataTest.kt | 44 ++--- ...reamAcceptableDataMimeTypesMetadataTest.kt | 5 +- .../PerStreamDataMimeTypeMetadataTest.kt | 5 +- .../kotlin/metadata/RoutingMetadataTest.kt | 5 +- .../kotlin/io/rsocket/kotlin/metadata/Util.kt | 6 +- .../metadata/ZipkinTracingMetadataTest.kt | 5 +- .../metadata/security/AuthMetadataTest.kt | 7 +- .../kotlin/operation/OperationOutboundTest.kt | 20 +- .../RequesterRequestResponseOperationTest.kt | 7 +- .../kotlin/payload/PayloadBuilderTest.kt | 18 +- .../internal/PrioritizationFrameQueueTest.kt | 38 ++-- .../api/rsocket-internal-io.api | 5 +- rsocket-internal-io/build.gradle.kts | 2 +- .../io/rsocket/kotlin/internal/io/Channels.kt | 14 +- .../io/rsocket/kotlin/internal/io/Int24.kt | 8 +- .../rsocket/kotlin/test/InUseTrackingPool.kt | 151 ---------------- .../kotlin/io/rsocket/kotlin/test/Packets.kt | 8 +- .../io/rsocket/kotlin/test/TestConfig.kt | 4 - .../kotlin/transport/tests/TransportTest.kt | 22 +-- .../transport/ktor/tcp/KtorTcpConnection.kt | 38 ++-- .../transport/ktor/tcp/TcpConnection.kt | 21 +-- .../transport/ktor/tcp/TcpServerTest.kt | 5 +- ...cket-transport-ktor-websocket-internal.api | 2 +- .../internal/KtorWebSocketConnection.kt | 10 +- .../websocket/internal/WebSocketConnection.kt | 10 +- .../ktor-websocket-server/build.gradle.kts | 2 - .../server/KtorWebSocketServerTransport.kt | 52 ++++-- .../server/WebSocketServerTransport.kt | 23 ++- .../server/WebSocketTransportTest.kt | 4 +- .../server/WebSocketTransportTests.kt | 7 - .../kotlin/transport/local/LocalConnection.kt | 12 +- .../kotlin/transport/local/LocalServer.kt | 5 +- .../transport/local/LocalServerConnector.kt | 43 +++-- .../api/rsocket-transport-netty-internal.api | 7 +- .../transport/netty/internal/coroutines.kt | 6 - .../kotlin/transport/netty/internal/io.kt | 47 +++++ .../netty/quic/NettyQuicStreamHandler.kt | 22 +-- .../netty/tcp/NettyTcpConnectionHandler.kt | 20 +- .../NettyWebSocketConnectionHandler.kt | 19 +- .../nodejs/tcp/FrameWithLengthAssembler.kt | 65 ++++--- .../nodejs/tcp/NodejsTcpConnection.kt | 22 +-- .../transport/nodejs/tcp/TcpConnection.kt | 18 +- 124 files changed, 962 insertions(+), 1195 deletions(-) delete mode 100644 rsocket-core/src/commonMain/kotlin/io/rsocket/kotlin/internal/BufferPool.kt delete mode 100644 rsocket-test/src/commonMain/kotlin/io/rsocket/kotlin/test/InUseTrackingPool.kt create mode 100644 rsocket-transports/netty-internal/src/jvmMain/kotlin/io/rsocket/kotlin/transport/netty/internal/io.kt diff --git a/README.md b/README.md index 897e5f54..0c785ca8 100644 --- a/README.md +++ b/README.md @@ -117,7 +117,7 @@ val stream: Flow = rSocket.requestStream( //take 5 values and print response stream.take(5).collect { payload: Payload -> - println(payload.data.readText()) + println(payload.data.readString()) } ``` @@ -143,12 +143,12 @@ embeddedServer(CIO) { routing { //configure route `/rsocket` rSocket("rsocket") { - println(config.setupPayload.data.readText()) //print setup payload data + println(config.setupPayload.data.readString()) //print setup payload data RSocketRequestHandler { //handler for request/response requestResponse { request: Payload -> - println(request.data.readText()) //print request payload data + println(request.data.readString()) //print request payload data delay(500) // work emulation buildPayload { data("""{ "data": "Server response" }""") @@ -156,7 +156,7 @@ embeddedServer(CIO) { } //handler for request/stream requestStream { request: Payload -> - println(request.data.readText()) //print request payload data + println(request.data.readString()) //print request payload data flow { repeat(10) { i -> emit( @@ -208,7 +208,7 @@ val connector = RSocketConnector { val rsocket: RSocket = connector.connect(transport) //use rsocket to do request val response = rsocket.requestResponse(buildPayload { data("""{ "data": "hello world" }""") }) -println(response.data.readText()) +println(response.data.readString()) ``` Example of usage standalone server transport: @@ -223,7 +223,7 @@ val server: TcpServer = server.bind(transport) { RSocketRequestHandler { //handler for request/response requestResponse { request: Payload -> - println(request.data.readText()) //print request payload data + println(request.data.readString()) //print request payload data delay(500) // work emulation buildPayload { data("""{ "data": "Server response" }""") @@ -267,7 +267,7 @@ val stream: Flow = client.requestStream(Payload("data")) //so on call `collect`, requestStream frame with requestN will be sent, and then, after 5 elements will be collected //new requestN with 5 will be sent, so collect will be smooth stream.flowOn(PrefetchStrategy(requestSize = 10, requestOn = 5)).collect { payload: Payload -> - println(payload.data.readText()) + println(payload.data.readString()) } ``` diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index eed89be4..e40ec88e 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,12 +1,13 @@ [versions] kotlin = "2.0.21" +kotlinx-io = "0.5.4" kotlinx-atomicfu = "0.26.0" kotlinx-coroutines = "1.9.0" kotlinx-benchmark = "0.4.8" kotlinx-bcv = "0.16.3" -ktor = "2.3.12" +ktor = "3.0.1" netty = "4.1.114.Final" netty-quic = "0.0.68.Final" @@ -23,6 +24,7 @@ jmh = "1.36" maven-publish = "0.30.0" [libraries] +kotlinx-io-core = { module = "org.jetbrains.kotlinx:kotlinx-io-core", version.ref = "kotlinx-io" } kotlinx-coroutines-core = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-core", version.ref = "kotlinx-coroutines" } kotlinx-coroutines-test = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-test", version.ref = "kotlinx-coroutines" } kotlinx-coroutines-reactor = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-reactor", version.ref = "kotlinx-coroutines" } diff --git a/ktor-plugins/ktor-server-rsocket/src/commonTest/kotlin/io/rsocket/kotlin/transport/ktor/websocket/server/WebSocketConnectionTest.kt b/ktor-plugins/ktor-server-rsocket/src/commonTest/kotlin/io/rsocket/kotlin/transport/ktor/websocket/server/WebSocketConnectionTest.kt index 0b5a981e..f6554720 100644 --- a/ktor-plugins/ktor-server-rsocket/src/commonTest/kotlin/io/rsocket/kotlin/transport/ktor/websocket/server/WebSocketConnectionTest.kt +++ b/ktor-plugins/ktor-server-rsocket/src/commonTest/kotlin/io/rsocket/kotlin/transport/ktor/websocket/server/WebSocketConnectionTest.kt @@ -36,7 +36,7 @@ import io.ktor.server.websocket.WebSockets as ServerWebSockets import io.rsocket.kotlin.ktor.client.RSocketSupport as ClientRSocketSupport import io.rsocket.kotlin.ktor.server.RSocketSupport as ServerRSocketSupport -class WebSocketConnectionTest : SuspendTest, TestWithLeakCheck { +class WebSocketConnectionTest : SuspendTest { private val client = HttpClient(ClientCIO) { install(ClientWebSockets) install(ClientRSocketSupport) { @@ -57,7 +57,7 @@ class WebSocketConnectionTest : SuspendTest, TestWithLeakCheck { install(ServerRSocketSupport) { server(TestServer()) } - install(Routing) { + routing { rSocket { RSocketRequestHandler { requestStream { @@ -87,7 +87,7 @@ class WebSocketConnectionTest : SuspendTest, TestWithLeakCheck { @Test fun testWorks() = test { - val port = server.resolvedConnectors().single().port + val port = server.engine.resolvedConnectors().single().port val rSocket = client.rSocket(port = port) val requesterJob = rSocket.coroutineContext.job diff --git a/rsocket-core/api/rsocket-core.api b/rsocket-core/api/rsocket-core.api index e0816d06..6408087e 100644 --- a/rsocket-core/api/rsocket-core.api +++ b/rsocket-core/api/rsocket-core.api @@ -11,7 +11,7 @@ public final class io/rsocket/kotlin/ChannelStrategy : io/rsocket/kotlin/Request public abstract interface class io/rsocket/kotlin/Connection : kotlinx/coroutines/CoroutineScope { public abstract fun receive (Lkotlin/coroutines/Continuation;)Ljava/lang/Object; - public abstract fun send (Lio/ktor/utils/io/core/ByteReadPacket;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; + public abstract fun send (Lkotlinx/io/Buffer;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; } public abstract interface class io/rsocket/kotlin/ConnectionAcceptor { @@ -47,8 +47,8 @@ public final class io/rsocket/kotlin/PrefetchStrategy : io/rsocket/kotlin/Reques public abstract interface class io/rsocket/kotlin/RSocket : kotlinx/coroutines/CoroutineScope { public fun fireAndForget (Lio/rsocket/kotlin/payload/Payload;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; public static synthetic fun fireAndForget$suspendImpl (Lio/rsocket/kotlin/RSocket;Lio/rsocket/kotlin/payload/Payload;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; - public fun metadataPush (Lio/ktor/utils/io/core/ByteReadPacket;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; - public static synthetic fun metadataPush$suspendImpl (Lio/rsocket/kotlin/RSocket;Lio/ktor/utils/io/core/ByteReadPacket;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; + public fun metadataPush (Lkotlinx/io/Buffer;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; + public static synthetic fun metadataPush$suspendImpl (Lio/rsocket/kotlin/RSocket;Lkotlinx/io/Buffer;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; public fun requestChannel (Lio/rsocket/kotlin/payload/Payload;Lkotlinx/coroutines/flow/Flow;)Lkotlinx/coroutines/flow/Flow; public fun requestResponse (Lio/rsocket/kotlin/payload/Payload;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; public static synthetic fun requestResponse$suspendImpl (Lio/rsocket/kotlin/RSocket;Lio/rsocket/kotlin/payload/Payload;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; @@ -116,7 +116,7 @@ public final class io/rsocket/kotlin/RSocketError$Setup$Unsupported : io/rsocket } public final class io/rsocket/kotlin/RSocketKt { - public static final fun emitOrClose (Lkotlinx/coroutines/flow/FlowCollector;Ljava/io/Closeable;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; + public static final fun emitOrClose (Lkotlinx/coroutines/flow/FlowCollector;Ljava/lang/AutoCloseable;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; } public abstract interface annotation class io/rsocket/kotlin/RSocketLoggingApi : java/lang/annotation/Annotation { @@ -200,14 +200,12 @@ public final class io/rsocket/kotlin/core/RSocketConnector { public final class io/rsocket/kotlin/core/RSocketConnectorBuilder { public final fun acceptor (Lio/rsocket/kotlin/ConnectionAcceptor;)V public final fun connectionConfig (Lkotlin/jvm/functions/Function1;)V - public final fun getBufferPool-7b3xaDw ()Lio/ktor/utils/io/pool/ObjectPool; public final fun getLoggerFactory ()Lio/rsocket/kotlin/logging/LoggerFactory; public final fun getMaxFragmentSize ()I public final fun interceptors (Lkotlin/jvm/functions/Function1;)V public final fun reconnectable (JLkotlin/jvm/functions/Function2;)V public final fun reconnectable (Lkotlin/jvm/functions/Function3;)V public static synthetic fun reconnectable$default (Lio/rsocket/kotlin/core/RSocketConnectorBuilder;JLkotlin/jvm/functions/Function2;ILjava/lang/Object;)V - public final fun setBufferPool-vHF7wRk (Lio/ktor/utils/io/pool/ObjectPool;)V public final fun setLoggerFactory (Lio/rsocket/kotlin/logging/LoggerFactory;)V public final fun setMaxFragmentSize (I)V } @@ -234,11 +232,9 @@ public final class io/rsocket/kotlin/core/RSocketServer { } public final class io/rsocket/kotlin/core/RSocketServerBuilder { - public final fun getBufferPool-7b3xaDw ()Lio/ktor/utils/io/pool/ObjectPool; public final fun getLoggerFactory ()Lio/rsocket/kotlin/logging/LoggerFactory; public final fun getMaxFragmentSize ()I public final fun interceptors (Lkotlin/jvm/functions/Function1;)V - public final fun setBufferPool-vHF7wRk (Lio/ktor/utils/io/pool/ObjectPool;)V public final fun setLoggerFactory (Lio/rsocket/kotlin/logging/LoggerFactory;)V public final fun setMaxFragmentSize (I)V } @@ -323,25 +319,6 @@ public final class io/rsocket/kotlin/core/WellKnownMimeType$Companion { public final fun invoke (Ljava/lang/String;)Lio/rsocket/kotlin/core/WellKnownMimeType; } -public final class io/rsocket/kotlin/internal/BufferPool { - public static final field Companion Lio/rsocket/kotlin/internal/BufferPool$Companion; - public static final synthetic fun box-impl (Lio/ktor/utils/io/pool/ObjectPool;)Lio/rsocket/kotlin/internal/BufferPool; - public static final fun buildPacket-impl (Lio/ktor/utils/io/pool/ObjectPool;Lkotlin/jvm/functions/Function1;)Lio/ktor/utils/io/core/ByteReadPacket; - public static fun constructor-impl (Lio/ktor/utils/io/pool/ObjectPool;)Lio/ktor/utils/io/pool/ObjectPool; - public fun equals (Ljava/lang/Object;)Z - public static fun equals-impl (Lio/ktor/utils/io/pool/ObjectPool;Ljava/lang/Object;)Z - public static final fun equals-impl0 (Lio/ktor/utils/io/pool/ObjectPool;Lio/ktor/utils/io/pool/ObjectPool;)Z - public fun hashCode ()I - public static fun hashCode-impl (Lio/ktor/utils/io/pool/ObjectPool;)I - public fun toString ()Ljava/lang/String; - public static fun toString-impl (Lio/ktor/utils/io/pool/ObjectPool;)Ljava/lang/String; - public final synthetic fun unbox-impl ()Lio/ktor/utils/io/pool/ObjectPool; -} - -public final class io/rsocket/kotlin/internal/BufferPool$Companion { - public final fun getDefault-7b3xaDw ()Lio/ktor/utils/io/pool/ObjectPool; -} - public final class io/rsocket/kotlin/keepalive/KeepAlive { public fun ()V public fun (II)V @@ -430,24 +407,24 @@ public abstract interface class io/rsocket/kotlin/metadata/CompositeMetadata : i public fun close ()V public abstract fun getEntries ()Ljava/util/List; public fun getMimeType ()Lio/rsocket/kotlin/core/MimeType; - public fun writeSelf (Lio/ktor/utils/io/core/BytePacketBuilder;)V + public fun writeSelf (Lkotlinx/io/Sink;)V } public final class io/rsocket/kotlin/metadata/CompositeMetadata$Entry { - public fun (Lio/rsocket/kotlin/core/MimeType;Lio/ktor/utils/io/core/ByteReadPacket;)V + public fun (Lio/rsocket/kotlin/core/MimeType;Lkotlinx/io/Buffer;)V public fun (Lio/rsocket/kotlin/metadata/Metadata;)V - public final fun getContent ()Lio/ktor/utils/io/core/ByteReadPacket; + public final fun getContent ()Lkotlinx/io/Buffer; public final fun getMimeType ()Lio/rsocket/kotlin/core/MimeType; } public final class io/rsocket/kotlin/metadata/CompositeMetadata$Reader : io/rsocket/kotlin/metadata/MetadataReader { public fun getMimeType ()Lio/rsocket/kotlin/core/MimeType; - public fun read-B471DwU (Lio/ktor/utils/io/core/ByteReadPacket;Lio/ktor/utils/io/pool/ObjectPool;)Lio/rsocket/kotlin/metadata/CompositeMetadata; - public synthetic fun read-B471DwU (Lio/ktor/utils/io/core/ByteReadPacket;Lio/ktor/utils/io/pool/ObjectPool;)Lio/rsocket/kotlin/metadata/Metadata; + public fun read (Lkotlinx/io/Source;)Lio/rsocket/kotlin/metadata/CompositeMetadata; + public synthetic fun read (Lkotlinx/io/Source;)Lio/rsocket/kotlin/metadata/Metadata; } -public abstract interface class io/rsocket/kotlin/metadata/CompositeMetadataBuilder : java/io/Closeable { - public abstract fun add (Lio/rsocket/kotlin/core/MimeType;Lio/ktor/utils/io/core/ByteReadPacket;)V +public abstract interface class io/rsocket/kotlin/metadata/CompositeMetadataBuilder : java/lang/AutoCloseable { + public abstract fun add (Lio/rsocket/kotlin/core/MimeType;Lkotlinx/io/Buffer;)V public abstract fun add (Lio/rsocket/kotlin/metadata/Metadata;)V } @@ -459,22 +436,20 @@ public final class io/rsocket/kotlin/metadata/CompositeMetadataBuilderKt { public final class io/rsocket/kotlin/metadata/CompositeMetadataExtensionsKt { public static final fun contains (Lio/rsocket/kotlin/metadata/CompositeMetadata;Lio/rsocket/kotlin/core/MimeType;)Z public static final fun contains (Lio/rsocket/kotlin/metadata/CompositeMetadata;Lio/rsocket/kotlin/metadata/MetadataReader;)Z - public static final fun get (Lio/rsocket/kotlin/metadata/CompositeMetadata;Lio/rsocket/kotlin/core/MimeType;)Lio/ktor/utils/io/core/ByteReadPacket; + public static final fun get (Lio/rsocket/kotlin/metadata/CompositeMetadata;Lio/rsocket/kotlin/core/MimeType;)Lkotlinx/io/Source; public static final fun get (Lio/rsocket/kotlin/metadata/CompositeMetadata;Lio/rsocket/kotlin/metadata/MetadataReader;)Lio/rsocket/kotlin/metadata/Metadata; - public static final fun getOrNull (Lio/rsocket/kotlin/metadata/CompositeMetadata;Lio/rsocket/kotlin/core/MimeType;)Lio/ktor/utils/io/core/ByteReadPacket; + public static final fun getOrNull (Lio/rsocket/kotlin/metadata/CompositeMetadata;Lio/rsocket/kotlin/core/MimeType;)Lkotlinx/io/Source; public static final fun getOrNull (Lio/rsocket/kotlin/metadata/CompositeMetadata;Lio/rsocket/kotlin/metadata/MetadataReader;)Lio/rsocket/kotlin/metadata/Metadata; public static final fun hasMimeTypeOf (Lio/rsocket/kotlin/metadata/CompositeMetadata$Entry;Lio/rsocket/kotlin/metadata/MetadataReader;)Z public static final fun list (Lio/rsocket/kotlin/metadata/CompositeMetadata;Lio/rsocket/kotlin/core/MimeType;)Ljava/util/List; public static final fun list (Lio/rsocket/kotlin/metadata/CompositeMetadata;Lio/rsocket/kotlin/metadata/MetadataReader;)Ljava/util/List; - public static final fun read-jfyA9PI (Lio/rsocket/kotlin/metadata/CompositeMetadata$Entry;Lio/rsocket/kotlin/metadata/MetadataReader;Lio/ktor/utils/io/pool/ObjectPool;)Lio/rsocket/kotlin/metadata/Metadata; - public static synthetic fun read-jfyA9PI$default (Lio/rsocket/kotlin/metadata/CompositeMetadata$Entry;Lio/rsocket/kotlin/metadata/MetadataReader;Lio/ktor/utils/io/pool/ObjectPool;ILjava/lang/Object;)Lio/rsocket/kotlin/metadata/Metadata; - public static final fun readOrNull-jfyA9PI (Lio/rsocket/kotlin/metadata/CompositeMetadata$Entry;Lio/rsocket/kotlin/metadata/MetadataReader;Lio/ktor/utils/io/pool/ObjectPool;)Lio/rsocket/kotlin/metadata/Metadata; - public static synthetic fun readOrNull-jfyA9PI$default (Lio/rsocket/kotlin/metadata/CompositeMetadata$Entry;Lio/rsocket/kotlin/metadata/MetadataReader;Lio/ktor/utils/io/pool/ObjectPool;ILjava/lang/Object;)Lio/rsocket/kotlin/metadata/Metadata; + public static final fun read (Lio/rsocket/kotlin/metadata/CompositeMetadata$Entry;Lio/rsocket/kotlin/metadata/MetadataReader;)Lio/rsocket/kotlin/metadata/Metadata; + public static final fun readOrNull (Lio/rsocket/kotlin/metadata/CompositeMetadata$Entry;Lio/rsocket/kotlin/metadata/MetadataReader;)Lio/rsocket/kotlin/metadata/Metadata; } public final class io/rsocket/kotlin/metadata/CompositeMetadataFromBuilder : io/rsocket/kotlin/metadata/CompositeMetadata, io/rsocket/kotlin/metadata/CompositeMetadataBuilder { public fun ()V - public fun add (Lio/rsocket/kotlin/core/MimeType;Lio/ktor/utils/io/core/ByteReadPacket;)V + public fun add (Lio/rsocket/kotlin/core/MimeType;Lkotlinx/io/Buffer;)V public fun add (Lio/rsocket/kotlin/metadata/Metadata;)V public fun getEntries ()Ljava/util/List; } @@ -484,22 +459,20 @@ public final class io/rsocket/kotlin/metadata/CompositeMetadataKt { public static final fun CompositeMetadata ([Lio/rsocket/kotlin/metadata/Metadata;)Lio/rsocket/kotlin/metadata/CompositeMetadata; } -public abstract interface class io/rsocket/kotlin/metadata/Metadata : java/io/Closeable { +public abstract interface class io/rsocket/kotlin/metadata/Metadata : java/lang/AutoCloseable { public abstract fun getMimeType ()Lio/rsocket/kotlin/core/MimeType; - public abstract fun writeSelf (Lio/ktor/utils/io/core/BytePacketBuilder;)V + public abstract fun writeSelf (Lkotlinx/io/Sink;)V } public final class io/rsocket/kotlin/metadata/MetadataKt { public static final fun metadata (Lio/rsocket/kotlin/payload/PayloadBuilder;Lio/rsocket/kotlin/metadata/Metadata;)V - public static final fun read-jfyA9PI (Lio/ktor/utils/io/core/ByteReadPacket;Lio/rsocket/kotlin/metadata/MetadataReader;Lio/ktor/utils/io/pool/ObjectPool;)Lio/rsocket/kotlin/metadata/Metadata; - public static synthetic fun read-jfyA9PI$default (Lio/ktor/utils/io/core/ByteReadPacket;Lio/rsocket/kotlin/metadata/MetadataReader;Lio/ktor/utils/io/pool/ObjectPool;ILjava/lang/Object;)Lio/rsocket/kotlin/metadata/Metadata; - public static final fun toPacket-B471DwU (Lio/rsocket/kotlin/metadata/Metadata;Lio/ktor/utils/io/pool/ObjectPool;)Lio/ktor/utils/io/core/ByteReadPacket; - public static synthetic fun toPacket-B471DwU$default (Lio/rsocket/kotlin/metadata/Metadata;Lio/ktor/utils/io/pool/ObjectPool;ILjava/lang/Object;)Lio/ktor/utils/io/core/ByteReadPacket; + public static final fun read (Lkotlinx/io/Source;Lio/rsocket/kotlin/metadata/MetadataReader;)Lio/rsocket/kotlin/metadata/Metadata; + public static final fun toBuffer (Lio/rsocket/kotlin/metadata/Metadata;)Lkotlinx/io/Buffer; } public abstract interface class io/rsocket/kotlin/metadata/MetadataReader { public abstract fun getMimeType ()Lio/rsocket/kotlin/core/MimeType; - public abstract fun read-B471DwU (Lio/ktor/utils/io/core/ByteReadPacket;Lio/ktor/utils/io/pool/ObjectPool;)Lio/rsocket/kotlin/metadata/Metadata; + public abstract fun read (Lkotlinx/io/Source;)Lio/rsocket/kotlin/metadata/Metadata; } public final class io/rsocket/kotlin/metadata/PerStreamAcceptableDataMimeTypesMetadata : io/rsocket/kotlin/metadata/Metadata { @@ -508,13 +481,13 @@ public final class io/rsocket/kotlin/metadata/PerStreamAcceptableDataMimeTypesMe public fun close ()V public fun getMimeType ()Lio/rsocket/kotlin/core/MimeType; public final fun getTypes ()Ljava/util/List; - public fun writeSelf (Lio/ktor/utils/io/core/BytePacketBuilder;)V + public fun writeSelf (Lkotlinx/io/Sink;)V } public final class io/rsocket/kotlin/metadata/PerStreamAcceptableDataMimeTypesMetadata$Reader : io/rsocket/kotlin/metadata/MetadataReader { public fun getMimeType ()Lio/rsocket/kotlin/core/MimeType; - public synthetic fun read-B471DwU (Lio/ktor/utils/io/core/ByteReadPacket;Lio/ktor/utils/io/pool/ObjectPool;)Lio/rsocket/kotlin/metadata/Metadata; - public fun read-B471DwU (Lio/ktor/utils/io/core/ByteReadPacket;Lio/ktor/utils/io/pool/ObjectPool;)Lio/rsocket/kotlin/metadata/PerStreamAcceptableDataMimeTypesMetadata; + public synthetic fun read (Lkotlinx/io/Source;)Lio/rsocket/kotlin/metadata/Metadata; + public fun read (Lkotlinx/io/Source;)Lio/rsocket/kotlin/metadata/PerStreamAcceptableDataMimeTypesMetadata; } public final class io/rsocket/kotlin/metadata/PerStreamAcceptableDataMimeTypesMetadataKt { @@ -527,22 +500,22 @@ public final class io/rsocket/kotlin/metadata/PerStreamDataMimeTypeMetadata : io public fun close ()V public fun getMimeType ()Lio/rsocket/kotlin/core/MimeType; public final fun getType ()Lio/rsocket/kotlin/core/MimeType; - public fun writeSelf (Lio/ktor/utils/io/core/BytePacketBuilder;)V + public fun writeSelf (Lkotlinx/io/Sink;)V } public final class io/rsocket/kotlin/metadata/PerStreamDataMimeTypeMetadata$Reader : io/rsocket/kotlin/metadata/MetadataReader { public fun getMimeType ()Lio/rsocket/kotlin/core/MimeType; - public synthetic fun read-B471DwU (Lio/ktor/utils/io/core/ByteReadPacket;Lio/ktor/utils/io/pool/ObjectPool;)Lio/rsocket/kotlin/metadata/Metadata; - public fun read-B471DwU (Lio/ktor/utils/io/core/ByteReadPacket;Lio/ktor/utils/io/pool/ObjectPool;)Lio/rsocket/kotlin/metadata/PerStreamDataMimeTypeMetadata; + public synthetic fun read (Lkotlinx/io/Source;)Lio/rsocket/kotlin/metadata/Metadata; + public fun read (Lkotlinx/io/Source;)Lio/rsocket/kotlin/metadata/PerStreamDataMimeTypeMetadata; } public final class io/rsocket/kotlin/metadata/RawMetadata : io/rsocket/kotlin/metadata/Metadata { public static final field Companion Lio/rsocket/kotlin/metadata/RawMetadata$Companion; - public fun (Lio/rsocket/kotlin/core/MimeType;Lio/ktor/utils/io/core/ByteReadPacket;)V + public fun (Lio/rsocket/kotlin/core/MimeType;Lkotlinx/io/Source;)V public fun close ()V - public final fun getContent ()Lio/ktor/utils/io/core/ByteReadPacket; + public final fun getContent ()Lkotlinx/io/Source; public fun getMimeType ()Lio/rsocket/kotlin/core/MimeType; - public fun writeSelf (Lio/ktor/utils/io/core/BytePacketBuilder;)V + public fun writeSelf (Lkotlinx/io/Sink;)V } public final class io/rsocket/kotlin/metadata/RawMetadata$Companion { @@ -555,13 +528,13 @@ public final class io/rsocket/kotlin/metadata/RoutingMetadata : io/rsocket/kotli public fun close ()V public fun getMimeType ()Lio/rsocket/kotlin/core/MimeType; public final fun getTags ()Ljava/util/List; - public fun writeSelf (Lio/ktor/utils/io/core/BytePacketBuilder;)V + public fun writeSelf (Lkotlinx/io/Sink;)V } public final class io/rsocket/kotlin/metadata/RoutingMetadata$Reader : io/rsocket/kotlin/metadata/MetadataReader { public fun getMimeType ()Lio/rsocket/kotlin/core/MimeType; - public synthetic fun read-B471DwU (Lio/ktor/utils/io/core/ByteReadPacket;Lio/ktor/utils/io/pool/ObjectPool;)Lio/rsocket/kotlin/metadata/Metadata; - public fun read-B471DwU (Lio/ktor/utils/io/core/ByteReadPacket;Lio/ktor/utils/io/pool/ObjectPool;)Lio/rsocket/kotlin/metadata/RoutingMetadata; + public synthetic fun read (Lkotlinx/io/Source;)Lio/rsocket/kotlin/metadata/Metadata; + public fun read (Lkotlinx/io/Source;)Lio/rsocket/kotlin/metadata/RoutingMetadata; } public final class io/rsocket/kotlin/metadata/RoutingMetadataKt { @@ -580,7 +553,7 @@ public final class io/rsocket/kotlin/metadata/ZipkinTracingMetadata : io/rsocket public final fun getSpanId ()J public final fun getTraceId ()J public final fun getTraceIdHigh ()J - public fun writeSelf (Lio/ktor/utils/io/core/BytePacketBuilder;)V + public fun writeSelf (Lkotlinx/io/Sink;)V } public final class io/rsocket/kotlin/metadata/ZipkinTracingMetadata$Kind : java/lang/Enum { @@ -595,8 +568,8 @@ public final class io/rsocket/kotlin/metadata/ZipkinTracingMetadata$Kind : java/ public final class io/rsocket/kotlin/metadata/ZipkinTracingMetadata$Reader : io/rsocket/kotlin/metadata/MetadataReader { public fun getMimeType ()Lio/rsocket/kotlin/core/MimeType; - public synthetic fun read-B471DwU (Lio/ktor/utils/io/core/ByteReadPacket;Lio/ktor/utils/io/pool/ObjectPool;)Lio/rsocket/kotlin/metadata/Metadata; - public fun read-B471DwU (Lio/ktor/utils/io/core/ByteReadPacket;Lio/ktor/utils/io/pool/ObjectPool;)Lio/rsocket/kotlin/metadata/ZipkinTracingMetadata; + public synthetic fun read (Lkotlinx/io/Source;)Lio/rsocket/kotlin/metadata/Metadata; + public fun read (Lkotlinx/io/Source;)Lio/rsocket/kotlin/metadata/ZipkinTracingMetadata; } public final class io/rsocket/kotlin/metadata/ZipkinTracingMetadataKt { @@ -610,15 +583,15 @@ public final class io/rsocket/kotlin/metadata/ZipkinTracingMetadataKt { public abstract interface class io/rsocket/kotlin/metadata/security/AuthMetadata : io/rsocket/kotlin/metadata/Metadata { public fun getMimeType ()Lio/rsocket/kotlin/core/MimeType; public abstract fun getType ()Lio/rsocket/kotlin/metadata/security/AuthType; - public abstract fun writeContent (Lio/ktor/utils/io/core/BytePacketBuilder;)V - public fun writeSelf (Lio/ktor/utils/io/core/BytePacketBuilder;)V + public abstract fun writeContent (Lkotlinx/io/Sink;)V + public fun writeSelf (Lkotlinx/io/Sink;)V } public abstract interface class io/rsocket/kotlin/metadata/security/AuthMetadataReader : io/rsocket/kotlin/metadata/MetadataReader { public fun getMimeType ()Lio/rsocket/kotlin/core/MimeType; - public synthetic fun read-B471DwU (Lio/ktor/utils/io/core/ByteReadPacket;Lio/ktor/utils/io/pool/ObjectPool;)Lio/rsocket/kotlin/metadata/Metadata; - public fun read-B471DwU (Lio/ktor/utils/io/core/ByteReadPacket;Lio/ktor/utils/io/pool/ObjectPool;)Lio/rsocket/kotlin/metadata/security/AuthMetadata; - public abstract fun readContent-jfyA9PI (Lio/ktor/utils/io/core/ByteReadPacket;Lio/rsocket/kotlin/metadata/security/AuthType;Lio/ktor/utils/io/pool/ObjectPool;)Lio/rsocket/kotlin/metadata/security/AuthMetadata; + public synthetic fun read (Lkotlinx/io/Source;)Lio/rsocket/kotlin/metadata/Metadata; + public fun read (Lkotlinx/io/Source;)Lio/rsocket/kotlin/metadata/security/AuthMetadata; + public abstract fun readContent (Lkotlinx/io/Source;Lio/rsocket/kotlin/metadata/security/AuthType;)Lio/rsocket/kotlin/metadata/security/AuthMetadata; } public abstract interface class io/rsocket/kotlin/metadata/security/AuthType { @@ -638,12 +611,12 @@ public final class io/rsocket/kotlin/metadata/security/BearerAuthMetadata : io/r public fun close ()V public final fun getToken ()Ljava/lang/String; public fun getType ()Lio/rsocket/kotlin/metadata/security/AuthType; - public fun writeContent (Lio/ktor/utils/io/core/BytePacketBuilder;)V + public fun writeContent (Lkotlinx/io/Sink;)V } public final class io/rsocket/kotlin/metadata/security/BearerAuthMetadata$Reader : io/rsocket/kotlin/metadata/security/AuthMetadataReader { - public synthetic fun readContent-jfyA9PI (Lio/ktor/utils/io/core/ByteReadPacket;Lio/rsocket/kotlin/metadata/security/AuthType;Lio/ktor/utils/io/pool/ObjectPool;)Lio/rsocket/kotlin/metadata/security/AuthMetadata; - public fun readContent-jfyA9PI (Lio/ktor/utils/io/core/ByteReadPacket;Lio/rsocket/kotlin/metadata/security/AuthType;Lio/ktor/utils/io/pool/ObjectPool;)Lio/rsocket/kotlin/metadata/security/BearerAuthMetadata; + public synthetic fun readContent (Lkotlinx/io/Source;Lio/rsocket/kotlin/metadata/security/AuthType;)Lio/rsocket/kotlin/metadata/security/AuthMetadata; + public fun readContent (Lkotlinx/io/Source;Lio/rsocket/kotlin/metadata/security/AuthType;)Lio/rsocket/kotlin/metadata/security/BearerAuthMetadata; } public final class io/rsocket/kotlin/metadata/security/CustomAuthType : io/rsocket/kotlin/metadata/security/AuthTypeWithName { @@ -659,24 +632,22 @@ public final class io/rsocket/kotlin/metadata/security/CustomAuthType : io/rsock public final class io/rsocket/kotlin/metadata/security/RawAuthMetadata : io/rsocket/kotlin/metadata/security/AuthMetadata { public static final field Reader Lio/rsocket/kotlin/metadata/security/RawAuthMetadata$Reader; - public fun (Lio/rsocket/kotlin/metadata/security/AuthType;Lio/ktor/utils/io/core/ByteReadPacket;)V + public fun (Lio/rsocket/kotlin/metadata/security/AuthType;Lkotlinx/io/Source;)V public fun close ()V - public final fun getContent ()Lio/ktor/utils/io/core/ByteReadPacket; + public final fun getContent ()Lkotlinx/io/Source; public fun getType ()Lio/rsocket/kotlin/metadata/security/AuthType; - public fun writeContent (Lio/ktor/utils/io/core/BytePacketBuilder;)V + public fun writeContent (Lkotlinx/io/Sink;)V } public final class io/rsocket/kotlin/metadata/security/RawAuthMetadata$Reader : io/rsocket/kotlin/metadata/security/AuthMetadataReader { - public synthetic fun readContent-jfyA9PI (Lio/ktor/utils/io/core/ByteReadPacket;Lio/rsocket/kotlin/metadata/security/AuthType;Lio/ktor/utils/io/pool/ObjectPool;)Lio/rsocket/kotlin/metadata/security/AuthMetadata; - public fun readContent-jfyA9PI (Lio/ktor/utils/io/core/ByteReadPacket;Lio/rsocket/kotlin/metadata/security/AuthType;Lio/ktor/utils/io/pool/ObjectPool;)Lio/rsocket/kotlin/metadata/security/RawAuthMetadata; + public synthetic fun readContent (Lkotlinx/io/Source;Lio/rsocket/kotlin/metadata/security/AuthType;)Lio/rsocket/kotlin/metadata/security/AuthMetadata; + public fun readContent (Lkotlinx/io/Source;Lio/rsocket/kotlin/metadata/security/AuthType;)Lio/rsocket/kotlin/metadata/security/RawAuthMetadata; } public final class io/rsocket/kotlin/metadata/security/RawAuthMetadataKt { public static final fun hasAuthTypeOf (Lio/rsocket/kotlin/metadata/security/RawAuthMetadata;Lio/rsocket/kotlin/metadata/security/AuthMetadataReader;)Z - public static final fun read-jfyA9PI (Lio/rsocket/kotlin/metadata/security/RawAuthMetadata;Lio/rsocket/kotlin/metadata/security/AuthMetadataReader;Lio/ktor/utils/io/pool/ObjectPool;)Lio/rsocket/kotlin/metadata/security/AuthMetadata; - public static synthetic fun read-jfyA9PI$default (Lio/rsocket/kotlin/metadata/security/RawAuthMetadata;Lio/rsocket/kotlin/metadata/security/AuthMetadataReader;Lio/ktor/utils/io/pool/ObjectPool;ILjava/lang/Object;)Lio/rsocket/kotlin/metadata/security/AuthMetadata; - public static final fun readOrNull-jfyA9PI (Lio/rsocket/kotlin/metadata/security/RawAuthMetadata;Lio/rsocket/kotlin/metadata/security/AuthMetadataReader;Lio/ktor/utils/io/pool/ObjectPool;)Lio/rsocket/kotlin/metadata/security/AuthMetadata; - public static synthetic fun readOrNull-jfyA9PI$default (Lio/rsocket/kotlin/metadata/security/RawAuthMetadata;Lio/rsocket/kotlin/metadata/security/AuthMetadataReader;Lio/ktor/utils/io/pool/ObjectPool;ILjava/lang/Object;)Lio/rsocket/kotlin/metadata/security/AuthMetadata; + public static final fun read (Lio/rsocket/kotlin/metadata/security/RawAuthMetadata;Lio/rsocket/kotlin/metadata/security/AuthMetadataReader;)Lio/rsocket/kotlin/metadata/security/AuthMetadata; + public static final fun readOrNull (Lio/rsocket/kotlin/metadata/security/RawAuthMetadata;Lio/rsocket/kotlin/metadata/security/AuthMetadataReader;)Lio/rsocket/kotlin/metadata/security/AuthMetadata; } public final class io/rsocket/kotlin/metadata/security/ReservedAuthType : io/rsocket/kotlin/metadata/security/AuthTypeWithId { @@ -697,12 +668,12 @@ public final class io/rsocket/kotlin/metadata/security/SimpleAuthMetadata : io/r public final fun getPassword ()Ljava/lang/String; public fun getType ()Lio/rsocket/kotlin/metadata/security/AuthType; public final fun getUsername ()Ljava/lang/String; - public fun writeContent (Lio/ktor/utils/io/core/BytePacketBuilder;)V + public fun writeContent (Lkotlinx/io/Sink;)V } public final class io/rsocket/kotlin/metadata/security/SimpleAuthMetadata$Reader : io/rsocket/kotlin/metadata/security/AuthMetadataReader { - public synthetic fun readContent-jfyA9PI (Lio/ktor/utils/io/core/ByteReadPacket;Lio/rsocket/kotlin/metadata/security/AuthType;Lio/ktor/utils/io/pool/ObjectPool;)Lio/rsocket/kotlin/metadata/security/AuthMetadata; - public fun readContent-jfyA9PI (Lio/ktor/utils/io/core/ByteReadPacket;Lio/rsocket/kotlin/metadata/security/AuthType;Lio/ktor/utils/io/pool/ObjectPool;)Lio/rsocket/kotlin/metadata/security/SimpleAuthMetadata; + public synthetic fun readContent (Lkotlinx/io/Source;Lio/rsocket/kotlin/metadata/security/AuthType;)Lio/rsocket/kotlin/metadata/security/AuthMetadata; + public fun readContent (Lkotlinx/io/Source;Lio/rsocket/kotlin/metadata/security/AuthType;)Lio/rsocket/kotlin/metadata/security/SimpleAuthMetadata; } public final class io/rsocket/kotlin/metadata/security/WellKnowAuthType : java/lang/Enum, io/rsocket/kotlin/metadata/security/AuthTypeWithId, io/rsocket/kotlin/metadata/security/AuthTypeWithName { @@ -722,21 +693,21 @@ public final class io/rsocket/kotlin/metadata/security/WellKnowAuthType$Companio public final fun invoke (Ljava/lang/String;)Lio/rsocket/kotlin/metadata/security/WellKnowAuthType; } -public abstract interface class io/rsocket/kotlin/payload/Payload : java/io/Closeable { +public abstract interface class io/rsocket/kotlin/payload/Payload : java/lang/AutoCloseable { public static final field Companion Lio/rsocket/kotlin/payload/Payload$Companion; public fun close ()V public fun copy ()Lio/rsocket/kotlin/payload/Payload; - public abstract fun getData ()Lio/ktor/utils/io/core/ByteReadPacket; - public abstract fun getMetadata ()Lio/ktor/utils/io/core/ByteReadPacket; + public abstract fun getData ()Lkotlinx/io/Buffer; + public abstract fun getMetadata ()Lkotlinx/io/Buffer; } public final class io/rsocket/kotlin/payload/Payload$Companion { public final fun getEmpty ()Lio/rsocket/kotlin/payload/Payload; } -public abstract interface class io/rsocket/kotlin/payload/PayloadBuilder : java/io/Closeable { - public abstract fun data (Lio/ktor/utils/io/core/ByteReadPacket;)V - public abstract fun metadata (Lio/ktor/utils/io/core/ByteReadPacket;)V +public abstract interface class io/rsocket/kotlin/payload/PayloadBuilder : java/lang/AutoCloseable { + public abstract fun data (Lkotlinx/io/Buffer;)V + public abstract fun metadata (Lkotlinx/io/Buffer;)V } public final class io/rsocket/kotlin/payload/PayloadBuilderKt { @@ -752,15 +723,15 @@ public final class io/rsocket/kotlin/payload/PayloadBuilderKt { public final class io/rsocket/kotlin/payload/PayloadFromBuilder : io/rsocket/kotlin/payload/Payload, io/rsocket/kotlin/payload/PayloadBuilder { public fun ()V public final fun build ()Lio/rsocket/kotlin/payload/Payload; - public fun data (Lio/ktor/utils/io/core/ByteReadPacket;)V - public fun getData ()Lio/ktor/utils/io/core/ByteReadPacket; - public fun getMetadata ()Lio/ktor/utils/io/core/ByteReadPacket; - public fun metadata (Lio/ktor/utils/io/core/ByteReadPacket;)V + public fun data (Lkotlinx/io/Buffer;)V + public fun getData ()Lkotlinx/io/Buffer; + public fun getMetadata ()Lkotlinx/io/Buffer; + public fun metadata (Lkotlinx/io/Buffer;)V } public final class io/rsocket/kotlin/payload/PayloadKt { - public static final fun Payload (Lio/ktor/utils/io/core/ByteReadPacket;Lio/ktor/utils/io/core/ByteReadPacket;)Lio/rsocket/kotlin/payload/Payload; - public static synthetic fun Payload$default (Lio/ktor/utils/io/core/ByteReadPacket;Lio/ktor/utils/io/core/ByteReadPacket;ILjava/lang/Object;)Lio/rsocket/kotlin/payload/Payload; + public static final fun Payload (Lkotlinx/io/Buffer;Lkotlinx/io/Buffer;)Lio/rsocket/kotlin/payload/Payload; + public static synthetic fun Payload$default (Lkotlinx/io/Buffer;Lkotlinx/io/Buffer;ILjava/lang/Object;)Lio/rsocket/kotlin/payload/Payload; } public final class io/rsocket/kotlin/payload/PayloadMimeType { @@ -798,18 +769,18 @@ public abstract interface class io/rsocket/kotlin/transport/RSocketMultiplexedCo public abstract fun createStream (Lkotlin/coroutines/Continuation;)Ljava/lang/Object; } -public abstract interface class io/rsocket/kotlin/transport/RSocketMultiplexedConnection$Stream : java/io/Closeable { +public abstract interface class io/rsocket/kotlin/transport/RSocketMultiplexedConnection$Stream : java/lang/AutoCloseable { public abstract fun close ()V public abstract fun isClosedForSend ()Z public abstract fun receiveFrame (Lkotlin/coroutines/Continuation;)Ljava/lang/Object; - public abstract fun sendFrame (Lio/ktor/utils/io/core/ByteReadPacket;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; + public abstract fun sendFrame (Lkotlinx/io/Buffer;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; public abstract fun setSendPriority (I)V } public abstract interface class io/rsocket/kotlin/transport/RSocketSequentialConnection : io/rsocket/kotlin/transport/RSocketConnection { public abstract fun isClosedForSend ()Z public abstract fun receiveFrame (Lkotlin/coroutines/Continuation;)Ljava/lang/Object; - public abstract fun sendFrame (ILio/ktor/utils/io/core/ByteReadPacket;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; + public abstract fun sendFrame (ILkotlinx/io/Buffer;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; } public abstract interface class io/rsocket/kotlin/transport/RSocketServerInstance : kotlinx/coroutines/CoroutineScope { @@ -845,8 +816,8 @@ public final class io/rsocket/kotlin/transport/internal/PrioritizationFrameQueue public final fun cancel ()V public final fun close ()V public final fun dequeueFrame (Lkotlin/coroutines/Continuation;)Ljava/lang/Object; - public final fun enqueueFrame (ILio/ktor/utils/io/core/ByteReadPacket;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; + public final fun enqueueFrame (ILkotlinx/io/Buffer;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; public final fun isClosedForSend ()Z - public final fun tryDequeueFrame ()Lio/ktor/utils/io/core/ByteReadPacket; + public final fun tryDequeueFrame ()Lkotlinx/io/Buffer; } diff --git a/rsocket-core/build.gradle.kts b/rsocket-core/build.gradle.kts index 1d64b913..87aa8634 100644 --- a/rsocket-core/build.gradle.kts +++ b/rsocket-core/build.gradle.kts @@ -33,7 +33,7 @@ kotlin { implementation(projects.rsocketInternalIo) api(libs.kotlinx.coroutines.core) - api(libs.ktor.io) + api(libs.kotlinx.io.core) } commonTest.dependencies { implementation(projects.rsocketTest) diff --git a/rsocket-core/src/commonMain/kotlin/io/rsocket/kotlin/Connection.kt b/rsocket-core/src/commonMain/kotlin/io/rsocket/kotlin/Connection.kt index 7bff4e83..74f073ce 100644 --- a/rsocket-core/src/commonMain/kotlin/io/rsocket/kotlin/Connection.kt +++ b/rsocket-core/src/commonMain/kotlin/io/rsocket/kotlin/Connection.kt @@ -16,11 +16,11 @@ package io.rsocket.kotlin -import io.ktor.utils.io.core.* import kotlinx.coroutines.* +import kotlinx.io.* @Deprecated(level = DeprecationLevel.ERROR, message = "Deprecated in favor of new Transport API") public interface Connection : CoroutineScope { - public suspend fun send(packet: ByteReadPacket) - public suspend fun receive(): ByteReadPacket + public suspend fun send(packet: Buffer) + public suspend fun receive(): Buffer } diff --git a/rsocket-core/src/commonMain/kotlin/io/rsocket/kotlin/RSocket.kt b/rsocket-core/src/commonMain/kotlin/io/rsocket/kotlin/RSocket.kt index d42cd322..1c84c050 100644 --- a/rsocket-core/src/commonMain/kotlin/io/rsocket/kotlin/RSocket.kt +++ b/rsocket-core/src/commonMain/kotlin/io/rsocket/kotlin/RSocket.kt @@ -1,5 +1,5 @@ /* - * Copyright 2015-2022 the original author or authors. + * Copyright 2015-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,15 +16,17 @@ package io.rsocket.kotlin -import io.ktor.utils.io.core.* +import io.rsocket.kotlin.frame.io.* import io.rsocket.kotlin.payload.* import kotlinx.coroutines.* +import kotlinx.coroutines.channels.* import kotlinx.coroutines.flow.* +import kotlinx.io.* public interface RSocket : CoroutineScope { - public suspend fun metadataPush(metadata: ByteReadPacket) { - metadata.close() + public suspend fun metadataPush(metadata: Buffer) { + metadata.clear() notImplemented("Metadata Push") } @@ -55,7 +57,7 @@ private fun notImplemented(operation: String): Nothing = throw NotImplementedErr * Tries to emit [value], if emit failed, f.e. due cancellation, calls [Closeable.close] on [value]. * Better to use it instead of [FlowCollector.emit] with [Payload] or [ByteReadPacket] to avoid leaks of dropped elements. */ -public suspend fun FlowCollector.emitOrClose(value: C) { +public suspend fun FlowCollector.emitOrClose(value: C) { try { return emit(value) } catch (e: Throwable) { diff --git a/rsocket-core/src/commonMain/kotlin/io/rsocket/kotlin/RSocketRequestHandler.kt b/rsocket-core/src/commonMain/kotlin/io/rsocket/kotlin/RSocketRequestHandler.kt index 2e8a2fa7..c68b6d1d 100644 --- a/rsocket-core/src/commonMain/kotlin/io/rsocket/kotlin/RSocketRequestHandler.kt +++ b/rsocket-core/src/commonMain/kotlin/io/rsocket/kotlin/RSocketRequestHandler.kt @@ -1,5 +1,5 @@ /* - * Copyright 2015-2022 the original author or authors. + * Copyright 2015-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,21 +16,21 @@ package io.rsocket.kotlin -import io.ktor.utils.io.core.* import io.rsocket.kotlin.payload.* import kotlinx.coroutines.* import kotlinx.coroutines.flow.* +import kotlinx.io.* import kotlin.coroutines.* public class RSocketRequestHandlerBuilder internal constructor() { - private var metadataPush: (suspend RSocket.(metadata: ByteReadPacket) -> Unit)? = null + private var metadataPush: (suspend RSocket.(metadata: Buffer) -> Unit)? = null private var fireAndForget: (suspend RSocket.(payload: Payload) -> Unit)? = null private var requestResponse: (suspend RSocket.(payload: Payload) -> Payload)? = null private var requestStream: (suspend RSocket.(payload: Payload) -> Flow)? = null private var requestChannel: (suspend RSocket.(initPayload: Payload, payloads: Flow) -> Flow)? = null - public fun metadataPush(block: (suspend RSocket.(metadata: ByteReadPacket) -> Unit)) { + public fun metadataPush(block: (suspend RSocket.(metadata: Source) -> Unit)) { check(metadataPush == null) { "Metadata Push handler already configured" } metadataPush = block } @@ -78,13 +78,13 @@ public fun RSocketRequestHandler( private class RSocketRequestHandler( override val coroutineContext: CoroutineContext, - private val metadataPush: (suspend RSocket.(metadata: ByteReadPacket) -> Unit)? = null, + private val metadataPush: (suspend RSocket.(metadata: Buffer) -> Unit)? = null, private val fireAndForget: (suspend RSocket.(payload: Payload) -> Unit)? = null, private val requestResponse: (suspend RSocket.(payload: Payload) -> Payload)? = null, private val requestStream: (suspend RSocket.(payload: Payload) -> Flow)? = null, private val requestChannel: (suspend RSocket.(initPayload: Payload, payloads: Flow) -> Flow)? = null, ) : RSocket { - override suspend fun metadataPush(metadata: ByteReadPacket): Unit = + override suspend fun metadataPush(metadata: Buffer): Unit = metadataPush?.invoke(this, metadata) ?: super.metadataPush(metadata) override suspend fun fireAndForget(payload: Payload): Unit = diff --git a/rsocket-core/src/commonMain/kotlin/io/rsocket/kotlin/connection/Connection.kt b/rsocket-core/src/commonMain/kotlin/io/rsocket/kotlin/connection/Connection.kt index 27492d98..bc262862 100644 --- a/rsocket-core/src/commonMain/kotlin/io/rsocket/kotlin/connection/Connection.kt +++ b/rsocket-core/src/commonMain/kotlin/io/rsocket/kotlin/connection/Connection.kt @@ -16,7 +16,6 @@ package io.rsocket.kotlin.connection -import io.ktor.utils.io.core.* import io.rsocket.kotlin.* import io.rsocket.kotlin.frame.* import io.rsocket.kotlin.internal.* @@ -26,6 +25,7 @@ import io.rsocket.kotlin.payload.* import io.rsocket.kotlin.transport.* import kotlinx.coroutines.* import kotlinx.coroutines.flow.* +import kotlinx.io.* import kotlin.coroutines.* // TODO: rename to just `Connection` after root `Connection` will be dropped @@ -34,7 +34,7 @@ internal abstract class Connection2( protected val frameCodec: FrameCodec, // requestContext final override val coroutineContext: CoroutineContext, -) : RSocket, Closeable { +) : RSocket, AutoCloseable { // connection establishment part @@ -45,30 +45,30 @@ internal abstract class Connection2( // connection part - protected abstract suspend fun sendConnectionFrame(frame: ByteReadPacket) + protected abstract suspend fun sendConnectionFrame(frame: Buffer) private suspend fun sendConnectionFrame(frame: Frame): Unit = sendConnectionFrame(frameCodec.encodeFrame(frame)) suspend fun sendError(cause: Throwable) { sendConnectionFrame(ErrorFrame(0, cause)) } - private suspend fun sendMetadataPush(metadata: ByteReadPacket) { + private suspend fun sendMetadataPush(metadata: Buffer) { sendConnectionFrame(MetadataPushFrame(metadata)) } - suspend fun sendKeepAlive(respond: Boolean, data: ByteReadPacket, lastPosition: Long) { + suspend fun sendKeepAlive(respond: Boolean, data: Buffer, lastPosition: Long) { sendConnectionFrame(KeepAliveFrame(respond, lastPosition, data)) } // operations part protected abstract fun launchRequest(requestPayload: Payload, operation: RequesterOperation): Job - private suspend fun ensureActiveOrClose(closeable: Closeable) { + private suspend fun ensureActiveOrClose(closeable: AutoCloseable) { currentCoroutineContext().ensureActive { closeable.close() } coroutineContext.ensureActive { closeable.close() } } - final override suspend fun metadataPush(metadata: ByteReadPacket) { + final override suspend fun metadataPush(metadata: Buffer) { ensureActiveOrClose(metadata) sendMetadataPush(metadata) } diff --git a/rsocket-core/src/commonMain/kotlin/io/rsocket/kotlin/connection/ConnectionEstablishmentContext.kt b/rsocket-core/src/commonMain/kotlin/io/rsocket/kotlin/connection/ConnectionEstablishmentContext.kt index 0ff8ed5c..33b739d7 100644 --- a/rsocket-core/src/commonMain/kotlin/io/rsocket/kotlin/connection/ConnectionEstablishmentContext.kt +++ b/rsocket-core/src/commonMain/kotlin/io/rsocket/kotlin/connection/ConnectionEstablishmentContext.kt @@ -16,20 +16,20 @@ package io.rsocket.kotlin.connection -import io.ktor.utils.io.core.* import io.rsocket.kotlin.frame.* import io.rsocket.kotlin.frame.io.* import io.rsocket.kotlin.keepalive.* import io.rsocket.kotlin.payload.* import io.rsocket.kotlin.transport.* +import kotlinx.io.* // send/receive setup, resume, resume ok, lease, error @RSocketTransportApi internal abstract class ConnectionEstablishmentContext( private val frameCodec: FrameCodec, ) { - protected abstract suspend fun receiveFrameRaw(): ByteReadPacket? - protected abstract suspend fun sendFrame(frame: ByteReadPacket) + protected abstract suspend fun receiveFrameRaw(): Buffer? + protected abstract suspend fun sendFrame(frame: Buffer) private suspend fun sendFrame(frame: Frame): Unit = sendFrame(frameCodec.encodeFrame(frame)) // only setup|lease|resume|resume_ok|error frames @@ -42,7 +42,7 @@ internal abstract class ConnectionEstablishmentContext( version: Version, honorLease: Boolean, keepAlive: KeepAlive, - resumeToken: ByteReadPacket?, + resumeToken: Buffer?, payloadMimeType: PayloadMimeType, payload: Payload, ): Unit = sendFrame(SetupFrame(version, honorLease, keepAlive, resumeToken, payloadMimeType, payload)) diff --git a/rsocket-core/src/commonMain/kotlin/io/rsocket/kotlin/connection/ConnectionInbound.kt b/rsocket-core/src/commonMain/kotlin/io/rsocket/kotlin/connection/ConnectionInbound.kt index 9d584bc0..e023848d 100644 --- a/rsocket-core/src/commonMain/kotlin/io/rsocket/kotlin/connection/ConnectionInbound.kt +++ b/rsocket-core/src/commonMain/kotlin/io/rsocket/kotlin/connection/ConnectionInbound.kt @@ -16,13 +16,13 @@ package io.rsocket.kotlin.connection -import io.ktor.utils.io.core.* import io.rsocket.kotlin.* import io.rsocket.kotlin.frame.* import io.rsocket.kotlin.keepalive.* import io.rsocket.kotlin.operation.* import io.rsocket.kotlin.transport.* import kotlinx.coroutines.* +import kotlinx.io.* import kotlin.coroutines.* @RSocketTransportApi @@ -41,19 +41,19 @@ internal class ConnectionInbound( else -> frame.close() } - private fun receiveMetadataPush(metadata: ByteReadPacket) { + private fun receiveMetadataPush(metadata: Buffer) { launch { responder.metadataPush(metadata) }.invokeOnCompletion { metadata.close() } } @Suppress("UNUSED_PARAMETER") // will be used later - private fun receiveKeepAlive(respond: Boolean, data: ByteReadPacket, lastPosition: Long) { + private fun receiveKeepAlive(respond: Boolean, data: Buffer, lastPosition: Long) { keepAliveHandler.receive(data, respond) } @Suppress("UNUSED_PARAMETER") // will be used later - private fun receiveLease(ttl: Int, numberOfRequests: Int, metadata: ByteReadPacket?) { + private fun receiveLease(ttl: Int, numberOfRequests: Int, metadata: Buffer?) { metadata?.close() error("Lease is not supported") } diff --git a/rsocket-core/src/commonMain/kotlin/io/rsocket/kotlin/connection/LoggingConnection.kt b/rsocket-core/src/commonMain/kotlin/io/rsocket/kotlin/connection/LoggingConnection.kt index 8040bb8c..e3294ed8 100644 --- a/rsocket-core/src/commonMain/kotlin/io/rsocket/kotlin/connection/LoggingConnection.kt +++ b/rsocket-core/src/commonMain/kotlin/io/rsocket/kotlin/connection/LoggingConnection.kt @@ -16,23 +16,22 @@ package io.rsocket.kotlin.connection -import io.ktor.utils.io.core.* import io.rsocket.kotlin.* import io.rsocket.kotlin.frame.* -import io.rsocket.kotlin.internal.* import io.rsocket.kotlin.logging.* import io.rsocket.kotlin.transport.* +import kotlinx.io.* @RSocketLoggingApi @RSocketTransportApi -internal fun RSocketConnectionHandler.logging(logger: Logger, bufferPool: BufferPool): RSocketConnectionHandler { +internal fun RSocketConnectionHandler.logging(logger: Logger): RSocketConnectionHandler { if (!logger.isLoggable(LoggingLevel.DEBUG)) return this return RSocketConnectionHandler { handleConnection( when (it) { - is RSocketSequentialConnection -> SequentialLoggingConnection(it, logger, bufferPool) - is RSocketMultiplexedConnection -> MultiplexedLoggingConnection(it, logger, bufferPool) + is RSocketSequentialConnection -> SequentialLoggingConnection(it, logger) + is RSocketMultiplexedConnection -> MultiplexedLoggingConnection(it, logger) } ) } @@ -43,26 +42,25 @@ internal fun RSocketConnectionHandler.logging(logger: Logger, bufferPool: Buffer private class SequentialLoggingConnection( private val delegate: RSocketSequentialConnection, private val logger: Logger, - private val bufferPool: BufferPool, ) : RSocketSequentialConnection { override val isClosedForSend: Boolean get() = delegate.isClosedForSend - override suspend fun sendFrame(streamId: Int, frame: ByteReadPacket) { - logger.debug { "Send: ${dumpFrameToString(frame, bufferPool)}" } + override suspend fun sendFrame(streamId: Int, frame: Buffer) { + logger.debug { "Send: ${dumpFrameToString(frame)}" } delegate.sendFrame(streamId, frame) } - override suspend fun receiveFrame(): ByteReadPacket? { + override suspend fun receiveFrame(): Buffer? { return delegate.receiveFrame()?.also { frame -> - logger.debug { "Receive: ${dumpFrameToString(frame, bufferPool)}" } + logger.debug { "Receive: ${dumpFrameToString(frame)}" } } } } -private fun dumpFrameToString(frame: ByteReadPacket, bufferPool: BufferPool): String { - val length = frame.remaining - return frame.copy().use { it.readFrame(bufferPool).use { it.dump(length) } } +private fun dumpFrameToString(frame: Buffer): String { + val length = frame.size + return frame.copy().readFrame().use { it.dump(length) } } @RSocketLoggingApi @@ -70,15 +68,14 @@ private fun dumpFrameToString(frame: ByteReadPacket, bufferPool: BufferPool): St private class MultiplexedLoggingConnection( private val delegate: RSocketMultiplexedConnection, private val logger: Logger, - private val bufferPool: BufferPool, ) : RSocketMultiplexedConnection { override suspend fun createStream(): RSocketMultiplexedConnection.Stream { - return MultiplexedLoggingStream(delegate.createStream(), logger, bufferPool) + return MultiplexedLoggingStream(delegate.createStream(), logger) } override suspend fun acceptStream(): RSocketMultiplexedConnection.Stream? { return delegate.acceptStream()?.let { - MultiplexedLoggingStream(it, logger, bufferPool) + MultiplexedLoggingStream(it, logger) } } } @@ -88,7 +85,6 @@ private class MultiplexedLoggingConnection( private class MultiplexedLoggingStream( private val delegate: RSocketMultiplexedConnection.Stream, private val logger: Logger, - private val bufferPool: BufferPool, ) : RSocketMultiplexedConnection.Stream { override val isClosedForSend: Boolean get() = delegate.isClosedForSend @@ -96,14 +92,14 @@ private class MultiplexedLoggingStream( delegate.setSendPriority(priority) } - override suspend fun sendFrame(frame: ByteReadPacket) { - logger.debug { "Send: ${dumpFrameToString(frame, bufferPool)}" } + override suspend fun sendFrame(frame: Buffer) { + logger.debug { "Send: ${dumpFrameToString(frame)}" } delegate.sendFrame(frame) } - override suspend fun receiveFrame(): ByteReadPacket? { + override suspend fun receiveFrame(): Buffer? { return delegate.receiveFrame()?.also { frame -> - logger.debug { "Receive: ${dumpFrameToString(frame, bufferPool)}" } + logger.debug { "Receive: ${dumpFrameToString(frame)}" } } } diff --git a/rsocket-core/src/commonMain/kotlin/io/rsocket/kotlin/connection/MultiplexedConnection.kt b/rsocket-core/src/commonMain/kotlin/io/rsocket/kotlin/connection/MultiplexedConnection.kt index ebc37c5f..11ac0b90 100644 --- a/rsocket-core/src/commonMain/kotlin/io/rsocket/kotlin/connection/MultiplexedConnection.kt +++ b/rsocket-core/src/commonMain/kotlin/io/rsocket/kotlin/connection/MultiplexedConnection.kt @@ -16,7 +16,6 @@ package io.rsocket.kotlin.connection -import io.ktor.utils.io.core.* import io.rsocket.kotlin.* import io.rsocket.kotlin.frame.* import io.rsocket.kotlin.internal.* @@ -24,6 +23,7 @@ import io.rsocket.kotlin.operation.* import io.rsocket.kotlin.payload.* import io.rsocket.kotlin.transport.* import kotlinx.coroutines.* +import kotlinx.io.* import kotlin.coroutines.* @RSocketTransportApi @@ -45,8 +45,8 @@ internal class MultiplexedConnection( } private inner class EstablishmentContext : ConnectionEstablishmentContext(frameCodec) { - override suspend fun sendFrame(frame: ByteReadPacket): Unit = initialStream.sendFrame(frame) - override suspend fun receiveFrameRaw(): ByteReadPacket? = initialStream.receiveFrame() + override suspend fun sendFrame(frame: Buffer): Unit = initialStream.sendFrame(frame) + override suspend fun receiveFrameRaw(): Buffer? = initialStream.receiveFrame() } override suspend fun handleConnection(inbound: ConnectionInbound) = coroutineScope { @@ -63,11 +63,11 @@ internal class MultiplexedConnection( while (true) if (!acceptRequest(inbound)) break } - override suspend fun sendConnectionFrame(frame: ByteReadPacket) { + override suspend fun sendConnectionFrame(frame: Buffer) { initialStream.sendFrame(frame) } - @OptIn(ExperimentalCoroutinesApi::class) + @OptIn(DelicateCoroutinesApi::class) override fun launchRequest( requestPayload: Payload, operation: RequesterOperation, @@ -85,7 +85,7 @@ internal class MultiplexedConnection( } } - @OptIn(ExperimentalCoroutinesApi::class) + @OptIn(DelicateCoroutinesApi::class) private fun acceptRequest( connectionInbound: ConnectionInbound, stream: RSocketMultiplexedConnection.Stream, @@ -227,7 +227,7 @@ internal class MultiplexedConnection( private val stream: RSocketMultiplexedConnection.Stream, ) : OperationOutbound(streamId, frameCodec) { override val isClosed: Boolean get() = stream.isClosedForSend - override suspend fun sendFrame(frame: ByteReadPacket): Unit = stream.sendFrame(frame) + override suspend fun sendFrame(frame: Buffer): Unit = stream.sendFrame(frame) } } diff --git a/rsocket-core/src/commonMain/kotlin/io/rsocket/kotlin/connection/OldConnection.kt b/rsocket-core/src/commonMain/kotlin/io/rsocket/kotlin/connection/OldConnection.kt index 48e7cd98..ee3652d5 100644 --- a/rsocket-core/src/commonMain/kotlin/io/rsocket/kotlin/connection/OldConnection.kt +++ b/rsocket-core/src/commonMain/kotlin/io/rsocket/kotlin/connection/OldConnection.kt @@ -16,13 +16,13 @@ package io.rsocket.kotlin.connection -import io.ktor.utils.io.core.* import io.rsocket.kotlin.* import io.rsocket.kotlin.internal.io.* import io.rsocket.kotlin.transport.* import io.rsocket.kotlin.transport.internal.* import kotlinx.coroutines.* import kotlinx.coroutines.channels.* +import kotlinx.io.* @Suppress("DEPRECATION_ERROR") @RSocketTransportApi @@ -51,11 +51,11 @@ private class OldConnection( ) : RSocketSequentialConnection { override val isClosedForSend: Boolean get() = outboundQueue.isClosedForSend - override suspend fun sendFrame(streamId: Int, frame: ByteReadPacket) { + override suspend fun sendFrame(streamId: Int, frame: Buffer) { return outboundQueue.enqueueFrame(streamId, frame) } - override suspend fun receiveFrame(): ByteReadPacket? = try { + override suspend fun receiveFrame(): Buffer? = try { connection.receive() } catch (cause: Throwable) { currentCoroutineContext().ensureActive() diff --git a/rsocket-core/src/commonMain/kotlin/io/rsocket/kotlin/connection/SequentialConnection.kt b/rsocket-core/src/commonMain/kotlin/io/rsocket/kotlin/connection/SequentialConnection.kt index 398d5e56..e3739842 100644 --- a/rsocket-core/src/commonMain/kotlin/io/rsocket/kotlin/connection/SequentialConnection.kt +++ b/rsocket-core/src/commonMain/kotlin/io/rsocket/kotlin/connection/SequentialConnection.kt @@ -16,13 +16,13 @@ package io.rsocket.kotlin.connection -import io.ktor.utils.io.core.* import io.rsocket.kotlin.* import io.rsocket.kotlin.frame.* import io.rsocket.kotlin.operation.* import io.rsocket.kotlin.payload.* import io.rsocket.kotlin.transport.* import kotlinx.coroutines.* +import kotlinx.io.* import kotlin.coroutines.* @RSocketTransportApi @@ -43,8 +43,8 @@ internal class SequentialConnection( } private inner class EstablishmentContext : ConnectionEstablishmentContext(frameCodec) { - override suspend fun sendFrame(frame: ByteReadPacket): Unit = connection.sendFrame(streamId = 0, frame) - override suspend fun receiveFrameRaw(): ByteReadPacket? = connection.receiveFrame() + override suspend fun sendFrame(frame: Buffer): Unit = connection.sendFrame(streamId = 0, frame) + override suspend fun receiveFrameRaw(): Buffer? = connection.receiveFrame() } override suspend fun handleConnection(inbound: ConnectionInbound) { @@ -59,11 +59,11 @@ internal class SequentialConnection( } } - override suspend fun sendConnectionFrame(frame: ByteReadPacket) { + override suspend fun sendConnectionFrame(frame: Buffer) { connection.sendFrame(0, frame) } - @OptIn(ExperimentalCoroutinesApi::class) + @OptIn(DelicateCoroutinesApi::class) override fun launchRequest( requestPayload: Payload, operation: RequesterOperation, @@ -79,7 +79,7 @@ internal class SequentialConnection( } } - @OptIn(ExperimentalCoroutinesApi::class) + @OptIn(DelicateCoroutinesApi::class) private fun acceptRequest( connectionInbound: ConnectionInbound, operationData: ResponderOperationData, @@ -145,7 +145,7 @@ internal class SequentialConnection( private inner class Outbound(streamId: Int) : OperationOutbound(streamId, frameCodec) { override val isClosed: Boolean get() = !isActive || connection.isClosedForSend - override suspend fun sendFrame(frame: ByteReadPacket): Unit = connection.sendFrame(streamId, frame) + override suspend fun sendFrame(frame: Buffer): Unit = connection.sendFrame(streamId, frame) } private inner class ResponderInboundWrapper( diff --git a/rsocket-core/src/commonMain/kotlin/io/rsocket/kotlin/core/RSocketConnector.kt b/rsocket-core/src/commonMain/kotlin/io/rsocket/kotlin/core/RSocketConnector.kt index 9e560dad..61300dd9 100644 --- a/rsocket-core/src/commonMain/kotlin/io/rsocket/kotlin/core/RSocketConnector.kt +++ b/rsocket-core/src/commonMain/kotlin/io/rsocket/kotlin/core/RSocketConnector.kt @@ -20,7 +20,6 @@ import io.rsocket.kotlin.* import io.rsocket.kotlin.connection.* import io.rsocket.kotlin.frame.* import io.rsocket.kotlin.frame.io.* -import io.rsocket.kotlin.internal.* import io.rsocket.kotlin.internal.io.* import io.rsocket.kotlin.logging.* import io.rsocket.kotlin.transport.* @@ -35,7 +34,6 @@ public class RSocketConnector internal constructor( private val connectionConfigProvider: () -> ConnectionConfig, private val acceptor: ConnectionAcceptor, private val reconnectPredicate: ReconnectPredicate?, - private val bufferPool: BufferPool, ) { private val connectionLogger = loggerFactory.logger("io.rsocket.kotlin.connection") private val frameLogger = loggerFactory.logger("io.rsocket.kotlin.frame") @@ -62,7 +60,7 @@ public class RSocketConnector internal constructor( private suspend fun connectOnce(transport: RSocketClientTarget): RSocket { val requesterDeferred = CompletableDeferred() val connectJob = transport.connectClient( - SetupConnection(requesterDeferred).logging(frameLogger, bufferPool) + SetupConnection(requesterDeferred).logging(frameLogger) ).onCompletion { if (it != null) requesterDeferred.completeExceptionally(it) } return try { requesterDeferred.await() @@ -74,7 +72,7 @@ public class RSocketConnector internal constructor( private inner class SetupConnection(requesterDeferred: CompletableDeferred) : ConnectionEstablishmentHandler( isClient = true, - frameCodec = FrameCodec(bufferPool, maxFragmentSize), + frameCodec = FrameCodec(maxFragmentSize), connectionAcceptor = acceptor, interceptors = interceptors, requesterDeferred = requesterDeferred diff --git a/rsocket-core/src/commonMain/kotlin/io/rsocket/kotlin/core/RSocketConnectorBuilder.kt b/rsocket-core/src/commonMain/kotlin/io/rsocket/kotlin/core/RSocketConnectorBuilder.kt index cef8884b..ac561ba0 100644 --- a/rsocket-core/src/commonMain/kotlin/io/rsocket/kotlin/core/RSocketConnectorBuilder.kt +++ b/rsocket-core/src/commonMain/kotlin/io/rsocket/kotlin/core/RSocketConnectorBuilder.kt @@ -17,7 +17,6 @@ package io.rsocket.kotlin.core import io.rsocket.kotlin.* -import io.rsocket.kotlin.internal.* import io.rsocket.kotlin.keepalive.* import io.rsocket.kotlin.logging.* import io.rsocket.kotlin.payload.* @@ -35,9 +34,6 @@ public class RSocketConnectorBuilder internal constructor() { field = value } - @Deprecated("Only for tests in rsocket", level = DeprecationLevel.ERROR) - public var bufferPool: BufferPool = BufferPool.Default - private val connectionConfig: ConnectionConfigBuilder = ConnectionConfigBuilder() private val interceptors: InterceptorsBuilder = InterceptorsBuilder() private var acceptor: ConnectionAcceptor? = null @@ -112,7 +108,6 @@ public class RSocketConnectorBuilder internal constructor() { connectionConfig.producer(), acceptor ?: defaultAcceptor, reconnectPredicate, - @Suppress("DEPRECATION_ERROR") bufferPool ) private companion object { diff --git a/rsocket-core/src/commonMain/kotlin/io/rsocket/kotlin/core/RSocketServer.kt b/rsocket-core/src/commonMain/kotlin/io/rsocket/kotlin/core/RSocketServer.kt index b4540651..225de22c 100644 --- a/rsocket-core/src/commonMain/kotlin/io/rsocket/kotlin/core/RSocketServer.kt +++ b/rsocket-core/src/commonMain/kotlin/io/rsocket/kotlin/core/RSocketServer.kt @@ -20,7 +20,6 @@ import io.rsocket.kotlin.* import io.rsocket.kotlin.connection.* import io.rsocket.kotlin.frame.* import io.rsocket.kotlin.frame.io.* -import io.rsocket.kotlin.internal.* import io.rsocket.kotlin.logging.* import io.rsocket.kotlin.transport.* import kotlinx.coroutines.* @@ -30,7 +29,6 @@ public class RSocketServer internal constructor( loggerFactory: LoggerFactory, private val maxFragmentSize: Int, private val interceptors: Interceptors, - private val bufferPool: BufferPool, ) { private val frameLogger = loggerFactory.logger("io.rsocket.kotlin.frame") @@ -64,11 +62,11 @@ public class RSocketServer internal constructor( @RSocketTransportApi public fun createHandler(acceptor: ConnectionAcceptor): RSocketConnectionHandler = - AcceptConnection(acceptor).logging(frameLogger, bufferPool) + AcceptConnection(acceptor).logging(frameLogger) private inner class AcceptConnection(acceptor: ConnectionAcceptor) : ConnectionEstablishmentHandler( isClient = false, - frameCodec = FrameCodec(bufferPool, maxFragmentSize), + frameCodec = FrameCodec(maxFragmentSize), connectionAcceptor = acceptor, interceptors = interceptors, requesterDeferred = null diff --git a/rsocket-core/src/commonMain/kotlin/io/rsocket/kotlin/core/RSocketServerBuilder.kt b/rsocket-core/src/commonMain/kotlin/io/rsocket/kotlin/core/RSocketServerBuilder.kt index 2cb1c527..d326e31b 100644 --- a/rsocket-core/src/commonMain/kotlin/io/rsocket/kotlin/core/RSocketServerBuilder.kt +++ b/rsocket-core/src/commonMain/kotlin/io/rsocket/kotlin/core/RSocketServerBuilder.kt @@ -17,7 +17,6 @@ package io.rsocket.kotlin.core import io.rsocket.kotlin.* -import io.rsocket.kotlin.internal.* import io.rsocket.kotlin.logging.* public class RSocketServerBuilder internal constructor() { @@ -31,9 +30,6 @@ public class RSocketServerBuilder internal constructor() { field = value } - @Deprecated("Only for tests in rsocket", level = DeprecationLevel.ERROR) - public var bufferPool: BufferPool = BufferPool.Default - private val interceptors: InterceptorsBuilder = InterceptorsBuilder() public fun interceptors(configure: InterceptorsBuilder.() -> Unit) { @@ -45,7 +41,6 @@ public class RSocketServerBuilder internal constructor() { loggerFactory, maxFragmentSize, interceptors.build(), - @Suppress("DEPRECATION_ERROR") bufferPool ) } diff --git a/rsocket-core/src/commonMain/kotlin/io/rsocket/kotlin/core/ReconnectableRSocket.kt b/rsocket-core/src/commonMain/kotlin/io/rsocket/kotlin/core/ReconnectableRSocket.kt index 6968654e..c83484e6 100644 --- a/rsocket-core/src/commonMain/kotlin/io/rsocket/kotlin/core/ReconnectableRSocket.kt +++ b/rsocket-core/src/commonMain/kotlin/io/rsocket/kotlin/core/ReconnectableRSocket.kt @@ -16,12 +16,12 @@ package io.rsocket.kotlin.core -import io.ktor.utils.io.core.* import io.rsocket.kotlin.* import io.rsocket.kotlin.logging.* import io.rsocket.kotlin.payload.* import kotlinx.coroutines.* import kotlinx.coroutines.flow.* +import kotlinx.io.* import kotlin.coroutines.* internal typealias ReconnectPredicate = suspend (cause: Throwable, attempt: Long) -> Boolean @@ -87,11 +87,20 @@ private class ReconnectableRSocket( suspend fun currentRSocket(): RSocket = state.value.current() ?: state.mapNotNull { it.current() }.first() - private suspend fun currentRSocket(closeable: Closeable): RSocket { + private suspend fun currentRSocket(metadata: Buffer): RSocket { return try { currentRSocket() } catch (cause: Throwable) { - closeable.close() + metadata.clear() + throw cause + } + } + + private suspend fun currentRSocket(payload: Payload): RSocket { + return try { + currentRSocket() + } catch (cause: Throwable) { + payload.close() throw cause } } @@ -102,7 +111,7 @@ private class ReconnectableRSocket( ReconnectState.Connecting -> null //reconnection } - override suspend fun metadataPush(metadata: ByteReadPacket): Unit = + override suspend fun metadataPush(metadata: Buffer): Unit = currentRSocket(metadata).metadataPush(metadata) override suspend fun fireAndForget(payload: Payload): Unit = diff --git a/rsocket-core/src/commonMain/kotlin/io/rsocket/kotlin/frame/CancelFrame.kt b/rsocket-core/src/commonMain/kotlin/io/rsocket/kotlin/frame/CancelFrame.kt index 19cae8f7..e8822046 100644 --- a/rsocket-core/src/commonMain/kotlin/io/rsocket/kotlin/frame/CancelFrame.kt +++ b/rsocket-core/src/commonMain/kotlin/io/rsocket/kotlin/frame/CancelFrame.kt @@ -1,5 +1,5 @@ /* - * Copyright 2015-2022 the original author or authors. + * Copyright 2015-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,7 +16,7 @@ package io.rsocket.kotlin.frame -import io.ktor.utils.io.core.* +import kotlinx.io.* internal class CancelFrame( override val streamId: Int @@ -26,7 +26,7 @@ internal class CancelFrame( override fun close(): Unit = Unit - override fun BytePacketBuilder.writeSelf(): Unit = Unit + override fun Sink.writeSelf(): Unit = Unit override fun StringBuilder.appendFlags(): Unit = Unit override fun StringBuilder.appendSelf(): Unit = Unit diff --git a/rsocket-core/src/commonMain/kotlin/io/rsocket/kotlin/frame/ErrorFrame.kt b/rsocket-core/src/commonMain/kotlin/io/rsocket/kotlin/frame/ErrorFrame.kt index 104b685c..8c5fc06e 100644 --- a/rsocket-core/src/commonMain/kotlin/io/rsocket/kotlin/frame/ErrorFrame.kt +++ b/rsocket-core/src/commonMain/kotlin/io/rsocket/kotlin/frame/ErrorFrame.kt @@ -1,5 +1,5 @@ /* - * Copyright 2015-2022 the original author or authors. + * Copyright 2015-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,8 +16,8 @@ package io.rsocket.kotlin.frame -import io.ktor.utils.io.core.* import io.rsocket.kotlin.* +import kotlinx.io.* internal class ErrorFrame( override val streamId: Int, @@ -29,9 +29,9 @@ internal class ErrorFrame( override fun close(): Unit = Unit - override fun BytePacketBuilder.writeSelf() { + override fun Sink.writeSelf() { writeInt(errorCode) - writeText(throwable.message ?: "") + writeString(throwable.message ?: "") } override fun StringBuilder.appendFlags(): Unit = Unit @@ -41,8 +41,8 @@ internal class ErrorFrame( } } -internal fun ByteReadPacket.readError(streamId: Int): ErrorFrame { +internal fun Source.readError(streamId: Int): ErrorFrame { val errorCode = readInt() - val message = readText() + val message = readString() return ErrorFrame(streamId, RSocketError(streamId, errorCode, message)) } diff --git a/rsocket-core/src/commonMain/kotlin/io/rsocket/kotlin/frame/ExtensionFrame.kt b/rsocket-core/src/commonMain/kotlin/io/rsocket/kotlin/frame/ExtensionFrame.kt index 1cd7d6a4..b797656e 100644 --- a/rsocket-core/src/commonMain/kotlin/io/rsocket/kotlin/frame/ExtensionFrame.kt +++ b/rsocket-core/src/commonMain/kotlin/io/rsocket/kotlin/frame/ExtensionFrame.kt @@ -16,10 +16,9 @@ package io.rsocket.kotlin.frame -import io.ktor.utils.io.core.* import io.rsocket.kotlin.frame.io.* -import io.rsocket.kotlin.internal.* import io.rsocket.kotlin.payload.* +import kotlinx.io.* internal class ExtensionFrame( override val streamId: Int, @@ -33,7 +32,7 @@ internal class ExtensionFrame( payload.close() } - override fun BytePacketBuilder.writeSelf() { + override fun Sink.writeSelf() { writeInt(extendedType) writePayload(payload) } @@ -48,8 +47,8 @@ internal class ExtensionFrame( } } -internal fun ByteReadPacket.readExtension(pool: BufferPool, streamId: Int, flags: Int): ExtensionFrame { +internal fun Source.readExtension(streamId: Int, flags: Int): ExtensionFrame { val extendedType = readInt() - val payload = readPayload(pool, flags) + val payload = readPayload(flags) return ExtensionFrame(streamId, extendedType, payload) } diff --git a/rsocket-core/src/commonMain/kotlin/io/rsocket/kotlin/frame/Frame.kt b/rsocket-core/src/commonMain/kotlin/io/rsocket/kotlin/frame/Frame.kt index a24f2a4b..66b8584e 100644 --- a/rsocket-core/src/commonMain/kotlin/io/rsocket/kotlin/frame/Frame.kt +++ b/rsocket-core/src/commonMain/kotlin/io/rsocket/kotlin/frame/Frame.kt @@ -16,25 +16,24 @@ package io.rsocket.kotlin.frame -import io.ktor.utils.io.core.* import io.rsocket.kotlin.frame.io.* -import io.rsocket.kotlin.internal.* +import kotlinx.io.* private const val FlagsMask: Int = 1023 private const val FrameTypeShift: Int = 10 -internal sealed class Frame : Closeable { +internal sealed class Frame : AutoCloseable { abstract val type: FrameType abstract val streamId: Int abstract val flags: Int - protected abstract fun BytePacketBuilder.writeSelf() + protected abstract fun Sink.writeSelf() protected abstract fun StringBuilder.appendFlags() protected abstract fun StringBuilder.appendSelf() - internal fun toPacket(pool: BufferPool): ByteReadPacket { + internal fun toBuffer(): Buffer { check(type.canHaveMetadata || !(flags check Flags.Metadata)) { "bad value for metadata flag" } - return pool.buildPacket { + return Buffer().apply { writeInt(streamId) writeShort((type.encodedType shl FrameTypeShift or flags).toShort()) writeSelf() @@ -53,31 +52,31 @@ internal sealed class Frame : Closeable { } } -internal fun ByteReadPacket.readFrame(pool: BufferPool): Frame = use { +internal fun Buffer.readFrame(): Frame = use { val streamId = readInt() val typeAndFlags = readShort().toInt() and 0xFFFF val flags = typeAndFlags and FlagsMask when (val type = FrameType(typeAndFlags shr FrameTypeShift)) { //stream id = 0 - FrameType.Setup -> readSetup(pool, flags) - FrameType.Resume -> readResume(pool) + FrameType.Setup -> readSetup(flags) + FrameType.Resume -> readResume() FrameType.ResumeOk -> readResumeOk() - FrameType.MetadataPush -> readMetadataPush(pool) - FrameType.Lease -> readLease(pool, flags) - FrameType.KeepAlive -> readKeepAlive(pool, flags) + FrameType.MetadataPush -> readMetadataPush() + FrameType.Lease -> readLease(flags) + FrameType.KeepAlive -> readKeepAlive(flags) //stream id != 0 FrameType.Cancel -> CancelFrame(streamId) FrameType.Error -> readError(streamId) FrameType.RequestN -> readRequestN(streamId) - FrameType.Extension -> readExtension(pool, streamId, flags) + FrameType.Extension -> readExtension(streamId, flags) FrameType.Payload, FrameType.RequestFnF, FrameType.RequestResponse, - -> readRequest(pool, type, streamId, flags, withInitial = false) + -> readRequest(type, streamId, flags, withInitial = false) FrameType.RequestStream, FrameType.RequestChannel, - -> readRequest(pool, type, streamId, flags, withInitial = true) + -> readRequest(type, streamId, flags, withInitial = true) FrameType.Reserved -> error("Reserved") } diff --git a/rsocket-core/src/commonMain/kotlin/io/rsocket/kotlin/frame/FrameCodec.kt b/rsocket-core/src/commonMain/kotlin/io/rsocket/kotlin/frame/FrameCodec.kt index 7daff295..cd661379 100644 --- a/rsocket-core/src/commonMain/kotlin/io/rsocket/kotlin/frame/FrameCodec.kt +++ b/rsocket-core/src/commonMain/kotlin/io/rsocket/kotlin/frame/FrameCodec.kt @@ -16,23 +16,21 @@ package io.rsocket.kotlin.frame -import io.ktor.utils.io.core.* -import io.rsocket.kotlin.internal.* +import kotlinx.io.* internal class FrameCodec( - val bufferPool: BufferPool, // affects encoding only, val maxFragmentSize: Int, ) { - fun decodeFrame(frame: ByteReadPacket): Frame = frame.readFrame(bufferPool) - fun decodeFrame(expectedStreamId: Int, frame: ByteReadPacket): Frame = decodeFrame(frame).also { + fun decodeFrame(frame: Buffer): Frame = frame.readFrame() + fun decodeFrame(expectedStreamId: Int, frame: Buffer): Frame = decodeFrame(frame).also { if (it.streamId != expectedStreamId) { it.close() error("Invalid stream id, expected '$expectedStreamId', actual '${it.streamId}'") } } - fun encodeFrame(frame: Frame): ByteReadPacket = frame.toPacket(bufferPool) + fun encodeFrame(frame: Frame): Buffer = frame.toBuffer() // TODO: move fragmentation logic here or into separate class? } diff --git a/rsocket-core/src/commonMain/kotlin/io/rsocket/kotlin/frame/KeepAliveFrame.kt b/rsocket-core/src/commonMain/kotlin/io/rsocket/kotlin/frame/KeepAliveFrame.kt index 585d268a..2d68013e 100644 --- a/rsocket-core/src/commonMain/kotlin/io/rsocket/kotlin/frame/KeepAliveFrame.kt +++ b/rsocket-core/src/commonMain/kotlin/io/rsocket/kotlin/frame/KeepAliveFrame.kt @@ -16,16 +16,15 @@ package io.rsocket.kotlin.frame -import io.ktor.utils.io.core.* import io.rsocket.kotlin.frame.io.* -import io.rsocket.kotlin.internal.* +import kotlinx.io.* private const val RespondFlag = 128 internal class KeepAliveFrame( val respond: Boolean, val lastPosition: Long, - val data: ByteReadPacket, + val data: Buffer, ) : Frame() { override val type: FrameType get() = FrameType.KeepAlive override val streamId: Int get() = 0 @@ -35,9 +34,9 @@ internal class KeepAliveFrame( data.close() } - override fun BytePacketBuilder.writeSelf() { + override fun Sink.writeSelf() { writeLong(lastPosition.coerceAtLeast(0)) - writePacket(data) + transferFrom(data) } override fun StringBuilder.appendFlags() { @@ -46,13 +45,13 @@ internal class KeepAliveFrame( override fun StringBuilder.appendSelf() { append("\nLast position: ").append(lastPosition) - appendPacket("Data", data) + appendBuffer("Data", data) } } -internal fun ByteReadPacket.readKeepAlive(pool: BufferPool, flags: Int): KeepAliveFrame { +internal fun Source.readKeepAlive(flags: Int): KeepAliveFrame { val respond = flags check RespondFlag val lastPosition = readLong() - val data = readPacket(pool) + val data = readBuffer() return KeepAliveFrame(respond, lastPosition, data) } diff --git a/rsocket-core/src/commonMain/kotlin/io/rsocket/kotlin/frame/LeaseFrame.kt b/rsocket-core/src/commonMain/kotlin/io/rsocket/kotlin/frame/LeaseFrame.kt index 478d1f36..52644918 100644 --- a/rsocket-core/src/commonMain/kotlin/io/rsocket/kotlin/frame/LeaseFrame.kt +++ b/rsocket-core/src/commonMain/kotlin/io/rsocket/kotlin/frame/LeaseFrame.kt @@ -16,14 +16,13 @@ package io.rsocket.kotlin.frame -import io.ktor.utils.io.core.* import io.rsocket.kotlin.frame.io.* -import io.rsocket.kotlin.internal.* +import kotlinx.io.* internal class LeaseFrame( val ttl: Int, val numberOfRequests: Int, - val metadata: ByteReadPacket?, + val metadata: Buffer?, ) : Frame() { override val type: FrameType get() = FrameType.Lease override val streamId: Int get() = 0 @@ -33,7 +32,7 @@ internal class LeaseFrame( metadata?.close() } - override fun BytePacketBuilder.writeSelf() { + override fun Sink.writeSelf() { writeInt(ttl) writeInt(numberOfRequests) writeMetadata(metadata) @@ -45,13 +44,13 @@ internal class LeaseFrame( override fun StringBuilder.appendSelf() { append("\nNumber of requests: ").append(numberOfRequests) - if (metadata != null) appendPacket("Metadata", metadata) + if (metadata != null) appendBuffer("Metadata", metadata) } } -internal fun ByteReadPacket.readLease(pool: BufferPool, flags: Int): LeaseFrame { +internal fun Source.readLease(flags: Int): LeaseFrame { val ttl = readInt() val numberOfRequests = readInt() - val metadata = if (flags check Flags.Metadata) readMetadata(pool) else null + val metadata = if (flags check Flags.Metadata) readMetadata() else null return LeaseFrame(ttl, numberOfRequests, metadata) } diff --git a/rsocket-core/src/commonMain/kotlin/io/rsocket/kotlin/frame/MetadataPushFrame.kt b/rsocket-core/src/commonMain/kotlin/io/rsocket/kotlin/frame/MetadataPushFrame.kt index b57d29d6..342958f2 100644 --- a/rsocket-core/src/commonMain/kotlin/io/rsocket/kotlin/frame/MetadataPushFrame.kt +++ b/rsocket-core/src/commonMain/kotlin/io/rsocket/kotlin/frame/MetadataPushFrame.kt @@ -16,12 +16,11 @@ package io.rsocket.kotlin.frame -import io.ktor.utils.io.core.* import io.rsocket.kotlin.frame.io.* -import io.rsocket.kotlin.internal.* +import kotlinx.io.* internal class MetadataPushFrame( - val metadata: ByteReadPacket, + val metadata: Buffer, ) : Frame() { override val type: FrameType get() = FrameType.MetadataPush override val streamId: Int get() = 0 @@ -31,8 +30,8 @@ internal class MetadataPushFrame( metadata.close() } - override fun BytePacketBuilder.writeSelf() { - writePacket(metadata) + override fun Sink.writeSelf() { + transferFrom(metadata) } override fun StringBuilder.appendFlags() { @@ -40,9 +39,9 @@ internal class MetadataPushFrame( } override fun StringBuilder.appendSelf() { - appendPacket("Metadata", metadata) + appendBuffer("Metadata", metadata) } } -internal fun ByteReadPacket.readMetadataPush(pool: BufferPool): MetadataPushFrame = - MetadataPushFrame(readPacket(pool)) +internal fun Source.readMetadataPush(): MetadataPushFrame = + MetadataPushFrame(readBuffer()) diff --git a/rsocket-core/src/commonMain/kotlin/io/rsocket/kotlin/frame/RequestFrame.kt b/rsocket-core/src/commonMain/kotlin/io/rsocket/kotlin/frame/RequestFrame.kt index 2a3e7c76..fcc562db 100644 --- a/rsocket-core/src/commonMain/kotlin/io/rsocket/kotlin/frame/RequestFrame.kt +++ b/rsocket-core/src/commonMain/kotlin/io/rsocket/kotlin/frame/RequestFrame.kt @@ -18,10 +18,9 @@ package io.rsocket.kotlin.frame -import io.ktor.utils.io.core.* import io.rsocket.kotlin.frame.io.* -import io.rsocket.kotlin.internal.* import io.rsocket.kotlin.payload.* +import kotlinx.io.* internal class RequestFrame( override val type: FrameType, @@ -46,7 +45,7 @@ internal class RequestFrame( payload.close() } - override fun BytePacketBuilder.writeSelf() { + override fun Sink.writeSelf() { if (initialRequest > 0) writeInt(initialRequest) writePayload(payload) } @@ -64,8 +63,7 @@ internal class RequestFrame( } } -internal fun ByteReadPacket.readRequest( - pool: BufferPool, +internal fun Source.readRequest( type: FrameType, streamId: Int, flags: Int, @@ -76,7 +74,7 @@ internal fun ByteReadPacket.readRequest( val next = flags check Flags.Next val initialRequest = if (withInitial) readInt() else 0 - val payload = readPayload(pool, flags) + val payload = readPayload(flags) return RequestFrame(type, streamId, fragmentFollows, complete, next, initialRequest, payload) } diff --git a/rsocket-core/src/commonMain/kotlin/io/rsocket/kotlin/frame/RequestNFrame.kt b/rsocket-core/src/commonMain/kotlin/io/rsocket/kotlin/frame/RequestNFrame.kt index 6261e81c..14ec4532 100644 --- a/rsocket-core/src/commonMain/kotlin/io/rsocket/kotlin/frame/RequestNFrame.kt +++ b/rsocket-core/src/commonMain/kotlin/io/rsocket/kotlin/frame/RequestNFrame.kt @@ -1,5 +1,5 @@ /* - * Copyright 2015-2022 the original author or authors. + * Copyright 2015-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,7 +16,7 @@ package io.rsocket.kotlin.frame -import io.ktor.utils.io.core.* +import kotlinx.io.* internal class RequestNFrame( override val streamId: Int, @@ -27,7 +27,7 @@ internal class RequestNFrame( override fun close(): Unit = Unit - override fun BytePacketBuilder.writeSelf() { + override fun Sink.writeSelf() { writeInt(requestN) } @@ -38,7 +38,7 @@ internal class RequestNFrame( } } -internal fun ByteReadPacket.readRequestN(streamId: Int): RequestNFrame { +internal fun Source.readRequestN(streamId: Int): RequestNFrame { val requestN = readInt() return RequestNFrame(streamId, requestN) } diff --git a/rsocket-core/src/commonMain/kotlin/io/rsocket/kotlin/frame/ResumeFrame.kt b/rsocket-core/src/commonMain/kotlin/io/rsocket/kotlin/frame/ResumeFrame.kt index 1002eab9..85fd3ee7 100644 --- a/rsocket-core/src/commonMain/kotlin/io/rsocket/kotlin/frame/ResumeFrame.kt +++ b/rsocket-core/src/commonMain/kotlin/io/rsocket/kotlin/frame/ResumeFrame.kt @@ -16,13 +16,12 @@ package io.rsocket.kotlin.frame -import io.ktor.utils.io.core.* import io.rsocket.kotlin.frame.io.* -import io.rsocket.kotlin.internal.* +import kotlinx.io.* internal class ResumeFrame( val version: Version, - val resumeToken: ByteReadPacket, + val resumeToken: Buffer, val lastReceivedServerPosition: Long, val firstAvailableClientPosition: Long, ) : Frame() { @@ -32,7 +31,7 @@ internal class ResumeFrame( override fun close(): Unit = Unit - override fun BytePacketBuilder.writeSelf() { + override fun Sink.writeSelf() { writeVersion(version) writeResumeToken(resumeToken) writeLong(lastReceivedServerPosition) @@ -45,13 +44,13 @@ internal class ResumeFrame( append("\nVersion: ").append(version.toString()).append("\n") append("Last received server position: ").append(lastReceivedServerPosition).append("\n") append("First available client position: ").append(firstAvailableClientPosition) - appendPacket("Resume token", resumeToken) + appendBuffer("Resume token", resumeToken) } } -internal fun ByteReadPacket.readResume(pool: BufferPool): ResumeFrame { +internal fun Source.readResume(): ResumeFrame { val version = readVersion() - val resumeToken = readResumeToken(pool) + val resumeToken = readResumeToken() val lastReceivedServerPosition = readLong() val firstAvailableClientPosition = readLong() return ResumeFrame( diff --git a/rsocket-core/src/commonMain/kotlin/io/rsocket/kotlin/frame/ResumeOkFrame.kt b/rsocket-core/src/commonMain/kotlin/io/rsocket/kotlin/frame/ResumeOkFrame.kt index 8cbd961e..60e7ee3e 100644 --- a/rsocket-core/src/commonMain/kotlin/io/rsocket/kotlin/frame/ResumeOkFrame.kt +++ b/rsocket-core/src/commonMain/kotlin/io/rsocket/kotlin/frame/ResumeOkFrame.kt @@ -1,5 +1,5 @@ /* - * Copyright 2015-2022 the original author or authors. + * Copyright 2015-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,7 +16,7 @@ package io.rsocket.kotlin.frame -import io.ktor.utils.io.core.* +import kotlinx.io.* internal class ResumeOkFrame( val lastReceivedClientPosition: Long, @@ -27,7 +27,7 @@ internal class ResumeOkFrame( override fun close(): Unit = Unit - override fun BytePacketBuilder.writeSelf() { + override fun Sink.writeSelf() { writeLong(lastReceivedClientPosition) } @@ -38,4 +38,4 @@ internal class ResumeOkFrame( } } -internal fun ByteReadPacket.readResumeOk(): ResumeOkFrame = ResumeOkFrame(readLong()) +internal fun Source.readResumeOk(): ResumeOkFrame = ResumeOkFrame(readLong()) diff --git a/rsocket-core/src/commonMain/kotlin/io/rsocket/kotlin/frame/SetupFrame.kt b/rsocket-core/src/commonMain/kotlin/io/rsocket/kotlin/frame/SetupFrame.kt index 36984e25..778cbe8a 100644 --- a/rsocket-core/src/commonMain/kotlin/io/rsocket/kotlin/frame/SetupFrame.kt +++ b/rsocket-core/src/commonMain/kotlin/io/rsocket/kotlin/frame/SetupFrame.kt @@ -16,11 +16,10 @@ package io.rsocket.kotlin.frame -import io.ktor.utils.io.core.* import io.rsocket.kotlin.frame.io.* -import io.rsocket.kotlin.internal.* import io.rsocket.kotlin.keepalive.* import io.rsocket.kotlin.payload.* +import kotlinx.io.* private const val HonorLeaseFlag = 64 private const val ResumeEnabledFlag = 128 @@ -29,7 +28,7 @@ internal class SetupFrame( val version: Version, //TODO check val honorLease: Boolean, val keepAlive: KeepAlive, - val resumeToken: ByteReadPacket?, + val resumeToken: Buffer?, val payloadMimeType: PayloadMimeType, val payload: Payload, ) : Frame() { @@ -49,7 +48,7 @@ internal class SetupFrame( payload.close() } - override fun BytePacketBuilder.writeSelf() { + override fun Sink.writeSelf() { writeVersion(version) writeInt(keepAlive.intervalMillis) writeInt(keepAlive.maxLifetimeMillis) @@ -75,20 +74,20 @@ internal class SetupFrame( } } -internal fun ByteReadPacket.readSetup(pool: BufferPool, flags: Int): SetupFrame { +internal fun Source.readSetup(flags: Int): SetupFrame { val version = readVersion() val keepAlive = run { val interval = readInt() val maxLifetime = readInt() KeepAlive(intervalMillis = interval, maxLifetimeMillis = maxLifetime) } - val resumeToken = if (flags check ResumeEnabledFlag) readResumeToken(pool) else null + val resumeToken = if (flags check ResumeEnabledFlag) readResumeToken() else null val payloadMimeType = run { val metadata = readStringMimeType() val data = readStringMimeType() PayloadMimeType(data = data, metadata = metadata) } - val payload = readPayload(pool, flags) + val payload = readPayload(flags) return SetupFrame( version = version, honorLease = flags check HonorLeaseFlag, @@ -99,13 +98,13 @@ internal fun ByteReadPacket.readSetup(pool: BufferPool, flags: Int): SetupFrame ) } -private fun ByteReadPacket.readStringMimeType(): String { - val length = readByte().toInt() - return readTextExactBytes(length) +private fun Source.readStringMimeType(): String { + val length = readByte().toLong() + return readString(length) } -private fun BytePacketBuilder.writeStringMimeType(mimeType: String) { +private fun Sink.writeStringMimeType(mimeType: String) { val bytes = mimeType.encodeToByteArray() //TODO check writeByte(bytes.size.toByte()) - writeFully(bytes) + write(bytes) } diff --git a/rsocket-core/src/commonMain/kotlin/io/rsocket/kotlin/frame/io/Dump.kt b/rsocket-core/src/commonMain/kotlin/io/rsocket/kotlin/frame/io/Dump.kt index fface979..282dfeb6 100644 --- a/rsocket-core/src/commonMain/kotlin/io/rsocket/kotlin/frame/io/Dump.kt +++ b/rsocket-core/src/commonMain/kotlin/io/rsocket/kotlin/frame/io/Dump.kt @@ -1,5 +1,5 @@ /* - * Copyright 2015-2022 the original author or authors. + * Copyright 2015-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,8 +16,8 @@ package io.rsocket.kotlin.frame.io -import io.ktor.utils.io.core.* import io.rsocket.kotlin.payload.* +import kotlinx.io.* private val digits = "0123456789abcdef".toCharArray() @@ -34,7 +34,7 @@ private const val header = """ //|00000000| 74 65 73 74 2d 64 61 74 61 20 74 65 73 74 2d 64 |test-data test-d| //|00000001| 61 74 61 20 74 65 73 74 2d 64 61 74 61 |ata test-data | //+--------+-------------------------------------------------+----------------+ -internal fun StringBuilder.appendPacket(packet: ByteReadPacket) { +internal fun StringBuilder.appendBuffer(buffer: Buffer) { var rowIndex = 0 var byteIndex = 0 @@ -63,8 +63,8 @@ internal fun StringBuilder.appendPacket(packet: ByteReadPacket) { appendRowIndex() - val copy = packet.copy() - while (copy.isNotEmpty) { + val copy = buffer.copy() + while (!copy.exhausted()) { val byte = copy.readByte() val b = byte.toInt() and 0xff @@ -88,11 +88,11 @@ internal fun StringBuilder.appendPacket(packet: ByteReadPacket) { append(divider) } -internal fun StringBuilder.appendPacket(tag: String, packet: ByteReadPacket) { +internal fun StringBuilder.appendBuffer(tag: String, buffer: Buffer) { append("\n").append(tag) - if (packet.remaining > 0) { - append("(length=").append(packet.remaining).append("):") - appendPacket(packet) + if (buffer.size > 0) { + append("(length=").append(buffer.size).append("):") + appendBuffer(buffer) } else { append(": Empty") } @@ -100,8 +100,8 @@ internal fun StringBuilder.appendPacket(tag: String, packet: ByteReadPacket) { internal fun StringBuilder.appendPayload(payload: Payload) { val metadata = payload.metadata - if (metadata != null) appendPacket("Metadata", metadata) - appendPacket("Data", payload.data) + if (metadata != null) appendBuffer("Metadata", metadata) + appendBuffer("Data", payload.data) } internal fun Int.toBinaryString(): String { diff --git a/rsocket-core/src/commonMain/kotlin/io/rsocket/kotlin/frame/io/Version.kt b/rsocket-core/src/commonMain/kotlin/io/rsocket/kotlin/frame/io/Version.kt index 12b62af2..e3a51495 100644 --- a/rsocket-core/src/commonMain/kotlin/io/rsocket/kotlin/frame/io/Version.kt +++ b/rsocket-core/src/commonMain/kotlin/io/rsocket/kotlin/frame/io/Version.kt @@ -1,5 +1,5 @@ /* - * Copyright 2015-2022 the original author or authors. + * Copyright 2015-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,7 +16,7 @@ package io.rsocket.kotlin.frame.io -import io.ktor.utils.io.core.* +import kotlinx.io.* internal class Version(val major: Int, val minor: Int) { val intValue: Int get() = (major shl 16) or (minor and 0xFFFF) @@ -30,7 +30,7 @@ internal class Version(val major: Int, val minor: Int) { } } -internal fun ByteReadPacket.readVersion(): Version { +internal fun Source.readVersion(): Version { val value = readInt() return Version( major = value shr 16 and 0xFFFF, @@ -38,6 +38,6 @@ internal fun ByteReadPacket.readVersion(): Version { ) } -internal fun BytePacketBuilder.writeVersion(version: Version) { +internal fun Sink.writeVersion(version: Version) { writeInt(version.intValue) } diff --git a/rsocket-core/src/commonMain/kotlin/io/rsocket/kotlin/frame/io/mimeType.kt b/rsocket-core/src/commonMain/kotlin/io/rsocket/kotlin/frame/io/mimeType.kt index ce322ac1..5f3c78bb 100644 --- a/rsocket-core/src/commonMain/kotlin/io/rsocket/kotlin/frame/io/mimeType.kt +++ b/rsocket-core/src/commonMain/kotlin/io/rsocket/kotlin/frame/io/mimeType.kt @@ -1,5 +1,5 @@ /* - * Copyright 2015-2022 the original author or authors. + * Copyright 2015-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,36 +16,36 @@ package io.rsocket.kotlin.frame.io -import io.ktor.utils.io.core.* import io.rsocket.kotlin.core.* import io.rsocket.kotlin.metadata.security.* +import kotlinx.io.* import kotlin.experimental.* -internal fun BytePacketBuilder.writeMimeType(type: MimeType) { +internal fun Sink.writeMimeType(type: MimeType) { when (type) { is MimeTypeWithId -> writeIdentifier(type.identifier) - is MimeTypeWithName -> writeTextWithLength(type.text) + is MimeTypeWithName -> writeStringWithLength(type.text) } } -internal fun ByteReadPacket.readMimeType(): MimeType = readType( +internal fun Source.readMimeType(): MimeType = readType( { WellKnownMimeType(it) ?: ReservedMimeType(it) }, { WellKnownMimeType(it) ?: CustomMimeType(it) } ) -internal fun BytePacketBuilder.writeAuthType(type: AuthType) { +internal fun Sink.writeAuthType(type: AuthType) { when (type) { is AuthTypeWithId -> writeIdentifier(type.identifier) - is AuthTypeWithName -> writeTextWithLength(type.text) + is AuthTypeWithName -> writeStringWithLength(type.text) } } -internal fun ByteReadPacket.readAuthType(): AuthType = readType( +internal fun Source.readAuthType(): AuthType = readType( { WellKnowAuthType(it) ?: ReservedAuthType(it) }, { WellKnowAuthType(it) ?: CustomAuthType(it) } ) -private fun BytePacketBuilder.writeTextWithLength(text: String) { +private fun Sink.writeStringWithLength(text: String) { val typeBytes = text.encodeToByteArray() // The first byte indicates MIME type encoding: // - Values 0x00 to 0x7F represent predefined "well-known" MIME types, directly using the byte as the type ID. @@ -53,16 +53,16 @@ private fun BytePacketBuilder.writeTextWithLength(text: String) { // For custom types, the length stored (byte value minus 0x80) is adjusted by -1 when writing, and adjusted by +1 when reading, // mapping to an effective range of 1 to 128 characters for the MIME type name length. writeByte((typeBytes.size - 1).toByte()) - writeFully(typeBytes) + write(typeBytes) } private const val KnownTypeFlag: Byte = Byte.MIN_VALUE -private fun BytePacketBuilder.writeIdentifier(identifier: Byte) { +private fun Sink.writeIdentifier(identifier: Byte) { writeByte(identifier or KnownTypeFlag) } -private inline fun ByteReadPacket.readType( +private inline fun Source.readType( fromIdentifier: (Byte) -> T, fromText: (String) -> T, ): T { @@ -76,7 +76,7 @@ private inline fun ByteReadPacket.readType( // - Values 0x80 to 0xFF denote custom MIME types, where the byte represents the length of the MIME type name that follows. // For custom types, the length stored (byte value minus 0x80) is adjusted by -1 when writing, and adjusted by +1 when reading, // mapping to an effective range of 1 to 128 characters for the MIME type name length. - val stringType = readTextExactBytes(byte.toInt() + 1) + val stringType = readString(byte.toLong() + 1) fromText(stringType) } } diff --git a/rsocket-core/src/commonMain/kotlin/io/rsocket/kotlin/frame/io/payload.kt b/rsocket-core/src/commonMain/kotlin/io/rsocket/kotlin/frame/io/payload.kt index 6c9df70e..740235cb 100644 --- a/rsocket-core/src/commonMain/kotlin/io/rsocket/kotlin/frame/io/payload.kt +++ b/rsocket-core/src/commonMain/kotlin/io/rsocket/kotlin/frame/io/payload.kt @@ -16,30 +16,29 @@ package io.rsocket.kotlin.frame.io -import io.ktor.utils.io.core.* -import io.rsocket.kotlin.internal.* import io.rsocket.kotlin.internal.io.* import io.rsocket.kotlin.payload.* +import kotlinx.io.* -internal fun ByteReadPacket.readMetadata(pool: BufferPool): ByteReadPacket { +internal fun Source.readMetadata(): Buffer { val length = readInt24() - return readPacket(pool, length) + return readBuffer(length) } -internal fun BytePacketBuilder.writeMetadata(metadata: ByteReadPacket?) { +internal fun Sink.writeMetadata(metadata: Buffer?) { metadata?.let { - writeInt24(it.remaining.toInt()) - writePacket(it) + writeInt24(it.size.toInt()) + transferFrom(it) } } -internal fun ByteReadPacket.readPayload(pool: BufferPool, flags: Int): Payload { - val metadata = if (flags check Flags.Metadata) readMetadata(pool) else null - val data = readPacket(pool) +internal fun Source.readPayload(flags: Int): Payload { + val metadata = if (flags check Flags.Metadata) readMetadata() else null + val data = readBuffer() return Payload(data = data, metadata = metadata) } -internal fun BytePacketBuilder.writePayload(payload: Payload) { +internal fun Sink.writePayload(payload: Payload) { writeMetadata(payload.metadata) - writePacket(payload.data) + transferFrom(payload.data) } diff --git a/rsocket-core/src/commonMain/kotlin/io/rsocket/kotlin/frame/io/util.kt b/rsocket-core/src/commonMain/kotlin/io/rsocket/kotlin/frame/io/util.kt index f106c3a8..fe473899 100644 --- a/rsocket-core/src/commonMain/kotlin/io/rsocket/kotlin/frame/io/util.kt +++ b/rsocket-core/src/commonMain/kotlin/io/rsocket/kotlin/frame/io/util.kt @@ -16,32 +16,28 @@ package io.rsocket.kotlin.frame.io -import io.ktor.utils.io.core.* -import io.rsocket.kotlin.internal.* +import kotlinx.io.* -internal fun ByteReadPacket.readResumeToken(pool: BufferPool): ByteReadPacket { +internal fun Source.readResumeToken(): Buffer { val length = readShort().toInt() and 0xFFFF - return readPacket(pool, length) + return readBuffer(length) } -internal fun BytePacketBuilder.writeResumeToken(resumeToken: ByteReadPacket?) { +internal fun Sink.writeResumeToken(resumeToken: Buffer?) { resumeToken?.let { - val length = it.remaining - writeShort(length.toShort()) - writePacket(it) + writeShort(it.size.toShort()) + transferFrom(it) } } -internal fun ByteReadPacket.readPacket(pool: BufferPool): ByteReadPacket { - if (isEmpty) return ByteReadPacket.Empty - return pool.buildPacket { - writePacket(this@readPacket) - } +internal fun Source.readBuffer(): Buffer { + return Buffer().also(this::transferTo) } -internal fun ByteReadPacket.readPacket(pool: BufferPool, length: Int): ByteReadPacket { - if (length == 0) return ByteReadPacket.Empty - return pool.buildPacket { - writePacket(this@readPacket, length) - } +internal fun Source.readBuffer(length: Int): Buffer { + val output = Buffer() + output.write(this, length.toLong()) + return output } + +internal val EmptyBuffer: Buffer = Buffer() diff --git a/rsocket-core/src/commonMain/kotlin/io/rsocket/kotlin/internal/BufferPool.kt b/rsocket-core/src/commonMain/kotlin/io/rsocket/kotlin/internal/BufferPool.kt deleted file mode 100644 index c191360f..00000000 --- a/rsocket-core/src/commonMain/kotlin/io/rsocket/kotlin/internal/BufferPool.kt +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright 2015-2024 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.rsocket.kotlin.internal - -import io.ktor.utils.io.core.* -import io.ktor.utils.io.core.internal.* -import io.ktor.utils.io.pool.* -import kotlin.jvm.* - -@Suppress("DEPRECATION") -@JvmInline -public value class BufferPool( - @PublishedApi - internal val pool: ObjectPool, -) { - public inline fun buildPacket(block: BytePacketBuilder.() -> Unit): ByteReadPacket { - val builder = BytePacketBuilder(pool) - try { - block(builder) - return builder.build() - } catch (t: Throwable) { - builder.close() - throw t - } - } - - public companion object { - public val Default: BufferPool = BufferPool(ChunkBuffer.Pool) - } -} diff --git a/rsocket-core/src/commonMain/kotlin/io/rsocket/kotlin/internal/PayloadAssembler.kt b/rsocket-core/src/commonMain/kotlin/io/rsocket/kotlin/internal/PayloadAssembler.kt index 3fefe658..da4e94b3 100644 --- a/rsocket-core/src/commonMain/kotlin/io/rsocket/kotlin/internal/PayloadAssembler.kt +++ b/rsocket-core/src/commonMain/kotlin/io/rsocket/kotlin/internal/PayloadAssembler.kt @@ -16,28 +16,22 @@ package io.rsocket.kotlin.internal -import io.ktor.utils.io.core.* -import io.ktor.utils.io.core.internal.* -import io.ktor.utils.io.pool.* +import io.rsocket.kotlin.frame.io.* import io.rsocket.kotlin.payload.* +import kotlinx.io.* // TODO: make metadata should be fully transmitted before data -internal class PayloadAssembler : Closeable { +internal class PayloadAssembler : AutoCloseable { // TODO: better name - var hasPayload: Boolean = false - private set - private var hasMetadata: Boolean = false + val hasPayload: Boolean + get() = data != null - private val data = BytePacketBuilder(NoPool) - private val metadata = BytePacketBuilder(NoPool) + private var data: Buffer? = null + private var metadata: Buffer? = null fun appendFragment(fragment: Payload) { - hasPayload = true - data.writePacket(fragment.data) - - val meta = fragment.metadata ?: return - hasMetadata = true - metadata.writePacket(meta) + fragment.data.transferTo(data ?: Buffer().also { data = it }) + fragment.metadata?.transferTo(metadata ?: Buffer().also { metadata = it }) } fun assemblePayload(fragment: Payload): Payload { @@ -46,36 +40,18 @@ internal class PayloadAssembler : Closeable { appendFragment(fragment) val payload = Payload( - data = data.build(), - metadata = when { - hasMetadata -> metadata.build() - else -> null - } + data = data ?: EmptyBuffer, // probably never happens + metadata = metadata ) - hasMetadata = false - hasPayload = false + data = null + metadata = null return payload } override fun close() { - data.close() - metadata.close() - } - - @Suppress("DEPRECATION") - private object NoPool : ObjectPool { - override val capacity: Int get() = error("should not be called") - - override fun borrow(): ChunkBuffer { - error("should not be called") - } - - override fun dispose() { - error("should not be called") - } - - override fun recycle(instance: ChunkBuffer) { - error("should not be called") - } + data?.clear() + data = null + metadata?.clear() + metadata = null } -} \ No newline at end of file +} diff --git a/rsocket-core/src/commonMain/kotlin/io/rsocket/kotlin/keepalive/KeepAliveHandler.kt b/rsocket-core/src/commonMain/kotlin/io/rsocket/kotlin/keepalive/KeepAliveHandler.kt index c30670c4..58966841 100644 --- a/rsocket-core/src/commonMain/kotlin/io/rsocket/kotlin/keepalive/KeepAliveHandler.kt +++ b/rsocket-core/src/commonMain/kotlin/io/rsocket/kotlin/keepalive/KeepAliveHandler.kt @@ -16,12 +16,13 @@ package io.rsocket.kotlin.keepalive -import io.ktor.utils.io.core.* import io.rsocket.kotlin.* import io.rsocket.kotlin.connection.* +import io.rsocket.kotlin.frame.io.* import io.rsocket.kotlin.transport.* import kotlinx.atomicfu.* import kotlinx.coroutines.* +import kotlinx.io.* import kotlin.time.* @RSocketTransportApi @@ -43,12 +44,12 @@ internal class KeepAliveHandler( if (currentDelayMillis() - lastMark.value >= keepAlive.maxLifetimeMillis) throw RSocketError.ConnectionError("No keep-alive for ${keepAlive.maxLifetimeMillis} ms") - connection2.sendKeepAlive(true, ByteReadPacket.Empty, 0) + connection2.sendKeepAlive(true, EmptyBuffer, 0) } } } - fun receive(data: ByteReadPacket, respond: Boolean) { + fun receive(data: Buffer, respond: Boolean) { lastMark.value = currentDelayMillis() // in most cases it will be possible to not suspend at all if (respond) connectionScope.launch(start = CoroutineStart.UNDISPATCHED) { diff --git a/rsocket-core/src/commonMain/kotlin/io/rsocket/kotlin/metadata/CompositeMetadata.kt b/rsocket-core/src/commonMain/kotlin/io/rsocket/kotlin/metadata/CompositeMetadata.kt index 8bed39b4..584be8a1 100644 --- a/rsocket-core/src/commonMain/kotlin/io/rsocket/kotlin/metadata/CompositeMetadata.kt +++ b/rsocket-core/src/commonMain/kotlin/io/rsocket/kotlin/metadata/CompositeMetadata.kt @@ -16,12 +16,11 @@ package io.rsocket.kotlin.metadata -import io.ktor.utils.io.core.* import io.rsocket.kotlin.* import io.rsocket.kotlin.core.* import io.rsocket.kotlin.frame.io.* -import io.rsocket.kotlin.internal.* import io.rsocket.kotlin.internal.io.* +import kotlinx.io.* @ExperimentalMetadataApi public fun CompositeMetadata(vararg entries: Metadata): CompositeMetadata = @@ -36,30 +35,30 @@ public sealed interface CompositeMetadata : Metadata { public val entries: List override val mimeType: MimeType get() = Reader.mimeType - override fun BytePacketBuilder.writeSelf() { + override fun Sink.writeSelf() { entries.forEach { writeMimeType(it.mimeType) - writeInt24(it.content.remaining.toInt()) //write metadata length - writePacket(it.content) //write metadata content + writeInt24(it.content.size.toInt()) //write metadata length + transferFrom(it.content) //write metadata content } } override fun close() { - entries.forEach { it.content.close() } + entries.forEach { it.content.clear() } } - public class Entry(public val mimeType: MimeType, public val content: ByteReadPacket) { - public constructor(metadata: Metadata) : this(metadata.mimeType, metadata.toPacket()) + public class Entry(public val mimeType: MimeType, public val content: Buffer) { + public constructor(metadata: Metadata) : this(metadata.mimeType, metadata.toBuffer()) } public companion object Reader : MetadataReader { override val mimeType: MimeType get() = WellKnownMimeType.MessageRSocketCompositeMetadata - override fun ByteReadPacket.read(pool: BufferPool): CompositeMetadata { + override fun Source.read(): CompositeMetadata { val list = mutableListOf() - while (isNotEmpty) { + while (!exhausted()) { val type = readMimeType() val length = readInt24() - val packet = readPacket(pool, length) + val packet = readBuffer(length) list.add(Entry(type, packet)) } return DefaultCompositeMetadata(list.toList()) diff --git a/rsocket-core/src/commonMain/kotlin/io/rsocket/kotlin/metadata/CompositeMetadataBuilder.kt b/rsocket-core/src/commonMain/kotlin/io/rsocket/kotlin/metadata/CompositeMetadataBuilder.kt index 8bc82e44..f0de032e 100644 --- a/rsocket-core/src/commonMain/kotlin/io/rsocket/kotlin/metadata/CompositeMetadataBuilder.kt +++ b/rsocket-core/src/commonMain/kotlin/io/rsocket/kotlin/metadata/CompositeMetadataBuilder.kt @@ -1,5 +1,5 @@ /* - * Copyright 2015-2022 the original author or authors. + * Copyright 2015-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,14 +16,14 @@ package io.rsocket.kotlin.metadata -import io.ktor.utils.io.core.* import io.rsocket.kotlin.* import io.rsocket.kotlin.core.* import io.rsocket.kotlin.payload.* +import kotlinx.io.* @ExperimentalMetadataApi -public sealed interface CompositeMetadataBuilder : Closeable { - public fun add(mimeType: MimeType, metadata: ByteReadPacket) +public sealed interface CompositeMetadataBuilder : AutoCloseable { + public fun add(mimeType: MimeType, metadata: Buffer) public fun add(metadata: Metadata) } @@ -50,7 +50,7 @@ internal class CompositeMetadataFromBuilder : CompositeMetadataBuilder, Composit override val entries: List get() = _entries - override fun add(mimeType: MimeType, metadata: ByteReadPacket) { + override fun add(mimeType: MimeType, metadata: Buffer) { _entries += CompositeMetadata.Entry(mimeType, metadata) } diff --git a/rsocket-core/src/commonMain/kotlin/io/rsocket/kotlin/metadata/CompositeMetadataExtensions.kt b/rsocket-core/src/commonMain/kotlin/io/rsocket/kotlin/metadata/CompositeMetadataExtensions.kt index 37343e4a..7ac3b207 100644 --- a/rsocket-core/src/commonMain/kotlin/io/rsocket/kotlin/metadata/CompositeMetadataExtensions.kt +++ b/rsocket-core/src/commonMain/kotlin/io/rsocket/kotlin/metadata/CompositeMetadataExtensions.kt @@ -16,10 +16,9 @@ package io.rsocket.kotlin.metadata -import io.ktor.utils.io.core.* import io.rsocket.kotlin.* import io.rsocket.kotlin.core.* -import io.rsocket.kotlin.internal.* +import kotlinx.io.* @ExperimentalMetadataApi public fun CompositeMetadata.Entry.hasMimeTypeOf(reader: MetadataReader<*>): Boolean = mimeType == reader.mimeType @@ -27,9 +26,8 @@ public fun CompositeMetadata.Entry.hasMimeTypeOf(reader: MetadataReader<*>): Boo @ExperimentalMetadataApi public fun CompositeMetadata.Entry.read( reader: MetadataReader, - pool: BufferPool = BufferPool.Default, ): M { - if (mimeType == reader.mimeType) return content.read(reader, pool) + if (mimeType == reader.mimeType) return content.read(reader) content.close() error("Expected mimeType '${reader.mimeType}' but was '$mimeType'") @@ -38,9 +36,8 @@ public fun CompositeMetadata.Entry.read( @ExperimentalMetadataApi public fun CompositeMetadata.Entry.readOrNull( reader: MetadataReader, - pool: BufferPool = BufferPool.Default, ): M? { - return if (mimeType == reader.mimeType) content.read(reader, pool) else null + return if (mimeType == reader.mimeType) content.read(reader) else null } @@ -50,17 +47,17 @@ public operator fun CompositeMetadata.contains(mimeType: MimeType): Boolean { } @ExperimentalMetadataApi -public operator fun CompositeMetadata.get(mimeType: MimeType): ByteReadPacket { +public operator fun CompositeMetadata.get(mimeType: MimeType): Source { return entries.first { it.mimeType == mimeType }.content } @ExperimentalMetadataApi -public fun CompositeMetadata.getOrNull(mimeType: MimeType): ByteReadPacket? { +public fun CompositeMetadata.getOrNull(mimeType: MimeType): Source? { return entries.find { it.mimeType == mimeType }?.content } @ExperimentalMetadataApi -public fun CompositeMetadata.list(mimeType: MimeType): List { +public fun CompositeMetadata.list(mimeType: MimeType): List { return entries.mapNotNull { if (it.mimeType == mimeType) it.content else null } } diff --git a/rsocket-core/src/commonMain/kotlin/io/rsocket/kotlin/metadata/Metadata.kt b/rsocket-core/src/commonMain/kotlin/io/rsocket/kotlin/metadata/Metadata.kt index 2b4d8326..e5867835 100644 --- a/rsocket-core/src/commonMain/kotlin/io/rsocket/kotlin/metadata/Metadata.kt +++ b/rsocket-core/src/commonMain/kotlin/io/rsocket/kotlin/metadata/Metadata.kt @@ -16,36 +16,33 @@ package io.rsocket.kotlin.metadata -import io.ktor.utils.io.core.* import io.rsocket.kotlin.* import io.rsocket.kotlin.core.* -import io.rsocket.kotlin.internal.* import io.rsocket.kotlin.payload.* +import kotlinx.io.* @ExperimentalMetadataApi -public interface Metadata : Closeable { +public interface Metadata : AutoCloseable { public val mimeType: MimeType - public fun BytePacketBuilder.writeSelf() + public fun Sink.writeSelf() } @ExperimentalMetadataApi public interface MetadataReader { public val mimeType: MimeType - public fun ByteReadPacket.read(pool: BufferPool): M + public fun Source.read(): M } @ExperimentalMetadataApi -public fun PayloadBuilder.metadata(metadata: Metadata): Unit = metadata(metadata.toPacket()) +public fun PayloadBuilder.metadata(metadata: Metadata): Unit = metadata(metadata.toBuffer()) @ExperimentalMetadataApi -public fun ByteReadPacket.read( +public fun Source.read( reader: MetadataReader, - pool: BufferPool = BufferPool.Default, ): M = use { - with(reader) { read(pool) } + with(reader) { read() } } @ExperimentalMetadataApi -public fun Metadata.toPacket(pool: BufferPool = BufferPool.Default): ByteReadPacket = - pool.buildPacket { writeSelf() } +public fun Metadata.toBuffer(): Buffer = Buffer().apply { writeSelf() } diff --git a/rsocket-core/src/commonMain/kotlin/io/rsocket/kotlin/metadata/PerStreamAcceptableDataMimeTypesMetadata.kt b/rsocket-core/src/commonMain/kotlin/io/rsocket/kotlin/metadata/PerStreamAcceptableDataMimeTypesMetadata.kt index f0a9029a..326dacc3 100644 --- a/rsocket-core/src/commonMain/kotlin/io/rsocket/kotlin/metadata/PerStreamAcceptableDataMimeTypesMetadata.kt +++ b/rsocket-core/src/commonMain/kotlin/io/rsocket/kotlin/metadata/PerStreamAcceptableDataMimeTypesMetadata.kt @@ -16,11 +16,10 @@ package io.rsocket.kotlin.metadata -import io.ktor.utils.io.core.* import io.rsocket.kotlin.* import io.rsocket.kotlin.core.* import io.rsocket.kotlin.frame.io.* -import io.rsocket.kotlin.internal.* +import kotlinx.io.* @ExperimentalMetadataApi public fun PerStreamAcceptableDataMimeTypesMetadata(vararg tags: MimeType): PerStreamAcceptableDataMimeTypesMetadata = @@ -30,7 +29,7 @@ public fun PerStreamAcceptableDataMimeTypesMetadata(vararg tags: MimeType): PerS public class PerStreamAcceptableDataMimeTypesMetadata(public val types: List) : Metadata { override val mimeType: MimeType get() = Reader.mimeType - override fun BytePacketBuilder.writeSelf() { + override fun Sink.writeSelf() { types.forEach { writeMimeType(it) } @@ -40,9 +39,9 @@ public class PerStreamAcceptableDataMimeTypesMetadata(public val types: List { override val mimeType: MimeType get() = WellKnownMimeType.MessageRSocketAcceptMimeTypes - override fun ByteReadPacket.read(pool: BufferPool): PerStreamAcceptableDataMimeTypesMetadata { + override fun Source.read(): PerStreamAcceptableDataMimeTypesMetadata { val list = mutableListOf() - while (isNotEmpty) list.add(readMimeType()) + while (!exhausted()) list.add(readMimeType()) return PerStreamAcceptableDataMimeTypesMetadata(list.toList()) } } diff --git a/rsocket-core/src/commonMain/kotlin/io/rsocket/kotlin/metadata/PerStreamDataMimeTypeMetadata.kt b/rsocket-core/src/commonMain/kotlin/io/rsocket/kotlin/metadata/PerStreamDataMimeTypeMetadata.kt index 78a41fbd..889f839b 100644 --- a/rsocket-core/src/commonMain/kotlin/io/rsocket/kotlin/metadata/PerStreamDataMimeTypeMetadata.kt +++ b/rsocket-core/src/commonMain/kotlin/io/rsocket/kotlin/metadata/PerStreamDataMimeTypeMetadata.kt @@ -16,17 +16,16 @@ package io.rsocket.kotlin.metadata -import io.ktor.utils.io.core.* import io.rsocket.kotlin.* import io.rsocket.kotlin.core.* import io.rsocket.kotlin.frame.io.* -import io.rsocket.kotlin.internal.* +import kotlinx.io.* @ExperimentalMetadataApi public class PerStreamDataMimeTypeMetadata(public val type: MimeType) : Metadata { override val mimeType: MimeType get() = Reader.mimeType - override fun BytePacketBuilder.writeSelf() { + override fun Sink.writeSelf() { writeMimeType(type) } @@ -34,7 +33,7 @@ public class PerStreamDataMimeTypeMetadata(public val type: MimeType) : Metadata public companion object Reader : MetadataReader { override val mimeType: MimeType get() = WellKnownMimeType.MessageRSocketMimeType - override fun ByteReadPacket.read(pool: BufferPool): PerStreamDataMimeTypeMetadata = + override fun Source.read(): PerStreamDataMimeTypeMetadata = PerStreamDataMimeTypeMetadata(readMimeType()) } } diff --git a/rsocket-core/src/commonMain/kotlin/io/rsocket/kotlin/metadata/RawMetadata.kt b/rsocket-core/src/commonMain/kotlin/io/rsocket/kotlin/metadata/RawMetadata.kt index 92c6acb2..ebac375e 100644 --- a/rsocket-core/src/commonMain/kotlin/io/rsocket/kotlin/metadata/RawMetadata.kt +++ b/rsocket-core/src/commonMain/kotlin/io/rsocket/kotlin/metadata/RawMetadata.kt @@ -16,19 +16,18 @@ package io.rsocket.kotlin.metadata -import io.ktor.utils.io.core.* import io.rsocket.kotlin.* import io.rsocket.kotlin.core.* import io.rsocket.kotlin.frame.io.* -import io.rsocket.kotlin.internal.* +import kotlinx.io.* @ExperimentalMetadataApi public class RawMetadata( override val mimeType: MimeType, - public val content: ByteReadPacket, + public val content: Source, ) : Metadata { - override fun BytePacketBuilder.writeSelf() { - writePacket(content) + override fun Sink.writeSelf() { + transferFrom(content) } override fun close() { @@ -36,8 +35,8 @@ public class RawMetadata( } private class Reader(override val mimeType: MimeType) : MetadataReader { - override fun ByteReadPacket.read(pool: BufferPool): RawMetadata = - RawMetadata(mimeType, readPacket(pool)) + override fun Source.read(): RawMetadata = + RawMetadata(mimeType, readBuffer()) } public companion object { diff --git a/rsocket-core/src/commonMain/kotlin/io/rsocket/kotlin/metadata/RoutingMetadata.kt b/rsocket-core/src/commonMain/kotlin/io/rsocket/kotlin/metadata/RoutingMetadata.kt index 8b1770a6..78015b29 100644 --- a/rsocket-core/src/commonMain/kotlin/io/rsocket/kotlin/metadata/RoutingMetadata.kt +++ b/rsocket-core/src/commonMain/kotlin/io/rsocket/kotlin/metadata/RoutingMetadata.kt @@ -16,10 +16,9 @@ package io.rsocket.kotlin.metadata -import io.ktor.utils.io.core.* import io.rsocket.kotlin.* import io.rsocket.kotlin.core.* -import io.rsocket.kotlin.internal.* +import kotlinx.io.* @ExperimentalMetadataApi public fun RoutingMetadata(vararg tags: String): RoutingMetadata = RoutingMetadata(tags.toList()) @@ -34,11 +33,11 @@ public class RoutingMetadata(public val tags: List) : Metadata { override val mimeType: MimeType get() = Reader.mimeType - override fun BytePacketBuilder.writeSelf() { + override fun Sink.writeSelf() { tags.forEach { val bytes = it.encodeToByteArray() writeByte(bytes.size.toByte()) - writeFully(bytes) + write(bytes) } } @@ -46,11 +45,11 @@ public class RoutingMetadata(public val tags: List) : Metadata { public companion object Reader : MetadataReader { override val mimeType: MimeType get() = WellKnownMimeType.MessageRSocketRouting - override fun ByteReadPacket.read(pool: BufferPool): RoutingMetadata { + override fun Source.read(): RoutingMetadata { val list = mutableListOf() - while (isNotEmpty) { - val length = readByte().toInt() and 0xFF - list.add(readTextExactBytes(length)) + while (!exhausted()) { + val length = readByte().toLong() and 0xFF + list.add(readString(length)) } return RoutingMetadata(list.toList()) } diff --git a/rsocket-core/src/commonMain/kotlin/io/rsocket/kotlin/metadata/ZipkinTracingMetadata.kt b/rsocket-core/src/commonMain/kotlin/io/rsocket/kotlin/metadata/ZipkinTracingMetadata.kt index b1b9818d..404e4341 100644 --- a/rsocket-core/src/commonMain/kotlin/io/rsocket/kotlin/metadata/ZipkinTracingMetadata.kt +++ b/rsocket-core/src/commonMain/kotlin/io/rsocket/kotlin/metadata/ZipkinTracingMetadata.kt @@ -16,11 +16,10 @@ package io.rsocket.kotlin.metadata -import io.ktor.utils.io.core.* import io.rsocket.kotlin.* import io.rsocket.kotlin.core.* import io.rsocket.kotlin.frame.io.* -import io.rsocket.kotlin.internal.* +import kotlinx.io.* import kotlin.experimental.* @ExperimentalMetadataApi @@ -43,7 +42,7 @@ public class ZipkinTracingMetadata internal constructor( Unspecified } - override fun BytePacketBuilder.writeSelf() { + override fun Sink.writeSelf() { var flags = when (kind) { Kind.Debug -> DebugFlag Kind.Sample -> SampleFlag @@ -70,7 +69,7 @@ public class ZipkinTracingMetadata internal constructor( public companion object Reader : MetadataReader { override val mimeType: MimeType get() = WellKnownMimeType.MessageRSocketTracingZipkin - override fun ByteReadPacket.read(pool: BufferPool): ZipkinTracingMetadata { + override fun Source.read(): ZipkinTracingMetadata { val flags = readByte() val kind = when { diff --git a/rsocket-core/src/commonMain/kotlin/io/rsocket/kotlin/metadata/security/AuthMetadata.kt b/rsocket-core/src/commonMain/kotlin/io/rsocket/kotlin/metadata/security/AuthMetadata.kt index 9a68432f..a2596804 100644 --- a/rsocket-core/src/commonMain/kotlin/io/rsocket/kotlin/metadata/security/AuthMetadata.kt +++ b/rsocket-core/src/commonMain/kotlin/io/rsocket/kotlin/metadata/security/AuthMetadata.kt @@ -16,21 +16,20 @@ package io.rsocket.kotlin.metadata.security -import io.ktor.utils.io.core.* import io.rsocket.kotlin.* import io.rsocket.kotlin.core.* import io.rsocket.kotlin.frame.io.* -import io.rsocket.kotlin.internal.* import io.rsocket.kotlin.metadata.* +import kotlinx.io.* @ExperimentalMetadataApi public sealed interface AuthMetadata : Metadata { public val type: AuthType - public fun BytePacketBuilder.writeContent() + public fun Sink.writeContent() override val mimeType: MimeType get() = WellKnownMimeType.MessageRSocketAuthentication - override fun BytePacketBuilder.writeSelf() { + override fun Sink.writeSelf() { writeAuthType(type) writeContent() } @@ -38,11 +37,11 @@ public sealed interface AuthMetadata : Metadata { @ExperimentalMetadataApi public sealed interface AuthMetadataReader : MetadataReader { - public fun ByteReadPacket.readContent(type: AuthType, pool: BufferPool): AM + public fun Source.readContent(type: AuthType): AM override val mimeType: MimeType get() = WellKnownMimeType.MessageRSocketAuthentication - override fun ByteReadPacket.read(pool: BufferPool): AM { + override fun Source.read(): AM { val type = readAuthType() - return readContent(type, pool) + return readContent(type) } } diff --git a/rsocket-core/src/commonMain/kotlin/io/rsocket/kotlin/metadata/security/BearerAuthMetadata.kt b/rsocket-core/src/commonMain/kotlin/io/rsocket/kotlin/metadata/security/BearerAuthMetadata.kt index 5c3b4fa1..6cd49a83 100644 --- a/rsocket-core/src/commonMain/kotlin/io/rsocket/kotlin/metadata/security/BearerAuthMetadata.kt +++ b/rsocket-core/src/commonMain/kotlin/io/rsocket/kotlin/metadata/security/BearerAuthMetadata.kt @@ -16,25 +16,24 @@ package io.rsocket.kotlin.metadata.security -import io.ktor.utils.io.core.* import io.rsocket.kotlin.* -import io.rsocket.kotlin.internal.* +import kotlinx.io.* @ExperimentalMetadataApi public class BearerAuthMetadata( public val token: String, ) : AuthMetadata { override val type: AuthType get() = WellKnowAuthType.Bearer - override fun BytePacketBuilder.writeContent() { - writeText(token) + override fun Sink.writeContent() { + writeString(token) } override fun close(): Unit = Unit public companion object Reader : AuthMetadataReader { - override fun ByteReadPacket.readContent(type: AuthType, pool: BufferPool): BearerAuthMetadata { + override fun Source.readContent(type: AuthType): BearerAuthMetadata { require(type == WellKnowAuthType.Bearer) { "Metadata auth type should be 'bearer'" } - val token = readText() + val token = readString() return BearerAuthMetadata(token) } } diff --git a/rsocket-core/src/commonMain/kotlin/io/rsocket/kotlin/metadata/security/RawAuthMetadata.kt b/rsocket-core/src/commonMain/kotlin/io/rsocket/kotlin/metadata/security/RawAuthMetadata.kt index a7f909df..6e33227a 100644 --- a/rsocket-core/src/commonMain/kotlin/io/rsocket/kotlin/metadata/security/RawAuthMetadata.kt +++ b/rsocket-core/src/commonMain/kotlin/io/rsocket/kotlin/metadata/security/RawAuthMetadata.kt @@ -16,19 +16,18 @@ package io.rsocket.kotlin.metadata.security -import io.ktor.utils.io.core.* import io.rsocket.kotlin.* import io.rsocket.kotlin.frame.io.* -import io.rsocket.kotlin.internal.* +import kotlinx.io.* @ExperimentalMetadataApi public class RawAuthMetadata( public override val type: AuthType, - public val content: ByteReadPacket, + public val content: Source, ) : AuthMetadata { - override fun BytePacketBuilder.writeContent() { - writePacket(content) + override fun Sink.writeContent() { + transferFrom(content) } override fun close() { @@ -36,8 +35,8 @@ public class RawAuthMetadata( } public companion object Reader : AuthMetadataReader { - override fun ByteReadPacket.readContent(type: AuthType, pool: BufferPool): RawAuthMetadata { - val content = readPacket(pool) + override fun Source.readContent(type: AuthType): RawAuthMetadata { + val content = readBuffer() return RawAuthMetadata(type, content) } } @@ -49,9 +48,8 @@ public fun RawAuthMetadata.hasAuthTypeOf(reader: AuthMetadataReader<*>): Boolean @ExperimentalMetadataApi public fun RawAuthMetadata.read( reader: AuthMetadataReader, - pool: BufferPool = BufferPool.Default, ): AM { - return readOrNull(reader, pool) ?: run { + return readOrNull(reader) ?: run { content.close() error("Expected auth type '${reader.mimeType}' but was '$mimeType'") } @@ -61,11 +59,10 @@ public fun RawAuthMetadata.read( public fun RawAuthMetadata.readOrNull( reader: AuthMetadataReader, - pool: BufferPool = BufferPool.Default, ): AM? { if (type != reader.mimeType) return null with(reader) { - return content.use { it.readContent(type, pool) } + return content.use { it.readContent(type) } } } diff --git a/rsocket-core/src/commonMain/kotlin/io/rsocket/kotlin/metadata/security/SimpleAuthMetadata.kt b/rsocket-core/src/commonMain/kotlin/io/rsocket/kotlin/metadata/security/SimpleAuthMetadata.kt index 8cbc16c0..4f82b05d 100644 --- a/rsocket-core/src/commonMain/kotlin/io/rsocket/kotlin/metadata/security/SimpleAuthMetadata.kt +++ b/rsocket-core/src/commonMain/kotlin/io/rsocket/kotlin/metadata/security/SimpleAuthMetadata.kt @@ -16,9 +16,8 @@ package io.rsocket.kotlin.metadata.security -import io.ktor.utils.io.core.* import io.rsocket.kotlin.* -import io.rsocket.kotlin.internal.* +import kotlinx.io.* @ExperimentalMetadataApi public class SimpleAuthMetadata( @@ -32,21 +31,21 @@ public class SimpleAuthMetadata( override val type: AuthType get() = WellKnowAuthType.Simple - override fun BytePacketBuilder.writeContent() { + override fun Sink.writeContent() { val length = username.encodeToByteArray() writeShort(length.size.toShort()) - writeText(username) - writeText(password) + writeString(username) + writeString(password) } override fun close(): Unit = Unit public companion object Reader : AuthMetadataReader { - override fun ByteReadPacket.readContent(type: AuthType, pool: BufferPool): SimpleAuthMetadata { + override fun Source.readContent(type: AuthType): SimpleAuthMetadata { require(type == WellKnowAuthType.Simple) { "Metadata auth type should be 'simple'" } - val length = readShort().toInt() - val username = readTextExactBytes(length) - val password = readText() + val length = readShort().toLong() + val username = readString(length) + val password = readString() return SimpleAuthMetadata(username, password) } } diff --git a/rsocket-core/src/commonMain/kotlin/io/rsocket/kotlin/operation/OperationOutbound.kt b/rsocket-core/src/commonMain/kotlin/io/rsocket/kotlin/operation/OperationOutbound.kt index 0b67e014..debd9ff7 100644 --- a/rsocket-core/src/commonMain/kotlin/io/rsocket/kotlin/operation/OperationOutbound.kt +++ b/rsocket-core/src/commonMain/kotlin/io/rsocket/kotlin/operation/OperationOutbound.kt @@ -16,10 +16,10 @@ package io.rsocket.kotlin.operation -import io.ktor.utils.io.core.* import io.rsocket.kotlin.frame.* import io.rsocket.kotlin.frame.io.* import io.rsocket.kotlin.payload.* +import kotlinx.io.* import kotlin.math.* private const val lengthSize = 3 @@ -36,7 +36,7 @@ internal abstract class OperationOutbound( abstract val isClosed: Boolean - protected abstract suspend fun sendFrame(frame: ByteReadPacket) + protected abstract suspend fun sendFrame(frame: Buffer) private suspend fun sendFrame(frame: Frame): Unit = sendFrame(frameCodec.encodeFrame(frame)) suspend fun sendError(cause: Throwable) { @@ -90,24 +90,24 @@ internal abstract class OperationOutbound( if (metadata != null) remaining -= lengthSize do { - val metadataFragment = if (metadata != null && metadata.isNotEmpty) { + val metadataFragment = if (metadata != null && !metadata.exhausted()) { if (!first) remaining -= lengthSize - val length = min(metadata.remaining.toInt(), remaining) + val length = min(metadata.size.toInt(), remaining) remaining -= length - metadata.readPacket(frameCodec.bufferPool, length) + metadata.readBuffer(length) } else null - val dataFragment = if (remaining > 0 && data.isNotEmpty) { - val length = min(data.remaining.toInt(), remaining) + val dataFragment = if (remaining > 0 && !data.exhausted()) { + val length = min(data.size.toInt(), remaining) remaining -= length - data.readPacket(frameCodec.bufferPool, length) + data.readBuffer(length) } else { - ByteReadPacket.Empty + EmptyBuffer } val fType = if (first && type.isRequestType) type else FrameType.Payload val fragment = Payload(dataFragment, metadataFragment) - val follows = metadata != null && metadata.isNotEmpty || data.isNotEmpty + val follows = metadata != null && !metadata.exhausted() || !data.exhausted() sendFrame( RequestFrame( type = fType, @@ -127,8 +127,8 @@ internal abstract class OperationOutbound( private fun Payload.isFragmentable(hasInitialRequest: Boolean) = when (frameCodec.maxFragmentSize) { 0 -> false else -> when (val meta = metadata) { - null -> data.remaining > frameCodec.maxFragmentSize - fragmentOffset - (if (hasInitialRequest) Int.SIZE_BYTES else 0) - else -> data.remaining + meta.remaining > frameCodec.maxFragmentSize - fragmentOffsetWithMetadata - (if (hasInitialRequest) Int.SIZE_BYTES else 0) + null -> data.size > frameCodec.maxFragmentSize - fragmentOffset - (if (hasInitialRequest) Int.SIZE_BYTES else 0) + else -> data.size + meta.size > frameCodec.maxFragmentSize - fragmentOffsetWithMetadata - (if (hasInitialRequest) Int.SIZE_BYTES else 0) } } diff --git a/rsocket-core/src/commonMain/kotlin/io/rsocket/kotlin/payload/Payload.kt b/rsocket-core/src/commonMain/kotlin/io/rsocket/kotlin/payload/Payload.kt index 04787dae..623fc8b9 100644 --- a/rsocket-core/src/commonMain/kotlin/io/rsocket/kotlin/payload/Payload.kt +++ b/rsocket-core/src/commonMain/kotlin/io/rsocket/kotlin/payload/Payload.kt @@ -1,5 +1,5 @@ /* - * Copyright 2015-2022 the original author or authors. + * Copyright 2015-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,27 +16,28 @@ package io.rsocket.kotlin.payload -import io.ktor.utils.io.core.* +import io.rsocket.kotlin.frame.io.* +import kotlinx.io.* -public fun Payload(data: ByteReadPacket, metadata: ByteReadPacket? = null): Payload = DefaultPayload(data, metadata) +public fun Payload(data: Buffer, metadata: Buffer? = null): Payload = DefaultPayload(data, metadata) -public sealed interface Payload : Closeable { - public val data: ByteReadPacket - public val metadata: ByteReadPacket? +public sealed interface Payload : AutoCloseable { + public val data: Buffer + public val metadata: Buffer? public fun copy(): Payload = DefaultPayload(data.copy(), metadata?.copy()) - override fun close() { - data.close() - metadata?.close() + public override fun close() { + data.clear() + metadata?.clear() } public companion object { - public val Empty: Payload = Payload(ByteReadPacket.Empty) + public val Empty: Payload = DefaultPayload(EmptyBuffer, null) } } private class DefaultPayload( - override val data: ByteReadPacket, - override val metadata: ByteReadPacket?, + override val data: Buffer, + override val metadata: Buffer?, ) : Payload diff --git a/rsocket-core/src/commonMain/kotlin/io/rsocket/kotlin/payload/PayloadBuilder.kt b/rsocket-core/src/commonMain/kotlin/io/rsocket/kotlin/payload/PayloadBuilder.kt index 49275474..b485a665 100644 --- a/rsocket-core/src/commonMain/kotlin/io/rsocket/kotlin/payload/PayloadBuilder.kt +++ b/rsocket-core/src/commonMain/kotlin/io/rsocket/kotlin/payload/PayloadBuilder.kt @@ -1,5 +1,5 @@ /* - * Copyright 2015-2022 the original author or authors. + * Copyright 2015-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,11 +16,12 @@ package io.rsocket.kotlin.payload -import io.ktor.utils.io.core.* +import io.rsocket.kotlin.frame.io.* +import kotlinx.io.* -public sealed interface PayloadBuilder : Closeable { - public fun data(value: ByteReadPacket) - public fun metadata(value: ByteReadPacket) +public sealed interface PayloadBuilder : AutoCloseable { + public fun data(value: Buffer) + public fun metadata(value: Buffer) } public inline fun buildPayload(block: PayloadBuilder.() -> Unit): Payload { @@ -34,15 +35,14 @@ public inline fun buildPayload(block: PayloadBuilder.() -> Unit): Payload { } } -public inline fun PayloadBuilder.data(block: BytePacketBuilder.() -> Unit): Unit = data(buildPacket(block = block)) -public fun PayloadBuilder.data(value: String): Unit = data { writeText(value) } -public fun PayloadBuilder.data(value: ByteArray): Unit = data { writeFully(value) } +public inline fun PayloadBuilder.data(block: Sink.() -> Unit): Unit = data(Buffer().apply(block)) +public fun PayloadBuilder.data(value: String): Unit = data { writeString(value) } +public fun PayloadBuilder.data(value: ByteArray): Unit = data { write(value) } -public inline fun PayloadBuilder.metadata(block: BytePacketBuilder.() -> Unit): Unit = - metadata(buildPacket(block = block)) +public inline fun PayloadBuilder.metadata(block: Sink.() -> Unit): Unit = metadata(Buffer().apply(block)) -public fun PayloadBuilder.metadata(value: String): Unit = metadata { writeText(value) } -public fun PayloadBuilder.metadata(value: ByteArray): Unit = metadata { writeFully(value) } +public fun PayloadBuilder.metadata(value: String): Unit = metadata { writeString(value) } +public fun PayloadBuilder.metadata(value: ByteArray): Unit = metadata { write(value) } @PublishedApi @@ -50,12 +50,12 @@ internal class PayloadFromBuilder : PayloadBuilder, Payload { private var hasData = false private var hasMetadata = false - override var data: ByteReadPacket = ByteReadPacket.Empty + override var data: Buffer = EmptyBuffer private set - override var metadata: ByteReadPacket? = null + override var metadata: Buffer? = null private set - override fun data(value: ByteReadPacket) { + override fun data(value: Buffer) { if (hasData) { value.close() error("Data already provided") @@ -64,7 +64,7 @@ internal class PayloadFromBuilder : PayloadBuilder, Payload { hasData = true } - override fun metadata(value: ByteReadPacket) { + override fun metadata(value: Buffer) { if (hasMetadata) { value.close() error("Metadata already provided") diff --git a/rsocket-core/src/commonMain/kotlin/io/rsocket/kotlin/transport/RSocketConnection.kt b/rsocket-core/src/commonMain/kotlin/io/rsocket/kotlin/transport/RSocketConnection.kt index 7b62af0a..c49ee3b5 100644 --- a/rsocket-core/src/commonMain/kotlin/io/rsocket/kotlin/transport/RSocketConnection.kt +++ b/rsocket-core/src/commonMain/kotlin/io/rsocket/kotlin/transport/RSocketConnection.kt @@ -16,7 +16,7 @@ package io.rsocket.kotlin.transport -import io.ktor.utils.io.core.* +import kotlinx.io.* // all methods can be called from any thread/context at any time // should be accessed only internally @@ -36,10 +36,10 @@ public interface RSocketSequentialConnection : RSocketConnection { // throws if frame not sent // streamId=0 should be sent earlier - public suspend fun sendFrame(streamId: Int, frame: ByteReadPacket) + public suspend fun sendFrame(streamId: Int, frame: Buffer) // null if no more frames could be received - public suspend fun receiveFrame(): ByteReadPacket? + public suspend fun receiveFrame(): Buffer? } @RSocketTransportApi @@ -47,7 +47,7 @@ public interface RSocketMultiplexedConnection : RSocketConnection { public suspend fun createStream(): Stream public suspend fun acceptStream(): Stream? - public interface Stream : Closeable { + public interface Stream : AutoCloseable { public val isClosedForSend: Boolean // 0 - highest priority @@ -55,10 +55,10 @@ public interface RSocketMultiplexedConnection : RSocketConnection { public fun setSendPriority(priority: Int) // throws if frame not sent - public suspend fun sendFrame(frame: ByteReadPacket) + public suspend fun sendFrame(frame: Buffer) // null if no more frames could be received - public suspend fun receiveFrame(): ByteReadPacket? + public suspend fun receiveFrame(): Buffer? // closing stream will send buffered frames (if needed) // sending/receiving frames will be not possible after it diff --git a/rsocket-core/src/commonMain/kotlin/io/rsocket/kotlin/transport/internal/PrioritizationFrameQueue.kt b/rsocket-core/src/commonMain/kotlin/io/rsocket/kotlin/transport/internal/PrioritizationFrameQueue.kt index 3b59c76c..158148cd 100644 --- a/rsocket-core/src/commonMain/kotlin/io/rsocket/kotlin/transport/internal/PrioritizationFrameQueue.kt +++ b/rsocket-core/src/commonMain/kotlin/io/rsocket/kotlin/transport/internal/PrioritizationFrameQueue.kt @@ -16,19 +16,19 @@ package io.rsocket.kotlin.transport.internal -import io.ktor.utils.io.core.* import io.rsocket.kotlin.internal.io.* import io.rsocket.kotlin.transport.* import kotlinx.coroutines.* import kotlinx.coroutines.channels.* import kotlinx.coroutines.selects.* +import kotlinx.io.* -private val selectFrame: suspend (ChannelResult) -> ChannelResult = { it } +private val selectFrame: suspend (ChannelResult) -> ChannelResult = { it } @RSocketTransportApi public class PrioritizationFrameQueue(buffersCapacity: Int) { - private val priorityFrames = channelForCloseable(buffersCapacity) - private val normalFrames = channelForCloseable(buffersCapacity) + private val priorityFrames = bufferChannel(buffersCapacity) + private val normalFrames = bufferChannel(buffersCapacity) private val priorityOnReceive = priorityFrames.onReceiveCatching private val normalOnReceive = normalFrames.onReceiveCatching @@ -37,14 +37,14 @@ public class PrioritizationFrameQueue(buffersCapacity: Int) { @OptIn(DelicateCoroutinesApi::class) public val isClosedForSend: Boolean get() = priorityFrames.isClosedForSend - private fun channel(streamId: Int): SendChannel = when (streamId) { + private fun channel(streamId: Int): SendChannel = when (streamId) { 0 -> priorityFrames else -> normalFrames } - public suspend fun enqueueFrame(streamId: Int, frame: ByteReadPacket): Unit = channel(streamId).send(frame) + public suspend fun enqueueFrame(streamId: Int, frame: Buffer): Unit = channel(streamId).send(frame) - public fun tryDequeueFrame(): ByteReadPacket? { + public fun tryDequeueFrame(): Buffer? { // priority is first priorityFrames.tryReceive().onSuccess { return it } normalFrames.tryReceive().onSuccess { return it } @@ -52,7 +52,7 @@ public class PrioritizationFrameQueue(buffersCapacity: Int) { } // TODO: recheck, that it works fine in case priority channel is closed, but normal channel has other frames to send - public suspend fun dequeueFrame(): ByteReadPacket? { + public suspend fun dequeueFrame(): Buffer? { tryDequeueFrame()?.let { return it } return select { priorityOnReceive(selectFrame) diff --git a/rsocket-core/src/commonTest/kotlin/io/rsocket/kotlin/ConnectionEstablishmentTest.kt b/rsocket-core/src/commonTest/kotlin/io/rsocket/kotlin/ConnectionEstablishmentTest.kt index c5e44ced..86d7b8cd 100644 --- a/rsocket-core/src/commonTest/kotlin/io/rsocket/kotlin/ConnectionEstablishmentTest.kt +++ b/rsocket-core/src/commonTest/kotlin/io/rsocket/kotlin/ConnectionEstablishmentTest.kt @@ -16,7 +16,6 @@ package io.rsocket.kotlin -import io.ktor.utils.io.core.* import io.rsocket.kotlin.frame.* import io.rsocket.kotlin.frame.io.* import io.rsocket.kotlin.keepalive.* @@ -27,7 +26,7 @@ import kotlinx.coroutines.* import kotlin.coroutines.* import kotlin.test.* -class ConnectionEstablishmentTest : SuspendTest, TestWithLeakCheck { +class ConnectionEstablishmentTest : SuspendTest { private class TestInstance(val deferred: Deferred) : RSocketServerInstance { override val coroutineContext: CoroutineContext get() = deferred @@ -101,14 +100,14 @@ class ConnectionEstablishmentTest : SuspendTest, TestWithLeakCheck { setupPayload { p } } acceptor { - assertTrue(config.setupPayload.data.isNotEmpty) - assertTrue(p.data.isNotEmpty) + assertTrue(!config.setupPayload.data.exhausted()) + assertTrue(!p.data.exhausted()) error("failed") } }.connect(connection) } connection.coroutineContext.job.join() - assertTrue(p.data.isEmpty) + assertTrue(p.data.exhausted()) } } diff --git a/rsocket-core/src/commonTest/kotlin/io/rsocket/kotlin/TestConnection.kt b/rsocket-core/src/commonTest/kotlin/io/rsocket/kotlin/TestConnection.kt index 107e2cfe..d2f1d851 100644 --- a/rsocket-core/src/commonTest/kotlin/io/rsocket/kotlin/TestConnection.kt +++ b/rsocket-core/src/commonTest/kotlin/io/rsocket/kotlin/TestConnection.kt @@ -17,7 +17,6 @@ package io.rsocket.kotlin import app.cash.turbine.* -import io.ktor.utils.io.core.* import io.rsocket.kotlin.frame.* import io.rsocket.kotlin.internal.io.* import io.rsocket.kotlin.test.* @@ -25,6 +24,7 @@ import io.rsocket.kotlin.transport.* import kotlinx.coroutines.* import kotlinx.coroutines.channels.* import kotlinx.coroutines.flow.* +import kotlinx.io.* import kotlin.coroutines.* import kotlin.test.* import kotlin.time.* @@ -34,8 +34,8 @@ class TestConnection : RSocketSequentialConnection, RSocketClientTarget { private val job = Job() override val coroutineContext: CoroutineContext = job + Dispatchers.Unconfined + TestExceptionHandler - private val sendChannel = channelForCloseable(Channel.UNLIMITED) - private val receiveChannel = channelForCloseable(Channel.UNLIMITED) + private val sendChannel = bufferChannel(Channel.UNLIMITED) + private val receiveChannel = bufferChannel(Channel.UNLIMITED) init { coroutineContext.job.invokeOnCompletion { @@ -52,28 +52,28 @@ class TestConnection : RSocketSequentialConnection, RSocketClientTarget { override val isClosedForSend: Boolean get() = sendChannel.isClosedForSend - override suspend fun sendFrame(streamId: Int, frame: ByteReadPacket) { + override suspend fun sendFrame(streamId: Int, frame: Buffer) { sendChannel.send(frame) } - override suspend fun receiveFrame(): ByteReadPacket { + override suspend fun receiveFrame(): Buffer? { return receiveChannel.receive() } suspend fun ignoreSetupFrame() { - assertEquals(FrameType.Setup, sendChannel.receive().readFrame(InUseTrackingPool).type) + assertEquals(FrameType.Setup, sendChannel.receive().readFrame().type) } internal suspend fun sendToReceiver(vararg frames: Frame) { frames.forEach { - val packet = it.toPacket(InUseTrackingPool) + val packet = it.toBuffer() receiveChannel.send(packet) } } internal suspend fun test(validate: suspend ReceiveTurbine.() -> Unit) { sendChannel.consumeAsFlow().map { - it.readFrame(InUseTrackingPool) + it.readFrame() }.test(5.seconds, validate = validate) } } diff --git a/rsocket-core/src/commonTest/kotlin/io/rsocket/kotlin/core/RSocketTest.kt b/rsocket-core/src/commonTest/kotlin/io/rsocket/kotlin/core/RSocketTest.kt index 3ee10863..6771a99f 100644 --- a/rsocket-core/src/commonTest/kotlin/io/rsocket/kotlin/core/RSocketTest.kt +++ b/rsocket-core/src/commonTest/kotlin/io/rsocket/kotlin/core/RSocketTest.kt @@ -17,7 +17,6 @@ package io.rsocket.kotlin.core import app.cash.turbine.* -import io.ktor.utils.io.core.* import io.rsocket.kotlin.* import io.rsocket.kotlin.keepalive.* import io.rsocket.kotlin.payload.* @@ -26,6 +25,7 @@ import io.rsocket.kotlin.transport.local.* import kotlinx.coroutines.* import kotlinx.coroutines.channels.* import kotlinx.coroutines.flow.* +import kotlinx.io.* import kotlin.coroutines.* import kotlin.test.* import kotlin.time.Duration.Companion.seconds @@ -80,7 +80,7 @@ abstract class RSocketTest( context: CoroutineContext, acceptor: ConnectionAcceptor, ) -> RSocket, -) : SuspendTest, TestWithLeakCheck { +) : SuspendTest { private val testJob: Job = Job() @@ -150,7 +150,7 @@ abstract class RSocketTest( val requester = start(RSocketRequestHandler { requestStream { //copy payload, for some specific usage, and don't release original payload - val text = it.copy().use { it.data.readText() } + val text = it.copy().use { it.data.readString() } p = it //don't use payload flow { @@ -171,7 +171,7 @@ abstract class RSocketTest( assertEquals("FAIL", error.message) } delay(100) //async cancellation - assertEquals(0, p?.data?.remaining) + assertTrue(p?.data?.exhausted() ?: false) } @Test @@ -514,8 +514,8 @@ abstract class RSocketTest( private suspend fun ReceiveChannel.checkReceived(otherPayload: Payload) { val payload = receive() - assertEquals(payload.metadata?.readText(), otherPayload.metadata?.readText()) - assertEquals(payload.data.readText(), otherPayload.data.readText()) + assertEquals(payload.metadata?.readString(), otherPayload.metadata?.readString()) + assertEquals(payload.data.readString(), otherPayload.data.readString()) } } diff --git a/rsocket-core/src/commonTest/kotlin/io/rsocket/kotlin/core/ReconnectableRSocketTest.kt b/rsocket-core/src/commonTest/kotlin/io/rsocket/kotlin/core/ReconnectableRSocketTest.kt index 606d69dc..7f267378 100644 --- a/rsocket-core/src/commonTest/kotlin/io/rsocket/kotlin/core/ReconnectableRSocketTest.kt +++ b/rsocket-core/src/commonTest/kotlin/io/rsocket/kotlin/core/ReconnectableRSocketTest.kt @@ -17,7 +17,6 @@ package io.rsocket.kotlin.core import app.cash.turbine.* -import io.ktor.utils.io.core.* import io.rsocket.kotlin.* import io.rsocket.kotlin.logging.* import io.rsocket.kotlin.payload.* @@ -28,7 +27,7 @@ import kotlinx.coroutines.flow.* import kotlin.test.* import kotlin.time.Duration.Companion.seconds -class ReconnectableRSocketTest : SuspendTest, TestWithLeakCheck { +class ReconnectableRSocketTest : SuspendTest { //needed for native private val fails = atomic(0) @@ -250,13 +249,13 @@ class ReconnectableRSocketTest : SuspendTest, TestWithLeakCheck { assertFails { rSocket.interaction(p) //test release on reconnecting } - assertTrue(p.data.isEmpty) + assertTrue(p.data.exhausted()) val p2 = payload("text") assertFails { rSocket.interaction(p2) //test release on failed } - assertTrue(p2.data.isEmpty) + assertTrue(p2.data.exhausted()) } private fun handler(job: Job): RSocket = RSocketRequestHandler(job) { diff --git a/rsocket-core/src/commonTest/kotlin/io/rsocket/kotlin/frame/CancelFrameTest.kt b/rsocket-core/src/commonTest/kotlin/io/rsocket/kotlin/frame/CancelFrameTest.kt index 2a0a9f00..bc2524f2 100644 --- a/rsocket-core/src/commonTest/kotlin/io/rsocket/kotlin/frame/CancelFrameTest.kt +++ b/rsocket-core/src/commonTest/kotlin/io/rsocket/kotlin/frame/CancelFrameTest.kt @@ -1,5 +1,5 @@ /* - * Copyright 2015-2022 the original author or authors. + * Copyright 2015-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,10 +16,9 @@ package io.rsocket.kotlin.frame -import io.rsocket.kotlin.test.* import kotlin.test.* -class CancelFrameTest : TestWithLeakCheck { +class CancelFrameTest { private val streamId = 1 diff --git a/rsocket-core/src/commonTest/kotlin/io/rsocket/kotlin/frame/ErrorFrameTest.kt b/rsocket-core/src/commonTest/kotlin/io/rsocket/kotlin/frame/ErrorFrameTest.kt index 49322bbe..815bac9f 100644 --- a/rsocket-core/src/commonTest/kotlin/io/rsocket/kotlin/frame/ErrorFrameTest.kt +++ b/rsocket-core/src/commonTest/kotlin/io/rsocket/kotlin/frame/ErrorFrameTest.kt @@ -16,19 +16,19 @@ package io.rsocket.kotlin.frame -import io.ktor.utils.io.core.* import io.rsocket.kotlin.* import io.rsocket.kotlin.test.* +import kotlinx.io.* import kotlin.test.* -class ErrorFrameTest : TestWithLeakCheck { +class ErrorFrameTest { private val dump = "00000b000000012c000000020164" @Test fun testEncoding() { val frame = ErrorFrame(1, RSocketError.ApplicationError("d")) - val bytes = frame.toPacketWithLength().readBytes() + val bytes = frame.toBufferWithLength().readByteArray() assertEquals(dump, bytes.toHexString()) } diff --git a/rsocket-core/src/commonTest/kotlin/io/rsocket/kotlin/frame/ExtensionFrameTest.kt b/rsocket-core/src/commonTest/kotlin/io/rsocket/kotlin/frame/ExtensionFrameTest.kt index 06ee8be7..7cc821ee 100644 --- a/rsocket-core/src/commonTest/kotlin/io/rsocket/kotlin/frame/ExtensionFrameTest.kt +++ b/rsocket-core/src/commonTest/kotlin/io/rsocket/kotlin/frame/ExtensionFrameTest.kt @@ -1,5 +1,5 @@ /* - * Copyright 2015-2022 the original author or authors. + * Copyright 2015-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,12 +16,13 @@ package io.rsocket.kotlin.frame -import io.ktor.utils.io.core.* +import io.rsocket.kotlin.frame.io.* import io.rsocket.kotlin.payload.* import io.rsocket.kotlin.test.* +import kotlinx.io.* import kotlin.test.* -class ExtensionFrameTest : TestWithLeakCheck { +class ExtensionFrameTest { private val streamId = 1 private val extendedType = 1 @@ -37,19 +38,19 @@ class ExtensionFrameTest : TestWithLeakCheck { assertEquals(streamId, decodedFrame.streamId) assertEquals(extendedType, decodedFrame.extendedType) assertNull(decodedFrame.payload.metadata) - assertEquals(data, decodedFrame.payload.data.readText()) + assertEquals(data, decodedFrame.payload.data.readString()) } @Test fun testMetadata() { - val frame = ExtensionFrame(1, extendedType, Payload(ByteReadPacket.Empty, packet(metadata))) + val frame = ExtensionFrame(1, extendedType, Payload(EmptyBuffer, packet(metadata))) val decodedFrame = frame.loopFrame() assertTrue(decodedFrame is ExtensionFrame) assertEquals(streamId, decodedFrame.streamId) assertEquals(extendedType, decodedFrame.extendedType) - assertEquals(metadata, decodedFrame.payload.metadata?.readText()) - assertEquals(0, decodedFrame.payload.data.remaining) + assertEquals(metadata, decodedFrame.payload.metadata?.readString()) + assertTrue(decodedFrame.payload.data.exhausted()) } @Test @@ -60,7 +61,7 @@ class ExtensionFrameTest : TestWithLeakCheck { assertTrue(decodedFrame is ExtensionFrame) assertEquals(streamId, decodedFrame.streamId) assertEquals(extendedType, decodedFrame.extendedType) - assertEquals(metadata, decodedFrame.payload.metadata?.readText()) - assertEquals(data, decodedFrame.payload.data.readText()) + assertEquals(metadata, decodedFrame.payload.metadata?.readString()) + assertEquals(data, decodedFrame.payload.data.readString()) } } diff --git a/rsocket-core/src/commonTest/kotlin/io/rsocket/kotlin/frame/KeepAliveFrameTest.kt b/rsocket-core/src/commonTest/kotlin/io/rsocket/kotlin/frame/KeepAliveFrameTest.kt index f0236131..e0bd87a6 100644 --- a/rsocket-core/src/commonTest/kotlin/io/rsocket/kotlin/frame/KeepAliveFrameTest.kt +++ b/rsocket-core/src/commonTest/kotlin/io/rsocket/kotlin/frame/KeepAliveFrameTest.kt @@ -16,17 +16,17 @@ package io.rsocket.kotlin.frame -import io.ktor.utils.io.core.* import io.rsocket.kotlin.test.* +import kotlinx.io.* import kotlin.test.* -class KeepAliveFrameTest : TestWithLeakCheck { +class KeepAliveFrameTest { private val dump = "00000f000000000c80000000000000000064" @Test fun testEncoding() { val frame = KeepAliveFrame(true, 0, packet("d")) - val bytes = frame.toPacketWithLength().readBytes() + val bytes = frame.toBufferWithLength().readByteArray() assertEquals(dump, bytes.toHexString()) } @@ -40,6 +40,6 @@ class KeepAliveFrameTest : TestWithLeakCheck { assertEquals(0, frame.streamId) assertTrue(frame.respond) assertEquals(0, frame.lastPosition) - assertEquals("d", frame.data.readText()) + assertEquals("d", frame.data.readString()) } } diff --git a/rsocket-core/src/commonTest/kotlin/io/rsocket/kotlin/frame/LeaseFrameTest.kt b/rsocket-core/src/commonTest/kotlin/io/rsocket/kotlin/frame/LeaseFrameTest.kt index 76be88da..97676cc4 100644 --- a/rsocket-core/src/commonTest/kotlin/io/rsocket/kotlin/frame/LeaseFrameTest.kt +++ b/rsocket-core/src/commonTest/kotlin/io/rsocket/kotlin/frame/LeaseFrameTest.kt @@ -1,5 +1,5 @@ /* - * Copyright 2015-2022 the original author or authors. + * Copyright 2015-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -17,9 +17,10 @@ package io.rsocket.kotlin.frame import io.rsocket.kotlin.test.* +import kotlinx.io.* import kotlin.test.* -class LeaseFrameTest : TestWithLeakCheck { +class LeaseFrameTest { private val ttl = 1 private val numberOfRequests = 42 @@ -34,7 +35,7 @@ class LeaseFrameTest : TestWithLeakCheck { assertEquals(0, decodedFrame.streamId) assertEquals(ttl, decodedFrame.ttl) assertEquals(numberOfRequests, decodedFrame.numberOfRequests) - assertEquals(metadata, decodedFrame.metadata?.readText()) + assertEquals(metadata, decodedFrame.metadata?.readString()) } @Test diff --git a/rsocket-core/src/commonTest/kotlin/io/rsocket/kotlin/frame/MetadataPushFrameTest.kt b/rsocket-core/src/commonTest/kotlin/io/rsocket/kotlin/frame/MetadataPushFrameTest.kt index dd1c6f3b..ce3a9c82 100644 --- a/rsocket-core/src/commonTest/kotlin/io/rsocket/kotlin/frame/MetadataPushFrameTest.kt +++ b/rsocket-core/src/commonTest/kotlin/io/rsocket/kotlin/frame/MetadataPushFrameTest.kt @@ -1,5 +1,5 @@ /* - * Copyright 2015-2022 the original author or authors. + * Copyright 2015-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,11 +16,11 @@ package io.rsocket.kotlin.frame -import io.ktor.utils.io.core.* import io.rsocket.kotlin.test.* +import kotlinx.io.* import kotlin.test.* -class MetadataPushFrameTest : TestWithLeakCheck { +class MetadataPushFrameTest { private val metadata = ByteArray(65000) { 6 } @@ -31,7 +31,7 @@ class MetadataPushFrameTest : TestWithLeakCheck { assertTrue(decodedFrame is MetadataPushFrame) assertEquals(0, decodedFrame.streamId) - assertBytesEquals(metadata, decodedFrame.metadata.readBytes()) + assertBytesEquals(metadata, decodedFrame.metadata.readByteArray()) } } diff --git a/rsocket-core/src/commonTest/kotlin/io/rsocket/kotlin/frame/PayloadFrameTest.kt b/rsocket-core/src/commonTest/kotlin/io/rsocket/kotlin/frame/PayloadFrameTest.kt index acbfeea7..32fdf2c5 100644 --- a/rsocket-core/src/commonTest/kotlin/io/rsocket/kotlin/frame/PayloadFrameTest.kt +++ b/rsocket-core/src/commonTest/kotlin/io/rsocket/kotlin/frame/PayloadFrameTest.kt @@ -1,5 +1,5 @@ /* - * Copyright 2015-2022 the original author or authors. + * Copyright 2015-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,12 +16,13 @@ package io.rsocket.kotlin.frame -import io.ktor.utils.io.core.* +import io.rsocket.kotlin.frame.io.* import io.rsocket.kotlin.payload.* import io.rsocket.kotlin.test.* +import kotlinx.io.* import kotlin.test.* -class PayloadFrameTest : TestWithLeakCheck { +class PayloadFrameTest { @Test fun testNextCompleteDataMetadata() { @@ -34,8 +35,8 @@ class PayloadFrameTest : TestWithLeakCheck { assertFalse(decodedFrame.follows) assertTrue(decodedFrame.complete) assertTrue(decodedFrame.next) - assertEquals("d", decodedFrame.payload.data.readText()) - assertEquals("md", decodedFrame.payload.metadata?.readText()) + assertEquals("d", decodedFrame.payload.data.readString()) + assertEquals("md", decodedFrame.payload.metadata?.readString()) } @Test @@ -49,13 +50,13 @@ class PayloadFrameTest : TestWithLeakCheck { assertFalse(decodedFrame.follows) assertTrue(decodedFrame.complete) assertTrue(decodedFrame.next) - assertEquals("d", decodedFrame.payload.data.readText()) + assertEquals("d", decodedFrame.payload.data.readString()) assertNull(decodedFrame.payload.metadata) } @Test fun testNextCompleteMetadata() { - val frame = NextCompletePayloadFrame(3, Payload(ByteReadPacket.Empty, packet("md"))) + val frame = NextCompletePayloadFrame(3, Payload(EmptyBuffer, packet("md"))) val decodedFrame = frame.loopFrame() assertTrue(decodedFrame is RequestFrame) @@ -64,8 +65,8 @@ class PayloadFrameTest : TestWithLeakCheck { assertFalse(decodedFrame.follows) assertTrue(decodedFrame.complete) assertTrue(decodedFrame.next) - assertEquals(0, decodedFrame.payload.data.remaining) - assertEquals("md", decodedFrame.payload.metadata?.readText()) + assertTrue(decodedFrame.payload.data.exhausted()) + assertEquals("md", decodedFrame.payload.metadata?.readString()) } @Test @@ -79,8 +80,8 @@ class PayloadFrameTest : TestWithLeakCheck { assertFalse(decodedFrame.follows) assertFalse(decodedFrame.complete) assertTrue(decodedFrame.next) - assertEquals("d", decodedFrame.payload.data.readText()) - assertEquals("md", decodedFrame.payload.metadata?.readText()) + assertEquals("d", decodedFrame.payload.data.readString()) + assertEquals("md", decodedFrame.payload.metadata?.readString()) } @Test @@ -94,13 +95,13 @@ class PayloadFrameTest : TestWithLeakCheck { assertFalse(decodedFrame.follows) assertFalse(decodedFrame.complete) assertTrue(decodedFrame.next) - assertEquals("d", decodedFrame.payload.data.readText()) + assertEquals("d", decodedFrame.payload.data.readString()) assertNull(decodedFrame.payload.metadata) } @Test fun testNextDataEmptyMetadata() { - val frame = NextPayloadFrame(3, Payload(packet("d"), ByteReadPacket.Empty)) + val frame = NextPayloadFrame(3, Payload(packet("d"), Buffer())) val decodedFrame = frame.loopFrame() assertTrue(decodedFrame is RequestFrame) @@ -109,8 +110,8 @@ class PayloadFrameTest : TestWithLeakCheck { assertFalse(decodedFrame.follows) assertFalse(decodedFrame.complete) assertTrue(decodedFrame.next) - assertEquals("d", decodedFrame.payload.data.readText()) - assertEquals(0, decodedFrame.payload.metadata?.remaining) + assertEquals("d", decodedFrame.payload.data.readString()) + assertTrue(decodedFrame.payload.metadata?.exhausted() ?: false) } } diff --git a/rsocket-core/src/commonTest/kotlin/io/rsocket/kotlin/frame/RequestFireAndForgetFrameTest.kt b/rsocket-core/src/commonTest/kotlin/io/rsocket/kotlin/frame/RequestFireAndForgetFrameTest.kt index 1c152f57..067910c5 100644 --- a/rsocket-core/src/commonTest/kotlin/io/rsocket/kotlin/frame/RequestFireAndForgetFrameTest.kt +++ b/rsocket-core/src/commonTest/kotlin/io/rsocket/kotlin/frame/RequestFireAndForgetFrameTest.kt @@ -1,5 +1,5 @@ /* - * Copyright 2015-2022 the original author or authors. + * Copyright 2015-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -17,9 +17,10 @@ package io.rsocket.kotlin.frame import io.rsocket.kotlin.test.* +import kotlinx.io.* import kotlin.test.* -class RequestFireAndForgetFrameTest : TestWithLeakCheck { +class RequestFireAndForgetFrameTest { @Test fun testData() { @@ -32,7 +33,7 @@ class RequestFireAndForgetFrameTest : TestWithLeakCheck { assertFalse(decodedFrame.follows) assertFalse(decodedFrame.complete) assertFalse(decodedFrame.next) - assertEquals("d", decodedFrame.payload.data.readText()) + assertEquals("d", decodedFrame.payload.data.readString()) assertEquals(null, decodedFrame.payload.metadata) } @@ -47,8 +48,8 @@ class RequestFireAndForgetFrameTest : TestWithLeakCheck { assertFalse(decodedFrame.follows) assertFalse(decodedFrame.complete) assertFalse(decodedFrame.next) - assertEquals("d", decodedFrame.payload.data.readText()) - assertEquals("md", decodedFrame.payload.metadata?.readText()) + assertEquals("d", decodedFrame.payload.data.readString()) + assertEquals("md", decodedFrame.payload.metadata?.readString()) } } diff --git a/rsocket-core/src/commonTest/kotlin/io/rsocket/kotlin/frame/RequestNFrameTest.kt b/rsocket-core/src/commonTest/kotlin/io/rsocket/kotlin/frame/RequestNFrameTest.kt index 0582afe9..9200124d 100644 --- a/rsocket-core/src/commonTest/kotlin/io/rsocket/kotlin/frame/RequestNFrameTest.kt +++ b/rsocket-core/src/commonTest/kotlin/io/rsocket/kotlin/frame/RequestNFrameTest.kt @@ -16,18 +16,18 @@ package io.rsocket.kotlin.frame -import io.ktor.utils.io.core.* import io.rsocket.kotlin.test.* +import kotlinx.io.* import kotlin.test.* -class RequestNFrameTest : TestWithLeakCheck { +class RequestNFrameTest { private val dump = "00000a00000001200000000005" @Test fun testEncoding() { val frame = RequestNFrame(1, 5) - val bytes = frame.toPacketWithLength().readBytes() + val bytes = frame.toBufferWithLength().readByteArray() assertEquals(dump, bytes.toHexString()) } diff --git a/rsocket-core/src/commonTest/kotlin/io/rsocket/kotlin/frame/RequestResponseFrameTest.kt b/rsocket-core/src/commonTest/kotlin/io/rsocket/kotlin/frame/RequestResponseFrameTest.kt index cbfb3757..6cbfc2f2 100644 --- a/rsocket-core/src/commonTest/kotlin/io/rsocket/kotlin/frame/RequestResponseFrameTest.kt +++ b/rsocket-core/src/commonTest/kotlin/io/rsocket/kotlin/frame/RequestResponseFrameTest.kt @@ -1,5 +1,5 @@ /* - * Copyright 2015-2022 the original author or authors. + * Copyright 2015-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,11 +16,11 @@ package io.rsocket.kotlin.frame -import io.ktor.utils.io.core.* import io.rsocket.kotlin.test.* +import kotlinx.io.* import kotlin.test.* -class RequestResponseFrameTest : TestWithLeakCheck { +class RequestResponseFrameTest { @Test fun testData() { @@ -33,7 +33,7 @@ class RequestResponseFrameTest : TestWithLeakCheck { assertFalse(decodedFrame.follows) assertFalse(decodedFrame.complete) assertFalse(decodedFrame.next) - assertEquals("d", decodedFrame.payload.data.readText()) + assertEquals("d", decodedFrame.payload.data.readString()) assertEquals(null, decodedFrame.payload.metadata) } @@ -48,8 +48,8 @@ class RequestResponseFrameTest : TestWithLeakCheck { assertFalse(decodedFrame.follows) assertFalse(decodedFrame.complete) assertFalse(decodedFrame.next) - assertEquals("d", decodedFrame.payload.data.readText()) - assertEquals("md", decodedFrame.payload.metadata?.readText()) + assertEquals("d", decodedFrame.payload.data.readString()) + assertEquals("md", decodedFrame.payload.metadata?.readString()) } @Test @@ -66,8 +66,8 @@ class RequestResponseFrameTest : TestWithLeakCheck { assertFalse(decodedFrame.follows) assertFalse(decodedFrame.complete) assertFalse(decodedFrame.next) - assertBytesEquals(data, decodedFrame.payload.data.readBytes()) - assertBytesEquals(metadata, decodedFrame.payload.metadata?.readBytes()) + assertBytesEquals(data, decodedFrame.payload.data.readByteArray()) + assertBytesEquals(metadata, decodedFrame.payload.metadata?.readByteArray()) } } diff --git a/rsocket-core/src/commonTest/kotlin/io/rsocket/kotlin/frame/RequestStreamFrameTest.kt b/rsocket-core/src/commonTest/kotlin/io/rsocket/kotlin/frame/RequestStreamFrameTest.kt index 0e115967..5f2f5559 100644 --- a/rsocket-core/src/commonTest/kotlin/io/rsocket/kotlin/frame/RequestStreamFrameTest.kt +++ b/rsocket-core/src/commonTest/kotlin/io/rsocket/kotlin/frame/RequestStreamFrameTest.kt @@ -16,18 +16,19 @@ package io.rsocket.kotlin.frame -import io.ktor.utils.io.core.* +import io.rsocket.kotlin.frame.io.* import io.rsocket.kotlin.payload.* import io.rsocket.kotlin.test.* +import kotlinx.io.* import kotlin.test.* -class RequestStreamFrameTest : TestWithLeakCheck { +class RequestStreamFrameTest { @Test fun testEncoding() { val dump = "000010000000011900000000010000026d6464" val frame = RequestStreamFrame(1, 1, payload("d", "md")) - val bytes = frame.toPacketWithLength().readBytes() + val bytes = frame.toBufferWithLength().readByteArray() assertEquals(dump, bytes.toHexString()) } @@ -44,15 +45,15 @@ class RequestStreamFrameTest : TestWithLeakCheck { assertFalse(frame.complete) assertFalse(frame.next) assertEquals(1, frame.initialRequest) - assertEquals("d", frame.payload.data.readText()) - assertEquals("md", frame.payload.metadata?.readText()) + assertEquals("d", frame.payload.data.readString()) + assertEquals("md", frame.payload.metadata?.readString()) } @Test fun testEncodingWithEmptyMetadata() { val dump = "00000e0000000119000000000100000064" - val frame = RequestStreamFrame(1, 1, Payload(packet("d"), ByteReadPacket.Empty)) - val bytes = frame.toPacketWithLength().readBytes() + val frame = RequestStreamFrame(1, 1, Payload(packet("d"), Buffer())) + val bytes = frame.toBufferWithLength().readByteArray() assertEquals(dump, bytes.toHexString()) } @@ -69,15 +70,15 @@ class RequestStreamFrameTest : TestWithLeakCheck { assertFalse(frame.complete) assertFalse(frame.next) assertEquals(1, frame.initialRequest) - assertEquals("d", frame.payload.data.readText()) - assertEquals(0, frame.payload.metadata?.remaining) + assertEquals("d", frame.payload.data.readString()) + assertTrue(frame.payload.metadata?.exhausted() ?: false) } @Test fun testEncodingWithNullMetadata() { val dump = "00000b0000000118000000000164" val frame = RequestStreamFrame(1, 1, payload("d")) - val bytes = frame.toPacketWithLength().readBytes() + val bytes = frame.toBufferWithLength().readByteArray() assertEquals(dump, bytes.toHexString()) } @@ -94,13 +95,13 @@ class RequestStreamFrameTest : TestWithLeakCheck { assertFalse(frame.complete) assertFalse(frame.next) assertEquals(1, frame.initialRequest) - assertEquals("d", frame.payload.data.readText()) + assertEquals("d", frame.payload.data.readString()) assertNull(frame.payload.metadata) } @Test fun testEmptyData() { - val frame = RequestStreamFrame(3, 10, Payload(ByteReadPacket.Empty, packet("md"))) + val frame = RequestStreamFrame(3, 10, Payload(EmptyBuffer, packet("md"))) val decodedFrame = frame.loopFrame() assertTrue(decodedFrame is RequestFrame) @@ -110,13 +111,13 @@ class RequestStreamFrameTest : TestWithLeakCheck { assertFalse(decodedFrame.complete) assertFalse(decodedFrame.next) assertEquals(10, decodedFrame.initialRequest) - assertEquals(0, decodedFrame.payload.data.remaining) - assertEquals("md", decodedFrame.payload.metadata?.readText()) + assertTrue(decodedFrame.payload.data.exhausted()) + assertEquals("md", decodedFrame.payload.metadata?.readString()) } @Test fun testEmptyPayload() { - val frame = RequestStreamFrame(3, 10, Payload(ByteReadPacket.Empty, ByteReadPacket.Empty)) + val frame = RequestStreamFrame(3, 10, Payload(EmptyBuffer, Buffer())) val decodedFrame = frame.loopFrame() assertTrue(decodedFrame is RequestFrame) @@ -126,8 +127,8 @@ class RequestStreamFrameTest : TestWithLeakCheck { assertFalse(decodedFrame.complete) assertFalse(decodedFrame.next) assertEquals(10, decodedFrame.initialRequest) - assertEquals(0, decodedFrame.payload.data.remaining) - assertEquals(0, decodedFrame.payload.metadata?.remaining) + assertTrue(decodedFrame.payload.data.exhausted()) + assertTrue(decodedFrame.payload.metadata?.exhausted() ?: false) } @Test @@ -142,8 +143,8 @@ class RequestStreamFrameTest : TestWithLeakCheck { assertFalse(decodedFrame.complete) assertFalse(decodedFrame.next) assertEquals(Int.MAX_VALUE, decodedFrame.initialRequest) - assertEquals("d", decodedFrame.payload.data.readText()) - assertEquals("md", decodedFrame.payload.metadata?.readText()) + assertEquals("d", decodedFrame.payload.data.readString()) + assertEquals("md", decodedFrame.payload.metadata?.readString()) } } diff --git a/rsocket-core/src/commonTest/kotlin/io/rsocket/kotlin/frame/ResumeFrameTest.kt b/rsocket-core/src/commonTest/kotlin/io/rsocket/kotlin/frame/ResumeFrameTest.kt index 634ffaa3..382dc073 100644 --- a/rsocket-core/src/commonTest/kotlin/io/rsocket/kotlin/frame/ResumeFrameTest.kt +++ b/rsocket-core/src/commonTest/kotlin/io/rsocket/kotlin/frame/ResumeFrameTest.kt @@ -1,5 +1,5 @@ /* - * Copyright 2015-2022 the original author or authors. + * Copyright 2015-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,12 +16,12 @@ package io.rsocket.kotlin.frame -import io.ktor.utils.io.core.* import io.rsocket.kotlin.frame.io.* import io.rsocket.kotlin.test.* +import kotlinx.io.* import kotlin.test.* -class ResumeFrameTest : TestWithLeakCheck { +class ResumeFrameTest { private val version = Version.Current private val lastReceivedServerPosition = 21L @@ -36,7 +36,7 @@ class ResumeFrameTest : TestWithLeakCheck { assertTrue(decodedFrame is ResumeFrame) assertEquals(0, decodedFrame.streamId) assertEquals(version, decodedFrame.version) - assertBytesEquals(token, decodedFrame.resumeToken.readBytes()) + assertBytesEquals(token, decodedFrame.resumeToken.readByteArray()) assertEquals(lastReceivedServerPosition, decodedFrame.lastReceivedServerPosition) assertEquals(firstAvailableClientPosition, decodedFrame.firstAvailableClientPosition) } @@ -51,7 +51,7 @@ class ResumeFrameTest : TestWithLeakCheck { assertTrue(decodedFrame is ResumeFrame) assertEquals(0, decodedFrame.streamId) assertEquals(version, decodedFrame.version) - assertBytesEquals(token, decodedFrame.resumeToken.readBytes()) + assertBytesEquals(token, decodedFrame.resumeToken.readByteArray()) assertEquals(lastReceivedServerPosition, decodedFrame.lastReceivedServerPosition) assertEquals(firstAvailableClientPosition, decodedFrame.firstAvailableClientPosition) } @@ -65,7 +65,7 @@ class ResumeFrameTest : TestWithLeakCheck { assertTrue(decodedFrame is ResumeFrame) assertEquals(0, decodedFrame.streamId) assertEquals(version, decodedFrame.version) - assertBytesEquals(token, decodedFrame.resumeToken.readBytes()) + assertBytesEquals(token, decodedFrame.resumeToken.readByteArray()) assertEquals(lastReceivedServerPosition, decodedFrame.lastReceivedServerPosition) assertEquals(firstAvailableClientPosition, decodedFrame.firstAvailableClientPosition) } diff --git a/rsocket-core/src/commonTest/kotlin/io/rsocket/kotlin/frame/ResumeOkFrameTest.kt b/rsocket-core/src/commonTest/kotlin/io/rsocket/kotlin/frame/ResumeOkFrameTest.kt index 7562b7e9..d3ddbb08 100644 --- a/rsocket-core/src/commonTest/kotlin/io/rsocket/kotlin/frame/ResumeOkFrameTest.kt +++ b/rsocket-core/src/commonTest/kotlin/io/rsocket/kotlin/frame/ResumeOkFrameTest.kt @@ -1,5 +1,5 @@ /* - * Copyright 2015-2022 the original author or authors. + * Copyright 2015-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,10 +16,9 @@ package io.rsocket.kotlin.frame -import io.rsocket.kotlin.test.* import kotlin.test.* -class ResumeOkFrameTest : TestWithLeakCheck { +class ResumeOkFrameTest { private val lastReceivedClientPosition = 42L diff --git a/rsocket-core/src/commonTest/kotlin/io/rsocket/kotlin/frame/SetupFrameTest.kt b/rsocket-core/src/commonTest/kotlin/io/rsocket/kotlin/frame/SetupFrameTest.kt index 4c67c007..1a07ab66 100644 --- a/rsocket-core/src/commonTest/kotlin/io/rsocket/kotlin/frame/SetupFrameTest.kt +++ b/rsocket-core/src/commonTest/kotlin/io/rsocket/kotlin/frame/SetupFrameTest.kt @@ -1,5 +1,5 @@ /* - * Copyright 2015-2022 the original author or authors. + * Copyright 2015-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,16 +16,16 @@ package io.rsocket.kotlin.frame -import io.ktor.utils.io.core.* import io.rsocket.kotlin.core.* import io.rsocket.kotlin.frame.io.* import io.rsocket.kotlin.keepalive.* import io.rsocket.kotlin.payload.* import io.rsocket.kotlin.test.* +import kotlinx.io.* import kotlin.test.* import kotlin.time.Duration.Companion.seconds -class SetupFrameTest : TestWithLeakCheck { +class SetupFrameTest { private val version = Version.Current private val keepAlive = KeepAlive(10.seconds, 500.seconds) @@ -45,7 +45,7 @@ class SetupFrameTest : TestWithLeakCheck { assertNull(decodedFrame.resumeToken) assertEquals(payloadMimeType.data, decodedFrame.payloadMimeType.data) assertEquals(payloadMimeType.metadata, decodedFrame.payloadMimeType.metadata) - assertEquals(0, decodedFrame.payload.data.remaining) + assertTrue(decodedFrame.payload.data.exhausted()) assertNull(decodedFrame.payload.metadata) } @@ -64,8 +64,8 @@ class SetupFrameTest : TestWithLeakCheck { assertNull(decodedFrame.resumeToken) assertEquals(payloadMimeType.data, decodedFrame.payloadMimeType.data) assertEquals(payloadMimeType.metadata, decodedFrame.payloadMimeType.metadata) - assertBytesEquals(ByteArray(30000) { 1 }, decodedFrame.payload.data.readBytes()) - assertBytesEquals(ByteArray(20000) { 5 }, decodedFrame.payload.metadata?.readBytes()) + assertBytesEquals(ByteArray(30000) { 1 }, decodedFrame.payload.data.readByteArray()) + assertBytesEquals(ByteArray(20000) { 5 }, decodedFrame.payload.metadata?.readByteArray()) } @Test @@ -80,10 +80,10 @@ class SetupFrameTest : TestWithLeakCheck { assertTrue(decodedFrame.honorLease) assertEquals(keepAlive.intervalMillis, decodedFrame.keepAlive.intervalMillis) assertEquals(keepAlive.maxLifetimeMillis, decodedFrame.keepAlive.maxLifetimeMillis) - assertBytesEquals(ByteArray(65000) { 5 }, decodedFrame.resumeToken?.readBytes()) + assertBytesEquals(ByteArray(65000) { 5 }, decodedFrame.resumeToken?.readByteArray()) assertEquals(payloadMimeType.data, decodedFrame.payloadMimeType.data) assertEquals(payloadMimeType.metadata, decodedFrame.payloadMimeType.metadata) - assertEquals(0, decodedFrame.payload.data.remaining) + assertTrue(decodedFrame.payload.data.exhausted()) assertNull(decodedFrame.payload.metadata) } @@ -100,11 +100,11 @@ class SetupFrameTest : TestWithLeakCheck { assertTrue(decodedFrame.honorLease) assertEquals(keepAlive.intervalMillis, decodedFrame.keepAlive.intervalMillis) assertEquals(keepAlive.maxLifetimeMillis, decodedFrame.keepAlive.maxLifetimeMillis) - assertBytesEquals(ByteArray(65000) { 5 }, decodedFrame.resumeToken?.readBytes()) + assertBytesEquals(ByteArray(65000) { 5 }, decodedFrame.resumeToken?.readByteArray()) assertEquals(payloadMimeType.data, decodedFrame.payloadMimeType.data) assertEquals(payloadMimeType.metadata, decodedFrame.payloadMimeType.metadata) - assertBytesEquals(ByteArray(30000) { 1 }, decodedFrame.payload.data.readBytes()) - assertBytesEquals(ByteArray(20000) { 5 }, decodedFrame.payload.metadata?.readBytes()) + assertBytesEquals(ByteArray(30000) { 1 }, decodedFrame.payload.data.readByteArray()) + assertBytesEquals(ByteArray(20000) { 5 }, decodedFrame.payload.metadata?.readByteArray()) } } diff --git a/rsocket-core/src/commonTest/kotlin/io/rsocket/kotlin/frame/Util.kt b/rsocket-core/src/commonTest/kotlin/io/rsocket/kotlin/frame/Util.kt index a2b61f06..7100ae6e 100644 --- a/rsocket-core/src/commonTest/kotlin/io/rsocket/kotlin/frame/Util.kt +++ b/rsocket-core/src/commonTest/kotlin/io/rsocket/kotlin/frame/Util.kt @@ -16,21 +16,20 @@ package io.rsocket.kotlin.frame -import io.ktor.utils.io.core.* import io.rsocket.kotlin.internal.io.* -import io.rsocket.kotlin.test.* +import kotlinx.io.* import kotlin.test.* -internal fun Frame.toPacketWithLength(): ByteReadPacket = InUseTrackingPool.buildPacket { - val packet = toPacket(InUseTrackingPool) - writeInt24(packet.remaining.toInt()) - writePacket(packet) +internal fun Frame.toBufferWithLength(): Buffer = Buffer().apply { + val packet = Buffer() + writeInt24(packet.transferFrom(toBuffer()).toInt()) + transferFrom(packet) } -internal fun ByteReadPacket.toFrameWithLength(): Frame { +internal fun Buffer.toFrameWithLength(): Frame { val length = readInt24() - assertEquals(length, remaining.toInt()) - return readFrame(InUseTrackingPool) + assertEquals(length, size.toInt()) + return readFrame() } -internal fun Frame.loopFrame(): Frame = toPacket(InUseTrackingPool).readFrame(InUseTrackingPool) +internal fun Frame.loopFrame(): Frame = toBuffer().readFrame() diff --git a/rsocket-core/src/commonTest/kotlin/io/rsocket/kotlin/frame/io/MimeTypeTest.kt b/rsocket-core/src/commonTest/kotlin/io/rsocket/kotlin/frame/io/MimeTypeTest.kt index 6f2ce376..957c4a00 100644 --- a/rsocket-core/src/commonTest/kotlin/io/rsocket/kotlin/frame/io/MimeTypeTest.kt +++ b/rsocket-core/src/commonTest/kotlin/io/rsocket/kotlin/frame/io/MimeTypeTest.kt @@ -20,7 +20,7 @@ import io.rsocket.kotlin.core.* import io.rsocket.kotlin.test.* import kotlin.test.* -class MimeTypeTest : TestWithLeakCheck { +class MimeTypeTest { private val asciiChars = '!'..'~' @@ -41,7 +41,7 @@ class MimeTypeTest : TestWithLeakCheck { val packet = packet { writeMimeType(mimeType) } - assertEquals(name.length - 1, packet.tryPeek()) + assertEquals(name.length - 1, packet.peek().readByte().toInt()) assertEquals(mimeType, packet.readMimeType()) } } diff --git a/rsocket-core/src/commonTest/kotlin/io/rsocket/kotlin/internal/RSocketRequesterTest.kt b/rsocket-core/src/commonTest/kotlin/io/rsocket/kotlin/internal/RSocketRequesterTest.kt index df3c69dd..25813de0 100644 --- a/rsocket-core/src/commonTest/kotlin/io/rsocket/kotlin/internal/RSocketRequesterTest.kt +++ b/rsocket-core/src/commonTest/kotlin/io/rsocket/kotlin/internal/RSocketRequesterTest.kt @@ -24,10 +24,11 @@ import io.rsocket.kotlin.test.* import kotlinx.coroutines.* import kotlinx.coroutines.channels.* import kotlinx.coroutines.flow.* +import kotlinx.io.* import kotlin.test.* import kotlin.time.Duration.Companion.seconds -class RSocketRequesterTest : TestWithConnection(), TestWithLeakCheck { +class RSocketRequesterTest : TestWithConnection() { private lateinit var requester: RSocket override suspend fun before() { @@ -369,7 +370,7 @@ class RSocketRequesterTest : TestWithConnection(), TestWithLeakCheck { assertTrue(frame is RequestFrame) assertEquals(FrameType.RequestChannel, frame.type) assertEquals(Int.MAX_VALUE, frame.initialRequest) - assertEquals("INIT", frame.payload.data.readText()) + assertEquals("INIT", frame.payload.data.readString()) } expectNoEventsIn(200) delay.complete() diff --git a/rsocket-core/src/commonTest/kotlin/io/rsocket/kotlin/internal/RSocketResponderRequestNTest.kt b/rsocket-core/src/commonTest/kotlin/io/rsocket/kotlin/internal/RSocketResponderRequestNTest.kt index 5f98631b..52cd7c7d 100644 --- a/rsocket-core/src/commonTest/kotlin/io/rsocket/kotlin/internal/RSocketResponderRequestNTest.kt +++ b/rsocket-core/src/commonTest/kotlin/io/rsocket/kotlin/internal/RSocketResponderRequestNTest.kt @@ -30,7 +30,7 @@ import kotlinx.coroutines.flow.* import kotlin.coroutines.* import kotlin.test.* -class RSocketResponderRequestNTest : TestWithLeakCheck, TestWithConnection() { +class RSocketResponderRequestNTest : TestWithConnection() { private val testJob: Job = Job() private class TestInstance(val deferred: Deferred) : RSocketServerInstance { diff --git a/rsocket-core/src/commonTest/kotlin/io/rsocket/kotlin/keepalive/KeepAliveTest.kt b/rsocket-core/src/commonTest/kotlin/io/rsocket/kotlin/keepalive/KeepAliveTest.kt index 3339bc21..c4fcf63f 100644 --- a/rsocket-core/src/commonTest/kotlin/io/rsocket/kotlin/keepalive/KeepAliveTest.kt +++ b/rsocket-core/src/commonTest/kotlin/io/rsocket/kotlin/keepalive/KeepAliveTest.kt @@ -16,16 +16,16 @@ package io.rsocket.kotlin.keepalive -import io.ktor.utils.io.core.* import io.rsocket.kotlin.* import io.rsocket.kotlin.frame.* import io.rsocket.kotlin.test.* import kotlinx.coroutines.* +import kotlinx.io.* import kotlin.test.* import kotlin.time.Duration.Companion.milliseconds import kotlin.time.Duration.Companion.seconds -class KeepAliveTest : TestWithConnection(), TestWithLeakCheck { +class KeepAliveTest : TestWithConnection() { private suspend fun requester( keepAlive: KeepAlive = KeepAlive(100.milliseconds, 1.seconds), @@ -56,7 +56,7 @@ class KeepAliveTest : TestWithConnection(), TestWithLeakCheck { connection.launch { repeat(50) { delay(100.milliseconds) - connection.sendToReceiver(KeepAliveFrame(true, 0, ByteReadPacket.Empty)) + connection.sendToReceiver(KeepAliveFrame(true, 0, Buffer())) } } delay(1.5.seconds) @@ -74,7 +74,7 @@ class KeepAliveTest : TestWithConnection(), TestWithLeakCheck { connection.launch { while (isActive) { delay(100.milliseconds) - connection.sendToReceiver(KeepAliveFrame(true, 0, ByteReadPacket.Empty)) + connection.sendToReceiver(KeepAliveFrame(true, 0, Buffer())) } } diff --git a/rsocket-core/src/commonTest/kotlin/io/rsocket/kotlin/metadata/CompositeMetadataTest.kt b/rsocket-core/src/commonTest/kotlin/io/rsocket/kotlin/metadata/CompositeMetadataTest.kt index 83f23415..f466ada2 100644 --- a/rsocket-core/src/commonTest/kotlin/io/rsocket/kotlin/metadata/CompositeMetadataTest.kt +++ b/rsocket-core/src/commonTest/kotlin/io/rsocket/kotlin/metadata/CompositeMetadataTest.kt @@ -1,5 +1,5 @@ /* - * Copyright 2015-2022 the original author or authors. + * Copyright 2015-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,17 +16,17 @@ package io.rsocket.kotlin.metadata -import io.ktor.utils.io.core.* import io.rsocket.kotlin.core.* import io.rsocket.kotlin.test.* +import kotlinx.io.* import kotlin.test.* -class CompositeMetadataTest : TestWithLeakCheck { +class CompositeMetadataTest { @Test fun decodeEntryHasNoContent() { val cm = buildCompositeMetadata { - add(CustomMimeType("w"), ByteReadPacket.Empty) + add(CustomMimeType("w"), Buffer()) } val decoded = cm.readLoop(CompositeMetadata) @@ -34,7 +34,7 @@ class CompositeMetadataTest : TestWithLeakCheck { assertEquals(1, decoded.entries.size) val entry = decoded.entries.first() assertEquals(CustomMimeType("w"), entry.mimeType) - assertEquals(0, entry.content.remaining) + assertTrue(entry.content.exhausted()) } @Test @@ -49,15 +49,15 @@ class CompositeMetadataTest : TestWithLeakCheck { assertEquals(3, decoded.entries.size) decoded.entries[0].let { custom -> assertEquals(CustomMimeType("custom"), custom.mimeType) - assertEquals("custom metadata", custom.content.readText()) + assertEquals("custom metadata", custom.content.readString()) } decoded.entries[1].let { reserved -> assertEquals(ReservedMimeType(120), reserved.mimeType) - assertEquals("reserved metadata", reserved.content.readText()) + assertEquals("reserved metadata", reserved.content.readString()) } decoded.entries[2].let { known -> assertEquals(WellKnownMimeType.ApplicationAvro, known.mimeType) - assertEquals("avro metadata", known.content.readText()) + assertEquals("avro metadata", known.content.readString()) } } @@ -67,7 +67,7 @@ class CompositeMetadataTest : TestWithLeakCheck { writeByte(120) } assertFails { - packet.read(CompositeMetadata, InUseTrackingPool) + packet.read(CompositeMetadata) } } @@ -101,9 +101,9 @@ class CompositeMetadataTest : TestWithLeakCheck { } val decoded = cm.readLoop(CompositeMetadata) - assertEquals("custom metadata", decoded[CustomMimeType("custom")].readText()) - assertEquals("reserved metadata", decoded[ReservedMimeType(120)].readText()) - assertEquals("avro metadata", decoded[WellKnownMimeType.ApplicationAvro].readText()) + assertEquals("custom metadata", decoded[CustomMimeType("custom")].readString()) + assertEquals("reserved metadata", decoded[ReservedMimeType(120)].readString()) + assertEquals("avro metadata", decoded[WellKnownMimeType.ApplicationAvro].readString()) } @Test @@ -119,9 +119,9 @@ class CompositeMetadataTest : TestWithLeakCheck { assertNull(decoded.getOrNull(CustomMimeType("custom2"))) assertNull(decoded.getOrNull(WellKnownMimeType.MessageRSocketRouting)) - assertEquals("custom metadata", decoded.getOrNull(CustomMimeType("custom"))?.readText()) - assertEquals("reserved metadata", decoded.getOrNull(ReservedMimeType(120))?.readText()) - assertEquals("avro metadata", decoded.getOrNull(WellKnownMimeType.ApplicationAvro)?.readText()) + assertEquals("custom metadata", decoded.getOrNull(CustomMimeType("custom"))?.readString()) + assertEquals("reserved metadata", decoded.getOrNull(ReservedMimeType(120))?.readString()) + assertEquals("avro metadata", decoded.getOrNull(WellKnownMimeType.ApplicationAvro)?.readString()) } @Test @@ -151,19 +151,19 @@ class CompositeMetadataTest : TestWithLeakCheck { decoded.list(WellKnownMimeType.MessageRSocketRouting).let { assertEquals(1, it.size) - assertEquals("routing metadata", it[0].readText()) + assertEquals("routing metadata", it[0].readString()) } decoded.list(CustomMimeType("custom")).let { assertEquals(2, it.size) - assertEquals("custom metadata - 1", it[0].readText()) - assertEquals("custom metadata - 2", it[1].readText()) + assertEquals("custom metadata - 1", it[0].readString()) + assertEquals("custom metadata - 2", it[1].readString()) } decoded.list(ReservedMimeType(120)).let { assertEquals(2, it.size) - assertEquals("reserved metadata - 1", it[0].readText()) - assertEquals("reserved metadata - 2", it[1].readText()) + assertEquals("reserved metadata - 1", it[0].readString()) + assertEquals("reserved metadata - 2", it[1].readString()) } } @@ -176,7 +176,7 @@ class CompositeMetadataTest : TestWithLeakCheck { error("") } } - assertTrue(packet.isEmpty) + assertTrue(packet.exhausted()) } @Test @@ -205,7 +205,7 @@ class CompositeMetadataTest : TestWithLeakCheck { ), decoded[PerStreamAcceptableDataMimeTypesMetadata].types ) - assertEquals("{}", decoded[WellKnownMimeType.ApplicationJson].readText()) + assertEquals("{}", decoded[WellKnownMimeType.ApplicationJson].readString()) } @Test diff --git a/rsocket-core/src/commonTest/kotlin/io/rsocket/kotlin/metadata/PerStreamAcceptableDataMimeTypesMetadataTest.kt b/rsocket-core/src/commonTest/kotlin/io/rsocket/kotlin/metadata/PerStreamAcceptableDataMimeTypesMetadataTest.kt index 7d19eb18..4b6c29ba 100644 --- a/rsocket-core/src/commonTest/kotlin/io/rsocket/kotlin/metadata/PerStreamAcceptableDataMimeTypesMetadataTest.kt +++ b/rsocket-core/src/commonTest/kotlin/io/rsocket/kotlin/metadata/PerStreamAcceptableDataMimeTypesMetadataTest.kt @@ -1,5 +1,5 @@ /* - * Copyright 2015-2022 the original author or authors. + * Copyright 2015-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -17,10 +17,9 @@ package io.rsocket.kotlin.metadata import io.rsocket.kotlin.core.* -import io.rsocket.kotlin.test.* import kotlin.test.* -class PerStreamAcceptableDataMimeTypesMetadataTest : TestWithLeakCheck { +class PerStreamAcceptableDataMimeTypesMetadataTest { @Test fun encodeMetadata() { val metadata = PerStreamAcceptableDataMimeTypesMetadata( diff --git a/rsocket-core/src/commonTest/kotlin/io/rsocket/kotlin/metadata/PerStreamDataMimeTypeMetadataTest.kt b/rsocket-core/src/commonTest/kotlin/io/rsocket/kotlin/metadata/PerStreamDataMimeTypeMetadataTest.kt index 51f6e18f..5417207b 100644 --- a/rsocket-core/src/commonTest/kotlin/io/rsocket/kotlin/metadata/PerStreamDataMimeTypeMetadataTest.kt +++ b/rsocket-core/src/commonTest/kotlin/io/rsocket/kotlin/metadata/PerStreamDataMimeTypeMetadataTest.kt @@ -1,5 +1,5 @@ /* - * Copyright 2015-2022 the original author or authors. + * Copyright 2015-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -17,10 +17,9 @@ package io.rsocket.kotlin.metadata import io.rsocket.kotlin.core.* -import io.rsocket.kotlin.test.* import kotlin.test.* -class PerStreamDataMimeTypeMetadataTest : TestWithLeakCheck { +class PerStreamDataMimeTypeMetadataTest { @Test fun encodeReserved() { val metadata = PerStreamDataMimeTypeMetadata(ReservedMimeType(110)) diff --git a/rsocket-core/src/commonTest/kotlin/io/rsocket/kotlin/metadata/RoutingMetadataTest.kt b/rsocket-core/src/commonTest/kotlin/io/rsocket/kotlin/metadata/RoutingMetadataTest.kt index f0fd237b..d3d0af1e 100644 --- a/rsocket-core/src/commonTest/kotlin/io/rsocket/kotlin/metadata/RoutingMetadataTest.kt +++ b/rsocket-core/src/commonTest/kotlin/io/rsocket/kotlin/metadata/RoutingMetadataTest.kt @@ -1,5 +1,5 @@ /* - * Copyright 2015-2022 the original author or authors. + * Copyright 2015-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,10 +16,9 @@ package io.rsocket.kotlin.metadata -import io.rsocket.kotlin.test.* import kotlin.test.* -class RoutingMetadataTest : TestWithLeakCheck { +class RoutingMetadataTest { @Test fun encodeMetadata() { val tags = listOf("ws://localhost:8080/rsocket", "x".repeat(200)) diff --git a/rsocket-core/src/commonTest/kotlin/io/rsocket/kotlin/metadata/Util.kt b/rsocket-core/src/commonTest/kotlin/io/rsocket/kotlin/metadata/Util.kt index fb6c068d..ce2e93bb 100644 --- a/rsocket-core/src/commonTest/kotlin/io/rsocket/kotlin/metadata/Util.kt +++ b/rsocket-core/src/commonTest/kotlin/io/rsocket/kotlin/metadata/Util.kt @@ -1,5 +1,5 @@ /* - * Copyright 2015-2022 the original author or authors. + * Copyright 2015-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,7 +16,5 @@ package io.rsocket.kotlin.metadata -import io.rsocket.kotlin.test.* - fun Metadata.readLoop(reader: MetadataReader): M = - toPacket(InUseTrackingPool).read(reader, InUseTrackingPool) + toBuffer().read(reader) diff --git a/rsocket-core/src/commonTest/kotlin/io/rsocket/kotlin/metadata/ZipkinTracingMetadataTest.kt b/rsocket-core/src/commonTest/kotlin/io/rsocket/kotlin/metadata/ZipkinTracingMetadataTest.kt index d81daefe..fe4c59d5 100644 --- a/rsocket-core/src/commonTest/kotlin/io/rsocket/kotlin/metadata/ZipkinTracingMetadataTest.kt +++ b/rsocket-core/src/commonTest/kotlin/io/rsocket/kotlin/metadata/ZipkinTracingMetadataTest.kt @@ -1,5 +1,5 @@ /* - * Copyright 2015-2022 the original author or authors. + * Copyright 2015-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,11 +16,10 @@ package io.rsocket.kotlin.metadata -import io.rsocket.kotlin.test.* import kotlin.random.* import kotlin.test.* -class ZipkinTracingMetadataTest : TestWithLeakCheck { +class ZipkinTracingMetadataTest { @Test fun encodeEmptyTrace() = forAllKinds { kind -> diff --git a/rsocket-core/src/commonTest/kotlin/io/rsocket/kotlin/metadata/security/AuthMetadataTest.kt b/rsocket-core/src/commonTest/kotlin/io/rsocket/kotlin/metadata/security/AuthMetadataTest.kt index 7da80dc5..0e7d2163 100644 --- a/rsocket-core/src/commonTest/kotlin/io/rsocket/kotlin/metadata/security/AuthMetadataTest.kt +++ b/rsocket-core/src/commonTest/kotlin/io/rsocket/kotlin/metadata/security/AuthMetadataTest.kt @@ -1,5 +1,5 @@ /* - * Copyright 2015-2022 the original author or authors. + * Copyright 2015-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -18,9 +18,10 @@ package io.rsocket.kotlin.metadata.security import io.rsocket.kotlin.metadata.* import io.rsocket.kotlin.test.* +import kotlinx.io.* import kotlin.test.* -class AuthMetadataTest : TestWithLeakCheck { +class AuthMetadataTest { @Test fun encodeSimple() { val metadata = SimpleAuthMetadata("user", "password1234") @@ -73,7 +74,7 @@ class AuthMetadataTest : TestWithLeakCheck { val decoded = metadata.readLoop(RawAuthMetadata) assertEquals(CustomAuthType("custom/auth"), decoded.type) - assertEquals("hello world auth data", decoded.content.readText()) + assertEquals("hello world auth data", decoded.content.readString()) } @Test diff --git a/rsocket-core/src/commonTest/kotlin/io/rsocket/kotlin/operation/OperationOutboundTest.kt b/rsocket-core/src/commonTest/kotlin/io/rsocket/kotlin/operation/OperationOutboundTest.kt index a57f5b81..b1d7eb7e 100644 --- a/rsocket-core/src/commonTest/kotlin/io/rsocket/kotlin/operation/OperationOutboundTest.kt +++ b/rsocket-core/src/commonTest/kotlin/io/rsocket/kotlin/operation/OperationOutboundTest.kt @@ -16,23 +16,23 @@ package io.rsocket.kotlin.operation -import io.ktor.utils.io.core.* import io.rsocket.kotlin.frame.* import io.rsocket.kotlin.internal.io.* import io.rsocket.kotlin.payload.* import io.rsocket.kotlin.test.* import kotlinx.coroutines.channels.* +import kotlinx.io.* import kotlin.test.* -class OperationOutboundTest : SuspendTest, TestWithLeakCheck { +class OperationOutboundTest : SuspendTest { private class Outbound( streamId: Int, maxFragmentSize: Int, - ) : OperationOutbound(streamId, FrameCodec(InUseTrackingPool, maxFragmentSize)) { - val frames = channelForCloseable(Channel.BUFFERED) + ) : OperationOutbound(streamId, FrameCodec(maxFragmentSize)) { + val frames = bufferChannel(Channel.BUFFERED) override val isClosed: Boolean get() = frames.isClosedForSend - override suspend fun sendFrame(frame: ByteReadPacket) { + override suspend fun sendFrame(frame: Buffer) { frames.send(frame) } } @@ -48,16 +48,16 @@ class OperationOutboundTest : SuspendTest, TestWithLeakCheck { }, false) repeat(6) { - val frame = sender.frames.receive().readFrame(InUseTrackingPool) + val frame = sender.frames.receive().readFrame() assertIs(frame) assertTrue(frame.next) assertNull(frame.payload.metadata) if (it != 5) { assertTrue(frame.follows) - assertEquals("1234567890".repeat(9), frame.payload.data.readText()) + assertEquals("1234567890".repeat(9), frame.payload.data.readString()) } else { //last frame assertFalse(frame.follows) - assertEquals("1234567890".repeat(5), frame.payload.data.readText()) + assertEquals("1234567890".repeat(5), frame.payload.data.readString()) } } } @@ -71,11 +71,11 @@ class OperationOutboundTest : SuspendTest, TestWithLeakCheck { }, false) repeat(2) { - val frame = sender.frames.receive().readFrame(InUseTrackingPool) + val frame = sender.frames.receive().readFrame() assertIs(frame) assertTrue(frame.next) assertNull(frame.payload.metadata) - assertEquals("1234567890".repeat(9), frame.payload.data.readText()) + assertEquals("1234567890".repeat(9), frame.payload.data.readString()) if (it != 1) { assertTrue(frame.follows) } else { //last frame diff --git a/rsocket-core/src/commonTest/kotlin/io/rsocket/kotlin/operation/RequesterRequestResponseOperationTest.kt b/rsocket-core/src/commonTest/kotlin/io/rsocket/kotlin/operation/RequesterRequestResponseOperationTest.kt index 1196b584..7f3de311 100644 --- a/rsocket-core/src/commonTest/kotlin/io/rsocket/kotlin/operation/RequesterRequestResponseOperationTest.kt +++ b/rsocket-core/src/commonTest/kotlin/io/rsocket/kotlin/operation/RequesterRequestResponseOperationTest.kt @@ -21,10 +21,11 @@ import io.rsocket.kotlin.frame.* import io.rsocket.kotlin.payload.* import io.rsocket.kotlin.test.* import kotlinx.coroutines.* +import kotlinx.io.* import kotlin.test.* // TODO: write better tests -class RequesterRequestResponseOperationTest : SuspendTest, TestWithLeakCheck { +class RequesterRequestResponseOperationTest : SuspendTest { private val deferred = CompletableDeferred() private val operation = RequesterRequestResponseOperation(deferred) private val handler = OperationFrameHandler(operation) @@ -33,7 +34,7 @@ class RequesterRequestResponseOperationTest : SuspendTest, TestWithLeakCheck { fun testCompleteOnPayloadReceive() = test { handler.handleFrame(RequestFrame(FrameType.Payload, 1, false, false, true, 0, payload("hello"))) assertTrue(deferred.isCompleted) - assertEquals("hello", deferred.await().data.readText()) + assertEquals("hello", deferred.await().data.readString()) } @Test @@ -56,6 +57,6 @@ class RequesterRequestResponseOperationTest : SuspendTest, TestWithLeakCheck { assertFalse(deferred.isCompleted) handler.handleFrame(RequestFrame(FrameType.Payload, 1, false, false, true, 0, payload(" world"))) assertTrue(deferred.isCompleted) - assertEquals("hello world", deferred.await().data.readText()) + assertEquals("hello world", deferred.await().data.readString()) } } diff --git a/rsocket-core/src/commonTest/kotlin/io/rsocket/kotlin/payload/PayloadBuilderTest.kt b/rsocket-core/src/commonTest/kotlin/io/rsocket/kotlin/payload/PayloadBuilderTest.kt index 7974225d..76735667 100644 --- a/rsocket-core/src/commonTest/kotlin/io/rsocket/kotlin/payload/PayloadBuilderTest.kt +++ b/rsocket-core/src/commonTest/kotlin/io/rsocket/kotlin/payload/PayloadBuilderTest.kt @@ -1,5 +1,5 @@ /* - * Copyright 2015-2022 the original author or authors. + * Copyright 2015-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,24 +16,24 @@ package io.rsocket.kotlin.payload -import io.ktor.utils.io.core.* import io.rsocket.kotlin.test.* +import kotlinx.io.* import kotlin.test.* -class PayloadBuilderTest : TestWithLeakCheck { +class PayloadBuilderTest { @Test fun payloadCopy() { val payload = Payload(packet("data"), packet("metadata")) val copy = payload.copy() - assertTrue(payload.data.isNotEmpty) - assertTrue(payload.metadata?.isNotEmpty == true) - assertTrue(copy.data.isNotEmpty) - assertTrue(copy.metadata?.isNotEmpty == true) + assertTrue(!payload.data.exhausted()) + assertTrue(payload.metadata?.let { !it.exhausted() } == true) + assertTrue(!copy.data.exhausted()) + assertTrue(copy.metadata?.let { !it.exhausted() } == true) - assertBytesEquals(payload.data.readBytes(), copy.data.readBytes()) - assertBytesEquals(payload.metadata?.readBytes(), copy.metadata?.readBytes()) + assertBytesEquals(payload.data.readByteArray(), copy.data.readByteArray()) + assertBytesEquals(payload.metadata?.readByteArray(), copy.metadata?.readByteArray()) } @Test diff --git a/rsocket-core/src/commonTest/kotlin/io/rsocket/kotlin/transport/internal/PrioritizationFrameQueueTest.kt b/rsocket-core/src/commonTest/kotlin/io/rsocket/kotlin/transport/internal/PrioritizationFrameQueueTest.kt index e8c9120a..beace8d1 100644 --- a/rsocket-core/src/commonTest/kotlin/io/rsocket/kotlin/transport/internal/PrioritizationFrameQueueTest.kt +++ b/rsocket-core/src/commonTest/kotlin/io/rsocket/kotlin/transport/internal/PrioritizationFrameQueueTest.kt @@ -16,13 +16,13 @@ package io.rsocket.kotlin.transport.internal -import io.ktor.utils.io.core.* import io.rsocket.kotlin.test.* import kotlinx.coroutines.* import kotlinx.coroutines.channels.* +import kotlinx.io.* import kotlin.test.* -class PrioritizationFrameQueueTest : SuspendTest, TestWithLeakCheck { +class PrioritizationFrameQueueTest : SuspendTest { private val queue = PrioritizationFrameQueue(Channel.BUFFERED) @Test @@ -31,9 +31,9 @@ class PrioritizationFrameQueueTest : SuspendTest, TestWithLeakCheck { queue.enqueueFrame(2, packet("2")) queue.enqueueFrame(3, packet("3")) - assertEquals("1", queue.dequeueFrame()?.readText()) - assertEquals("2", queue.dequeueFrame()?.readText()) - assertEquals("3", queue.dequeueFrame()?.readText()) + assertEquals("1", queue.dequeueFrame()?.readString()) + assertEquals("2", queue.dequeueFrame()?.readString()) + assertEquals("3", queue.dequeueFrame()?.readString()) } @Test @@ -41,8 +41,8 @@ class PrioritizationFrameQueueTest : SuspendTest, TestWithLeakCheck { queue.enqueueFrame(0, packet("1")) queue.enqueueFrame(0, packet("2")) - assertEquals("1", queue.dequeueFrame()?.readText()) - assertEquals("2", queue.dequeueFrame()?.readText()) + assertEquals("1", queue.dequeueFrame()?.readString()) + assertEquals("2", queue.dequeueFrame()?.readString()) } @Test @@ -52,22 +52,22 @@ class PrioritizationFrameQueueTest : SuspendTest, TestWithLeakCheck { queue.enqueueFrame(1, packet("3")) queue.enqueueFrame(0, packet("4")) - assertEquals("2", queue.dequeueFrame()?.readText()) - assertEquals("4", queue.dequeueFrame()?.readText()) + assertEquals("2", queue.dequeueFrame()?.readString()) + assertEquals("4", queue.dequeueFrame()?.readString()) - assertEquals("1", queue.dequeueFrame()?.readText()) - assertEquals("3", queue.dequeueFrame()?.readText()) + assertEquals("1", queue.dequeueFrame()?.readString()) + assertEquals("3", queue.dequeueFrame()?.readString()) } @Test fun testAsyncReceive() = test { - val deferred = CompletableDeferred() + val deferred = CompletableDeferred() launch(anotherDispatcher) { deferred.complete(queue.dequeueFrame()) } delay(100) queue.enqueueFrame(5, packet("1")) - assertEquals("1", deferred.await()?.readText()) + assertEquals("1", deferred.await()?.readString()) } @Test @@ -77,17 +77,17 @@ class PrioritizationFrameQueueTest : SuspendTest, TestWithLeakCheck { queue.enqueueFrame(0, p1) queue.enqueueFrame(1, p2) - assertTrue(p1.isNotEmpty) - assertTrue(p2.isNotEmpty) + assertTrue(!p1.exhausted()) + assertTrue(!p2.exhausted()) queue.close() - assertTrue(p1.isNotEmpty) - assertTrue(p2.isNotEmpty) + assertTrue(!p1.exhausted()) + assertTrue(!p2.exhausted()) queue.cancel() - assertTrue(p1.isEmpty) - assertTrue(p2.isEmpty) + assertTrue(p1.exhausted()) + assertTrue(p2.exhausted()) } } diff --git a/rsocket-internal-io/api/rsocket-internal-io.api b/rsocket-internal-io/api/rsocket-internal-io.api index e98f43e4..8f783f53 100644 --- a/rsocket-internal-io/api/rsocket-internal-io.api +++ b/rsocket-internal-io/api/rsocket-internal-io.api @@ -1,4 +1,5 @@ public final class io/rsocket/kotlin/internal/io/ChannelsKt { + public static final fun bufferChannel (I)Lkotlinx/coroutines/channels/Channel; public static final fun cancelWithCause (Lkotlinx/coroutines/channels/Channel;Ljava/lang/Throwable;)V public static final fun channelForCloseable (I)Lkotlinx/coroutines/channels/Channel; } @@ -13,7 +14,7 @@ public final class io/rsocket/kotlin/internal/io/ContextKt { } public final class io/rsocket/kotlin/internal/io/Int24Kt { - public static final fun readInt24 (Lio/ktor/utils/io/core/ByteReadPacket;)I - public static final fun writeInt24 (Lio/ktor/utils/io/core/BytePacketBuilder;I)V + public static final fun readInt24 (Lkotlinx/io/Source;)I + public static final fun writeInt24 (Lkotlinx/io/Sink;I)V } diff --git a/rsocket-internal-io/build.gradle.kts b/rsocket-internal-io/build.gradle.kts index a978c9b7..7211178b 100644 --- a/rsocket-internal-io/build.gradle.kts +++ b/rsocket-internal-io/build.gradle.kts @@ -30,7 +30,7 @@ kotlin { sourceSets { commonMain.dependencies { api(libs.kotlinx.coroutines.core) - api(libs.ktor.io) + api(libs.kotlinx.io.core) } } } diff --git a/rsocket-internal-io/src/commonMain/kotlin/io/rsocket/kotlin/internal/io/Channels.kt b/rsocket-internal-io/src/commonMain/kotlin/io/rsocket/kotlin/internal/io/Channels.kt index 72718d97..b1f9ee19 100644 --- a/rsocket-internal-io/src/commonMain/kotlin/io/rsocket/kotlin/internal/io/Channels.kt +++ b/rsocket-internal-io/src/commonMain/kotlin/io/rsocket/kotlin/internal/io/Channels.kt @@ -1,5 +1,5 @@ /* - * Copyright 2015-2023 the original author or authors. + * Copyright 2015-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,15 +16,19 @@ package io.rsocket.kotlin.internal.io -import io.ktor.utils.io.core.* import kotlinx.coroutines.channels.* +import kotlinx.io.* -private val onUndeliveredCloseable: (Closeable) -> Unit = Closeable::close +private val onUndeliveredCloseable: (AutoCloseable) -> Unit = AutoCloseable::close +private val onUndeliveredBuffer: (Buffer) -> Unit = Buffer::clear -public fun channelForCloseable(capacity: Int): Channel = +public fun bufferChannel(capacity: Int): Channel = Channel(capacity, onUndeliveredElement = onUndeliveredBuffer) + +// TODO: may be drop it? +public fun channelForCloseable(capacity: Int): Channel = Channel(capacity, onUndeliveredElement = onUndeliveredCloseable) -public fun Channel.cancelWithCause(cause: Throwable?) { +public fun Channel.cancelWithCause(cause: Throwable?) { close(cause) // close channel to provide right cause cancel() // force call of onUndeliveredElement to release buffered elements } diff --git a/rsocket-internal-io/src/commonMain/kotlin/io/rsocket/kotlin/internal/io/Int24.kt b/rsocket-internal-io/src/commonMain/kotlin/io/rsocket/kotlin/internal/io/Int24.kt index ef439d5a..7dbbc475 100644 --- a/rsocket-internal-io/src/commonMain/kotlin/io/rsocket/kotlin/internal/io/Int24.kt +++ b/rsocket-internal-io/src/commonMain/kotlin/io/rsocket/kotlin/internal/io/Int24.kt @@ -1,5 +1,5 @@ /* - * Copyright 2015-2023 the original author or authors. + * Copyright 2015-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,18 +16,18 @@ package io.rsocket.kotlin.internal.io -import io.ktor.utils.io.core.* +import kotlinx.io.* private const val lengthMask: Int = 0xFFFFFF.inv() -public fun ByteReadPacket.readInt24(): Int { +public fun Source.readInt24(): Int { val b = readByte().toInt() and 0xFF shl 16 val b1 = readByte().toInt() and 0xFF shl 8 val b2 = readByte().toInt() and 0xFF return b or b1 or b2 } -public fun BytePacketBuilder.writeInt24(length: Int) { +public fun Sink.writeInt24(length: Int) { require(length and lengthMask == 0) { "Length is larger than 24 bits" } writeByte((length shr 16).toByte()) writeByte((length shr 8).toByte()) diff --git a/rsocket-test/src/commonMain/kotlin/io/rsocket/kotlin/test/InUseTrackingPool.kt b/rsocket-test/src/commonMain/kotlin/io/rsocket/kotlin/test/InUseTrackingPool.kt deleted file mode 100644 index 86cb1c65..00000000 --- a/rsocket-test/src/commonMain/kotlin/io/rsocket/kotlin/test/InUseTrackingPool.kt +++ /dev/null @@ -1,151 +0,0 @@ -/* - * Copyright 2015-2024 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.rsocket.kotlin.test - -import io.ktor.utils.io.bits.* -import io.ktor.utils.io.core.* -import io.ktor.utils.io.core.internal.* -import io.ktor.utils.io.pool.* -import io.rsocket.kotlin.internal.* -import kotlinx.atomicfu.locks.* -import kotlin.test.* - -val InUseTrackingPool: BufferPool = BufferPool(InUseTrackingPoolInstance) - -@Suppress("DEPRECATION") -private object InUseTrackingPoolInstance : ObjectPool, SynchronizedObject() { - override val capacity: Int get() = BufferPool.capacity - private val inUse = mutableSetOf() - - override fun borrow(): ChunkBuffer { - val instance = BufferPool.borrow() - synchronized(this) { - check(inUse.add(IdentityWrapper(instance, Throwable()))) - } - return instance - } - - override fun recycle(instance: ChunkBuffer) { - synchronized(this) { - check(inUse.remove(IdentityWrapper(instance, null))) - } - BufferPool.recycle(instance) - } - - override fun dispose() { - BufferPool.dispose() - } - - fun resetInUse() { - synchronized(this) { - inUse.clear() - } - } - - fun assertNoInUse() { - val traces = synchronized(this) { - inUse.mapNotNull(IdentityWrapper::throwable) - } - if (traces.isEmpty()) return - fail(traceMessage(traces)) - } - - private fun traceMessage(traces: List): String = traces - .groupBy(Throwable::stackTraceToString) - .mapKeys { alignStackTrace(it.key) } - .mapValues { it.value.size } - .toList() - .joinToString("\n", "Buffers in use[${traces.size}]:\n", "\n") { (stack, amount) -> - "Buffer creation trace ($amount the same):\n$stack" - } - - private fun alignStackTrace(trace: String): String { - val stack = trace.split("\n").drop(1) // drops first empty trace - val filtered = - stack - .filterNot { it.contains("TrackingSet") || it.contains("InUseTrackingPool") } //filter not relevant - .filter { - //works on K/JVM and K/N - //on K/JS works only for legacy + node - it.contains("io.rsocket.kotlin") || it.contains("rsocket-kotlin/rsocket") - }.ifEmpty { stack } //fallback to full stacktrace on unsupported K/JS variants - - //replaces `at` with `->` because on all platforms except K/JVM such strings are interpreted as stacktrace and merged - return filtered.joinToString("\n ->", " ->") { it.substringAfter("at") } - } - - //uses internal ktor APIs - - // after ktor 1.5.3 it's the only way to make sure, - // that there are no leaked buffers - // used only on tests, so it's more or less safe - // copy of io.ktor.utils.io.core.DefaultBufferPool with changed parent pool!!! - @Suppress("INVISIBLE_MEMBER", "INVISIBLE_REFERENCE") - private object BufferPool : DefaultPool(1000) { - override fun produceInstance(): ChunkBuffer { - return ChunkBuffer(DefaultAllocator.alloc(DEFAULT_BUFFER_SIZE), null, InUseTrackingPoolInstance) - } - - override fun disposeInstance(instance: ChunkBuffer) { - DefaultAllocator.free(instance.memory) - super.disposeInstance(instance) - instance.unlink() - } - - override fun validateInstance(instance: ChunkBuffer) { - super.validateInstance(instance) - - check(instance !== Buffer.Empty) { "Empty instance couldn't be recycled" } - check(instance !== ChunkBuffer.Empty) { "Empty instance couldn't be recycled" } - - check(instance.referenceCount == 0) { "Unable to clear buffer: it is still in use." } - check(instance.next == null) { "Recycled instance shouldn't be a part of a chain." } - check(instance.origin == null) { "Recycled instance shouldn't be a view or another buffer." } - } - - override fun clearInstance(instance: ChunkBuffer): ChunkBuffer { - return super.clearInstance(instance).apply { - unpark() - reset() - } - } - } -} - -private class IdentityWrapper( - private val instance: Any, - val throwable: Throwable?, -) { - override fun equals(other: Any?): Boolean { - if (other !is IdentityWrapper) return false - return other.instance === this.instance - } - - override fun hashCode(): Int = identityHashCode(instance) -} - -interface TestWithLeakCheck { - - @BeforeTest - fun resetInUse() { - InUseTrackingPoolInstance.resetInUse() - } - - @AfterTest - fun checkNoBuffersInUse() { - InUseTrackingPoolInstance.assertNoInUse() - } -} diff --git a/rsocket-test/src/commonMain/kotlin/io/rsocket/kotlin/test/Packets.kt b/rsocket-test/src/commonMain/kotlin/io/rsocket/kotlin/test/Packets.kt index ed9657fd..51531276 100644 --- a/rsocket-test/src/commonMain/kotlin/io/rsocket/kotlin/test/Packets.kt +++ b/rsocket-test/src/commonMain/kotlin/io/rsocket/kotlin/test/Packets.kt @@ -16,15 +16,15 @@ package io.rsocket.kotlin.test -import io.ktor.utils.io.core.* import io.rsocket.kotlin.payload.* +import kotlinx.io.* import kotlin.test.* -fun packet(block: BytePacketBuilder.() -> Unit): ByteReadPacket = InUseTrackingPool.buildPacket(block) +fun packet(block: Sink.() -> Unit): Buffer = Buffer().apply(block) -fun packet(text: String): ByteReadPacket = InUseTrackingPool.buildPacket { writeText(text) } +fun packet(text: String): Buffer = packet { writeString(text) } -fun packet(array: ByteArray): ByteReadPacket = InUseTrackingPool.buildPacket { writeFully(array) } +fun packet(array: ByteArray): Buffer = packet { write(array) } fun payload(data: ByteArray, metadata: ByteArray? = null): Payload = Payload(packet(data), metadata?.let(::packet)) diff --git a/rsocket-test/src/commonMain/kotlin/io/rsocket/kotlin/test/TestConfig.kt b/rsocket-test/src/commonMain/kotlin/io/rsocket/kotlin/test/TestConfig.kt index 642a83dc..c5189b51 100644 --- a/rsocket-test/src/commonMain/kotlin/io/rsocket/kotlin/test/TestConfig.kt +++ b/rsocket-test/src/commonMain/kotlin/io/rsocket/kotlin/test/TestConfig.kt @@ -25,8 +25,6 @@ fun TestServer( logging: Boolean = true, block: RSocketServerBuilder.() -> Unit = {} ): RSocketServer = RSocketServer { - @Suppress("DEPRECATION_ERROR") - bufferPool = InUseTrackingPool loggerFactory = if (logging) { LoggerFactory { PrintLogger.withLevel(LoggingLevel.DEBUG).logger("SERVER |$it") } } else { @@ -39,8 +37,6 @@ fun TestConnector( logging: Boolean = true, block: RSocketConnectorBuilder.() -> Unit = {} ): RSocketConnector = RSocketConnector { - @Suppress("DEPRECATION_ERROR") - bufferPool = InUseTrackingPool loggerFactory = if (logging) { LoggerFactory { PrintLogger.withLevel(LoggingLevel.DEBUG).logger("CLIENT |$it") } } else { diff --git a/rsocket-transport-tests/src/commonMain/kotlin/io/rsocket/kotlin/transport/tests/TransportTest.kt b/rsocket-transport-tests/src/commonMain/kotlin/io/rsocket/kotlin/transport/tests/TransportTest.kt index c4ffd8d2..59b9fa05 100644 --- a/rsocket-transport-tests/src/commonMain/kotlin/io/rsocket/kotlin/transport/tests/TransportTest.kt +++ b/rsocket-transport-tests/src/commonMain/kotlin/io/rsocket/kotlin/transport/tests/TransportTest.kt @@ -16,7 +16,6 @@ package io.rsocket.kotlin.transport.tests -import io.ktor.utils.io.core.* import io.rsocket.kotlin.* import io.rsocket.kotlin.keepalive.* import io.rsocket.kotlin.payload.* @@ -24,6 +23,7 @@ import io.rsocket.kotlin.test.* import io.rsocket.kotlin.transport.* import kotlinx.coroutines.* import kotlinx.coroutines.flow.* +import kotlinx.io.* import kotlin.coroutines.* import kotlin.test.* import kotlin.time.* @@ -31,7 +31,7 @@ import kotlin.time.Duration.Companion.minutes import kotlin.time.Duration.Companion.seconds //TODO: need to somehow rework those tests, as now they are super flaky -abstract class TransportTest : SuspendTest, TestWithLeakCheck { +abstract class TransportTest : SuspendTest { override val testTimeout: Duration = 3.minutes private val testJob = SupervisorJob() @@ -62,25 +62,21 @@ abstract class TransportTest : SuspendTest, TestWithLeakCheck { @Test fun fireAndForget10() = test { (1..10).map { async { client.fireAndForget(payload(it)) } }.awaitAll() - delay(1000) //TODO: leak check } @Test open fun largePayloadFireAndForget10() = test { (1..10).map { async { client.fireAndForget(requesterLargePayload) } }.awaitAll() - delay(1000) //TODO: leak check } @Test fun metadataPush10() = test { (1..10).map { async { client.metadataPush(packet(requesterData)) } }.awaitAll() - delay(1000) //TODO: leak check } @Test open fun largePayloadMetadataPush10() = test { (1..10).map { async { client.metadataPush(packet(requesterLargeData)) } }.awaitAll() - delay(1000) //TODO: leak check } @Test @@ -131,8 +127,8 @@ abstract class TransportTest : SuspendTest, TestWithLeakCheck { repeat(20_000) { emit(payload(7)) } } val count = client.requestChannel(payload(7), request).flowOn(PrefetchStrategy(Int.MAX_VALUE, 0)).onEach { - assertEquals(requesterData, it.data.readText()) - assertEquals(requesterMetadata, it.metadata?.readText()) + assertEquals(requesterData, it.data.readString()) + assertEquals(requesterMetadata, it.metadata?.readString()) }.count() assertEquals(20_000, count) } @@ -217,8 +213,8 @@ abstract class TransportTest : SuspendTest, TestWithLeakCheck { .flowOn(PrefetchStrategy(Int.MAX_VALUE, 0)) .take(500) .onEach { - assertEquals(requesterData, it.data.readText()) - assertEquals(requesterMetadata, it.metadata?.readText()) + assertEquals(requesterData, it.data.readString()) + assertEquals(requesterMetadata, it.metadata?.readString()) } .count() assertEquals(500, count) @@ -312,15 +308,15 @@ abstract class TransportTest : SuspendTest, TestWithLeakCheck { } fun checkPayload(payload: Payload) { - assertEquals(responderData, payload.data.readText()) - assertEquals(responderMetadata, payload.metadata?.readText()) + assertEquals(responderData, payload.data.readString()) + assertEquals(responderMetadata, payload.metadata?.readString()) } } private class ResponderRSocket : RSocket { override val coroutineContext: CoroutineContext = Job() - override suspend fun metadataPush(metadata: ByteReadPacket): Unit = metadata.close() + override suspend fun metadataPush(metadata: Buffer): Unit = metadata.close() override suspend fun fireAndForget(payload: Payload): Unit = payload.close() diff --git a/rsocket-transports/ktor-tcp/src/commonMain/kotlin/io/rsocket/kotlin/transport/ktor/tcp/KtorTcpConnection.kt b/rsocket-transports/ktor-tcp/src/commonMain/kotlin/io/rsocket/kotlin/transport/ktor/tcp/KtorTcpConnection.kt index b65c1077..3ad8ac7d 100644 --- a/rsocket-transports/ktor-tcp/src/commonMain/kotlin/io/rsocket/kotlin/transport/ktor/tcp/KtorTcpConnection.kt +++ b/rsocket-transports/ktor-tcp/src/commonMain/kotlin/io/rsocket/kotlin/transport/ktor/tcp/KtorTcpConnection.kt @@ -18,17 +18,17 @@ package io.rsocket.kotlin.transport.ktor.tcp import io.ktor.network.sockets.* import io.ktor.utils.io.* -import io.ktor.utils.io.core.* import io.rsocket.kotlin.internal.io.* import io.rsocket.kotlin.transport.* import io.rsocket.kotlin.transport.internal.* import kotlinx.coroutines.* import kotlinx.coroutines.channels.* +import kotlinx.io.* @RSocketTransportApi internal suspend fun RSocketConnectionHandler.handleKtorTcpConnection(socket: Socket): Unit = coroutineScope { val outboundQueue = PrioritizationFrameQueue(Channel.BUFFERED) - val inbound = channelForCloseable(Channel.BUFFERED) + val inbound = bufferChannel(Channel.BUFFERED) val readerJob = launch { val input = socket.openReadChannel() @@ -79,33 +79,31 @@ internal suspend fun RSocketConnectionHandler.handleKtorTcpConnection(socket: So @RSocketTransportApi private class KtorTcpConnection( private val outboundQueue: PrioritizationFrameQueue, - private val inbound: ReceiveChannel, + private val inbound: ReceiveChannel, ) : RSocketSequentialConnection { override val isClosedForSend: Boolean get() = outboundQueue.isClosedForSend - override suspend fun sendFrame(streamId: Int, frame: ByteReadPacket) { + override suspend fun sendFrame(streamId: Int, frame: Buffer) { return outboundQueue.enqueueFrame(streamId, frame) } - override suspend fun receiveFrame(): ByteReadPacket? { + override suspend fun receiveFrame(): Buffer? { return inbound.receiveCatching().getOrNull() } } -private suspend fun ByteWriteChannel.writeFrame(frame: ByteReadPacket) { - val packet = buildPacket { - writeInt24(frame.remaining.toInt()) - writePacket(frame) - } - try { - writePacket(packet) - } catch (cause: Throwable) { - packet.close() - throw cause - } +@OptIn(InternalAPI::class) // TODO? +private fun ByteWriteChannel.writeFrame(frame: Buffer) { + writeBuffer.writeInt24(frame.size.toInt()) + writeBuffer.transferFrom(frame) } -private suspend fun ByteReadChannel.readFrame(): ByteReadPacket? { - val lengthPacket = readRemaining(3) - if (lengthPacket.remaining == 0L) return null - return readPacket(lengthPacket.readInt24()) +@OptIn(InternalAPI::class) // TODO? +private suspend fun ByteReadChannel.readFrame(): Buffer? { + while (availableForRead < 3 && awaitContent(3)) yield() + if (availableForRead == 0) return null + + val length = readBuffer.readInt24() + return readBuffer(length).also { + it.require(length.toLong()) + } } diff --git a/rsocket-transports/ktor-tcp/src/commonMain/kotlin/io/rsocket/kotlin/transport/ktor/tcp/TcpConnection.kt b/rsocket-transports/ktor-tcp/src/commonMain/kotlin/io/rsocket/kotlin/transport/ktor/tcp/TcpConnection.kt index fb0e1287..98347f0e 100644 --- a/rsocket-transports/ktor-tcp/src/commonMain/kotlin/io/rsocket/kotlin/transport/ktor/tcp/TcpConnection.kt +++ b/rsocket-transports/ktor-tcp/src/commonMain/kotlin/io/rsocket/kotlin/transport/ktor/tcp/TcpConnection.kt @@ -19,9 +19,9 @@ package io.rsocket.kotlin.transport.ktor.tcp import io.ktor.network.sockets.* import io.ktor.util.cio.* import io.ktor.utils.io.* -import io.ktor.utils.io.core.* import io.rsocket.kotlin.internal.io.* import kotlinx.coroutines.* +import kotlinx.io.* import kotlin.coroutines.* @Suppress("DEPRECATION_ERROR") @@ -31,20 +31,19 @@ internal class TcpConnection( ) : io.rsocket.kotlin.Connection { private val socketConnection = socket.connection() - private val sendChannel = channelForCloseable(8) - private val receiveChannel = channelForCloseable(8) + private val sendChannel = bufferChannel(8) + private val receiveChannel = bufferChannel(8) init { launch { socketConnection.output.use { while (isActive) { val packet = sendChannel.receive() - val length = packet.remaining.toInt() + val temp = Buffer().also(packet::transferTo) + val length = temp.size.toInt() try { - writePacket { - writeInt24(length) - writePacket(packet) - } + writeBuffer(Buffer().apply { writeInt24(length) }) + writeBuffer(temp) flush() } catch (e: Throwable) { packet.close() @@ -57,7 +56,7 @@ internal class TcpConnection( socketConnection.input.apply { while (isActive) { val length = readPacket(3).readInt24() - val packet = readPacket(length) + val packet = readBuffer(length) try { receiveChannel.send(packet) } catch (cause: Throwable) { @@ -76,6 +75,6 @@ internal class TcpConnection( } } - override suspend fun send(packet: ByteReadPacket): Unit = sendChannel.send(packet) - override suspend fun receive(): ByteReadPacket = receiveChannel.receive() + override suspend fun send(packet: Buffer): Unit = sendChannel.send(packet) + override suspend fun receive(): Buffer = receiveChannel.receive() } diff --git a/rsocket-transports/ktor-tcp/src/commonTest/kotlin/io/rsocket/kotlin/transport/ktor/tcp/TcpServerTest.kt b/rsocket-transports/ktor-tcp/src/commonTest/kotlin/io/rsocket/kotlin/transport/ktor/tcp/TcpServerTest.kt index df99dc02..732768b7 100644 --- a/rsocket-transports/ktor-tcp/src/commonTest/kotlin/io/rsocket/kotlin/transport/ktor/tcp/TcpServerTest.kt +++ b/rsocket-transports/ktor-tcp/src/commonTest/kotlin/io/rsocket/kotlin/transport/ktor/tcp/TcpServerTest.kt @@ -19,9 +19,10 @@ package io.rsocket.kotlin.transport.ktor.tcp import io.rsocket.kotlin.* import io.rsocket.kotlin.test.* import kotlinx.coroutines.* +import kotlinx.io.* import kotlin.test.* -class TcpServerTest : SuspendTest, TestWithLeakCheck { +class TcpServerTest : SuspendTest { private val testJob = Job() private val testContext = testJob + TestExceptionHandler private val serverTransport = KtorTcpServerTransport(testContext).target() @@ -35,7 +36,7 @@ class TcpServerTest : SuspendTest, TestWithLeakCheck { @Test fun testFailedConnection() = test { val server = TestServer().startServer(serverTransport) { - if (config.setupPayload.data.readText() == "ok") { + if (config.setupPayload.data.readString() == "ok") { RSocketRequestHandler { requestResponse { it } } diff --git a/rsocket-transports/ktor-websocket-internal/api/rsocket-transport-ktor-websocket-internal.api b/rsocket-transports/ktor-websocket-internal/api/rsocket-transport-ktor-websocket-internal.api index 8607860c..19f78978 100644 --- a/rsocket-transports/ktor-websocket-internal/api/rsocket-transport-ktor-websocket-internal.api +++ b/rsocket-transports/ktor-websocket-internal/api/rsocket-transport-ktor-websocket-internal.api @@ -6,6 +6,6 @@ public final class io/rsocket/kotlin/transport/ktor/websocket/internal/WebSocket public fun (Lio/ktor/websocket/WebSocketSession;)V public fun getCoroutineContext ()Lkotlin/coroutines/CoroutineContext; public fun receive (Lkotlin/coroutines/Continuation;)Ljava/lang/Object; - public fun send (Lio/ktor/utils/io/core/ByteReadPacket;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; + public fun send (Lkotlinx/io/Buffer;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; } diff --git a/rsocket-transports/ktor-websocket-internal/src/commonMain/kotlin/io/rsocket/kotlin/transport/ktor/websocket/internal/KtorWebSocketConnection.kt b/rsocket-transports/ktor-websocket-internal/src/commonMain/kotlin/io/rsocket/kotlin/transport/ktor/websocket/internal/KtorWebSocketConnection.kt index 05e351ae..50447626 100644 --- a/rsocket-transports/ktor-websocket-internal/src/commonMain/kotlin/io/rsocket/kotlin/transport/ktor/websocket/internal/KtorWebSocketConnection.kt +++ b/rsocket-transports/ktor-websocket-internal/src/commonMain/kotlin/io/rsocket/kotlin/transport/ktor/websocket/internal/KtorWebSocketConnection.kt @@ -16,20 +16,20 @@ package io.rsocket.kotlin.transport.ktor.websocket.internal -import io.ktor.utils.io.core.* import io.ktor.websocket.* import io.rsocket.kotlin.internal.io.* import io.rsocket.kotlin.transport.* import io.rsocket.kotlin.transport.internal.* import kotlinx.coroutines.* import kotlinx.coroutines.channels.* +import kotlinx.io.* @RSocketTransportApi public suspend fun RSocketConnectionHandler.handleKtorWebSocketConnection(webSocketSession: WebSocketSession): Unit = coroutineScope { val outboundQueue = PrioritizationFrameQueue(Channel.BUFFERED) val senderJob = launch { - while (true) webSocketSession.send(outboundQueue.dequeueFrame()?.readBytes() ?: break) + while (true) webSocketSession.send(outboundQueue.dequeueFrame()?.readByteArray() ?: break) }.onCompletion { outboundQueue.cancel() } try { @@ -52,12 +52,12 @@ private class KtorWebSocketConnection( ) : RSocketSequentialConnection { override val isClosedForSend: Boolean get() = outboundQueue.isClosedForSend - override suspend fun sendFrame(streamId: Int, frame: ByteReadPacket) { + override suspend fun sendFrame(streamId: Int, frame: Buffer) { return outboundQueue.enqueueFrame(streamId, frame) } - override suspend fun receiveFrame(): ByteReadPacket? { + override suspend fun receiveFrame(): Buffer? { val frame = inbound.receiveCatching().getOrNull() ?: return null - return ByteReadPacket(frame.data) + return Buffer().apply { write(frame.data) } } } diff --git a/rsocket-transports/ktor-websocket-internal/src/commonMain/kotlin/io/rsocket/kotlin/transport/ktor/websocket/internal/WebSocketConnection.kt b/rsocket-transports/ktor-websocket-internal/src/commonMain/kotlin/io/rsocket/kotlin/transport/ktor/websocket/internal/WebSocketConnection.kt index 6883f3c4..6c90b9f7 100644 --- a/rsocket-transports/ktor-websocket-internal/src/commonMain/kotlin/io/rsocket/kotlin/transport/ktor/websocket/internal/WebSocketConnection.kt +++ b/rsocket-transports/ktor-websocket-internal/src/commonMain/kotlin/io/rsocket/kotlin/transport/ktor/websocket/internal/WebSocketConnection.kt @@ -16,23 +16,23 @@ package io.rsocket.kotlin.transport.ktor.websocket.internal -import io.ktor.utils.io.core.* import io.ktor.websocket.* import io.rsocket.kotlin.* import kotlinx.coroutines.* +import kotlinx.io.* @Suppress("DEPRECATION_ERROR") @Deprecated(level = DeprecationLevel.ERROR, message = "Deprecated in favor of new Transport API") public class WebSocketConnection( private val session: WebSocketSession, ) : Connection, CoroutineScope by session { - override suspend fun send(packet: ByteReadPacket) { - session.send(packet.readBytes()) + override suspend fun send(packet: Buffer) { + session.send(packet.readByteArray()) } - override suspend fun receive(): ByteReadPacket { + override suspend fun receive(): Buffer { val frame = session.incoming.receive() - return ByteReadPacket(frame.data) + return Buffer().apply { write(frame.data) } } } diff --git a/rsocket-transports/ktor-websocket-server/build.gradle.kts b/rsocket-transports/ktor-websocket-server/build.gradle.kts index 157ab04f..ae436493 100644 --- a/rsocket-transports/ktor-websocket-server/build.gradle.kts +++ b/rsocket-transports/ktor-websocket-server/build.gradle.kts @@ -42,9 +42,7 @@ kotlin { } jvmTest.dependencies { implementation(libs.ktor.client.okhttp) - implementation(libs.ktor.server.netty) - implementation(libs.ktor.server.jetty) } } } diff --git a/rsocket-transports/ktor-websocket-server/src/commonMain/kotlin/io/rsocket/kotlin/transport/ktor/websocket/server/KtorWebSocketServerTransport.kt b/rsocket-transports/ktor-websocket-server/src/commonMain/kotlin/io/rsocket/kotlin/transport/ktor/websocket/server/KtorWebSocketServerTransport.kt index 81750f5d..7d690157 100644 --- a/rsocket-transports/ktor-websocket-server/src/commonMain/kotlin/io/rsocket/kotlin/transport/ktor/websocket/server/KtorWebSocketServerTransport.kt +++ b/rsocket-transports/ktor-websocket-server/src/commonMain/kotlin/io/rsocket/kotlin/transport/ktor/websocket/server/KtorWebSocketServerTransport.kt @@ -155,11 +155,12 @@ private class KtorWebSocketServerTargetImpl( currentCoroutineContext().ensureActive() coroutineContext.ensureActive() - val engine = createServerEngine(handler) - val resolvedConnectors = startServerEngine(engine) + val serverContext = coroutineContext.childContext() + val embeddedServer = createServer(handler, serverContext) + val resolvedConnectors = startServer(embeddedServer, serverContext) return KtorWebSocketServerInstanceImpl( - coroutineContext = engine.environment.parentCoroutineContext, + coroutineContext = serverContext, connectors = resolvedConnectors, path = path, protocol = protocol @@ -168,11 +169,13 @@ private class KtorWebSocketServerTargetImpl( // parentCoroutineContext is the context of server instance @RSocketTransportApi - private fun createServerEngine(handler: RSocketConnectionHandler): ApplicationEngine = factory.createServer( - applicationEngineEnvironment { + private fun createServer( + handler: RSocketConnectionHandler, + serverContext: CoroutineContext, + ): EmbeddedServer<*, *> { + val config = serverConfig { val target = this@KtorWebSocketServerTargetImpl - parentCoroutineContext = target.coroutineContext.childContext() - connectors.addAll(target.connectors) + parentCoroutineContext = serverContext module { install(WebSockets, webSocketsConfig) routing { @@ -182,16 +185,26 @@ private class KtorWebSocketServerTargetImpl( } } } - ) + return factory.createServer(config, connectors) + } - @OptIn(ExperimentalCoroutinesApi::class) - private suspend fun startServerEngine( - applicationEngine: ApplicationEngine, - ): List = launchCoroutine { cont -> - applicationEngine.start().stopServerOnCancellation() - cont.resume(applicationEngine.resolvedConnectors()) { cause, _, _ -> + private suspend fun startServer( + embeddedServer: EmbeddedServer<*, *>, + serverContext: CoroutineContext, + ): List = launchCoroutine(serverContext + Dispatchers.IO) { cont -> + embeddedServer.start() + launch(serverContext + Dispatchers.IO) { + try { + awaitCancellation() + } finally { + withContext(NonCancellable) { + embeddedServer.stop() + } + } + } + cont.resume(embeddedServer.engine.resolvedConnectors()) { cause, _, _ -> // will cause stopping of the server - applicationEngine.environment.parentCoroutineContext.job.cancel("Cancelled", cause) + serverContext.job.cancel("Cancelled", cause) } } } @@ -207,8 +220,11 @@ private class HttpServerFactory, private val configure: T.() -> Unit = {}, ) { - @RSocketTransportApi - fun createServer(environment: ApplicationEngineEnvironment): ApplicationEngine { - return factory.create(environment, configure) + fun createServer( + config: ServerConfig, + connectors: List, + ): EmbeddedServer = embeddedServer(factory, config) { + this.connectors.addAll(connectors) + this.configure() } } diff --git a/rsocket-transports/ktor-websocket-server/src/commonMain/kotlin/io/rsocket/kotlin/transport/ktor/websocket/server/WebSocketServerTransport.kt b/rsocket-transports/ktor-websocket-server/src/commonMain/kotlin/io/rsocket/kotlin/transport/ktor/websocket/server/WebSocketServerTransport.kt index ad4f7efe..47bbaa1d 100644 --- a/rsocket-transports/ktor-websocket-server/src/commonMain/kotlin/io/rsocket/kotlin/transport/ktor/websocket/server/WebSocketServerTransport.kt +++ b/rsocket-transports/ktor-websocket-server/src/commonMain/kotlin/io/rsocket/kotlin/transport/ktor/websocket/server/WebSocketServerTransport.kt @@ -31,7 +31,7 @@ public fun WebSocke path: String? = null, protocol: String? = null, engine: T.() -> Unit = {}, webSockets: WebSockets.WebSocketOptions.() -> Unit = {}, -): ServerTransport = WebSocketServerTransport( +): ServerTransport> = WebSocketServerTransport( engineFactory, EngineConnectorBuilder().apply { this.port = port @@ -51,20 +51,27 @@ public fun WebSocke path: String? = null, protocol: String? = null, engine: T.() -> Unit = {}, webSockets: WebSockets.WebSocketOptions.() -> Unit = {}, -): ServerTransport = ServerTransport { acceptor -> +): ServerTransport> = ServerTransport { acceptor -> val handler: suspend DefaultWebSocketServerSession.() -> Unit = { val connection = WebSocketConnection(this) acceptor(connection) } - embeddedServer(engineFactory, *connectors, configure = engine) { - install(WebSockets, webSockets) - routing { - when (path) { - null -> webSocket(protocol, handler) - else -> webSocket(path, protocol, handler) + embeddedServer(engineFactory, serverConfig { + this.parentCoroutineContext = coroutineContext + module { + install(WebSockets, webSockets) + routing { + when (path) { + null -> webSocket(protocol, handler) + else -> webSocket(path, protocol, handler) + } } } + }) { + this.connectors.addAll(connectors) + engine() }.also { it.start(wait = false) + it.engine.stopServerOnCancellation(it.application) } } diff --git a/rsocket-transports/ktor-websocket-server/src/commonTest/kotlin/io/rsocket/kotlin/transport/ktor/websocket/server/WebSocketTransportTest.kt b/rsocket-transports/ktor-websocket-server/src/commonTest/kotlin/io/rsocket/kotlin/transport/ktor/websocket/server/WebSocketTransportTest.kt index d90379e0..a0a3f06a 100644 --- a/rsocket-transports/ktor-websocket-server/src/commonTest/kotlin/io/rsocket/kotlin/transport/ktor/websocket/server/WebSocketTransportTest.kt +++ b/rsocket-transports/ktor-websocket-server/src/commonTest/kotlin/io/rsocket/kotlin/transport/ktor/websocket/server/WebSocketTransportTest.kt @@ -27,10 +27,10 @@ abstract class WebSocketTransportTest( private val serverEngine: ApplicationEngineFactory<*, *>, ) : TransportTest() { override suspend fun before() { - val engine = startServer( + val embeddedServer = startServer( WebSocketServerTransport(serverEngine, port = 0) ) - val connector = engine.resolvedConnectors().single() + val connector = embeddedServer.engine.resolvedConnectors().single() client = connectClient( WebSocketClientTransport(clientEngine, port = connector.port, context = testContext) ) diff --git a/rsocket-transports/ktor-websocket-server/src/jvmTest/kotlin/io/rsocket/kotlin/transport/ktor/websocket/server/WebSocketTransportTests.kt b/rsocket-transports/ktor-websocket-server/src/jvmTest/kotlin/io/rsocket/kotlin/transport/ktor/websocket/server/WebSocketTransportTests.kt index 3afca1bf..315b6773 100644 --- a/rsocket-transports/ktor-websocket-server/src/jvmTest/kotlin/io/rsocket/kotlin/transport/ktor/websocket/server/WebSocketTransportTests.kt +++ b/rsocket-transports/ktor-websocket-server/src/jvmTest/kotlin/io/rsocket/kotlin/transport/ktor/websocket/server/WebSocketTransportTests.kt @@ -17,7 +17,6 @@ package io.rsocket.kotlin.transport.ktor.websocket.server import io.ktor.client.engine.okhttp.* -import io.ktor.server.jetty.* import io.ktor.server.netty.* import io.ktor.client.engine.cio.CIO as ClientCIO import io.ktor.server.cio.CIO as ServerCIO @@ -26,12 +25,6 @@ class OkHttpClientWebSocketTransportTest : WebSocketTransportTest(OkHttp, Server class NettyServerWebSocketTransportTest : WebSocketTransportTest(ClientCIO, Netty) -class JettyServerWebSocketTransportTest : WebSocketTransportTest(ClientCIO, Jetty) - - - class OkHttpClientKtorWebSocketTransportTest : KtorWebSocketTransportTest(OkHttp, ServerCIO) class NettyServerKtorWebSocketTransportTest : KtorWebSocketTransportTest(ClientCIO, Netty) - -class JettyServerKtorWebSocketTransportTest : KtorWebSocketTransportTest(ClientCIO, Jetty) diff --git a/rsocket-transports/local/src/commonMain/kotlin/io/rsocket/kotlin/transport/local/LocalConnection.kt b/rsocket-transports/local/src/commonMain/kotlin/io/rsocket/kotlin/transport/local/LocalConnection.kt index dc583c79..20aa9913 100644 --- a/rsocket-transports/local/src/commonMain/kotlin/io/rsocket/kotlin/transport/local/LocalConnection.kt +++ b/rsocket-transports/local/src/commonMain/kotlin/io/rsocket/kotlin/transport/local/LocalConnection.kt @@ -16,23 +16,23 @@ package io.rsocket.kotlin.transport.local -import io.ktor.utils.io.core.* import io.rsocket.kotlin.* import kotlinx.coroutines.channels.* +import kotlinx.io.* import kotlin.coroutines.* @Suppress("DEPRECATION_ERROR") internal class LocalConnection( - private val sender: SendChannel, - private val receiver: ReceiveChannel, - override val coroutineContext: CoroutineContext + private val sender: SendChannel, + private val receiver: ReceiveChannel, + override val coroutineContext: CoroutineContext, ) : Connection { - override suspend fun send(packet: ByteReadPacket) { + override suspend fun send(packet: Buffer) { sender.send(packet) } - override suspend fun receive(): ByteReadPacket { + override suspend fun receive(): Buffer { return receiver.receive() } } diff --git a/rsocket-transports/local/src/commonMain/kotlin/io/rsocket/kotlin/transport/local/LocalServer.kt b/rsocket-transports/local/src/commonMain/kotlin/io/rsocket/kotlin/transport/local/LocalServer.kt index d910fd56..ca531672 100644 --- a/rsocket-transports/local/src/commonMain/kotlin/io/rsocket/kotlin/transport/local/LocalServer.kt +++ b/rsocket-transports/local/src/commonMain/kotlin/io/rsocket/kotlin/transport/local/LocalServer.kt @@ -18,7 +18,6 @@ package io.rsocket.kotlin.transport.local -import io.ktor.utils.io.core.* import io.rsocket.kotlin.* import io.rsocket.kotlin.internal.io.* import io.rsocket.kotlin.transport.* @@ -49,8 +48,8 @@ public class LocalServer internal constructor( override val coroutineContext: CoroutineContext, ) : ClientTransport { override suspend fun connect(): Connection { - val clientChannel = channelForCloseable(Channel.UNLIMITED) - val serverChannel = channelForCloseable(Channel.UNLIMITED) + val clientChannel = bufferChannel(Channel.UNLIMITED) + val serverChannel = bufferChannel(Channel.UNLIMITED) val connectionJob = Job(coroutineContext[Job]) connectionJob.invokeOnCompletion { clientChannel.cancelWithCause(it) diff --git a/rsocket-transports/local/src/commonMain/kotlin/io/rsocket/kotlin/transport/local/LocalServerConnector.kt b/rsocket-transports/local/src/commonMain/kotlin/io/rsocket/kotlin/transport/local/LocalServerConnector.kt index d5ea6a0e..ce5d3086 100644 --- a/rsocket-transports/local/src/commonMain/kotlin/io/rsocket/kotlin/transport/local/LocalServerConnector.kt +++ b/rsocket-transports/local/src/commonMain/kotlin/io/rsocket/kotlin/transport/local/LocalServerConnector.kt @@ -16,12 +16,12 @@ package io.rsocket.kotlin.transport.local -import io.ktor.utils.io.core.* import io.rsocket.kotlin.internal.io.* import io.rsocket.kotlin.transport.* import io.rsocket.kotlin.transport.internal.* import kotlinx.coroutines.* import kotlinx.coroutines.channels.* +import kotlinx.io.* internal sealed class LocalServerConnector { @RSocketTransportApi @@ -70,11 +70,11 @@ internal sealed class LocalServerConnector { ) : RSocketSequentialConnection { override val isClosedForSend: Boolean get() = outbound.isClosedForSend - override suspend fun sendFrame(streamId: Int, frame: ByteReadPacket) { + override suspend fun sendFrame(streamId: Int, frame: Buffer) { return outbound.enqueueFrame(streamId, frame) } - override suspend fun receiveFrame(): ByteReadPacket? { + override suspend fun receiveFrame(): Buffer? { return inbound.dequeueFrame() } } @@ -92,7 +92,7 @@ internal sealed class LocalServerConnector { serverScope: CoroutineScope, serverHandler: RSocketConnectionHandler, ): Job { - val streams = Channels>(streamsQueueCapacity) + val streams = Streams(streamsQueueCapacity) launchLocalConnection(serverScope, streams.serverToClient, streams.clientToServer, serverHandler) return launchLocalConnection(clientScope, streams.clientToServer, streams.serverToClient, clientHandler) @@ -101,8 +101,8 @@ internal sealed class LocalServerConnector { @RSocketTransportApi private fun launchLocalConnection( scope: CoroutineScope, - outbound: SendChannel>, - inbound: ReceiveChannel>, + outbound: SendChannel, + inbound: ReceiveChannel, handler: RSocketConnectionHandler, ): Job = scope.launch { handler.handleConnection(Connection(SupervisorJob(coroutineContext.job), outbound, inbound, streamBufferCapacity)) @@ -114,12 +114,12 @@ internal sealed class LocalServerConnector { @RSocketTransportApi private class Connection( private val streamsJob: Job, - private val outbound: SendChannel>, - private val inbound: ReceiveChannel>, + private val outbound: SendChannel, + private val inbound: ReceiveChannel, private val streamBufferCapacity: Int, ) : RSocketMultiplexedConnection { override suspend fun createStream(): RSocketMultiplexedConnection.Stream { - val frames = Channels(streamBufferCapacity) + val frames = Frames(streamBufferCapacity) outbound.send(frames) @@ -144,8 +144,8 @@ internal sealed class LocalServerConnector { @RSocketTransportApi private class Stream( parentJob: Job, - private val outbound: SendChannel, - private val inbound: ReceiveChannel, + private val outbound: SendChannel, + private val inbound: ReceiveChannel, ) : RSocketMultiplexedConnection.Stream { private val streamJob = Job(parentJob).onCompletion { outbound.close() @@ -161,18 +161,29 @@ internal sealed class LocalServerConnector { override fun setSendPriority(priority: Int) {} - override suspend fun sendFrame(frame: ByteReadPacket) { + override suspend fun sendFrame(frame: Buffer) { return outbound.send(frame) } - override suspend fun receiveFrame(): ByteReadPacket? { + override suspend fun receiveFrame(): Buffer? { return inbound.receiveCatching().getOrNull() } } - private class Channels(bufferCapacity: Int) : Closeable { - val clientToServer = channelForCloseable(bufferCapacity) - val serverToClient = channelForCloseable(bufferCapacity) + private class Streams(bufferCapacity: Int) : AutoCloseable { + val clientToServer = channelForCloseable(bufferCapacity) + val serverToClient = channelForCloseable(bufferCapacity) + + // only for undelivered element case + override fun close() { + clientToServer.cancel() + serverToClient.cancel() + } + } + + private class Frames(bufferCapacity: Int) : AutoCloseable { + val clientToServer = bufferChannel(bufferCapacity) + val serverToClient = bufferChannel(bufferCapacity) // only for undelivered element case override fun close() { diff --git a/rsocket-transports/netty-internal/api/rsocket-transport-netty-internal.api b/rsocket-transports/netty-internal/api/rsocket-transport-netty-internal.api index 66fea981..0fe8a5fc 100644 --- a/rsocket-transports/netty-internal/api/rsocket-transport-netty-internal.api +++ b/rsocket-transports/netty-internal/api/rsocket-transport-netty-internal.api @@ -2,7 +2,10 @@ public final class io/rsocket/kotlin/transport/netty/internal/CoroutinesKt { public static final fun awaitChannel (Lio/netty/channel/ChannelFuture;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; public static final fun awaitFuture (Lio/netty/util/concurrent/Future;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; public static final fun callOnCancellation (Lkotlinx/coroutines/CoroutineScope;Lkotlin/jvm/functions/Function1;)V - public static final fun toByteBuf (Lio/ktor/utils/io/core/ByteReadPacket;)Lio/netty/buffer/ByteBuf; - public static final fun toByteReadPacket (Lio/netty/buffer/ByteBuf;)Lio/ktor/utils/io/core/ByteReadPacket; +} + +public final class io/rsocket/kotlin/transport/netty/internal/IoKt { + public static final fun toBuffer (Lio/netty/buffer/ByteBuf;)Lkotlinx/io/Buffer; + public static final fun toByteBuf (Lkotlinx/io/Buffer;Lio/netty/buffer/ByteBufAllocator;)Lio/netty/buffer/ByteBuf; } diff --git a/rsocket-transports/netty-internal/src/jvmMain/kotlin/io/rsocket/kotlin/transport/netty/internal/coroutines.kt b/rsocket-transports/netty-internal/src/jvmMain/kotlin/io/rsocket/kotlin/transport/netty/internal/coroutines.kt index 25be5e32..f2a84fc6 100644 --- a/rsocket-transports/netty-internal/src/jvmMain/kotlin/io/rsocket/kotlin/transport/netty/internal/coroutines.kt +++ b/rsocket-transports/netty-internal/src/jvmMain/kotlin/io/rsocket/kotlin/transport/netty/internal/coroutines.kt @@ -16,8 +16,6 @@ package io.rsocket.kotlin.transport.netty.internal -import io.ktor.utils.io.core.* -import io.netty.buffer.* import io.netty.channel.* import io.netty.util.concurrent.* import kotlinx.coroutines.* @@ -58,7 +56,3 @@ public inline fun CoroutineScope.callOnCancellation(crossinline block: suspend ( } } } - -// TODO: what to use: this or ByteReadPacket(msg.nioBuffer()) -public fun ByteBuf.toByteReadPacket(): ByteReadPacket = buildPacket { writeFully(nioBuffer()) } -public fun ByteReadPacket.toByteBuf(): ByteBuf = Unpooled.wrappedBuffer(readByteBuffer()) diff --git a/rsocket-transports/netty-internal/src/jvmMain/kotlin/io/rsocket/kotlin/transport/netty/internal/io.kt b/rsocket-transports/netty-internal/src/jvmMain/kotlin/io/rsocket/kotlin/transport/netty/internal/io.kt new file mode 100644 index 00000000..8758134d --- /dev/null +++ b/rsocket-transports/netty-internal/src/jvmMain/kotlin/io/rsocket/kotlin/transport/netty/internal/io.kt @@ -0,0 +1,47 @@ +/* + * Copyright 2015-2024 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.rsocket.kotlin.transport.netty.internal + +import io.netty.buffer.* +import kotlinx.io.* +import kotlinx.io.unsafe.* + +@OptIn(UnsafeIoApi::class) +public fun ByteBuf.toBuffer(): Buffer { + val buffer = Buffer() + while (readableBytes() > 0) { + val maxToRead = minOf(readableBytes(), UnsafeBufferOperations.maxSafeWriteCapacity) + UnsafeBufferOperations.writeToTail(buffer, maxToRead) { bytes, start, end -> + val toRead = minOf(readableBytes(), end - start) + readBytes(bytes, start, toRead) + toRead + } + } + return buffer +} + +@OptIn(UnsafeIoApi::class) +public fun Buffer.toByteBuf(allocator: ByteBufAllocator): ByteBuf { + val nettyBuffer = allocator.buffer(size.toInt()) // TODO: length + while (!exhausted()) { + UnsafeBufferOperations.readFromHead(this) { bytes, start, end -> + nettyBuffer.writeBytes(bytes, start, end - start) + end - start + } + } + return nettyBuffer +} diff --git a/rsocket-transports/netty-quic/src/jvmMain/kotlin/io/rsocket/kotlin/transport/netty/quic/NettyQuicStreamHandler.kt b/rsocket-transports/netty-quic/src/jvmMain/kotlin/io/rsocket/kotlin/transport/netty/quic/NettyQuicStreamHandler.kt index e624c0b0..f5c5df8c 100644 --- a/rsocket-transports/netty-quic/src/jvmMain/kotlin/io/rsocket/kotlin/transport/netty/quic/NettyQuicStreamHandler.kt +++ b/rsocket-transports/netty-quic/src/jvmMain/kotlin/io/rsocket/kotlin/transport/netty/quic/NettyQuicStreamHandler.kt @@ -16,7 +16,6 @@ package io.rsocket.kotlin.transport.netty.quic -import io.ktor.utils.io.core.* import io.netty.buffer.* import io.netty.channel.* import io.netty.channel.socket.* @@ -27,6 +26,7 @@ import io.rsocket.kotlin.transport.netty.internal.* import kotlinx.coroutines.* import kotlinx.coroutines.channels.* import kotlinx.coroutines.channels.Channel +import kotlinx.io.* // TODO: first stream is a hack to initiate first stream because of buffering // quic streams could be received unordered by server, so f.e we could receive first stream with id 4 and then with id 0 @@ -35,8 +35,8 @@ import kotlinx.coroutines.channels.Channel @RSocketTransportApi internal class NettyQuicStreamState(val startMarker: CompletableJob?) { val closeMarker: CompletableJob = Job() - val outbound = channelForCloseable(Channel.BUFFERED) - val inbound = channelForCloseable(Channel.UNLIMITED) + val outbound = bufferChannel(Channel.BUFFERED) + val inbound = bufferChannel(Channel.UNLIMITED) fun wrapStream(stream: QuicStreamChannel): RSocketMultiplexedConnection.Stream = NettyQuicStream(stream, outbound, inbound, closeMarker) @@ -60,8 +60,8 @@ internal class NettyQuicStreamHandler( // avoiding unnecessary flushes // TODO: could be optimized to avoid allocation of not-needed promises - var lastWriteFuture = channel.write(outbound.receiveCatching().getOrNull()?.toByteBuf() ?: break) - while (true) lastWriteFuture = channel.write(outbound.tryReceive().getOrNull()?.toByteBuf() ?: break) + var lastWriteFuture = channel.write(outbound.receiveCatching().getOrNull()?.toByteBuf(channel.alloc()) ?: break) + while (true) lastWriteFuture = channel.write(outbound.tryReceive().getOrNull()?.toByteBuf(channel.alloc()) ?: break) //println("FLUSH: $isClient: ${channel.streamId()}") channel.flush() // await writing to respect transport backpressure @@ -110,12 +110,12 @@ internal class NettyQuicStreamHandler( } private class NettyQuicStreamInboundHandler( - private val inbound: SendChannel, + private val inbound: SendChannel, ) : ChannelInboundHandlerAdapter() { override fun channelRead(ctx: ChannelHandlerContext, msg: Any) { msg as ByteBuf try { - val frame = msg.toByteReadPacket() + val frame = msg.toBuffer() if (inbound.trySend(frame).isFailure) { frame.close() } @@ -136,8 +136,8 @@ private class NettyQuicStreamInboundHandler( private class NettyQuicStream( // for priority private val stream: QuicStreamChannel, - private val outbound: SendChannel, - private val inbound: ReceiveChannel, + private val outbound: SendChannel, + private val inbound: ReceiveChannel, private val closeMarker: CompletableJob, ) : RSocketMultiplexedConnection.Stream { @@ -148,11 +148,11 @@ private class NettyQuicStream( stream.updatePriority(QuicStreamPriority(priority, false)) } - override suspend fun sendFrame(frame: ByteReadPacket) { + override suspend fun sendFrame(frame: Buffer) { outbound.send(frame) } - override suspend fun receiveFrame(): ByteReadPacket? { + override suspend fun receiveFrame(): Buffer? { return inbound.receiveCatching().getOrNull() } diff --git a/rsocket-transports/netty-tcp/src/jvmMain/kotlin/io/rsocket/kotlin/transport/netty/tcp/NettyTcpConnectionHandler.kt b/rsocket-transports/netty-tcp/src/jvmMain/kotlin/io/rsocket/kotlin/transport/netty/tcp/NettyTcpConnectionHandler.kt index fa557ab9..07cbaabf 100644 --- a/rsocket-transports/netty-tcp/src/jvmMain/kotlin/io/rsocket/kotlin/transport/netty/tcp/NettyTcpConnectionHandler.kt +++ b/rsocket-transports/netty-tcp/src/jvmMain/kotlin/io/rsocket/kotlin/transport/netty/tcp/NettyTcpConnectionHandler.kt @@ -16,7 +16,6 @@ package io.rsocket.kotlin.transport.netty.tcp -import io.ktor.utils.io.core.* import io.netty.buffer.* import io.netty.channel.* import io.netty.channel.socket.* @@ -27,6 +26,7 @@ import io.rsocket.kotlin.transport.netty.internal.* import kotlinx.coroutines.* import kotlinx.coroutines.channels.* import kotlinx.coroutines.channels.Channel +import kotlinx.io.* import io.netty.channel.socket.DuplexChannel as NettyDuplexChannel @RSocketTransportApi @@ -35,7 +35,7 @@ internal class NettyTcpConnectionHandler( private val handler: RSocketConnectionHandler, scope: CoroutineScope, ) : ChannelInboundHandlerAdapter() { - private val inbound = channelForCloseable(Channel.UNLIMITED) + private val inbound = bufferChannel(Channel.UNLIMITED) private val handlerJob = scope.launch(start = CoroutineStart.LAZY) { val outboundQueue = PrioritizationFrameQueue(Channel.BUFFERED) @@ -47,8 +47,8 @@ internal class NettyTcpConnectionHandler( // in this case, if there are several buffered frames we can send them in one go // avoiding unnecessary flushes // TODO: could be optimized to avoid allocation of not-needed promises - var lastWriteFuture = channel.write(outboundQueue.dequeueFrame()?.toByteBuf() ?: break) - while (true) lastWriteFuture = channel.write(outboundQueue.tryDequeueFrame()?.toByteBuf() ?: break) + var lastWriteFuture = channel.write(outboundQueue.dequeueFrame()?.toByteBuf(channel.alloc()) ?: break) + while (true) lastWriteFuture = channel.write(outboundQueue.tryDequeueFrame()?.toByteBuf(channel.alloc()) ?: break) channel.flush() // await writing to respect transport backpressure lastWriteFuture.awaitFuture() @@ -94,14 +94,14 @@ internal class NettyTcpConnectionHandler( // TODO: implement support for isAutoRead=false to support `inbound` backpressure private class NettyTcpConnectionInboundHandler( - private val inbound: SendChannel, + private val inbound: SendChannel, ) : ChannelInboundHandlerAdapter() { override fun channelRead(ctx: ChannelHandlerContext, msg: Any) { msg as ByteBuf try { - val frame = msg.toByteReadPacket() + val frame = msg.toBuffer() if (inbound.trySend(frame).isFailure) { - frame.close() + frame.clear() error("inbound is closed") } } finally { @@ -120,14 +120,14 @@ private class NettyTcpConnectionInboundHandler( @RSocketTransportApi private class NettyTcpConnection( private val outboundQueue: PrioritizationFrameQueue, - private val inbound: ReceiveChannel, + private val inbound: ReceiveChannel, ) : RSocketSequentialConnection { override val isClosedForSend: Boolean get() = outboundQueue.isClosedForSend - override suspend fun sendFrame(streamId: Int, frame: ByteReadPacket) { + override suspend fun sendFrame(streamId: Int, frame: Buffer) { return outboundQueue.enqueueFrame(streamId, frame) } - override suspend fun receiveFrame(): ByteReadPacket? { + override suspend fun receiveFrame(): Buffer? { return inbound.receiveCatching().getOrNull() } } diff --git a/rsocket-transports/netty-websocket/src/jvmMain/kotlin/io/rsocket/kotlin/transport/netty/websocket/NettyWebSocketConnectionHandler.kt b/rsocket-transports/netty-websocket/src/jvmMain/kotlin/io/rsocket/kotlin/transport/netty/websocket/NettyWebSocketConnectionHandler.kt index 13919215..d8671449 100644 --- a/rsocket-transports/netty-websocket/src/jvmMain/kotlin/io/rsocket/kotlin/transport/netty/websocket/NettyWebSocketConnectionHandler.kt +++ b/rsocket-transports/netty-websocket/src/jvmMain/kotlin/io/rsocket/kotlin/transport/netty/websocket/NettyWebSocketConnectionHandler.kt @@ -16,7 +16,6 @@ package io.rsocket.kotlin.transport.netty.websocket -import io.ktor.utils.io.core.* import io.netty.channel.* import io.netty.channel.socket.* import io.netty.handler.codec.http.websocketx.* @@ -27,6 +26,7 @@ import io.rsocket.kotlin.transport.netty.internal.* import kotlinx.coroutines.* import kotlinx.coroutines.channels.* import kotlinx.coroutines.channels.Channel +import kotlinx.io.* @RSocketTransportApi internal class NettyWebSocketConnectionHandler( @@ -34,7 +34,7 @@ internal class NettyWebSocketConnectionHandler( private val handler: RSocketConnectionHandler, scope: CoroutineScope, ) : ChannelInboundHandlerAdapter() { - private val inbound = channelForCloseable(Channel.UNLIMITED) + private val inbound = bufferChannel(Channel.UNLIMITED) private val handlerJob = scope.launch(start = CoroutineStart.LAZY) { val outboundQueue = PrioritizationFrameQueue(Channel.BUFFERED) @@ -46,9 +46,10 @@ internal class NettyWebSocketConnectionHandler( // in this case, if there are several buffered frames we can send them in one go // avoiding unnecessary flushes // TODO: could be optimized to avoid allocation of not-needed promises - var lastWriteFuture = channel.write(BinaryWebSocketFrame(outboundQueue.dequeueFrame()?.toByteBuf() ?: break)) + var lastWriteFuture = + channel.write(BinaryWebSocketFrame(outboundQueue.dequeueFrame()?.toByteBuf(channel.alloc()) ?: break)) while (true) lastWriteFuture = - channel.write(BinaryWebSocketFrame(outboundQueue.tryDequeueFrame()?.toByteBuf() ?: break)) + channel.write(BinaryWebSocketFrame(outboundQueue.tryDequeueFrame()?.toByteBuf(channel.alloc()) ?: break)) channel.flush() // await writing to respect transport backpressure lastWriteFuture.awaitFuture() @@ -100,13 +101,13 @@ internal class NettyWebSocketConnectionHandler( // TODO: implement support for isAutoRead=false to support `inbound` backpressure private class NettyWebSocketConnectionInboundHandler( - private val inbound: SendChannel, + private val inbound: SendChannel, ) : ChannelInboundHandlerAdapter() { override fun channelRead(ctx: ChannelHandlerContext, msg: Any) { msg as WebSocketFrame try { - val frame = msg.content().toByteReadPacket() + val frame = msg.content().toBuffer() if (inbound.trySend(frame).isFailure) { frame.close() error("inbound is closed") @@ -127,14 +128,14 @@ private class NettyWebSocketConnectionInboundHandler( @RSocketTransportApi private class NettyWebSocketConnection( private val outboundQueue: PrioritizationFrameQueue, - private val inbound: ReceiveChannel, + private val inbound: ReceiveChannel, ) : RSocketSequentialConnection { override val isClosedForSend: Boolean get() = outboundQueue.isClosedForSend - override suspend fun sendFrame(streamId: Int, frame: ByteReadPacket) { + override suspend fun sendFrame(streamId: Int, frame: Buffer) { return outboundQueue.enqueueFrame(streamId, frame) } - override suspend fun receiveFrame(): ByteReadPacket? { + override suspend fun receiveFrame(): Buffer? { return inbound.receiveCatching().getOrNull() } } diff --git a/rsocket-transports/nodejs-tcp/src/jsMain/kotlin/io/rsocket/kotlin/transport/nodejs/tcp/FrameWithLengthAssembler.kt b/rsocket-transports/nodejs-tcp/src/jsMain/kotlin/io/rsocket/kotlin/transport/nodejs/tcp/FrameWithLengthAssembler.kt index d91c45cc..c56213a4 100644 --- a/rsocket-transports/nodejs-tcp/src/jsMain/kotlin/io/rsocket/kotlin/transport/nodejs/tcp/FrameWithLengthAssembler.kt +++ b/rsocket-transports/nodejs-tcp/src/jsMain/kotlin/io/rsocket/kotlin/transport/nodejs/tcp/FrameWithLengthAssembler.kt @@ -16,54 +16,59 @@ package io.rsocket.kotlin.transport.nodejs.tcp -import io.ktor.utils.io.core.* import io.rsocket.kotlin.internal.io.* +import io.rsocket.kotlin.transport.nodejs.tcp.internal.* +import kotlinx.io.* +import org.khronos.webgl.* -internal fun ByteReadPacket.withLength(): ByteReadPacket = buildPacket { - writeInt24(this@withLength.remaining.toInt()) - writePacket(this@withLength) +private fun ByteArray.toUint8Array(): Uint8Array { + val int8Array = unsafeCast() + return Uint8Array(int8Array.buffer, int8Array.byteOffset, int8Array.length) } -internal class FrameWithLengthAssembler(private val onFrame: (frame: ByteReadPacket) -> Unit) : Closeable { +private fun Uint8Array.toByteArray(): ByteArray { + return Int8Array(buffer, byteOffset, length).unsafeCast() +} + +internal fun Socket.writeFrame(frame: Buffer) { + val packet = Buffer().apply { + writeInt24(frame.size.toInt()) + transferFrom(frame) + } + write(packet.readByteArray().toUint8Array()) +} + +internal class FrameWithLengthAssembler(private val onFrame: (frame: Buffer) -> Unit) : AutoCloseable { private var closed = false private var expectedFrameLength = 0 - private val packetBuilder: BytePacketBuilder = BytePacketBuilder() + private val buffer = Buffer() override fun close() { - packetBuilder.close() + buffer.clear() closed = true } - inline fun write(write: BytePacketBuilder.() -> Unit) { + fun write(array: Uint8Array) { if (closed) return - packetBuilder.write() + buffer.write(array.toByteArray()) loop() } private fun loop() { while (true) when { - expectedFrameLength == 0 && packetBuilder.size < 3 -> return // no length - expectedFrameLength == 0 -> withTemp { // has length - expectedFrameLength = it.readInt24() - if (it.remaining >= expectedFrameLength) build(it) // if has length and frame + // no length + expectedFrameLength == 0 && buffer.size < 3 -> return + // has length + expectedFrameLength == 0 -> expectedFrameLength = buffer.readInt24() + // not enough bytes to read frame + buffer.size < expectedFrameLength -> return + // enough bytes to read frame + else -> { + val frame = Buffer() + buffer.readTo(frame, expectedFrameLength.toLong()) + expectedFrameLength = 0 + onFrame(frame) } - - packetBuilder.size < expectedFrameLength -> return // not enough bytes to read frame - else -> withTemp { build(it) } // enough bytes to read frame } } - - private fun build(from: ByteReadPacket) { - val frame = buildPacket { - writePacket(from, expectedFrameLength) - } - expectedFrameLength = 0 - onFrame(frame) - } - - private inline fun withTemp(block: (tempPacket: ByteReadPacket) -> Unit) { - val tempPacket = packetBuilder.build() - block(tempPacket) - packetBuilder.writePacket(tempPacket) - } } diff --git a/rsocket-transports/nodejs-tcp/src/jsMain/kotlin/io/rsocket/kotlin/transport/nodejs/tcp/NodejsTcpConnection.kt b/rsocket-transports/nodejs-tcp/src/jsMain/kotlin/io/rsocket/kotlin/transport/nodejs/tcp/NodejsTcpConnection.kt index 7846f0f4..189b5191 100644 --- a/rsocket-transports/nodejs-tcp/src/jsMain/kotlin/io/rsocket/kotlin/transport/nodejs/tcp/NodejsTcpConnection.kt +++ b/rsocket-transports/nodejs-tcp/src/jsMain/kotlin/io/rsocket/kotlin/transport/nodejs/tcp/NodejsTcpConnection.kt @@ -16,25 +16,23 @@ package io.rsocket.kotlin.transport.nodejs.tcp -import io.ktor.utils.io.core.* -import io.ktor.utils.io.js.* import io.rsocket.kotlin.internal.io.* import io.rsocket.kotlin.transport.* import io.rsocket.kotlin.transport.internal.* import io.rsocket.kotlin.transport.nodejs.tcp.internal.* import kotlinx.coroutines.* import kotlinx.coroutines.channels.* -import org.khronos.webgl.* +import kotlinx.io.* @RSocketTransportApi internal suspend fun RSocketConnectionHandler.handleNodejsTcpConnection(socket: Socket): Unit = coroutineScope { val outboundQueue = PrioritizationFrameQueue(Channel.BUFFERED) - val inbound = channelForCloseable(Channel.UNLIMITED) + val inbound = bufferChannel(Channel.UNLIMITED) val closed = CompletableDeferred() val frameAssembler = FrameWithLengthAssembler { inbound.trySend(it) } socket.on( - onData = { frameAssembler.write { writeFully(it.buffer) } }, + onData = frameAssembler::write, onError = { closed.completeExceptionally(it) }, onClose = { frameAssembler.close() @@ -64,22 +62,14 @@ internal suspend fun RSocketConnectionHandler.handleNodejsTcpConnection(socket: @RSocketTransportApi private class NodejsTcpConnection( private val outboundQueue: PrioritizationFrameQueue, - private val inbound: ReceiveChannel, + private val inbound: ReceiveChannel, ) : RSocketSequentialConnection { override val isClosedForSend: Boolean get() = outboundQueue.isClosedForSend - override suspend fun sendFrame(streamId: Int, frame: ByteReadPacket) { + override suspend fun sendFrame(streamId: Int, frame: Buffer) { return outboundQueue.enqueueFrame(streamId, frame) } - override suspend fun receiveFrame(): ByteReadPacket? { + override suspend fun receiveFrame(): Buffer? { return inbound.receiveCatching().getOrNull() } } - -private fun Socket.writeFrame(frame: ByteReadPacket) { - val packet = buildPacket { - writeInt24(frame.remaining.toInt()) - writePacket(frame) - } - write(Uint8Array(packet.readArrayBuffer())) -} diff --git a/rsocket-transports/nodejs-tcp/src/jsMain/kotlin/io/rsocket/kotlin/transport/nodejs/tcp/TcpConnection.kt b/rsocket-transports/nodejs-tcp/src/jsMain/kotlin/io/rsocket/kotlin/transport/nodejs/tcp/TcpConnection.kt index af991c39..a3450902 100644 --- a/rsocket-transports/nodejs-tcp/src/jsMain/kotlin/io/rsocket/kotlin/transport/nodejs/tcp/TcpConnection.kt +++ b/rsocket-transports/nodejs-tcp/src/jsMain/kotlin/io/rsocket/kotlin/transport/nodejs/tcp/TcpConnection.kt @@ -16,14 +16,12 @@ package io.rsocket.kotlin.transport.nodejs.tcp -import io.ktor.utils.io.core.* -import io.ktor.utils.io.js.* import io.rsocket.kotlin.* import io.rsocket.kotlin.internal.io.* import io.rsocket.kotlin.transport.nodejs.tcp.internal.* import kotlinx.coroutines.* import kotlinx.coroutines.channels.* -import org.khronos.webgl.* +import kotlinx.io.* import kotlin.coroutines.* @Suppress("DEPRECATION_ERROR") @@ -32,14 +30,12 @@ internal class TcpConnection( private val socket: Socket, ) : Connection { - private val sendChannel = channelForCloseable(8) - private val receiveChannel = channelForCloseable(Channel.UNLIMITED) + private val sendChannel = bufferChannel(8) + private val receiveChannel = bufferChannel(Channel.UNLIMITED) init { launch { - sendChannel.consumeEach { packet -> - socket.write(Uint8Array(packet.withLength().readArrayBuffer())) - } + sendChannel.consumeEach(socket::writeFrame) } coroutineContext.job.invokeOnCompletion { @@ -51,17 +47,17 @@ internal class TcpConnection( val frameAssembler = FrameWithLengthAssembler { receiveChannel.trySend(it) } //TODO socket.on( - onData = { frameAssembler.write { writeFully(it.buffer) } }, + onData = frameAssembler::write, onError = { coroutineContext.job.cancel("Socket error", it) }, onClose = { if (!it) coroutineContext.job.cancel("Socket closed") } ) } - override suspend fun send(packet: ByteReadPacket) { + override suspend fun send(packet: Buffer) { sendChannel.send(packet) } - override suspend fun receive(): ByteReadPacket { + override suspend fun receive(): Buffer { return receiveChannel.receive() } }