rohas_runtime/
rust_runtime.rs

1use crate::error::{Result, RuntimeError};
2use crate::handler::{HandlerContext, HandlerResult};
3use std::collections::HashMap;
4use std::path::{Path, PathBuf};
5use std::sync::{Arc, Mutex};
6use tokio::sync::RwLock;
7use tracing::{debug, info, warn};
8
9pub struct RustRuntime {
10    handlers: Arc<RwLock<HashMap<String, RustHandlerFn>>>,
11    project_root: Arc<Mutex<Option<PathBuf>>>,
12}
13
14type RustHandlerFn = Box<
15    dyn Fn(HandlerContext) -> std::pin::Pin<Box<dyn std::future::Future<Output = Result<HandlerResult>> + Send>> + Send + Sync,
16>;
17
18impl RustRuntime {
19    pub fn new() -> Result<Self> {
20        info!("Rust runtime initialized");
21
22        Ok(Self {
23            handlers: Arc::new(RwLock::new(HashMap::new())),
24            project_root: Arc::new(Mutex::new(None)),
25        })
26    }
27
28    pub fn set_project_root(&mut self, root: PathBuf) {
29        let mut project_root = self.project_root.lock().unwrap();
30        *project_root = Some(root);
31    }
32
33    pub async fn register_handler<F, Fut>(&self, name: String, handler: F)
34    where
35        F: Fn(HandlerContext) -> Fut + Send + Sync + 'static,
36        Fut: std::future::Future<Output = Result<HandlerResult>> + Send + 'static,
37    {
38        let handler_fn: RustHandlerFn = Box::new(move |ctx| {
39            Box::pin(handler(ctx))
40        });
41
42        let mut handlers = self.handlers.write().await;
43        let was_present = handlers.contains_key(&name);
44
45        let handler_ptr = &handler_fn as *const _ as usize;
46        if was_present {
47            if let Some(old_handler) = handlers.get(&name) {
48                let old_ptr = old_handler as *const _ as usize;
49                info!("Re-registering Rust handler: {} (old closure ptr: 0x{:x}, new closure ptr: 0x{:x})", name, old_ptr, handler_ptr);
50                if old_ptr == handler_ptr {
51                    warn!("WARNING: Handler closure pointer is the same! This may indicate the handler wasn't actually replaced.");
52                } else {
53                    info!("Handler closure pointer changed - old handler should be replaced");
54                }
55            } else {
56                info!("Re-registering Rust handler: {} (new closure ptr: 0x{:x})", name, handler_ptr);
57            }
58            handlers.remove(&name);
59        } else {
60            info!("Registering Rust handler: {} (closure ptr: 0x{:x})", name, handler_ptr);
61        }
62
63        handlers.insert(name.clone(), handler_fn);
64    }
65
66    pub async fn execute_handler(
67        &self,
68        handler_path: &Path,
69        context: HandlerContext,
70    ) -> Result<HandlerResult> {
71        let start = std::time::Instant::now();
72        let handler_name = context.handler_name.clone();
73
74        debug!("Executing Rust handler: {:?}", handler_path);
75
76        {
77            let handlers = self.handlers.read().await;
78            if let Some(handler_fn) = handlers.get(&handler_name) {
79                let closure_ptr = handler_fn as *const _ as usize;
80                debug!("Executing registered Rust handler: {} (closure pointer: 0x{:x})", handler_name, closure_ptr);
81                let result = handler_fn(context).await?;
82                let execution_time_ms = start.elapsed().as_millis() as u64;
83
84                if let Some(data) = &result.data {
85                    if let Some(data_str) = data.as_str() {
86                        debug!("Handler response snippet: {}...", &data_str[..data_str.len().min(50)]);
87                    }
88                }
89
90                return Ok(HandlerResult {
91                    execution_time_ms,
92                    ..result
93                });
94            }
95        }
96
97        self.execute_handler_from_file(handler_path, context, start).await
98    }
99
100    async fn execute_handler_from_file(
101        &self,
102        handler_path: &Path,
103        context: HandlerContext,
104        start: std::time::Instant,
105    ) -> Result<HandlerResult> {
106        let execution_time_ms = start.elapsed().as_millis() as u64;
107
108        Err(RuntimeError::HandlerNotFound(format!(
109            "Rust handler '{}' not found. To register handlers, call the init_handlers function from your generated project.\n\
110            Example: rust_example::init_handlers(runtime).await\n\
111            Or call: generated::register_all_handlers(runtime).await\n\
112            Handler path: {:?}",
113            context.handler_name,
114            handler_path
115        )))
116    }
117
118    pub async fn handler_count(&self) -> usize {
119        let handlers = self.handlers.read().await;
120        handlers.len()
121    }
122
123    pub async fn list_handlers(&self) -> Vec<String> {
124        let handlers = self.handlers.read().await;
125        handlers.keys().cloned().collect()
126    }
127
128    pub async fn clear_handlers(&self) {
129        let mut handlers = self.handlers.write().await;
130        handlers.clear();
131        info!("Cleared all Rust handlers");
132    }
133}
134
135impl Default for RustRuntime {
136    fn default() -> Self {
137        Self::new().expect("Failed to initialize Rust runtime")
138    }
139}
140
141/// Helper macro for registering Rust handlers.
142///
143/// This macro simplifies handler registration and ensures type safety.
144///
145/// # Example
146/// ```rust
147/// use rohas_runtime::{RustRuntime, HandlerContext, HandlerResult};
148///
149/// # async fn example() -> Result<(), Box<dyn std::error::Error>> {
150/// let runtime = RustRuntime::new()?;
151///
152/// async fn my_handler(ctx: HandlerContext) -> rohas_runtime::error::Result<HandlerResult> {
153///     // Handler implementation
154///     Ok(HandlerResult::success(serde_json::json!({}), 0))
155/// }
156///
157/// // Register the handler
158/// runtime.register_handler("my_handler".to_string(), my_handler).await;
159/// # Ok(())
160/// # }
161/// ```
162#[macro_export]
163macro_rules! register_rust_handler {
164    ($runtime:expr, $name:expr, $handler:expr) => {
165        $runtime.register_handler($name.to_string(), $handler).await
166    };
167}
168
169#[cfg(test)]
170mod tests {
171    use super::*;
172    use crate::handler::HandlerContext;
173
174    #[tokio::test]
175    async fn test_rust_runtime_creation() {
176        let runtime = RustRuntime::new().unwrap();
177        assert_eq!(runtime.handler_count().await, 0);
178    }
179
180    #[tokio::test]
181    async fn test_handler_registration() {
182        let runtime = Arc::new(RustRuntime::new().unwrap());
183
184        let handler = |ctx: HandlerContext| async move {
185            Ok(HandlerResult::success(
186                serde_json::json!({"message": "test"}),
187                0,
188            ))
189        };
190
191        runtime
192            .register_handler("test_handler".to_string(), handler)
193            .await;
194
195        assert_eq!(runtime.handler_count().await, 1);
196
197        let handlers = runtime.list_handlers().await;
198        assert_eq!(handlers, vec!["test_handler"]);
199    }
200
201    #[tokio::test]
202    async fn test_handler_execution() {
203        let runtime = Arc::new(RustRuntime::new().unwrap());
204
205        let handler = |ctx: HandlerContext| async move {
206            Ok(HandlerResult::success(
207                serde_json::json!({
208                    "handler": ctx.handler_name,
209                    "message": "executed"
210                }),
211                0,
212            ))
213        };
214
215        runtime
216            .register_handler("test_exec".to_string(), handler)
217            .await;
218
219        let context = HandlerContext::new("test_exec", serde_json::json!({}));
220        let result = runtime
221            .execute_handler(Path::new("test.rs"), context)
222            .await
223            .unwrap();
224
225        assert!(result.success);
226        assert_eq!(
227            result.data.unwrap()["handler"],
228            serde_json::json!("test_exec")
229        );
230    }
231}
232