예제 #1
0
 internal void HandleStreamReceived(object sender, StreamReceivedFromServerEventArgs args)
 {
     WrappedEventHandler(() => StreamReceived?.Invoke(sender, args), "StreamReceived", sender);
 }
예제 #2
0
 internal void HandleStreamReceived(object sender, StreamReceivedFromServerEventArgs args)
 {
     StreamReceived?.Invoke(sender, args);
 }
예제 #3
0
        private async Task DataReceiver()
        {
            while (true)
            {
                bool readLocked = false;

                try
                {
                    #region Check-for-Connection

                    if (_Client == null || !_Client.Connected)
                    {
                        _Settings.Logger?.Invoke(_Header + "disconnect detected");
                        break;
                    }

                    #endregion

                    #region Read-Message

                    while (true)
                    {
                        readLocked = await _ReadLock.WaitAsync(10, _Token).ConfigureAwait(false);

                        if (readLocked)
                        {
                            break;
                        }
                        await Task.Delay(10, _Token).ConfigureAwait(false);
                    }

                    WatsonMessage msg          = new WatsonMessage(_DataStream, (_Settings.DebugMessages ? _Settings.Logger : null));
                    bool          buildSuccess = await msg.BuildFromStream(_Token).ConfigureAwait(false);

                    if (!buildSuccess)
                    {
                        _Settings.Logger?.Invoke(_Header + "disconnect detected");
                        break;
                    }

                    if (msg == null)
                    {
                        await Task.Delay(30, _Token).ConfigureAwait(false);

                        continue;
                    }

                    #endregion

                    #region Process-by-Status

                    if (msg.Status == MessageStatus.Removed)
                    {
                        _Settings.Logger?.Invoke(_Header + "disconnect due to server-side removal");
                        break;
                    }
                    else if (msg.Status == MessageStatus.Disconnecting)
                    {
                        _Settings.Logger?.Invoke(_Header + "disconnect due to server shutdown");
                        break;
                    }
                    else if (msg.Status == MessageStatus.AuthSuccess)
                    {
                        _Settings.Logger?.Invoke(_Header + "authentication successful");
                        Task unawaited = Task.Run(() => _Events.HandleAuthenticationSucceeded(this, EventArgs.Empty), _Token);
                        continue;
                    }
                    else if (msg.Status == MessageStatus.AuthFailure)
                    {
                        _Settings.Logger?.Invoke(_Header + "authentication failed");
                        Task unawaited = Task.Run(() => _Events.HandleAuthenticationFailure(this, EventArgs.Empty), _Token);
                        continue;
                    }
                    else if (msg.Status == MessageStatus.AuthRequired)
                    {
                        _Settings.Logger?.Invoke(_Header + "authentication required by server; please authenticate using pre-shared key");
                        string psk = _Callbacks.HandleAuthenticationRequested();
                        if (!String.IsNullOrEmpty(psk))
                        {
                            Authenticate(psk);
                        }
                        continue;
                    }

                    #endregion

                    #region Process-Message

                    if (msg.SyncRequest != null && msg.SyncRequest.Value)
                    {
                        DateTime expiration = WatsonCommon.GetExpirationTimestamp(msg);
                        byte[]   msgData    = await WatsonCommon.ReadMessageDataAsync(msg, _Settings.StreamBufferSize).ConfigureAwait(false);

                        if (DateTime.Now < expiration)
                        {
                            SyncRequest syncReq = new SyncRequest(
                                _ServerIp + ":" + _ServerPort,
                                msg.ConversationGuid,
                                msg.Expiration.Value,
                                msg.Metadata,
                                msgData);

                            SyncResponse syncResp = _Callbacks.HandleSyncRequestReceived(syncReq);
                            if (syncResp != null)
                            {
                                WatsonCommon.BytesToStream(syncResp.Data, out long contentLength, out Stream stream);
                                WatsonMessage respMsg = new WatsonMessage(
                                    syncResp.Metadata,
                                    contentLength,
                                    stream,
                                    false,
                                    true,
                                    msg.Expiration.Value,
                                    msg.ConversationGuid,
                                    (_Settings.DebugMessages ? _Settings.Logger : null));
                                SendInternal(respMsg, contentLength, stream);
                            }
                        }
                        else
                        {
                            _Settings.Logger?.Invoke(_Header + "expired synchronous request received and discarded");
                        }
                    }
                    else if (msg.SyncResponse != null && msg.SyncResponse.Value)
                    {
                        // No need to amend message expiration; it is copied from the request, which was set by this node
                        // DateTime expiration = WatsonCommon.GetExpirationTimestamp(msg);
                        byte[] msgData = await WatsonCommon.ReadMessageDataAsync(msg, _Settings.StreamBufferSize).ConfigureAwait(false);

                        if (DateTime.Now < msg.Expiration.Value)
                        {
                            lock (_SyncResponseLock)
                            {
                                _SyncResponses.Add(msg.ConversationGuid, new SyncResponse(msg.Expiration.Value, msg.Metadata, msgData));
                            }
                        }
                        else
                        {
                            _Settings.Logger?.Invoke(_Header + "expired synchronous response received and discarded");
                        }
                    }
                    else
                    {
                        byte[] msgData = null;

                        if (_Events.IsUsingMessages)
                        {
                            msgData = await WatsonCommon.ReadMessageDataAsync(msg, _Settings.StreamBufferSize).ConfigureAwait(false);

                            MessageReceivedFromServerEventArgs args = new MessageReceivedFromServerEventArgs(msg.Metadata, msgData);
                            await Task.Run(() => _Events.HandleMessageReceived(this, args));
                        }
                        else if (_Events.IsUsingStreams)
                        {
                            StreamReceivedFromServerEventArgs sr = null;
                            WatsonStream ws = null;

                            if (msg.ContentLength >= _Settings.MaxProxiedStreamSize)
                            {
                                ws = new WatsonStream(msg.ContentLength, msg.DataStream);
                                sr = new StreamReceivedFromServerEventArgs(msg.Metadata, msg.ContentLength, ws);
                                // sr = new StreamReceivedFromServerEventArgs(msg.Metadata, msg.ContentLength, msg.DataStream);
                                // must run synchronously, data exists in the underlying stream
                                _Events.HandleStreamReceived(this, sr);
                            }
                            else
                            {
                                MemoryStream ms = WatsonCommon.DataStreamToMemoryStream(msg.ContentLength, msg.DataStream, _Settings.StreamBufferSize);
                                ws = new WatsonStream(msg.ContentLength, ms);
                                sr = new StreamReceivedFromServerEventArgs(msg.Metadata, msg.ContentLength, ws);
                                // sr = new StreamReceivedFromServerEventArgs(msg.Metadata, msg.ContentLength, ms);
                                // data has been read, can continue to next message
                                Task unawaited = Task.Run(() => _Events.HandleStreamReceived(this, sr), _Token);
                            }
                        }
                        else
                        {
                            _Settings.Logger?.Invoke(_Header + "event handler not set for either MessageReceived or StreamReceived");
                            break;
                        }
                    }

                    #endregion

                    _Statistics.IncrementReceivedMessages();
                    _Statistics.AddReceivedBytes(msg.ContentLength);
                }
                catch (ObjectDisposedException)
                {
                    break;
                }
                catch (TaskCanceledException)
                {
                    break;
                }
                catch (OperationCanceledException)
                {
                    break;
                }
                catch (Exception e)
                {
                    _Settings.Logger?.Invoke(
                        _Header + "data receiver exception for " + _ServerIp + ":" + _ServerPort + ":" +
                        Environment.NewLine +
                        SerializationHelper.SerializeJson(e, true) +
                        Environment.NewLine);

                    _Events.HandleExceptionEncountered(this, new ExceptionEventArgs(e));
                    break;
                }
                finally
                {
                    if (readLocked && _ReadLock != null)
                    {
                        _ReadLock.Release();
                    }
                }
            }

            Connected = false;

            _Settings.Logger?.Invoke(_Header + "data receiver terminated for " + _ServerIp + ":" + _ServerPort);
            _Events.HandleServerDisconnected(this, EventArgs.Empty);
        }
예제 #4
0
 internal void HandleStreamReceived(object sender, StreamReceivedFromServerEventArgs args)
 {
     CatchAndReport(() => StreamReceived?.Invoke(sender, args), "StreamReceived", sender);
 }
예제 #5
0
        private async Task DataReceiver()
        {
            while (true)
            {
                bool readLocked = false;

                try
                {
                    _Token.ThrowIfCancellationRequested();

                    if (_Client == null ||
                        !_Client.Connected ||
                        _Token.IsCancellationRequested)
                    {
                        Logger?.Invoke("[WatsonTcpClient] Disconnect detected");
                        break;
                    }

                    WatsonMessage msg = null;
                    readLocked = await _ReadLock.WaitAsync(1);

                    bool buildSuccess = false;

                    if (_SslStream != null)
                    {
                        msg = new WatsonMessage(_SslStream, Debug);
                    }
                    else
                    {
                        msg = new WatsonMessage(_TcpStream, Debug);
                    }

                    if (_MessageReceived != null &&
                        _MessageReceived.GetInvocationList().Length > 0)
                    {
                        buildSuccess = await msg.Build();
                    }
                    else if (_StreamReceived != null &&
                             _StreamReceived.GetInvocationList().Length > 0)
                    {
                        buildSuccess = await msg.BuildStream();
                    }
                    else
                    {
                        break;
                    }

                    if (!buildSuccess)
                    {
                        Logger?.Invoke("[WatsonTcpClient] Message build failed due to disconnect");
                        break;
                    }

                    if (msg == null)
                    {
                        await Task.Delay(30);

                        continue;
                    }

                    if (msg.Status == MessageStatus.Removed)
                    {
                        Logger?.Invoke("[WatsonTcpClient] Disconnect due to server-side removal");
                        break;
                    }
                    else if (msg.Status == MessageStatus.Disconnecting)
                    {
                        Logger?.Invoke("[WatsonTcpClient] Disconnect due to server shutdown");
                        break;
                    }
                    else if (msg.Status == MessageStatus.AuthSuccess)
                    {
                        Logger?.Invoke("[WatsonTcpClient] Authentication successful");
                        AuthenticationSucceeded?.Invoke(this, EventArgs.Empty);
                        continue;
                    }
                    else if (msg.Status == MessageStatus.AuthFailure)
                    {
                        Logger?.Invoke("[WatsonTcpClient] Authentication failed");
                        AuthenticationFailure?.Invoke(this, EventArgs.Empty);
                        continue;
                    }

                    if (msg.Status == MessageStatus.AuthRequired)
                    {
                        Logger?.Invoke("[WatsonTcpClient] Authentication required by server; please authenticate using pre-shared key");
                        if (AuthenticationRequested != null)
                        {
                            string psk = AuthenticationRequested();
                            if (!String.IsNullOrEmpty(psk))
                            {
                                Authenticate(psk);
                            }
                        }
                        continue;
                    }

                    if (_MessageReceived != null &&
                        _MessageReceived.GetInvocationList().Length > 0)
                    {
                        MessageReceivedFromServerEventArgs args = new MessageReceivedFromServerEventArgs(msg.Metadata, msg.Data);
                        _MessageReceived?.Invoke(this, args);
                    }
                    else if (_StreamReceived != null &&
                             _StreamReceived.GetInvocationList().Length > 0)
                    {
                        StreamReceivedFromServerEventArgs args = new StreamReceivedFromServerEventArgs(msg.Metadata, msg.ContentLength, msg.DataStream);
                        _StreamReceived?.Invoke(this, args);
                    }
                    else
                    {
                        break;
                    }

                    _Stats.ReceivedMessages = _Stats.ReceivedMessages + 1;
                    _Stats.ReceivedBytes   += msg.ContentLength;
                }
                catch (Exception e)
                {
                    Logger?.Invoke(
                        "[WatsonTcpClient] Data receiver exception: " +
                        Environment.NewLine +
                        e.ToString() +
                        Environment.NewLine);
                    break;
                }
                finally
                {
                    if (readLocked)
                    {
                        _ReadLock.Release();
                    }
                }
            }

            Logger?.Invoke("[WatsonTcpClient] Data receiver terminated");
            Connected = false;
            ServerDisconnected?.Invoke(this, EventArgs.Empty);
            Dispose();
        }