94 lines
2.3 KiB
Rust
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);
|