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

View file

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

View file

@ -49,7 +49,7 @@ defmodule AprsmeWeb.MapLive.HistoricalLoader do
end
# 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
socket = cancel_pending_loads(socket)
@ -99,7 +99,7 @@ defmodule AprsmeWeb.MapLive.HistoricalLoader do
end
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)
else
# Stale request, skip
@ -330,7 +330,7 @@ defmodule AprsmeWeb.MapLive.HistoricalLoader do
defp maybe_schedule_next_batch(socket, batch_offset, false) do
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)
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
# 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}
end
def handle_info({:load_historical_batch, batch_offset, generation}, socket) do
# 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)
{:noreply, socket}
else
@ -368,7 +370,7 @@ defmodule AprsmeWeb.MapLive.Index do
def handle_info({:historical_loading_timeout, generation}, socket) do
# 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")
socket =

View file

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

View file

@ -37,7 +37,7 @@ defmodule AprsmeWeb.Live.SharedPacketHandler do
Checks if packet sender matches the given callsign.
"""
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)
end

View file

@ -135,7 +135,7 @@ defmodule AprsmeWeb.Live.Shared.PacketUtils do
case Map.get(packet, to_string(field)) do
nil ->
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