minghuaw / fe2o3-amqp

A rust implementation of the AMQP1.0 protocol based on serde and tokio.
MIT License
58 stars 7 forks source link

Receive Message without apriori knowledge of the message body type #235

Closed LarryOsterman closed 5 months ago

LarryOsterman commented 5 months ago

Looking at the Message and Receiver structs, it appears that it is not possible to receive a message without the caller having apriori knowledge of the underlying message format.

The challenge here is that a message receiver has no way of knowing what type of message was sent from the sender, so an API surface which forces the receiver to know the type of message being received is going to be challenging.

Knowing the body type of message on Send is reasonable because the sender always knows what they're sending, but for a receiver it is challenging.

For reference, other AMQP implementation handle this differently - they typically define a Message type with 3 fields, one for each possible body type, and then fill in the appropriate fields (either one or zero of the fields).

Here's the definition of Message for Go AMQP

Here's the definition of Message for Python AMQP and where it's decoded

Here's the definition of Message for Java AMQP - note that Java doesn't yet support Sequence or Value.

Here's the definition of Message for uAMQP.

What is common among all of these is that the receiver (or creator) Message object doesn't know the underlying body type.

Would it be possible to enable receiving messages where the receiver doesn't know the type of message being received ahead of time?

Please note that I am not an expert Rust developer. If it is already possible to receive messages without knowing the incoming message type, I would love to be wrong.

minghuaw commented 5 months ago

I think this is already covered by using Body<Value> as the receiving type. It is documented in the recv method, which is kind of hard to find. I should probably organize the documentation differently so it becomes more obvious

If the user is not certain the exact type (including the exact body section type) to receive, Body<Value> is probably the safest bet. Body<T> covers all possible body section types, including an empty body, and Value covers all possible AMQP 1.0 types

The Body<T>type covers all possible body section defined in the spec including an empty body, which was an unintended mistake in the spec.

The documentation of Body<T> can be found here, and the documentation of Value can be found here

minghuaw commented 5 months ago

Here is a simple example showing receiving a message from Service Bus without knowing the type beforehand and then try to interpret the message as a Data section that contains a string. The unwrapping and next are there because the Body could have one or more Data sections, and the example is only inspecting the first one.

https://github.com/minghuaw/fe2o3-amqp/blob/ddc8f3bf654ebbff5bed8133ce839f60c7ba20c9/examples/service_bus/src/bin/topic_receiver.rs#L39-L40

The Body type allows the user to inspect the body section type. If the body section is an AmqpValue, the user could then deserialize that Value using the method from_value

LarryOsterman commented 5 months ago

Ah, thank you, that answers my question. I had noticed the Body<Value> variant and was trying to use it, but I missed the try_as_data()/try_as_value()/try_as_sequence() functions on the Body<T> type.