2.6 KiB · text History 9c0fc16
defmodule LambentExWeb.BrightnessChannel do
  @moduledoc """
  Mirrors `LambentExWeb.BrightnessLive.Index`: the global clamp and one per
  place, each with where it is, where it is headed and how long it takes to
  get there.

  Pushes
    * `"brightness"` — `%{global: clamp, places: %{place => clamp}}`, where a
      clamp is `%{tgt:, curr:, rate:}`. Sent on join and on every publish.
    * `"ladder"` — the named brightness rungs and fade rates, on join, so a
      client does not have to carry its own copy of either.
  """

  use Phoenix.Channel

  alias LambentEx.Brightness
  alias LambentEx.Utils.Brightness, as: B
  alias LambentExWeb.Channels.Payload

  @pubsub LambentEx.PubSub

  @impl true
  def join("brightness", _params, socket) do
    Phoenix.PubSub.subscribe(@pubsub, "brightness")
    send(self(), :snapshot)
    {:ok, socket}
  end

  @impl true
  def handle_info(:snapshot, socket) do
    push(socket, "ladder", %{
      steps: rungs(),
      fades: fades()
    })

    push(socket, "brightness", Payload.wire(Brightness.snapshot()))
    {:noreply, socket}
  end

  @impl true
  def handle_info({:brightness_pub, clamps}, socket) do
    push(socket, "brightness", Payload.wire(clamps))
    {:noreply, socket}
  end

  @impl true
  def handle_info(_msg, socket), do: {:noreply, socket}

  # the global clamp is the one with no place
  @impl true
  def handle_in("set", %{"value" => value} = params, socket) do
    case place(params) do
      nil -> Brightness.set_global(value)
      place -> Brightness.set_place(place, value)
    end

    {:reply, :ok, socket}
  end

  @impl true
  def handle_in(cmd, params, socket) when cmd in ~w(brighter dimmer) do
    cmd = String.to_existing_atom(cmd)

    case place(params) do
      nil -> apply(Brightness, cmd, [])
      place -> apply(Brightness, cmd, [place])
    end

    {:reply, :ok, socket}
  end

  @impl true
  def handle_in("rate", %{"rate" => rate} = params, socket) do
    case place(params) do
      nil -> Brightness.set_global_rate(rate)
      place -> Brightness.set_place_rate(place, rate)
    end

    {:reply, :ok, socket}
  end

  @impl true
  def handle_in("clear", %{"place" => place}, socket) do
    Brightness.clear_place(place)
    {:reply, :ok, socket}
  end

  defp place(params) do
    case params |> Map.get("place") do
      "" -> nil
      place -> place
    end
  end

  defp rungs do
    B.steps()
    |> Enum.sort_by(fn {value, _name} -> value end)
    |> Enum.map(fn {value, name} -> %{value: value, name: to_string(name)} end)
  end

  defp fades do
    B.fades()
    |> Enum.sort_by(fn {rate, _name} -> rate end)
    |> Enum.map(fn {rate, name} -> %{rate: rate, name: to_string(name)} end)
  end
end