//! 画中画/字幕素材:SQLite 访问与 Tauri 状态 use std::path::PathBuf; use std::sync::Arc; use tokio::sync::RwLock; use crate::material_db::{MaterialDb, MaterialRecord}; #[derive(Debug, Default)] pub struct MaterialStore { inner: Arc>>>, } impl MaterialStore { pub fn new() -> Self { Self::default() } pub async fn init(&self, db_path: PathBuf) -> Result<(), String> { let db = tokio::task::spawn_blocking(move || { MaterialDb::open(db_path).map_err(|e| e.to_string()) }) .await .map_err(|e| e.to_string())??; let count = tokio::task::spawn_blocking({ let db = Arc::new(db); let db2 = db.clone(); move || db2.list().map(|l| (db, l.len())).map_err(|e| e.to_string()) }) .await .map_err(|e| e.to_string())??; let (db, n) = count; *self.inner.write().await = Some(db); log::info!(target: "material", "素材数据库已初始化,共 {n} 条记录"); Ok(()) } async fn with_db(&self, f: F) -> Result where F: FnOnce(Arc) -> Result + Send + 'static, T: Send + 'static, { let db = self .inner .read() .await .clone() .ok_or_else(|| "素材数据库未初始化".to_string())?; tokio::task::spawn_blocking(move || f(db)) .await .map_err(|e| e.to_string())? } pub async fn list(&self) -> Result, String> { self.with_db(|db| db.list().map_err(|e| e.to_string())) .await } pub async fn insert( &self, name: String, path: String, material_type: String, info: serde_json::Value, created_at: i64, updated_at: i64, ) -> Result { self.with_db(move |db| { db.insert( &name, &path, &material_type, info, created_at, updated_at, ) .map_err(|e| e.to_string()) }) .await } pub async fn update_name(&self, id: i64, name: String) -> Result<(), String> { self.with_db(move |db| db.update_name(id, &name).map_err(|e| e.to_string())) .await } pub async fn get(&self, id: i64) -> Result, String> { self.with_db(move |db| db.get(id).map_err(|e| e.to_string())) .await } pub async fn delete(&self, id: i64) -> Result { self.with_db(move |db| db.delete(id).map_err(|e| e.to_string())) .await } }