1pub mod wasm_types;
6
7mod macros;
8mod plugin_ctx;
9mod wasm_ctx;
10
11pub use crate::plugin_ctx::{
12 FormPart, HttpRequest, HttpRequestBuilder, HttpResponse, LOG_DEBUG, LOG_ERROR, LOG_INFO,
13 LOG_TRACE, LOG_WARN, PluginContext, PluginContextExt,
14};
15pub use async_trait::async_trait;
16pub use bincode;
17pub use bytes::Bytes;
18pub use http;
19pub use semver::Version;
20use serde::de::DeserializeOwned;
21pub use serde_json;
22use serde_json::Value;
23pub use wasm_ctx::{respond_to_host, WasmHttpContext};
24
25#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
27pub struct PluginInfo {
28 pub version: Version,
30 pub default_config: Value,
32 pub description: String,
34 pub readme: Option<String>,
36}
37
38#[derive(Debug)]
42pub enum Outcome {
43 Continue,
45 Respond(Response),
47}
48
49#[derive(Debug)]
53pub struct Response {
54 pub status: u16,
56 pub headers: Vec<(String, String)>,
58 pub body: Vec<u8>,
60}
61
62#[derive(Debug)]
64pub enum PluginError {
65 ExecuteError(String),
67 NotFound(String),
69 LoadError(String),
71 SerdeError(String),
73 HttpError(String),
75}
76
77pub type PluginResult = Result<Outcome, PluginError>;
78
79impl Outcome {
80 pub fn goon() -> PluginResult {
82 Ok(Outcome::Continue)
83 }
84
85 pub fn respond(status: u16, headers: Vec<(String, String)>, body: Vec<u8>) -> PluginResult {
87 Ok(Outcome::Respond(Response {
88 status,
89 headers,
90 body,
91 }))
92 }
93
94 pub fn reject(status: u16, msg: impl Into<String>) -> PluginResult {
98 Ok(Outcome::Respond(Response {
99 status,
100 headers: Vec::new(),
101 body: msg.into().into_bytes(),
102 }))
103 }
104
105 pub fn execute_error(msg: impl Into<String>) -> PluginResult {
106 Err(PluginError::ExecuteError(msg.into()))
107 }
108
109 pub fn not_found(msg: impl Into<String>) -> PluginResult {
110 Err(PluginError::NotFound(msg.into()))
111 }
112}
113
114impl std::fmt::Display for PluginError {
115 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
116 match self {
117 PluginError::ExecuteError(msg) => write!(f, "{}", msg),
118 PluginError::NotFound(msg) => write!(f, "{}", msg),
119 PluginError::LoadError(msg) => write!(f, "{}", msg),
120 PluginError::SerdeError(msg) => write!(f, "{}", msg),
121 PluginError::HttpError(msg) => write!(f, "{}", msg),
122 }
123 }
124}
125
126#[async_trait]
130pub trait Plugin: Send + Sync {
131 fn name(&self) -> &str;
133 fn info(&self) -> PluginInfo;
135
136 async fn on_request(&self, _ctx: &mut dyn PluginContext) -> PluginResult {
140 Ok(Outcome::Continue)
141 }
142
143 async fn on_request_body(&self, _ctx: &mut dyn PluginContext) -> PluginResult {
147 Ok(Outcome::Continue)
148 }
149
150 async fn on_response(&self, _ctx: &mut dyn PluginContext) -> PluginResult {
152 Ok(Outcome::Continue)
153 }
154
155 async fn on_response_body(&self, _ctx: &mut dyn PluginContext) -> PluginResult {
159 Ok(Outcome::Continue)
160 }
161
162 async fn on_logging(&self, _: &mut dyn PluginContext) {}
164}
165
166pub trait PluginConfigExt: Plugin {
167 fn parse_config<T>(&self, config: &Value) -> Result<T, PluginError>
169 where
170 T: DeserializeOwned,
171 {
172 serde_json::from_value(config.clone()).map_err(|e| {
173 PluginError::SerdeError(format!("[{}] pase plugin config error: {}", self.name(), e))
174 })
175 }
176}
177
178impl<T: Plugin> PluginConfigExt for T {}
179
180pub fn block_on<F: Future>(f: F) -> F::Output {
185 use std::task::{Context, Poll, RawWaker, RawWakerVTable, Waker};
186
187 fn noop_clone(_: *const ()) -> RawWaker {
188 RawWaker::new(std::ptr::null(), &VTABLE)
189 }
190 fn noop(_: *const ()) {}
191 static VTABLE: RawWakerVTable = RawWakerVTable::new(noop_clone, noop, noop, noop);
192
193 let raw_waker = RawWaker::new(std::ptr::null(), &VTABLE);
194 let waker = unsafe { Waker::from_raw(raw_waker) };
195 let mut cx = Context::from_waker(&waker);
196
197 let mut f = std::pin::pin!(f);
198 match f.as_mut().poll(&mut cx) {
199 Poll::Ready(val) => val,
200 Poll::Pending => panic!(
201 "plugin future returned Pending in WASM context; \
202 WASM plugins must not perform real async I/O"
203 ),
204 }
205}