add patterns storage functions.
This commit is contained in:
parent
a1b5859cd6
commit
26e825bb19
|
@ -1,4 +1,4 @@
|
|||
use std::sync::Arc;
|
||||
use std::{collections::VecDeque, sync::Arc};
|
||||
|
||||
use btleplug::{
|
||||
api::{Central as _, Peripheral as _},
|
||||
|
@ -9,6 +9,7 @@ use tauri::{async_runtime::RwLock, AppHandle, Emitter, State};
|
|||
|
||||
use crate::{
|
||||
bluetooth, errors,
|
||||
pattern::Pattern,
|
||||
state::{self as global, AppState},
|
||||
};
|
||||
|
||||
|
@ -128,3 +129,17 @@ pub async fn stop_scan_devices(app_handle: AppHandle) -> Result<(), errors::AppE
|
|||
bluetooth::stop_scan(Arc::new(app_handle)).await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub async fn list_patterns(
|
||||
app_state: State<'_, Arc<RwLock<AppState>>>,
|
||||
keyword: Option<String>,
|
||||
) -> Result<VecDeque<Pattern>, errors::AppError> {
|
||||
let state = app_state.read().await;
|
||||
let patterns = state
|
||||
.db
|
||||
.get_patterns(keyword)
|
||||
.await
|
||||
.map_err(|e| errors::AppError::StorageFailure(e.to_string()))?;
|
||||
Ok(patterns)
|
||||
}
|
||||
|
|
|
@ -1,6 +1,12 @@
|
|||
use std::{fs::DirBuilder, path::PathBuf};
|
||||
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
|
||||
|
@ -16,8 +22,81 @@ fn ensure_dir<R: Runtime>(resolver: &PathResolver<R>) -> anyhow::Result<PathBuf>
|
|||
Ok(config_dir)
|
||||
}
|
||||
|
||||
pub fn open_config_db<R: Runtime>(app_handle: &AppHandle<R>) -> anyhow::Result<sled::Db> {
|
||||
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");
|
||||
sled::open(&db_path).map_err(|e| anyhow::anyhow!("Unable to open config database: {}", e))
|
||||
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))?;
|
||||
db.flush_async()
|
||||
.await
|
||||
.map_err(|e| anyhow::anyhow!("Unable to save db: {}", e))?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
|
|
@ -23,4 +23,6 @@ pub enum AppError {
|
|||
UnableToRetrievePeripheralState,
|
||||
#[error("Unable to retrieve peripheral services")]
|
||||
UnableToRetrievePeripheralServices,
|
||||
#[error("Visit data storage failed: {0}")]
|
||||
StorageFailure(String),
|
||||
}
|
||||
|
|
|
@ -64,7 +64,8 @@ pub fn run() {
|
|||
cmd::channel_b_state,
|
||||
cmd::activate_central_adapter,
|
||||
cmd::start_scan_devices,
|
||||
cmd::stop_scan_devices
|
||||
cmd::stop_scan_devices,
|
||||
cmd::list_patterns
|
||||
])
|
||||
.run(tauri::generate_context!())
|
||||
.expect("error while running tauri application");
|
||||
|
|
|
@ -10,10 +10,10 @@ use tauri::{
|
|||
};
|
||||
use uuid::Uuid;
|
||||
|
||||
use crate::config_db;
|
||||
use crate::config_db::ConfigDb;
|
||||
|
||||
pub struct AppState {
|
||||
pub db: Arc<Mutex<sled::Db>>,
|
||||
pub db: ConfigDb,
|
||||
pub central_event_handler: Arc<Mutex<Option<JoinHandle<()>>>>,
|
||||
}
|
||||
|
||||
|
@ -32,10 +32,10 @@ static CONNECTED_PERIPHERAL: LazyLock<Arc<Mutex<Option<PeripheralId>>>> =
|
|||
|
||||
impl AppState {
|
||||
pub async fn new<R: Runtime>(app: &AppHandle<R>) -> anyhow::Result<Self> {
|
||||
let db = config_db::open_config_db(app)?;
|
||||
let db = ConfigDb::open(app)?;
|
||||
|
||||
Ok(Self {
|
||||
db: Arc::new(Mutex::new(db)),
|
||||
db,
|
||||
central_event_handler: Arc::new(Mutex::new(None)),
|
||||
})
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue
Block a user