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 { 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 { 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, 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, }) }