pub(crate) mod fs_store;
pub(crate) mod sqlite_store;
pub(crate) mod utils;
pub use fs_store::FilesystemStore;
pub use sqlite_store::SqliteStore;
use lightning::util::persist::KVStorePersister;
use std::io::Read;
use std::path::PathBuf;
use std::str::FromStr;
pub(crate) const CHANNEL_MANAGER_PERSISTENCE_NAMESPACE: &str = "";
pub(crate) const CHANNEL_MANAGER_PERSISTENCE_KEY: &str = "manager";
pub(crate) const CHANNEL_MONITOR_PERSISTENCE_NAMESPACE: &str = "monitors";
pub(crate) const NETWORK_GRAPH_PERSISTENCE_NAMESPACE: &str = "";
pub(crate) const NETWORK_GRAPH_PERSISTENCE_KEY: &str = "network_graph";
pub(crate) const SCORER_PERSISTENCE_NAMESPACE: &str = "";
pub(crate) const SCORER_PERSISTENCE_KEY: &str = "scorer";
pub(crate) const EVENT_QUEUE_PERSISTENCE_NAMESPACE: &str = "";
pub(crate) const EVENT_QUEUE_PERSISTENCE_KEY: &str = "events";
pub(crate) const PEER_INFO_PERSISTENCE_NAMESPACE: &str = "";
pub(crate) const PEER_INFO_PERSISTENCE_KEY: &str = "peers";
pub(crate) const PAYMENT_INFO_PERSISTENCE_NAMESPACE: &str = "payments";
pub(crate) const LATEST_RGS_SYNC_TIMESTAMP_NAMESPACE: &str = "";
pub(crate) const LATEST_RGS_SYNC_TIMESTAMP_KEY: &str = "latest_rgs_sync_timestamp";
pub(crate) const LATEST_NODE_ANN_BCAST_TIMESTAMP_NAMESPACE: &str = "";
pub(crate) const LATEST_NODE_ANN_BCAST_TIMESTAMP_KEY: &str = "latest_node_ann_bcast_timestamp";
pub trait KVStore: KVStorePersister {
type Reader: Read;
fn read(&self, namespace: &str, key: &str) -> std::io::Result<Self::Reader>;
fn write(&self, namespace: &str, key: &str, buf: &[u8]) -> std::io::Result<()>;
fn remove(&self, namespace: &str, key: &str) -> std::io::Result<bool>;
fn list(&self, namespace: &str) -> std::io::Result<Vec<String>>;
}
fn get_namespace_and_key_from_prefixed(
prefixed_key: &str,
) -> lightning::io::Result<(String, String)> {
let dest_file_path = PathBuf::from_str(prefixed_key).map_err(|_| {
let msg = format!("Could not persist file for key {}.", prefixed_key);
lightning::io::Error::new(lightning::io::ErrorKind::InvalidInput, msg)
})?;
let parent_directory = dest_file_path.parent().ok_or_else(|| {
let msg = format!("Could not persist file for key {}.", prefixed_key);
lightning::io::Error::new(lightning::io::ErrorKind::InvalidInput, msg)
})?;
let namespace = parent_directory.display().to_string();
let dest_without_namespace = dest_file_path.strip_prefix(&namespace).map_err(|_| {
let msg = format!("Could not persist file for key {}.", prefixed_key);
lightning::io::Error::new(lightning::io::ErrorKind::InvalidInput, msg)
})?;
let key = dest_without_namespace.display().to_string();
Ok((namespace, key))
}
#[cfg(test)]
fn do_read_write_remove_list_persist<K: KVStore>(data: &[u8; 32], kv_store: &K) {
use lightning::util::ser::Readable;
let namespace = "testspace";
let key = "testkey";
kv_store.write(namespace, key, data).unwrap();
kv_store.write("", key, data).unwrap();
assert!(kv_store.write(namespace, "", data).is_err());
let listed_keys = kv_store.list(namespace).unwrap();
assert_eq!(listed_keys.len(), 1);
assert_eq!(listed_keys[0], key);
let mut reader = kv_store.read(namespace, key).unwrap();
let read_data: [u8; 32] = Readable::read(&mut reader).unwrap();
assert_eq!(*data, read_data);
kv_store.remove(namespace, key).unwrap();
let listed_keys = kv_store.list(namespace).unwrap();
assert_eq!(listed_keys.len(), 0);
let prefixed_key = format!("{}/{}", namespace, key);
kv_store.persist(&prefixed_key, &data).unwrap();
let mut reader = kv_store.read(namespace, key).unwrap();
let read_data: [u8; 32] = Readable::read(&mut reader).unwrap();
assert_eq!(*data, read_data);
}