Ejemplo n.º 1
0
        /// <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)));
        }
Ejemplo n.º 2
0
        public static CloudEvent ToCloudEvent(this Message <string, byte[]> message,
                                              CloudEventFormatter eventFormatter, IEnumerable <CloudEventAttribute> extensionAttributes)
        {
            if (!IsCloudEvent(message))
            {
                throw new InvalidOperationException();
            }

            var contentType = ExtractContentType(message);

            CloudEvent cloudEvent;

            // Structured mode
            if (contentType?.StartsWith(CloudEvent.MediaType, StringComparison.InvariantCultureIgnoreCase) == true)
            {
                cloudEvent = eventFormatter.DecodeStructuredModeMessage(message.Value, new ContentType(contentType), extensionAttributes);
            }
            else
            {
                // Binary mode
                if (!(GetHeaderValue(message, KafkaCloudEventMessage.SpecVersionKafkaHeader) is byte[] versionIdBytes))
                {
                    throw new ArgumentException("Request is not a CloudEvent");
                }
                string versionId = Encoding.UTF8.GetString(versionIdBytes);
                CloudEventsSpecVersion version = CloudEventsSpecVersion.FromVersionId(versionId);
                if (version is null)
                {
                    throw new ArgumentException($"Unsupported CloudEvents spec version '{versionId}'");
                }

                cloudEvent = new CloudEvent(version, extensionAttributes)
                {
                    Data            = message.Value,
                    DataContentType = contentType
                };
                foreach (var header in message.Headers.Where(h => h.Key.StartsWith(KafkaCloudEventMessage.KafkaHeaderPrefix)))
                {
                    var attributeName = header.Key.Substring(KafkaCloudEventMessage.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);
                }
            }

            InitPartitioningKey(message, cloudEvent);
            return(cloudEvent);
        }
Ejemplo n.º 3
0
        /// <summary>
        /// Converts this MQTT message into a CloudEvent object.
        /// </summary>
        /// <param name="message">The MQTT 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 MqttApplicationMessage message,
                                              CloudEventFormatter formatter, IEnumerable <CloudEventAttribute>?extensionAttributes)
        {
            Validation.CheckNotNull(formatter, nameof(formatter));
            Validation.CheckNotNull(message, nameof(message));

            // TODO: Determine if there's a sensible content type we should apply.
            return(formatter.DecodeStructuredModeMessage(message.Payload, contentType: null, extensionAttributes));
        }
 private static CloudEvent StructuredToCloudEvent(
     Message message,
     string contentType,
     CloudEventFormatter formatter,
     IEnumerable <CloudEventAttribute>?extensionAttributes
     )
 {
     using (var stream = new MemoryStream(message.Body))
     {
         var cloudEvent = formatter.DecodeStructuredModeMessage(stream, new ContentType(contentType), extensionAttributes);
         cloudEvent.Id = message.MessageId;
         return(cloudEvent);
     }
 }
        private async static Task <CloudEvent> ToCloudEventAsyncImpl(HttpListenerRequest httpListenerRequest,
                                                                     CloudEventFormatter formatter, IEnumerable <CloudEventAttribute>?extensionAttributes, bool async)
        {
            Validation.CheckNotNull(httpListenerRequest, nameof(httpListenerRequest));
            Validation.CheckNotNull(formatter, nameof(formatter));
            var stream = httpListenerRequest.InputStream;

            if (HasCloudEventsContentType(httpListenerRequest))
            {
                var contentType = MimeUtilities.CreateContentTypeOrNull(httpListenerRequest.ContentType);
                return(async
                    ? await formatter.DecodeStructuredModeMessageAsync(stream, contentType, extensionAttributes).ConfigureAwait(false)
                    : formatter.DecodeStructuredModeMessage(stream, contentType, extensionAttributes));
            }
            else
            {
                string versionId = httpListenerRequest.Headers[HttpUtilities.SpecVersionHttpHeader];
                if (versionId is null)
                {
                    throw new ArgumentException($"Request does not represent a CloudEvent. It has neither a {HttpUtilities.SpecVersionHttpHeader} header, nor a suitable content type.", nameof(httpListenerRequest));
                }
                var version = CloudEventsSpecVersion.FromVersionId(versionId)
                              ?? throw new ArgumentException($"Unknown CloudEvents spec version '{versionId}'", nameof(httpListenerRequest));

                var cloudEvent = new CloudEvent(version, extensionAttributes);
                var headers    = httpListenerRequest.Headers;
                foreach (var key in headers.AllKeys)
                {
                    string?attributeName = HttpUtilities.GetAttributeNameFromHeaderName(key);
                    if (attributeName is null || attributeName == CloudEventsSpecVersion.SpecVersionAttribute.Name)
                    {
                        continue;
                    }
                    string attributeValue = HttpUtilities.DecodeHeaderValue(headers[key]);
                    cloudEvent.SetAttributeFromString(attributeName, attributeValue);
                }

                // The data content type should not have been set via a "ce-" header; instead,
                // it's in the regular content type.
                cloudEvent.DataContentType = httpListenerRequest.ContentType;

                ReadOnlyMemory <byte> data = async
                    ? await BinaryDataUtilities.ToReadOnlyMemoryAsync(stream).ConfigureAwait(false)
                    : BinaryDataUtilities.ToReadOnlyMemory(stream);

                formatter.DecodeBinaryModeEventData(data, cloudEvent);
                return(Validation.CheckCloudEventArgument(cloudEvent, nameof(httpListenerRequest)));
            }
        }
Ejemplo n.º 6
0
        /// <summary>
        /// Converts this listener request into a CloudEvent object, with the given extension attributes.
        /// </summary>
        /// <param name="httpListenerRequest">Listener request</param>
        /// <param name="formatter"></param>
        /// <param name="extensions">List of extension instances</param>
        /// <returns>The CloudEvent corresponding to the given request.</returns>
        /// <exception cref="ArgumentException">The request does not represent a CloudEvent,
        /// or the event's specification version is not supported,
        /// or the event formatter cannot interpret it.</exception>
        public static CloudEvent ToCloudEvent(this HttpListenerRequest httpListenerRequest,
                                              CloudEventFormatter formatter, params CloudEventAttribute[] extensionAttributes)
        {
            if (HasCloudEventsContentType(httpListenerRequest))
            {
                return(formatter.DecodeStructuredModeMessage(httpListenerRequest.InputStream, MimeUtilities.CreateContentTypeOrNull(httpListenerRequest.ContentType), extensionAttributes));
            }
            else
            {
                string versionId = httpListenerRequest.Headers[HttpUtilities.SpecVersionHttpHeader];
                if (versionId is null)
                {
                    throw new ArgumentException("Request is not a CloudEvent");
                }
                var version = CloudEventsSpecVersion.FromVersionId(versionId);
                if (version is null)
                {
                    throw new ArgumentException($"Unsupported CloudEvents spec version '{versionId}'");
                }

                var cloudEvent = new CloudEvent(version, extensionAttributes);
                var headers    = httpListenerRequest.Headers;
                foreach (var key in headers.AllKeys)
                {
                    string attributeName = HttpUtilities.GetAttributeNameFromHeaderName(key);
                    if (attributeName is null || attributeName == CloudEventsSpecVersion.SpecVersionAttribute.Name)
                    {
                        continue;
                    }
                    string attributeValue = HttpUtilities.DecodeHeaderValue(headers[key]);
                    cloudEvent.SetAttributeFromString(attributeName, attributeValue);
                }

                // The data content type should not have been set via a "ce-" header; instead,
                // it's in the regular content type.
                cloudEvent.DataContentType = httpListenerRequest.ContentType;

                formatter.DecodeBinaryModeEventData(BinaryDataUtilities.ToByteArray(httpListenerRequest.InputStream), cloudEvent);
                return(cloudEvent);
            }
        }
Ejemplo n.º 7
0
        public static CloudEvent ToCloudEvent(this Message message,
                                              CloudEventFormatter formatter,
                                              params CloudEventAttribute[] extensionAttributes)
        {
            if (HasCloudEventsContentType(message, out var contentType))
            {
                return(formatter.DecodeStructuredModeMessage(new MemoryStream((byte[])message.Body), new ContentType(contentType), extensionAttributes));
            }
            else
            {
                var propertyMap = message.ApplicationProperties.Map;
                if (!propertyMap.TryGetValue(SpecVersionAmqpHeader, out var versionId) || !(versionId is string versionIdText))
                {
                    throw new ArgumentException("Request is not a CloudEvent");
                }
                var version = CloudEventsSpecVersion.FromVersionId(versionIdText);
                if (version is null)
                {
                    throw new ArgumentException($"Unsupported CloudEvents spec version '{versionIdText}'");
                }

                var cloudEvent = new CloudEvent(version, extensionAttributes)
                {
                    Data            = message.Body,
                    DataContentType = message.Properties.ContentType
                };

                foreach (var property in propertyMap)
                {
                    if (!(property.Key is string key && key.StartsWith(AmqpHeaderPrefix)))
                    {
                        continue;
                    }
                    string attributeName = key.Substring(AmqpHeaderPrefix.Length).ToLowerInvariant();

                    // We've already dealt with the spec version.
                    if (attributeName == CloudEventsSpecVersion.SpecVersionAttribute.Name)
                    {
                        continue;
                    }

                    // Timestamps are serialized via DateTime instead of DateTimeOffset.
                    if (property.Value is DateTime dt)
                    {
                        if (dt.Kind != DateTimeKind.Utc)
                        {
                            // This should only happen for MinValue and MaxValue...
                            // just respecify as UTC. (We could add validation that it really
                            // *is* MinValue or MaxValue if we wanted to.)
                            dt = DateTime.SpecifyKind(dt, DateTimeKind.Utc);
                        }
                        cloudEvent[attributeName] = (DateTimeOffset)dt;
                    }
                    // URIs are serialized as strings, but we need to convert them back to URIs.
                    // It's simplest to let CloudEvent do this for us.
                    else if (property.Value is string text)
                    {
                        cloudEvent.SetAttributeFromString(attributeName, text);
                    }
                    else
                    {
                        cloudEvent[attributeName] = property.Value;
                    }
                }
                return(cloudEvent);
            }
        }
Ejemplo n.º 8
0
        /// <summary>
        /// Converts this AMQP message into a CloudEvent object.
        /// </summary>
        /// <param name="message">The AMQP 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 message,
            CloudEventFormatter formatter,
            IEnumerable <CloudEventAttribute> extensionAttributes)
        {
            Validation.CheckNotNull(message, nameof(message));
            Validation.CheckNotNull(formatter, nameof(formatter));

            if (HasCloudEventsContentType(message, out var contentType))
            {
                return(formatter.DecodeStructuredModeMessage(new MemoryStream((byte[])message.Body), new ContentType(contentType), extensionAttributes));
            }
            else
            {
                var propertyMap = message.ApplicationProperties.Map;
                if (!propertyMap.TryGetValue(SpecVersionAmqpHeader, out var versionId))
                {
                    throw new ArgumentException("Request is not a CloudEvent");
                }

                var version = CloudEventsSpecVersion.FromVersionId(versionId as string)
                              ?? throw new ArgumentException($"Unknown CloudEvents spec version '{versionId}'", nameof(message));

                var cloudEvent = new CloudEvent(version, extensionAttributes)
                {
                    DataContentType = message.Properties.ContentType
                };

                foreach (var property in propertyMap)
                {
                    if (!(property.Key is string key && key.StartsWith(AmqpHeaderPrefix)))
                    {
                        continue;
                    }
                    string attributeName = key.Substring(AmqpHeaderPrefix.Length).ToLowerInvariant();

                    // We've already dealt with the spec version.
                    if (attributeName == CloudEventsSpecVersion.SpecVersionAttribute.Name)
                    {
                        continue;
                    }

                    // Timestamps are serialized via DateTime instead of DateTimeOffset.
                    if (property.Value is DateTime dt)
                    {
                        if (dt.Kind != DateTimeKind.Utc)
                        {
                            // This should only happen for MinValue and MaxValue...
                            // just respecify as UTC. (We could add validation that it really
                            // *is* MinValue or MaxValue if we wanted to.)
                            dt = DateTime.SpecifyKind(dt, DateTimeKind.Utc);
                        }
                        cloudEvent[attributeName] = (DateTimeOffset)dt;
                    }
                    // URIs are serialized as strings, but we need to convert them back to URIs.
                    // It's simplest to let CloudEvent do this for us.
                    else if (property.Value is string text)
                    {
                        cloudEvent.SetAttributeFromString(attributeName, text);
                    }
                    else
                    {
                        cloudEvent[attributeName] = property.Value;
                    }
                }
                // Populate the data after the rest of the CloudEvent
                if (message.BodySection is Data data)
                {
                    // Note: Fetching the Binary property will always retrieve the data. It will
                    // be copied from the Buffer property if necessary.
                    formatter.DecodeBinaryModeEventData(data.Binary, cloudEvent);
                }
                else if (message.BodySection is object)
                {
                    throw new ArgumentException("Binary mode data in AMQP message must be in the application data section");
                }

                return(Validation.CheckCloudEventArgument(cloudEvent, nameof(message)));
            }
        }
Ejemplo n.º 9
0
 public static CloudEvent ToCloudEvent(this MqttApplicationMessage message,
                                       CloudEventFormatter eventFormatter, params CloudEventAttribute[] extensionAttributes)
 {
     // TODO: Determine if there's a sensible content type we should apply.
     return(eventFormatter.DecodeStructuredModeMessage(message.Payload, contentType: null, extensionAttributes));
 }
Ejemplo n.º 10
0
 internal static CloudEvent DecodeStructuredModeText(this CloudEventFormatter eventFormatter, string text, IEnumerable <CloudEventAttribute> extensionAttributes) =>
 eventFormatter.DecodeStructuredModeMessage(Encoding.UTF8.GetBytes(text), contentType: null, extensionAttributes);