use crate::js_engine::error::JsEngineError; use rquickjs::{AsyncContext, Ctx, FromJs, IntoJs, Object, Value}; use std::collections::HashMap; /// JavaScript请求对象包装器 #[derive(Debug, Clone)] pub struct JsRequest { pub method: String, pub uri: String, pub headers: HashMap, pub body: Option, } impl<'js> FromJs<'js> for JsRequest { fn from_js(ctx: &Ctx<'js>, value: Value<'js>) -> Result { let obj = value .as_object() .ok_or_else(|| rquickjs::Error::new_from_js("value", "object"))?; let method = obj.get::<_, String>("method")?; let uri = obj.get::<_, String>("uri")?; // 获取headers let headers_obj: Object = match obj.get("headers") { Ok(obj) => obj, Err(_) => Object::new(ctx.clone())?, }; let mut headers = HashMap::new(); for key in headers_obj.keys::() { if let Ok(key_str) = key { if let Ok(value) = headers_obj.get::<_, String>(&key_str) { headers.insert(key_str, value); } } } // 可选的body let body = obj.get::<_, Option>("body").unwrap_or(None); Ok(JsRequest { method, uri, headers, body, }) } } impl<'js> IntoJs<'js> for JsRequest { fn into_js(self, ctx: &Ctx<'js>) -> Result, rquickjs::Error> { let obj = Object::new(ctx.clone())?; obj.set("method", self.method)?; obj.set("uri", self.uri)?; // 设置headers let headers_obj = Object::new(ctx.clone())?; for (key, value) in self.headers { headers_obj.set(key, value)?; } obj.set("headers", headers_obj)?; // 设置body obj.set("body", self.body)?; Ok(obj.into_value()) } } /// JavaScript响应对象包装器 #[derive(Debug, Clone)] pub struct JsResponse { pub status: u16, pub headers: HashMap, pub body: Option, } impl<'js> FromJs<'js> for JsResponse { fn from_js(ctx: &Ctx<'js>, value: Value<'js>) -> Result { let obj = value .as_object() .ok_or_else(|| rquickjs::Error::new_from_js("value", "object"))?; let status = obj.get::<_, u16>("status")?; // 获取headers let headers_obj: Object = match obj.get("headers") { Ok(obj) => obj, Err(_) => Object::new(ctx.clone())?, }; let mut headers = HashMap::new(); for key in headers_obj.keys::() { if let Ok(key_str) = key { if let Ok(value) = headers_obj.get::<_, String>(&key_str) { headers.insert(key_str, value); } } } // 可选的body let body = obj.get::<_, Option>("body").unwrap_or(None); Ok(JsResponse { status, headers, body, }) } } impl<'js> IntoJs<'js> for JsResponse { fn into_js(self, ctx: &Ctx<'js>) -> Result, rquickjs::Error> { let obj = Object::new(ctx.clone())?; obj.set("status", self.status)?; // 设置headers let headers_obj = Object::new(ctx.clone())?; for (key, value) in self.headers { headers_obj.set(key, value)?; } obj.set("headers", headers_obj)?; // 设置body obj.set("body", self.body)?; Ok(obj.into_value()) } } // Note: 由于类型复杂性,实际的HTTP转换函数将在middleware模块中实现 // 这样可以更容易地处理axum/hyper的类型转换 /// 为JavaScript上下文注册全局绑定 pub async fn register_bindings(context: &AsyncContext) -> Result<(), JsEngineError> { context .clone() .with(|ctx| { let globals = ctx.globals(); // 创建console对象 let console = Object::new(ctx.clone())?; // 添加log方法 - 使用简单的函数 let log_func = rquickjs::Function::new(ctx.clone(), |args: Vec| { println!("[JS] {}", args.join(" ")); Ok::<(), rquickjs::Error>(()) })?; console.set("log", log_func)?; globals.set("console", console)?; Ok::<_, rquickjs::Error>(()) }) .await .map_err(|e| JsEngineError::Runtime(format!("Failed to register bindings: {}", e))) }