1use super::*;
18
19use blake2::{Blake2b, Digest};
20use http::Extensions;
21use serde::{Deserialize, Serialize};
22use std::fmt::{Display, Formatter, Result as FmtResult};
23
24const KEY_SIZE: usize = 16;
26
27pub type HashBinary = [u8; KEY_SIZE];
29
30fn hex2str(hex: &[u8]) -> String {
31 use std::fmt::Write;
32 let mut s = String::with_capacity(KEY_SIZE * 2);
33 for c in hex {
34 write!(s, "{:02x}", c).unwrap(); }
36 s
37}
38
39pub fn str2hex(s: &str) -> Option<HashBinary> {
43 if s.len() != KEY_SIZE * 2 {
44 return None;
45 }
46 let mut output = [0; KEY_SIZE];
47 hex::decode_to_slice(s.as_bytes(), &mut output).ok()?;
49 Some(output)
50}
51
52pub trait CacheHashKey {
54 fn primary_bin(&self) -> HashBinary;
56
57 fn variance_bin(&self) -> Option<HashBinary>;
61
62 fn combined_bin(&self) -> HashBinary {
64 let key = self.primary_bin();
65 if let Some(v) = self.variance_bin() {
66 let mut hasher = Blake2b128::new();
67 hasher.update(key);
68 hasher.update(v);
69 hasher.finalize().into()
70 } else {
71 key
73 }
74 }
75
76 fn user_tag(&self) -> &str;
80
81 fn primary(&self) -> String {
83 hex2str(&self.primary_bin())
84 }
85
86 fn variance(&self) -> Option<String> {
88 self.variance_bin().as_ref().map(|b| hex2str(&b[..]))
89 }
90
91 fn combined(&self) -> String {
93 hex2str(&self.combined_bin())
94 }
95}
96
97#[derive(Debug, Clone)]
99pub struct CacheKey {
100 namespace: String,
102 primary: String,
103 primary_bin_override: Option<HashBinary>,
104 variance: Option<HashBinary>,
105 pub user_tag: String,
109
110 pub extensions: Extensions,
112}
113
114impl CacheKey {
115 pub fn set_variance_key(&mut self, key: HashBinary) {
117 self.variance = Some(key)
118 }
119
120 pub fn get_variance_key(&self) -> Option<&HashBinary> {
122 self.variance.as_ref()
123 }
124
125 pub fn remove_variance_key(&mut self) {
127 self.variance = None
128 }
129
130 pub fn set_primary_bin_override(&mut self, key: HashBinary) {
132 self.primary_bin_override = Some(key)
133 }
134}
135
136#[derive(Debug, Deserialize, Serialize, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)]
139pub struct CompactCacheKey {
140 pub primary: HashBinary,
141 pub variance: Option<Box<HashBinary>>,
143 pub user_tag: Box<str>, }
145
146impl Display for CompactCacheKey {
147 fn fmt(&self, f: &mut Formatter) -> FmtResult {
148 write!(f, "{}", hex2str(&self.primary))?;
149 if let Some(var) = &self.variance {
150 write!(f, ", variance: {}", hex2str(var.as_ref()))?;
151 }
152 write!(f, ", user_tag: {}", self.user_tag)
153 }
154}
155
156impl CacheHashKey for CompactCacheKey {
157 fn primary_bin(&self) -> HashBinary {
158 self.primary
159 }
160
161 fn variance_bin(&self) -> Option<HashBinary> {
162 self.variance.as_ref().map(|s| *s.as_ref())
163 }
164
165 fn user_tag(&self) -> &str {
166 &self.user_tag
167 }
168}
169
170pub(crate) type Blake2b128 = Blake2b<blake2::digest::consts::U16>;
180
181pub fn hash_u8(key: &str) -> u8 {
183 let mut hasher = Blake2b128::new();
184 hasher.update(key);
185 let raw = hasher.finalize();
186 raw[0]
187}
188
189pub fn hash_key(key: &str) -> HashBinary {
191 let mut hasher = Blake2b128::new();
192 hasher.update(key);
193 let raw = hasher.finalize();
194 raw.into()
195}
196
197impl CacheKey {
198 fn primary_hasher(&self) -> Blake2b128 {
199 let mut hasher = Blake2b128::new();
200 hasher.update(&self.namespace);
201 hasher.update(&self.primary);
202 hasher
203 }
204
205 pub fn default(req_header: &ReqHeader) -> Self {
207 CacheKey {
208 namespace: "".into(),
209 primary: format!("{}", req_header.uri),
210 primary_bin_override: None,
211 variance: None,
212 user_tag: "".into(),
213 extensions: Extensions::new(),
214 }
215 }
216
217 pub fn new<S1, S2, S3>(namespace: S1, primary: S2, user_tag: S3) -> Self
221 where
222 S1: Into<String>,
223 S2: Into<String>,
224 S3: Into<String>,
225 {
226 CacheKey {
227 namespace: namespace.into(),
228 primary: primary.into(),
229 primary_bin_override: None,
230 variance: None,
231 user_tag: user_tag.into(),
232 extensions: Extensions::new(),
233 }
234 }
235
236 pub fn namespace(&self) -> &str {
238 &self.namespace
239 }
240
241 pub fn primary_key(&self) -> &str {
243 &self.primary
244 }
245
246 pub fn to_compact(&self) -> CompactCacheKey {
248 let primary = self.primary_bin();
249 CompactCacheKey {
250 primary,
251 variance: self.variance_bin().map(Box::new),
252 user_tag: self.user_tag.clone().into_boxed_str(),
253 }
254 }
255}
256
257impl CacheHashKey for CacheKey {
258 fn primary_bin(&self) -> HashBinary {
259 if let Some(primary_bin_override) = self.primary_bin_override {
260 primary_bin_override
261 } else {
262 self.primary_hasher().finalize().into()
263 }
264 }
265
266 fn variance_bin(&self) -> Option<HashBinary> {
267 self.variance
268 }
269
270 fn user_tag(&self) -> &str {
271 &self.user_tag
272 }
273}
274
275#[cfg(test)]
276mod tests {
277 use super::*;
278
279 #[test]
280 fn test_cache_key_hash() {
281 let key = CacheKey {
282 namespace: "".into(),
283 primary: "aa".into(),
284 primary_bin_override: None,
285 variance: None,
286 user_tag: "1".into(),
287 extensions: Extensions::new(),
288 };
289 let hash = key.primary();
290 assert_eq!(hash, "ac10f2aef117729f8dad056b3059eb7e");
291 assert!(key.variance().is_none());
292 assert_eq!(key.combined(), hash);
293 let compact = key.to_compact();
294 assert_eq!(compact.primary(), hash);
295 assert!(compact.variance().is_none());
296 assert_eq!(compact.combined(), hash);
297 }
298
299 #[test]
300 fn test_cache_key_hash_override() {
301 let mut key = CacheKey {
302 namespace: "".into(),
303 primary: "aa".into(),
304 primary_bin_override: str2hex("27c35e6e9373877f29e562464e46497e"),
305 variance: None,
306 user_tag: "1".into(),
307 extensions: Extensions::new(),
308 };
309 let hash = key.primary();
310 assert_eq!(hash, "27c35e6e9373877f29e562464e46497e");
311 assert!(key.variance().is_none());
312 assert_eq!(key.combined(), hash);
313 let compact = key.to_compact();
314 assert_eq!(compact.primary(), hash);
315 assert!(compact.variance().is_none());
316 assert_eq!(compact.combined(), hash);
317
318 key.set_primary_bin_override(str2hex("004174d3e75a811a5b44c46b3856f3ee").unwrap());
320 let hash = key.primary();
321 assert_eq!(hash, "004174d3e75a811a5b44c46b3856f3ee");
322 assert!(key.variance().is_none());
323 assert_eq!(key.combined(), hash);
324 let compact = key.to_compact();
325 assert_eq!(compact.primary(), hash);
326 assert!(compact.variance().is_none());
327 assert_eq!(compact.combined(), hash);
328 }
329
330 #[test]
331 fn test_cache_key_vary_hash() {
332 let key = CacheKey {
333 namespace: "".into(),
334 primary: "aa".into(),
335 primary_bin_override: None,
336 variance: Some([0u8; 16]),
337 user_tag: "1".into(),
338 extensions: Extensions::new(),
339 };
340 let hash = key.primary();
341 assert_eq!(hash, "ac10f2aef117729f8dad056b3059eb7e");
342 assert_eq!(key.variance().unwrap(), "00000000000000000000000000000000");
343 assert_eq!(key.combined(), "004174d3e75a811a5b44c46b3856f3ee");
344 let compact = key.to_compact();
345 assert_eq!(compact.primary(), "ac10f2aef117729f8dad056b3059eb7e");
346 assert_eq!(
347 compact.variance().unwrap(),
348 "00000000000000000000000000000000"
349 );
350 assert_eq!(compact.combined(), "004174d3e75a811a5b44c46b3856f3ee");
351 }
352
353 #[test]
354 fn test_cache_key_vary_hash_override() {
355 let key = CacheKey {
356 namespace: "".into(),
357 primary: "saaaad".into(),
358 primary_bin_override: str2hex("ac10f2aef117729f8dad056b3059eb7e"),
359 variance: Some([0u8; 16]),
360 user_tag: "1".into(),
361 extensions: Extensions::new(),
362 };
363 let hash = key.primary();
364 assert_eq!(hash, "ac10f2aef117729f8dad056b3059eb7e");
365 assert_eq!(key.variance().unwrap(), "00000000000000000000000000000000");
366 assert_eq!(key.combined(), "004174d3e75a811a5b44c46b3856f3ee");
367 let compact = key.to_compact();
368 assert_eq!(compact.primary(), "ac10f2aef117729f8dad056b3059eb7e");
369 assert_eq!(
370 compact.variance().unwrap(),
371 "00000000000000000000000000000000"
372 );
373 assert_eq!(compact.combined(), "004174d3e75a811a5b44c46b3856f3ee");
374 }
375
376 #[test]
377 fn test_hex_str() {
378 let mut key = [0; KEY_SIZE];
379 for (i, v) in key.iter_mut().enumerate() {
380 *v = i as u8;
382 }
383 let hex_str = hex2str(&key);
384 let key2 = str2hex(&hex_str).unwrap();
385 for i in 0..KEY_SIZE {
386 assert_eq!(key[i], key2[i]);
387 }
388 }
389}