From 8a05a21bb528cdf485afc9a9c8ca7dea17ce8612 Mon Sep 17 00:00:00 2001 From: slonkazoid Date: Tue, 24 Dec 2024 23:52:20 +0300 Subject: [PATCH] make blag worse --- src/error.rs | 3 ++ src/post/blag.rs | 102 +++++++++++++++++++++++++++-------------------- 2 files changed, 62 insertions(+), 43 deletions(-) diff --git a/src/error.rs b/src/error.rs index 93d96b2..07f295d 100644 --- a/src/error.rs +++ b/src/error.rs @@ -3,6 +3,7 @@ use std::sync::Arc; use askama_axum::Template; use axum::http::StatusCode; use axum::response::{IntoResponse, Response}; +use color_eyre::eyre; use thiserror::Error; use tracing::error; @@ -17,6 +18,8 @@ pub enum PostError { RenderError(String), #[error("post {0:?} not found")] NotFound(Arc), + #[error("unexpected: {0}")] + Other(#[from] eyre::Error), } impl From for PostError { diff --git a/src/post/blag.rs b/src/post/blag.rs index 35821e1..5ba27c8 100644 --- a/src/post/blag.rs +++ b/src/post/blag.rs @@ -38,10 +38,11 @@ struct BlagMetadata { #[serde(default)] pub tags: BTreeSet>, pub dont_cache: bool, + pub raw: Option>, } impl BlagMetadata { - pub fn into_full(self, name: Arc) -> (PostMetadata, bool) { + pub fn into_full(self, name: Arc) -> (PostMetadata, bool, Option>) { ( PostMetadata { name, @@ -56,6 +57,7 @@ impl BlagMetadata { tags: self.tags.into_iter().collect(), }, self.dont_cache, + self.raw, ) } } @@ -67,6 +69,11 @@ pub struct Blag { _fastblag: bool, } +enum RenderResult { + Normal(PostMetadata, String, (Duration, Duration), bool), + Raw(Vec, Arc), +} + impl Blag { pub fn new(root: Arc, blag_bin: Arc, cache: Option>) -> Blag { Self { @@ -82,7 +89,7 @@ impl Blag { name: Arc, path: impl AsRef, query_json: String, - ) -> Result<(PostMetadata, String, (Duration, Duration), bool), PostError> { + ) -> Result { let start = Instant::now(); debug!(%name, "rendering"); @@ -91,6 +98,8 @@ impl Blag { .arg(path.as_ref()) .env("BLAG_QUERY", query_json) .stdout(Stdio::piped()) + .stderr(Stdio::inherit()) + .stdin(Stdio::null()) .spawn() .map_err(|err| { error!("failed to spawn {:?}: {err}", self.blag_bin); @@ -105,24 +114,36 @@ impl Blag { let blag_meta: BlagMetadata = serde_json::from_str(&buf)?; debug!("blag meta: {blag_meta:?}"); - let (meta, dont_cache) = blag_meta.into_full(name); + let (meta, dont_cache, raw) = blag_meta.into_full(name); + + // this is morally reprehensible + if let Some(raw) = raw { + let mut buf = buf.into_bytes(); + reader.read_to_end(&mut buf).await?; + return Ok(RenderResult::Raw(buf, raw)); + } + let parsed = start.elapsed(); let rendering = Instant::now(); + buf.clear(); reader.read_to_string(&mut buf).await?; - debug!("read output: {} bytes", buf.len()); - - let exit_status = cmd.wait().await?; - debug!("exited: {exit_status}"); - if !exit_status.success() { - return Err(PostError::RenderError(exit_status.to_string())); + let status = cmd.wait().await?; + debug!("exited: {status}"); + if !status.success() { + return Err(PostError::RenderError(status.to_string())); } let rendered = rendering.elapsed(); - Ok((meta, buf, (parsed, rendered), dont_cache)) + Ok(RenderResult::Normal( + meta, + buf, + (parsed, rendered), + dont_cache, + )) } } @@ -233,46 +254,41 @@ impl PostManager for Blag { query_json.hash(&mut hasher); let query_hash = hasher.finish(); - let post = if let Some(cache) = &self.cache { - if let Some(CacheValue { meta, body, .. }) = + let post = if let Some(cache) = &self.cache + && let Some(CacheValue { meta, body, .. }) = cache.lookup(name.clone(), mtime, query_hash).await - { - ReturnedPost::Rendered { - meta, - body, - perf: RenderStats::Cached(start.elapsed()), - } - } else { - let (meta, content, (parsed, rendered), dont_cache) = - self.render(name.clone(), path, query_json).await?; - let body = content.into(); - - if !dont_cache { - cache - .insert(name, meta.clone(), mtime, Arc::clone(&body), query_hash) - .await - .unwrap_or_else(|err| warn!("failed to insert {:?} into cache", err.0)); - } - - let total = start.elapsed(); - ReturnedPost::Rendered { - meta, - body, - perf: RenderStats::Rendered { - total, - parsed, - rendered, - }, - } + { + ReturnedPost::Rendered { + meta, + body, + perf: RenderStats::Cached(start.elapsed()), } } else { - let (meta, content, (parsed, rendered), ..) = - self.render(name, path, query_json).await?; + let (meta, content, (parsed, rendered), dont_cache) = + match self.render(name.clone(), path, query_json).await? { + RenderResult::Normal(x, y, z, w) => (x, y, z, w), + RenderResult::Raw(buffer, content_type) => { + return Ok(ReturnedPost::Raw { + buffer, + content_type: HeaderValue::from_str(&content_type) + .map_err(Into::into) + .map_err(PostError::Other)?, + }); + } + }; + let body = content.into(); + + if !dont_cache && let Some(cache) = &self.cache { + cache + .insert(name, meta.clone(), mtime, Arc::clone(&body), query_hash) + .await + .unwrap_or_else(|err| warn!("failed to insert {:?} into cache", err.0)); + } let total = start.elapsed(); ReturnedPost::Rendered { meta, - body: content.into(), + body, perf: RenderStats::Rendered { total, parsed,