rhttp/src/js_engine/bindings.rs

160 lines
4.5 KiB
Rust
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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)))
}