-
-
Notifications
You must be signed in to change notification settings - Fork 235
feat(bridge): support incoming mosquitto bridge connections #584
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
The incoming mosquitto bridge connections add 128 to the protocol version to indicate ras=true and nl=true. Support for this was added in mqtt-packet with mqttjs/mqtt-packet#106 Subscriptions from these connections will have ras=true and nl=true When publishing to these connections, aedes will now copy the Packet and set retain to false only if ras is not true.
Pull Request Test Coverage Report for Build 620166757
💛 - Coveralls |
| } | ||
|
|
||
| function emitPacket (packet, done) { | ||
| packet.retain = false |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why? This is used to prevent other broker instances to store this packet again when it's emiitted
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Unfortunately this cannot be easily removed.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We need to keep the retain on the packet until we are able to check if "retain as published" (rap) is true. That's the whole point of the rap flag. The bridge protocol enables retain-as-published. I moved this into the subscription handler. What are the concerns with moving this into the subscription handler?
The tests are passing with my change, so if there is a problem with removing this line, it must not have been covered by the tests. I'm happy to make adjustments, but I'd like to know more about the concerns.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
can you link it to the block of code that replaces this?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@mcollina this is what handlePacketSubscription in subscribe.js is doing. Instead of globally setting it to false for all subscriptions, it sets it to false only if the retain-as-published flag is not set on the subscription.
If clusters go through a different (untested?) path, then clearing the retain flag can happen on that path, or I could set up a different emitter for client subscriptions so that clusters always get the flag set to false while bridges and regular clients respect the rap flag.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we should verify if this is still needed, e.g. if the packet gets stored multiple times when using a cluster.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This only happens when a user sends a packet using broker.publish function. BTW I think that it could be safely removed by double checking the code, the 'worst' thing that could happen is some useless write to the db
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I had thought of the _stored idea, but wasn't sure whether it would cause other issues. In any case, it becomes the event listener's responsibility to not retain the packet if it's not supposed to. I guess that can be a breaking change for some custom code, so I understand it's a bit dangerous. But I don't see a good way to support bridge protocol (or, going forward, MQTT v5) without doing this.
As I've said, the tests pass, including some new ones I added, so how can I verify this concern?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As I've said, the tests pass, including some new ones I added, so how can I verify this concern?
You should add a test where you do a broker subscribe followed by a broker publish to check if the received message has the retained flag cleared or not
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I added the test and, indeed, the retain flag was previously set to false and is now true. I've pushed a change with a proposed solution. The publish function now takes the rap parameter and applies the wrapper function that I had previously placed in subscription.js. This way all callers of subscribe have the retain-as-published functionality available to them but default to the standard behaviour of setting retain to false.
| } | ||
|
|
||
| function emitPacket (packet, done) { | ||
| packet.retain = false |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Unfortunately this cannot be easily removed.
README.md
Outdated
| ## Bridge connections | ||
|
|
||
| Normally, when publishing a message, the `retain` flag is consumed by Aedes and | ||
| then set to `false` so that recipients of the message do not retain it as well. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's not really correct, it is set to false because Aedes can be used in a cluster env, in such cases the mqemitter is used to share a message between different broker instances, the retain is set to false to prevent other instances to store it again
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@robertsLando that's correct.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Probably also true, but my understanding of the MQTT spec is that the retain flag needs to be false when received through a subscribe.
http://docs.oasis-open.org/mqtt/mqtt/v3.1.1/os/mqtt-v3.1.1-os.html
It MUST set the RETAIN flag to 0 when a PUBLISH Packet is sent to a Client because it matches an established subscription regardless of how the flag was set in the message it received [MQTT-3.3.1-9].
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
First of all I would add this comment there, then sincerly I dunno what's the best way to continue as both seems to have a reson to be accepted. I see no reference on bridge retain handling on specs
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Bridge retain handling is outside of the standard, so the only spec about bridge retain handling is here: https://github.com/mqtt/mqtt.github.io/wiki/bridge_protocol
However, MQTT v5 does mention retain handling: https://docs.oasis-open.org/mqtt/mqtt/v5.0/mqtt-v5.0.html
The setting of the RETAIN flag in an Application Message forwarded by the Server from an established connection is controlled by the Retain As Published subscription option. Refer to section 3.8.3.1 for a definition of the Subscription Options.
· If the value of Retain As Published subscription option is set to 0, the Server MUST set the RETAIN flag to 0 when forwarding an Application Message regardless of how the RETAIN flag was set in the received PUBLISH packet [MQTT-3.3.1-12].
· If the value of Retain As Published subscription option is set to 1, the Server MUST set the RETAIN flag equal to the RETAIN flag in the received PUBLISH packet [MQTT-3.3.1-13].
This allows all callers of subscribe to receive the retain flag set to false unless explicitly requested by passing rap=true
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think you can move the wrapper inside lib/handlers/subscribe instead.
To be clear, you'd like me to put it back the way it was, knowing the behaviour change to those who subscribe directly to the broker? |
No, I didn't really understand why the function was moved out of subscribe. |
It was moved out because the broker subscribe doesn't go through lib/handlers/subscribe. So it was moved to share the functionality with broker subscribe. |
|
Why does the broker subscribe need it? |
@robertsLando said so? |
If broker.subscribe doesn't add this wrapper, then when I remove the retain = false from emitPacket the subscribers who call broker.subscribe have retain = true. There has been a long conversation with you and @robertsLando saying that would be a bad thing. |
|
Ultimately I don't care, but if you can give me consistent direction, I'll do it. Otherwise, I'll just use my fork of this repo the way it works for me. |
Multiple maintainers can have different view about the project, that's the good/bad side of having open governance. To recap, I would recommend:
WDYT @robertsLando? What will leave us with then? I'm sorry but you are probably more into this feature than me at this point - I'd need some guidance. |
I agree with @mcollina expecially latest commit has introduced some complexity that makes the code hard to read. I think i may have explained wrong in my comment, my idea was to create a strict test for the |
|
Okay, so I guess I misinterpreted your request to add that test. You wanted me to test the new behaviour where retain is not set to false in broker.subscribe. I have reverted to the behaviour where retain is not modified in emitPacket. |
|
I think we keep misinterpreting ourselves (maybe it's the language).
Is this doable while supporting the protocol? |
If retain is false when it reaches subscriber.js (which subscribes to the event via broker.subscribe), then it is not possible to know what its value was in order to set it back to true. If we introduce another field in the Packet to indicate that it was retained, then we could use that, but that might have other side-effects. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry pressed the approve changes by error... From a code side it looks almost all good to me, @phil-mitchell I think that @mcollina would prefer to don't create the wrapping function in the doSubscribe function but to clear the retained flag in the client deliverQoS and deliver0 functions instead. This is the only missing thing right now I think?
I don't see where @mcollina requested that. Sorry, but I don't see how this is feasible unless we pass another parameter to these methods. The subscription coming out of |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
I thought a bit more about this and I think this code is ok.
The incoming mosquitto bridge connections add 128 to the protocol
version to indicate ras=true and nl=true.
Support for this was added in mqtt-packet with
mqttjs/mqtt-packet#106
Subscriptions from these connections will have ras=true and nl=true
When publishing to these connections, aedes will now
copy the Packet and set retain to false only if ras is not true.
Fixes #329