Skip to main content

cortex_runtime/renderer/
mod.rs

1//! Renderer abstraction for browser-based page rendering.
2//!
3//! Defines the `Renderer` and `RenderContext` traits that abstract over
4//! the browser engine (currently Chromium via chromiumoxide).
5
6pub mod chromium;
7
8use anyhow::Result;
9use async_trait::async_trait;
10use serde::{Deserialize, Serialize};
11
12/// Result of navigating to a URL.
13#[derive(Debug, Clone, Serialize, Deserialize)]
14pub struct NavigationResult {
15    /// The final URL after any redirects.
16    pub final_url: String,
17    /// HTTP status code.
18    pub status: u16,
19    /// Chain of redirect URLs.
20    pub redirect_chain: Vec<String>,
21    /// Time taken to load the page in milliseconds.
22    pub load_time_ms: u64,
23}
24
25/// A browser engine that can create rendering contexts.
26#[async_trait]
27pub trait Renderer: Send + Sync {
28    /// Create a new browser context (tab).
29    async fn new_context(&self) -> Result<Box<dyn RenderContext>>;
30    /// Shut down the browser engine.
31    async fn shutdown(&self) -> Result<()>;
32    /// Number of currently active contexts.
33    fn active_contexts(&self) -> usize;
34}
35
36/// A single browser context (tab) for rendering pages.
37#[async_trait]
38pub trait RenderContext: Send + Sync {
39    /// Navigate to a URL with a timeout.
40    async fn navigate(&mut self, url: &str, timeout_ms: u64) -> Result<NavigationResult>;
41    /// Execute JavaScript in the page context and return the result.
42    async fn execute_js(&self, script: &str) -> Result<serde_json::Value>;
43    /// Get the full page HTML.
44    async fn get_html(&self) -> Result<String>;
45    /// Get the current URL.
46    async fn get_url(&self) -> Result<String>;
47    /// Close this context.
48    async fn close(self: Box<Self>) -> Result<()>;
49}
50
51/// A no-op renderer used when Chromium is unavailable.
52///
53/// The mapper's HTTP acquisition layers (0-2.5) work without a browser.
54/// This stub makes Layer 3 (browser fallback) return errors, but everything
55/// else still functions.
56pub struct NoopRenderer;
57
58#[async_trait]
59impl Renderer for NoopRenderer {
60    async fn new_context(&self) -> Result<Box<dyn RenderContext>> {
61        Err(anyhow::anyhow!("Browser not available — HTTP-only mode"))
62    }
63    async fn shutdown(&self) -> Result<()> {
64        Ok(())
65    }
66    fn active_contexts(&self) -> usize {
67        0
68    }
69}