Skip to main content

src/pharos@event_bus.erl

-module(pharos@event_bus).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).
-define(FILEPATH, "src/pharos/event_bus.gleam").
-export([from_name/1, start_link/1, notify/2, add_handler/2, remove_handler/2]).
-export_type([event_bus/0, handler_id/0]).

-if(?OTP_RELEASE >= 27).
-define(MODULEDOC(Str), -moduledoc(Str)).
-define(DOC(Str), -doc(Str)).
-else.
-define(MODULEDOC(Str), -compile([])).
-define(DOC(Str), -compile([])).
-endif.

?MODULEDOC(
    " The alert event bus.\n"
    "\n"
    " A thin, restart-resilient wrapper around an `eparch/event_manager`\n"
    " configured with a registered name. The wrapper holds the `Name`, not\n"
    " a `Pid` or `Manager` value, so handles stay valid across supervisor\n"
    " restarts: when the underlying gen_event process is restarted under\n"
    " the same registered name, every previously-issued `EventBus` handle\n"
    " keeps working transparently.\n"
    "\n"
    " Most callers should not interact with `EventBus` directly: it is\n"
    " constructed by the pharos supervisor and exposed indirectly via\n"
    " `pharos.subscribe` / `pharos.unsubscribe`.\n"
).

-opaque event_bus() :: {event_bus,
        gleam@erlang@process:name(pharos@alert:alert_event())}.

-opaque handler_id() :: {handler_id, eparch@event_manager:handler_ref(nil, nil)}.

-file("src/pharos/event_bus.gleam", 38).
?DOC(
    " Wrap a registered name as an `EventBus`. The name must already (or\n"
    " eventually) be registered to a running `gen_event` manager process;\n"
    " the wrapper resolves it lazily on every API call.\n"
).
-spec from_name(gleam@erlang@process:name(pharos@alert:alert_event())) -> event_bus().
from_name(Name) ->
    {event_bus, Name}.

-file("src/pharos/event_bus.gleam", 47).
?DOC(
    " Start a fresh event bus registered under `name`.\n"
    "\n"
    " Used by the supervisor's bus child. The returned `Pid` is the bus's\n"
    " process id (suitable for `actor.Started`); the bus is also registered\n"
    " under `name` so other processes can reach it after a restart.\n"
).
-spec start_link(gleam@erlang@process:name(pharos@alert:alert_event())) -> {ok,
        {gleam@erlang@process:pid_(), event_bus()}} |
    {error, eparch@event_manager:start_error()}.
start_link(Name) ->
    Options = begin
        _pipe = eparch@event_manager:new_start_options(),
        eparch@event_manager:with_name(_pipe, {local, Name})
    end,
    _pipe@1 = eparch@event_manager:start_link(Options),
    gleam@result:map(
        _pipe@1,
        fun(Manager) ->
            {eparch@event_manager:manager_pid(Manager), {event_bus, Name}}
        end
    ).

-file("src/pharos/event_bus.gleam", 90).
?DOC(
    " Resolve the bus's `Name(AlertEvent)` to an eparch `Manager(AlertEvent)`.\n"
    " At the Erlang level both are interchangeable references that gen_event\n"
    " resolves at call time, so the FFI shim is an identity function on the\n"
    " underlying atom.\n"
).
-spec manager_for(event_bus()) -> eparch@event_manager:manager(pharos@alert:alert_event()).
manager_for(Bus) ->
    pharos_ffi:manager_from_name(erlang:element(2, Bus)).

-file("src/pharos/event_bus.gleam", 60).
?DOC(" Broadcast `event` to every registered handler. Non-blocking.\n").
-spec notify(event_bus(), pharos@alert:alert_event()) -> nil.
notify(Bus, Event) ->
    eparch@event_manager:notify(manager_for(Bus), Event).

-file("src/pharos/event_bus.gleam", 65).
?DOC(" Register a Gleam function as an event handler on the bus.\n").
-spec add_handler(event_bus(), fun((pharos@alert:alert_event()) -> nil)) -> {ok,
        handler_id()} |
    {error, eparch@event_manager:add_error(nil, nil)}.
add_handler(Bus, Handler) ->
    Handler_spec = eparch@event_manager:new_handler(
        nil,
        fun(Event, _) ->
            Handler(Event),
            {continue, nil}
        end
    ),
    _pipe = eparch@event_manager:add_handler(manager_for(Bus), Handler_spec),
    gleam@result:map(_pipe, fun(Field@0) -> {handler_id, Field@0} end).

-file("src/pharos/event_bus.gleam", 79).
?DOC(" Unregister a previously added handler.\n").
-spec remove_handler(event_bus(), handler_id()) -> {ok, nil} |
    {error, eparch@event_manager:remove_error(nil, nil)}.
remove_handler(Bus, Id) ->
    eparch@event_manager:remove_handler(manager_for(Bus), erlang:element(2, Id)).