|
9 | 9 | // You may not use this file except in accordance with one or both of these |
10 | 10 | // licenses. |
11 | 11 |
|
| 12 | +use std::path::Path; |
| 13 | + |
12 | 14 | use bitcoin::consensus::encode::{deserialize, serialize}; |
13 | 15 | use bitcoin::hash_types::Txid; |
14 | 16 | use bitcoin::{OutPoint, Script, Transaction, TxOut}; |
15 | 17 |
|
16 | 18 | use crate::database::{BatchDatabase, BatchOperations, Database, SyncTime}; |
17 | 19 | use crate::error::Error; |
18 | 20 | use crate::types::*; |
| 21 | +use crate::wallet::wallet_name_from_descriptor; |
19 | 22 |
|
20 | 23 | use rusqlite::{named_params, Connection}; |
21 | 24 |
|
| 25 | +use super::DatabaseFactory; |
| 26 | + |
22 | 27 | static MIGRATIONS: &[&str] = &[ |
23 | 28 | "CREATE TABLE version (version INTEGER)", |
24 | 29 | "INSERT INTO version VALUES (1)", |
@@ -970,11 +975,48 @@ pub fn migrate(conn: &Connection) -> rusqlite::Result<()> { |
970 | 975 | Ok(()) |
971 | 976 | } |
972 | 977 |
|
| 978 | +/// A [`DatabaseFactory`] implementation that builds [`SqliteDatabase`]. |
| 979 | +/// |
| 980 | +/// Each built database is stored in path of format: `<path_root>_<hash>.<path_ext>` |
| 981 | +/// Where `hash` contains identifying data derived with inputs provided by |
| 982 | +/// [`DatabaseFactory::build`] or [`DatabaseFactory::build_with_change`] calls. |
| 983 | +pub struct SqliteDatabaseFactory<P> { |
| 984 | + pub dir: P, |
| 985 | + pub ext: String, |
| 986 | +} |
| 987 | + |
| 988 | +impl<P: AsRef<Path>> DatabaseFactory for SqliteDatabaseFactory<P> { |
| 989 | + type Inner = SqliteDatabase; |
| 990 | + |
| 991 | + fn build( |
| 992 | + &self, |
| 993 | + descriptor: &crate::descriptor::ExtendedDescriptor, |
| 994 | + network: bitcoin::Network, |
| 995 | + secp: &crate::wallet::utils::SecpCtx, |
| 996 | + ) -> Result<Self::Inner, Error> { |
| 997 | + // ensure dir exists |
| 998 | + std::fs::create_dir_all(&self.dir).map_err(|e| Error::Generic(e.to_string()))?; |
| 999 | + |
| 1000 | + let name = wallet_name_from_descriptor(descriptor.clone(), None, network, secp)?; |
| 1001 | + let ext = self.ext.trim_start_matches('.'); |
| 1002 | + |
| 1003 | + let mut path = std::path::PathBuf::new(); |
| 1004 | + path.push(&self.dir); |
| 1005 | + path.push(name); |
| 1006 | + path.set_extension(ext); |
| 1007 | + |
| 1008 | + // TODO: This is stupid, fix this |
| 1009 | + Ok(Self::Inner::new(path.to_str().unwrap().to_string())) |
| 1010 | + } |
| 1011 | +} |
| 1012 | + |
973 | 1013 | #[cfg(test)] |
974 | 1014 | pub mod test { |
975 | 1015 | use crate::database::SqliteDatabase; |
976 | 1016 | use std::time::{SystemTime, UNIX_EPOCH}; |
977 | 1017 |
|
| 1018 | + use super::SqliteDatabaseFactory; |
| 1019 | + |
978 | 1020 | fn get_database() -> SqliteDatabase { |
979 | 1021 | let time = SystemTime::now().duration_since(UNIX_EPOCH).unwrap(); |
980 | 1022 | let mut dir = std::env::temp_dir(); |
@@ -1031,4 +1073,20 @@ pub mod test { |
1031 | 1073 | fn test_txs() { |
1032 | 1074 | crate::database::test::test_list_transaction(get_database()); |
1033 | 1075 | } |
| 1076 | + |
| 1077 | + #[test] |
| 1078 | + fn test_factory() { |
| 1079 | + let time = SystemTime::now().duration_since(UNIX_EPOCH).unwrap(); |
| 1080 | + let mut dir = std::env::temp_dir(); |
| 1081 | + dir.push(format!("bdk_{}", time.as_nanos())); |
| 1082 | + |
| 1083 | + let fac = SqliteDatabaseFactory { |
| 1084 | + dir: dir.clone(), |
| 1085 | + ext: "db".to_string(), |
| 1086 | + }; |
| 1087 | + |
| 1088 | + crate::database::test::test_factory(&fac); |
| 1089 | + |
| 1090 | + std::fs::remove_dir_all(&dir).unwrap(); |
| 1091 | + } |
1034 | 1092 | } |
0 commit comments