# ConduitMQTT
[![CircleCI](https://img.shields.io/circleci/project/github/conduitframework/conduit_mqtt.svg?style=flat-square)](https://circleci.com/gh/conduitframework/conduit_mqtt)
[![Coveralls](https://img.shields.io/coveralls/conduitframework/conduit_mqtt.svg?style=flat-square)](https://coveralls.io/github/conduitframework/conduit_mqtt)
[![Hex.pm](https://img.shields.io/hexpm/v/conduit_mqtt.svg?style=flat-square)](https://hex.pm/packages/conduit_mqtt)
[![Hex.pm](https://img.shields.io/hexpm/l/conduit_mqtt.svg?style=flat-square)](https://github.com/conduitframework/conduit_mqtt/blob/master/LICENSE.md)
[![Hex.pm](https://img.shields.io/hexpm/dt/conduit_mqtt.svg?style=flat-square)](https://hex.pm/packages/conduit_mqtt)
An MQTT adapter for [Conduit](https://github.com/conduitframework/conduit).
## Installation
This package can be installed as:
1. Add `conduit_mqtt` to your list of dependencies in `mix.exs`:
```elixir
def deps do
[{:conduit_mqtt, "~> 0.1.0"}]
end
```
2. Ensure `conduit_mqtt` is started before your application:
```elixir
def application do
[applications: [:conduit_mqtt]]
end
```
## Configuring the Adapter
```elixir
# config/config.exs
config :my_app, MyApp.Broker,
adapter: ConduitMQTT, connection_opts: [server: {Tortoise.Transport.Tcp, host: 'localhost', port: 1883}]
```
For the full set of connection_opts, see the docs for underlying library [Tortiose](https://hexdocs.pm/tortoise/connecting_to_a_mqtt_broker.html#connection-handler).
NOTE: will and retain have not been tested. They may work by passing through on the opts. Let us know your use cases
or submit a PR
## Configuring Queues
MQTT defines queues on use. Configuring subscribers and publishers is all that's needed.
## Configuring a Subscriber
Inside an `incoming` block for a broker, you can define subscriptions to queues. Conduit will route messages on those
topics to your subscribers.
``` elixir
defmodule MyApp.Broker do
incoming MyApp do
subscribe :my_subscriber, MySubscriber, from: "rooms/+/temp", qos: 1
subscribe :my_other_subscriber, MyOtherSubscriber,
from: "rooms/#",
prefetch_size: 20
end
end
```
### Options
* `:from` - The topic filter to subscribe to.
* `:qos` - The quality of service to use for the subscription - defaults to 0.
See [mqtt-overview](https://hexdocs.pm/tortoise/introduction.html#mqtt-overview) for more details on options.
## Configuring a Publisher
Inside an `outgoing` block for a broker, you can define publications to exchanges. Conduit will deliver messages using the
options specified. You can override these options, by passing different options to your broker's `publish/3`.
``` elixir
defmodule MyApp.Broker do
outgoing do
publish :something,
to: "rooms/living-room/temp",
qos: 1
publish :something_else,
to: "rooms/dining-room/temp",
qos: 1
end
end
```
### Options
* `:to` - The topic for the message. If the message already has it's destination set, this option will be ignored.
* `:qos` - The quality of service for the publish defaults to 0.
## Supporting Message Fields and Headers
MQTT 3.1.1 and below do not support a mechanism for message headers. In order to support Conduit's message headers and
fields, you need to wrap them into your message body. You can use
[Conduit.Plug.Wrap](https://hexdocs.pm/conduit/Conduit.Plug.Wrap.html) and [Conduit.Plug.Unwrap](https://hexdocs.pm/conduit/Conduit.Plug.Unwrap.html) to help with that.
Example pipelines might look as follows:
```elixir
pipeline :serialize do
plug Conduit.Plug.Format, content_type: "application/json"
plug Conduit.Plug.Encode, encoding: "aes256gcm"
plug Conduit.Plug.Wrap
plug Conduit.Plug.Format, content_type: "application/json"
end
```
The above formats the message body into json, encrypts it, wraps the headers, fields, and body into a map and then
formats that into json for transport. Your pipeline could be simpler.
And the reverse of the above pipeline:
```elixir
pipeline :deserialize do
plug Conduit.Plug.Parse, content_type: "application/json"
plug Conduit.Plug.Unwrap
plug Conduit.Plug.Decode, encoding: "aes256gcm"
plug Conduit.Plug.Parse, content_type: "application/json"
end
```
## Local Testing with Docker
verneMQ docker command for development testing:
``` bash
docker run -p 1883:1883 -e "DOCKER_VERNEMQ_ALLOW_ANONYMOUS=on" -e "DOCKER_VERNEMQ_log.console.level=debug" -it erlio/docker-vernemq:1.5.0
```