//! Persistence Manager - handles SQLite storage outside Bevy use rusqlite::{Connection, OptionalExtension}; use std::sync::{Arc, Mutex}; use crate::networking::{Session, SessionId}; pub struct PersistenceManager { conn: Arc>, } impl PersistenceManager { pub fn new(db_path: &str) -> Self { let conn = Connection::open(db_path).expect("Failed to open database"); // Schema is handled by the migration system in persistence/migrations // No hardcoded schema creation here Self { conn: Arc::new(Mutex::new(conn)), } } pub fn save_session(&self, session: &Session) -> anyhow::Result<()> { let conn = self.conn.lock().unwrap(); // Schema from migration 004: id (BLOB), code, name, created_at, last_active, entity_count, state, secret conn.execute( "INSERT OR REPLACE INTO sessions (id, code, state, created_at, last_active, entity_count) VALUES (?1, ?2, ?3, ?4, ?5, ?6)", ( session.id.as_uuid().as_bytes(), // id is BLOB in migration 004 session.id.to_code(), // code is the text representation format!("{:?}", session.state), session.created_at, session.last_active, 0, // entity_count default ), )?; Ok(()) } pub fn load_last_active_session(&self) -> anyhow::Result> { let conn = self.conn.lock().unwrap(); // Query for the most recently active session // Schema from migration 004: uses last_active (not last_active_at) let mut stmt = conn.prepare( "SELECT code, state, created_at, last_active FROM sessions ORDER BY last_active DESC LIMIT 1" )?; let session = stmt.query_row([], |row| { let code: String = row.get(0)?; let _state: String = row.get(1)?; let _created_at: i64 = row.get(2)?; let _last_active: i64 = row.get(3)?; // Parse session ID from code if let Ok(session_id) = SessionId::from_code(&code) { Ok(Some(Session::new(session_id))) } else { Ok(None) } }).optional()?; Ok(session.flatten()) } }