Live-update contact detail page when enrichment completes
- HRRR and terrain workers broadcast via PubSub on completion - Contact show page subscribes and recomputes elevation profile, propagation analysis, and HRRR data on receipt - Page updates in-place without reload when background jobs finish
This commit is contained in:
parent
0503fb3799
commit
d207863b15
4 changed files with 66 additions and 0 deletions
|
|
@ -34,6 +34,7 @@ defmodule Microwaveprop.Workers.HrrrFetchWorker do
|
||||||
{:ok, grid_data} ->
|
{:ok, grid_data} ->
|
||||||
Enum.each(grid_data, fn {{lat, lon}, data} ->
|
Enum.each(grid_data, fn {{lat, lon}, data} ->
|
||||||
store_profile(lat, lon, valid_time, data)
|
store_profile(lat, lon, valid_time, data)
|
||||||
|
broadcast_enrichment(lat, lon, valid_time)
|
||||||
end)
|
end)
|
||||||
|
|
||||||
Logger.info("HRRR batch: saved #{map_size(grid_data)} profiles for #{valid_time_str}")
|
Logger.info("HRRR batch: saved #{map_size(grid_data)} profiles for #{valid_time_str}")
|
||||||
|
|
@ -59,6 +60,7 @@ defmodule Microwaveprop.Workers.HrrrFetchWorker do
|
||||||
case HrrrClient.fetch_profile(lat, lon, valid_time) do
|
case HrrrClient.fetch_profile(lat, lon, valid_time) do
|
||||||
{:ok, data} ->
|
{:ok, data} ->
|
||||||
store_profile(lat, lon, valid_time, data)
|
store_profile(lat, lon, valid_time, data)
|
||||||
|
broadcast_enrichment(lat, lon, valid_time)
|
||||||
:ok
|
:ok
|
||||||
|
|
||||||
{:error, reason} ->
|
{:error, reason} ->
|
||||||
|
|
@ -123,4 +125,12 @@ defmodule Microwaveprop.Workers.HrrrFetchWorker do
|
||||||
duct_characteristics: params.duct_characteristics
|
duct_characteristics: params.duct_characteristics
|
||||||
})
|
})
|
||||||
end
|
end
|
||||||
|
|
||||||
|
defp broadcast_enrichment(lat, lon, valid_time) do
|
||||||
|
Phoenix.PubSub.broadcast(
|
||||||
|
Microwaveprop.PubSub,
|
||||||
|
"contact_enrichment:hrrr",
|
||||||
|
{:hrrr_ready, %{lat: lat, lon: lon, valid_time: valid_time}}
|
||||||
|
)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
||||||
|
|
@ -56,6 +56,12 @@ defmodule Microwaveprop.Workers.TerrainProfileWorker do
|
||||||
verdict: analysis.verdict
|
verdict: analysis.verdict
|
||||||
})
|
})
|
||||||
|
|
||||||
|
Phoenix.PubSub.broadcast(
|
||||||
|
Microwaveprop.PubSub,
|
||||||
|
"contact_enrichment:#{qso_id}",
|
||||||
|
{:terrain_ready, qso_id}
|
||||||
|
)
|
||||||
|
|
||||||
:ok
|
:ok
|
||||||
|
|
||||||
{:error, reason} ->
|
{:error, reason} ->
|
||||||
|
|
|
||||||
|
|
@ -21,6 +21,11 @@ defmodule MicrowavepropWeb.ContactLive.Show do
|
||||||
def mount(%{"id" => id}, _session, socket) do
|
def mount(%{"id" => id}, _session, socket) do
|
||||||
contact = Radio.get_contact!(id)
|
contact = Radio.get_contact!(id)
|
||||||
|
|
||||||
|
if connected?(socket) do
|
||||||
|
Phoenix.PubSub.subscribe(Microwaveprop.PubSub, "contact_enrichment:#{contact.id}")
|
||||||
|
Phoenix.PubSub.subscribe(Microwaveprop.PubSub, "contact_enrichment:hrrr")
|
||||||
|
end
|
||||||
|
|
||||||
weather = load_weather(contact)
|
weather = load_weather(contact)
|
||||||
solar = load_solar(contact)
|
solar = load_solar(contact)
|
||||||
hrrr_path = Weather.hrrr_profiles_for_path(contact)
|
hrrr_path = Weather.hrrr_profiles_for_path(contact)
|
||||||
|
|
@ -106,6 +111,47 @@ defmodule MicrowavepropWeb.ContactLive.Show do
|
||||||
)}
|
)}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@impl true
|
||||||
|
def handle_info({:terrain_ready, _qso_id}, socket) do
|
||||||
|
contact = socket.assigns.contact
|
||||||
|
terrain = Terrain.get_terrain_profile(contact.id)
|
||||||
|
soundings = socket.assigns.soundings
|
||||||
|
hrrr_path = Weather.hrrr_profiles_for_path(contact)
|
||||||
|
hrrr = List.first(hrrr_path)
|
||||||
|
elevation_profile = compute_elevation_profile(contact, hrrr_path, soundings)
|
||||||
|
propagation_analysis = build_propagation_analysis(contact, hrrr, terrain, elevation_profile, soundings)
|
||||||
|
|
||||||
|
{:noreply,
|
||||||
|
assign(socket,
|
||||||
|
terrain: terrain,
|
||||||
|
elevation_profile: elevation_profile,
|
||||||
|
propagation_analysis: propagation_analysis
|
||||||
|
)}
|
||||||
|
end
|
||||||
|
|
||||||
|
def handle_info({:hrrr_ready, _info}, socket) do
|
||||||
|
contact = socket.assigns.contact
|
||||||
|
hrrr_path = Weather.hrrr_profiles_for_path(contact)
|
||||||
|
hrrr = List.first(hrrr_path)
|
||||||
|
|
||||||
|
if hrrr do
|
||||||
|
soundings = socket.assigns.soundings
|
||||||
|
terrain = socket.assigns.terrain
|
||||||
|
elevation_profile = compute_elevation_profile(contact, hrrr_path, soundings)
|
||||||
|
propagation_analysis = build_propagation_analysis(contact, hrrr, terrain, elevation_profile, soundings)
|
||||||
|
|
||||||
|
{:noreply,
|
||||||
|
assign(socket,
|
||||||
|
hrrr: hrrr,
|
||||||
|
hrrr_status: :loaded,
|
||||||
|
elevation_profile: elevation_profile,
|
||||||
|
propagation_analysis: propagation_analysis
|
||||||
|
)}
|
||||||
|
else
|
||||||
|
{:noreply, socket}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
defp toggle_sort(current_field, current_order, new_field) do
|
defp toggle_sort(current_field, current_order, new_field) do
|
||||||
if current_field == new_field && current_order == "asc",
|
if current_field == new_field && current_order == "asc",
|
||||||
do: {new_field, "desc"},
|
do: {new_field, "desc"},
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,10 @@ defmodule MicrowavepropWeb.ContactLiveTest do
|
||||||
Req.Test.json(conn, [])
|
Req.Test.json(conn, [])
|
||||||
end)
|
end)
|
||||||
|
|
||||||
|
Req.Test.stub(Microwaveprop.Weather.HrrrClient, fn conn ->
|
||||||
|
Plug.Conn.send_resp(conn, 404, "not found")
|
||||||
|
end)
|
||||||
|
|
||||||
:ok
|
:ok
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue