streamdeck/src/store.rs
2021-05-06 00:26:15 -05:00

234 lines
6.3 KiB
Rust

use crate::message::Command;
use sled::{Db, IVec, Tree};
use std::collections::HashMap;
#[derive(Clone, Debug)]
pub(crate) struct Store {
commands: Tree,
settings: Tree,
names: Tree,
db: Db,
}
impl Store {
pub(crate) async fn build(db: Db) -> Result<Self, anyhow::Error> {
tokio::task::spawn_blocking(move || {
Ok(Store {
commands: db.open_tree("dog.asonix.git.asonix.streamdeck/commands")?,
settings: db.open_tree("dog.asonix.git.asonix.streamdeck/settings")?,
names: db.open_tree("dog.asonix.git.asonix.streamdeck/names")?,
db,
}) as Result<Store, anyhow::Error>
})
.await?
}
pub(crate) async fn set_input_name(
&self,
deck: &str,
input: u8,
name: &str,
) -> Result<(), anyhow::Error> {
let key = self.input_name_key(deck, input);
let value = name.as_bytes().to_vec();
let names = self.names.clone();
tokio::task::spawn_blocking(move || names.insert(key, value)).await??;
Ok(())
}
pub(crate) async fn input_names(
&self,
deck: &str,
) -> Result<HashMap<u8, String>, anyhow::Error> {
let prefix = self.input_name_prefix(deck);
let prefix_len = prefix.len();
let names = self.names.clone();
let vec = tokio::task::spawn_blocking(move || {
names
.scan_prefix(prefix.clone())
.filter_map(|res| {
let (key, value) = res.ok()?;
if key.len() != prefix_len + 1 {
return None;
}
let input = key[prefix_len];
let value = String::from_utf8_lossy(&value).to_string();
Some((input, value))
})
.collect()
})
.await?;
Ok(vec)
}
pub(crate) async fn set_deck_name(&self, deck: &str, name: &str) -> Result<(), anyhow::Error> {
let key = self.deck_name_key(deck);
let value = name.as_bytes().to_vec();
let names = self.names.clone();
tokio::task::spawn_blocking(move || names.insert(key, value)).await??;
Ok(())
}
pub(crate) async fn deck_name(&self, deck: &str) -> Result<Option<String>, anyhow::Error> {
let key = self.deck_name_key(deck);
let names = self.names.clone();
let opt = tokio::task::spawn_blocking(move || names.get(key)).await??;
if let Some(ivec) = opt {
return Ok(Some(String::from_utf8_lossy(&ivec).to_string()));
}
Ok(None)
}
pub(crate) async fn setting<T>(&self, key: &str) -> Result<Option<T>, anyhow::Error>
where
T: serde::de::DeserializeOwned,
{
let key = key.to_owned();
let settings = self.settings.clone();
let opt = tokio::task::spawn_blocking(move || settings.get(key)).await??;
if let Some(ivec) = opt {
return Ok(Some(serde_json::from_slice(&ivec)?));
}
Ok(None)
}
pub(crate) async fn save_setting<T>(&self, key: &str, value: T) -> Result<(), anyhow::Error>
where
T: serde::Serialize,
{
let key = key.to_owned();
let value = serde_json::to_vec(&value)?;
let settings = self.settings.clone();
tokio::task::spawn_blocking(move || settings.insert(key, value)).await??;
Ok(())
}
pub(crate) async fn unset(&self, deck: &str, input: u8) -> Result<(), anyhow::Error> {
let key = self.cmd_key(deck, input);
let commands = self.commands.clone();
tokio::task::spawn_blocking(move || commands.remove(key)).await??;
Ok(())
}
pub(crate) async fn store(
&self,
deck: &str,
input: u8,
command: &Command,
) -> Result<(), anyhow::Error> {
let key = self.cmd_key(deck, input);
let value = self.cmd_value(command)?;
let commands = self.commands.clone();
tokio::task::spawn_blocking(move || commands.insert(key, value)).await??;
Ok(())
}
pub(crate) async fn pressed(
&self,
deck: &str,
input: u8,
) -> Result<Option<Command>, anyhow::Error> {
let key = self.cmd_key(deck, input);
let commands = self.commands.clone();
let opt = tokio::task::spawn_blocking(move || commands.get(key)).await??;
if let Some(ivec) = opt {
return Ok(Some(serde_json::from_slice(&ivec)?));
}
Ok(None)
}
pub(crate) async fn get_commands(
&self,
deck: &str,
) -> Result<Vec<(u8, Command)>, anyhow::Error> {
let prefix = self.cmd_prefix(deck);
let commands = self.commands.clone();
let vec = tokio::task::spawn_blocking(move || {
let prefix_len = prefix.len();
commands
.scan_prefix(prefix)
.filter_map(|res| {
let (key, value) = res.ok()?;
if key.len() != prefix_len + 1 {
return None;
}
let key = key[prefix_len];
let command = serde_json::from_slice(&value).ok()?;
Some((key, command))
})
.collect()
})
.await?;
Ok(vec)
}
fn deck_name_key(&self, deck: &str) -> IVec {
let mut key = b"names/".to_vec();
key.extend(deck.as_bytes());
IVec::from(key)
}
fn input_name_prefix(&self, deck: &str) -> IVec {
let mut key = b"names/".to_vec();
key.extend(deck.as_bytes());
key.push(b'/');
IVec::from(key)
}
fn input_name_key(&self, deck: &str, input: u8) -> IVec {
let mut key = b"names/".to_vec();
key.extend(deck.as_bytes());
key.push(b'/');
key.push(input);
IVec::from(key)
}
fn cmd_prefix(&self, deck: &str) -> IVec {
let mut prefix = deck.as_bytes().to_vec();
prefix.push(b'/');
IVec::from(prefix)
}
fn cmd_key(&self, deck: &str, input: u8) -> IVec {
let mut key = deck.as_bytes().to_vec();
key.push(b'/');
key.push(input);
IVec::from(key)
}
fn cmd_value(&self, command: &Command) -> Result<IVec, anyhow::Error> {
Ok(IVec::from(serde_json::to_vec(&command)?))
}
}