69 lines
2.3 KiB
Elixir
69 lines
2.3 KiB
Elixir
defmodule Aprsme.PostgresNotifier do
|
|
@moduledoc """
|
|
Listens to PostgreSQL NOTIFY events on the "aprs_events" and "aprs_packets" channels and broadcasts
|
|
them via Phoenix.PubSub for reactive, event-driven updates.
|
|
"""
|
|
use GenServer
|
|
|
|
@event_channel "aprs_events"
|
|
@event_topic "postgres:aprsme_events"
|
|
@packet_channel "aprs_packets"
|
|
@packet_topic "postgres:aprsme_packets"
|
|
|
|
def start_link(_opts) do
|
|
GenServer.start_link(__MODULE__, nil, name: __MODULE__)
|
|
end
|
|
|
|
@impl true
|
|
def init(_) do
|
|
{:ok, conn} = Postgrex.Notifications.start_link(Aprsme.Repo.config())
|
|
{:ok, _ref1} = Postgrex.Notifications.listen(conn, @event_channel)
|
|
{:ok, _ref2} = Postgrex.Notifications.listen(conn, @packet_channel)
|
|
{:ok, %{conn: conn}}
|
|
end
|
|
|
|
@impl true
|
|
def handle_info({:notification, _conn, _pid, @event_channel, payload}, state) do
|
|
Phoenix.PubSub.broadcast(Aprsme.PubSub, @event_topic, {:postgres_notify, payload})
|
|
{:noreply, state}
|
|
end
|
|
|
|
def handle_info({:notification, _conn, _pid, @packet_channel, payload}, state) do
|
|
case Jason.decode(payload) do
|
|
{:ok, packet} ->
|
|
# Broadcast to the general packet topic
|
|
Phoenix.PubSub.broadcast(Aprsme.PubSub, @packet_topic, {:postgres_packet, packet})
|
|
|
|
# Also broadcast to callsign-specific weather topic if it's a weather packet
|
|
broadcast_weather_packet_if_relevant(packet)
|
|
|
|
_ ->
|
|
:noop
|
|
end
|
|
|
|
{:noreply, state}
|
|
end
|
|
|
|
def handle_info(_msg, state), do: {:noreply, state}
|
|
|
|
defp broadcast_weather_packet_if_relevant(packet) do
|
|
# Check if this is a weather packet using centralized weather fields
|
|
has_weather_data =
|
|
Enum.any?(Aprsme.EncodingUtils.weather_fields(), fn field ->
|
|
value = Map.get(packet, to_string(field))
|
|
not is_nil(value)
|
|
end)
|
|
|
|
if has_weather_data do
|
|
# Extract callsign from packet
|
|
callsign = Map.get(packet, "sender") || Map.get(packet, :sender)
|
|
|
|
if is_binary(callsign) and callsign != "" do
|
|
# Normalize callsign and broadcast to weather-specific topic
|
|
normalized_callsign = String.upcase(String.trim(callsign))
|
|
weather_topic = "weather:#{normalized_callsign}"
|
|
Phoenix.PubSub.broadcast(Aprsme.PubSub, weather_topic, {:weather_packet, packet})
|
|
end
|
|
end
|
|
end
|
|
end
|