use std::path::PathBuf; use std::fs::{self, File}; use std::io::Write; use std::thread; use std::time::Duration; use std::error::Error; use std::sync::Arc; use tera::{Context}; use rhai_system::{create_hot_reloadable_system}; use tera_factory::TeraFactory; /// Function to modify a script file with content from another file fn modify_script(target_path: &PathBuf, source_path: &PathBuf, delay_secs: u64, message: &str) { println!("\nšŸ”„ {}", message); // Read the source script content let source_content = fs::read_to_string(&source_path) .expect(&format!("Failed to read source script file: {}", source_path.display())); // Write the content to the target file let mut file = File::create(target_path) .expect("Failed to open target script file for writing"); file.write_all(source_content.as_bytes()) .expect("Failed to write to target script file"); println!("āœ… Script modified successfully!"); // Wait before the next modification if delay is specified if delay_secs > 0 { thread::sleep(Duration::from_secs(delay_secs)); } } fn main() -> Result<(), Box> { // Set up the script paths let script_dir = PathBuf::from("examples/hot_reload/scripts"); // Main script paths let main_script_path = script_dir.join("main.rhai"); let utils_script_path = script_dir.join("utils.rhai"); // Initial script paths let initial_main_path = script_dir.join("initial_main.rhai"); let initial_utils_path = script_dir.join("initial_utils.rhai"); // Modified script paths let modified_main_path = script_dir.join("modified_main.rhai"); let modified_utils_path = script_dir.join("modified_utils.rhai"); println!("Main script path: {:?}", main_script_path); println!("Utils script path: {:?}", utils_script_path); // Initialize main.rhai with the content from initial_main.rhai let initial_main_content = fs::read_to_string(&initial_main_path) .expect("Failed to read initial main script file"); let mut file = File::create(&main_script_path) .expect("Failed to open main script file for writing"); file.write_all(initial_main_content.as_bytes()) .expect("Failed to write to main script file"); // Initialize utils.rhai with the content from initial_utils.rhai let initial_utils_content = fs::read_to_string(&initial_utils_path) .expect("Failed to read initial utils script file"); let mut file = File::create(&utils_script_path) .expect("Failed to open utils script file for writing"); file.write_all(initial_utils_content.as_bytes()) .expect("Failed to write to utils script file"); // Set up the template path let template_dir = PathBuf::from("examples/hot_reload/templates"); let template_path = template_dir.join("index.html.tera"); println!("Template path: {:?}", template_path); println!("Template exists: {}", template_path.exists()); // Create a hot reloadable Rhai system let script_paths = vec![main_script_path.clone(), utils_script_path.clone()]; // Use the first script as the main script let main_script_index = Some(0); println!("Using main script index: {}", main_script_index.unwrap()); let system = Arc::new(create_hot_reloadable_system(&script_paths, main_script_index)?); // Create a TeraFactory instance let factory = TeraFactory::new(); // Create a Tera instance with the hot reloadable Rhai system println!("Creating Tera with template directory: {}", template_dir.display()); let mut tera = factory.create_tera_with_hot_rhai( &[template_dir.to_str().unwrap()], Arc::clone(&system) )?; // Manually add the template to Tera println!("Manually adding template: {}", template_path.display()); let template_content = fs::read_to_string(&template_path)?; tera.add_raw_template("index.html.tera", &template_content)?; // List available templates println!("Available templates: {:?}", tera.get_template_names().collect::>()); // Create a thread to modify the scripts after a delay let main_script_path_clone = main_script_path.clone(); let utils_script_path_clone = utils_script_path.clone(); let modified_main_path_clone = modified_main_path.clone(); let modified_utils_path_clone = modified_utils_path.clone(); let _modification_thread = thread::spawn(move || { // Modify the main script after 5 seconds modify_script( &main_script_path_clone, &modified_main_path_clone, 5, "Modifying the main script with updated functions..." ); // Modify the utils script after another 5 seconds modify_script( &utils_script_path_clone, &modified_utils_path_clone, 5, "Modifying the utils script with updated functions..." ); }); // Main rendering loop for i in 1..30 { // Create a context with some data let mut context = Context::new(); context.insert("name", "User"); context.insert("current_date", "2025-05-02"); context.insert("current_time", &format!("{:02}:{:02}:{:02}", (12 + i % 12) % 12, i % 60, i % 60)); // Add some products let products = vec![ tera::to_value(serde_json::json!({ "name": "Deluxe Widget", "price": 99.99, "discount": 15.0 })).unwrap(), tera::to_value(serde_json::json!({ "name": "Premium Gadget", "price": 149.95, "discount": 20.0 })).unwrap(), tera::to_value(serde_json::json!({ "name": "Basic Tool", "price": 29.99, "discount": 5.0 })).unwrap(), ]; context.insert("products", &products); // Add some categories let categories = vec![ "Electronics", "Home & Garden", "Clothing", "Sports" ]; context.insert("categories", &categories); // Render the template match tera.render("index.html.tera", &context) { Ok(result) => { // Print the first 500 characters of the result to avoid flooding the console let preview = if result.len() > 500 { format!("{}... (truncated)", &result[..500]) } else { result.clone() }; println!("\n--- Render #{} ---\n{}", i, preview); }, Err(e) => { println!("Error rendering template: {}", e); // Print more detailed error information if let Some(source) = e.source() { println!("Error source: {}", source); if let Some(next_source) = source.source() { println!("Next error source: {}", next_source); } } } } // Wait for a second before rendering again thread::sleep(Duration::from_secs(1)); } Ok(()) }