Gunnar

mikronova/kyokkou

src/renderer.rs

use std::sync::{Arc, Mutex};
use std::time::Duration;

#[derive(Debug, Clone, PartialEq)]
pub enum RenderState {
    Idle,
    Rendering,
    Done(String),
    Error(String),
}

pub struct Renderer {
    pub state: Arc<Mutex<RenderState>>,
}

impl Default for Renderer {
    fn default() -> Self {
        Self { state: Arc::new(Mutex::new(RenderState::Idle)) }
    }
}

impl Renderer {
    pub fn submit(&self, json: String, ctx: egui::Context) {
        let state = self.state.clone();
        *state.lock().unwrap() = RenderState::Rendering;
        std::thread::spawn(move || {
            let result = post_render(json);
            *state.lock().unwrap() = match result {
                Ok(path) => RenderState::Done(path),
                Err(e)   => RenderState::Error(e),
            };
            ctx.request_repaint();
        });
    }
}

fn post_render(json: String) -> Result<String, String> {
    let client = reqwest::blocking::Client::builder()
        .timeout(Duration::from_secs(1800))
        .build()
        .map_err(|e| e.to_string())?;

    let resp = client
        .post("http://localhost:8080/render")
        .header("content-type", "application/json")
        .body(json)
        .send()
        .map_err(|e| e.to_string())?;

    if resp.status().is_success() {
        Ok("/tmp/kyokkou/out/render.png".to_string())
    } else {
        let status = resp.status();
        let body = resp.text().unwrap_or_default();
        Err(format!("{status}: {body}"))
    }
}