Open ryan-summers opened 5 months ago
I think the simplest approach here would be to simply pull the NetworkStack
out of the MqttClient
struct. Then, we could essentially have the MqttClient
operate at a packet level. When a packet is read from the stack, it gets fed into the client for processing. Similarly, when it generates a packet for transmission, it returns the slice for transmission on the network. This would make the client entirely synchronous regardless of the transport (async or sync) and would allow us to use the same core logic for both async and sync implementations.
I think this would essentially result in us moving some of the MqttClient
APIs outwards to the Minimq
structure. The main impact of this would be that a user could not publish
or subscribe
within the current closure of Minimq::poll()
.
However, I think it may make sense to update poll()
to similarly not actually process publications
but simply buffer them for future processing. I'm still unsure how one would go about generating a Publication
or Subscribe
in response to an inbound message without copying it though.
Edit: I think the fix here is to have the MqttClient
serialize into its TX buffer and essentially flag to the Minimq
structure that it has something to send at a future time (i.e. in poll()
).
Might be wise to analyze how rust-mqtt
et al. do it.
From what I've seen, all of the crates either provide an async or a sync interface, but not both.
Wrong button
Might be wise to analyze how rust-mqtt et al. do it.
rust-mqtt
is not supporting simultaneous listen and publish - method corresponding for listening is taking &mut self
and is not cancel safe, i. e. you cannot stop listening (not polling anymore) via select
etc, because data might be lost.
But rumqttc
, while an std+tokio based library, is doing things quite well. They also do have an async method that should be continuously polled, but they have an eventloop based structure, so requests to publish a message a queued and do not interfere with reading, which is done via Framed
tokio util to keep cancellation safety.
with minimal code duplication
One option may be to go with async only - blocking is very plarform specific, while asynchronism is a language level concept, independent of os etc. If user would want a sync version, it is only a matter of semaphore to block on future. There is std crate pollster that uses a condvar, but it is trivial to make something like that for custom embedded use case and without any heap allocations.
It would be really nice to be able to use
minimq
as an async MQTT client as well. We should investigate what it would take. Ideally, we would be able to reuse most of the logic and parsing here with minimal code duplication to be able to have bothasync
and synchronous versions of the client.