feat(store): add SecretStore, ApiKey, remove Store trait

This commit is contained in:
2026-01-26 21:00:56 +05:30
parent e7fd01c0af
commit 5b4fbd5df6
4 changed files with 241 additions and 230 deletions

10
Cargo.lock generated
View File

@@ -6603,6 +6603,15 @@ version = "4.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1c107b6f4780854c8b126e228ea8869f4d7b71260f962fefb57b996b8959ba6b" checksum = "1c107b6f4780854c8b126e228ea8869f4d7b71260f962fefb57b996b8959ba6b"
[[package]]
name = "secrecy"
version = "0.10.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e891af845473308773346dc847b2c23ee78fe442e0472ac50e22a18a93d3ae5a"
dependencies = [
"zeroize",
]
[[package]] [[package]]
name = "security-framework" name = "security-framework"
version = "2.11.1" version = "2.11.1"
@@ -7124,6 +7133,7 @@ dependencies = [
"futures", "futures",
"parking_lot", "parking_lot",
"redb", "redb",
"secrecy",
"serde", "serde",
"tokio", "tokio",
"uuid", "uuid",

View File

@@ -8,6 +8,7 @@ bson = { version = "3.1.0", features = ["serde"] }
futures = "0.3.31" futures = "0.3.31"
parking_lot = "0.12.5" parking_lot = "0.12.5"
redb = { version = "3.1.0", features = ["uuid"] } redb = { version = "3.1.0", features = ["uuid"] }
secrecy = "0.10.3"
serde = "1.0.228" serde = "1.0.228"
tokio = { version = "1.48.0", features = ["rt"] } tokio = { version = "1.48.0", features = ["rt"] }
uuid = "1.18.1" uuid = { version = "1.18.1", features = ["v4"] }

View File

@@ -1,10 +1,10 @@
pub mod redb; use std::collections::BTreeMap;
pub mod sqlite;
pub mod toml;
pub trait Store { use uuid::Uuid;
fn image(&self, id: &str) -> Option<Vec<u8>>;
fn save_image(&mut self, id: &str, data: &[u8]); pub struct ApiKey {
inner: secrecy::SecretBox<String>,
}
pub struct SecretStore {
api_keys: BTreeMap<Uuid, ApiKey>,
} }
pub struct Settings {}

View File

@@ -1,225 +1,225 @@
use std::{ // use std::{
borrow::Borrow, // borrow::Borrow,
collections::VecDeque, // collections::VecDeque,
marker::PhantomData, // marker::PhantomData,
path::Path, // path::Path,
sync::{Arc, RwLock, atomic::AtomicBool}, // sync::{Arc, RwLock, atomic::AtomicBool},
}; // };
//
use futures::task::AtomicWaker; // use futures::task::AtomicWaker;
use redb::{Error, Key, ReadableDatabase, TableDefinition, Value}; // use redb::{Error, Key, ReadableDatabase, TableDefinition, Value};
use serde::{Serialize, de::DeserializeOwned}; // use serde::{Serialize, de::DeserializeOwned};
//
const USERS: TableDefinition<uuid::Uuid, Vec<u8>> = TableDefinition::new("users"); // const USERS: TableDefinition<uuid::Uuid, Vec<u8>> = TableDefinition::new("users");
const SERVERS: TableDefinition<uuid::Uuid, Vec<u8>> = TableDefinition::new("servers"); // const SERVERS: TableDefinition<uuid::Uuid, Vec<u8>> = TableDefinition::new("servers");
const SETTINGS: TableDefinition<uuid::Uuid, Vec<u8>> = TableDefinition::new("settings"); // const SETTINGS: TableDefinition<uuid::Uuid, Vec<u8>> = TableDefinition::new("settings");
//
#[derive(Debug)] // #[derive(Debug)]
pub struct TableInner<T> { // pub struct TableInner<T> {
db: Arc<T>, // db: Arc<T>,
}
impl<T> Clone for TableInner<T> {
fn clone(&self) -> Self {
Self {
db: Arc::clone(&self.db),
}
}
}
impl<T> TableInner<T> {
fn new(db: Arc<T>) -> Self {
Self { db }
}
}
impl TableInner<DatabaseHandle> {
async fn get<'a, K: Key, V: Serialize + DeserializeOwned>(
&self,
table: TableDefinition<'static, K, Vec<u8>>,
key: impl Borrow<K::SelfType<'a>>,
) -> Result<Option<V>> {
let db: &redb::Database = &self.db.as_ref().database;
let db_reader = db.begin_read()?;
let table = db_reader.open_table(table)?;
table
.get(key)?
.map(|value| bson::deserialize_from_slice(&value.value()))
.transpose()
.map_err(|e| redb::Error::Io(std::io::Error::other(e)))
}
async fn insert<
'a,
'b,
K: Key + Send + Sync,
V: Serialize + DeserializeOwned + Send + Sync + 'a,
>(
&'b self,
table: TableDefinition<'static, K, Vec<u8>>,
key: impl Borrow<K::SelfType<'a>> + Send + 'b,
value: V,
) -> Result<Option<V>> {
let db: &redb::Database = &self.db.as_ref().database;
// self.db
// .writing
// .store(true, std::sync::atomic::Ordering::SeqCst);
// let out = tokio::task::spawn_blocking(move || -> Result<Option<V>>
let out = tokio::task::spawn_blocking(|| -> Result<Option<V>> {
let db_writer = db.begin_write()?;
let out = {
let mut table = db_writer.open_table(table)?;
let serialized_value = bson::serialize_to_vec(&value)
.map_err(|e| redb::Error::Io(std::io::Error::other(e)))?;
let previous = table.insert(key, &serialized_value)?;
let out = previous
.map(|value| bson::deserialize_from_slice(&value.value()))
.transpose()
.map_err(|e| redb::Error::Io(std::io::Error::other(e)));
out
};
db_writer.commit()?;
out
})
.await
.expect("Task panicked");
out
}
}
// impl<K: Key, V: Serialize + DeserializeOwned> Table<K, V> for TableInner {
// async fn get(&self, key: K) -> Result<Option<Value>> {}
// async fn insert(&self, key: K, value: V) -> Result<Option<Value>> {}
// async fn modify(&self, key: K, v: FnOnce(V) -> V) -> Result<bool> {}
// async fn remove(&self, key: K) -> Result<Option<Value>> {}
// } // }
//
#[derive(Debug)] // impl<T> Clone for TableInner<T> {
pub struct Users<T>(TableInner<T>); // fn clone(&self) -> Self {
// Self {
impl<T> Clone for Users<T> { // db: Arc::clone(&self.db),
fn clone(&self) -> Self {
Self(self.0.clone())
}
}
impl<T> Users<T> {
const TABLE: TableDefinition<'static, uuid::Uuid, Vec<u8>> = USERS;
}
#[derive(Debug)]
pub struct Servers<T>(TableInner<T>);
impl<T> Clone for Servers<T> {
fn clone(&self) -> Self {
Self(self.0.clone())
}
}
impl<T> Servers<T> {
const TABLE: TableDefinition<'static, uuid::Uuid, Vec<u8>> = SERVERS;
}
#[derive(Debug)]
pub struct Settings<T>(TableInner<T>);
impl<T> Clone for Settings<T> {
fn clone(&self) -> Self {
Self(self.0.clone())
}
}
impl<T> Settings<T> {
const TABLE: TableDefinition<'static, uuid::Uuid, Vec<u8>> = SETTINGS;
}
#[derive(Debug, Clone)]
pub struct Database {
users: Users<DatabaseHandle>,
servers: Servers<DatabaseHandle>,
settings: Settings<DatabaseHandle>,
handle: Arc<DatabaseHandle>,
}
#[derive(Debug)]
pub struct DatabaseHandle {
database: redb::Database,
writing: AtomicBool,
wakers: RwLock<VecDeque<AtomicWaker>>,
}
#[derive(Debug)]
pub struct DatabaseWriterGuard<'a> {
handle: &'a DatabaseHandle,
dropper: Arc<AtomicBool>,
}
// impl Drop for DatabaseWriterGuard<'_> {
// fn drop(&mut self) {
// self.handle
// .writing
// .store(false, std::sync::atomic::Ordering::SeqCst);
// let is_panicking = std::thread::panicking();
// let Ok(writer) = self.handle.wakers.write() else {
// if is_panicking {
// return;
// } else {
// panic!("Wakers lock poisoned");
// }
// } // }
// if let Some(waker) = (self.handle.wakers.write()).pop() {
// waker.wake();
// };
// // let mut wakers = self.handle.wakers.write().expect();
// // if let Some(waker) = self.handle.wakers.write().expect("Wakers lock poisoned").pop_front() {
// // waker.wake();
// // }
// // while let Some(waker) = wakers.pop_front() {
// // waker.wake();
// // }
// } // }
// } // }
//
type Result<O, E = redb::Error> = core::result::Result<O, E>; // impl<T> TableInner<T> {
// fn new(db: Arc<T>) -> Self {
pub trait Table<K: Key> { // Self { db }
fn insert<V: Serialize + DeserializeOwned>( // }
&self, // }
key: K, //
value: V, // impl TableInner<DatabaseHandle> {
) -> impl Future<Output = Result<Option<V>>> + Send; // async fn get<'a, K: Key, V: Serialize + DeserializeOwned>(
fn modify<V: Serialize + DeserializeOwned, O: Serialize + DeserializeOwned>( // &self,
&self, // table: TableDefinition<'static, K, Vec<u8>>,
key: K, // key: impl Borrow<K::SelfType<'a>>,
v: impl FnOnce(V) -> O, // ) -> Result<Option<V>> {
) -> impl Future<Output = Result<bool>> + Send; // let db: &redb::Database = &self.db.as_ref().database;
fn remove<V: Serialize + DeserializeOwned>( // let db_reader = db.begin_read()?;
&self, // let table = db_reader.open_table(table)?;
key: K, // table
) -> impl Future<Output = Result<Option<V>>> + Send; // .get(key)?
fn get<V: Serialize + DeserializeOwned>( // .map(|value| bson::deserialize_from_slice(&value.value()))
&self, // .transpose()
key: K, // .map_err(|e| redb::Error::Io(std::io::Error::other(e)))
) -> impl Future<Output = Result<Option<V>>> + Send; // }
} //
// async fn insert<
impl Database { // 'a,
pub fn create(path: impl AsRef<Path>) -> Result<Self, Error> { // 'b,
let writing = AtomicBool::new(false); // K: Key + Send + Sync,
let wakers = RwLock::new(VecDeque::new()); // V: Serialize + DeserializeOwned + Send + Sync + 'a,
let db = redb::Database::create(path)?; // >(
let db = Arc::new(DatabaseHandle { // &'b self,
database: db, // table: TableDefinition<'static, K, Vec<u8>>,
writing, // key: impl Borrow<K::SelfType<'a>> + Send + 'b,
wakers, // value: V,
}); // ) -> Result<Option<V>> {
let table_inner = TableInner::new(Arc::clone(&db)); // let db: &redb::Database = &self.db.as_ref().database;
let users = Users(table_inner.clone()); // // self.db
let servers = Servers(table_inner.clone()); // // .writing
let settings = Settings(table_inner.clone()); // // .store(true, std::sync::atomic::Ordering::SeqCst);
Ok(Self { //
servers, // // let out = tokio::task::spawn_blocking(move || -> Result<Option<V>>
users, //
settings, // let out = tokio::task::spawn_blocking(|| -> Result<Option<V>> {
handle: db, // let db_writer = db.begin_write()?;
}) // let out = {
} // let mut table = db_writer.open_table(table)?;
} // let serialized_value = bson::serialize_to_vec(&value)
// .map_err(|e| redb::Error::Io(std::io::Error::other(e)))?;
// let previous = table.insert(key, &serialized_value)?;
// let out = previous
// .map(|value| bson::deserialize_from_slice(&value.value()))
// .transpose()
// .map_err(|e| redb::Error::Io(std::io::Error::other(e)));
// out
// };
// db_writer.commit()?;
// out
// })
// .await
// .expect("Task panicked");
//
// out
// }
// }
//
// // impl<K: Key, V: Serialize + DeserializeOwned> Table<K, V> for TableInner {
// // async fn get(&self, key: K) -> Result<Option<Value>> {}
// // async fn insert(&self, key: K, value: V) -> Result<Option<Value>> {}
// // async fn modify(&self, key: K, v: FnOnce(V) -> V) -> Result<bool> {}
// // async fn remove(&self, key: K) -> Result<Option<Value>> {}
// // }
//
// #[derive(Debug)]
// pub struct Users<T>(TableInner<T>);
//
// impl<T> Clone for Users<T> {
// fn clone(&self) -> Self {
// Self(self.0.clone())
// }
// }
// impl<T> Users<T> {
// const TABLE: TableDefinition<'static, uuid::Uuid, Vec<u8>> = USERS;
// }
//
// #[derive(Debug)]
// pub struct Servers<T>(TableInner<T>);
// impl<T> Clone for Servers<T> {
// fn clone(&self) -> Self {
// Self(self.0.clone())
// }
// }
// impl<T> Servers<T> {
// const TABLE: TableDefinition<'static, uuid::Uuid, Vec<u8>> = SERVERS;
// }
//
// #[derive(Debug)]
// pub struct Settings<T>(TableInner<T>);
// impl<T> Clone for Settings<T> {
// fn clone(&self) -> Self {
// Self(self.0.clone())
// }
// }
// impl<T> Settings<T> {
// const TABLE: TableDefinition<'static, uuid::Uuid, Vec<u8>> = SETTINGS;
// }
//
// #[derive(Debug, Clone)]
// pub struct Database {
// users: Users<DatabaseHandle>,
// servers: Servers<DatabaseHandle>,
// settings: Settings<DatabaseHandle>,
// handle: Arc<DatabaseHandle>,
// }
//
// #[derive(Debug)]
// pub struct DatabaseHandle {
// database: redb::Database,
// writing: AtomicBool,
// wakers: RwLock<VecDeque<AtomicWaker>>,
// }
//
// #[derive(Debug)]
// pub struct DatabaseWriterGuard<'a> {
// handle: &'a DatabaseHandle,
// dropper: Arc<AtomicBool>,
// }
//
// // impl Drop for DatabaseWriterGuard<'_> {
// // fn drop(&mut self) {
// // self.handle
// // .writing
// // .store(false, std::sync::atomic::Ordering::SeqCst);
// // let is_panicking = std::thread::panicking();
// // let Ok(writer) = self.handle.wakers.write() else {
// // if is_panicking {
// // return;
// // } else {
// // panic!("Wakers lock poisoned");
// // }
// // }
// // if let Some(waker) = (self.handle.wakers.write()).pop() {
// // waker.wake();
// // };
// // // let mut wakers = self.handle.wakers.write().expect();
// // // if let Some(waker) = self.handle.wakers.write().expect("Wakers lock poisoned").pop_front() {
// // // waker.wake();
// // // }
// // // while let Some(waker) = wakers.pop_front() {
// // // waker.wake();
// // // }
// // }
// // }
//
// type Result<O, E = redb::Error> = core::result::Result<O, E>;
//
// pub trait Table<K: Key> {
// fn insert<V: Serialize + DeserializeOwned>(
// &self,
// key: K,
// value: V,
// ) -> impl Future<Output = Result<Option<V>>> + Send;
// fn modify<V: Serialize + DeserializeOwned, O: Serialize + DeserializeOwned>(
// &self,
// key: K,
// v: impl FnOnce(V) -> O,
// ) -> impl Future<Output = Result<bool>> + Send;
// fn remove<V: Serialize + DeserializeOwned>(
// &self,
// key: K,
// ) -> impl Future<Output = Result<Option<V>>> + Send;
// fn get<V: Serialize + DeserializeOwned>(
// &self,
// key: K,
// ) -> impl Future<Output = Result<Option<V>>> + Send;
// }
//
// impl Database {
// pub fn create(path: impl AsRef<Path>) -> Result<Self, Error> {
// let writing = AtomicBool::new(false);
// let wakers = RwLock::new(VecDeque::new());
// let db = redb::Database::create(path)?;
// let db = Arc::new(DatabaseHandle {
// database: db,
// writing,
// wakers,
// });
// let table_inner = TableInner::new(Arc::clone(&db));
// let users = Users(table_inner.clone());
// let servers = Servers(table_inner.clone());
// let settings = Settings(table_inner.clone());
// Ok(Self {
// servers,
// users,
// settings,
// handle: db,
// })
// }
// }