-
Notifications
You must be signed in to change notification settings - Fork 53
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
e00f4c3
commit be8ef41
Showing
4 changed files
with
324 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,301 @@ | ||
use std::sync::Arc; | ||
|
||
use async_trait::async_trait; | ||
use cashu::nuts::{Id, KeySetInfo, Keys, MintInfo, Proofs}; | ||
use cashu::types::{MeltQuote, MintQuote}; | ||
use cashu::url::UncheckedUrl; | ||
use redb::{ | ||
Database, MultimapTableDefinition, ReadableMultimapTable, ReadableTable, TableDefinition, | ||
}; | ||
use tokio::sync::Mutex; | ||
|
||
use super::{Error, LocalStore}; | ||
|
||
const MINTS_TABLE: TableDefinition<&str, &str> = TableDefinition::new("mints_table"); | ||
const MINT_KEYSETS_TABLE: MultimapTableDefinition<&str, &str> = | ||
MultimapTableDefinition::new("mint_keysets"); | ||
const MINT_QUOTES_TABLE: TableDefinition<&str, &str> = TableDefinition::new("mint_quotes"); | ||
const MELT_QUOTES_TABLE: TableDefinition<&str, &str> = TableDefinition::new("melt_quotes"); | ||
const MINT_KEYS_TABLE: TableDefinition<&str, &str> = TableDefinition::new("mint_keys"); | ||
const PROOFS_TABLE: MultimapTableDefinition<&str, &str> = MultimapTableDefinition::new("proofs"); | ||
|
||
#[derive(Debug, Clone)] | ||
pub struct RedbLocalStore { | ||
db: Arc<Mutex<Database>>, | ||
} | ||
|
||
impl RedbLocalStore { | ||
pub fn new(path: &str) -> Result<Self, Error> { | ||
let db = Database::create(path)?; | ||
|
||
let write_txn = db.begin_write()?; | ||
{ | ||
let _ = write_txn.open_table(MINTS_TABLE)?; | ||
let _ = write_txn.open_multimap_table(MINT_KEYSETS_TABLE)?; | ||
let _ = write_txn.open_table(MINT_QUOTES_TABLE)?; | ||
let _ = write_txn.open_table(MELT_QUOTES_TABLE)?; | ||
let _ = write_txn.open_table(MINT_KEYS_TABLE)?; | ||
let _ = write_txn.open_multimap_table(PROOFS_TABLE)?; | ||
} | ||
write_txn.commit()?; | ||
|
||
Ok(Self { | ||
db: Arc::new(Mutex::new(db)), | ||
}) | ||
} | ||
} | ||
|
||
#[async_trait(?Send)] | ||
impl LocalStore for RedbLocalStore { | ||
async fn add_mint( | ||
&self, | ||
mint_url: UncheckedUrl, | ||
mint_info: Option<MintInfo>, | ||
) -> Result<(), Error> { | ||
let db = self.db.lock().await; | ||
|
||
let write_txn = db.begin_write()?; | ||
|
||
{ | ||
let mut table = write_txn.open_table(MINTS_TABLE)?; | ||
table.insert( | ||
mint_url.to_string().as_str(), | ||
serde_json::to_string(&mint_info)?.as_str(), | ||
)?; | ||
} | ||
write_txn.commit()?; | ||
|
||
Ok(()) | ||
} | ||
|
||
async fn get_mint(&self, mint_url: UncheckedUrl) -> Result<Option<MintInfo>, Error> { | ||
let db = self.db.lock().await; | ||
let read_txn = db.begin_read()?; | ||
let table = read_txn.open_table(MINTS_TABLE)?; | ||
|
||
if let Some(mint_info) = table.get(mint_url.to_string().as_str())? { | ||
return Ok(serde_json::from_str(mint_info.value())?); | ||
} | ||
|
||
Ok(None) | ||
} | ||
|
||
async fn add_mint_keysets( | ||
&self, | ||
mint_url: UncheckedUrl, | ||
keysets: Vec<KeySetInfo>, | ||
) -> Result<(), Error> { | ||
let db = self.db.lock().await; | ||
|
||
let write_txn = db.begin_write()?; | ||
|
||
{ | ||
let mut table = write_txn.open_multimap_table(MINT_KEYSETS_TABLE)?; | ||
|
||
for keyset in keysets { | ||
table.insert( | ||
mint_url.to_string().as_str(), | ||
serde_json::to_string(&keyset)?.as_str(), | ||
)?; | ||
} | ||
} | ||
write_txn.commit()?; | ||
|
||
Ok(()) | ||
} | ||
|
||
async fn get_mint_keysets( | ||
&self, | ||
mint_url: UncheckedUrl, | ||
) -> Result<Option<Vec<KeySetInfo>>, Error> { | ||
let db = self.db.lock().await; | ||
let read_txn = db.begin_read()?; | ||
let table = read_txn.open_multimap_table(MINT_KEYSETS_TABLE)?; | ||
|
||
let keysets = table | ||
.get(mint_url.to_string().as_str())? | ||
.flatten() | ||
.flat_map(|k| serde_json::from_str(k.value())) | ||
.collect(); | ||
|
||
Ok(keysets) | ||
} | ||
|
||
async fn add_mint_quote(&self, quote: MintQuote) -> Result<(), Error> { | ||
let db = self.db.lock().await; | ||
let write_txn = db.begin_write()?; | ||
|
||
{ | ||
let mut table = write_txn.open_table(MINT_QUOTES_TABLE)?; | ||
table.insert(quote.id.as_str(), serde_json::to_string("e)?.as_str())?; | ||
} | ||
|
||
write_txn.commit()?; | ||
|
||
Ok(()) | ||
} | ||
|
||
async fn get_mint_quote(&self, quote_id: &str) -> Result<Option<MintQuote>, Error> { | ||
let db = self.db.lock().await; | ||
let read_txn = db.begin_read()?; | ||
let table = read_txn.open_table(MINT_QUOTES_TABLE)?; | ||
|
||
if let Some(mint_info) = table.get(quote_id)? { | ||
return Ok(serde_json::from_str(mint_info.value())?); | ||
} | ||
|
||
Ok(None) | ||
} | ||
|
||
async fn remove_mint_quote(&self, quote_id: &str) -> Result<(), Error> { | ||
let db = self.db.lock().await; | ||
let write_txn = db.begin_write()?; | ||
|
||
{ | ||
let mut table = write_txn.open_table(MINT_QUOTES_TABLE)?; | ||
table.remove(quote_id)?; | ||
} | ||
|
||
write_txn.commit()?; | ||
|
||
Ok(()) | ||
} | ||
|
||
async fn add_melt_quote(&self, quote: MeltQuote) -> Result<(), Error> { | ||
let db = self.db.lock().await; | ||
let write_txn = db.begin_write()?; | ||
|
||
{ | ||
let mut table = write_txn.open_table(MELT_QUOTES_TABLE)?; | ||
table.insert(quote.id.as_str(), serde_json::to_string("e)?.as_str())?; | ||
} | ||
|
||
write_txn.commit()?; | ||
|
||
Ok(()) | ||
} | ||
|
||
async fn get_melt_quote(&self, quote_id: &str) -> Result<Option<MeltQuote>, Error> { | ||
let db = self.db.lock().await; | ||
let read_txn = db.begin_read()?; | ||
let table = read_txn.open_table(MELT_QUOTES_TABLE)?; | ||
|
||
if let Some(mint_info) = table.get(quote_id)? { | ||
return Ok(serde_json::from_str(mint_info.value())?); | ||
} | ||
|
||
Ok(None) | ||
} | ||
|
||
async fn remove_melt_quote(&self, quote_id: &str) -> Result<(), Error> { | ||
let db = self.db.lock().await; | ||
let write_txn = db.begin_write()?; | ||
|
||
{ | ||
let mut table = write_txn.open_table(MELT_QUOTES_TABLE)?; | ||
table.remove(quote_id)?; | ||
} | ||
|
||
write_txn.commit()?; | ||
|
||
Ok(()) | ||
} | ||
|
||
async fn add_keys(&self, keys: Keys) -> Result<(), Error> { | ||
let db = self.db.lock().await; | ||
let write_txn = db.begin_write()?; | ||
|
||
{ | ||
let mut table = write_txn.open_table(MINT_KEYS_TABLE)?; | ||
table.insert( | ||
Id::from(&keys).to_string().as_str(), | ||
serde_json::to_string(&keys)?.as_str(), | ||
)?; | ||
} | ||
|
||
write_txn.commit()?; | ||
|
||
Ok(()) | ||
} | ||
|
||
async fn get_keys(&self, id: &Id) -> Result<Option<Keys>, Error> { | ||
let db = self.db.lock().await; | ||
let read_txn = db.begin_read()?; | ||
let table = read_txn.open_table(MINT_KEYS_TABLE)?; | ||
|
||
if let Some(mint_info) = table.get(id.to_string().as_str())? { | ||
return Ok(serde_json::from_str(mint_info.value())?); | ||
} | ||
|
||
Ok(None) | ||
} | ||
|
||
async fn remove_keys(&self, id: &Id) -> Result<(), Error> { | ||
let db = self.db.lock().await; | ||
let write_txn = db.begin_write()?; | ||
|
||
{ | ||
let mut table = write_txn.open_table(MINT_KEYS_TABLE)?; | ||
|
||
table.remove(id.to_string().as_str())?; | ||
} | ||
|
||
write_txn.commit()?; | ||
|
||
Ok(()) | ||
} | ||
|
||
async fn add_proofs(&self, mint_url: UncheckedUrl, proofs: Proofs) -> Result<(), Error> { | ||
let db = self.db.lock().await; | ||
|
||
let write_txn = db.begin_write()?; | ||
|
||
{ | ||
let mut table = write_txn.open_multimap_table(PROOFS_TABLE)?; | ||
|
||
for proof in proofs { | ||
table.insert( | ||
mint_url.to_string().as_str(), | ||
serde_json::to_string(&proof)?.as_str(), | ||
)?; | ||
} | ||
} | ||
write_txn.commit()?; | ||
|
||
Ok(()) | ||
} | ||
|
||
async fn get_proofs(&self, mint_url: UncheckedUrl) -> Result<Option<Proofs>, Error> { | ||
let db = self.db.lock().await; | ||
let read_txn = db.begin_read()?; | ||
let table = read_txn.open_multimap_table(PROOFS_TABLE)?; | ||
|
||
let proofs = table | ||
.get(mint_url.to_string().as_str())? | ||
.flatten() | ||
.flat_map(|k| serde_json::from_str(k.value())) | ||
.collect(); | ||
|
||
Ok(proofs) | ||
} | ||
|
||
async fn remove_proofs(&self, mint_url: UncheckedUrl, proofs: &Proofs) -> Result<(), Error> { | ||
let db = self.db.lock().await; | ||
|
||
let write_txn = db.begin_write()?; | ||
|
||
{ | ||
let mut table = write_txn.open_multimap_table(PROOFS_TABLE)?; | ||
|
||
for proof in proofs { | ||
table.remove( | ||
mint_url.to_string().as_str(), | ||
serde_json::to_string(&proof)?.as_str(), | ||
)?; | ||
} | ||
} | ||
write_txn.commit()?; | ||
|
||
Ok(()) | ||
} | ||
} |