Module nh_extensions

The extensions channel: health, geo and logs.

Description

The extensions channel: health, geo and logs.

Extensions are optional capabilities a device offers and the platform turns on. The device joins the extensions topic with what it can do and the versions it speaks, and the join reply names the subset the platform wants attached — a device may support an extension the product has switched off.

  join payload   #{<<"health">> => <<"0.0.1">>, ...}   device -> server
  join reply     [<<"health">>, <<"geo">>]             server -> device

Scoped events

Every event on this topic is prefixed with the extension it belongs to, so health:check is check for health. Splitting on the first colon is the whole of the routing — the rest of the event name may contain colons of its own, as geo:location:request does.

What this module does not do

It has no side effects. Building a health report reads the system, resolving a location makes an HTTP request, and neither belongs in a routing table, so both come back as actions for the caller to carry out. See nh_agent.

Data Types

state()

state() = #{enabled := [binary()], attached := [binary()]}

Function Index

attach/2Record the attach list from the join reply, and confirm it.
attached/1
available/1The join payload: what this device offers, and at which version.
enabled/1
handle_event/3Route an event to its extension.
is_attached/2
new/1Build the registry from configuration.
scope/1Split a scoped event into its extension and the event within it.

Function Details

attach/2

attach(Response::term(), State::state()) -> {state(), [term()]}

Record the attach list from the join reply, and confirm it.

Anything the platform did not name stays detached, and anything named that this device does not actually offer is ignored rather than trusted.

The confirmations are the point. NervesHub does not start an extension when it puts it in the attach list — it waits for the device to answer &lt;key&gt;:attached, and only then runs the extension's own attach, which is what asks for the first health report and the first location. A device that attaches silently is a device the platform never speaks to again, and nothing about that looks like an error from either end.

attached/1

attached(X1::state()) -> [binary()]

available/1

available(X1::state()) -> map()

The join payload: what this device offers, and at which version.

enabled/1

enabled(X1::state()) -> [binary()]

handle_event/3

handle_event(Scoped::binary(), Payload::map(), State::state()) -> {state(), [term()]}

Route an event to its extension.

Returns actions rather than performing them: {push, ScopedEvent, Payload} to answer immediately, {resolve_location} for the one that needs the network. An event for an extension that is not attached is dropped — the platform asking for something it never turned on is not something to answer.

is_attached/2

is_attached(Name::binary(), X2::state()) -> boolean()

new/1

new(Config::map()) -> state()

Build the registry from configuration.

extensions => [health, geo, logging], or all. Nothing is enabled by default: each one costs traffic a device may not want to spend.

scope/1

scope(Scoped::binary()) -> {binary(), binary()} | error

Split a scoped event into its extension and the event within it.


Generated by EDoc