Files
bDS2/lib/bds/events.ex

59 lines
2.1 KiB
Elixir

defmodule BDS.Events do
@moduledoc """
Domain event bus (issue #26, phase 2).
Contexts broadcast entity mutations on the same `"entity:changed"` topic
(and payload shape) that `BDS.CliSync.Watcher` already uses for external
CLI writes, so every connected client — LiveView shells and TUI sessions
alike — stays synchronized through one subscription regardless of where
a change originated.
"""
@entity_topic "entity:changed"
@settings_topic "settings:changed"
@type action :: :created | :updated | :deleted
@doc "Subscribe the calling process to entity and settings changes."
@spec subscribe() :: :ok
def subscribe do
:ok = Phoenix.PubSub.subscribe(BDS.PubSub, @entity_topic)
:ok = Phoenix.PubSub.subscribe(BDS.PubSub, @settings_topic)
end
@doc """
Broadcast an entity mutation as `{:entity_changed, %{entity: entity,
entity_id: id, action: action}}` — the same message the CLI sync watcher
emits, so subscribers handle both through one code path.
"""
@spec entity_changed(String.t(), String.t(), action()) :: :ok
def entity_changed(entity, entity_id, action)
when is_binary(entity) and is_binary(entity_id) and
action in [:created, :updated, :deleted] do
Phoenix.PubSub.broadcast(
BDS.PubSub,
@entity_topic,
{:entity_changed, %{entity: entity, entity_id: entity_id, action: action}}
)
end
@doc """
Pipe-friendly broadcast: on `{:ok, %{id: id}}` broadcasts `action` for
`entity` and returns the result unchanged; any other result passes
through untouched.
"""
@spec broadcast_result(term(), String.t(), action()) :: term()
def broadcast_result({:ok, %{id: id}} = result, entity, action) when is_binary(id) do
:ok = entity_changed(entity, id, action)
result
end
def broadcast_result(result, _entity, _action), do: result
@doc "Broadcast a global setting change as `{:settings_changed, key}`."
@spec settings_changed(String.t()) :: :ok
def settings_changed(key) when is_binary(key) do
Phoenix.PubSub.broadcast(BDS.PubSub, @settings_topic, {:settings_changed, key})
end
end