/// <summary> /// Initializes a new instance of the <see cref="SenderMessage"/> as a copy of /// the specified <see cref="IReceiverMessage"/>. /// </summary> /// <param name="receiverMessage">The <see cref="IReceiverMessage"/> to make a copy of.</param> /// <param name="validateHeaderValue"> /// A function that validates header values, returning either the value passed to it /// or an equivalent value. If a value is invalid, the function should attempt to /// convert it to another type that is valid. If a value cannot be converted, the /// function should throw an exception. /// </param> public SenderMessage(IReceiverMessage receiverMessage, Func <object, object>?validateHeaderValue = null) { if (receiverMessage is null) { throw new ArgumentNullException(nameof(receiverMessage)); } _headers = new HeaderDictionary(validateHeaderValue); if (receiverMessage.IsBinary()) { InitAsBinary(receiverMessage.BinaryPayload, receiverMessage.IsCompressed(), out _stringPayload, out _binaryPayload); } else { InitAsString(receiverMessage.StringPayload, receiverMessage.IsCompressed(), out _stringPayload, out _binaryPayload); } foreach (var header in receiverMessage.Headers) { if (header.Key != HeaderNames.MessageId) // Don't copy the message id { _headers[header.Key] = header.Value; } } }
private async Task OnMessageReceived(IReceiverMessage message) { if (message.Headers.TryGetValue("operation", out string operation)) { if (operation == "create") { await Database.CreateAsync(message.StringPayload); await message.AcknowledgeAsync(); } else if (operation == "update") { await Database.UpdateAsync(message.StringPayload); await message.AcknowledgeAsync(); } else if (operation == "delete") { await Database.DeleteAsync(message.StringPayload); await message.AcknowledgeAsync(); } else { // TODO: Send error log - invalid message await message.RejectAsync(); } } else { // TODO: Send error log - invalid message await message.RejectAsync(); } }
private async Task OnMessageReceivedAsync(IReceiverMessage message) { var newSettings = new Dictionary <string, string>(StringComparer.OrdinalIgnoreCase); try { JsonConvert.PopulateObject(message.StringPayload, newSettings); } catch { await message.RejectAsync().ConfigureAwait(false); return; } var changed = Data.Count != newSettings.Count; if (!changed) { foreach (var newSetting in newSettings) { if (Data.ContainsKey(newSetting.Key)) { if (Data[newSetting.Key] != newSetting.Value) { changed = true; break; } } else { changed = true; break; } } } if (changed) { IDictionary <string, string> previousData = null; if (message.Headers.TryGetValue("RevertAfterMilliseconds", out int milliseconds) && milliseconds > 0) { previousData = Data; } Data = newSettings; OnReload(); if (previousData != null) { await message.AcknowledgeAsync().ConfigureAwait(false); await RevertDataAfterDelay(previousData, milliseconds).ConfigureAwait(false); return; } } await message.AcknowledgeAsync().ConfigureAwait(false); }
public void Bind(IReceiverMessage fromReceiverMessage, CloudEvent toCloudEvent) { if (fromReceiverMessage.Headers.TryGetValue(KafkaKeyHeader, out string?kafkaKey)) { toCloudEvent.Attributes.Remove(KafkaKeyHeader); toCloudEvent.SetPartitionKey(kafkaKey); } }
/// <summary> /// Indicates that the message was successfully processed and should not /// be redelivered. /// </summary> /// <param name="receiverMessage">The message to acknowledge.</param> public static Task AcknowledgeAsync(this IReceiverMessage receiverMessage) { if (receiverMessage is null) { throw new ArgumentNullException(nameof(receiverMessage)); } return(receiverMessage.AcknowledgeAsync(CancellationToken.None)); }
/// <summary> /// Initializes a new instance of the <see cref="CloudEvent"/> class and sets its data, /// attributes, and headers according to the payload and headers of the <paramref name= /// "receiverMessage"/>. /// </summary> /// <param name="receiverMessage"> /// The <see cref="IReceiverMessage"/> with headers that map to cloud event attributes. /// </param> /// <param name="protocolBinding"> /// The <see cref="IProtocolBinding"/> used to map <see cref="IReceiverMessage"/> headers to /// CloudEvent attributes. If <see langword="null"/>, then <see cref="DefaultProtocolBinding"/> /// is used instead. /// </param> public CloudEvent(IReceiverMessage receiverMessage, IProtocolBinding protocolBinding = null) { if (receiverMessage is null) { throw new ArgumentNullException(nameof(receiverMessage)); } FromReceiverMessage(receiverMessage, protocolBinding); }
private async Task OnUserEventReceivedAsync(CorrelatedEvent userEvent, IReceiverMessage message) { Console.WriteLine($"Received user event: '{userEvent.StringData}' with correlation id: {userEvent.CorrelationId}"); var worker1Event = userEvent.Copy(); var worker2Event = userEvent.Copy(); var middle = userEvent.StringData.Length / 2; worker1Event.SetData(userEvent.StringData[..middle]);
/// <summary> /// Creates an instance of <typeparamref name="TCloudEvent"/> with properties mapped from /// the headers of <paramref name="receiverMessage"/>. /// <para> /// The <typeparamref name="TCloudEvent"/> type <em>must</em> define a public constructor /// with the exact parameters <c>(<see cref="IReceiverMessage"/>, <see cref= /// "IProtocolBinding"/>)</c>. A <see cref="MissingMemberException"/> is immediately /// thrown if the class does not define such a constructor. /// </para> /// </summary> /// <typeparam name="TCloudEvent">The type of <see cref="CloudEvent"/> to create.</typeparam> /// <param name="receiverMessage"> /// The <see cref="IReceiverMessage"/> to be mapped to the new <typeparamref name="TCloudEvent"/>. /// </param> /// <param name="protocolBinding"> /// The <see cref="IProtocolBinding"/> used to map <see cref="IReceiverMessage"/> headers to /// CloudEvent attributes. /// </param> /// <returns> /// A new <typeparamref name="TCloudEvent"/> with properties mapped from the headers of the <see cref="IReceiverMessage"/>. /// </returns> /// <exception cref="ArgumentNullException"> /// If <paramref name="receiverMessage"/> is <see langword="null"/>. /// </exception> /// <exception cref="MissingMemberException"> /// If the <typeparamref name="TCloudEvent"/> class does not define a public constructor /// with the exact parameters <c>(<see cref="IReceiverMessage"/>, <see cref= /// "IProtocolBinding"/>)</c>. /// </exception> public static TCloudEvent To <TCloudEvent>(this IReceiverMessage receiverMessage, IProtocolBinding protocolBinding = null) where TCloudEvent : CloudEvent { if (receiverMessage is null) { throw new ArgumentNullException(nameof(receiverMessage)); } var messageConstructor = _messageConstructors.GetOrAdd(typeof(TCloudEvent), MessageConstructor.Create) ?? throw MissingReceiverConstructor(typeof(TCloudEvent)); return((TCloudEvent)messageConstructor.Invoke(receiverMessage, protocolBinding)); }
/// <summary> /// Gets the Key of the Kafka message, as stored in the <see cref="KafkaKeyHeader"/> header /// of the <see cref="IReceiverMessage"/>. /// </summary> /// <param name="receiverMessage">The <see cref="IReceiverMessage"/>.</param> /// <returns>The Key of the Kafka message.</returns> public static string GetKafkaKey(this IReceiverMessage receiverMessage) { if (receiverMessage is null) { throw new ArgumentNullException(nameof(receiverMessage)); } if (receiverMessage.Headers.TryGetValue(KafkaKeyHeader, out string kafkaKey)) { return(kafkaKey); } return(null); }
public Task OnMessageReceivedAsync(IReceiver receiver, IReceiverMessage message) { var source = new TaskCompletionSource <int>(); try { _onMessageReceived(receiver, message); source.SetResult(0); } catch (Exception ex) { source.SetException(ex); } return(source.Task); }
public Task OnMessageReceivedAsync(IReceiver receiver, IReceiverMessage message) { var source = new TaskCompletionSource <int>(); try { _onMessageReceived(receiver, message); source.SetResult(0); } #pragma warning disable CA1031 // Do not catch general exception types catch (Exception ex) #pragma warning restore CA1031 // Do not catch general exception types { source.SetException(ex); } return(source.Task); }
private async Task OnMessageReceivedAsync(IReceiverMessage message) { var newSettings = new Dictionary <string, string>(StringComparer.OrdinalIgnoreCase); try { JsonConvert.PopulateObject(message.StringPayload, newSettings); } catch { await message.RejectAsync().ConfigureAwait(false); return; } if (IsChanged(newSettings, message.Headers)) { Data = newSettings; OnReload(); } await message.AcknowledgeAsync().ConfigureAwait(false); }
/// <summary> /// Indicates that the message was successfully processed and should not /// be redelivered. /// </summary> /// <param name="receiverMessage">The message to acknowledge.</param> public static Task AcknowledgeAsync(this IReceiverMessage receiverMessage) => receiverMessage.AcknowledgeAsync(CancellationToken.None);
public void Bind(IReceiverMessage fromReceiverMessage, CloudEvent toCloudEvent) { }
/// <summary> /// Gets a value indicating whether the message's payload was sent compressed, /// as indicated in the message's headers. /// </summary> /// <param name="receiverMessage">The source <see cref="IReceiverMessage"/> object.</param> /// <returns>Whether the message's payload was sent compressed.</returns> public static bool IsCompressed(this IReceiverMessage receiverMessage) => receiverMessage.GetHeaders() .TryGetValue(HeaderNames.IsCompressedPayload, out bool isCompressed) && isCompressed;
/// <summary> /// Initializes a new instance of the <see cref="MessageReceivedEventArgs"/> class. /// </summary> /// <param name="message">The received message.</param> public MessageReceivedEventArgs(IReceiverMessage message) { _message = message; }
public static void Rollback(this IReceiverMessage receiverMessage) => Sync(() => receiverMessage.RollbackAsync());
/// <summary> /// Handles a received message. /// <para> /// When invoked, this method invokes the <see cref="IMessageHandler.OnMessageReceivedAsync"/> /// method of the <see cref="MessageHandler"/> property. It passes the /// <see cref="ForwardingReceiver"/> property as the <c>receiver</c> argument and /// a new <see cref="ForwardingReceiverMessage"/> decorator as the <c>message</c> /// argument. /// </para> /// </summary> /// <param name="receiver">The instance of <see cref="IReceiver"/> that received the message.</param> /// <param name="message">The message that was received.</param> public Task OnMessageReceivedAsync(IReceiver receiver, IReceiverMessage message) => MessageHandler.OnMessageReceivedAsync(ForwardingReceiver, new ForwardingReceiverMessage(ForwardingReceiver, message));
/// <summary> /// Handles a received message. /// <para> /// When invoked, this method invokes the <see cref="IMessageHandler.OnMessageReceivedAsync"/> /// method of the <see cref="MessageHandler"/> property. It passes the /// <see cref="ForwardingReceiver"/> property as the <c>receiver</c> argument and /// a new <see cref="ForwardingReceiverMessage"/> decorator as the <c>message</c> /// argument. /// </para> /// </summary> /// <param name="receiver">The instance of <see cref="IReceiver"/> that received the message.</param> /// <param name="message">The message that was received.</param> public Task OnMessageReceivedAsync(IReceiver receiver, IReceiverMessage message) => MessageHandler?.OnMessageReceivedAsync(ForwardingReceiver, new ForwardingReceiverMessage(ForwardingReceiver, message)) ?? Task.CompletedTask;
/// <summary> /// Indicates that the message could not be successfully processed and should /// not be redelivered. /// </summary> /// <param name="receiverMessage">The message to reject.</param> public static Task RejectAsync(this IReceiverMessage receiverMessage) => receiverMessage.RejectAsync(CancellationToken.None);
/// <summary> /// Initializes a new instance of the <see cref="PartitionedEvent"/> class and sets its /// data, attributes, and headers according to the payload and headers of the <paramref /// name="receiverMessage"/>. /// </summary> /// <param name="receiverMessage"> /// The <see cref="IReceiverMessage"/> with headers that map to cloud event attributes. /// </param> /// <param name="protocolBinding"> /// The <see cref="IProtocolBinding"/> used to map <see cref="IReceiverMessage"/> headers /// to CloudEvent attributes. If <see langword="null"/>, then <see cref= /// "CloudEvent.DefaultProtocolBinding"/> is used instead. /// </param> public PartitionedEvent(IReceiverMessage receiverMessage, IProtocolBinding protocolBinding = null) : base(receiverMessage, protocolBinding) { }
internal ForwardingReceiverMessage(ForwardingReceiver forwardingReceiver, IReceiverMessage message) { ForwardingReceiver = forwardingReceiver; Message = message; }
public static void Reject(this IReceiverMessage receiverMessage) => Sync(() => receiverMessage.RejectAsync());
/// <summary> /// Gets the binary value of the message. If the implemenation "speaks" string, /// <see cref="Encoding.UTF8"/> is used to convert the string message to a byte array. /// </summary> /// <param name="source">The message from which to obtain a binary value.</param> /// <returns>The binary value of the message.</returns> public static byte[] GetBinaryValue(this IReceiverMessage source) { return(source.GetBinaryValue(Encoding.UTF8)); }
public static void Acknowledge(this IReceiverMessage receiverMessage) => Sync(() => receiverMessage.AcknowledgeAsync());
/// <summary> /// Gets a header value by key. If the implementation "speaks" binary, /// <see cref="Encoding.UTF8"/> is used to convert the binary header to a string. /// </summary> /// <param name="source">The message from which to obtain a binary value.</param> /// <param name="key">The key of the header to retrieve.</param> /// <returns>The string value of the header.</returns> public static string GetHeaderValue(this IReceiverMessage source, string key) { return(source.GetHeaderValue(key, Encoding.UTF8)); }
/// <summary> /// Initializes a new instance of the <see cref="CorrelatedEvent"/> class and sets its /// data, attributes, and headers according to the payload and headers of the <paramref /// name="receiverMessage"/>. /// </summary> /// <param name="receiverMessage"> /// The <see cref="IReceiverMessage"/> with headers that map to cloud event attributes. /// </param> /// <param name="protocolBinding"> /// The <see cref="IProtocolBinding"/> used to map <see cref="IReceiverMessage"/> headers to /// CloudEvent attributes. If <see langword="null"/>, then <see cref="CloudEvent.DefaultProtocolBinding"/> /// is used instead. /// </param> public CorrelatedEvent(IReceiverMessage receiverMessage, IProtocolBinding protocolBinding = null) : base(receiverMessage, protocolBinding) { }
public Task DataReceivedAsync(IReceiverMessage message) { WriteLine(FormatMessage(message.StringPayload)); return(message.AcknowledgeAsync()); }
/// <summary> /// Gets the string value of the message. If the implemenation "speaks" binary, /// <see cref="Encoding.UTF8"/> is used to convert the binary message to a string. /// </summary> /// <param name="source">The message from which to obtain a string value.</param> /// <returns>The string value of the message.</returns> public static string GetStringValue(this IReceiverMessage source) { return(source.GetStringValue(Encoding.UTF8)); }
/// <summary> /// Gets the ID of the message, or null if not found in the message's headers. /// </summary> /// <param name="receiverMessage">The source <see cref="IReceiverMessage"/> object.</param> /// <returns>The ID of the message.</returns> public static string GetMessageId(this IReceiverMessage receiverMessage) => receiverMessage.GetHeaders() .TryGetValue(HeaderNames.MessageId, out string messageId) ? messageId : null;