Skip to main content

pharos_native/runtime/
cache_key.rs

1//! Stable Redis cache-key builders for runtime-owned namespaces.
2
3use sha2::{Digest, Sha256};
4
5/// Builds the stable cache key for one browser-session lookup record.
6pub fn session_value(app_id: &str, session_token_hash: &str) -> Option<String> {
7    cache_key("session", &format!("{app_id}\0{session_token_hash}"))
8}
9
10/// Builds the stable cache key for the session-index set used to revoke all sessions for one user.
11pub fn session_user_index(app_id: &str, user_id: i64) -> Option<String> {
12    (user_id > 0)
13        .then(|| cache_key("session-user", &format!("{app_id}\0{user_id}")))
14        .flatten()
15}
16
17/// Builds the stable cache key for one mounted-route match decision.
18pub fn route_match(path: &str) -> Option<String> {
19    cache_key("route-match", path)
20}
21
22/// Builds the stable cache key for one template-source file.
23pub fn template_source(app_root: &str, relative_path: &str) -> Option<String> {
24    cache_key("template-source", &format!("{app_root}\0{relative_path}"))
25}
26
27/// Builds the stable cache key for one allowlisted dynamic-config value.
28pub fn config_allowlist(
29    app_root: &str,
30    runtime_conf_path: Option<&str>,
31    key: &str,
32) -> Option<String> {
33    cache_key(
34        "config-allowlist",
35        &format!(
36            "{app_root}\0{}\0{key}",
37            runtime_conf_path.unwrap_or_default()
38        ),
39    )
40}
41
42fn cache_key(namespace: &str, payload: &str) -> Option<String> {
43    if namespace.is_empty() || payload.is_empty() {
44        return None;
45    }
46    let digest = hex_digest(Sha256::digest(payload.as_bytes()));
47    Some(format!("runtime:{namespace}:{digest}"))
48}
49
50fn hex_digest(digest: impl AsRef<[u8]>) -> String {
51    digest
52        .as_ref()
53        .iter()
54        .map(|byte| format!("{byte:02x}"))
55        .collect()
56}