# `StemMqtt.Broker`
[🔗](https://github.com/sorinirimies/stem-mqtt/blob/v0.6.1/lib/stem_mqtt/broker.ex#L1)

An embeddable MQTT 3.1.1 / 5.0 broker: for tests, edge devices, or an app
that is its own broker.

The process that creates a broker owns it; when it exits the broker stops.

    {:ok, broker} = StemMqtt.Broker.new(port: 0, events: true)
    :ok = StemMqtt.Broker.start(broker)
    port = StemMqtt.Broker.port(broker)

## Config

  * `:bind_address` (`"127.0.0.1"`), `:port` (1883; 0 picks a free port)
  * `:ws_port` - also serve MQTT over WebSocket
  * `:tls` - `%{port: ..., cert_pem: ..., key_pem: ..., client_ca_pem: nil}`
  * `:allow_anonymous` (`true`), `:max_clients` (0: unlimited), `:max_qos` (2)
  * `:max_retained_messages`, `:max_queued_per_client`, `:redelivery_interval_secs`,
    `:max_packet_size`, `:max_outbound_queue`, `:session_expiry_secs`

Owner options, not passed to the broker:

  * `:events` (`false`) - send `{:stem_mqtt, broker.id, event}` for
    `{:client_connected, client_id}`, `{:client_disconnected, client_id, reason}`
    and `{:message_published, client_id, topic, qos}`
  * `:auth` (`false`) - send every CONNECT as
    `{:stem_mqtt, broker.id, {:auth_request, id, client_id, username, password}}`;
    answer with `resolve_auth/3` within 10 seconds or it is denied
  * `:owner` (the caller)

Unknown keys raise `ArgumentError`. Errors are `{:error, {kind, message}}`
with `kind` one of `:already_running`, `:io`, `:tls`.

# `error`

```elixir
@type error() :: {:error, {atom(), String.t()}}
```

# `t`

```elixir
@type t() :: %StemMqtt.Broker{id: pos_integer(), ref: reference()}
```

# `client_count`

```elixir
@spec client_count(t()) :: non_neg_integer()
```

# `new`

```elixir
@spec new(keyword() | map()) :: {:ok, t()}
```

Creates a stopped broker.

# `port`

```elixir
@spec port(t()) :: :inet.port_number() | nil
```

The TCP port the broker listens on (useful with `port: 0`), or `nil` when stopped.

# `resolve_auth`

```elixir
@spec resolve_auth(t(), non_neg_integer(), boolean()) :: boolean()
```

Admits or refuses the CONNECT behind an `:auth_request`; `false` if it already expired.

# `running?`

```elixir
@spec running?(t()) :: boolean()
```

# `start`

```elixir
@spec start(t()) :: :ok | error()
```

Binds every listener and starts accepting connections.

# `stop`

```elixir
@spec stop(t()) :: :ok | error()
```

# `tls_port`

```elixir
@spec tls_port(t()) :: :inet.port_number() | nil
```

# `ws_port`

```elixir
@spec ws_port(t()) :: :inet.port_number() | nil
```

---

*Consult [api-reference.md](api-reference.md) for complete listing*
