Skip to content

beryl_ewe

Ewe WebSocket transport for beryl

This module provides the bridge between Ewe's native WebSocket handling and the beryl runtime using Ewe request and response types directly.

It mirrors the beryl_mist package: the two transports expose the same handler API, so an integrator can run beryl sockets on either web server by choosing the matching transport package.

Transport configuration (path, on_connect authentication, origin policy) lives in beryl/transport/server; build a server.TransportConfig with its config builders and pass it to handler or upgrade. This module supplies only the Ewe-specific glue: the WebSocket upgrade call, frame sending, and peer IP extraction.

pub fn handler(
beryl.Sockets,
server.TransportConfig(http1.Connection),
fn(request.Request(http1.Connection)) -> response.Response(ewe.ResponseBody)
) -> fn(request.Request(http1.Connection)) -> response.Response(ewe.ResponseBody)

Build a combined request handler that serves both WebSocket upgrades and regular HTTP from a single Ewe listener.

The returned function inspects and routes each request:

  • It passes WebSocket upgrade requests for the configured socket path to upgrade, which also runs any on_connect callback.
  • It passes all other requests to http_fallback. This includes non-upgrade requests and upgrades for a different path.

This removes the need to write an upgrade guard:

ewe_transport.handler(sockets, server.default_config("/socket"), http_handler)
|> ewe.new
|> ewe.listening(port: 8000)
|> ewe.start
pub fn upgrade(
request.Request(http1.Connection),
beryl.Sockets,
server.TransportConfig(http1.Connection),
fn() -> response.Response(ewe.ResponseBody)
) -> response.Response(ewe.ResponseBody)

Upgrade a request to WebSocket if it matches the configured path.

Usage in your Ewe handler:

fn handle_request(http_request: Request(Connection), sockets: Sockets) -> Response(ResponseBody) {
use <- ewe_transport.upgrade(http_request, sockets, server.default_config("/socket"))
// Fall through to regular HTTP routing
case request.path_segments(http_request) {
[] -> index_page()
_ -> response.new(404) |> response.set_body(ewe.Empty)
}
}

Path matching, origin policy, ?vsn version negotiation, connection limits (per-IP and per beryl system on the current node, rejected with 429 Too Many Requests), and the on_connect callback use the shared admission pipeline. See beryl/transport/server.upgrade for the full contract. Enforcement uses the real socket peer IP from the TCP connection; forwarded headers such as X-Forwarded-For are not trusted.