import os import sqlite3 import json from datetime import datetime, timezone from app.config import DB_PATH def _conn(): conn = sqlite3.connect(DB_PATH) conn.row_factory = sqlite3.Row return conn def init_db(): os.makedirs(os.path.dirname(os.path.abspath(DB_PATH)), exist_ok=True) conn = _conn() conn.executescript(''' CREATE TABLE IF NOT EXISTS players ( id INTEGER PRIMARY KEY, name TEXT NOT NULL, online INTEGER NOT NULL DEFAULT 0, last_seen TEXT, updating INTEGER NOT NULL DEFAULT 0, registered INTEGER NOT NULL DEFAULT 0, workspace_name TEXT, player_type TEXT, updated_at TEXT NOT NULL, last_pushed TEXT, last_ip_address TEXT, status_last_updated TEXT, screen_resolution TEXT, hardware_version TEXT, hostname TEXT, eth0_ip TEXT ); CREATE TABLE IF NOT EXISTS logs ( id INTEGER PRIMARY KEY AUTOINCREMENT, timestamp TEXT NOT NULL, event_type TEXT NOT NULL, message TEXT NOT NULL, details TEXT ); CREATE INDEX IF NOT EXISTS idx_logs_ts ON logs(timestamp DESC); ''') # Migrate existing databases that predate the new columns new_cols = [ ('last_pushed', 'TEXT'), ('last_ip_address', 'TEXT'), ('status_last_updated', 'TEXT'), ('screen_resolution', 'TEXT'), ('hardware_version', 'TEXT'), ('hostname', 'TEXT'), ('eth0_ip', 'TEXT'), ] for col, typ in new_cols: try: conn.execute(f'ALTER TABLE players ADD COLUMN {col} {typ}') except Exception: pass # column already exists conn.commit() conn.close() def upsert_player(p): state = p.get('state', {}) workspace = p.get('workspace', {}) ps = p.get('player_status') or {} res = ps.get('screen_resolution') eth0 = (ps.get('public_ip') or {}).get('eth0') or {} now = datetime.now(timezone.utc).isoformat() conn = _conn() conn.execute(''' INSERT INTO players (id, name, online, last_seen, updating, registered, workspace_name, player_type, updated_at, last_pushed, last_ip_address, status_last_updated, screen_resolution, hardware_version, hostname, eth0_ip) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) ON CONFLICT(id) DO UPDATE SET name = excluded.name, online = excluded.online, last_seen = excluded.last_seen, updating = excluded.updating, registered = excluded.registered, workspace_name = excluded.workspace_name, player_type = excluded.player_type, updated_at = excluded.updated_at, last_pushed = excluded.last_pushed, last_ip_address = excluded.last_ip_address, status_last_updated = excluded.status_last_updated, screen_resolution = excluded.screen_resolution, hardware_version = excluded.hardware_version, hostname = excluded.hostname, eth0_ip = excluded.eth0_ip ''', ( p['id'], p['name'], 1 if state.get('online') else 0, state.get('last_seen'), 1 if state.get('updating') else 0, 1 if state.get('registered') else 0, workspace.get('name'), p.get('player_type'), now, p.get('last_pushed'), p.get('last_ip_address'), ps.get('status_last_updated'), f"{res[0]}x{res[1]}" if isinstance(res, list) and len(res) == 2 else None, ps.get('hardware_version'), ps.get('hostname'), eth0.get('ip_v4'), )) conn.commit() conn.close() def get_all_players(): conn = _conn() rows = conn.execute('SELECT * FROM players ORDER BY name').fetchall() conn.close() return [dict(r) for r in rows] def get_player_counts(): conn = _conn() total = conn.execute('SELECT COUNT(*) FROM players').fetchone()[0] online = conn.execute('SELECT COUNT(*) FROM players WHERE online = 1').fetchone()[0] conn.close() return total, online def add_log(event_type, message, details=None): now = datetime.now(timezone.utc).isoformat() conn = _conn() conn.execute( 'INSERT INTO logs (timestamp, event_type, message, details) VALUES (?, ?, ?, ?)', (now, event_type, message, json.dumps(details) if details else None), ) conn.commit() conn.close() def get_recent_logs(limit=200): conn = _conn() rows = conn.execute('SELECT * FROM logs ORDER BY id DESC LIMIT ?', (limit,)).fetchall() conn.close() return [dict(r) for r in rows]