internal SyncResponse HandleSyncRequestReceived(SyncRequest req) { SyncResponse ret = null; if (SyncRequestReceived != null) { ret = SyncRequestReceived(req); } return(ret); }
internal SyncResponse HandleSyncRequestReceived(SyncRequest req) { SyncResponse ret = null; if (SyncRequestReceived != null) { try { ret = SyncRequestReceived(req); } catch (Exception) { } } return(ret); }
private SyncResponse GetSyncResponse(string guid, DateTime expirationUtc) { SyncResponse ret = null; try { while (true) { lock (_SyncResponseLock) { if (_SyncResponses.ContainsKey(guid)) { ret = _SyncResponses[guid]; _SyncResponses.Remove(guid); break; } } if (DateTime.Now >= expirationUtc) { break; } Task.Delay(50).Wait(_Token); } if (ret != null) { return(ret); } else { throw new TimeoutException("A response to a synchronous request was not received within the timeout window."); } } catch (TaskCanceledException) { return(null); } catch (OperationCanceledException) { return(null); } }
private async Task DataReceiver() { DisconnectReason reason = DisconnectReason.Normal; 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"); reason = DisconnectReason.Removed; break; } else if (msg.Status == MessageStatus.Shutdown) { _Settings.Logger?.Invoke(_Header + "disconnect due to server shutdown"); reason = DisconnectReason.Shutdown; break; } else if (msg.Status == MessageStatus.Timeout) { _Settings.Logger?.Invoke(_Header + "disconnect due to timeout"); reason = DisconnectReason.Timeout; 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); MessageReceivedEventArgs args = new MessageReceivedEventArgs((_ServerIp + ":" + _ServerPort), msg.Metadata, msgData); await Task.Run(() => _Events.HandleMessageReceived(this, args)); } else if (_Events.IsUsingStreams) { StreamReceivedEventArgs sr = null; WatsonStream ws = null; if (msg.ContentLength >= _Settings.MaxProxiedStreamSize) { ws = new WatsonStream(msg.ContentLength, msg.DataStream); sr = new StreamReceivedEventArgs((_ServerIp + ":" + _ServerPort), 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 StreamReceivedEventArgs((_ServerIp + ":" + _ServerPort), 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, new DisconnectionEventArgs((_ServerIp + ":" + _ServerPort), reason)); }
private SyncResponse SendAndWaitInternal(WatsonMessage msg, int timeoutMs, long contentLength, Stream stream) { if (msg == null) { throw new ArgumentNullException(nameof(msg)); } if (!Connected) { throw new InvalidOperationException("Client is not connected to the server."); } if (contentLength > 0 && (stream == null || !stream.CanRead)) { throw new ArgumentException("Cannot read from supplied stream."); } bool disconnectDetected = false; if (_Client == null || !_Client.Connected) { disconnectDetected = true; throw new InvalidOperationException("Client is not connected to the server."); } _WriteLock.Wait(); try { SendHeaders(msg); SendDataStream(contentLength, stream); _Statistics.IncrementSentMessages(); _Statistics.AddSentBytes(contentLength); } catch (TaskCanceledException) { return(null); } catch (OperationCanceledException) { return(null); } catch (Exception e) { _Settings.Logger?.Invoke( _Header + "failed to write message to " + _ServerIp + ":" + _ServerPort + ":" + Environment.NewLine + e.ToString() + Environment.NewLine); disconnectDetected = true; throw; } finally { _WriteLock.Release(); if (disconnectDetected) { Connected = false; Dispose(); } } SyncResponse ret = GetSyncResponse(msg.ConversationGuid, msg.Expiration.Value); return(ret); }