fix: handle both string and atom keys in packet map accessors
Some checks failed
Elixir CI / Build and test (push) Failing after 3m33s
Elixir CI / Dialyzer (push) Successful in 3m57s
Elixir CI / Build and Push Docker Image (push) Has been skipped

CoordinateUtils, Clustering, DataBuilder, HistoricalLoader, PacketHandler,
PacketUtils, and Index now support both string-keyed and atom-keyed packet maps
via Map.get/3 nested fallback pattern.
This commit is contained in:
Graham McIntire 2026-08-06 17:31:33 -05:00
parent 2e101870d7
commit d63cdf4cda
No known key found for this signature in database
GPG key ID: F4ABF488E6029E59
7 changed files with 21 additions and 19 deletions

View file

@ -69,8 +69,8 @@ defmodule Aprsme.Packets.Clustering do
# Filter packets with valid lat/lon coordinates # Filter packets with valid lat/lon coordinates
defp filter_valid_coordinates(packets) do defp filter_valid_coordinates(packets) do
Enum.filter(packets, fn packet -> Enum.filter(packets, fn packet ->
lat = decimal_to_float(Map.get(packet, :lat)) lat = decimal_to_float(Map.get(packet, :lat, Map.get(packet, "lat")))
lon = decimal_to_float(Map.get(packet, :lon)) lon = decimal_to_float(Map.get(packet, :lon, Map.get(packet, "lon")))
not is_nil(lat) and not is_nil(lon) and not is_nil(lat) and not is_nil(lon) and
lat >= -90 and lat <= 90 and lat >= -90 and lat <= 90 and
@ -96,8 +96,8 @@ defmodule Aprsme.Packets.Clustering do
defp perform_clustering(packets, radius) do defp perform_clustering(packets, radius) do
packets packets
|> Enum.reduce(%{}, fn packet, clusters -> |> Enum.reduce(%{}, fn packet, clusters ->
lat = decimal_to_float(Map.get(packet, :lat)) lat = decimal_to_float(Map.get(packet, :lat, Map.get(packet, "lat")))
lon = decimal_to_float(Map.get(packet, :lon)) lon = decimal_to_float(Map.get(packet, :lon, Map.get(packet, "lon")))
# Find cluster key by rounding to grid # Find cluster key by rounding to grid
cluster_lat = Float.round(lat / radius) * radius cluster_lat = Float.round(lat / radius) * radius

View file

@ -585,7 +585,7 @@ defmodule AprsmeWeb.MapLive.DataBuilder do
# Helper to get packet ID # Helper to get packet ID
@spec get_packet_id(map()) :: any() @spec get_packet_id(map()) :: any()
defp get_packet_id(packet) do defp get_packet_id(packet) do
Map.get(packet, :id) Map.get(packet, :id, Map.get(packet, "id"))
end end
# Helper to get packet received_at datetime # Helper to get packet received_at datetime

View file

@ -49,7 +49,7 @@ defmodule AprsmeWeb.MapLive.HistoricalLoader do
end end
# Increment generation to invalidate any in-flight loads # Increment generation to invalidate any in-flight loads
new_generation = socket.assigns.loading_generation + 1 new_generation = Map.get(socket.assigns, :loading_generation, 0) + 1
# Cancel any pending batch tasks # Cancel any pending batch tasks
socket = cancel_pending_loads(socket) socket = cancel_pending_loads(socket)
@ -99,7 +99,7 @@ defmodule AprsmeWeb.MapLive.HistoricalLoader do
end end
def load_historical_batch(socket, batch_offset, generation) do def load_historical_batch(socket, batch_offset, generation) do
if generation == socket.assigns.loading_generation do if generation == Map.get(socket.assigns, :loading_generation, 0) do
do_load_historical_batch(socket, batch_offset) do_load_historical_batch(socket, batch_offset)
else else
# Stale request, skip # Stale request, skip
@ -330,7 +330,7 @@ defmodule AprsmeWeb.MapLive.HistoricalLoader do
defp maybe_schedule_next_batch(socket, batch_offset, false) do defp maybe_schedule_next_batch(socket, batch_offset, false) do
next_batch = batch_offset + 1 next_batch = batch_offset + 1
generation = socket.assigns.loading_generation generation = Map.get(socket.assigns, :loading_generation, 0)
timer_ref = Process.send_after(self(), {:load_historical_batch, next_batch, generation}, 50) timer_ref = Process.send_after(self(), {:load_historical_batch, next_batch, generation}, 50)
assign(socket, :pending_batch_tasks, [timer_ref | socket.assigns.pending_batch_tasks]) assign(socket, :pending_batch_tasks, [timer_ref | socket.assigns.pending_batch_tasks])

View file

@ -351,13 +351,15 @@ defmodule AprsmeWeb.MapLive.Index do
def handle_info({:load_historical_batch, batch_offset}, socket) do def handle_info({:load_historical_batch, batch_offset}, socket) do
# For backward compatibility with old messages # For backward compatibility with old messages
socket = HistoricalLoader.load_historical_batch(socket, batch_offset, socket.assigns.loading_generation) socket =
HistoricalLoader.load_historical_batch(socket, batch_offset, Map.get(socket.assigns, :loading_generation, 0))
{:noreply, socket} {:noreply, socket}
end end
def handle_info({:load_historical_batch, batch_offset, generation}, socket) do def handle_info({:load_historical_batch, batch_offset, generation}, socket) do
# Only process if generation matches current loading generation # Only process if generation matches current loading generation
if generation == socket.assigns.loading_generation do if generation == Map.get(socket.assigns, :loading_generation, 0) do
socket = HistoricalLoader.load_historical_batch(socket, batch_offset, generation) socket = HistoricalLoader.load_historical_batch(socket, batch_offset, generation)
{:noreply, socket} {:noreply, socket}
else else
@ -368,7 +370,7 @@ defmodule AprsmeWeb.MapLive.Index do
def handle_info({:historical_loading_timeout, generation}, socket) do def handle_info({:historical_loading_timeout, generation}, socket) do
# Only process if generation matches current loading generation and we're still loading # Only process if generation matches current loading generation and we're still loading
if generation == socket.assigns.loading_generation && socket.assigns.historical_loading do if generation == Map.get(socket.assigns, :loading_generation, 0) && socket.assigns.historical_loading do
Logger.warning("Historical loading timeout reached, forcing completion") Logger.warning("Historical loading timeout reached, forcing completion")
socket = socket =

View file

@ -23,9 +23,9 @@ defmodule AprsmeWeb.Live.Shared.CoordinateUtils do
end end
def get_coordinates(packet) do def get_coordinates(packet) do
lat = Map.get(packet, :lat) lat = Map.get(packet, :lat, Map.get(packet, "lat"))
lon = Map.get(packet, :lon) lon = Map.get(packet, :lon, Map.get(packet, "lon"))
data_extended = Map.get(packet, :data_extended) data_extended = Map.get(packet, :data_extended, Map.get(packet, "data_extended"))
{lat, lon, data_extended} {lat, lon, data_extended}
end end
@ -64,8 +64,8 @@ defmodule AprsmeWeb.Live.Shared.CoordinateUtils do
""" """
@spec has_position_data?(map()) :: boolean() @spec has_position_data?(map()) :: boolean()
def has_position_data?(packet) do def has_position_data?(packet) do
lat = Map.get(packet, :lat) lat = Map.get(packet, :lat, Map.get(packet, "lat"))
lon = Map.get(packet, :lon) lon = Map.get(packet, :lon, Map.get(packet, "lon"))
has_direct_coordinates?(lat, lon) or has_position_in_data_extended?(packet) has_direct_coordinates?(lat, lon) or has_position_in_data_extended?(packet)
end end
@ -130,7 +130,7 @@ defmodule AprsmeWeb.Live.Shared.CoordinateUtils do
defp has_direct_coordinates?(_, _), do: false defp has_direct_coordinates?(_, _), do: false
defp has_position_in_data_extended?(packet) do defp has_position_in_data_extended?(packet) do
data_extended = Map.get(packet, :data_extended) data_extended = Map.get(packet, :data_extended, Map.get(packet, "data_extended"))
has_position_in_data_extended_case?(data_extended) has_position_in_data_extended_case?(data_extended)
end end

View file

@ -37,7 +37,7 @@ defmodule AprsmeWeb.Live.SharedPacketHandler do
Checks if packet sender matches the given callsign. Checks if packet sender matches the given callsign.
""" """
def packet_matches_callsign?(packet, callsign) do def packet_matches_callsign?(packet, callsign) do
packet_sender = Map.get(packet, :sender, "") packet_sender = Map.get(packet, "sender", Map.get(packet, :sender, ""))
Callsign.matches?(packet_sender, callsign) Callsign.matches?(packet_sender, callsign)
end end

View file

@ -135,7 +135,7 @@ defmodule AprsmeWeb.Live.Shared.PacketUtils do
case Map.get(packet, to_string(field)) do case Map.get(packet, to_string(field)) do
nil -> nil ->
de = de =
Map.get(packet, :data_extended) || %{} Map.get(packet, :data_extended, Map.get(packet, "data_extended")) || %{}
Map.get(de, field) || Map.get(de, to_string(field)) || default Map.get(de, field) || Map.get(de, to_string(field)) || default