dustin / mqttd

a complete mqtt v5 broker
BSD 3-Clause "New" or "Revised" License
16 stars 4 forks source link

MQTTD as a library #5

Open cdupont opened 3 years ago

cdupont commented 3 years ago

Hello, it would be very useful if some parts of MQTTD become a library. My use case is a REST API server, in which I want to add MQTT capacities. RIght now, I used the MQTT types from https://hackage.haskell.org/package/net-mqtt https://github.com/Waziup/waziup-api/blob/master/src/MQTT.hs The server implements a simple pass-through and mosquito is used as MQTT back-end.

However, it would be much better to run the last mile and to handle all MQTT business in my server, getting rid of Mosquito. I see that MQTTD monad would be useful to add on my own stack:

newtype MQTTD m a = MQTTD
  { runMQTTD :: ReaderT Env m a
  } deriving (Applicative, Functor, Monad, MonadIO, MonadLogger,
              MonadCatch, MonadThrow, MonadMask, MonadReader Env, MonadFail)

My stack is based on Servant:

type MyApp = ReaderT MyEnv Servant.Handler

So I see that I could easily add MQTT capacity to that server.

dustin commented 3 years ago

Do you intend to try to respond to particular mqtt events in application code, or just consolidate the functionality into a single binary?

The server's main is just this:

main = void . waitAnyCancel =<< runServer =<< parseConfFile "mqttd.conf"

Main.hs defines all these convenient entry points:

I didn't get much fancier because the closest thing I'd need would be tests, and for that I just spin up an in-memory server with a :memory: database and do integration tests against it.

If there's particular integrations you're interested in, it'd be interesting to figure out how to get them in. Right now, there are a few threads managing state and connections and it's going to need to make sure all the things happen.

cdupont commented 3 years ago

What I need is a server that responds only to some preconfigured topics (not a generic MQTT server). It will mimic the capacity of the REST API (just for some endpoints): https://api.waziup.io/docs/ For instance, I will have a topic /sensors/<sensor_id>/value, where you can subscribe on a particular sensor using its ID. When somebody publishes OR perform a REST POST on that sensor, subscribers will receive a MQTT notification.

dustin commented 3 years ago

The easiest thing to do, tbh, is just run a server and have the web handler connect to it. There are lots of edge cases that would be difficult to cover if you got too custom. e.g., client sessions can exist across connections so you have to maintain that state so a subscriber can reconnect and pick up messages that it missed while it was offline. Similarly, you'll want these sessions to exist across server restarts, so that stuff's there.

cdupont commented 3 years ago

OK that's clear. Right now I'm filtering the MQTT requests in my server, before forwarding them to Mosquitto. I do that because I wanted to apply my own access control...

dustin commented 3 years ago

AAA is an area that could probably use some increased fanciness. I just added support for separate ro/rw ACLs, but it's only good enough for my needs. It might be nice to have some BL.ByteString -> IO User hook to fetch users and their ACLs. The ACL has control over their topic access. This currently exists in the users section of the config file, which is fine for my small needs. There's a lot of space for improvement there, though.