Never download SRTM tiles during page load, only in Oban workers

- Srtm.lookup no longer auto-downloads by default, requires download: true
- TerrainProfileWorker passes download: true for background tile fetch
- Contact detail page enqueues TerrainProfileWorker if profile missing
- Page load gracefully handles missing tiles via API fallback or nil
This commit is contained in:
Graham McIntire 2026-04-02 08:07:26 -05:00
parent ebd22ce156
commit fd00de7bc6
No known key found for this signature in database
GPG key ID: F4ABF488E6029E59
5 changed files with 33 additions and 13 deletions

View file

@ -7,16 +7,16 @@ defmodule Microwaveprop.Terrain.ElevationClient do
@batch_size 100
@spec fetch_elevation_profile(float(), float(), float(), float(), pos_integer()) ::
@spec fetch_elevation_profile(float(), float(), float(), float(), pos_integer(), keyword()) ::
{:ok, list(map())} | {:error, String.t()}
def fetch_elevation_profile(lat1, lon1, lat2, lon2, n \\ 64) do
def fetch_elevation_profile(lat1, lon1, lat2, lon2, n \\ 64, opts \\ []) do
case srtm_tiles_dir() do
nil ->
Logger.debug("SRTM tiles_dir not configured, using API")
fetch_elevation_profile_api(lat1, lon1, lat2, lon2, n)
tiles_dir ->
case Srtm.fetch_elevation_profile(lat1, lon1, lat2, lon2, tiles_dir, n) do
case Srtm.fetch_elevation_profile(lat1, lon1, lat2, lon2, tiles_dir, n, opts) do
{:ok, _profile} = ok ->
Logger.info("Elevation profile served from SRTM tiles")
ok

View file

@ -51,9 +51,9 @@ defmodule Microwaveprop.Terrain.Srtm do
end
end
@spec lookup(float(), float(), String.t()) ::
@spec lookup(float(), float(), String.t(), keyword()) ::
{:ok, integer()} | {:error, :no_tile} | {:error, :void}
def lookup(lat, lon, tiles_dir) do
def lookup(lat, lon, tiles_dir, opts \\ []) do
path = Path.join(tiles_dir, tile_filename(lat, lon))
case :file.open(path, [:read, :binary, :raw]) do
@ -61,9 +61,9 @@ defmodule Microwaveprop.Terrain.Srtm do
read_elevation(fd, lat, lon)
{:error, :enoent} ->
if File.dir?(tiles_dir) do
if opts[:download] && File.dir?(tiles_dir) do
case download_tile(lat, lon, tiles_dir) do
{:ok, _path} ->
{:ok, _} ->
case :file.open(path, [:read, :binary, :raw]) do
{:ok, fd} -> read_elevation(fd, lat, lon)
{:error, _} -> {:error, :no_tile}
@ -78,15 +78,15 @@ defmodule Microwaveprop.Terrain.Srtm do
end
end
@spec fetch_elevation_profile(float(), float(), float(), float(), String.t(), pos_integer()) ::
@spec fetch_elevation_profile(float(), float(), float(), float(), String.t(), pos_integer(), keyword()) ::
{:ok, list(map())} | {:error, term()}
def fetch_elevation_profile(lat1, lon1, lat2, lon2, tiles_dir, n \\ 64) do
def fetch_elevation_profile(lat1, lon1, lat2, lon2, tiles_dir, n \\ 64, opts \\ []) do
pts = sample_path(lat1, lon1, lat2, lon2, n)
dist_km = haversine_km(lat1, lon1, lat2, lon2)
results =
Enum.reduce_while(pts, {:ok, []}, fn pt, {:ok, acc} ->
case lookup(pt.lat, pt.lon, tiles_dir) do
case lookup(pt.lat, pt.lon, tiles_dir, opts) do
{:ok, elev} ->
entry = %{
lat: pt.lat,

View file

@ -29,7 +29,7 @@ defmodule Microwaveprop.Workers.TerrainProfileWorker do
# Look up HRRR refractivity gradient for dynamic k-factor
k = lookup_k_factor(contact)
case ElevationClient.fetch_elevation_profile(lat1, lon1, lat2, lon2) do
case ElevationClient.fetch_elevation_profile(lat1, lon1, lat2, lon2, 64, download: true) do
{:ok, profile} ->
analysis = TerrainAnalysis.analyse(profile, dist_km, freq_ghz, k_factor: k)

View file

@ -13,6 +13,7 @@ defmodule MicrowavepropWeb.ContactLive.Show do
alias Microwaveprop.Weather
# alias Microwaveprop.Weather.HrrrClient
# alias Microwaveprop.Workers.HrrrFetchWorker
alias Microwaveprop.Workers.TerrainProfileWorker
@earth_radius_m 6_371_000.0
@ -26,6 +27,7 @@ defmodule MicrowavepropWeb.ContactLive.Show do
hrrr = List.first(hrrr_path)
{hrrr, hrrr_status} = maybe_enqueue_hrrr(hrrr, contact)
terrain = Terrain.get_terrain_profile(contact.id)
maybe_enqueue_terrain(terrain, contact)
elevation_profile = compute_elevation_profile(contact, hrrr_path, weather.soundings)
propagation_analysis = build_propagation_analysis(contact, hrrr, terrain, elevation_profile, weather.soundings)
@ -175,6 +177,16 @@ defmodule MicrowavepropWeb.ContactLive.Show do
end
end
defp maybe_enqueue_terrain(terrain, _contact) when not is_nil(terrain), do: :ok
defp maybe_enqueue_terrain(nil, contact) do
if contact.pos1 && contact.pos2 do
Oban.insert(TerrainProfileWorker.new(%{"qso_id" => contact.id}))
end
:ok
end
defp maybe_enqueue_hrrr(hrrr, _contact) when not is_nil(hrrr), do: {hrrr, :loaded}
# TODO: Re-enable auto HRRR backfill on page view when appropriate

View file

@ -98,7 +98,15 @@ defmodule Microwaveprop.Terrain.SrtmTest do
Plug.Conn.send_resp(conn, 200, gzipped)
end)
assert {:ok, @test_elevation} = Srtm.lookup(32.0, -97.0, tmp_dir)
assert {:ok, @test_elevation} = Srtm.lookup(32.0, -97.0, tmp_dir, download: true)
end
test "returns {:error, :no_tile} without download opt" do
tmp_dir = Path.join(System.tmp_dir!(), "srtm_test_#{System.unique_integer([:positive])}")
File.mkdir_p!(tmp_dir)
on_exit(fn -> File.rm_rf!(tmp_dir) end)
assert {:error, :no_tile} = Srtm.lookup(32.0, -97.0, tmp_dir)
end
test "returns {:error, :no_tile} when download fails" do
@ -112,7 +120,7 @@ defmodule Microwaveprop.Terrain.SrtmTest do
end)
capture_log(fn ->
assert {:error, :no_tile} = Srtm.lookup(80.0, 0.0, tmp_dir)
assert {:error, :no_tile} = Srtm.lookup(80.0, 0.0, tmp_dir, download: true)
end)
end
end