🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
112 lines
3.8 KiB
Python
112 lines
3.8 KiB
Python
"""Database models and initialization."""
|
|
import aiosqlite
|
|
from pathlib import Path
|
|
from .. import config
|
|
|
|
|
|
async def init_db():
|
|
"""Initialize the SQLite database."""
|
|
# Ensure data directory exists
|
|
config.DATA_DIR.mkdir(parents=True, exist_ok=True)
|
|
|
|
async with aiosqlite.connect(config.DATABASE_PATH) as db:
|
|
# Devices table (NEW for multi-device support)
|
|
await db.execute("""
|
|
CREATE TABLE IF NOT EXISTS devices (
|
|
device_id TEXT PRIMARY KEY,
|
|
device_path TEXT NOT NULL,
|
|
serial_number TEXT,
|
|
friendly_name TEXT,
|
|
usb_vid TEXT,
|
|
usb_pid TEXT,
|
|
first_seen TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
|
last_seen TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
|
firmware_version TEXT,
|
|
bootrom_version TEXT,
|
|
metadata TEXT,
|
|
version_mismatch_ignored BOOLEAN DEFAULT FALSE,
|
|
ignored_at TIMESTAMP,
|
|
ignored_version TEXT
|
|
)
|
|
""")
|
|
|
|
# Sessions table (UPDATED for multi-device support)
|
|
await db.execute("""
|
|
CREATE TABLE IF NOT EXISTS sessions (
|
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
session_id TEXT UNIQUE NOT NULL,
|
|
device_id TEXT,
|
|
device_path TEXT,
|
|
client_ip TEXT NOT NULL,
|
|
user_agent TEXT,
|
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
|
last_activity TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
|
released_at TIMESTAMP,
|
|
is_active BOOLEAN DEFAULT 1,
|
|
FOREIGN KEY (device_id) REFERENCES devices(device_id)
|
|
)
|
|
""")
|
|
|
|
# Config table
|
|
await db.execute("""
|
|
CREATE TABLE IF NOT EXISTS config (
|
|
key TEXT PRIMARY KEY,
|
|
value TEXT NOT NULL,
|
|
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
|
)
|
|
""")
|
|
|
|
# Crash reports table
|
|
await db.execute("""
|
|
CREATE TABLE IF NOT EXISTS crash_reports (
|
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
error_type TEXT NOT NULL,
|
|
error_message TEXT NOT NULL,
|
|
traceback TEXT,
|
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
|
)
|
|
""")
|
|
|
|
# Command history table
|
|
await db.execute("""
|
|
CREATE TABLE IF NOT EXISTS command_history (
|
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
session_id TEXT NOT NULL,
|
|
command TEXT NOT NULL,
|
|
response TEXT,
|
|
success BOOLEAN,
|
|
executed_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
|
FOREIGN KEY (session_id) REFERENCES sessions(session_id)
|
|
)
|
|
""")
|
|
|
|
# Firmware flash log table (NEW for firmware update tracking)
|
|
await db.execute("""
|
|
CREATE TABLE IF NOT EXISTS firmware_flash_log (
|
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
device_id TEXT NOT NULL,
|
|
device_path TEXT NOT NULL,
|
|
timestamp TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
|
old_version TEXT,
|
|
new_version TEXT,
|
|
flash_bootrom BOOLEAN DEFAULT FALSE,
|
|
success BOOLEAN,
|
|
error_message TEXT,
|
|
duration_seconds INTEGER,
|
|
user_ip TEXT,
|
|
FOREIGN KEY (device_id) REFERENCES devices(device_id)
|
|
)
|
|
""")
|
|
|
|
await db.commit()
|
|
|
|
|
|
async def get_db():
|
|
"""Get database connection."""
|
|
db = await aiosqlite.connect(config.DATABASE_PATH)
|
|
db.row_factory = aiosqlite.Row
|
|
try:
|
|
yield db
|
|
finally:
|
|
await db.close()
|