Пример #1
0
        private void WorkerLoop(object messageHandler)
        {
            MessageHandler  handler = (MessageHandler)messageHandler;
            bool            firstConnectionAttempt = true;
            TcpClient       client                   = null;
            FrameReader     reader                   = null;
            IBackoffLimiter backoffLimiter           = null;
            IDisposable     cancellationRegistration = Disposable.Empty;

            while (true)
            {
                try
                {
                    if (_connectionClosedSource.IsCancellationRequested)
                    {
                        return;
                    }

                    if (!Connected)
                    {
                        lock (_connectionSwapLock)
                        {
                            if (firstConnectionAttempt)
                            {
                                firstConnectionAttempt = false;
                            }
                            else
                            {
                                if (backoffLimiter == null)
                                {
                                    backoffLimiter = _backoffStrategy.Create();
                                }

                                TimeSpan delay;
                                if (backoffLimiter.ShouldReconnect(out delay))
                                {
                                    OnInternalMessage("Delaying {0} ms before reconnecting", (int)delay.TotalMilliseconds);
                                    Thread.Sleep(delay);
                                }
                                else
                                {
                                    // We give up
                                    OnInternalMessage("Abandoning connection");
                                    Dispose();
                                    return;
                                }
                            }

                            lock (_connectionSwapInProgressLock)
                            {
                                CancellationToken cancellationToken;
                                lock (_disposeLock)
                                {
                                    if (_disposed)
                                    {
                                        return;
                                    }

                                    if (client != null)
                                    {
                                        cancellationRegistration.Dispose();
                                        ((IDisposable)client).Dispose();
                                    }

                                    cancellationToken = _connectionClosedSource.Token;
                                }

                                OnInternalMessage("TCP client starting");

                                client = new TcpClient();
                                client.ConnectAsync(EndPoint.Host, EndPoint.Port).Wait(cancellationToken);
                                //client.Client.
                                //((_endPoint.Host, _endPoint.Port);
                                //cancellationRegistration = cancellationToken.Register(() => ((IDisposable)client).Dispose(), false);
                                Connected = true;
                                OnInternalMessage("TCP client started");

                                _stream = client.GetStream();
                                reader  = new FrameReader(_stream);

                                Handshake(_stream, reader);

                                _firstConnection.TrySetResult(true);

                                // Start a new backoff cycle next time we disconnect
                                backoffLimiter = null;

                                _nextReconnectionTaskSource.SetResult(true);
                                _nextReconnectionTaskSource = new TaskCompletionSource <bool>();
                            }
                        }
                    }

                    Frame frame;
                    while ((frame = reader.ReadFrame()) != null)
                    {
                        if (frame.Type == FrameType.Result)
                        {
                            if (Heartbeat.SequenceEqual(frame.Data))
                            {
                                OnInternalMessage("Heartbeat");
                                SendCommandAsync(new Nop())
                                .ContinueWith(t => Dispose(), TaskContinuationOptions.OnlyOnFaulted);
                            }
                            else
                            {
                                OnInternalMessage("Received result. Length = {0}", frame.MessageSize);
                            }
                        }
                        else if (frame.Type == FrameType.Message)
                        {
                            OnInternalMessage("Received message. Length = {0}", frame.MessageSize);
                            var message = new Message(frame, this);
                            Task.Run(() =>
                            {
                                try
                                {
                                    handler(message);
                                }
                                catch (Exception)
                                {
                                    // ignored
                                }
                            }
                                     );
                        }
                        else if (frame.Type == FrameType.Error)
                        {
                            string errorString;
                            try
                            {
                                errorString = Encoding.ASCII.GetString(frame.Data);
                            }
                            catch
                            {
                                errorString = BitConverter.ToString(frame.Data);
                            }
                            OnInternalMessage("Received error. Message = {0}", errorString);
                        }
                        else
                        {
                            OnInternalMessage("Unknown message type: {0}", frame.Type);
                            throw new InvalidOperationException("Unknown message type " + frame.Type);
                        }
                    }
                }
                catch (ObjectDisposedException ex)
                {
                    OnInternalMessage("Exiting worker loop due to disposal. Message = {0}", ex.Message);
                    Connected = false;
                    return;
                }
                catch (IOException ex)
                {
                    if (!_disposed)
                    {
                        OnInternalMessage("EXCEPTION: {0}", ex.Message);
                    }
                    Connected = false;
                }
                catch (SocketException ex)
                {
                    if (!_disposed)
                    {
                        OnInternalMessage("EXCEPTION: {0}", ex.Message);
                    }
                    Connected = false;
                }
            }
        }