From 001af2228632337bfe83a9e92cb097ffc1ee5dd3 Mon Sep 17 00:00:00 2001 From: Graham McIntire Date: Fri, 8 May 2026 17:49:23 -0500 Subject: [PATCH] Remove dead code: round_coordinate non-float heads, unreachable get_nearby_stations branch, redundant pattern-match guards --- lib/aprsme/packet.ex | 58 +++++-------------- lib/aprsme/packets.ex | 80 +++++++++------------------ lib/aprsme_web/live/map_live/index.ex | 28 ++++------ 3 files changed, 49 insertions(+), 117 deletions(-) diff --git a/lib/aprsme/packet.ex b/lib/aprsme/packet.ex index b134ee9..f4bb4ca 100644 --- a/lib/aprsme/packet.ex +++ b/lib/aprsme/packet.ex @@ -657,22 +657,11 @@ defmodule Aprsme.Packet do defp process_weather_data(attrs, weather_data) do case weather_data do - weather when is_binary(weather) -> - process_binary_weather_data(attrs, weather) - - weather when is_map(weather) -> - process_map_weather_data(attrs, weather) - - _ -> - attrs + weather when is_map(weather) -> process_map_weather_data(attrs, weather) + _ -> attrs end end - defp process_binary_weather_data(attrs, _weather) do - # If you have a weather parsing function, call it here - attrs - end - defp process_map_weather_data(attrs, weather) do weather = Map.drop(weather, [:raw_weather_data, "raw_weather_data"]) @@ -791,21 +780,12 @@ defmodule Aprsme.Packet do ) end - # Extract altitude from APRS comment field (e.g., "/A=000680" means 680 feet) - defp extract_altitude_from_comment(nil), do: nil - + # Extract altitude from APRS comment field (e.g., "/A=000680" means 680 feet). + # The regex captures exactly six digits, so Integer.parse always succeeds. defp extract_altitude_from_comment(comment) when is_binary(comment) do case Regex.run(~r/\/A=(\d{6})/, comment) do - [_, altitude_str] -> - # Convert string to integer (altitude in feet) - case Integer.parse(altitude_str) do - # Convert to float - {altitude, _} -> altitude * 1.0 - _ -> nil - end - - _ -> - nil + [_, altitude_str] -> String.to_integer(altitude_str) * 1.0 + _ -> nil end end @@ -831,30 +811,18 @@ defmodule Aprsme.Packet do defp extract_phg_from_comment(_), do: nil + # The PHG regex captures single digits 0-9, so Integer.parse always + # succeeds and the value is always in 0..9. No fallback clauses needed. + # PHG power calculation: power = n^2 watts - defp calculate_phg_power(n) when is_binary(n) do - case Integer.parse(n) do - {num, _} -> num * num - _ -> 0 - end - end + defp calculate_phg_power(<>) when n in ?0..?9, do: (n - ?0) * (n - ?0) # PHG height calculation: height = 10 * 2^n feet - defp calculate_phg_height(n) when is_binary(n) do - case Integer.parse(n) do - {num, _} -> 10 * trunc(:math.pow(2, num)) - _ -> 10 - end - end + defp calculate_phg_height(<>) when n in ?0..?9, do: 10 * trunc(:math.pow(2, n - ?0)) # PHG directivity: 0-8 = directional (n * 45 degrees), 9 = omni (360 degrees) - defp calculate_phg_directivity(n) when is_binary(n) do - case Integer.parse(n) do - {9, _} -> 360 - {num, _} when num >= 0 and num <= 8 -> num * 45 - _ -> 0 - end - end + defp calculate_phg_directivity(<>), do: 360 + defp calculate_phg_directivity(<>) when n in ?0..?8, do: (n - ?0) * 45 # Normalize format field from atom to string defp normalize_format_field(nil), do: nil diff --git a/lib/aprsme/packets.ex b/lib/aprsme/packets.ex index 985b1df..7120a72 100644 --- a/lib/aprsme/packets.ex +++ b/lib/aprsme/packets.ex @@ -100,18 +100,10 @@ defmodule Aprsme.Packets do end defp normalize_packet_attrs(packet_data) do - case_result = - case packet_data do - %Packet{} = packet -> - packet - |> Map.from_struct() - |> Map.delete(:__meta__) - - %{} -> - packet_data - end - - case_result + # store_packet's rescue branch indexes packet_data[:sender], which only works + # on plain maps — Packet structs would raise. So normalize_packet_attrs only + # ever sees a plain map here. + packet_data |> Aprsme.EncodingUtils.sanitize_packet() |> normalize_data_type() end @@ -147,9 +139,7 @@ defmodule Aprsme.Packets do defp normalize_to_map(%{__struct__: _} = struct), do: Map.from_struct(struct) defp normalize_to_map(map) when is_map(map), do: map - # Safe decimal conversion with pattern matching - defp to_decimal_safe(nil), do: {:error, :nil_value} - + # Callers guard with `when not is_nil(value)`, so we never see nil here. defp to_decimal_safe(value) do case Aprsme.EncodingUtils.to_decimal(value) do nil -> {:error, :conversion_failed} @@ -166,15 +156,14 @@ defmodule Aprsme.Packets do extract_coordinate(ext_map, :longitude) end - # Unified coordinate extraction with pattern matching - defp extract_coordinate(%{} = map, coord_type) when coord_type in [:latitude, :longitude] do + # Callers always pass a map (patch_lat_lon_from_data_extended pattern-matches + # %{data_extended: %{} = ext} before calling, then wraps via normalize_to_map). + defp extract_coordinate(map, coord_type) when coord_type in [:latitude, :longitude] do coord_string = Atom.to_string(coord_type) find_coordinate_value(map, coord_type) || find_coordinate_value(map, coord_string) end - defp extract_coordinate(_, _), do: nil - # Pattern matching for direct coordinate access defp find_coordinate_value(%{latitude: lat}, :latitude) when not is_nil(lat), do: lat defp find_coordinate_value(%{longitude: lon}, :longitude) when not is_nil(lon), do: lon @@ -200,20 +189,10 @@ defmodule Aprsme.Packets do |> Map.put(:lon, round_coordinate(lon)) end - # Moved out as a separate function to avoid recreating on each call + # extract_position runs values through EncodingUtils.to_float, so by the + # time round_coordinate sees them they're either float or nil. defp round_coordinate(nil), do: nil - defp round_coordinate(%Decimal{} = d), do: Decimal.round(d, 6) defp round_coordinate(n) when is_float(n), do: Float.round(n, 6) - defp round_coordinate(n) when is_integer(n), do: n * 1.0 - - defp round_coordinate(n) when is_binary(n) do - case Float.parse(n) do - {f, _} -> Float.round(f, 6) - :error -> nil - end - end - - defp round_coordinate(_), do: nil # Pattern matching for SSID normalization defp normalize_ssid(%{ssid: nil} = attrs), do: attrs @@ -474,8 +453,7 @@ defmodule Aprsme.Packets do case Repo.one(query) do nil -> 0 - count when is_integer(count) -> count - _ -> 0 + count -> count end rescue _ -> 0 @@ -575,27 +553,21 @@ defmodule Aprsme.Packets do @impl true @spec get_nearby_stations(float(), float(), String.t() | nil, map()) :: [struct()] def get_nearby_stations(lat, lon, exclude_callsign \\ nil, opts \\ %{}) do - # Use KNN (K-nearest neighbors) query for better performance - results = PreparedQueries.get_nearby_stations_knn(lat, lon, exclude_callsign, opts) - - # Convert results back to Packet structs if needed - Enum.map(results, fn result -> - # If result is already a Packet struct, return it - if is_struct(result, Packet) do - result - else - # Otherwise, create a minimal Packet struct from the map - %Packet{ - sender: result.callsign, - base_callsign: result.base_callsign, - lat: result.lat, - lon: result.lon, - received_at: result.received_at, - symbol_table_id: result.symbol_table_id, - symbol_code: result.symbol_code, - comment: result.comment - } - end + # PreparedQueries returns plain maps from a select clause; wrap each in a + # minimal Packet struct so callers get the shape they expect. + lat + |> PreparedQueries.get_nearby_stations_knn(lon, exclude_callsign, opts) + |> Enum.map(fn result -> + %Packet{ + sender: result.callsign, + base_callsign: result.base_callsign, + lat: result.lat, + lon: result.lon, + received_at: result.received_at, + symbol_table_id: result.symbol_table_id, + symbol_code: result.symbol_code, + comment: result.comment + } end) end diff --git a/lib/aprsme_web/live/map_live/index.ex b/lib/aprsme_web/live/map_live/index.ex index 846975a..3d2b787 100644 --- a/lib/aprsme_web/live/map_live/index.ex +++ b/lib/aprsme_web/live/map_live/index.ex @@ -66,10 +66,12 @@ defmodule AprsmeWeb.MapLive.Index do # Handle callsign tracking - check path params first, then query params tracked_callsign = - case Map.get(params, "callsign", Map.get(params, "call", "")) do - "" -> "" - nil -> "" - callsign -> callsign |> String.trim() |> String.upcase() + case Map.get(params, "callsign") || Map.get(params, "call") do + callsign when is_binary(callsign) and callsign != "" -> + callsign |> String.trim() |> String.upcase() + + _ -> + "" end {final_map_center, final_map_zoom} = @@ -1114,20 +1116,10 @@ defmodule AprsmeWeb.MapLive.Index do defp update_display_for_batch(socket, []), do: socket - defp update_display_for_batch(socket, marker_data_list) do - tracked_callsign = socket.assigns.tracked_callsign || "" - - if socket.assigns.map_zoom <= 8 do - # If tracking a callsign, send trail line instead of heat map - if tracked_callsign == "" do - DisplayManager.send_heat_map_for_current_bounds(socket) - else - DisplayManager.send_trail_line_for_tracked_callsign(socket) - end - else - send_marker_batch(socket, marker_data_list) - end - end + # PacketProcessor.build_marker_data returns nil when zoom <= 8, so by the time + # marker_data_list is non-empty here, zoom is always > 8. Heat-map / trail-line + # rendering for low-zoom packet batches happens inside the per-packet handler. + defp update_display_for_batch(socket, marker_data_list), do: send_marker_batch(socket, marker_data_list) defp send_marker_batch(socket, marker_data_list) do reversed = Enum.reverse(marker_data_list)