Skip to main content

lib/pi/plugin/event.ex

defmodule Pi.Plugin.Event do
  @moduledoc "Pi-side events delivered to BEAM plugins."

  use GenServer

  alias Pi.Protocol.PluginEvent
  alias Pi.Transport.Stdio

  def start_link(opts \\ []), do: GenServer.start_link(__MODULE__, opts, name: __MODULE__)

  def install do
    case Process.whereis(__MODULE__) do
      nil -> start_link([])
      _pid -> :ok
    end
  end

  def push(event) when is_map(event) do
    install()
    GenServer.cast(__MODULE__, {:event, event})
  end

  def emit(name, data \\ %{}) when is_binary(name) and is_map(data) do
    Stdio.emit(%PluginEvent{type: :event, name: name, data: data})
  end

  def recent(n \\ 50), do: GenServer.call(__MODULE__, {:recent, n})
  def clear, do: GenServer.call(__MODULE__, :clear)

  @impl true
  def init(_opts), do: {:ok, :queue.new()}

  @impl true
  def handle_cast({:event, event}, events) do
    events = :queue.in(event, events)
    events = if :queue.len(events) > 256, do: elem(:queue.out(events), 1), else: events
    {:noreply, events}
  end

  @impl true
  def handle_call({:recent, n}, _from, events) do
    {:reply, events |> :queue.to_list() |> Enum.take(-n), events}
  end

  def handle_call(:clear, _from, _events), do: {:reply, :ok, :queue.new()}
end