fix: BUG-028 byte_data init; BUG-LOG-1/4 SocketIO and cleanup_database handler fixes

This commit is contained in:
Stacy Olivas authored and agessaman committed 2026-04-14 10:02:46 -07:00
1 parent 7679eb7e2c
commit 973d1fc947
7 files changed
+102 -10

No files matched your search

+10 -1
View File
@@ -2924,6 +2924,15 @@ class RepeaterManager:
async def cleanup_database(self, days_to_keep_logs: int = 90):
"""Clean up old purging log entries"""
try:
# Guard: purging_log table may not exist on older installs
with self.db_manager.connection() as conn:
cursor = conn.cursor()
cursor.execute(
"SELECT name FROM sqlite_master WHERE type='table' AND name='purging_log'"
)
if not cursor.fetchone():
return
cutoff_date = datetime.now() - timedelta(days=days_to_keep_logs)
deleted_count = self.db_manager.execute_update(
@@ -2935,7 +2944,7 @@ class RepeaterManager:
self.logger.info(f"Cleaned up {deleted_count} old purging log entries")
except Exception as e:
self.logger.error(f"Error cleaning up database: {e}")
self.logger.error(f"Error cleaning up database: {type(e).__name__}: {e}")
def cleanup_repeater_retention(
self,
+82
View File
@@ -516,6 +516,88 @@ class MessageScheduler:
self.logger.info("Scheduler thread stopped")
def _run_data_retention(self):
"""Run data retention cleanup: packet_stream, repeater tables, stats, caches, mesh_connections."""
import asyncio
def get_retention_days(section: str, key: str, default: int) -> int:
try:
if self.bot.config.has_section(section) and self.bot.config.has_option(section, key):
return self.bot.config.getint(section, key)
except Exception:
pass
return default
packet_stream_days = get_retention_days('Data_Retention', 'packet_stream_retention_days', 3)
purging_log_days = get_retention_days('Data_Retention', 'purging_log_retention_days', 90)
daily_stats_days = get_retention_days('Data_Retention', 'daily_stats_retention_days', 90)
observed_paths_days = get_retention_days('Data_Retention', 'observed_paths_retention_days', 90)
mesh_connections_days = get_retention_days('Data_Retention', 'mesh_connections_retention_days', 7)
stats_days = get_retention_days('Stats_Command', 'data_retention_days', 7)
try:
# Packet stream (web viewer integration)
if hasattr(self.bot, 'web_viewer_integration') and self.bot.web_viewer_integration:
bi = getattr(self.bot.web_viewer_integration, 'bot_integration', None)
if bi and hasattr(bi, 'cleanup_old_data'):
bi.cleanup_old_data(packet_stream_days)
# Repeater manager: purging_log and optional daily_stats / unique_advert / observed_paths
if hasattr(self.bot, 'repeater_manager') and self.bot.repeater_manager:
if hasattr(self.bot, 'main_event_loop') and self.bot.main_event_loop and self.bot.main_event_loop.is_running():
future = asyncio.run_coroutine_threadsafe(
self.bot.repeater_manager.cleanup_database(purging_log_days),
self.bot.main_event_loop
)
try:
future.result(timeout=60)
except Exception as e:
self.logger.error(f"Error in repeater_manager.cleanup_database: {type(e).__name__}: {e}")
else:
try:
loop = asyncio.get_event_loop()
except RuntimeError:
loop = asyncio.new_event_loop()
asyncio.set_event_loop(loop)
loop.run_until_complete(self.bot.repeater_manager.cleanup_database(purging_log_days))
if hasattr(self.bot.repeater_manager, 'cleanup_repeater_retention'):
self.bot.repeater_manager.cleanup_repeater_retention(
daily_stats_days=daily_stats_days,
observed_paths_days=observed_paths_days
)
# Stats tables (message_stats, command_stats, path_stats)
if hasattr(self.bot, 'command_manager') and self.bot.command_manager:
stats_cmd = self.bot.command_manager.commands.get('stats') if getattr(self.bot.command_manager, 'commands', None) else None
if stats_cmd and hasattr(stats_cmd, 'cleanup_old_stats'):
stats_cmd.cleanup_old_stats(stats_days)
# Expired caches (geocoding_cache, generic_cache)
if hasattr(self.bot, 'db_manager') and self.bot.db_manager and hasattr(self.bot.db_manager, 'cleanup_expired_cache'):
self.bot.db_manager.cleanup_expired_cache()
# Mesh connections (DB prune to match in-memory expiration)
if hasattr(self.bot, 'mesh_graph') and self.bot.mesh_graph and hasattr(self.bot.mesh_graph, 'delete_expired_edges_from_db'):
self.bot.mesh_graph.delete_expired_edges_from_db(mesh_connections_days)
ran_at = datetime.datetime.utcnow().isoformat()
self._last_retention_stats['ran_at'] = ran_at
try:
self.bot.db_manager.set_metadata('maint.status.data_retention_ran_at', ran_at)
self.bot.db_manager.set_metadata('maint.status.data_retention_outcome', 'ok')
except Exception:
pass
except Exception as e:
self.logger.exception(f"Error during data retention cleanup: {e}")
self._last_retention_stats['error'] = str(e)
try:
ran_at = datetime.datetime.utcnow().isoformat()
self.bot.db_manager.set_metadata('maint.status.data_retention_ran_at', ran_at)
self.bot.db_manager.set_metadata('maint.status.data_retention_outcome', f'error: {e}')
except Exception:
pass
def check_interval_advertising(self):
"""Check if it's time to send an interval-based advert"""
try:
+5 -4
View File
@@ -795,13 +795,14 @@
}
}
// Initialize connection manager when page loads
// Create connection manager synchronously so page scripts in the extra_js
// block can share the same socket without calling io() a second time.
window.connectionManager = new ModernConnectionManager();
document.addEventListener('DOMContentLoaded', () => {
// Initialize dark mode manager first
window.darkModeManager = new DarkModeManager();
window.connectionManager = new ModernConnectionManager();
// Update timestamp immediately and every second
updateTimestamp();
setInterval(updateTimestamp, 1000);
+1 -1
View File
@@ -1325,7 +1325,7 @@ window.addEventListener('beforeunload', () => {
feed.scrollTop = dir === 'top' ? 0 : feed.scrollHeight;
};
const socket = io({ transports: ['websocket', 'polling'] });
const socket = window.connectionManager.socket;
socket.on('connect', () => {
dot.className = 'status-indicator status-connected ms-2';
+1 -1
View File
@@ -226,7 +226,7 @@
});
}
const socket = io({ transports: ['websocket', 'polling'] });
const socket = window.connectionManager.socket;
socket.on('connect', function () {
updateStatus('log-status', 'Connected', 'success');
+1 -1
View File
@@ -2411,7 +2411,7 @@
// re-stabilization layout (nodes clumping, edges tangling) that occurs when vis-network
// runs physics again. User can refresh or switch to map and back to see updated graph.
function setupSocketIO() {
const socket = io();
const socket = window.connectionManager.socket;
socket.emit('subscribe_mesh');
+2 -2
View File
@@ -818,8 +818,8 @@
console.warn('MeshCore decoder unavailable:', e);
});
// Initialize Socket.IO connection (plain io() with same defaults as base.html)
const socket = io();
// Reuse the shared socket from base.html's ModernConnectionManager
const socket = window.connectionManager.socket;
// Connection status
let commandConnected = false;