GODSIGH ▸ World View
+
diff --git a/serve.py b/serve.py
index b8f6b12..1823988 100644
--- a/serve.py
+++ b/serve.py
@@ -78,7 +78,7 @@ ADSB_PATH_RE = re.compile(
r'|lat/-?\d{1,3}(\.\d+)?/lon/-?\d{1,3}(\.\d+)?/dist/\d{1,4}(\.\d+)?'
r'|closest/-?\d{1,3}(\.\d+)?/-?\d{1,3}(\.\d+)?/\d{1,4}(\.\d+)?)$')
ADSB_CACHE_SEC = 120
-ADSB_MIN_INTERVAL = 1.0 # min seconds between upstream adsb.lol calls (anti-burst; it 429s fast)
+ADSB_MIN_INTERVAL = 1.3 # min seconds between upstream adsb.lol calls (anti-burst; it 429s fast)
_adsb_cache = {} # path -> (body, ts)
_adsb_lock = threading.Lock()
_adsb_next = [0.0] # earliest wall-time the next upstream call may start
@@ -353,6 +353,12 @@ class Handler(SimpleHTTPRequestHandler):
except urllib.error.HTTPError as e:
if hit is not None:
return self._send(200, "application/json", hit[0], {"X-Godsigh-Cache": "stale"})
+ # adsb.lol rate-limits with 429 or 420 ("Enhance Your Calm"). With no
+ # cache to fall back on, return a clean empty result (200) rather than
+ # surfacing the error — the layer just shows nothing until the next
+ # poll, and the browser console stays quiet.
+ if e.code in (420, 429):
+ return self._send(200, "application/json", b'{"ac":[]}', {"X-Godsigh-Cache": "ratelimited"})
return self._send_json(e.code, {"error": f"adsb.lol upstream {e.code}"})
except Exception as e:
if hit is not None: