Current section
Files
Jump to
Current section
Files
lib/off_broadway_mqtt/handler.ex
defmodule OffBroadway.MQTT.Handler do
@moduledoc false
# Default `Tortoise.Handler` implementation used by
# `OffBroadway.MQTT.Client`.
# Incoming messages are wrapped in `t:Broadway.Message.t/0` structs and pushed
# into the provided queue.
use Tortoise.Handler
require Logger
alias Broadway.Message
alias OffBroadway.MQTT.Data
alias OffBroadway.MQTT.Telemetry
defstruct queue: nil,
config: nil,
meta: nil,
sub_ack: nil,
client_id: nil
def init(opts) do
config = Keyword.fetch!(opts, :config)
queue_name = Keyword.fetch!(opts, :queue)
client_id = Keyword.fetch!(opts, :client_id)
meta = Keyword.get(opts, :meta) || %{}
Logger.debug("initializing client", Enum.into(meta, []))
{:ok,
%__MODULE__{
config: config,
meta: meta,
client_id: client_id,
queue: queue_name,
sub_ack: opts[:sub_ack]
}}
end
def connection(status, %{config: config} = state) do
Logger.debug("client attempting to connect", Enum.into(state.meta, []))
Telemetry.client_connection_status(config, status, state.meta)
{:ok, state}
end
def handle_message(topic, payload, %{config: config, queue: queue} = state) do
message = wrap_message(state, topic, payload)
:ok = config.queue.enqueue(queue, message)
Telemetry.client_message_received(config, state.meta)
{:ok, state}
end
def subscription(status, topic_filter, %{config: config} = state) do
Logger.debug(
"client subscription #{status} on #{topic_filter}",
Enum.into(state.meta, [])
)
Telemetry.client_subscription_status(config, status, state.meta)
{:ok, maybe_suback(state, topic_filter, status)}
end
defp maybe_suback(%{sub_ack: nil} = state, _, _), do: state
defp maybe_suback(
%{sub_ack: dest, client_id: client_id} = state,
topic_filter,
status
) do
if Process.alive?(dest),
do: send(dest, {:subscription, client_id, topic_filter, status})
state
end
def terminate(_reason, _state) do
:ok
end
defp wrap_message(
%{meta: meta, config: config, queue: queue},
topic,
payload
) do
ack_data = %{queue: queue, tries: 0, config: config}
topic_str = Enum.join(topic, "/")
%Message{
data: %Data{topic: topic, acc: payload},
metadata: Map.merge(meta, %{topic: topic_str}),
acknowledger: {config.acknowledger, topic_str, ack_data}
}
end
end