LemonChannels. InboundHttp
(lemon_channels v0.1.0)
View Source
Optional inbound HTTP listener for channel adapters.
Every adapter shipped before this module was a client — a poller, a
websocket client, or a bridge process. Adapters that instead need to receive
HTTP (an email webhook, for instance) had nowhere to bind a port, which is why
those surfaces stayed in lemon_gateway. This is the smallest thing that
closes that gap: one Bandit listener, off unless configured, dispatching by
the first path segment to a registered handler.
Configuration
config :lemon_channels, LemonChannels.InboundHttp,
enabled: true,
port: 4090,
ip: {127, 0, 0, 1}Disabled by default. When disabled the supervisor starts with no children, so nothing binds a port and adapters that need inbound HTTP simply never receive anything — the same failure mode as an unconfigured poller.
Registering a handler
Adapters register a path segment at boot and implement
LemonChannels.InboundHttp.Handler:
LemonChannels.InboundHttp.register("email", MyAdapter.Webhook)A request to /email/anything is then routed to
MyAdapter.Webhook.handle_inbound/1, which receives the Plug.Conn (already
parsed) and returns it having sent a response.
Registration is deliberately runtime rather than compile-time so satellite packages can add listeners without this app knowing they exist.
Summary
Functions
Returns a specification to start this module under a supervisor.
Whether the listener is configured to bind a port.
Looks up the handler registered for a path segment.
All registered segment => handler pairs.
Configured bind address, loopback by default.
Largest request body the listener will read, in bytes.
Configured port. Only meaningful when enabled?/0.
Registers handler for the first path segment segment.
Functions
Returns a specification to start this module under a supervisor.
See Supervisor.
@spec enabled?() :: boolean()
Whether the listener is configured to bind a port.
Looks up the handler registered for a path segment.
All registered segment => handler pairs.
@spec ip() :: :inet.ip_address()
Configured bind address, loopback by default.
@spec max_body_bytes() :: pos_integer()
Largest request body the listener will read, in bytes.
2 MB by default — deliberately well under Plug.Parsers' 8 MB, since a
webhook endpoint is reachable by anyone who learns the URL and this is what
bounds the memory one request can cost. Over the limit the caller gets a 413.
Raise it for an adapter that must accept large payloads, remembering that attachments are usually base64-encoded on the wire and so occupy about a third more than their decoded size:
config :lemon_channels, LemonChannels.InboundHttp, max_body_bytes: 8_000_000LemonChannels.Adapters.Email derives its own attachment cap from this, so
the two cannot contradict each other.
@spec port() :: non_neg_integer()
Configured port. Only meaningful when enabled?/0.
Registers handler for the first path segment segment.
Returns :ok, or {:error, :not_running} when the listener supervisor is not
started (which is the case in apps that never start lemon_channels).
Last registration wins. Two packages claiming the same segment is a misconfiguration rather than a supported layout — the loser's webhooks would silently arrive at the winner — so a replacement is logged at warning level. Registration order between two applications is not something either of them controls, which is exactly why this must not be quiet.
@spec start_link(keyword()) :: Supervisor.on_start()