IEnumerator PingLoop(DuplexStreamingResult <Nil, Nil> streaming, CancellationToken token) { var waiter = new UnityEngine.WaitForSeconds(pingSecond); while (true) { if (token.IsCancellationRequested) { yield break; } yield return(waiter); if (token.IsCancellationRequested) { yield break; } var r = streaming.RequestStream.WriteAsync(Nil.Default).ToYieldInstruction(false); yield return(r); if (r.HasError) { yield break; } } }
// call immediately after create. public async Task __ConnectAndSubscribeAsync(TReceiver receiver, CancellationToken cancellationToken) { var syncContext = SynchronizationContext.Current; // capture SynchronizationContext. var callResult = callInvoker.AsyncDuplexStreamingCall <byte[], byte[]>(DuplexStreamingAsyncMethod, host, option); var streamingResult = new DuplexStreamingResult <byte[], byte[]>( callResult, new MarshallingClientStreamWriter <byte[]>(callResult.RequestStream, serializerOptions), new MarshallingAsyncStreamReader <byte[]>(callResult.ResponseStream, serializerOptions), serializerOptions ); this.connection = streamingResult; this.receiver = receiver; // Establish StreamingHub connection between the client and the server. Metadata.Entry messageVersion = default; try { // The client can read the response headers before any StreamingHub's message. // MagicOnion.Server v4.0.x or before doesn't send any response headers. The client is incompatible with that versions. // NOTE: Grpc.Net: // If the channel can not be connected, ResponseHeadersAsync will throw an exception. // C-core: // If the channel can not be connected, ResponseHeadersAsync will **return** an empty metadata. var headers = await streamingResult.ResponseHeadersAsync.ConfigureAwait(false); messageVersion = headers.FirstOrDefault(x => x.Key == StreamingHubVersionHeaderKey); cancellationToken.ThrowIfCancellationRequested(); // Check message version of StreamingHub. if (messageVersion != null && messageVersion.Value != StreamingHubVersionHeaderValue) { throw new RpcException(new Status(StatusCode.Internal, $"The message version of StreamingHub mismatch between the client and the server. (ServerVersion={messageVersion?.Value}; Expected={StreamingHubVersionHeaderValue})")); } } catch (RpcException e) { throw new RpcException(e.Status, $"Failed to connect to StreamingHub '{DuplexStreamingAsyncMethod.ServiceName}'. ({e.Status})"); } var firstMoveNextTask = connection.RawStreamingCall.ResponseStream.MoveNext(CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, cts.Token).Token); if (firstMoveNextTask.IsFaulted || messageVersion == null) { // NOTE: Grpc.Net: // If an error is returned from `StreamingHub.Connect` method on a server-side, // ResponseStream.MoveNext synchronously returns a task that is `IsFaulted = true`. // `ConnectAsync` method should throw an exception here immediately. // C-core: // `firstMoveNextTask` is incomplete task (`IsFaulted = false`) whether ResponseHeadersAsync is failed or not. // If the channel is disconnected or the server returns an error (StatusCode != OK), awaiting the Task will throw an exception. await firstMoveNextTask.ConfigureAwait(false); // NOTE: C-core: If the execution reaches here, Connect method returns without any error (StatusCode = OK). but MessageVersion isn't provided from the server. throw new RpcException(new Status(StatusCode.Internal, $"The message version of StreamingHub is not provided from the server.")); } this.subscription = StartSubscribe(syncContext, firstMoveNextTask); }
public ClientConnectionLifetimeManager(Task connectiongTask, CancellationTokenSource source, string connectionId, DuplexStreamingResult <Nil, Nil> method) { this.connectiongTask = connectiongTask; this.source = source; this.connectionId = connectionId; this.method = method; }
// call immediately after create. public void __ConnectAndSubscribe(TReceiver receiver) { var callResult = callInvoker.AsyncDuplexStreamingCall <byte[], byte[]>(DuplexStreamingAsyncMethod, host, option); var streamingResult = new DuplexStreamingResult <byte[], byte[]>(callResult, resolver); this.connection = streamingResult; this.receiver = receiver; this.subscription = StartSubscribe(); }
async Task ConnectAlways() { while (true) { try { if (isDisposed) { return; } if (channel.State == ChannelState.Shutdown) { return; } await channel.ConnectAsync(); if (isDisposed) { return; } var connectionId = (useSameId) ? this.connectionId : connectionIdFactory(); var client = new HeartbeatClient(channel, connectionId); latestStreamingResult.Dispose(); latestStreamingResult = client.Connect(); // wait connect complete. await latestStreamingResult.ResponseStream.MoveNext(); this.connectionId = connectionId; currentRetryCount = 0; waitConnectComplete.TrySetResult(new object()); try { // now channelstate is ready and wait changed. await Task.WhenAny(channel.WaitForStateChangedAsync(ChannelState.Ready), latestStreamingResult.ResponseStream.MoveNext()).ConfigureAwait(false); } finally { waitConnectComplete = new TaskCompletionSource <object>(); foreach (var action in disconnectedActions) { action(); } } } catch (Exception ex) { GrpcEnvironment.Logger.Error(ex, "Reconnect Failed, Retrying:" + currentRetryCount++); } } }
// call immediately after create. public void __ConnectAndSubscribe(TReceiver receiver) { var callResult = callInvoker.AsyncDuplexStreamingCall <byte[], byte[]>(DuplexStreamingAsyncMethod, host, option); var streamingResult = new DuplexStreamingResult <byte[], byte[]>( callResult, new MarshallingClientStreamWriter <byte[]>(callResult.RequestStream, serializerOptions), new MarshallingAsyncStreamReader <byte[]>(callResult.ResponseStream, serializerOptions), serializerOptions ); this.connection = streamingResult; this.receiver = receiver; this.subscription = StartSubscribe(); }
IEnumerator ConnectAlways() { while (true) { if (isDisposed) { yield break; } if (channel.State == ChannelState.Shutdown) { yield break; } var conn = channel.ConnectAsync().ToYieldInstruction(false); yield return(conn); if (isDisposed) { yield break; } if (conn.HasError) { GrpcEnvironment.Logger.Error(conn.Error, "Reconnect Failed, Retrying:" + currentRetryCount++); continue; } var connectionId = (useSameId) ? this.connectionId : connectionIdFactory(); var client = new HeartbeatClient(channel, connectionId); latestStreamingResult.Dispose(); var heartBeatConnect = client.Connect().ToYieldInstruction(false); yield return(heartBeatConnect); if (heartBeatConnect.HasError) { GrpcEnvironment.Logger.Error(heartBeatConnect.Error, "Reconnect Failed, Retrying:" + currentRetryCount++); continue; } else { latestStreamingResult = heartBeatConnect.Result; } var connectCheck = heartBeatConnect.Result.ResponseStream.MoveNext().ToYieldInstruction(false); yield return(connectCheck); if (connectCheck.HasError) { GrpcEnvironment.Logger.Error(heartBeatConnect.Error, "Reconnect Failed, Retrying:" + currentRetryCount++); continue; } this.connectionId = connectionId; currentRetryCount = 0; waitConnectComplete.OnNext(Unit.Default); waitConnectComplete.OnCompleted(); var waitForDisconnect = Observable.Amb(channel.WaitForStateChangedAsync(ChannelState.Ready), heartBeatConnect.Result.ResponseStream.MoveNext()).ToYieldInstruction(false); yield return(waitForDisconnect); try { waitConnectComplete = new AsyncSubject <Unit>(); foreach (var action in disconnectedActions) { action(); } } catch (Exception ex) { GrpcEnvironment.Logger.Error(ex, "Reconnect Failed, Retrying:" + currentRetryCount++); } if (waitForDisconnect.HasError) { GrpcEnvironment.Logger.Error(waitForDisconnect.Error, "Reconnect Failed, Retrying:" + currentRetryCount++); } } }
async Task ConnectAlways() { while (true) { try { if (isDisposed) { return; } if (channel.State == ChannelState.Shutdown) { return; } await channel.ConnectAsync(); if (isDisposed) { return; } var connectionId = (useSameId) ? this.connectionId : connectionIdFactory(); var client = new HeartbeatClient(channel, connectionId); latestStreamingResult.Dispose(); latestStreamingResult = client.Connect(); // wait connect complete. await latestStreamingResult.ResponseStream.MoveNext(); this.connectionId = connectionId; currentRetryCount = 0; waitConnectComplete.TrySetResult(new object()); bool isFinished = false; try { var heartbeat = Task.Run(async() => { try { while (true) { if (isFinished) { return; } await Task.Delay(TimeSpan.FromSeconds(pingSecond)).ConfigureAwait(false); if (isFinished) { return; } await latestStreamingResult.RequestStream.WriteAsync(Nil.Default).ConfigureAwait(false); } } catch { } }); await Task.WhenAny(channel.WaitForStateChangedAsync(ChannelState.Ready), latestStreamingResult.ResponseStream.MoveNext(), heartbeat).ConfigureAwait(false); } finally { isFinished = true; waitConnectComplete = new TaskCompletionSource <object>(); foreach (var action in disconnectedActions) { action(); } } } catch (Exception ex) { GrpcEnvironment.Logger.Error(ex, "Reconnect Failed, Retrying:" + currentRetryCount++); } } }