gitdataai/lib/git/graphql/cache_helper.rs
2026-05-30 01:38:40 +08:00

94 lines
2.3 KiB
Rust

use std::{fmt::Display, future::Future, time::Duration};
use cache::AppCache;
use serde::{Serialize, de::DeserializeOwned};
use crate::{bare::GitBare, graphql::GraphqlContext};
const KEY_SEPARATOR: &str = ":";
pub fn cache_key(namespace: &str, parts: &[&str]) -> String {
let mut segments: Vec<&str> = vec![namespace];
for part in parts {
if !part.is_empty() {
segments.push(part);
}
}
segments.join(KEY_SEPARATOR)
}
pub fn cache_key_with_revision(
namespace: &str,
revision: impl Display,
parts: &[&str],
) -> String {
let mut key = cache_key(namespace, parts);
key.push_str(KEY_SEPARATOR);
key.push_str(&revision.to_string());
key
}
fn path_hash(repo: &GitBare) -> String {
let path_str = repo.bare_dir.to_string_lossy();
let hash = simple_hash(&path_str);
hash[..8].to_string()
}
fn simple_hash(s: &str) -> String {
let mut h: u64 = 0;
for b in s.bytes() {
h = h.wrapping_mul(31).wrapping_add(b as u64);
}
format!("{:016x}", h)
}
pub async fn repo_revision(ctx: &GraphqlContext) -> String {
let repo = ctx.repo.clone();
let result = tokio::task::spawn_blocking(move || {
repo.git_command_stdout(vec![
"rev-parse".to_string(),
"HEAD".to_string(),
])
})
.await;
match result {
Ok(Ok(oid)) => oid.trim().to_string(),
_ => "unknown".to_string(),
}
}
pub fn mutable_cache_key(
ctx: &GraphqlContext,
namespace: &str,
parts: &[&str],
revision: &str,
) -> String {
let ph = path_hash(&ctx.repo);
let mut all_parts: Vec<&str> = vec![&ph];
all_parts.extend_from_slice(parts);
cache_key_with_revision(namespace, revision, &all_parts)
}
pub async fn cached_json<T, F, Fut>(
cache: &AppCache,
key: &str,
_ttl: Duration,
build: F,
) -> anyhow::Result<T>
where
T: Serialize + DeserializeOwned,
F: FnOnce() -> Fut,
Fut: Future<Output = anyhow::Result<T>>,
{
if let Ok(Some(cached)) = cache.get::<T>(key).await {
return Ok(cached);
}
let value = build().await?;
cache.set(key, &value).await.ok();
Ok(value)
}
pub const IMMUTABLE_TTL: Duration = Duration::from_secs(86400);
pub const MUTABLE_TTL: Duration = Duration::from_secs(300);