@@ -20,45 +20,59 @@ import io.rsocket.kotlin.*
2020import io.rsocket.kotlin.core.*
2121import io.rsocket.kotlin.frame.*
2222import io.rsocket.kotlin.internal.io.*
23- import io.rsocket.kotlin.keepalive.*
2423import io.rsocket.kotlin.transport.*
2524import kotlinx.coroutines.*
26- import kotlin.coroutines.*
2725
2826@RSocketTransportApi
29- internal abstract class ConnectionEstablishmentHandler (
27+ internal abstract class ConnectionInitializer (
3028 private val isClient : Boolean ,
3129 private val frameCodec : FrameCodec ,
3230 private val connectionAcceptor : ConnectionAcceptor ,
3331 private val interceptors : Interceptors ,
34- private val requesterDeferred : CompletableDeferred <RSocket >? ,
35- ) : RSocketConnectionInitializer<Unit> {
36- abstract suspend fun establishConnection (context : ConnectionEstablishmentContext ): ConnectionConfig
32+ ) {
33+ protected abstract suspend fun establishConnection (context : ConnectionEstablishmentContext ): ConnectionConfig
3734
3835 private suspend fun wrapConnection (
3936 connection : RSocketConnection ,
40- requestContext : CoroutineContext ,
41- ): Connection2 = when (connection) {
37+ requestsScope : CoroutineScope ,
38+ ): ConnectionOutbound = when (connection) {
4239 is RSocketMultiplexedConnection -> {
4340 val initialStream = when {
4441 isClient -> connection.createStream()
4542 else -> connection.acceptStream() ? : error(" Initial stream should be received" )
4643 }
4744 initialStream.setSendPriority(0 )
48- MultiplexedConnection (isClient, frameCodec, requestContext, connection, initialStream)
45+ MultiplexedConnection (isClient, frameCodec, connection, initialStream, requestsScope )
4946 }
5047
5148 is RSocketSequentialConnection -> {
52- SequentialConnection (isClient, frameCodec, requestContext, connection )
49+ SequentialConnection (isClient, frameCodec, connection, requestsScope )
5350 }
5451 }
5552
56- @Suppress(" SuspendFunctionOnCoroutineScope" )
57- private suspend fun CoroutineScope.handleConnection (connection : Connection2 ) {
53+ private suspend fun initialize (connection : RSocketConnection ): RSocket {
54+ val requestsScope = CoroutineScope (connection.coroutineContext.supervisorContext())
55+ val outbound = wrapConnection(connection, requestsScope)
56+ val connectionJob = connection.launch(start = CoroutineStart .ATOMIC ) {
57+ try {
58+ awaitCancellation()
59+ } catch (cause: Throwable ) {
60+ if (connection.isActive) {
61+ nonCancellable {
62+ outbound.sendError(RSocketError .ConnectionError (cause.message ? : " Connection failed" ))
63+ }
64+ connection.cancel(" Connection failed" , cause)
65+ }
66+ throw cause
67+ }
68+ }
69+ val connectionScope = CoroutineScope (connection.coroutineContext + connectionJob)
5870 try {
59- val connectionConfig = connection. establishConnection(this @ConnectionEstablishmentHandler )
71+ val connectionConfig = establishConnection(outbound )
6072 try {
61- val requester = interceptors.wrapRequester(connection)
73+ val requester = interceptors.wrapRequester(
74+ RequesterRSocket (requestsScope, outbound)
75+ )
6276 val responder = interceptors.wrapResponder(
6377 with (interceptors.wrapAcceptor(connectionAcceptor)) {
6478 ConnectionAcceptorContext (connectionConfig, requester).accept()
@@ -67,49 +81,57 @@ internal abstract class ConnectionEstablishmentHandler(
6781
6882 // link completing of requester, connection and requestHandler
6983 requester.coroutineContext.job.invokeOnCompletion {
70- coroutineContext.job .cancel(" Requester cancelled" , it)
84+ connectionJob .cancel(" Requester cancelled" , it)
7185 }
7286 responder.coroutineContext.job.invokeOnCompletion {
73- coroutineContext.job .cancel(" Responder cancelled" , it)
87+ connectionJob .cancel(" Responder cancelled" , it)
7488 }
75- coroutineContext.job .invokeOnCompletion { cause ->
89+ connectionJob .invokeOnCompletion { cause ->
7690 // the responder is not linked to `coroutineContext`
7791 responder.cancel(" Connection closed" , cause)
7892 }
7993
80- requesterDeferred?.complete(requester)
81-
82- val keepAliveHandler = KeepAliveHandler (connectionConfig.keepAlive, connection, this )
83- connection.handleConnection(
84- ConnectionInbound (connection.coroutineContext, responder, keepAliveHandler)
85- )
94+ val keepAliveHandler = KeepAliveHandler (connectionConfig.keepAlive, outbound, connectionScope)
95+ connectionScope.launch {
96+ outbound.handleConnection(ConnectionInbound (requestsScope, responder, keepAliveHandler))
97+ }
98+ return requester
8699 } catch (cause: Throwable ) {
87100 connectionConfig.setupPayload.close()
88101 throw cause
89102 }
90103 } catch (cause: Throwable ) {
91- connection.close()
92104 nonCancellable {
93- connection .sendError(
105+ outbound .sendError(
94106 when (cause) {
95107 is RSocketError -> cause
96- else -> RSocketError .ConnectionError (cause.message ? : " Connection failed" )
108+ else -> RSocketError .ConnectionError (cause.message ? : " Connection establishment failed" )
97109 }
98110 )
99111 }
100112 throw cause
101113 }
102114 }
103115
104- override suspend fun initialize (connection : RSocketConnection ) {
116+ private fun asyncInitializer (connection : RSocketConnection ): Deferred < RSocket > = connection.async {
105117 try {
106- coroutineScope {
107- handleConnection(wrapConnection(connection, coroutineContext.supervisorContext()))
108- }
109- connection.cancel()
118+ initialize(connection)
110119 } catch (cause: Throwable ) {
111- connection.cancel(" Connection closed " , cause)
120+ connection.cancel(" Connection initialization failed " , cause)
112121 throw cause
113122 }
114123 }
124+
125+ suspend fun runInitializer (connection : RSocketConnection ): RSocket {
126+ val result = asyncInitializer(connection)
127+ try {
128+ result.join()
129+ } catch (cause: Throwable ) {
130+ connection.cancel(" Connection initialization cancelled" , cause)
131+ throw cause
132+ }
133+ return result.await()
134+ }
135+
136+ fun launchInitializer (connection : RSocketConnection ): Job = asyncInitializer(connection)
115137}
0 commit comments