fix: guard pubsub APIs when not running
This commit is contained in:
parent
1e98a71431
commit
4d45c8351a
4 changed files with 120 additions and 10 deletions
|
|
@ -18,42 +18,64 @@ defmodule Aprsme.SpatialPubSub do
|
|||
Register a client with their current viewport bounds.
|
||||
"""
|
||||
def register_viewport(client_id, bounds) do
|
||||
GenServer.call(__MODULE__, {:register_viewport, client_id, bounds})
|
||||
with_server({:error, :not_running}, fn ->
|
||||
GenServer.call(__MODULE__, {:register_viewport, client_id, bounds})
|
||||
end)
|
||||
end
|
||||
|
||||
@doc """
|
||||
Update a client's viewport bounds.
|
||||
"""
|
||||
def update_viewport(client_id, bounds) do
|
||||
GenServer.call(__MODULE__, {:update_viewport, client_id, bounds})
|
||||
with_server({:error, :not_running}, fn ->
|
||||
GenServer.call(__MODULE__, {:update_viewport, client_id, bounds})
|
||||
end)
|
||||
end
|
||||
|
||||
@doc """
|
||||
Unregister a client.
|
||||
"""
|
||||
def unregister_client(client_id) do
|
||||
GenServer.cast(__MODULE__, {:unregister_client, client_id})
|
||||
with_server(:ok, fn ->
|
||||
GenServer.cast(__MODULE__, {:unregister_client, client_id})
|
||||
end)
|
||||
end
|
||||
|
||||
@doc """
|
||||
Broadcast a packet to all clients whose viewports contain the packet's location.
|
||||
"""
|
||||
def broadcast_packet(packet) do
|
||||
GenServer.cast(__MODULE__, {:broadcast_packet, packet})
|
||||
with_server(:ok, fn ->
|
||||
GenServer.cast(__MODULE__, {:broadcast_packet, packet})
|
||||
end)
|
||||
end
|
||||
|
||||
@doc """
|
||||
Get statistics about spatial filtering.
|
||||
"""
|
||||
def get_stats do
|
||||
GenServer.call(__MODULE__, :get_stats)
|
||||
with_server(
|
||||
%{
|
||||
total_broadcasts: 0,
|
||||
filtered_broadcasts: 0,
|
||||
total_packets: 0,
|
||||
clients_count: 0,
|
||||
grid_cells: 0,
|
||||
avg_clients_per_cell: 0.0
|
||||
},
|
||||
fn ->
|
||||
GenServer.call(__MODULE__, :get_stats)
|
||||
end
|
||||
)
|
||||
end
|
||||
|
||||
@doc """
|
||||
Start telemetry reporting for LiveDashboard integration.
|
||||
"""
|
||||
def start_telemetry_reporting do
|
||||
GenServer.cast(__MODULE__, :start_telemetry_reporting)
|
||||
with_server(:ok, fn ->
|
||||
GenServer.cast(__MODULE__, :start_telemetry_reporting)
|
||||
end)
|
||||
end
|
||||
|
||||
# Server callbacks
|
||||
|
|
@ -439,4 +461,12 @@ defmodule Aprsme.SpatialPubSub do
|
|||
%{}
|
||||
)
|
||||
end
|
||||
|
||||
defp with_server(default, fun) do
|
||||
if Process.whereis(__MODULE__) do
|
||||
fun.()
|
||||
else
|
||||
default
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -32,28 +32,36 @@ defmodule Aprsme.StreamingPacketsPubSub do
|
|||
- :ok
|
||||
"""
|
||||
def subscribe_to_bounds(pid, bounds) do
|
||||
GenServer.call(__MODULE__, {:subscribe, pid, bounds})
|
||||
with_server({:error, :not_running}, fn ->
|
||||
GenServer.call(__MODULE__, {:subscribe, pid, bounds})
|
||||
end)
|
||||
end
|
||||
|
||||
@doc """
|
||||
Unsubscribe from packet notifications.
|
||||
"""
|
||||
def unsubscribe(pid) do
|
||||
GenServer.call(__MODULE__, {:unsubscribe, pid})
|
||||
with_server(:ok, fn ->
|
||||
GenServer.call(__MODULE__, {:unsubscribe, pid})
|
||||
end)
|
||||
end
|
||||
|
||||
@doc """
|
||||
Broadcast a packet to all subscribers whose bounds contain the packet's location.
|
||||
"""
|
||||
def broadcast_packet(packet) do
|
||||
GenServer.cast(__MODULE__, {:broadcast, packet})
|
||||
with_server(:ok, fn ->
|
||||
GenServer.cast(__MODULE__, {:broadcast, packet})
|
||||
end)
|
||||
end
|
||||
|
||||
@doc """
|
||||
List all active subscribers and their bounds.
|
||||
"""
|
||||
def list_subscribers do
|
||||
GenServer.call(__MODULE__, :list_subscribers)
|
||||
with_server([], fn ->
|
||||
GenServer.call(__MODULE__, :list_subscribers)
|
||||
end)
|
||||
end
|
||||
|
||||
# Server Callbacks
|
||||
|
|
@ -200,4 +208,12 @@ defmodule Aprsme.StreamingPacketsPubSub do
|
|||
defp test_env? do
|
||||
Application.get_env(:aprsme, :env) == :test
|
||||
end
|
||||
|
||||
defp with_server(default, fun) do
|
||||
if Process.whereis(__MODULE__) do
|
||||
fun.()
|
||||
else
|
||||
default
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -97,4 +97,41 @@ defmodule Aprsme.SpatialPubSubTest do
|
|||
SpatialPubSub.unregister_client(client_id)
|
||||
end
|
||||
end
|
||||
|
||||
describe "when the server is not running" do
|
||||
setup do
|
||||
pid = Process.whereis(SpatialPubSub)
|
||||
|
||||
if pid do
|
||||
GenServer.stop(pid)
|
||||
end
|
||||
|
||||
on_exit(fn ->
|
||||
if !Process.whereis(SpatialPubSub) do
|
||||
start_supervised!({SpatialPubSub, []})
|
||||
end
|
||||
end)
|
||||
|
||||
:ok
|
||||
end
|
||||
|
||||
test "public APIs return safe defaults instead of crashing" do
|
||||
bounds = %{north: 41.0, south: 40.0, east: -73.0, west: -74.0}
|
||||
|
||||
assert {:error, :not_running} = SpatialPubSub.register_viewport("missing", bounds)
|
||||
assert {:error, :not_running} = SpatialPubSub.update_viewport("missing", bounds)
|
||||
assert :ok = SpatialPubSub.unregister_client("missing")
|
||||
assert :ok = SpatialPubSub.broadcast_packet(%{lat: 40.5, lon: -73.5})
|
||||
assert :ok = SpatialPubSub.start_telemetry_reporting()
|
||||
|
||||
assert SpatialPubSub.get_stats() == %{
|
||||
total_broadcasts: 0,
|
||||
filtered_broadcasts: 0,
|
||||
total_packets: 0,
|
||||
clients_count: 0,
|
||||
grid_cells: 0,
|
||||
avg_clients_per_cell: 0.0
|
||||
}
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -140,6 +140,33 @@ defmodule Aprsme.StreamingPacketsPubSubTest do
|
|||
end
|
||||
end
|
||||
|
||||
describe "when the server is not running" do
|
||||
setup do
|
||||
pid = Process.whereis(StreamingPacketsPubSub)
|
||||
|
||||
if pid do
|
||||
GenServer.stop(pid)
|
||||
end
|
||||
|
||||
on_exit(fn ->
|
||||
if !Process.whereis(StreamingPacketsPubSub) do
|
||||
start_supervised!({StreamingPacketsPubSub, []})
|
||||
end
|
||||
end)
|
||||
|
||||
:ok
|
||||
end
|
||||
|
||||
test "returns safe defaults instead of crashing" do
|
||||
bounds = %{north: 40.0, south: 30.0, east: -70.0, west: -80.0}
|
||||
|
||||
assert {:error, :not_running} = StreamingPacketsPubSub.subscribe_to_bounds(self(), bounds)
|
||||
assert :ok = StreamingPacketsPubSub.unsubscribe(self())
|
||||
assert :ok = StreamingPacketsPubSub.broadcast_packet(%{latitude: 35.0, longitude: -75.0})
|
||||
assert [] == StreamingPacketsPubSub.list_subscribers()
|
||||
end
|
||||
end
|
||||
|
||||
describe "performance" do
|
||||
test "handles high volume of packets efficiently" do
|
||||
bounds = %{north: 90.0, south: -90.0, east: 180.0, west: -180.0}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue