package binding import ( "context" "github.com/cloudevents/sdk-go/v2/binding/spec" ) // MessageReader defines the read-related portion of the Message interface. // // The ReadStructured and ReadBinary methods allows to perform an optimized encoding of a Message to a specific data structure. // // If MessageReader.ReadEncoding() can be equal to EncodingBinary, then the implementation of MessageReader // MUST also implement MessageMetadataReader. // // A Sender should try each method of interest and fall back to binding.ToEvent() if none are supported. // An out of the box algorithm is provided for writing a message: binding.Write(). type MessageReader interface { // Return the type of the message Encoding. // The encoding should be preferably computed when the message is constructed. ReadEncoding() Encoding // ReadStructured transfers a structured-mode event to a StructuredWriter. // It must return ErrNotStructured if message is not in structured mode. // // Returns a different err if something wrong happened while trying to read the structured event. // In this case, the caller must Finish the message with appropriate error. // // This allows Senders to avoid re-encoding messages that are // already in suitable structured form. ReadStructured(context.Context, StructuredWriter) error // ReadBinary transfers a binary-mode event to an BinaryWriter. // It must return ErrNotBinary if message is not in binary mode. // // The implementation of ReadBinary must not control the lifecycle with BinaryWriter.Start() and BinaryWriter.End(), // because the caller must control the lifecycle. // // Returns a different err if something wrong happened while trying to read the binary event // In this case, the caller must Finish the message with appropriate error // // This allows Senders to avoid re-encoding messages that are // already in suitable binary form. ReadBinary(context.Context, BinaryWriter) error } // MessageMetadataReader defines how to read metadata from a binary/event message // // If a message implementing MessageReader is encoded as binary (MessageReader.ReadEncoding() == EncodingBinary) // or it's an EventMessage, then it's safe to assume that it also implements this interface type MessageMetadataReader interface { // GetAttribute returns: // // * attribute, value: if the message contains an attribute of that attribute kind // * attribute, nil: if the message spec version supports the attribute kind, but doesn't have any value // * nil, nil: if the message spec version doesn't support the attribute kind GetAttribute(attributeKind spec.Kind) (spec.Attribute, interface{}) // GetExtension returns the value of that extension, if any. GetExtension(name string) interface{} } // Message is the interface to a binding-specific message containing an event. // // Reliable Delivery // // There are 3 reliable qualities of service for messages: // // 0/at-most-once/unreliable: messages can be dropped silently. // // 1/at-least-once: messages are not dropped without signaling an error // to the sender, but they may be duplicated in the event of a re-send. // // 2/exactly-once: messages are never dropped (without error) or // duplicated, as long as both sending and receiving ends maintain // some binding-specific delivery state. Whether this is persisted // depends on the configuration of the binding implementations. // // The Message interface supports QoS 0 and 1, the ExactlyOnceMessage interface // supports QoS 2 // // Message includes the MessageReader interface to read messages. Every binding.Message implementation *must* specify if the message can be accessed one or more times. // // When a Message can be forgotten by the entity who produced the message, Message.Finish() *must* be invoked. type Message interface { MessageReader // Finish *must* be called when message from a Receiver can be forgotten by // the receiver. A QoS 1 sender should not call Finish() until it gets an acknowledgment of // receipt on the underlying transport. For QoS 2 see ExactlyOnceMessage. // // Note that, depending on the Message implementation, forgetting to Finish the message // could produce memory/resources leaks! // // Passing a non-nil err indicates sending or processing failed. // A non-nil return indicates that the message was not accepted // by the receivers peer. Finish(error) error } // ExactlyOnceMessage is implemented by received Messages // that support QoS 2. Only transports that support QoS 2 need to // implement or use this interface. type ExactlyOnceMessage interface { Message // Received is called by a forwarding QoS2 Sender when it gets // acknowledgment of receipt (e.g. AMQP 'accept' or MQTT PUBREC) // // The receiver must call settle(nil) when it get's the ack-of-ack // (e.g. AMQP 'settle' or MQTT PUBCOMP) or settle(err) if the // transfer fails. // // Finally the Sender calls Finish() to indicate the message can be // discarded. // // If sending fails, or if the sender does not support QoS 2, then // Finish() may be called without any call to Received() Received(settle func(error)) } // MessageWrapper interface is used to walk through a decorated Message and unwrap it. type MessageWrapper interface { Message MessageMetadataReader // Method to get the wrapped message GetWrappedMessage() Message } func UnwrapMessage(message Message) Message { m := message for m != nil { switch mt := m.(type) { case MessageWrapper: m = mt.GetWrappedMessage() default: return m } } return m }