Turned on :error_handling, :underspecs, and :unmatched_returns in mix.exs dialyzer config. The 97 warnings this surfaced were fixed in place rather than suppressed: - unmatched_return (79): explicit discard with `_ = ...` for fire-and-forget side effects (Process.cancel_timer, :ets.new, send/2), and pattern-matched `:ok = ...` for control-plane Phoenix.PubSub subscribe/unsubscribe/broadcast calls so a future return-shape change fails loud. - contract_supertype (18): tightened @spec arg and return types on data_builder, historical_loader, url_params, packet_utils, encoding_utils, aprs_symbol, weather_controller, packet_replay to match each function's actual success typing. No behavioural change. mix compile clean, 1008 tests pass, dialyzer count is now 0.
57 lines
1.4 KiB
Elixir
57 lines
1.4 KiB
Elixir
defmodule Aprsme.Cluster.PacketDistributor do
|
|
@moduledoc """
|
|
Distributes APRS packets from the leader node to all cluster members.
|
|
This ensures all nodes can serve real-time updates via LiveView while
|
|
only the leader maintains the APRS-IS connection.
|
|
"""
|
|
use GenServer
|
|
|
|
alias Aprsme.Cluster.LeaderElection
|
|
|
|
@pubsub_topic "cluster:packets"
|
|
|
|
def start_link(opts) do
|
|
GenServer.start_link(__MODULE__, opts, name: __MODULE__)
|
|
end
|
|
|
|
def distribute_packet(packet) do
|
|
cluster_enabled = Application.get_env(:aprsme, :cluster_enabled, false)
|
|
|
|
if cluster_enabled and LeaderElection.leader_cached?() do
|
|
Phoenix.PubSub.broadcast(
|
|
Aprsme.PubSub,
|
|
@pubsub_topic,
|
|
{:distributed_packet, packet}
|
|
)
|
|
end
|
|
end
|
|
|
|
def subscribe do
|
|
Phoenix.PubSub.subscribe(Aprsme.PubSub, @pubsub_topic)
|
|
end
|
|
|
|
def handle_distributed_packet({:distributed_packet, packet}) do
|
|
Aprsme.StreamingPacketsPubSub.broadcast_packet(packet)
|
|
Aprsme.SpatialPubSub.broadcast_packet(packet)
|
|
|
|
:ok
|
|
end
|
|
|
|
@impl true
|
|
def handle_info({:distributed_packet, _packet} = msg, state) do
|
|
handle_distributed_packet(msg)
|
|
{:noreply, state}
|
|
end
|
|
|
|
@impl true
|
|
def init(_opts) do
|
|
:ok = Phoenix.PubSub.subscribe(Aprsme.PubSub, @pubsub_topic)
|
|
{:ok, %{}}
|
|
end
|
|
|
|
@impl true
|
|
def terminate(_reason, _state) do
|
|
_ = Phoenix.PubSub.unsubscribe(Aprsme.PubSub, @pubsub_topic)
|
|
:ok
|
|
end
|
|
end
|