From 49de8e51804995131014fc5a7d52986ac085c141 Mon Sep 17 00:00:00 2001 From: Lloyd Date: Tue, 11 Nov 2025 20:54:59 +0000 Subject: [PATCH] add route_stats endpoint and implement get_route_stats method in SQLiteHandler --- repeater/data_acquisition/sqlite_handler.py | 46 +++++++++++++++++++++ repeater/web/api_endpoints.py | 20 ++++++--- 2 files changed, 61 insertions(+), 5 deletions(-) diff --git a/repeater/data_acquisition/sqlite_handler.py b/repeater/data_acquisition/sqlite_handler.py index 9c66abd..9fce559 100644 --- a/repeater/data_acquisition/sqlite_handler.py +++ b/repeater/data_acquisition/sqlite_handler.py @@ -404,6 +404,52 @@ class SQLiteHandler: logger.error(f"Failed to get packet type stats from SQLite: {e}") return {"error": str(e), "data_source": "error"} + def get_route_stats(self, hours: int = 24) -> dict: + + try: + cutoff = time.time() - (hours * 3600) + + with sqlite3.connect(self.sqlite_path) as conn: + conn.row_factory = sqlite3.Row + + route_counts = {} + route_names = { + 0: 'Transport Flood', + 1: 'Flood', + 2: 'Direct', + 3: 'Transport Direct' + } + + for route_type in range(4): + count = conn.execute( + "SELECT COUNT(*) FROM packets WHERE route = ? AND timestamp > ?", + (route_type, cutoff) + ).fetchone()[0] + + route_name = route_names.get(route_type, f'Route {route_type}') + if count > 0: + route_counts[route_name] = count + + # Count any other route types > 3 + other_count = conn.execute( + "SELECT COUNT(*) FROM packets WHERE route > 3 AND timestamp > ?", + (cutoff,) + ).fetchone()[0] + if other_count > 0: + route_counts['Other Routes (>3)'] = other_count + + return { + "hours": hours, + "route_totals": route_counts, + "total_packets": sum(route_counts.values()), + "period": f"{hours} hours", + "data_source": "sqlite" + } + + except Exception as e: + logger.error(f"Failed to get route stats from SQLite: {e}") + return {"error": str(e), "data_source": "error"} + def get_neighbors(self) -> dict: try: with sqlite3.connect(self.sqlite_path) as conn: diff --git a/repeater/web/api_endpoints.py b/repeater/web/api_endpoints.py index 6e98115..c36eb24 100644 --- a/repeater/web/api_endpoints.py +++ b/repeater/web/api_endpoints.py @@ -244,13 +244,25 @@ class APIEndpoints: @cherrypy.expose @cherrypy.tools.json_out() @cors_enabled - def packet_stats(self, hours=24): + def packet_type_stats(self, hours=24): try: hours = int(hours) - stats = self._get_storage().get_packet_stats(hours=hours) + stats = self._get_storage().get_packet_type_stats(hours=hours) return self._success(stats) except Exception as e: - logger.error(f"Error getting packet stats: {e}") + logger.error(f"Error getting packet type stats: {e}") + return self._error(e) + + @cherrypy.expose + @cherrypy.tools.json_out() + @cors_enabled + def route_stats(self, hours=24): + try: + hours = int(hours) + stats = self._get_storage().get_route_stats(hours=hours) + return self._success(stats) + except Exception as e: + logger.error(f"Error getting route stats: {e}") return self._error(e) @cherrypy.expose @@ -332,10 +344,8 @@ class APIEndpoints: hours = int(hours) start_time, end_time = self._get_time_range(hours) - # Use SQLite directly for packet type graph data since RRD data is too sparse storage = self._get_storage() - # Get packet type stats directly from SQLite handler to avoid RRD formatting issues stats = storage.sqlite_handler.get_packet_type_stats(hours) if 'error' in stats: return self._error(stats['error'])