@@ -150,7 +150,7 @@ internal async Task<TResponse> UnaryCall<TRequest, TResponse>(
150150 }
151151 }
152152
153- internal StreamIterator < TResponse > StreamCall < TRequest , TResponse > (
153+ internal ServerStream < TResponse > ServerStreamCall < TRequest , TResponse > (
154154 Method < TRequest , TResponse > method ,
155155 TRequest request ,
156156 GrpcRequestSettings settings )
@@ -160,22 +160,30 @@ internal StreamIterator<TResponse> StreamCall<TRequest, TResponse>(
160160 var ( endpoint , channel ) = GetChannel ( settings . NodeId ) ;
161161 var callInvoker = channel . CreateCallInvoker ( ) ;
162162
163- try
164- {
165- var call = callInvoker . AsyncServerStreamingCall (
166- method : method ,
167- host : null ,
168- options : GetCallOptions ( settings , true ) ,
169- request : request ) ;
163+ var call = callInvoker . AsyncServerStreamingCall (
164+ method : method ,
165+ host : null ,
166+ options : GetCallOptions ( settings , true ) ,
167+ request : request ) ;
170168
171- return new StreamIterator < TResponse > ( call , ( ) => { PessimizeEndpoint ( endpoint ) ; } ) ;
172- }
173- catch ( RpcException e )
174- {
175- PessimizeEndpoint ( endpoint ) ;
169+ return new ServerStream < TResponse > ( call , ( ) => { PessimizeEndpoint ( endpoint ) ; } ) ;
170+ }
176171
177- throw new TransportException ( e ) ;
178- }
172+ internal BidirectionalStream < TRequest , TResponse > BidirectionalStreamCall < TRequest , TResponse > (
173+ Method < TRequest , TResponse > method ,
174+ GrpcRequestSettings settings )
175+ where TRequest : class
176+ where TResponse : class
177+ {
178+ var ( endpoint , channel ) = GetChannel ( settings . NodeId ) ;
179+ var callInvoker = channel . CreateCallInvoker ( ) ;
180+
181+ var call = callInvoker . AsyncDuplexStreamingCall (
182+ method : method ,
183+ host : null ,
184+ options : GetCallOptions ( settings , true ) ) ;
185+
186+ return new BidirectionalStream < TRequest , TResponse > ( call , ( ) => { PessimizeEndpoint ( endpoint ) ; } ) ;
179187 }
180188
181189 private ( string , GrpcChannel ) GetChannel ( long nodeId )
@@ -319,12 +327,12 @@ private CallOptions GetCallOptions(GrpcRequestSettings settings, bool streaming)
319327 return options ;
320328 }
321329
322- internal sealed class StreamIterator < TResponse > : IAsyncEnumerator < TResponse > , IAsyncEnumerable < TResponse >
330+ internal sealed class ServerStream < TResponse > : IAsyncEnumerator < TResponse > , IAsyncEnumerable < TResponse >
323331 {
324332 private readonly AsyncServerStreamingCall < TResponse > _responseStream ;
325333 private readonly Action _rpcErrorAction ;
326334
327- internal StreamIterator ( AsyncServerStreamingCall < TResponse > responseStream , Action rpcErrorAction )
335+ internal ServerStream ( AsyncServerStreamingCall < TResponse > responseStream , Action rpcErrorAction )
328336 {
329337 _responseStream = responseStream ;
330338 _rpcErrorAction = rpcErrorAction ;
@@ -359,6 +367,62 @@ public async ValueTask<bool> MoveNextAsync()
359367 }
360368 }
361369
370+ internal sealed class BidirectionalStream < TRequest , TResponse > : IAsyncEnumerator < TResponse > ,
371+ IAsyncEnumerable < TResponse >
372+ {
373+ private readonly AsyncDuplexStreamingCall < TRequest , TResponse > _bidirectionalStream ;
374+ private readonly Action _rpcErrorAction ;
375+
376+ public BidirectionalStream ( AsyncDuplexStreamingCall < TRequest , TResponse > bidirectionalStream ,
377+ Action rpcErrorAction )
378+ {
379+ _bidirectionalStream = bidirectionalStream ;
380+ _rpcErrorAction = rpcErrorAction ;
381+ }
382+
383+ public async Task Write ( TRequest request )
384+ {
385+ try
386+ {
387+ await _bidirectionalStream . RequestStream . WriteAsync ( request ) ;
388+ }
389+ catch ( RpcException e )
390+ {
391+ _rpcErrorAction ( ) ;
392+
393+ throw new TransportException ( e ) ;
394+ }
395+ }
396+
397+ public ValueTask DisposeAsync ( )
398+ {
399+ _bidirectionalStream . Dispose ( ) ;
400+
401+ return default ;
402+ }
403+
404+ public async ValueTask < bool > MoveNextAsync ( )
405+ {
406+ try
407+ {
408+ return await _bidirectionalStream . ResponseStream . MoveNext ( CancellationToken . None ) ;
409+ }
410+ catch ( RpcException e )
411+ {
412+ _rpcErrorAction ( ) ;
413+
414+ throw new TransportException ( e ) ;
415+ }
416+ }
417+
418+ public TResponse Current => _bidirectionalStream . ResponseStream . Current ;
419+
420+ public IAsyncEnumerator < TResponse > GetAsyncEnumerator ( CancellationToken cancellationToken = new ( ) )
421+ {
422+ return this ;
423+ }
424+ }
425+
362426 public class InitializationFailureException : Exception
363427 {
364428 internal InitializationFailureException ( string message ) : base ( message )
0 commit comments