defmodule LambentExWeb.Channels.Payload do
@moduledoc """
The pubsub payloads the liveviews consume are built for elixir, not for the
wire: ip addresses are tuples, machine and link options are keyword lists,
and map keys are a mix of atoms and strings. None of that survives a json
encoder, so everything a channel pushes goes through here first.
"""
@doc """
Recursively makes a term json-safe. Keyword lists become objects, other
tuples become arrays, atoms and structs become strings or plain maps.
"""
def wire(%DateTime{} = dt), do: DateTime.to_iso8601(dt)
def wire(%NaiveDateTime{} = dt), do: NaiveDateTime.to_iso8601(dt)
def wire(%_struct{} = s), do: s |> Map.from_struct() |> wire()
def wire(%{} = map) do
Map.new(map, fn {k, v} -> {key(k), wire(v)} end)
end
def wire(list) when is_list(list) do
case Keyword.keyword?(list) and list != [] do
true -> list |> Map.new() |> wire()
false -> Enum.map(list, &wire/1)
end
end
def wire(tuple) when is_tuple(tuple), do: tuple |> Tuple.to_list() |> wire()
def wire(atom) when is_atom(atom) and not is_boolean(atom) and not is_nil(atom),
do: to_string(atom)
def wire(pid) when is_pid(pid), do: inspect(pid)
def wire(other), do: other
@doc """
Devices carry their address as an `:inet` tuple, which reads better on the
wire as the dotted string the ui shows.
"""
def device(device) when is_map(device) do
case Map.get(device, "ip") do
ip when is_tuple(ip) -> device |> Map.put("ip", ip |> Tuple.to_list() |> Enum.join("."))
_otherwise -> device
end
|> wire()
end
def devices(devices) when is_map(devices) do
Map.new(devices, fn {mac, device} -> {mac, device(device)} end)
end
defp key(k) when is_binary(k), do: k
defp key(k), do: to_string(k)
end
neiam
/lambent_ex
Lambent Aether 5
public · Issues · Pulls 1 · Labels · Forks · Compare · Actions success · Badges · Packages
⭐
Log in to mark this repository.
1.8 KiB · text
History
9c0fc16