mirror of
https://github.com/pablorevilla-meshtastic/meshview.git
synced 2026-08-06 08:53:20 +02:00
Merge remote-tracking branch 'origin/dev-v3' into dev-v3
This commit is contained in:
+14
-16
@@ -24,7 +24,9 @@ async def get_fuzzy_nodes(query):
|
||||
return result.scalars()
|
||||
|
||||
|
||||
async def get_packets(node_id=None, portnum=None, after=None, before=None, limit=None, packet_id=None):
|
||||
async def get_packets(
|
||||
node_id=None, portnum=None, after=None, before=None, limit=None, packet_id=None
|
||||
):
|
||||
async with database.async_session() as session:
|
||||
# --- Fast path: fetch by packet_id (uses primary key lookup) ---
|
||||
if packet_id is not None:
|
||||
@@ -53,7 +55,6 @@ async def get_packets(node_id=None, portnum=None, after=None, before=None, limit
|
||||
return packets
|
||||
|
||||
|
||||
|
||||
async def get_packets_from(node_id=None, portnum=None, since=None, limit=500):
|
||||
async with database.async_session() as session:
|
||||
q = select(Packet)
|
||||
@@ -75,7 +76,6 @@ async def get_packet(packet_id):
|
||||
return result.scalar_one_or_none()
|
||||
|
||||
|
||||
|
||||
async def get_packets_seen(packet_id):
|
||||
async with database.async_session() as session:
|
||||
result = await session.execute(
|
||||
@@ -373,11 +373,11 @@ async def get_total_packet_count(
|
||||
|
||||
# CASE 1: no filters -> count everything
|
||||
if (
|
||||
period_type is None and
|
||||
length is None and
|
||||
channel is None and
|
||||
from_node is None and
|
||||
to_node is None
|
||||
period_type is None
|
||||
and length is None
|
||||
and channel is None
|
||||
and from_node is None
|
||||
and to_node is None
|
||||
):
|
||||
async with database.async_session() as session:
|
||||
q = select(func.count(Packet.id))
|
||||
@@ -431,19 +431,17 @@ async def get_total_packet_seen_count(
|
||||
# SPECIAL CASE: direct packet_id lookup
|
||||
if packet_id is not None:
|
||||
async with database.async_session() as session:
|
||||
q = select(func.count(PacketSeen.packet_id)).where(
|
||||
PacketSeen.packet_id == packet_id
|
||||
)
|
||||
q = select(func.count(PacketSeen.packet_id)).where(PacketSeen.packet_id == packet_id)
|
||||
res = await session.execute(q)
|
||||
return res.scalar() or 0
|
||||
|
||||
# No filters -> return ALL seen entries
|
||||
if (
|
||||
period_type is None and
|
||||
length is None and
|
||||
channel is None and
|
||||
from_node is None and
|
||||
to_node is None
|
||||
period_type is None
|
||||
and length is None
|
||||
and channel is None
|
||||
and from_node is None
|
||||
and to_node is None
|
||||
):
|
||||
async with database.async_session() as session:
|
||||
q = select(func.count(PacketSeen.packet_id))
|
||||
|
||||
+29
-19
@@ -193,6 +193,7 @@ async def index(request):
|
||||
starting_url = CONFIG["site"].get("starting", "/map") # default to /map if not set
|
||||
raise web.HTTPFound(location=starting_url)
|
||||
|
||||
|
||||
@routes.get("/net")
|
||||
async def net(request):
|
||||
return web.Response(
|
||||
@@ -200,21 +201,21 @@ async def net(request):
|
||||
content_type="text/html",
|
||||
)
|
||||
|
||||
|
||||
@routes.get("/map")
|
||||
async def map(request):
|
||||
template = env.get_template("map.html")
|
||||
return web.Response(
|
||||
text=template.render(),
|
||||
content_type="text/html"
|
||||
)
|
||||
return web.Response(text=template.render(), content_type="text/html")
|
||||
|
||||
|
||||
@routes.get("/nodelist")
|
||||
async def nodelist(request):
|
||||
template = env.get_template("nodelist.html")
|
||||
return web.Response(
|
||||
text=template.render(),
|
||||
content_type="text/html",
|
||||
)
|
||||
template = env.get_template("nodelist.html")
|
||||
return web.Response(
|
||||
text=template.render(),
|
||||
content_type="text/html",
|
||||
)
|
||||
|
||||
|
||||
@routes.get("/firehose")
|
||||
async def firehose(request):
|
||||
@@ -223,21 +224,24 @@ async def firehose(request):
|
||||
content_type="text/html",
|
||||
)
|
||||
|
||||
|
||||
@routes.get("/chat")
|
||||
async def chat(request):
|
||||
template = env.get_template("chat.html")
|
||||
return web.Response(
|
||||
text=template.render(),
|
||||
content_type="text/html",
|
||||
)
|
||||
template = env.get_template("chat.html")
|
||||
return web.Response(
|
||||
text=template.render(),
|
||||
content_type="text/html",
|
||||
)
|
||||
|
||||
|
||||
@routes.get("/new_packet/{packet_id}")
|
||||
async def new_packet(request):
|
||||
template = env.get_template("new_packet.html")
|
||||
return web.Response(
|
||||
text=template.render(),
|
||||
content_type="text/html",
|
||||
)
|
||||
template = env.get_template("new_packet.html")
|
||||
return web.Response(
|
||||
text=template.render(),
|
||||
content_type="text/html",
|
||||
)
|
||||
|
||||
|
||||
@routes.get("/new_node/{from_node_id}")
|
||||
async def firehose_node(request):
|
||||
@@ -247,6 +251,7 @@ async def firehose_node(request):
|
||||
content_type="text/html",
|
||||
)
|
||||
|
||||
|
||||
@routes.get("/nodegraph")
|
||||
async def nodegraph(request):
|
||||
template = env.get_template("nodegraph.html")
|
||||
@@ -255,6 +260,7 @@ async def nodegraph(request):
|
||||
content_type="text/html",
|
||||
)
|
||||
|
||||
|
||||
@routes.get("/top")
|
||||
async def top(request):
|
||||
template = env.get_template("top.html")
|
||||
@@ -263,6 +269,7 @@ async def top(request):
|
||||
content_type="text/html",
|
||||
)
|
||||
|
||||
|
||||
# Keep !!
|
||||
@routes.get("/graph/traceroute/{packet_id}")
|
||||
async def graph_traceroute(request):
|
||||
@@ -370,6 +377,7 @@ async def graph_traceroute(request):
|
||||
content_type="image/svg+xml",
|
||||
)
|
||||
|
||||
|
||||
@routes.get("/stats")
|
||||
async def stats(request):
|
||||
try:
|
||||
@@ -392,6 +400,7 @@ async def stats(request):
|
||||
content_type="text/plain",
|
||||
)
|
||||
|
||||
|
||||
'''
|
||||
@routes.get("/top")
|
||||
async def top(request):
|
||||
@@ -470,6 +479,7 @@ async def top(request):
|
||||
return web.Response(text=rendered, status=500, content_type="text/html")
|
||||
'''
|
||||
|
||||
|
||||
async def run_server():
|
||||
# Wait for database migrations to complete before starting web server
|
||||
logger.info("Checking database schema status...")
|
||||
|
||||
+38
-49
@@ -79,8 +79,8 @@ async def api_nodes(request):
|
||||
"last_lat": getattr(n, "last_lat", None),
|
||||
"last_long": getattr(n, "last_long", None),
|
||||
"channel": n.channel,
|
||||
#"last_update": n.last_update.isoformat(),
|
||||
"last_seen_us":n.last_seen_us,
|
||||
# "last_update": n.last_update.isoformat(),
|
||||
"last_seen_us": n.last_seen_us,
|
||||
}
|
||||
)
|
||||
|
||||
@@ -170,14 +170,9 @@ async def api_packets(request):
|
||||
|
||||
# --- Text message filtering ---
|
||||
if portnum == PortNum.TEXT_MESSAGE_APP:
|
||||
ui_packets = [
|
||||
p for p in ui_packets
|
||||
if p.payload and not SEQ_REGEX.fullmatch(p.payload)
|
||||
]
|
||||
ui_packets = [p for p in ui_packets if p.payload and not SEQ_REGEX.fullmatch(p.payload)]
|
||||
if contains:
|
||||
ui_packets = [
|
||||
p for p in ui_packets if contains.lower() in p.payload.lower()
|
||||
]
|
||||
ui_packets = [p for p in ui_packets if contains.lower() in p.payload.lower()]
|
||||
|
||||
# --- Sort descending by import_time_us ---
|
||||
ui_packets.sort(key=lambda p: p.import_time_us, reverse=True)
|
||||
@@ -258,13 +253,15 @@ async def api_stats(request):
|
||||
to_node=node_id,
|
||||
)
|
||||
|
||||
return web.json_response({
|
||||
"node_id": node_id,
|
||||
"period_type": period_type,
|
||||
"length": length,
|
||||
"sent": sent.get("total", 0),
|
||||
"seen": seen.get("total", 0),
|
||||
})
|
||||
return web.json_response(
|
||||
{
|
||||
"node_id": node_id,
|
||||
"period_type": period_type,
|
||||
"length": length,
|
||||
"sent": sent.get("total", 0),
|
||||
"seen": seen.get("total", 0),
|
||||
}
|
||||
)
|
||||
|
||||
# ---- Existing full stats mode (unchanged) ----
|
||||
channel = request.query.get("channel")
|
||||
@@ -344,21 +341,18 @@ async def api_stats_count(request):
|
||||
|
||||
# -------- Case 1: NO FILTERS → return global totals --------
|
||||
no_filters = (
|
||||
period_type is None and
|
||||
length is None and
|
||||
channel is None and
|
||||
from_node is None and
|
||||
to_node is None and
|
||||
packet_id is None
|
||||
period_type is None
|
||||
and length is None
|
||||
and channel is None
|
||||
and from_node is None
|
||||
and to_node is None
|
||||
and packet_id is None
|
||||
)
|
||||
|
||||
if no_filters:
|
||||
total_packets = await store.get_total_packet_count()
|
||||
total_seen = await store.get_total_packet_seen_count()
|
||||
return web.json_response({
|
||||
"total_packets": total_packets,
|
||||
"total_seen": total_seen
|
||||
})
|
||||
return web.json_response({"total_packets": total_packets, "total_seen": total_seen})
|
||||
|
||||
# -------- Case 2: Apply filters → compute totals --------
|
||||
total_packets = await store.get_total_packet_count(
|
||||
@@ -378,13 +372,7 @@ async def api_stats_count(request):
|
||||
to_node=to_node,
|
||||
)
|
||||
|
||||
return web.json_response({
|
||||
"total_packets": total_packets,
|
||||
"total_seen": total_seen
|
||||
})
|
||||
|
||||
|
||||
|
||||
return web.json_response({"total_packets": total_packets, "total_seen": total_seen})
|
||||
|
||||
|
||||
@routes.get("/api/edges")
|
||||
@@ -618,6 +606,7 @@ async def version_endpoint(request):
|
||||
logger.error(f"Error in /version: {e}")
|
||||
return web.json_response({"error": "Failed to fetch version info"}, status=500)
|
||||
|
||||
|
||||
@routes.get("/api/packets_seen/{packet_id}")
|
||||
async def api_packets_seen(request):
|
||||
try:
|
||||
@@ -634,22 +623,22 @@ async def api_packets_seen(request):
|
||||
rows = await store.get_packets_seen(packet_id)
|
||||
|
||||
items = []
|
||||
for row in rows: # <-- FIX: normal for-loop
|
||||
items.append({
|
||||
"packet_id": row.packet_id,
|
||||
"node_id": row.node_id,
|
||||
"rx_time": row.rx_time,
|
||||
"hop_limit": row.hop_limit,
|
||||
"hop_start": row.hop_start,
|
||||
"channel": row.channel,
|
||||
"rx_snr": row.rx_snr,
|
||||
"rx_rssi": row.rx_rssi,
|
||||
"topic": row.topic,
|
||||
"import_time": (
|
||||
row.import_time.isoformat() if row.import_time else None
|
||||
),
|
||||
"import_time_us": row.import_time_us,
|
||||
})
|
||||
for row in rows: # <-- FIX: normal for-loop
|
||||
items.append(
|
||||
{
|
||||
"packet_id": row.packet_id,
|
||||
"node_id": row.node_id,
|
||||
"rx_time": row.rx_time,
|
||||
"hop_limit": row.hop_limit,
|
||||
"hop_start": row.hop_start,
|
||||
"channel": row.channel,
|
||||
"rx_snr": row.rx_snr,
|
||||
"rx_rssi": row.rx_rssi,
|
||||
"topic": row.topic,
|
||||
"import_time": (row.import_time.isoformat() if row.import_time else None),
|
||||
"import_time_us": row.import_time_us,
|
||||
}
|
||||
)
|
||||
|
||||
return web.json_response({"seen": items})
|
||||
|
||||
|
||||
Reference in New Issue
Block a user