defmodule LambentExWeb.ServicesChannel do
@moduledoc """
Mirrors `LambentExWeb.ServicesLive.Index`: the configured mqtt / http /
cronos services and the delete buttons.
Cronos entries can be created here, the same way the web form creates them.
Mqtt and http cannot yet.
Pushes
* `"services"` — `%{kind: "http" | "mqtt" | "cronos", services: ...}`
"""
use Phoenix.Channel
require Logger
alias LambentEx.Schema.Cronos
alias LambentExWeb.Channels.Payload
@pubsub LambentEx.PubSub
@impl true
def join("services", _params, socket) do
Phoenix.PubSub.subscribe(@pubsub, "svc_pub")
Phoenix.PubSub.subscribe(@pubsub, "svc_idx")
send(self(), :snapshot)
{:ok, socket}
end
@impl true
def handle_info(:snapshot, socket) do
for {kind, svcs} <- [
{"http", LambentEx.Meta.get_http()},
{"mqtt", LambentEx.Meta.get_mqtt()},
{"cronos", LambentEx.Meta.get_cronos()}
] do
push(socket, "services", %{kind: kind, services: services(svcs)})
end
{:noreply, socket}
end
@impl true
def handle_info({kind, svcs}, socket) when kind in [:http, :mqtt, :cronos] do
push(socket, "services", %{kind: to_string(kind), services: services(svcs)})
{:noreply, socket}
end
# stored as {name, entry} pairs, which would land on the wire as bare arrays
defp services(list) when is_list(list) do
Enum.map(list, fn
{name, entry} -> %{name: to_string(name), entry: Payload.wire(entry)}
other -> %{name: nil, entry: Payload.wire(other)}
end)
end
defp services(other), do: Payload.wire(other)
@impl true
def handle_info({:mqtt_pub, svc}, socket) do
push(socket, "service", %{kind: "mqtt", service: Payload.wire(svc)})
{:noreply, socket}
end
@impl true
def handle_info(_msg, socket), do: {:noreply, socket}
# %{"cronos" => %{"name" =>, "time" => "22:00", "action" =>, "arg" =>, "targets" => []}}
@impl true
def handle_in("create_cronos", %{"cronos" => params}, socket) do
case %Cronos{} |> Cronos.change(params) |> Cronos.save() do
{:ok, entry} ->
{:reply, {:ok, %{name: entry.name}}, socket}
{:error, changeset} ->
{:reply, {:error, %{errors: errors(changeset)}}, socket}
end
end
# what a client needs to offer the same choices the web form does
@impl true
def handle_in("cronos_options", _params, socket) do
push(socket, "cronos_options", %{
actions: options(Cronos.actions()),
args:
Cronos.actions()
|> Enum.map(fn {_label, action} ->
{to_string(action), options(Cronos.arg_options(action))}
end)
|> Map.new()
})
{:reply, :ok, socket}
end
@impl true
def handle_in("delete", %{"kind" => kind, "id" => id}, socket) do
case kind do
"http" -> LambentEx.Meta.del_http(id)
"mqtt" -> LambentEx.MQTTSupervisor.remove(id)
"cronos" -> LambentEx.Meta.del_cronos(id)
other -> Logger.info("Need handler for this service kind: #{other}")
end
{:reply, :ok, socket}
end
defp options(pairs) do
Enum.map(pairs, fn {label, value} -> %{label: to_string(label), value: to_string(value)} end)
end
defp errors(changeset) do
Ecto.Changeset.traverse_errors(changeset, fn {msg, opts} ->
Regex.replace(~r"%{(\w+)}", msg, fn _whole, key ->
opts |> Keyword.get(String.to_existing_atom(key), "") |> to_string()
end)
end)
end
end
neiam
/lambent_ex
Lambent Aether 5
public · Issues · Pulls 1 · Labels · Forks · Compare · Actions success · Badges · Packages
⭐
Log in to mark this repository.
3.4 KiB · text
History
9c0fc16