104 lines
3.6 KiB
Rust
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(())
|
|
}
|
|
}
|