/// <summary> /// Converts this Kafka message into a CloudEvent object. /// </summary> /// <param name="message">The Kafka message to convert. Must not be null.</param> /// <param name="formatter">The event formatter to use to parse the CloudEvent. Must not be null.</param> /// <param name="extensionAttributes">The extension attributes to use when parsing the CloudEvent. May be null.</param> /// <returns>A reference to a validated CloudEvent instance.</returns> public static CloudEvent ToCloudEvent(this Message <string, byte[]> message, CloudEventFormatter formatter, IEnumerable <CloudEventAttribute> extensionAttributes) { Validation.CheckNotNull(message, nameof(message)); Validation.CheckNotNull(formatter, nameof(formatter)); if (!IsCloudEvent(message)) { throw new InvalidOperationException(); } var contentType = ExtractContentType(message); CloudEvent cloudEvent; // Structured mode if (MimeUtilities.IsCloudEventsContentType(contentType)) { cloudEvent = formatter.DecodeStructuredModeMessage(message.Value, new ContentType(contentType), extensionAttributes); } else { // Binary mode if (!(GetHeaderValue(message, SpecVersionKafkaHeader) is byte[] versionIdBytes)) { throw new ArgumentException("Request is not a CloudEvent"); } string versionId = Encoding.UTF8.GetString(versionIdBytes); CloudEventsSpecVersion version = CloudEventsSpecVersion.FromVersionId(versionId) ?? throw new ArgumentException($"Unknown CloudEvents spec version '{versionId}'", nameof(message)); cloudEvent = new CloudEvent(version, extensionAttributes) { DataContentType = contentType }; foreach (var header in message.Headers.Where(h => h.Key.StartsWith(KafkaHeaderPrefix))) { var attributeName = header.Key.Substring(KafkaHeaderPrefix.Length).ToLowerInvariant(); if (attributeName == CloudEventsSpecVersion.SpecVersionAttribute.Name) { continue; } // TODO: Is this feasible? var headerValue = header.GetValueBytes(); if (headerValue is null) { continue; } string attributeValue = Encoding.UTF8.GetString(headerValue); cloudEvent.SetAttributeFromString(attributeName, attributeValue); } formatter.DecodeBinaryModeEventData(message.Value, cloudEvent); } InitPartitioningKey(message, cloudEvent); return(Validation.CheckCloudEventArgument(cloudEvent, nameof(message))); }
public void IsCloudEventsContentType(string contentType, bool expectedResult) => Assert.Equal(expectedResult, MimeUtilities.IsCloudEventsContentType(contentType));
private static bool HasCloudEventsContentType(HttpRequest request) => MimeUtilities.IsCloudEventsContentType(request?.ContentType);
// TODO: This would include "application/cloudeventsarerubbish" for example... private static bool HasCloudEventsContentType(HttpContent content) => MimeUtilities.IsCloudEventsContentType(content?.Headers?.ContentType?.MediaType);
// TODO: Avoid all the byte[] -> string conversions? If we didn't care about case-sensitivity, we could prepare byte arrays to perform comparisons with. /// <summary> /// Indicates whether this message holds a single CloudEvent. /// </summary> /// <remarks> /// This method returns false for batch requests, as they need to be parsed differently. /// </remarks> /// <param name="message">The message to check for the presence of a CloudEvent. Must not be null.</param> /// <returns>true, if the request is a CloudEvent</returns> public static bool IsCloudEvent(this Message <string, byte[]> message) => GetHeaderValue(message, SpecVersionKafkaHeader) is object || MimeUtilities.IsCloudEventsContentType(ExtractContentType(message));
private static bool HasCloudEventsContentType(Message message, out string contentType) { contentType = message.Properties.ContentType?.ToString(); return(MimeUtilities.IsCloudEventsContentType(contentType)); }