160 lines
4.5 KiB
Rust
160 lines
4.5 KiB
Rust
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<String, String>,
|
||
pub body: Option<String>,
|
||
}
|
||
|
||
impl<'js> FromJs<'js> for JsRequest {
|
||
fn from_js(ctx: &Ctx<'js>, value: Value<'js>) -> Result<Self, rquickjs::Error> {
|
||
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::<String>() {
|
||
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<String>>("body").unwrap_or(None);
|
||
|
||
Ok(JsRequest {
|
||
method,
|
||
uri,
|
||
headers,
|
||
body,
|
||
})
|
||
}
|
||
}
|
||
|
||
impl<'js> IntoJs<'js> for JsRequest {
|
||
fn into_js(self, ctx: &Ctx<'js>) -> Result<Value<'js>, 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<String, String>,
|
||
pub body: Option<String>,
|
||
}
|
||
|
||
impl<'js> FromJs<'js> for JsResponse {
|
||
fn from_js(ctx: &Ctx<'js>, value: Value<'js>) -> Result<Self, rquickjs::Error> {
|
||
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::<String>() {
|
||
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<String>>("body").unwrap_or(None);
|
||
|
||
Ok(JsResponse {
|
||
status,
|
||
headers,
|
||
body,
|
||
})
|
||
}
|
||
}
|
||
|
||
impl<'js> IntoJs<'js> for JsResponse {
|
||
fn into_js(self, ctx: &Ctx<'js>) -> Result<Value<'js>, 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<String>| {
|
||
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)))
|
||
}
|