|
25 | 25 | from adsb_api.utils.api_v2 import router as v2_router |
26 | 26 | from adsb_api.utils.dependencies import browser, feederData, provider, redisVRS |
27 | 27 | from adsb_api.utils.models import ApiUuidRequest, PrettyJSONResponse |
28 | | -from adsb_api.utils.settings import (INSECURE, REDIS_HOST, SALT_BEAST, |
29 | | - SALT_MLAT, SALT_MY) |
| 28 | +from adsb_api.utils.settings import INSECURE, REDIS_HOST, SALT_BEAST, SALT_MLAT, SALT_MY |
30 | 29 |
|
31 | 30 | PROJECT_PATH = pathlib.Path(__file__).parent.parent.parent |
32 | 31 |
|
@@ -161,7 +160,9 @@ async def mlat_receivers( |
161 | 160 | return {"error": "not found"} |
162 | 161 |
|
163 | 162 | if server not in provider.mlat_sync_json.keys(): |
164 | | - print(f"failed mlat_sync host={host}, server={server} (not in {provider.mlat_sync_json.keys()})") |
| 163 | + print( |
| 164 | + f"failed mlat_sync host={host}, server={server} (not in {provider.mlat_sync_json.keys()})" |
| 165 | + ) |
165 | 166 | return {"error": "not found"} |
166 | 167 |
|
167 | 168 | return provider.mlat_sync_json[server] |
@@ -236,8 +237,14 @@ async def api_me(request: Request): |
236 | 237 | # If any bad |
237 | 238 | return response |
238 | 239 |
|
| 240 | + |
239 | 241 | @app.get("/0/my", tags=["v0"], summary="My Map redirect based on IP") |
240 | | -@app.get("/api/0/my", tags=["v0"], summary="My Map redirect based on IP", include_in_schema=False) |
| 242 | +@app.get( |
| 243 | + "/api/0/my", |
| 244 | + tags=["v0"], |
| 245 | + summary="My Map redirect based on IP", |
| 246 | + include_in_schema=False, |
| 247 | +) |
241 | 248 | async def api_my(request: Request): |
242 | 249 | client_ip = request.client.host |
243 | 250 | my_beast_clients = provider.get_clients_per_client_ip(client_ip) |
@@ -376,36 +383,44 @@ async def planespotters_net_hex_options(): |
376 | 383 | }, |
377 | 384 | ) |
378 | 385 |
|
| 386 | + |
379 | 387 | @app.get( |
380 | 388 | "/0/h3_latency", |
381 | 389 | include_in_schema=False, |
382 | 390 | tags=["v0"], |
383 | 391 | ) |
384 | 392 | async def h3_latency(): |
| 393 | + # Start with fine resolution |
385 | 394 | _h3 = defaultdict(list) |
386 | 395 | for receiverId, lat, lon in provider.beast_receivers: |
387 | 396 | for client in provider.beast_clients: |
388 | | - if not client["_uuid"].startswith(receiverId) or client.get("ms", -1) < 0: |
389 | | - continue |
390 | | - _h3[h3.latlng_to_cell(lat, lon, 1)].append(client["ms"]) |
391 | | - ret = defaultdict(dict) |
392 | | - for key, value in _h3.items(): |
393 | | - # calculate median |
394 | | - value.sort() |
395 | | - ret[key]["median"] = value[len(value) // 2] |
396 | | - # calculate average, limit to 2 decimals |
397 | | - ret[key]["average"] = round(sum(value) / len(value), 2) |
398 | | - # calculate min |
399 | | - ret[key]["min"] = min(value) |
400 | | - # calculate max |
401 | | - ret[key]["max"] = max(value) |
402 | | - # calculate count |
403 | | - ret[key]["count"] = len(value) |
404 | | - # if count < 2, remove the key |
405 | | - ret = {key: value for key, value in ret.items() if value["count"] > 1} |
406 | | - # sort by median |
407 | | - ret = dict(sorted(ret.items(), key=lambda item: item[1]["median"])) |
408 | | - return Response(orjson.dumps(ret), media_type="application/json") |
| 397 | + if client["_uuid"].startswith(receiverId) and client.get("ms", -1) >= 0: |
| 398 | + _h3[h3.latlng_to_cell(lat, lon, 6)].append(client["ms"]) |
| 399 | + |
| 400 | + # Group up sparse hexes progressively |
| 401 | + for res in range(5, 0, -1): |
| 402 | + for cell, values in list(_h3.items()): |
| 403 | + if len(values) < 3 and h3.cell_to_res(cell) == res + 1: |
| 404 | + _h3[h3.cell_to_parent(cell, res)].extend(_h3.pop(cell)) |
| 405 | + |
| 406 | + # Calculate stats and filter |
| 407 | + ret = {} |
| 408 | + for key, values in _h3.items(): |
| 409 | + if len(values) > 1: |
| 410 | + values.sort() |
| 411 | + ret[key] = { |
| 412 | + "median": values[len(values) // 2], |
| 413 | + "average": round(sum(values) / len(values), 2), |
| 414 | + "min": min(values), |
| 415 | + "max": max(values), |
| 416 | + "count": len(values), |
| 417 | + } |
| 418 | + |
| 419 | + return Response( |
| 420 | + orjson.dumps(dict(sorted(ret.items(), key=lambda x: x[1]["median"]))), |
| 421 | + media_type="application/json", |
| 422 | + ) |
| 423 | + |
409 | 424 |
|
410 | 425 | if __name__ == "__main__": |
411 | 426 | print("Run with:") |
|
0 commit comments