aprs.me/lib/aprsme_web/live/map_live/rf_path.ex

80 lines
2.1 KiB
Elixir

defmodule AprsmeWeb.MapLive.RfPath do
@moduledoc """
Handles RF path parsing and visualization for APRS packets.
"""
alias Aprsme.Packets
alias AprsmeWeb.MapLive.Utils
@doc """
Parse RF path string to extract digipeater/igate stations.
Excludes APRS-IS (Internet) paths that contain TCPIP.
APRS-IS path indicators:
- TCPIP: Packet came via Internet connection
- NOGATE: Should not be gated to RF
- qA*: Various APRS-IS q-constructs (qAC, qAS, qAR, etc.)
These are not actual RF digipeaters, so we don't show path lines for them.
"""
@spec parse_rf_path(binary()) :: list(binary())
def parse_rf_path(path) when is_binary(path) do
# Skip APRS-IS paths - these are Internet-only, not RF
if String.contains?(path, "TCPIP") or String.contains?(path, "NOGATE") or String.contains?(path, "qA") do
[]
else
path
|> String.split(",")
|> Enum.map(&String.trim/1)
|> Enum.map(&extract_callsign_from_path_element/1)
|> Enum.filter(&(&1 != ""))
|> Enum.uniq()
end
end
def parse_rf_path(_), do: []
@doc """
Get positions for path stations from the database.
"""
@spec get_path_station_positions(list(binary()), Phoenix.LiveView.Socket.t()) :: list(map())
def get_path_station_positions(path_stations, _socket) do
# Limit to prevent excessive database queries
limited_stations = Enum.take(path_stations, 10)
limited_stations
|> Enum.map(&get_station_position/1)
|> Enum.filter(& &1)
end
defp extract_callsign_from_path_element(element) do
# Remove asterisk (used flag) and extract callsign
element
|> String.replace("*", "")
|> String.trim()
|> String.upcase()
|> validate_path_callsign()
end
defp validate_path_callsign(callsign) do
if Utils.valid_callsign?(callsign) do
callsign
else
""
end
end
defp get_station_position(callsign) do
case Packets.get_latest_packet_for_callsign(callsign) do
%{lat: lat, lon: lon} when is_number(lat) and is_number(lon) ->
%{
callsign: callsign,
lat: lat,
lng: lon
}
_ ->
nil
end
end
end