137 lines
3.6 KiB
Elixir
137 lines
3.6 KiB
Elixir
defmodule AprsWeb.MapLive.PacketUtils do
|
|
@moduledoc """
|
|
Shared utilities for extracting and processing packet data in map views.
|
|
"""
|
|
|
|
@doc """
|
|
Safely extracts a value from a packet or data_extended map with fallback support.
|
|
Checks both atom and string keys, and provides a default value.
|
|
"""
|
|
@spec get_packet_field(map(), atom() | String.t(), any()) :: any()
|
|
def get_packet_field(packet, field, default \\ nil) do
|
|
data_extended = Map.get(packet, :data_extended, Map.get(packet, "data_extended", %{})) || %{}
|
|
|
|
Map.get(packet, field) ||
|
|
Map.get(packet, to_string(field)) ||
|
|
Map.get(data_extended, field) ||
|
|
Map.get(data_extended, to_string(field)) ||
|
|
default
|
|
end
|
|
|
|
@doc """
|
|
Extracts symbol information from a packet with fallbacks.
|
|
"""
|
|
@spec get_symbol_info(map()) :: {String.t(), String.t()}
|
|
def get_symbol_info(packet) do
|
|
symbol_table_id = get_packet_field(packet, :symbol_table_id, "/")
|
|
symbol_code = get_packet_field(packet, :symbol_code, ">")
|
|
|
|
{symbol_table_id, symbol_code}
|
|
end
|
|
|
|
@doc """
|
|
Extracts timestamp from a packet in ISO8601 format.
|
|
"""
|
|
@spec get_timestamp(map()) :: String.t()
|
|
def get_timestamp(packet) do
|
|
cond do
|
|
Map.has_key?(packet, :received_at) && packet.received_at ->
|
|
DateTime.to_iso8601(packet.received_at)
|
|
|
|
Map.has_key?(packet, "received_at") && packet["received_at"] ->
|
|
DateTime.to_iso8601(packet["received_at"])
|
|
|
|
true ->
|
|
""
|
|
end
|
|
end
|
|
|
|
@doc """
|
|
Converts various numeric types to float for consistent display.
|
|
"""
|
|
@spec to_float(any()) :: float()
|
|
def to_float(value) do
|
|
case value do
|
|
%Decimal{} = d ->
|
|
Decimal.to_float(d)
|
|
|
|
n when is_float(n) ->
|
|
n
|
|
|
|
n when is_integer(n) ->
|
|
n * 1.0
|
|
|
|
n when is_binary(n) ->
|
|
case Float.parse(n) do
|
|
{f, _} -> f
|
|
:error -> 0.0
|
|
end
|
|
|
|
_ ->
|
|
0.0
|
|
end
|
|
end
|
|
|
|
@doc """
|
|
Generates a callsign string with SSID if present.
|
|
"""
|
|
@spec generate_callsign(map()) :: String.t()
|
|
def generate_callsign(packet) do
|
|
base_callsign = get_packet_field(packet, :base_callsign, "")
|
|
ssid = get_packet_field(packet, :ssid, 0)
|
|
|
|
if ssid != 0 and ssid != "" and ssid != nil do
|
|
"#{base_callsign}-#{ssid}"
|
|
else
|
|
base_callsign
|
|
end
|
|
end
|
|
|
|
@doc """
|
|
Determines if a packet is a weather packet.
|
|
"""
|
|
@spec is_weather_packet?(map()) :: boolean()
|
|
def is_weather_packet?(packet) do
|
|
data_type = get_packet_field(packet, :data_type, "")
|
|
{symbol_table_id, symbol_code} = get_symbol_info(packet)
|
|
|
|
data_type == "weather" or (symbol_table_id == "/" and symbol_code == "_")
|
|
end
|
|
|
|
@doc """
|
|
Recursively converts tuples in data structures to strings for JSON serialization.
|
|
"""
|
|
@spec convert_tuples_to_strings(any()) :: any()
|
|
def convert_tuples_to_strings(map) when is_map(map) do
|
|
if Map.has_key?(map, :__struct__) do
|
|
map
|
|
else
|
|
Map.new(map, fn {k, v} ->
|
|
{k, convert_tuples_to_strings(v)}
|
|
end)
|
|
end
|
|
end
|
|
|
|
def convert_tuples_to_strings(list) when is_list(list) do
|
|
Enum.map(list, &convert_tuples_to_strings/1)
|
|
end
|
|
|
|
def convert_tuples_to_strings(tuple) when is_tuple(tuple) do
|
|
to_string(inspect(tuple))
|
|
end
|
|
|
|
def convert_tuples_to_strings(other), do: other
|
|
|
|
@doc """
|
|
Extracts weather field data with fallback support.
|
|
"""
|
|
@spec get_weather_field(map(), atom()) :: String.t()
|
|
def get_weather_field(packet, key) do
|
|
data_extended = Map.get(packet, "data_extended", %{}) || %{}
|
|
|
|
Map.get(packet, key) ||
|
|
Map.get(packet, to_string(key)) ||
|
|
Map.get(data_extended, key) ||
|
|
Map.get(data_extended, to_string(key)) || "N/A"
|
|
end
|
|
end
|