1use crate::error::{Result, RuntimeError};
2use crate::handler::{Handler, HandlerContext, HandlerResult};
3use crate::node_runtime::NodeRuntime;
4use crate::python_runtime::PythonRuntime;
5use crate::rust_runtime::RustRuntime;
6use crate::{Language, RuntimeConfig};
7use rohas_codegen::templates;
8use std::collections::HashMap;
9use std::path::PathBuf;
10use std::sync::Arc;
11use tokio::sync::RwLock;
12use tracing::{debug, info};
13
14pub struct Executor {
15 config: RuntimeConfig,
16 handlers: Arc<RwLock<HashMap<String, Arc<dyn Handler>>>>,
17 python_runtime: Arc<PythonRuntime>,
18 node_runtime: Arc<NodeRuntime>,
19 rust_runtime: Arc<RustRuntime>,
20}
21
22impl Executor {
23 pub fn new(config: RuntimeConfig) -> Self {
24 let mut python_runtime = PythonRuntime::new().expect("Failed to initialize Python runtime");
25 python_runtime.set_project_root(config.project_root.clone());
26 let python_runtime = Arc::new(python_runtime);
27
28 let mut node_runtime = NodeRuntime::new().expect("Failed to initialize Node.js runtime");
29 node_runtime.set_project_root(config.project_root.clone());
30 let node_runtime = Arc::new(node_runtime);
31
32 let mut rust_runtime = RustRuntime::new().expect("Failed to initialize Rust runtime");
33 rust_runtime.set_project_root(config.project_root.clone());
34 let rust_runtime = Arc::new(rust_runtime);
35
36 info!("Executor initialized with Python, Node.js, and Rust runtimes");
37
38 let executor = Self {
39 config: config.clone(),
40 handlers: Arc::new(RwLock::new(HashMap::new())),
41 python_runtime,
42 node_runtime,
43 rust_runtime: rust_runtime.clone(),
44 };
45
46 executor
47 }
48
49
50 pub async fn register_handler(&self, handler: Arc<dyn Handler>) {
51 let name = handler.name().to_string();
52 let mut handlers = self.handlers.write().await;
53 handlers.insert(name.clone(), handler);
54 info!("Registered handler: {}", name);
55 }
56
57 pub async fn execute(
58 &self,
59 handler_name: &str,
60 payload: serde_json::Value,
61 ) -> Result<HandlerResult> {
62 self.execute_with_params(handler_name, payload, HashMap::new())
63 .await
64 }
65
66 pub async fn execute_with_params(
67 &self,
68 handler_name: &str,
69 payload: serde_json::Value,
70 query_params: HashMap<String, String>,
71 ) -> Result<HandlerResult> {
72 debug!("Executing handler: {}", handler_name);
73
74 let mut context = HandlerContext::new(handler_name, payload);
75 context.query_params = query_params;
76
77 {
78 let handlers = self.handlers.read().await;
79 if let Some(handler) = handlers.get(handler_name) {
80 return handler.execute(context.clone()).await;
81 }
82 }
83
84 self.execute_external_handler(context).await
85 }
86
87 pub async fn execute_with_context(&self, context: HandlerContext) -> Result<HandlerResult> {
88 debug!("Executing handler: {}", context.handler_name);
89
90 {
91 let handlers = self.handlers.read().await;
92 if let Some(handler) = handlers.get(&context.handler_name) {
93 return handler.execute(context.clone()).await;
94 }
95 }
96
97 self.execute_external_handler(context).await
98 }
99
100 async fn execute_external_handler(&self, context: HandlerContext) -> Result<HandlerResult> {
101 let start = std::time::Instant::now();
102
103 let handler_path = self.resolve_handler_path(&context.handler_name)?;
104
105 let result = match self.config.language {
106 Language::TypeScript => self.execute_typescript(&handler_path, &context).await,
107 Language::Python => self.execute_python(&handler_path, &context).await,
108 Language::Rust => self.execute_rust(&handler_path, &context).await,
109 };
110
111 let execution_time_ms = start.elapsed().as_millis() as u64;
112
113 match result {
114 Ok(mut res) => {
115 res.execution_time_ms = execution_time_ms;
116 Ok(res)
117 }
118 Err(e) => Ok(HandlerResult::error(e.to_string(), execution_time_ms)),
119 }
120 }
121
122 fn resolve_handler_path(&self, handler_name: &str) -> Result<PathBuf> {
123 let handlers_dir = self.config.project_root.join("src/handlers");
124 let middlewares_dir = self.config.project_root.join("src/middlewares");
125
126 let snake_case_name = templates::to_snake_case(handler_name);
127
128 let possible_paths = [
129 middlewares_dir.join(format!(
130 "{}.{}",
131 snake_case_name,
132 self.config.language.file_extension()
133 )),
134 middlewares_dir.join(format!(
135 "{}.{}",
136 handler_name,
137 self.config.language.file_extension()
138 )),
139 handlers_dir.join(format!(
140 "api/{}.{}",
141 handler_name,
142 self.config.language.file_extension()
143 )),
144 handlers_dir.join(format!(
145 "events/{}.{}",
146 handler_name,
147 self.config.language.file_extension()
148 )),
149 handlers_dir.join(format!(
150 "websockets/{}.{}",
151 handler_name,
152 self.config.language.file_extension()
153 )),
154 handlers_dir.join(format!(
155 "cron/{}.{}",
156 snake_case_name,
157 self.config.language.file_extension()
158 )),
159 handlers_dir.join(format!(
160 "cron/{}.{}",
161 handler_name,
162 self.config.language.file_extension()
163 )),
164 handlers_dir.join(format!(
165 "{}.{}",
166 handler_name,
167 self.config.language.file_extension()
168 )),
169 ];
170
171 for path in &possible_paths {
172 if path.exists() {
173 return Ok(path.clone());
174 }
175 }
176
177 Err(RuntimeError::HandlerNotFound(format!(
178 "Handler '{}' not found in any handlers directory",
179 handler_name
180 )))
181 }
182
183 async fn execute_typescript(
184 &self,
185 handler_path: &PathBuf,
186 context: &HandlerContext,
187 ) -> Result<HandlerResult> {
188 debug!(
189 "Executing TypeScript handler via Node.js runtime: {:?}",
190 handler_path
191 );
192 self.node_runtime
193 .execute_handler(handler_path, context.clone())
194 .await
195 }
196
197 async fn execute_python(
198 &self,
199 handler_path: &PathBuf,
200 context: &HandlerContext,
201 ) -> Result<HandlerResult> {
202 debug!("Executing Python handler via pyo3: {:?}", handler_path);
203 self.python_runtime
204 .execute_handler(handler_path, context.clone())
205 .await
206 }
207
208 async fn execute_rust(
209 &self,
210 handler_path: &PathBuf,
211 context: &HandlerContext,
212 ) -> Result<HandlerResult> {
213 debug!("Executing Rust handler (high-performance): {:?}", handler_path);
214 self.rust_runtime
215 .execute_handler(handler_path, context.clone())
216 .await
217 }
218
219 pub async fn list_handlers(&self) -> Vec<String> {
220 let handlers = self.handlers.read().await;
221 handlers.keys().cloned().collect()
222 }
223
224 pub async fn reload_python_module(&self, module_name: &str) -> Result<()> {
225 self.python_runtime.reload_module(module_name).await
226 }
227
228 pub async fn reload_node_module(&self, module_name: &str) -> Result<()> {
229 self.node_runtime.reload_module(module_name).await
230 }
231
232 pub async fn clear_handler_cache(&self) -> Result<()> {
233 match self.config.language {
234 Language::TypeScript => {
235 self.node_runtime.clear_cache().await?;
236 }
237 Language::Python => {
238 }
241 Language::Rust => {
242 self.rust_runtime.clear_handlers().await;
243 }
244 }
245 Ok(())
246 }
247
248 pub fn rust_runtime(&self) -> &Arc<RustRuntime> {
266 &self.rust_runtime
267 }
268}
269
270#[cfg(test)]
271mod tests {
272 use super::*;
273
274 struct TestHandler {
275 name: String,
276 }
277
278 #[async_trait::async_trait]
279 impl Handler for TestHandler {
280 async fn execute(&self, _context: HandlerContext) -> Result<HandlerResult> {
281 Ok(HandlerResult::success(
282 serde_json::json!({"message": "test"}),
283 0,
284 ))
285 }
286
287 fn name(&self) -> &str {
288 &self.name
289 }
290 }
291
292 #[tokio::test]
293 async fn test_register_and_execute_handler() {
294 let config = RuntimeConfig::default();
295 let executor = Executor::new(config);
296
297 let handler = Arc::new(TestHandler {
298 name: "test_handler".to_string(),
299 });
300
301 executor.register_handler(handler).await;
302
303 let handlers = executor.list_handlers().await;
304 assert_eq!(handlers.len(), 1);
305 assert_eq!(handlers[0], "test_handler");
306
307 let result = executor
308 .execute("test_handler", serde_json::json!({}))
309 .await
310 .unwrap();
311
312 assert!(result.success);
313 }
314}