Altair-Bueno / axum-template

Layers, extractors and template engine wrappers for axum based Web MVC applications
https://crates.io/crates/axum-template
MIT License
78 stars 6 forks source link

Mutable access to the inner type of the `Engine` #21

Closed peddermaster2 closed 1 year ago

peddermaster2 commented 1 year ago

My use case is to listen on changes in the template directory and reload the templates (with Tera::full_reload()).

I'm not sure how to provide the required &mut Tera though.

Altair-Bueno commented 1 year ago

By design Engine is read-only. There is no way to obtain a mutable reference to the inner engine

This choice was made to maximise performance. If the engine were wrapped inside a Mutex, we could archive interior mutability, but this would result on lower server throughput. Nonetheless, here are some alternatives:

///! Not tested
use std::sync::{Mutex, Arc};

struct MutableEngine(pub Arc<Mutex<Tera>>);

impl MutableEngine {
    pub fn reload(&self) -> tera::Result<()>{
        self.lock().unwrap().full_reload()
    }
}

impl TemplateEngine for MutableEngine {
    type Error = axum_template::engine::TeraError;

    fn render<S: Serialize>(&self, key: &str, data: S) -> Result<String, Self::Error> {
        let tera = self.0.lock().unwrap();
        let data = Context::from_serialize(data)?;
        let rendered = tera.render(key, &data)?;

        Ok(rendered)
    }
}
///! Not tested

type AppEngine = Engine<Tera>;

#[derive(Clone, FromRef)]
struct AppState {
    engine: AppEngine,
}

#[tokio::main]
async fn main() {
    loop {
        let tera = Tera::new("templates/**.html").expect("Template folder not found");
        let app = Router::new()
            .with_state(AppState {
                engine: Engine::from(tera),
            });

        println!("See example: http://127.0.0.1:8080/example");
        Server::bind(&([127, 0, 0, 1], 8080).into())
            .serve(app.into_make_service())
            .with_graceful_shutdown(async { /* Watch for file changes */ })
            .await
            .unwrap();
    }
}