/// <summary> /// Logs the specified message header and body. /// </summary> /// <typeparam name="T">The type of the message.</typeparam> /// <param name="header">The message header.</param> /// <param name="message">The message body.</param> protected void Received <T>(IMessageHeader header, T message) { if (Session?.Output == null) { return; } Session.Log("[{0}] Message received at {1}", Session.SessionId, DateTime.Now.ToString(TimestampFormat)); Session.Log(EtpExtensions.Serialize(header)); Session.Log(EtpExtensions.Serialize(message, true)); }
/// <summary> /// Handles the message. /// </summary> /// <param name="header">The header.</param> /// <param name="decoder">The decoder.</param> /// <param name="body">The body.</param> protected void HandleMessage(IMessageHeader header, Decoder decoder, string body) { try { IProtocolHandler handler; _handlersLock.TryEnterReadLock(-1); HandlersByProtocol.TryGetValue(header.Protocol, out handler); if (handler == null) { HandlersByProtocol.TryGetValue((int)v11.Protocols.Core, out handler); if (handler == null) // Socket has been closed { Logger.Trace($"Ignoring message on closed session: {EtpExtensions.Serialize(header)}"); return; } var msg = $"Protocol handler not registered for protocol { header.Protocol }."; handler.ProtocolException((int)EtpErrorCodes.UnsupportedProtocol, msg, header.MessageId); return; } var message = Adapter.DecodeMessage(header.Protocol, header.MessageType, decoder, body); if (message == null) { handler.InvalidMessage(header); return; } Received(header, message); try { // Handle global Acknowledge request if (header.IsAcknowledgeRequested()) { handler.Acknowledge(header.MessageId); } handler.HandleMessage(header, message); } catch (Exception ex) { Logger.Debug(ex); handler.ProtocolException((int)EtpErrorCodes.InvalidState, ex.Message, header.MessageId); } } finally { _handlersLock.ExitReadLock(); } }
/// <summary> /// Asynchronously sends the message. /// </summary> /// <typeparam name="T"></typeparam> /// <param name="header">The header.</param> /// <param name="body">The body.</param> /// <param name="onBeforeSend">Action called just before sending the message with the actual header having the definitive message ID.</param> /// <returns>The message identifier.</returns> public async Task <long> SendMessageAsync <T>(IMessageHeader header, T body, Action <IMessageHeader> onBeforeSend = null) where T : ISpecificRecord { // Lock to ensure only one thread at a time attempts to send data and to ensure that messages are sent with sequential IDs try { try { await _sendLock.WaitAsync().ConfigureAwait(CaptureAsyncContext); if (!IsOpen) { Log("Warning: Sending on a session that is not open."); Logger.Debug("Sending on a session that is not open."); return(-1); } header.MessageId = NewMessageId(); // Call the pre-send action in case any deterministic handling is needed with the actual message ID. // Must be invoked before sending to ensure the response is not asynchronously processed before this method returns. onBeforeSend?.Invoke(header); // Log message just before it gets sent if needed. Sending(header, body); if (IsJsonEncoding) { var message = EtpExtensions.Serialize(new object[] { header, body }); await SendAsync(message).ConfigureAwait(CaptureAsyncContext); } else { var data = body.Encode(header, SupportedCompression); await SendAsync(data, 0, data.Length).ConfigureAwait(CaptureAsyncContext); } } finally { _sendLock.Release(); } } catch (Exception ex) { // Handler already locked by the calling code... return(Handler(header.Protocol) .ProtocolException((int)EtpErrorCodes.InvalidState, ex.Message, header.MessageId)); } return(header.MessageId); }
/// <summary> /// Logs the specified message header and body. /// </summary> /// <param name="header">The message header.</param> /// <param name="message">The message body.</param> protected void Received(IMessageHeader header, ISpecificRecord message) { var now = DateTime.Now; if (Output != null) { Log("[{0}] Message received at {1}", SessionId, now.ToString(TimestampFormat)); Log(EtpExtensions.Serialize(header)); Log(EtpExtensions.Serialize(message, true)); } if (Logger.IsVerboseEnabled()) { Logger.VerboseFormat("[{0}] Message received at {1}: {2}{3}{4}", SessionId, now.ToString(TimestampFormat), EtpExtensions.Serialize(header), Environment.NewLine, EtpExtensions.Serialize(message, true)); } }
/// <summary> /// Logs the specified header and message body. /// </summary> /// <typeparam name="T">The type of message.</typeparam> /// <param name="header">The header.</param> /// <param name="body">The message body.</param> protected void Sending <T>(IMessageHeader header, T body) { var now = DateTime.Now; if (Output != null) { Log("[{0}] Sending message at {1}", SessionId, now.ToString(TimestampFormat)); Log(EtpExtensions.Serialize(header)); Log(EtpExtensions.Serialize(body, true)); } if (Logger.IsVerboseEnabled()) { Logger.VerboseFormat("[{0}] Sending message at {1}: {2}{3}{4}", SessionId, now.ToString(TimestampFormat), EtpExtensions.Serialize(header), Environment.NewLine, EtpExtensions.Serialize(body, true)); } }
/// <summary> /// Decodes the specified data. /// </summary> /// <param name="data">The data.</param> protected void Decode(byte[] data) { using (var inputStream = new MemoryStream(data)) { // create avro binary decoder to read from memory stream var decoder = new BinaryDecoder(inputStream); // deserialize the header var header = Adapter.DecodeMessageHeader(decoder, null); // log message metadata if (Logger.IsVerboseEnabled()) { Logger.VerboseFormat("[{0}] Binary message received: {1}", SessionId, EtpExtensions.Serialize(header)); } Stream gzip = null; try { // decompress message body if compression has been negotiated if (header.CanCompressMessageBody(true)) { if (EtpExtensions.GzipEncoding.Equals(SupportedCompression, StringComparison.InvariantCultureIgnoreCase)) { gzip = new GZipStream(inputStream, CompressionMode.Decompress, true); decoder = new BinaryDecoder(gzip); } } // call processing action HandleMessage(header, decoder, null); } finally { gzip?.Dispose(); } } }