mirror of
https://github.com/fly-apps/live_beats.git
synced 2024-11-22 08:01:00 +00:00
95 lines
2.8 KiB
Elixir
95 lines
2.8 KiB
Elixir
defmodule LiveBeats do
|
|
@moduledoc """
|
|
The main interface for shared functionality.
|
|
"""
|
|
require Logger
|
|
|
|
@doc """
|
|
Looks up `Application` config or raises if keyspace is not configured.
|
|
|
|
## Examples
|
|
|
|
config :live_beats, :files, [
|
|
uploads_dir: Path.expand("../priv/uploads", __DIR__),
|
|
host: [scheme: "http", host: "localhost", port: 4000],
|
|
]
|
|
|
|
iex> LiveBeats.config([:files, :uploads_dir])
|
|
iex> LiveBeats.config([:files, :host, :port])
|
|
"""
|
|
def config([main_key | rest] = keyspace) when is_list(keyspace) do
|
|
main = Application.fetch_env!(:live_beats, main_key)
|
|
Enum.reduce(rest, main, fn next_key, current ->
|
|
case Keyword.fetch(current, next_key) do
|
|
{:ok, val} -> val
|
|
:error -> raise ArgumentError, "no config found under #{inspect(keyspace)}"
|
|
end
|
|
end)
|
|
end
|
|
|
|
@doc """
|
|
Attaches a modules to another for listening of events.
|
|
|
|
Events are executed in the caller's process. Accepts
|
|
the `:to` option which a tuple of the form: {ContextModule, StructModule}
|
|
|
|
You attached to conctext modules on a struct-by-struct basis for granular
|
|
events. The struct module passed must implement a valid struct or an error
|
|
is raised.
|
|
|
|
Events that executed are sent to a `handle_execute/2`, callback, which the
|
|
source module and executed event as arguments.
|
|
|
|
## Examples
|
|
|
|
defmodule MyModule do
|
|
def handle_execute({Accounts, %Accounts.Events.UpdateUpdated{user: user}}) do
|
|
IO.inspect({:user_updated, user})
|
|
end
|
|
end
|
|
|
|
iex> LiveBeats.attach(MyModule, to: {Accounts, Accounts.Events.UserUpdated})
|
|
:ok
|
|
|
|
iex> LiveBeats.execute(Accounts, %Accounts.Events.UserUpdated{user: new_user})
|
|
"""
|
|
def attach(target_mod, opts) when is_atom(target_mod) do
|
|
{src_mod, struct_mod} = Keyword.fetch!(opts, :to)
|
|
_ = struct_mod.__struct__
|
|
|
|
:ok =
|
|
:telemetry.attach(target_mod, [src_mod, struct_mod], &__MODULE__.handle_execute/4, %{
|
|
target: target_mod
|
|
})
|
|
end
|
|
|
|
@doc """
|
|
Executes an event from the context module with an event struct.
|
|
|
|
Events are exected *in the caller's process*, for every attached listener.
|
|
|
|
## Examples
|
|
|
|
iex> LiveBeats.attach(MyModule, to: {Accounts, Accounts.Events.UserUpdated})
|
|
:ok
|
|
|
|
iex> LiveBeats.execute(Accounts, %Accounts.Events.UserUpdated{user: new_user})
|
|
"""
|
|
def execute(src_mod, event_struct) when is_struct(event_struct) do
|
|
:telemetry.execute([src_mod, event_struct.__struct__], event_struct, %{})
|
|
end
|
|
|
|
@doc false
|
|
def handle_execute([src_mod, event_mod], %event_mod{} = event_struct, _meta, %{target: target}) do
|
|
try do
|
|
target.handle_execute({src_mod, event_struct})
|
|
catch
|
|
kind, err ->
|
|
Logger.error """
|
|
executing {#{inspect(src_mod)}, #{inspect(event_mod)}} failed with #{inspect(kind)}
|
|
|
|
#{inspect(err)}
|
|
"""
|
|
end
|
|
end
|
|
end
|