diff --git a/Cargo.lock b/Cargo.lock index 501bae7..6f9ca70 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -17,6 +17,12 @@ version = "1.0.56" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4361135be9122e0870de935d7c439aef945b9f9ddd4199a553b5270b49c82a27" +[[package]] +name = "base64" +version = "0.21.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "35636a1494ede3b646cc98f74f8e62c773a38a659ebc777a2cf26b9b74171df9" + [[package]] name = "bincode" version = "1.3.3" @@ -37,6 +43,7 @@ name = "bkt" version = "0.7.1" dependencies = [ "anyhow", + "base64", "bincode", "clap", "filetime", diff --git a/Cargo.toml b/Cargo.toml index f74eadb..d929d8d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -28,6 +28,7 @@ bincode = "1.3.1" humantime = "2.1.0" rand = "0.8" serde = { version = "1.0", features = ["derive"] } +base64 = "0.21.5" [dependencies.clap] version = "4.2" diff --git a/src/lib.rs b/src/lib.rs index b7fc504..dd49381 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -28,6 +28,9 @@ use anyhow::{anyhow, Context, Error, Result}; use serde::{Serialize, Deserialize}; use serde::de::DeserializeOwned; +use base64::{Engine as _, engine::general_purpose}; + + #[cfg(feature="debug")] macro_rules! debug_msg { ($($arg:tt)*) => { eprintln!("bkt: {}", format!($($arg)*)) } @@ -661,7 +664,7 @@ impl Cache { fn key_path(&self, key: &str) -> PathBuf { let file = match &self.scope { - Some(scope) => format!("{}.{}", scope, key), + Some(scope) => format!("{}.{}", general_purpose::STANDARD_NO_PAD.encode(scope), key), None => key.into(), }; self.key_dir().join(file) @@ -931,6 +934,24 @@ mod cache_tests { assert_eq!(present_scoped.unwrap().0, val_b); } + #[test] + fn scopes_support_special_chars() { + let dir = TestDir::temp(); + let key = "foo".to_string(); + let val_a = "A".to_string(); + let val_b = "B".to_string(); + let cache = Cache::new(dir.root()); + let cache_scoped = Cache::new(dir.root()).scoped("/scope/with/path/separators".into()); + + cache.store(&key, &val_a, Duration::from_secs(100)).unwrap(); + cache_scoped.store(&key, &val_b, Duration::from_secs(100)).unwrap(); + + let present = cache.lookup::<_, String>(&key, Duration::from_secs(20)).unwrap(); + assert_eq!(present.unwrap().0, val_a); + let present_scoped = cache_scoped.lookup::<_, String>(&key, Duration::from_secs(20)).unwrap(); + assert_eq!(present_scoped.unwrap().0, val_b); + } + #[test] fn cleanup() { let dir = TestDir::temp();