estim_control/src-tauri/src/config_db.rs
2025-03-11 17:06:56 +08:00

104 lines
3.6 KiB
Rust

use std::{collections::VecDeque, fs::DirBuilder, path::PathBuf, sync::Arc};
use tauri::{path::PathResolver, AppHandle, Manager, Runtime};
use tokio::sync::Mutex;
use uuid::Uuid;
use crate::pattern::Pattern;
static PATTERN_KEY_PREFIX: &[u8] = b"PATTERN:";
fn ensure_dir<R: Runtime>(resolver: &PathResolver<R>) -> anyhow::Result<PathBuf> {
let config_dir = resolver
.local_data_dir()
.map_err(|e| anyhow::anyhow!("Unable to get local data directory: {}", e))?;
if !config_dir.exists() {
let mut dir_creator = DirBuilder::new();
dir_creator
.recursive(true)
.create(&config_dir)
.map_err(|e| anyhow::anyhow!("Unable to create config directory: {}", e))?;
}
Ok(config_dir)
}
pub struct ConfigDb(Arc<Mutex<sled::Db>>);
impl ConfigDb {
pub fn open<R: Runtime>(app_handle: &AppHandle<R>) -> anyhow::Result<Self> {
let config_dir = ensure_dir(app_handle.path())?;
let db_path = config_dir.join("conf.db");
let db = sled::open(&db_path)
.map_err(|e| anyhow::anyhow!("Unable to open config database: {}", e))?;
Ok(Self(Arc::new(Mutex::new(db))))
}
pub async fn store_pattern(&self, pattern: &Pattern) -> anyhow::Result<()> {
let db = self.0.lock().await;
let key = PATTERN_KEY_PREFIX
.iter()
.chain(pattern.id.as_bytes())
.cloned()
.collect::<Vec<u8>>();
db.insert(key, pattern)
.map_err(|e| anyhow::anyhow!("Unable to store pattern: {}", e))?;
db.flush_async()
.await
.map_err(|e| anyhow::anyhow!("Unable to save db: {}", e))?;
Ok(())
}
pub async fn get_patterns(&self, keyword: Option<String>) -> anyhow::Result<VecDeque<Pattern>> {
let db = self.0.lock().await;
let patterns = db.scan_prefix(PATTERN_KEY_PREFIX);
let mut result: VecDeque<Pattern> = VecDeque::new();
for entry in patterns {
if let Ok((_, pattern)) = entry {
let pattern = Into::<Pattern>::into(pattern);
if let Some(keyword) = &keyword {
if !pattern.name.contains(keyword) {
continue;
}
}
let index =
result.binary_search_by(|item| item.created_at.cmp(&pattern.created_at));
match index {
Ok(index) => result.insert(index + 1, pattern),
Err(index) => result.insert(index, pattern),
};
}
}
Ok(result)
}
pub async fn get_pattern(&self, pattern_id: &Uuid) -> anyhow::Result<Option<Pattern>> {
let db = self.0.lock().await;
let key = PATTERN_KEY_PREFIX
.iter()
.chain(pattern_id.as_bytes())
.cloned()
.collect::<Vec<u8>>();
let pattern = db
.get(key)
.map_err(|e| anyhow::anyhow!("Unable to get pattern: {}", e))?
.map(|p| Into::<Pattern>::into(p));
Ok(pattern)
}
pub async fn remove_pattern(&self, pattern_id: &Uuid) -> anyhow::Result<()> {
let db = self.0.lock().await;
let key = PATTERN_KEY_PREFIX
.iter()
.chain(pattern_id.as_bytes())
.cloned()
.collect::<Vec<u8>>();
db.remove(key)
.map_err(|e| anyhow::anyhow!("Unable to remove pattern: {}", e))?;
// todo: need to remove requested pattern in all playlists.
db.flush_async()
.await
.map_err(|e| anyhow::anyhow!("Unable to save db: {}", e))?;
Ok(())
}
}