cuprate/helper/src/fs.rs
Boog900 fdd1689665
Some checks failed
Audit / audit (push) Has been cancelled
CI / fmt (push) Has been cancelled
CI / typo (push) Has been cancelled
CI / ci (macos-latest, stable, bash) (push) Has been cancelled
CI / ci (ubuntu-latest, stable, bash) (push) Has been cancelled
CI / ci (windows-latest, stable-x86_64-pc-windows-gnu, msys2 {0}) (push) Has been cancelled
Deny / audit (push) Has been cancelled
Doc / build (push) Has been cancelled
Doc / deploy (push) Has been cancelled
Storage: tx-pool database (#238)
* split the DB service abstraction

* fix ci

* misc changes

* init tx-pool DBs

* add some comments

* move more types to `/types`

* add some ops

* add config & more ops functions & open function

* add read & write svcs

* add more docs

* add write functions + docs

* fix merge

* fix test

* fix ci

* move `TxPoolWriteError`

* add more docs

* fix toml formatting

* fix some docs

* fix clippy

* review fixes

* update docs

* fix merge

* fix docs

* fix tests

* fix tests

* add back lints

* Update storage/txpool/README.md

Co-authored-by: hinto-janai <hinto.janai@protonmail.com>

---------

Co-authored-by: hinto-janai <hinto.janai@protonmail.com>
2024-08-22 02:09:07 +01:00

261 lines
9.8 KiB
Rust

//! Cuprate directories and filenames.
//!
//! # Environment variables on Linux
//! Note that this module's functions uses [`dirs`],
//! which adheres to the XDG standard on Linux.
//!
//! This means that the values returned by these statics
//! may change at runtime depending on environment variables,
//! for example:
//!
//! By default the config directory is `~/.config`, however
//! if `$XDG_CONFIG_HOME` is set to something, that will be
//! used instead.
//!
//! ```rust
//! # use cuprate_helper::fs::*;
//! # if cfg!(target_os = "linux") {
//! std::env::set_var("XDG_CONFIG_HOME", "/custom/path");
//! assert_eq!(
//! CUPRATE_CONFIG_DIR.to_string_lossy(),
//! "/custom/path/cuprate"
//! );
//! # }
//! ```
//!
//! Reference:
//! - <https://github.com/Cuprate/cuprate/issues/46>
//! - <https://docs.rs/dirs>
//---------------------------------------------------------------------------------------------------- Use
use std::{path::PathBuf, sync::LazyLock};
//---------------------------------------------------------------------------------------------------- Const
/// Cuprate's main directory.
///
/// This is the head PATH node used for any top-level Cuprate directories.
///
/// | OS | PATH |
/// |---------|-----------------------------------------------------|
/// | Windows | `C:\Users\Alice\AppData\Roaming\Cuprate\` |
/// | macOS | `/Users/Alice/Library/Application Support/Cuprate/` |
/// | Linux | `/home/alice/.config/cuprate/` |
///
/// This is shared between all Cuprate programs.
///
/// # Value
/// This is `Cuprate` on `Windows|macOS` and `cuprate` on everything else.
///
/// # Monero Equivalent
/// `.bitmonero`
pub const CUPRATE_DIR: &str = {
if cfg!(target_os = "windows") || cfg!(target_os = "macos") {
// The standard for main directories is capitalized.
"Cuprate"
} else {
// Standard on Linux + BSDs is lowercase.
"cuprate"
}
};
//---------------------------------------------------------------------------------------------------- Directories
/// Create a `LazyLock` for common PATHs used by Cuprate.
///
/// This currently creates these directories:
/// - [`CUPRATE_CACHE_DIR`]
/// - [`CUPRATE_CONFIG_DIR`]
/// - [`CUPRATE_DATA_DIR`]
/// - [`CUPRATE_BLOCKCHAIN_DIR`]
macro_rules! impl_path_lazylock {
($(
$(#[$attr:meta])* // Documentation and any `derive`'s.
$name:ident, // Name of the corresponding `LazyLock`.
$dirs_fn:ident, // Name of the `dirs` function to use, the PATH prefix.
$sub_dirs:literal // Any sub-directories to add onto the PATH.
),* $(,)?) => {$(
// Create the `LazyLock` if needed, append
// the Cuprate directory string and return.
$(#[$attr])*
pub static $name: LazyLock<PathBuf> = LazyLock::new(|| {
// There's nothing we can do but panic if
// we cannot acquire critical system directories.
//
// Although, this realistically won't panic on
// normal systems for all OS's supported by `dirs`.
let mut path = dirs::$dirs_fn().unwrap();
// FIXME:
// Consider a user who does `HOME=/ ./cuprated`
//
// Should we say "that's stupid" and panic here?
// Or should it be respected?
// We really don't want a `rm -rf /` type of situation...
assert!(
path.parent().is_some(),
"SAFETY: returned OS PATH was either root or empty, aborting"
);
// Returned OS PATH should be absolute, not relative.
assert!(path.is_absolute(), "SAFETY: returned OS PATH was not absolute");
// Unconditionally prefix with the top-level Cuprate directory.
path.push(CUPRATE_DIR);
// Add any sub directories if specified in the macro.
if !$sub_dirs.is_empty() {
path.push($sub_dirs);
}
path
});
)*};
}
impl_path_lazylock! {
/// Cuprate's cache directory.
///
/// This is the PATH used for any Cuprate cache files.
///
/// | OS | PATH |
/// |---------|-----------------------------------------|
/// | Windows | `C:\Users\Alice\AppData\Local\Cuprate\` |
/// | macOS | `/Users/Alice/Library/Caches/Cuprate/` |
/// | Linux | `/home/alice/.cache/cuprate/` |
CUPRATE_CACHE_DIR,
cache_dir,
"",
/// Cuprate's config directory.
///
/// This is the PATH used for any Cuprate configuration files.
///
/// | OS | PATH |
/// |---------|-----------------------------------------------------|
/// | Windows | `C:\Users\Alice\AppData\Roaming\Cuprate\` |
/// | macOS | `/Users/Alice/Library/Application Support/Cuprate/` |
/// | Linux | `/home/alice/.config/cuprate/` |
CUPRATE_CONFIG_DIR,
config_dir,
"",
/// Cuprate's data directory.
///
/// This is the PATH used for any Cuprate data files.
///
/// | OS | PATH |
/// |---------|-----------------------------------------------------|
/// | Windows | `C:\Users\Alice\AppData\Roaming\Cuprate\` |
/// | macOS | `/Users/Alice/Library/Application Support/Cuprate/` |
/// | Linux | `/home/alice/.local/share/cuprate/` |
CUPRATE_DATA_DIR,
data_dir,
"",
/// Cuprate's blockchain directory.
///
/// This is the PATH used for any Cuprate blockchain files.
///
/// | OS | PATH |
/// |---------|----------------------------------------------------------------|
/// | Windows | `C:\Users\Alice\AppData\Roaming\Cuprate\blockchain\` |
/// | macOS | `/Users/Alice/Library/Application Support/Cuprate/blockchain/` |
/// | Linux | `/home/alice/.local/share/cuprate/blockchain/` |
CUPRATE_BLOCKCHAIN_DIR,
data_dir,
"blockchain",
/// Cuprate's transaction pool directory.
///
/// This is the PATH used for any Cuprate txpool files.
///
/// | OS | PATH |
/// |---------|------------------------------------------------------------|
/// | Windows | `C:\Users\Alice\AppData\Roaming\Cuprate\txpool\` |
/// | macOS | `/Users/Alice/Library/Application Support/Cuprate/txpool/` |
/// | Linux | `/home/alice/.local/share/cuprate/txpool/` |
CUPRATE_TXPOOL_DIR,
data_dir,
"txpool",
}
//---------------------------------------------------------------------------------------------------- Tests
#[cfg(test)]
mod test {
use super::*;
// Sanity check every PATH defined in this file.
//
// Each new PATH should be added to this test:
// - It must be `is_absolute()`
// - It must `ends_with()` the expected end PATH for the OS
#[test]
fn path_sanity_check() {
assert!(CUPRATE_CACHE_DIR.is_absolute());
assert!(CUPRATE_CONFIG_DIR.is_absolute());
assert!(CUPRATE_DATA_DIR.is_absolute());
assert!(CUPRATE_BLOCKCHAIN_DIR.is_absolute());
if cfg!(target_os = "windows") {
let dir = &*CUPRATE_CACHE_DIR;
println!("cuprate_cache_dir: {dir:?}");
assert!(dir.ends_with(r"AppData\Local\Cuprate"));
let dir = &*CUPRATE_CONFIG_DIR;
println!("cuprate_config_dir: {dir:?}");
assert!(dir.ends_with(r"AppData\Roaming\Cuprate"));
let dir = &*CUPRATE_DATA_DIR;
println!("cuprate_data_dir: {dir:?}");
assert!(dir.ends_with(r"AppData\Roaming\Cuprate"));
let dir = &*CUPRATE_BLOCKCHAIN_DIR;
println!("cuprate_blockchain_dir: {dir:?}");
assert!(dir.ends_with(r"AppData\Roaming\Cuprate\blockchain"));
let dir = &*CUPRATE_TXPOOL_DIR;
println!("cuprate_txpool_dir: {dir:?}");
assert!(dir.ends_with(r"AppData\Roaming\Cuprate\txpool"));
} else if cfg!(target_os = "macos") {
let dir = &*CUPRATE_CACHE_DIR;
println!("cuprate_cache_dir: {dir:?}");
assert!(dir.ends_with("Library/Caches/Cuprate"));
let dir = &*CUPRATE_CONFIG_DIR;
println!("cuprate_config_dir: {dir:?}");
assert!(dir.ends_with("Library/Application Support/Cuprate"));
let dir = &*CUPRATE_DATA_DIR;
println!("cuprate_data_dir: {dir:?}");
assert!(dir.ends_with("Library/Application Support/Cuprate"));
let dir = &*CUPRATE_BLOCKCHAIN_DIR;
println!("cuprate_blockchain_dir: {dir:?}");
assert!(dir.ends_with("Library/Application Support/Cuprate/blockchain"));
let dir = &*CUPRATE_TXPOOL_DIR;
println!("cuprate_txpool_dir: {dir:?}");
assert!(dir.ends_with("Library/Application Support/Cuprate/txpool"));
} else {
// Assumes Linux.
let dir = &*CUPRATE_CACHE_DIR;
println!("cuprate_cache_dir: {dir:?}");
assert!(dir.ends_with(".cache/cuprate"));
let dir = &*CUPRATE_CONFIG_DIR;
println!("cuprate_config_dir: {dir:?}");
assert!(dir.ends_with(".config/cuprate"));
let dir = &*CUPRATE_DATA_DIR;
println!("cuprate_data_dir: {dir:?}");
assert!(dir.ends_with(".local/share/cuprate"));
let dir = &*CUPRATE_BLOCKCHAIN_DIR;
println!("cuprate_blockchain_dir: {dir:?}");
assert!(dir.ends_with(".local/share/cuprate/blockchain"));
let dir = &*CUPRATE_TXPOOL_DIR;
println!("cuprate_txpool_dir: {dir:?}");
assert!(dir.ends_with(".local/share/cuprate/txpool"));
}
}
}