#![cfg_attr(coverage_nightly, coverage(off))]
use anyhow::Result;
use lru::LruCache;
use std::sync::Arc;
use tokio::sync::RwLock;
use crate::models::template::TemplateResource;
use crate::services::renderer::TemplateRenderer;
use crate::{S3Client, TemplateServerTrait};
pub struct StatelessTemplateServer {
pub renderer: TemplateRenderer,
}
impl StatelessTemplateServer {
pub fn new() -> Result<Self> {
Ok(Self {
renderer: TemplateRenderer::new()?,
})
}
pub async fn get_template_metadata(&self, uri: &str) -> Result<Arc<TemplateResource>> {
let parts: Vec<&str> = uri
.strip_prefix("template://")
.ok_or_else(|| anyhow::anyhow!("Invalid URI: {uri}"))?
.split('/')
.collect();
if parts.len() != 3 {
return Err(anyhow::anyhow!("Invalid URI format: {uri}"));
}
crate::services::embedded_templates::get_template_metadata(uri)
.await
.map_err(|e| anyhow::anyhow!("Failed to get template metadata: {e}"))
}
pub async fn get_template_content(&self, uri: &str) -> Result<Arc<str>> {
crate::services::embedded_templates::get_template_content(uri)
.await
.map_err(|e| anyhow::anyhow!("Failed to get template content: {e}"))
}
pub async fn list_templates(&self, prefix: &str) -> Result<Vec<Arc<TemplateResource>>> {
crate::services::embedded_templates::list_templates(prefix)
.await
.map_err(|e| anyhow::anyhow!("Failed to list templates: {e}"))
}
}
#[async_trait::async_trait]
impl TemplateServerTrait for StatelessTemplateServer {
async fn get_template_metadata(&self, uri: &str) -> Result<Arc<TemplateResource>> {
self.get_template_metadata(uri).await
}
async fn get_template_content(&self, s3_key: &str) -> Result<Arc<str>> {
self.get_template_content(s3_key).await
}
async fn list_templates(&self, prefix: &str) -> Result<Vec<Arc<TemplateResource>>> {
self.list_templates(prefix).await
}
fn get_renderer(&self) -> &TemplateRenderer {
&self.renderer
}
fn get_metadata_cache(&self) -> Option<&Arc<RwLock<LruCache<String, Arc<TemplateResource>>>>> {
None
}
fn get_content_cache(&self) -> Option<&Arc<RwLock<LruCache<String, Arc<str>>>>> {
None
}
fn get_s3_client(&self) -> Option<&S3Client> {
None
}
fn get_bucket_name(&self) -> Option<&str> {
None
}
}
#[cfg_attr(coverage_nightly, coverage(off))]
#[cfg(test)]
mod coverage_tests {
use super::*;
use crate::TemplateServerTrait;
include!("stateless_server_tests_basic.rs");
include!("stateless_server_tests_trait_and_edge.rs");
}
#[cfg_attr(coverage_nightly, coverage(off))]
#[cfg(test)]
mod property_tests {
use super::*;
use proptest::prelude::*;
include!("stateless_server_property_tests.rs");
}