1use std::{sync::{Arc}, fs::{self}, rc::Rc, collections::{HashMap}, println};
2use actix_files as afs;
3use futures_util::{FutureExt};
4use types::{AppSettings};
5use uuid::Uuid;
6
7use actix_web::{App, HttpServer, web::{self}, HttpResponse, HttpRequest};
8
9use tera::{Tera, Context};
10
11use crate::{types::AppState, components::load_component_custom_function};
12
13use self::broadcast::Broadcaster;
14
15pub mod types;
16pub mod broadcast;
17mod components;
18mod routes;
19
20
21pub async fn configure(settings: AppSettings) -> std::io::Result<()>{
22 let broadcaster = Broadcaster::create();
23 HttpServer::new(move || {
25 let mut tera = Tera::default();
26 let layout_content = fs::read_to_string(&settings.master_layout).expect("Error loading layout");
28 tera.add_raw_template("layout", &layout_content).expect("Error adding template");
29 println!("----------------------------------------------------");
30 println!("Starting route listening for {:?}",std::thread::current().id());
31 let mut app = App::new();
32 app = app.service(routes::state_changed_action);
33 app = app.service(routes::state_changed);
34 app = app.service(routes::component_changed);
35 app = app.service(routes::components);
36 app = app.service(afs::Files::new(&settings.static_folder, &settings.static_folder).show_files_listing());
37
38 let dynamic_pages = settings.pages.clone();
39 let components = settings.components.clone();
40
41 for (key,comp) in &components {
42 let template = comp.template.clone();
43 let template_clone = &template;
44 tera.add_raw_template(key, template_clone.clone().unwrap().as_str()).expect("Error adding template");
45 }
46
47 for (key,component) in &components {
49 let component_name = key.clone().to_string();
50 let comp = component.clone();
51 let custom_function = load_component_custom_function(
52 tera.clone()
53 ,component_name.clone()
54 ,comp.load.clone().unwrap()
55 );
56
57 tera.register_function(
58 &key,
59 custom_function
60 );
61 }
62
63
64 app = app.app_data(web::Data::new(AppState {
65 broadcaster: Arc::clone(&broadcaster),
66 components: components.clone(),
67 pages: dynamic_pages.clone(),
68 tera: tera.clone()
69 }));
70
71 for route in dynamic_pages {
73 let route_cloned = route.clone();
74 let route_path = Rc::new(route_cloned.clone().path);
75
76 let mut has_action = false;
77 let mut has_load = false;
78
79 if route.action.is_some(){
80 has_action = true;
81 }
82
83 if route.load.is_some() {
84 has_load = true;
85 }
86
87 if has_action {
88 app = app.route(&route_path, web::post().to(move |req: HttpRequest,state: web::Data<AppState>, form: web::Form<HashMap<String, String>>| {
89 let app_state = state.clone(); let mut result = "".to_string();
91 async move {
92 let path = req.path().clone();
93 let mut _page = state.pages.iter().find(|p| p.path == path);
94 if _page.is_some(){
95 let mut context = Context::new();
96 let page = _page.unwrap();
97 let mut tera = app_state.tera.clone();
98 let template = page.template.clone();
99 tera.add_raw_template(&path, &template).expect("Error adding template");
100
101 let page_action_function = page.action.clone().unwrap();
103 let action_context = page_action_function(
104 Arc::new(req.clone()),
105 Arc::new(context.clone()),
106 form
107 ).await;
108 let load_context = page.load.clone().unwrap()(
109 Arc::new(req.clone()),
110 action_context
111 ).await;
112
113 context.extend(Arc::try_unwrap(load_context).expect("Error unwrapping context"));
114
115 let body = tera.render(&path, &context).expect("Error rendering template");
116 let mut layout_context = Context::new();
117 layout_context.insert("body", &body);
118 let id = Uuid::new_v4();
119 layout_context.insert("uuid", &id.to_string());
120
121 result = tera.render("layout", &layout_context).expect("Error rendering layout template");
122 }
123
124 HttpResponse::Ok().body(result)
125 }.boxed_local()
126 }));
127 }
128
129 if has_load {
130 app = app.route(&route_path, web::get().to(move |req: HttpRequest,state: web::Data<AppState>| {
131 let app_state = state.clone(); let mut result = "".to_string();
133 async move {
134 let path = req.path().clone();
135 let mut _page = state.pages.iter().find(|p| p.path == path);
136 if _page.is_some(){
137 let mut context = Context::new();
138 context.insert("state","null");
139 let page = _page.unwrap();
140 let mut tera = app_state.tera.clone();
141 let template = page.template.clone();
142 tera.add_raw_template(&path, &template).expect("Error adding template");
143
144 let page_function = page.load.clone().unwrap();
145 let action_context = page_function(
146 Arc::new(req.clone()),
147 Arc::new(context.clone())
148 ).await;
149
150 context.extend(Arc::try_unwrap(action_context).expect("Error unwrapping context"));
151
152 let body = tera.render(&path, &context).expect("Error rendering template");
153 let mut layout_context = Context::new();
154 layout_context.insert("body", &body);
155 let id = Uuid::new_v4();
156 layout_context.insert("uuid", &id.to_string());
157
158 result = tera.render("layout", &layout_context).expect("Error rendering layout template");
159 }
160
161 HttpResponse::Ok().body(result)
162 }.boxed_local()
163 }));
164
165 println!("Listening to {}",&route_path);
166 }
167 }
168
169
170 app
171 })
172 .bind(format!("{}:{}", settings.address, settings.port)).expect("Error binding server and/or port")
173 .run()
174 .await
175
176
177
178}
179