@@ -46,7 +46,7 @@ protected MultiplexedClient(Options configuration)
4646 output = input . CreateOutput ( GC . AllocateArray < byte > ( configuration . BufferCapacity , pinned : true ) , configuration . Timeout ) ;
4747 }
4848
49- private Task EnsureConnectedCoreAsync ( CancellationToken token )
49+ private Task EnsureConnectedAsync ( CancellationToken token )
5050 => readiness ? . Task . WaitAsync ( token ) ?? Task . CompletedTask ;
5151
5252 /// <summary>
@@ -57,7 +57,7 @@ private Task EnsureConnectedCoreAsync(CancellationToken token)
5757 /// <exception cref="ObjectDisposedException">The client is disposed.</exception>
5858 public ValueTask StartAsync ( CancellationToken token = default )
5959 {
60- var task = EnsureConnectedCoreAsync ( token ) ;
60+ var task = EnsureConnectedAsync ( token ) ;
6161 if ( ReferenceEquals ( dispatcher , Task . CompletedTask ) )
6262 {
6363 dispatcher = DispatchAsync ( ) ;
@@ -66,18 +66,6 @@ public ValueTask StartAsync(CancellationToken token = default)
6666 return new ( task ) ;
6767 }
6868
69- /// <summary>
70- /// Waits for the connection to be established.
71- /// </summary>
72- /// <remarks>
73- /// The method can be called to ensure that the connection to the server is established successfully.
74- /// This is useful when the underlying connection is lost to prevent inflation of the stream IDs.
75- /// </remarks>
76- /// <param name="token">The token that can be used to cancel the operation.</param>
77- /// <returns>The task representing connection state.</returns>
78- public ValueTask EnsureConnectedAsync ( CancellationToken token = default )
79- => new ( EnsureConnectedCoreAsync ( token ) ) ;
80-
8169 /// <summary>
8270 /// Creates a new multiplexed client stream.
8371 /// </summary>
@@ -99,29 +87,31 @@ public ValueTask EnsureConnectedAsync(CancellationToken token = default)
9987 /// </remarks>
10088 /// <returns>A duplex pipe for data input/output.</returns>
10189 /// <seealso cref="DotNext.IO.Pipelines.DuplexStream"/>
102- public ValueTask < IDuplexPipe > OpenStreamAsync ( CancellationToken token = default )
103- {
104- var readinessCopy = readiness ;
105- return readinessCopy is null or { Task . IsCompletedSuccessfully : true }
106- ? new ( OpenStream ( ) )
107- : OpenStreamCoreAsync ( readinessCopy . Task , token ) ;
108- }
109-
110- private async ValueTask < IDuplexPipe > OpenStreamCoreAsync ( Task readinessTask , CancellationToken token )
90+ public async ValueTask < IDuplexPipe > OpenStreamAsync ( CancellationToken token = default )
11191 {
112- await readinessTask . WaitAsync ( token ) . ConfigureAwait ( false ) ;
113- return OpenStream ( ) ;
92+ for ( var stream = OpenStream ( out var addedStreamId ) ; ; token . ThrowIfCancellationRequested ( ) )
93+ {
94+ try
95+ {
96+ await EnsureConnectedAsync ( token ) . ConfigureAwait ( false ) ;
97+ return stream ;
98+ }
99+ catch ( Exception e )
100+ {
101+ input . TryRemoveStream ( addedStreamId , stream ) ;
102+ await stream . AbortAppSideAsync ( e ) . ConfigureAwait ( false ) ;
103+ }
104+ }
114105 }
115106
116- private MultiplexedStream OpenStream ( )
107+ private MultiplexedStream OpenStream ( out uint id )
117108 {
118109 var stream = new MultiplexedStream ( options , writeSignal ) ;
119- uint id ;
120110 do
121111 {
122112 id = Interlocked . Increment ( ref streamId ) ;
123113 } while ( ! input . TryAddStream ( id , stream ) ) ;
124-
114+
125115 return stream ;
126116 }
127117
0 commit comments