Skip to main content

aiway_plugin/
wasm_types.rs

1//! WASM 插件边界序列化类型
2//!
3//! 定义 Host(网关)与 WASM 插件之间数据交换的格式。
4//! 使用 bincode 序列化,性能优于 JSON。
5
6use crate::http::{self, HeaderName, HeaderValue};
7use serde::{Deserialize, Serialize};
8use std::str::FromStr;
9use std::sync::Arc;
10
11/// 插件钩子 ID
12pub const HOOK_ON_REQUEST: i32 = 1;
13pub const HOOK_ON_REQUEST_BODY: i32 = 2;
14pub const HOOK_ON_RESPONSE: i32 = 3;
15pub const HOOK_ON_RESPONSE_BODY: i32 = 4;
16pub const HOOK_ON_LOGGING: i32 = 5;
17
18/// 传递给 WASM 插件的输入数据
19#[derive(Serialize, Deserialize)]
20pub struct WasmInput {
21    /// 插件配置(JSON 字符串)
22    pub config: Arc<str>,
23    /// HTTP 头部信息(请求或响应)
24    pub head: Option<WasmHead>,
25    /// Body 数据
26    pub body: Option<Vec<u8>>,
27    /// 请求 ID(仅 logging 阶段使用)
28    pub request_id: Option<String>,
29    /// 请求时间戳(仅 logging 阶段使用)
30    pub request_ts: Option<i64>,
31}
32
33/// HTTP 头部信息的可序列化表示
34#[derive(Serialize, Deserialize)]
35pub struct WasmHead {
36    /// 请求方法(仅请求阶段)
37    pub method: Option<String>,
38    /// 请求 URI(仅请求阶段)
39    pub uri: Option<String>,
40    /// 响应状态码(仅响应阶段)
41    pub status: Option<u16>,
42    /// 头部键值对列表
43    pub headers: Vec<(String, String)>,
44}
45
46impl WasmHead {
47    /// 从请求 Parts 构建
48    pub fn from_request_parts(parts: &http::request::Parts) -> Self {
49        let headers = parts
50            .headers
51            .iter()
52            .filter_map(|(k, v)| v.to_str().ok().map(|v| (k.to_string(), v.to_string())))
53            .collect();
54
55        Self {
56            method: Some(parts.method.to_string()),
57            uri: Some(parts.uri.to_string()),
58            status: None,
59            headers,
60        }
61    }
62
63    /// 从响应 Parts 构建
64    pub fn from_response_parts(parts: &http::response::Parts) -> Self {
65        let headers = parts
66            .headers
67            .iter()
68            .filter_map(|(k, v)| v.to_str().ok().map(|v| (k.to_string(), v.to_string())))
69            .collect();
70
71        Self {
72            method: None,
73            uri: None,
74            status: Some(parts.status.as_u16()),
75            headers,
76        }
77    }
78
79    /// 将修改应用到请求 Parts
80    pub fn apply_to_request_parts(&self, parts: &mut http::request::Parts) {
81        if let Some(ref method) = self.method
82            && let Ok(m) = method.parse()
83        {
84            parts.method = m;
85        }
86        if let Some(ref uri) = self.uri
87            && let Ok(u) = uri.parse()
88        {
89            parts.uri = u;
90        }
91        apply_headers(&self.headers, &mut parts.headers);
92    }
93
94    /// 将修改应用到响应 Parts
95    pub fn apply_to_response_parts(&self, parts: &mut http::response::Parts) {
96        if let Some(status) = self.status && let Ok(s) = http::StatusCode::from_u16(status) {
97                parts.status = s;
98            }
99        apply_headers(&self.headers, &mut parts.headers);
100    }
101}
102
103/// 将 WasmHead 中的 headers 应用到 http::HeaderMap
104fn apply_headers(wasm_headers: &[(String, String)], header_map: &mut http::HeaderMap) {
105    header_map.clear();
106    for (k, v) in wasm_headers {
107        if let (Ok(name), Ok(value)) = (HeaderName::from_str(k), HeaderValue::from_str(v)) {
108            header_map.insert(name, value);
109        }
110    }
111}
112
113/// WASM 插件返回的输出数据
114#[derive(Serialize, Deserialize)]
115pub struct WasmOutput {
116    /// 修改后的 HTTP 头部(None 表示不修改)
117    pub head: Option<WasmHead>,
118    /// 修改后的 Body(None 表示不修改)
119    pub body: Option<Vec<u8>>,
120}
121
122/// WASM 插件元信息(由 plugin_info 导出返回)
123#[derive(Serialize, Deserialize)]
124pub struct WasmPluginInfo {
125    pub name: String,
126    pub version: String,
127    pub description: String,
128    /// 默认配置(JSON 字符串)
129    pub default_config: String,
130    /// 插件文档
131    pub readme: Option<String>,
132}