Current section

Files

Jump to
yggdrasil lib yggdrasil subscriber adapter elixir.ex
Raw

lib/yggdrasil/subscriber/adapter/elixir.ex

defmodule Yggdrasil.Subscriber.Adapter.Elixir do
@moduledoc """
Yggdrasil subscriber adapter for Elixir. The name of the channel can be any
arbitrary term e.g:
First we subscribe to a channel:
```
iex> channel = [name: "elixir_channel"]
iex> Yggdrasil.subscribe(channel)
:ok
iex> flush()
{:Y_CONNECTED, ...}
```
Once connected, you can publish a message in that channel:
```
iex> Yggdrasil.publish(channel, "foo")
:ok
```
And the subscriber should receive the message:
```
iex> flush()
{:Y_EVENT, ..., "foo"}
```
Additionally, the subscriber can also unsubscribe from the channel:
```
iex> Yggdrasil.unsubscribe(channel)
:ok
iex> flush()
{:Y_DISCONNECTED, ...}
```
"""
use Yggdrasil.Subscriber.Adapter
use GenServer
require Logger
alias Yggdrasil.Backend
alias Yggdrasil.Channel
alias Yggdrasil.Subscriber.Manager
alias Yggdrasil.Subscriber.Publisher
@doc false
defstruct [:external, :internal]
alias __MODULE__, as: State
####################
# GenServer callback
@impl GenServer
def init(%{channel: %Channel{name: name} = external}) do
internal = %Channel{external | name: {:"$yggdrasil_elixir", name}}
state = %State{external: external, internal: internal}
Backend.subscribe(internal)
Manager.connected(external)
Logger.debug(fn -> "Started #{__MODULE__} for #{inspect(external)}" end)
{:ok, state}
end
@impl GenServer
def handle_info({:Y_EVENT, _, message}, %State{external: external} = state) do
Publisher.notify(external, message)
{:noreply, state}
end
def handle_info(_, state) do
{:noreply, state}
end
@impl GenServer
def terminate(:normal, %State{external: external, internal: internal}) do
Backend.unsubscribe(internal)
Manager.disconnected(external)
Logger.debug(fn -> "Stopped #{__MODULE__} for #{inspect(external)}" end)
end
def terminate(reason, %State{external: external, internal: internal}) do
Backend.unsubscribe(internal)
Manager.disconnected(external)
Logger.warn(fn ->
"Stopped #{__MODULE__} for #{inspect(external)} due to #{inspect(reason)}"
end)
end
end