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

94 lines
2.2 KiB
Rust

use std::time::Duration;
use juniper::graphql_object;
use crate::{
cmd::{
blob::{blob_load::BlobLoadParams, blob_size::BlobSizeParams},
oid::ObjectId,
},
graphql::{
GraphqlContext,
cache_helper::{IMMUTABLE_TTL, cache_key, cached_json},
},
};
const BLOB_SIZE_TTL: Duration = IMMUTABLE_TTL;
#[derive(Clone, serde::Serialize, serde::Deserialize)]
pub struct BlobResult {
pub oid: String,
pub size: i32,
pub is_binary: bool,
}
#[graphql_object(context = GraphqlContext)]
impl BlobResult {
fn oid(&self) -> &str {
&self.oid
}
fn size(&self) -> i32 {
self.size
}
fn is_binary(&self) -> bool {
self.is_binary
}
}
pub async fn resolve_blob_size(
ctx: &GraphqlContext,
oid: String,
) -> anyhow::Result<i32> {
let key = cache_key("query:git:blob_size", &[&oid]);
cached_json(&ctx.cache, &key, BLOB_SIZE_TTL, || {
let repo = ctx.repo.clone();
let oid_obj = ObjectId::new(&oid);
async move {
let size = tokio::task::spawn_blocking(move || {
repo.blob_size(&BlobSizeParams {
id: oid_obj,
path: String::new(),
})
})
.await?
.map_err(|e| anyhow::anyhow!(e))?;
Ok(size as i32)
}
})
.await
}
pub async fn resolve_blob(
ctx: &GraphqlContext,
oid: String,
) -> anyhow::Result<BlobResult> {
let repo = ctx.repo.clone();
let oid_obj = ObjectId::new(&oid);
let result = tokio::task::spawn_blocking(move || {
let size = repo.blob_size(&BlobSizeParams {
id: oid_obj.clone(),
path: String::new(),
})?;
let loaded = repo.blob_load(&BlobLoadParams {
id: oid_obj,
path: String::new(),
})?;
Ok::<(u64, Vec<u8>, String), crate::errors::GitError>((
size,
loaded.blob,
oid,
))
})
.await?
.map_err(|e| anyhow::anyhow!(e))?;
let (size, bytes, oid_str) = result;
let is_binary = bytes.contains(&0);
Ok(BlobResult {
oid: oid_str,
size: size as i32,
is_binary,
})
}