internal void HandleStreamReceived(object sender, StreamReceivedFromServerEventArgs args) { WrappedEventHandler(() => StreamReceived?.Invoke(sender, args), "StreamReceived", sender); }
internal void HandleStreamReceived(object sender, StreamReceivedFromServerEventArgs args) { StreamReceived?.Invoke(sender, args); }
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); }
internal void HandleStreamReceived(object sender, StreamReceivedFromServerEventArgs args) { CatchAndReport(() => StreamReceived?.Invoke(sender, args), "StreamReceived", sender); }
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(); }