コード例 #1
0
        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;
                }
            }
        }
コード例 #2
0
        // 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);
        }
コード例 #3
0
 public ClientConnectionLifetimeManager(Task connectiongTask, CancellationTokenSource source, string connectionId, DuplexStreamingResult <Nil, Nil> method)
 {
     this.connectiongTask = connectiongTask;
     this.source          = source;
     this.connectionId    = connectionId;
     this.method          = method;
 }
コード例 #4
0
        // 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();
        }
コード例 #5
0
        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++);
                }
            }
        }
コード例 #6
0
        // 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();
        }
コード例 #7
0
        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++);
                }
            }
        }
コード例 #8
0
        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++);
                }
            }
        }