Skip to content

Commit

Permalink
Add location helpers
Browse files Browse the repository at this point in the history
  • Loading branch information
ross-spencer committed Nov 27, 2024
1 parent 6d4e1ad commit 7fef4de
Show file tree
Hide file tree
Showing 4 changed files with 116 additions and 18 deletions.
50 changes: 32 additions & 18 deletions htmx/index.htm
Original file line number Diff line number Diff line change
Expand Up @@ -29,25 +29,39 @@
<body
hx-ext="pronom-api-params"
hx-vals='{"baseURLLocal": "http://0.0.0.0:24001", "baseURL": "https://itn.0.orcfax.io"}'>
<h1>ITN diagnostics</h1>
<div>
<h2>License holders</h2>
<div>
<div>
<div
hx-get="{baseURL}/api/participants"
hx-trigger="load"
hx-swap="innerHTML"
/>
</div>
<section id="license-holders">
<h1>ITN diagnostics</h1>
<div>
<h2>License holders</h2>
<div>
<div>
<div
hx-get="{baseURL}/api/participants"
hx-trigger="load"
hx-swap="innerHTML"
/>
</div>
</section>
<hr>
<h2>Active collector counts</h2>
<div
hx-get="{baseURL}/api/online_collectors"
hx-trigger="load"
hx-swap="innerHTML"
/>
</div>
<section id="collector-counts">
<h2>Active collector counts</h2>
<div
hx-get="{baseURL}/api/online_collectors"
hx-trigger="load"
hx-swap="innerHTML"
/>
</div>
</section>
<hr>
<section id="locations">
<h2>Collector locations</h2>
<div
hx-get="{baseURL}/locations"
hx-trigger="load"
hx-swap="innerHTML"
/>
</div>
</section>
<hr>
<div class="footer__bottom text--center">
<div class="footer__copyright">ITN | Diagnostics</div>
Expand Down
18 changes: 18 additions & 0 deletions src/itn_api/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -201,6 +201,17 @@ async def get_itn_aliases_and_staking_csv(
return reports.get_all_license_holders_csv(app, min_stake, sort)


@app.get("/geo", tags=[TAG_STATISTICS])
async def get_locations():
"""Return countries participating in the ITN."""
return await reports.get_locations(app)


# HTMX #################################################################
# HTMX #################################################################
# HTMX #################################################################


@app.get("/participants", tags=[TAG_HTMX], response_class=HTMLResponse)
async def get_itn_participants() -> str:
"""Return ITN aliases and licenses."""
Expand All @@ -223,6 +234,13 @@ async def get_online_collectors() -> str:
return htmx.strip()


@app.get("/locations", tags=[TAG_HTMX], response_class=HTMLResponse)
async def get_locations_hx():
"""Return countries participating in the ITN."""
locations = await reports.get_locations(app)
return htm_helpers.locations_table(locations)


def main():
"""Primary entry point for this script."""

Expand Down
35 changes: 35 additions & 0 deletions src/itn_api/htm_helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -81,3 +81,38 @@ def participants_count_table(participants_count_total):
rows = f"{rows}{row}\n"

return f"{head}\n{rows}</table>\n"


def locations_table(locations):
"""Create a table for participant locations."""

logging.info("formatting participants table")

if not locations:
return "no locations available"

head = """
<table>
<tr>
<th>Region</th>
<th>Country</th>
</tr>
""".strip()

seen = []
rows = ""
for locale in locations:
region = locale["region"]
country = locale["country"]
if (region, country) in seen:
continue
row = f"""
<tr>
<td>{region}</td>
<td nowrap>&nbsp;{country}&nbsp;</td>
</tr>
""".strip()
seen.append((region, country))
rows = f"{rows}{row}\n"

return f"{head}\n{rows}</table>\n"
31 changes: 31 additions & 0 deletions src/itn_api/reports.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,13 @@

# pylint: disable=R0917,R0913,R0914

import json
import logging
from collections import Counter
from dataclasses import dataclass
from typing import List, Tuple

import apsw
import humanize
from fastapi import FastAPI

Expand Down Expand Up @@ -303,3 +305,32 @@ async def get_date_ranges(app: FastAPI):
"earliest_date": dates[0],
"latest_date": dates[1],
}


async def get_locations(app: FastAPI) -> list:
"""Return locations from the database."""
try:
unique_raw_data = app.state.connection.execute(
"select min(node_id), raw_data from data_points group by node_id;"
)
except apsw.SQLError:
return "zero collectors online"
res = list(unique_raw_data)
countries = []
for item in res:
node = item[0]
message = json.loads(item[1])
try:
loc = message["message"]["identity"]["location"]
countries.append(
(
{
"geo": loc.get("loc"),
"region": loc.get("region"),
"country": loc.get("country"),
}
)
)
except KeyError as err:
logger.error("node: '%s' not reporting location (%s)", node, err)
return countries

0 comments on commit 7fef4de

Please sign in to comment.