From 9142f8a1ce54515339a9c771bcb9025d94323436 Mon Sep 17 00:00:00 2001 From: jizhuozhi Date: Thu, 10 Oct 2024 01:32:27 +0800 Subject: [PATCH 01/10] feat: implements Promise for dispatch callback --- plugins/wasm-rust/src/lib.rs | 1 + plugins/wasm-rust/src/promise.rs | 128 +++++++++++++++++++++++++++++++ 2 files changed, 129 insertions(+) create mode 100644 plugins/wasm-rust/src/promise.rs diff --git a/plugins/wasm-rust/src/lib.rs b/plugins/wasm-rust/src/lib.rs index 3296ff648a..ead78755f8 100644 --- a/plugins/wasm-rust/src/lib.rs +++ b/plugins/wasm-rust/src/lib.rs @@ -19,3 +19,4 @@ pub mod log; pub mod plugin_wrapper; pub mod request_wrapper; pub mod rule_matcher; +pub mod promise; diff --git a/plugins/wasm-rust/src/promise.rs b/plugins/wasm-rust/src/promise.rs new file mode 100644 index 0000000000..049d77045c --- /dev/null +++ b/plugins/wasm-rust/src/promise.rs @@ -0,0 +1,128 @@ +use std::cell::RefCell; +use std::rc::Rc; + +enum PromiseState { + Pending, + Fulfilled(T), + Rejected(String), +} + +pub struct Promise { + state: RefCell>, + then_callback: RefCell>>, + catch_callback: RefCell>>, +} + +impl Promise +where + T: 'static + Clone, +{ + pub fn new() -> Rc { + Rc::new(Self { + state: RefCell::new(PromiseState::Pending), + then_callback: RefCell::new(None), + catch_callback: RefCell::new(None), + }) + } + + pub fn fulfill(self: &Rc, value: T) { + *self.state.borrow_mut() = PromiseState::Fulfilled(value.clone()); + if let Some(callback) = self.then_callback.borrow_mut().take() { + callback(value); + } + } + + pub fn reject(self: &Rc, reason: String) { + *self.state.borrow_mut() = PromiseState::Rejected(reason.clone()); + if let Some(callback) = self.catch_callback.borrow_mut().take() { + callback(reason); + } + } + + pub fn then(self: &Rc, f: F) -> Rc> + where + F: FnOnce(T) -> R + 'static, + R: 'static + Clone, + { + let new_promise = Promise::new(); + let new_promise_clone = new_promise.clone(); + match &*self.state.borrow() { + PromiseState::Pending => { + *self.then_callback.borrow_mut() = Some(Box::new(move |value| { + let result = f(value.clone()); + new_promise_clone.fulfill(result); + })); + let new_promise_for_catch = new_promise.clone(); + *self.catch_callback.borrow_mut() = Some(Box::new(move |reason| { + new_promise_for_catch.reject(reason); + })); + } + PromiseState::Fulfilled(value) => { + let result = f(value.clone()); + new_promise.fulfill(result); + } + PromiseState::Rejected(reason) => { + new_promise.reject(reason.clone()); + } + } + new_promise + } + + pub fn catch(self: &Rc, f: F) -> Rc + where + F: FnOnce(String) + 'static, + { + match &*self.state.borrow() { + PromiseState::Pending => *self.catch_callback.borrow_mut() = Some(Box::new(f)), + PromiseState::Fulfilled(_) => {} + PromiseState::Rejected(reason) => { + f(reason.clone()) + } + } + self.clone() + } +} + +#[cfg(test)] +mod test { + use crate::promise::Promise; + use std::cell::RefCell; + use std::rc::Rc; + + #[test] + fn test_fulfill_and_then() { + let cell = Rc::new(RefCell::new(0)); + let cell_clone = cell.clone(); + + let promise = Promise::new(); + promise.then(|x| { + x + x + }).then(|x| { + x * x + }).then(move |x| { + *cell_clone.borrow_mut() = x + }); + + promise.fulfill(1); + assert_eq!(cell.take(), 4) + } + + #[test] + fn test_reject_and_catch() { + let cell = Rc::new(RefCell::new("".to_owned())); + let cell_clone = cell.clone(); + + let promise = Promise::new(); + promise.then(|x: i32| { + x + x + }).then(|x| { + x * x + }).catch(move |reason| { + *cell_clone.borrow_mut() = reason + }); + + promise.reject("panic!".to_string()); + + assert_eq!("panic!", cell.take()) + } +} From 248c1a7c32a000a9f08131587811cd2071fb9d6b Mon Sep 17 00:00:00 2001 From: jizhuozhi Date: Thu, 10 Oct 2024 20:15:57 +0800 Subject: [PATCH 02/10] refactor: public internal functions as hostcalls --- plugins/wasm-rust/src/cluster_wrapper.rs | 2 +- .../src/{internal.rs => hostcalls.rs} | 170 +++++++++--------- plugins/wasm-rust/src/lib.rs | 4 +- plugins/wasm-rust/src/promise.rs | 44 ++--- plugins/wasm-rust/src/request_wrapper.rs | 25 ++- plugins/wasm-rust/src/rule_matcher.rs | 9 +- 6 files changed, 133 insertions(+), 121 deletions(-) rename plugins/wasm-rust/src/{internal.rs => hostcalls.rs} (57%) diff --git a/plugins/wasm-rust/src/cluster_wrapper.rs b/plugins/wasm-rust/src/cluster_wrapper.rs index 2891293fb3..17f311e4c6 100644 --- a/plugins/wasm-rust/src/cluster_wrapper.rs +++ b/plugins/wasm-rust/src/cluster_wrapper.rs @@ -1,4 +1,4 @@ -use crate::{internal::get_property, request_wrapper::get_request_host}; +use crate::{hostcalls::get_property, request_wrapper::get_request_host}; pub trait Cluster { fn cluster_name(&self) -> String; diff --git a/plugins/wasm-rust/src/internal.rs b/plugins/wasm-rust/src/hostcalls.rs similarity index 57% rename from plugins/wasm-rust/src/internal.rs rename to plugins/wasm-rust/src/hostcalls.rs index 4116c5d798..ea714a017e 100644 --- a/plugins/wasm-rust/src/internal.rs +++ b/plugins/wasm-rust/src/hostcalls.rs @@ -15,26 +15,26 @@ #![allow(dead_code)] use proxy_wasm::hostcalls; -use proxy_wasm::types::{BufferType, Bytes, MapType, Status}; +use proxy_wasm::types::{BufferType, Bytes, LogLevel, MapType, Status}; use std::time::{Duration, SystemTime}; -pub(crate) fn get_current_time() -> SystemTime { +pub fn get_current_time() -> SystemTime { hostcalls::get_current_time().unwrap() } -pub(crate) fn get_property(path: Vec<&str>) -> Option { +pub fn get_property(path: Vec<&str>) -> Option { hostcalls::get_property(path).unwrap() } -pub(crate) fn set_property(path: Vec<&str>, value: Option<&[u8]>) { +pub fn set_property(path: Vec<&str>, value: Option<&[u8]>) { hostcalls::set_property(path, value).unwrap() } -pub(crate) fn get_shared_data(key: &str) -> (Option, Option) { +pub fn get_shared_data(key: &str) -> (Option, Option) { hostcalls::get_shared_data(key).unwrap() } -pub(crate) fn set_shared_data( +pub fn set_shared_data( key: &str, value: Option<&[u8]>, cas: Option, @@ -42,23 +42,23 @@ pub(crate) fn set_shared_data( hostcalls::set_shared_data(key, value, cas) } -pub(crate) fn register_shared_queue(name: &str) -> u32 { +pub fn register_shared_queue(name: &str) -> u32 { hostcalls::register_shared_queue(name).unwrap() } -pub(crate) fn resolve_shared_queue(vm_id: &str, name: &str) -> Option { +pub fn resolve_shared_queue(vm_id: &str, name: &str) -> Option { hostcalls::resolve_shared_queue(vm_id, name).unwrap() } -pub(crate) fn dequeue_shared_queue(queue_id: u32) -> Result, Status> { +pub fn dequeue_shared_queue(queue_id: u32) -> Result, Status> { hostcalls::dequeue_shared_queue(queue_id) } -pub(crate) fn enqueue_shared_queue(queue_id: u32, value: Option<&[u8]>) -> Result<(), Status> { +pub fn enqueue_shared_queue(queue_id: u32, value: Option<&[u8]>) -> Result<(), Status> { hostcalls::enqueue_shared_queue(queue_id, value) } -pub(crate) fn dispatch_http_call( +pub fn dispatch_http_call( upstream: &str, headers: Vec<(&str, &str)>, body: Option<&[u8]>, @@ -68,43 +68,43 @@ pub(crate) fn dispatch_http_call( hostcalls::dispatch_http_call(upstream, headers, body, trailers, timeout) } -pub(crate) fn get_http_call_response_headers() -> Vec<(String, String)> { +pub fn get_http_call_response_headers() -> Vec<(String, String)> { hostcalls::get_map(MapType::HttpCallResponseHeaders).unwrap() } -pub(crate) fn get_http_call_response_headers_bytes() -> Vec<(String, Bytes)> { +pub fn get_http_call_response_headers_bytes() -> Vec<(String, Bytes)> { hostcalls::get_map_bytes(MapType::HttpCallResponseHeaders).unwrap() } -pub(crate) fn get_http_call_response_header(name: &str) -> Option { +pub fn get_http_call_response_header(name: &str) -> Option { hostcalls::get_map_value(MapType::HttpCallResponseHeaders, name).unwrap() } -pub(crate) fn get_http_call_response_header_bytes(name: &str) -> Option { +pub fn get_http_call_response_header_bytes(name: &str) -> Option { hostcalls::get_map_value_bytes(MapType::HttpCallResponseHeaders, name).unwrap() } -pub(crate) fn get_http_call_response_body(start: usize, max_size: usize) -> Option { +pub fn get_http_call_response_body(start: usize, max_size: usize) -> Option { hostcalls::get_buffer(BufferType::HttpCallResponseBody, start, max_size).unwrap() } -pub(crate) fn get_http_call_response_trailers() -> Vec<(String, String)> { +pub fn get_http_call_response_trailers() -> Vec<(String, String)> { hostcalls::get_map(MapType::HttpCallResponseTrailers).unwrap() } -pub(crate) fn get_http_call_response_trailers_bytes() -> Vec<(String, Bytes)> { +pub fn get_http_call_response_trailers_bytes() -> Vec<(String, Bytes)> { hostcalls::get_map_bytes(MapType::HttpCallResponseTrailers).unwrap() } -pub(crate) fn get_http_call_response_trailer(name: &str) -> Option { +pub fn get_http_call_response_trailer(name: &str) -> Option { hostcalls::get_map_value(MapType::HttpCallResponseTrailers, name).unwrap() } -pub(crate) fn get_http_call_response_trailer_bytes(name: &str) -> Option { +pub fn get_http_call_response_trailer_bytes(name: &str) -> Option { hostcalls::get_map_value_bytes(MapType::HttpCallResponseTrailers, name).unwrap() } -pub(crate) fn dispatch_grpc_call( +pub fn dispatch_grpc_call( upstream_name: &str, service_name: &str, method_name: &str, @@ -122,15 +122,15 @@ pub(crate) fn dispatch_grpc_call( ) } -pub(crate) fn get_grpc_call_response_body(start: usize, max_size: usize) -> Option { +pub fn get_grpc_call_response_body(start: usize, max_size: usize) -> Option { hostcalls::get_buffer(BufferType::GrpcReceiveBuffer, start, max_size).unwrap() } -pub(crate) fn cancel_grpc_call(token_id: u32) { +pub fn cancel_grpc_call(token_id: u32) { hostcalls::cancel_grpc_call(token_id).unwrap() } -pub(crate) fn open_grpc_stream( +pub fn open_grpc_stream( cluster_name: &str, service_name: &str, method_name: &str, @@ -139,245 +139,249 @@ pub(crate) fn open_grpc_stream( hostcalls::open_grpc_stream(cluster_name, service_name, method_name, initial_metadata) } -pub(crate) fn get_grpc_stream_initial_metadata() -> Vec<(String, Bytes)> { +pub fn get_grpc_stream_initial_metadata() -> Vec<(String, Bytes)> { hostcalls::get_map_bytes(MapType::GrpcReceiveInitialMetadata).unwrap() } -pub(crate) fn get_grpc_stream_initial_metadata_value(name: &str) -> Option { +pub fn get_grpc_stream_initial_metadata_value(name: &str) -> Option { hostcalls::get_map_value_bytes(MapType::GrpcReceiveInitialMetadata, name).unwrap() } -pub(crate) fn send_grpc_stream_message(token_id: u32, message: Option<&[u8]>, end_stream: bool) { +pub fn send_grpc_stream_message(token_id: u32, message: Option<&[u8]>, end_stream: bool) { hostcalls::send_grpc_stream_message(token_id, message, end_stream).unwrap() } -pub(crate) fn get_grpc_stream_trailing_metadata() -> Vec<(String, Bytes)> { +pub fn get_grpc_stream_trailing_metadata() -> Vec<(String, Bytes)> { hostcalls::get_map_bytes(MapType::GrpcReceiveTrailingMetadata).unwrap() } -pub(crate) fn get_grpc_stream_trailing_metadata_value(name: &str) -> Option { +pub fn get_grpc_stream_trailing_metadata_value(name: &str) -> Option { hostcalls::get_map_value_bytes(MapType::GrpcReceiveTrailingMetadata, name).unwrap() } -pub(crate) fn cancel_grpc_stream(token_id: u32) { +pub fn cancel_grpc_stream(token_id: u32) { hostcalls::cancel_grpc_stream(token_id).unwrap() } -pub(crate) fn close_grpc_stream(token_id: u32) { +pub fn close_grpc_stream(token_id: u32) { hostcalls::close_grpc_stream(token_id).unwrap() } -pub(crate) fn get_grpc_status() -> (u32, Option) { +pub fn get_grpc_status() -> (u32, Option) { hostcalls::get_grpc_status().unwrap() } -pub(crate) fn call_foreign_function( +pub fn call_foreign_function( function_name: &str, arguments: Option<&[u8]>, ) -> Result, Status> { hostcalls::call_foreign_function(function_name, arguments) } -pub(crate) fn done() { +pub fn done() { hostcalls::done().unwrap() } -pub(crate) fn get_http_request_headers() -> Vec<(String, String)> { +pub fn get_http_request_headers() -> Vec<(String, String)> { hostcalls::get_map(MapType::HttpRequestHeaders).unwrap() } -pub(crate) fn get_http_request_headers_bytes() -> Vec<(String, Bytes)> { +pub fn get_http_request_headers_bytes() -> Vec<(String, Bytes)> { hostcalls::get_map_bytes(MapType::HttpRequestHeaders).unwrap() } -pub(crate) fn set_http_request_headers(headers: Vec<(&str, &str)>) { +pub fn set_http_request_headers(headers: Vec<(&str, &str)>) { hostcalls::set_map(MapType::HttpRequestHeaders, headers).unwrap() } -pub(crate) fn set_http_request_headers_bytes(headers: Vec<(&str, &[u8])>) { +pub fn set_http_request_headers_bytes(headers: Vec<(&str, &[u8])>) { hostcalls::set_map_bytes(MapType::HttpRequestHeaders, headers).unwrap() } -pub(crate) fn get_http_request_header(name: &str) -> Option { +pub fn get_http_request_header(name: &str) -> Option { hostcalls::get_map_value(MapType::HttpRequestHeaders, name).unwrap() } -pub(crate) fn get_http_request_header_bytes(name: &str) -> Option { +pub fn get_http_request_header_bytes(name: &str) -> Option { hostcalls::get_map_value_bytes(MapType::HttpRequestHeaders, name).unwrap() } -pub(crate) fn set_http_request_header(name: &str, value: Option<&str>) { +pub fn set_http_request_header(name: &str, value: Option<&str>) { hostcalls::set_map_value(MapType::HttpRequestHeaders, name, value).unwrap() } -pub(crate) fn set_http_request_header_bytes(name: &str, value: Option<&[u8]>) { +pub fn set_http_request_header_bytes(name: &str, value: Option<&[u8]>) { hostcalls::set_map_value_bytes(MapType::HttpRequestHeaders, name, value).unwrap() } -pub(crate) fn add_http_request_header(name: &str, value: &str) { +pub fn add_http_request_header(name: &str, value: &str) { hostcalls::add_map_value(MapType::HttpRequestHeaders, name, value).unwrap() } -pub(crate) fn add_http_request_header_bytes(name: &str, value: &[u8]) { +pub fn add_http_request_header_bytes(name: &str, value: &[u8]) { hostcalls::add_map_value_bytes(MapType::HttpRequestHeaders, name, value).unwrap() } -pub(crate) fn get_http_request_body(start: usize, max_size: usize) -> Option { +pub fn get_http_request_body(start: usize, max_size: usize) -> Option { hostcalls::get_buffer(BufferType::HttpRequestBody, start, max_size).unwrap() } -pub(crate) fn set_http_request_body(start: usize, size: usize, value: &[u8]) { +pub fn set_http_request_body(start: usize, size: usize, value: &[u8]) { hostcalls::set_buffer(BufferType::HttpRequestBody, start, size, value).unwrap() } -pub(crate) fn get_http_request_trailers() -> Vec<(String, String)> { +pub fn get_http_request_trailers() -> Vec<(String, String)> { hostcalls::get_map(MapType::HttpRequestTrailers).unwrap() } -pub(crate) fn get_http_request_trailers_bytes() -> Vec<(String, Bytes)> { +pub fn get_http_request_trailers_bytes() -> Vec<(String, Bytes)> { hostcalls::get_map_bytes(MapType::HttpRequestTrailers).unwrap() } -pub(crate) fn set_http_request_trailers(trailers: Vec<(&str, &str)>) { +pub fn set_http_request_trailers(trailers: Vec<(&str, &str)>) { hostcalls::set_map(MapType::HttpRequestTrailers, trailers).unwrap() } -pub(crate) fn set_http_request_trailers_bytes(trailers: Vec<(&str, &[u8])>) { +pub fn set_http_request_trailers_bytes(trailers: Vec<(&str, &[u8])>) { hostcalls::set_map_bytes(MapType::HttpRequestTrailers, trailers).unwrap() } -pub(crate) fn get_http_request_trailer(name: &str) -> Option { +pub fn get_http_request_trailer(name: &str) -> Option { hostcalls::get_map_value(MapType::HttpRequestTrailers, name).unwrap() } -pub(crate) fn get_http_request_trailer_bytes(name: &str) -> Option { +pub fn get_http_request_trailer_bytes(name: &str) -> Option { hostcalls::get_map_value_bytes(MapType::HttpRequestTrailers, name).unwrap() } -pub(crate) fn set_http_request_trailer(name: &str, value: Option<&str>) { +pub fn set_http_request_trailer(name: &str, value: Option<&str>) { hostcalls::set_map_value(MapType::HttpRequestTrailers, name, value).unwrap() } -pub(crate) fn set_http_request_trailer_bytes(name: &str, value: Option<&[u8]>) { +pub fn set_http_request_trailer_bytes(name: &str, value: Option<&[u8]>) { hostcalls::set_map_value_bytes(MapType::HttpRequestTrailers, name, value).unwrap() } -pub(crate) fn add_http_request_trailer(name: &str, value: &str) { +pub fn add_http_request_trailer(name: &str, value: &str) { hostcalls::add_map_value(MapType::HttpRequestTrailers, name, value).unwrap() } -pub(crate) fn add_http_request_trailer_bytes(name: &str, value: &[u8]) { +pub fn add_http_request_trailer_bytes(name: &str, value: &[u8]) { hostcalls::add_map_value_bytes(MapType::HttpRequestTrailers, name, value).unwrap() } -pub(crate) fn resume_http_request() { +pub fn resume_http_request() { hostcalls::resume_http_request().unwrap() } -pub(crate) fn reset_http_request() { +pub fn reset_http_request() { hostcalls::reset_http_request().unwrap() } -pub(crate) fn get_http_response_headers() -> Vec<(String, String)> { +pub fn get_http_response_headers() -> Vec<(String, String)> { hostcalls::get_map(MapType::HttpResponseHeaders).unwrap() } -pub(crate) fn get_http_response_headers_bytes() -> Vec<(String, Bytes)> { +pub fn get_http_response_headers_bytes() -> Vec<(String, Bytes)> { hostcalls::get_map_bytes(MapType::HttpResponseHeaders).unwrap() } -pub(crate) fn set_http_response_headers(headers: Vec<(&str, &str)>) { +pub fn set_http_response_headers(headers: Vec<(&str, &str)>) { hostcalls::set_map(MapType::HttpResponseHeaders, headers).unwrap() } -pub(crate) fn set_http_response_headers_bytes(headers: Vec<(&str, &[u8])>) { +pub fn set_http_response_headers_bytes(headers: Vec<(&str, &[u8])>) { hostcalls::set_map_bytes(MapType::HttpResponseHeaders, headers).unwrap() } -pub(crate) fn get_http_response_header(name: &str) -> Option { +pub fn get_http_response_header(name: &str) -> Option { hostcalls::get_map_value(MapType::HttpResponseHeaders, name).unwrap() } -pub(crate) fn get_http_response_header_bytes(name: &str) -> Option { +pub fn get_http_response_header_bytes(name: &str) -> Option { hostcalls::get_map_value_bytes(MapType::HttpResponseHeaders, name).unwrap() } -pub(crate) fn set_http_response_header(name: &str, value: Option<&str>) { +pub fn set_http_response_header(name: &str, value: Option<&str>) { hostcalls::set_map_value(MapType::HttpResponseHeaders, name, value).unwrap() } -pub(crate) fn set_http_response_header_bytes(name: &str, value: Option<&[u8]>) { +pub fn set_http_response_header_bytes(name: &str, value: Option<&[u8]>) { hostcalls::set_map_value_bytes(MapType::HttpResponseHeaders, name, value).unwrap() } -pub(crate) fn add_http_response_header(name: &str, value: &str) { +pub fn add_http_response_header(name: &str, value: &str) { hostcalls::add_map_value(MapType::HttpResponseHeaders, name, value).unwrap() } -pub(crate) fn add_http_response_header_bytes(name: &str, value: &[u8]) { +pub fn add_http_response_header_bytes(name: &str, value: &[u8]) { hostcalls::add_map_value_bytes(MapType::HttpResponseHeaders, name, value).unwrap() } -pub(crate) fn get_http_response_body(start: usize, max_size: usize) -> Option { +pub fn get_http_response_body(start: usize, max_size: usize) -> Option { hostcalls::get_buffer(BufferType::HttpResponseBody, start, max_size).unwrap() } -pub(crate) fn set_http_response_body(start: usize, size: usize, value: &[u8]) { +pub fn set_http_response_body(start: usize, size: usize, value: &[u8]) { hostcalls::set_buffer(BufferType::HttpResponseBody, start, size, value).unwrap() } -pub(crate) fn get_http_response_trailers() -> Vec<(String, String)> { +pub fn get_http_response_trailers() -> Vec<(String, String)> { hostcalls::get_map(MapType::HttpResponseTrailers).unwrap() } -pub(crate) fn get_http_response_trailers_bytes() -> Vec<(String, Bytes)> { +pub fn get_http_response_trailers_bytes() -> Vec<(String, Bytes)> { hostcalls::get_map_bytes(MapType::HttpResponseTrailers).unwrap() } -pub(crate) fn set_http_response_trailers(trailers: Vec<(&str, &str)>) { +pub fn set_http_response_trailers(trailers: Vec<(&str, &str)>) { hostcalls::set_map(MapType::HttpResponseTrailers, trailers).unwrap() } -pub(crate) fn set_http_response_trailers_bytes(trailers: Vec<(&str, &[u8])>) { +pub fn set_http_response_trailers_bytes(trailers: Vec<(&str, &[u8])>) { hostcalls::set_map_bytes(MapType::HttpResponseTrailers, trailers).unwrap() } -pub(crate) fn get_http_response_trailer(name: &str) -> Option { +pub fn get_http_response_trailer(name: &str) -> Option { hostcalls::get_map_value(MapType::HttpResponseTrailers, name).unwrap() } -pub(crate) fn get_http_response_trailer_bytes(name: &str) -> Option { +pub fn get_http_response_trailer_bytes(name: &str) -> Option { hostcalls::get_map_value_bytes(MapType::HttpResponseTrailers, name).unwrap() } -pub(crate) fn set_http_response_trailer(name: &str, value: Option<&str>) { +pub fn set_http_response_trailer(name: &str, value: Option<&str>) { hostcalls::set_map_value(MapType::HttpResponseTrailers, name, value).unwrap() } -pub(crate) fn set_http_response_trailer_bytes(name: &str, value: Option<&[u8]>) { +pub fn set_http_response_trailer_bytes(name: &str, value: Option<&[u8]>) { hostcalls::set_map_value_bytes(MapType::HttpResponseTrailers, name, value).unwrap() } -pub(crate) fn add_http_response_trailer(name: &str, value: &str) { +pub fn add_http_response_trailer(name: &str, value: &str) { hostcalls::add_map_value(MapType::HttpResponseTrailers, name, value).unwrap() } -pub(crate) fn add_http_response_trailer_bytes(name: &str, value: &[u8]) { +pub fn add_http_response_trailer_bytes(name: &str, value: &[u8]) { hostcalls::add_map_value_bytes(MapType::HttpResponseTrailers, name, value).unwrap() } -pub(crate) fn resume_http_response() { +pub fn resume_http_response() { hostcalls::resume_http_response().unwrap() } -pub(crate) fn reset_http_response() { +pub fn reset_http_response() { hostcalls::reset_http_response().unwrap() } -pub(crate) fn send_http_response( +pub fn send_http_response( status_code: u32, headers: Vec<(&str, &str)>, body: Option<&[u8]>, ) { hostcalls::send_http_response(status_code, headers, body).unwrap() } + +pub fn log(level: LogLevel, message: &str) { + hostcalls::log(level, message).unwrap() +} \ No newline at end of file diff --git a/plugins/wasm-rust/src/lib.rs b/plugins/wasm-rust/src/lib.rs index ead78755f8..670a632594 100644 --- a/plugins/wasm-rust/src/lib.rs +++ b/plugins/wasm-rust/src/lib.rs @@ -14,9 +14,9 @@ pub mod cluster_wrapper; pub mod error; -mod internal; +pub mod hostcalls; pub mod log; pub mod plugin_wrapper; +pub mod promise; pub mod request_wrapper; pub mod rule_matcher; -pub mod promise; diff --git a/plugins/wasm-rust/src/promise.rs b/plugins/wasm-rust/src/promise.rs index 049d77045c..b48838b3d0 100644 --- a/plugins/wasm-rust/src/promise.rs +++ b/plugins/wasm-rust/src/promise.rs @@ -1,3 +1,17 @@ +// Copyright (c) 2024 Alibaba Group Holding Ltd. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + use std::cell::RefCell; use std::rc::Rc; @@ -61,9 +75,7 @@ where let result = f(value.clone()); new_promise.fulfill(result); } - PromiseState::Rejected(reason) => { - new_promise.reject(reason.clone()); - } + PromiseState::Rejected(reason) => new_promise.reject(reason.clone()), } new_promise } @@ -75,9 +87,7 @@ where match &*self.state.borrow() { PromiseState::Pending => *self.catch_callback.borrow_mut() = Some(Box::new(f)), PromiseState::Fulfilled(_) => {} - PromiseState::Rejected(reason) => { - f(reason.clone()) - } + PromiseState::Rejected(reason) => f(reason.clone()), } self.clone() } @@ -95,13 +105,10 @@ mod test { let cell_clone = cell.clone(); let promise = Promise::new(); - promise.then(|x| { - x + x - }).then(|x| { - x * x - }).then(move |x| { - *cell_clone.borrow_mut() = x - }); + promise + .then(|x| x + x) + .then(|x| x * x) + .then(move |x| *cell_clone.borrow_mut() = x); promise.fulfill(1); assert_eq!(cell.take(), 4) @@ -113,13 +120,10 @@ mod test { let cell_clone = cell.clone(); let promise = Promise::new(); - promise.then(|x: i32| { - x + x - }).then(|x| { - x * x - }).catch(move |reason| { - *cell_clone.borrow_mut() = reason - }); + promise + .then(|x: i32| x + x) + .then(|x| x * x) + .catch(move |reason| *cell_clone.borrow_mut() = reason); promise.reject("panic!".to_string()); diff --git a/plugins/wasm-rust/src/request_wrapper.rs b/plugins/wasm-rust/src/request_wrapper.rs index bc9624f6a9..c52a08d82e 100644 --- a/plugins/wasm-rust/src/request_wrapper.rs +++ b/plugins/wasm-rust/src/request_wrapper.rs @@ -1,16 +1,13 @@ -use proxy_wasm::hostcalls; - -use crate::internal; +use crate::hostcalls; fn get_request_head(head: &str, log_flag: &str) -> String { - if let Some(value) = internal::get_http_request_header(head) { + if let Some(value) = hostcalls::get_http_request_header(head) { value } else { hostcalls::log( proxy_wasm::types::LogLevel::Error, &format!("get request {} failed", log_flag), - ) - .unwrap(); + ); String::new() } } @@ -31,12 +28,12 @@ pub fn get_request_method() -> String { } pub fn is_binary_request_body() -> bool { - if let Some(content_type) = internal::get_http_request_header("content-type") { + if let Some(content_type) = hostcalls::get_http_request_header("content-type") { if content_type.contains("octet-stream") || content_type.contains("grpc") { return true; } } - if let Some(encoding) = internal::get_http_request_header("content-encoding") { + if let Some(encoding) = hostcalls::get_http_request_header("content-encoding") { if !encoding.is_empty() { return true; } @@ -45,12 +42,12 @@ pub fn is_binary_request_body() -> bool { } pub fn is_binary_response_body() -> bool { - if let Some(content_type) = internal::get_http_response_header("content-type") { + if let Some(content_type) = hostcalls::get_http_response_header("content-type") { if content_type.contains("octet-stream") || content_type.contains("grpc") { return true; } } - if let Some(encoding) = internal::get_http_response_header("content-encoding") { + if let Some(encoding) = hostcalls::get_http_response_header("content-encoding") { if !encoding.is_empty() { return true; } @@ -58,16 +55,16 @@ pub fn is_binary_response_body() -> bool { false } pub fn has_request_body() -> bool { - let content_type = internal::get_http_request_header("content-type"); - let content_length_str = internal::get_http_request_header("content-length"); - let transfer_encoding = internal::get_http_request_header("transfer-encoding"); + let content_type = hostcalls::get_http_request_header("content-type"); + let content_length_str = hostcalls::get_http_request_header("content-length"); + let transfer_encoding = hostcalls::get_http_request_header("transfer-encoding"); hostcalls::log( proxy_wasm::types::LogLevel::Debug, &format!( "check has request body: content_type:{:?}, content_length_str:{:?}, transfer_encoding:{:?}", content_type, content_length_str, transfer_encoding ) - ).unwrap(); + ); if !content_type.is_some_and(|x| !x.is_empty()) { return true; } diff --git a/plugins/wasm-rust/src/rule_matcher.rs b/plugins/wasm-rust/src/rule_matcher.rs index 6478344334..c1420631be 100644 --- a/plugins/wasm-rust/src/rule_matcher.rs +++ b/plugins/wasm-rust/src/rule_matcher.rs @@ -13,7 +13,7 @@ // limitations under the License. use crate::error::WasmRustError; -use crate::internal::{get_http_request_header, get_property}; +use crate::hostcalls::{get_http_request_header, get_property}; use crate::log::Log; use proxy_wasm::hostcalls::log; use proxy_wasm::traits::RootContext; @@ -254,3 +254,10 @@ pub fn on_configure( rule_matcher.parse_rule_config(&value).is_ok() } + +pub fn new_shared() -> SharedRuleMatcher +where + PluginConfig: Default, +{ + Rc::new(RefCell::new(RuleMatcher::default())) +} From 5d7538aa437a525da74252ad5b72aa7a00d71824 Mon Sep 17 00:00:00 2001 From: jizhuozhi Date: Thu, 10 Oct 2024 20:16:33 +0800 Subject: [PATCH 03/10] feat: dispatcher for dispatching http calls --- plugins/wasm-rust/src/dispatcher.rs | 54 +++++++++++++++++++++++++++++ plugins/wasm-rust/src/lib.rs | 1 + 2 files changed, 55 insertions(+) create mode 100644 plugins/wasm-rust/src/dispatcher.rs diff --git a/plugins/wasm-rust/src/dispatcher.rs b/plugins/wasm-rust/src/dispatcher.rs new file mode 100644 index 0000000000..b9f3c8ef36 --- /dev/null +++ b/plugins/wasm-rust/src/dispatcher.rs @@ -0,0 +1,54 @@ +// Copyright (c) 2024 Alibaba Group Holding Ltd. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use crate::hostcalls; +use crate::promise::Promise; +use std::collections::HashMap; +use std::rc::Rc; +use std::time::Duration; + +#[derive(Default)] +pub struct HttpDispatcher { + m: HashMap>>, +} + +impl HttpDispatcher { + pub fn dispatch( + &mut self, + upstream: &str, + headers: Vec<(&str, &str)>, + body: Option<&[u8]>, + trailers: Vec<(&str, &str)>, + timeout: Duration, + ) -> Rc> { + let token = + hostcalls::dispatch_http_call(upstream, headers, body, trailers, timeout).unwrap(); + let promise = Promise::new(); + self.m.insert(token, promise.clone()); + promise + } + + pub fn callback( + &mut self, + _token_id: u32, + _num_headers: usize, + _body_size: usize, + _num_trailers: usize, + ) { + let promise = self.m.remove(&_token_id); + promise + .unwrap() + .fulfill((_token_id, _num_headers, _body_size, _num_trailers)) + } +} diff --git a/plugins/wasm-rust/src/lib.rs b/plugins/wasm-rust/src/lib.rs index 670a632594..0f53b238f2 100644 --- a/plugins/wasm-rust/src/lib.rs +++ b/plugins/wasm-rust/src/lib.rs @@ -13,6 +13,7 @@ // limitations under the License. pub mod cluster_wrapper; +pub mod dispatcher; pub mod error; pub mod hostcalls; pub mod log; From 9bfce1e016598814a73016c3b22e1d68d8f2ed06 Mon Sep 17 00:00:00 2001 From: jizhuozhi Date: Thu, 10 Oct 2024 20:42:02 +0800 Subject: [PATCH 04/10] fix: ci --- plugins/wasm-rust/src/hostcalls.rs | 14 +++----------- 1 file changed, 3 insertions(+), 11 deletions(-) diff --git a/plugins/wasm-rust/src/hostcalls.rs b/plugins/wasm-rust/src/hostcalls.rs index ea714a017e..0cc8919019 100644 --- a/plugins/wasm-rust/src/hostcalls.rs +++ b/plugins/wasm-rust/src/hostcalls.rs @@ -34,11 +34,7 @@ pub fn get_shared_data(key: &str) -> (Option, Option) { hostcalls::get_shared_data(key).unwrap() } -pub fn set_shared_data( - key: &str, - value: Option<&[u8]>, - cas: Option, -) -> Result<(), Status> { +pub fn set_shared_data(key: &str, value: Option<&[u8]>, cas: Option) -> Result<(), Status> { hostcalls::set_shared_data(key, value, cas) } @@ -374,14 +370,10 @@ pub fn reset_http_response() { hostcalls::reset_http_response().unwrap() } -pub fn send_http_response( - status_code: u32, - headers: Vec<(&str, &str)>, - body: Option<&[u8]>, -) { +pub fn send_http_response(status_code: u32, headers: Vec<(&str, &str)>, body: Option<&[u8]>) { hostcalls::send_http_response(status_code, headers, body).unwrap() } pub fn log(level: LogLevel, message: &str) { hostcalls::log(level, message).unwrap() -} \ No newline at end of file +} From b2a1f37062de2a371d53648a562330f955341a1f Mon Sep 17 00:00:00 2001 From: jizhuozhi Date: Thu, 10 Oct 2024 20:57:44 +0800 Subject: [PATCH 05/10] feat: add example of Promise and Dispatcher --- .../example/http-promise-example/Cargo.lock | 262 ++++++++++++++++++ .../example/http-promise-example/Cargo.toml | 15 + .../example/http-promise-example/Makefile | 11 + .../example/http-promise-example/README.md | 26 ++ .../example/http-promise-example/README_EN.md | 26 ++ .../example/http-promise-example/VERSION | 1 + .../example/http-promise-example/src/lib.rs | 130 +++++++++ plugins/wasm-rust/scripts/gen.sh | 253 +++++++++++++++++ 8 files changed, 724 insertions(+) create mode 100644 plugins/wasm-rust/example/http-promise-example/Cargo.lock create mode 100644 plugins/wasm-rust/example/http-promise-example/Cargo.toml create mode 100644 plugins/wasm-rust/example/http-promise-example/Makefile create mode 100644 plugins/wasm-rust/example/http-promise-example/README.md create mode 100644 plugins/wasm-rust/example/http-promise-example/README_EN.md create mode 100644 plugins/wasm-rust/example/http-promise-example/VERSION create mode 100644 plugins/wasm-rust/example/http-promise-example/src/lib.rs create mode 100644 plugins/wasm-rust/scripts/gen.sh diff --git a/plugins/wasm-rust/example/http-promise-example/Cargo.lock b/plugins/wasm-rust/example/http-promise-example/Cargo.lock new file mode 100644 index 0000000000..68d1c13049 --- /dev/null +++ b/plugins/wasm-rust/example/http-promise-example/Cargo.lock @@ -0,0 +1,262 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "ahash" +version = "0.8.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011" +dependencies = [ + "cfg-if", + "once_cell", + "version_check", + "zerocopy", +] + +[[package]] +name = "allocator-api2" +version = "0.2.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c6cb57a04249c6480766f7f7cef5467412af1490f8d1e243141daddada3264f" + +[[package]] +name = "bytes" +version = "1.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "428d9aa8fbc0670b7b8d6030a7fadd0f86151cae55e4dbbece15f3780a3dfaf3" + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + +[[package]] +name = "getrandom" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + +[[package]] +name = "hashbrown" +version = "0.14.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" +dependencies = [ + "ahash", + "allocator-api2", +] + +[[package]] +name = "higress-wasm-rust" +version = "0.1.0" +dependencies = [ + "http", + "lazy_static", + "multimap", + "proxy-wasm", + "serde", + "serde_json", + "uuid", +] + +[[package]] +name = "http" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "21b9ddb458710bc376481b842f5da65cdf31522de232c1ca8146abce2a358258" +dependencies = [ + "bytes", + "fnv", + "itoa", +] + +[[package]] +name = "http-promise-example" +version = "0.1.0" +dependencies = [ + "higress-wasm-rust", + "proxy-wasm", + "serde", + "serde_json", +] + +[[package]] +name = "itoa" +version = "1.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" + +[[package]] +name = "lazy_static" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" + +[[package]] +name = "libc" +version = "0.2.159" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "561d97a539a36e26a9a5fad1ea11a3039a67714694aaa379433e580854bc3dc5" + +[[package]] +name = "log" +version = "0.4.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" + +[[package]] +name = "memchr" +version = "2.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" + +[[package]] +name = "multimap" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "defc4c55412d89136f966bbb339008b474350e5e6e78d2714439c386b3137a03" +dependencies = [ + "serde", +] + +[[package]] +name = "once_cell" +version = "1.20.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775" + +[[package]] +name = "proc-macro2" +version = "1.0.87" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b3e4daa0dcf6feba26f985457cdf104d4b4256fc5a09547140f3631bb076b19a" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "proxy-wasm" +version = "0.2.2" +source = "git+https://github.com/higress-group/proxy-wasm-rust-sdk?branch=main#73833051f57d483570cf5aaa9d62bd7402fae63b" +dependencies = [ + "hashbrown", + "log", +] + +[[package]] +name = "quote" +version = "1.0.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "ryu" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" + +[[package]] +name = "serde" +version = "1.0.210" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8e3592472072e6e22e0a54d5904d9febf8508f65fb8552499a1abc7d1078c3a" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.210" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "243902eda00fad750862fc144cea25caca5e20d615af0a81bee94ca738f1df1f" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "serde_json" +version = "1.0.128" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ff5456707a1de34e7e37f2a6fd3d3f808c318259cbd01ab6377795054b483d8" +dependencies = [ + "itoa", + "memchr", + "ryu", + "serde", +] + +[[package]] +name = "syn" +version = "2.0.79" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89132cd0bf050864e1d38dc3bbc07a0eb8e7530af26344d3d2bbbef83499f590" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "unicode-ident" +version = "1.0.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e91b56cd4cadaeb79bbf1a5645f6b4f8dc5bde8834ad5894a8db35fda9efa1fe" + +[[package]] +name = "uuid" +version = "1.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81dfa00651efa65069b0b6b651f4aaa31ba9e3c3ce0137aaad053604ee7e0314" +dependencies = [ + "getrandom", +] + +[[package]] +name = "version_check" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" + +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" + +[[package]] +name = "zerocopy" +version = "0.7.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0" +dependencies = [ + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.7.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] diff --git a/plugins/wasm-rust/example/http-promise-example/Cargo.toml b/plugins/wasm-rust/example/http-promise-example/Cargo.toml new file mode 100644 index 0000000000..9a0c20666e --- /dev/null +++ b/plugins/wasm-rust/example/http-promise-example/Cargo.toml @@ -0,0 +1,15 @@ +[package] +name = "http-promise-example" +version = "0.1.0" +edition = "2021" +publish = false + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html +[lib] +crate-type = ["cdylib"] + +[dependencies] +higress-wasm-rust = { path = "../../", version = "0.1.0" } +proxy-wasm = { git="https://github.com/higress-group/proxy-wasm-rust-sdk", branch="main", version="0.2.2" } +serde = { version = "1.0", features = ["derive"] } +serde_json = "1.0" diff --git a/plugins/wasm-rust/example/http-promise-example/Makefile b/plugins/wasm-rust/example/http-promise-example/Makefile new file mode 100644 index 0000000000..042046fa26 --- /dev/null +++ b/plugins/wasm-rust/example/http-promise-example/Makefile @@ -0,0 +1,11 @@ +BUILD_OPTS="--release" + +.DEFAULT: +build: + rustup target add wasm32-wasi + cargo build --target wasm32-wasi ${BUILD_OPTS} + find target -name "*.wasm" -d 3 -exec cp "{}" plugin.wasm \; + +clean: + cargo clean + rm -f plugin.wasm diff --git a/plugins/wasm-rust/example/http-promise-example/README.md b/plugins/wasm-rust/example/http-promise-example/README.md new file mode 100644 index 0000000000..8d16005090 --- /dev/null +++ b/plugins/wasm-rust/example/http-promise-example/README.md @@ -0,0 +1,26 @@ +--- +title: http-promise-example +keywords: +description: +--- + +## 功能说明 + + + +## 运行属性 + +stage:`默认阶段` +level:`10` + +### 配置说明 + +| Name | Type | Requirement | Default | Description | +| -------- | -------- | -------- | -------- | -------- | +| | | | | | + +#### 配置示例 + +```yaml + +``` diff --git a/plugins/wasm-rust/example/http-promise-example/README_EN.md b/plugins/wasm-rust/example/http-promise-example/README_EN.md new file mode 100644 index 0000000000..affee75d67 --- /dev/null +++ b/plugins/wasm-rust/example/http-promise-example/README_EN.md @@ -0,0 +1,26 @@ +--- +title: http-promise-example +keywords: +description: +--- + +## Description + + + +## Runtime + +phase:`UNSPECIFIED_PHASE` +priority:`10` + +### Config + +| Name | Type | Requirement | Default | Description | +| -------- | -------- | -------- | -------- | -------- | +| | | | | | + +#### Example + +```yaml + +``` diff --git a/plugins/wasm-rust/example/http-promise-example/VERSION b/plugins/wasm-rust/example/http-promise-example/VERSION new file mode 100644 index 0000000000..6e8bf73aa5 --- /dev/null +++ b/plugins/wasm-rust/example/http-promise-example/VERSION @@ -0,0 +1 @@ +0.1.0 diff --git a/plugins/wasm-rust/example/http-promise-example/src/lib.rs b/plugins/wasm-rust/example/http-promise-example/src/lib.rs new file mode 100644 index 0000000000..f744b42cf4 --- /dev/null +++ b/plugins/wasm-rust/example/http-promise-example/src/lib.rs @@ -0,0 +1,130 @@ +// Copyright (c) 2024 Alibaba Group Holding Ltd. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use higress_wasm_rust::dispatcher::HttpDispatcher; +use higress_wasm_rust::log::Log; +use higress_wasm_rust::rule_matcher::{on_configure, SharedRuleMatcher}; +use higress_wasm_rust::{hostcalls, rule_matcher}; +use proxy_wasm::traits::{Context, HttpContext, RootContext}; +use proxy_wasm::types::{ContextType, HeaderAction, LogLevel}; +use serde::Deserialize; +use std::ops::DerefMut; +use std::rc::Rc; +use std::time::Duration; + +proxy_wasm::main! {{ + proxy_wasm::set_log_level(LogLevel::Trace); + proxy_wasm::set_root_context(|_|Box::new(HttpPromiseExampleRoot::new())); +}} + +struct HttpPromiseExampleRoot { + log: Rc, + rule_matcher: SharedRuleMatcher, +} + +struct HttpPromiseExample { + log: Rc, + rule_matcher: SharedRuleMatcher, + http_dispatcher: HttpDispatcher, +} + +#[derive(Default, Clone, Debug, Deserialize)] +struct HttpPromiseExampleConfig {} + +impl HttpPromiseExampleRoot { + fn new() -> Self { + HttpPromiseExampleRoot { + log: Rc::new(Log::new("http-promise-example".to_string())), + rule_matcher: rule_matcher::new_shared(), + } + } +} + +impl Context for HttpPromiseExampleRoot {} + +impl RootContext for HttpPromiseExampleRoot { + fn on_configure(&mut self, _plugin_configuration_size: usize) -> bool { + on_configure( + self, + _plugin_configuration_size, + self.rule_matcher.borrow_mut().deref_mut(), + &self.log, + ) + } + + fn create_http_context(&self, _context_id: u32) -> Option> { + Some(Box::new(HttpPromiseExample { + log: self.log.clone(), + rule_matcher: self.rule_matcher.clone(), + http_dispatcher: Default::default(), + })) + } + + fn get_type(&self) -> Option { + Some(ContextType::HttpContext) + } +} + +impl Context for HttpPromiseExample { + fn on_http_call_response( + &mut self, + _token_id: u32, + _num_headers: usize, + _body_size: usize, + _num_trailers: usize, + ) { + self.http_dispatcher + .callback(_token_id, _num_headers, _body_size, _num_trailers) + } +} + +impl HttpContext for HttpPromiseExample { + fn on_http_request_headers(&mut self, _: usize, _: bool) -> HeaderAction { + let log = self.log.clone(); + + self.http_dispatcher + .dispatch( + "httpbin", + vec![ + (":method", "GET"), + (":path", "/bytes/1"), + (":authority", "httpbin.org"), + ], + None, + vec![], + Duration::from_secs(1), + ) + .then(move |(_, _, _body_size, _)| { + if let Some(body) = hostcalls::get_http_call_response_body(0, _body_size) { + if !body.is_empty() && body[0] % 2 == 0 { + log.info("Access granted."); + hostcalls::resume_http_request(); + return; + } + } + log.info("Access forbidden."); + hostcalls::send_http_response( + 403, + vec![("Powered-By", "proxy-wasm")], + Some(b"Access forbidden.\n"), + ); + }); + HeaderAction::StopIteration + } + + fn on_http_response_headers(&mut self, _: usize, _: bool) -> HeaderAction { + self.set_http_response_header("Powered-By", Some("proxy-wasm")); + HeaderAction::Continue + } +} diff --git a/plugins/wasm-rust/scripts/gen.sh b/plugins/wasm-rust/scripts/gen.sh new file mode 100644 index 0000000000..e9976cc836 --- /dev/null +++ b/plugins/wasm-rust/scripts/gen.sh @@ -0,0 +1,253 @@ +#!/bin/sh + +plugin_root=$(cd "$(dirname $0)/..";pwd) + +name='' +keywords='' +description='' +version="0.1.0" +output="$plugin_root/extensions" + +help() { + echo "$0 is used to generated Rust WASM extensions." + echo "Usage:" + echo " $0 [arguments]" + echo "The arguments are:" + echo " --name NAME the name of extension" + echo " --keywords KEYWORDS the keywords of extension [optional]" + echo " --description DESCRIPTION the description of extension [optional]" + echo " --version VERSION the version of extension, default version is \"0.1.0\" [optional]" + echo " --output OUTPUT the output folder of extension, default output is {PROJECT_ROOT}/plugins/wasm-rust/extensions/ [optional]" + exit 1 +} + +while [[ $# -gt 0 ]]; do + case $1 in + --name) + name="$2" + shift # past argument + shift # past value + ;; + --keywords) + keywords="$2" + shift # past argument + shift # past value + ;; + --description) + description="$2" + shift # past argument + shift # past value + ;; + --phase) + phase="$2" + shift # past argument + shift # past value + ;; + --priority) + priority="$2" + shift # past argument + shift # past value + ;; + --version) + version="$2" + shift # past argument + shift # past value + ;; + --output) + output="$2" + shift # past argument + shift # past value + ;; + *) + help + esac +done + +if [ "$name" = "" ]; then + help +fi + +workdir=$output/"$name" +srcdir="$workdir"/src + +mkdir -p "$workdir" +mkdir -p "$srcdir" + +cat -t >"$workdir/Makefile"<"$workdir"/Cargo.toml<"$srcdir"/lib.rs<, + rule_matcher: SharedRuleMatcher<$struct_config_>, +} + +struct $struct_ { + log: Rc, + rule_matcher: SharedRuleMatcher<$struct_config_>, +} + +#[derive(Default, Clone, Debug, Deserialize)] +struct $struct_config_ {} + +impl $struct_root_ { + fn new() -> Self { + $struct_root_ { + log: Rc::new(Log::new("$name".to_string())), + rule_matcher: rule_matcher::new_shared(), + } + } +} + +impl Context for $struct_root_ {} + +impl RootContext for $struct_root_ { + fn on_configure(&mut self, _plugin_configuration_size: usize) -> bool { + on_configure( + self, + _plugin_configuration_size, + self.rule_matcher.borrow_mut().deref_mut(), + &self.log, + ) + } + + fn create_http_context(&self, _context_id: u32) -> Option> { + Some(Box::new($struct_ { + log: self.log.clone(), + rule_matcher: self.rule_matcher.clone(), + })) + } + + fn get_type(&self) -> Option { + Some(ContextType::HttpContext) + } +} + +impl Context for $struct_ {} + +impl HttpContext for $struct_ {} +EOF + +cat >"$workdir/VERSION"<"$workdir/README.md"<"$workdir/README_EN.md"< Date: Thu, 10 Oct 2024 21:02:36 +0800 Subject: [PATCH 06/10] feat: add example of http-dispatch --- .../Cargo.lock | 2 +- .../Cargo.toml | 2 +- .../Makefile | 2 +- .../README.md | 2 +- .../README_EN.md | 2 +- .../VERSION | 0 .../src/lib.rs | 26 +++++++++---------- plugins/wasm-rust/scripts/gen.sh | 2 +- 8 files changed, 19 insertions(+), 19 deletions(-) rename plugins/wasm-rust/example/{http-promise-example => http-dispatch-example}/Cargo.lock (99%) rename plugins/wasm-rust/example/{http-promise-example => http-dispatch-example}/Cargo.toml (93%) rename plugins/wasm-rust/example/{http-promise-example => http-dispatch-example}/Makefile (78%) rename plugins/wasm-rust/example/{http-promise-example => http-dispatch-example}/README.md (92%) rename plugins/wasm-rust/example/{http-promise-example => http-dispatch-example}/README_EN.md (92%) rename plugins/wasm-rust/example/{http-promise-example => http-dispatch-example}/VERSION (100%) rename plugins/wasm-rust/example/{http-promise-example => http-dispatch-example}/src/lib.rs (86%) diff --git a/plugins/wasm-rust/example/http-promise-example/Cargo.lock b/plugins/wasm-rust/example/http-dispatch-example/Cargo.lock similarity index 99% rename from plugins/wasm-rust/example/http-promise-example/Cargo.lock rename to plugins/wasm-rust/example/http-dispatch-example/Cargo.lock index 68d1c13049..7d3f61b915 100644 --- a/plugins/wasm-rust/example/http-promise-example/Cargo.lock +++ b/plugins/wasm-rust/example/http-dispatch-example/Cargo.lock @@ -84,7 +84,7 @@ dependencies = [ ] [[package]] -name = "http-promise-example" +name = "http-dispatch-example" version = "0.1.0" dependencies = [ "higress-wasm-rust", diff --git a/plugins/wasm-rust/example/http-promise-example/Cargo.toml b/plugins/wasm-rust/example/http-dispatch-example/Cargo.toml similarity index 93% rename from plugins/wasm-rust/example/http-promise-example/Cargo.toml rename to plugins/wasm-rust/example/http-dispatch-example/Cargo.toml index 9a0c20666e..c68ff20ac6 100644 --- a/plugins/wasm-rust/example/http-promise-example/Cargo.toml +++ b/plugins/wasm-rust/example/http-dispatch-example/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "http-promise-example" +name = "http-dispatch-example" version = "0.1.0" edition = "2021" publish = false diff --git a/plugins/wasm-rust/example/http-promise-example/Makefile b/plugins/wasm-rust/example/http-dispatch-example/Makefile similarity index 78% rename from plugins/wasm-rust/example/http-promise-example/Makefile rename to plugins/wasm-rust/example/http-dispatch-example/Makefile index 042046fa26..db0061daf7 100644 --- a/plugins/wasm-rust/example/http-promise-example/Makefile +++ b/plugins/wasm-rust/example/http-dispatch-example/Makefile @@ -3,7 +3,7 @@ BUILD_OPTS="--release" .DEFAULT: build: rustup target add wasm32-wasi - cargo build --target wasm32-wasi ${BUILD_OPTS} + cargo build --target wasm32-wasi find target -name "*.wasm" -d 3 -exec cp "{}" plugin.wasm \; clean: diff --git a/plugins/wasm-rust/example/http-promise-example/README.md b/plugins/wasm-rust/example/http-dispatch-example/README.md similarity index 92% rename from plugins/wasm-rust/example/http-promise-example/README.md rename to plugins/wasm-rust/example/http-dispatch-example/README.md index 8d16005090..b46e4b3fd1 100644 --- a/plugins/wasm-rust/example/http-promise-example/README.md +++ b/plugins/wasm-rust/example/http-dispatch-example/README.md @@ -1,5 +1,5 @@ --- -title: http-promise-example +title: http-dispatch-example keywords: description: --- diff --git a/plugins/wasm-rust/example/http-promise-example/README_EN.md b/plugins/wasm-rust/example/http-dispatch-example/README_EN.md similarity index 92% rename from plugins/wasm-rust/example/http-promise-example/README_EN.md rename to plugins/wasm-rust/example/http-dispatch-example/README_EN.md index affee75d67..1c16155512 100644 --- a/plugins/wasm-rust/example/http-promise-example/README_EN.md +++ b/plugins/wasm-rust/example/http-dispatch-example/README_EN.md @@ -1,5 +1,5 @@ --- -title: http-promise-example +title: http-dispatch-example keywords: description: --- diff --git a/plugins/wasm-rust/example/http-promise-example/VERSION b/plugins/wasm-rust/example/http-dispatch-example/VERSION similarity index 100% rename from plugins/wasm-rust/example/http-promise-example/VERSION rename to plugins/wasm-rust/example/http-dispatch-example/VERSION diff --git a/plugins/wasm-rust/example/http-promise-example/src/lib.rs b/plugins/wasm-rust/example/http-dispatch-example/src/lib.rs similarity index 86% rename from plugins/wasm-rust/example/http-promise-example/src/lib.rs rename to plugins/wasm-rust/example/http-dispatch-example/src/lib.rs index f744b42cf4..318cc9199c 100644 --- a/plugins/wasm-rust/example/http-promise-example/src/lib.rs +++ b/plugins/wasm-rust/example/http-dispatch-example/src/lib.rs @@ -25,35 +25,35 @@ use std::time::Duration; proxy_wasm::main! {{ proxy_wasm::set_log_level(LogLevel::Trace); - proxy_wasm::set_root_context(|_|Box::new(HttpPromiseExampleRoot::new())); + proxy_wasm::set_root_context(|_|Box::new(HttpDispatchExampleRoot::new())); }} -struct HttpPromiseExampleRoot { +struct HttpDispatchExampleRoot { log: Rc, - rule_matcher: SharedRuleMatcher, + rule_matcher: SharedRuleMatcher, } -struct HttpPromiseExample { +struct HttpDispatchExample { log: Rc, - rule_matcher: SharedRuleMatcher, + rule_matcher: SharedRuleMatcher, http_dispatcher: HttpDispatcher, } #[derive(Default, Clone, Debug, Deserialize)] -struct HttpPromiseExampleConfig {} +struct HttpDispatchExampleConfig {} -impl HttpPromiseExampleRoot { +impl HttpDispatchExampleRoot { fn new() -> Self { - HttpPromiseExampleRoot { + HttpDispatchExampleRoot { log: Rc::new(Log::new("http-promise-example".to_string())), rule_matcher: rule_matcher::new_shared(), } } } -impl Context for HttpPromiseExampleRoot {} +impl Context for HttpDispatchExampleRoot {} -impl RootContext for HttpPromiseExampleRoot { +impl RootContext for HttpDispatchExampleRoot { fn on_configure(&mut self, _plugin_configuration_size: usize) -> bool { on_configure( self, @@ -64,7 +64,7 @@ impl RootContext for HttpPromiseExampleRoot { } fn create_http_context(&self, _context_id: u32) -> Option> { - Some(Box::new(HttpPromiseExample { + Some(Box::new(HttpDispatchExample { log: self.log.clone(), rule_matcher: self.rule_matcher.clone(), http_dispatcher: Default::default(), @@ -76,7 +76,7 @@ impl RootContext for HttpPromiseExampleRoot { } } -impl Context for HttpPromiseExample { +impl Context for HttpDispatchExample { fn on_http_call_response( &mut self, _token_id: u32, @@ -89,7 +89,7 @@ impl Context for HttpPromiseExample { } } -impl HttpContext for HttpPromiseExample { +impl HttpContext for HttpDispatchExample { fn on_http_request_headers(&mut self, _: usize, _: bool) -> HeaderAction { let log = self.log.clone(); diff --git a/plugins/wasm-rust/scripts/gen.sh b/plugins/wasm-rust/scripts/gen.sh index e9976cc836..57bb3ed82c 100644 --- a/plugins/wasm-rust/scripts/gen.sh +++ b/plugins/wasm-rust/scripts/gen.sh @@ -73,7 +73,7 @@ srcdir="$workdir"/src mkdir -p "$workdir" mkdir -p "$srcdir" -cat -t >"$workdir/Makefile"<"$workdir/Makefile"< Date: Thu, 10 Oct 2024 21:08:14 +0800 Subject: [PATCH 07/10] feat: add example of http-dispatch --- plugins/wasm-rust/example/http-dispatch-example/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/wasm-rust/example/http-dispatch-example/src/lib.rs b/plugins/wasm-rust/example/http-dispatch-example/src/lib.rs index 318cc9199c..dec0baea3a 100644 --- a/plugins/wasm-rust/example/http-dispatch-example/src/lib.rs +++ b/plugins/wasm-rust/example/http-dispatch-example/src/lib.rs @@ -45,7 +45,7 @@ struct HttpDispatchExampleConfig {} impl HttpDispatchExampleRoot { fn new() -> Self { HttpDispatchExampleRoot { - log: Rc::new(Log::new("http-promise-example".to_string())), + log: Rc::new(Log::new("http-dispatch-example".to_string())), rule_matcher: rule_matcher::new_shared(), } } From 7a68fe48e0c8f8cfb5222daac1559216afc74d05 Mon Sep 17 00:00:00 2001 From: jizhuozhi Date: Thu, 10 Oct 2024 22:15:11 +0800 Subject: [PATCH 08/10] feat: implements Promise for dispatch callback --- .../example/http-dispatch-example/Makefile | 2 +- .../http-dispatch-example/docker-compose.yaml | 38 ++++++++++ .../example/http-dispatch-example/envoy.yaml | 75 +++++++++++++++++++ plugins/wasm-rust/scripts/gen.sh | 10 ++- 4 files changed, 122 insertions(+), 3 deletions(-) create mode 100644 plugins/wasm-rust/example/http-dispatch-example/docker-compose.yaml create mode 100644 plugins/wasm-rust/example/http-dispatch-example/envoy.yaml diff --git a/plugins/wasm-rust/example/http-dispatch-example/Makefile b/plugins/wasm-rust/example/http-dispatch-example/Makefile index db0061daf7..042046fa26 100644 --- a/plugins/wasm-rust/example/http-dispatch-example/Makefile +++ b/plugins/wasm-rust/example/http-dispatch-example/Makefile @@ -3,7 +3,7 @@ BUILD_OPTS="--release" .DEFAULT: build: rustup target add wasm32-wasi - cargo build --target wasm32-wasi + cargo build --target wasm32-wasi ${BUILD_OPTS} find target -name "*.wasm" -d 3 -exec cp "{}" plugin.wasm \; clean: diff --git a/plugins/wasm-rust/example/http-dispatch-example/docker-compose.yaml b/plugins/wasm-rust/example/http-dispatch-example/docker-compose.yaml new file mode 100644 index 0000000000..0d480ea214 --- /dev/null +++ b/plugins/wasm-rust/example/http-dispatch-example/docker-compose.yaml @@ -0,0 +1,38 @@ +# Copyright (c) 2023 Alibaba Group Holding Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +services: + envoy: + image: higress-registry.cn-hangzhou.cr.aliyuncs.com/higress/all-in-one:latest + entrypoint: /usr/local/bin/envoy + command: -c /etc/envoy/envoy.yaml --component-log-level wasm:debug + depends_on: + - httpbin + hostname: envoy + ports: + - "10000:10000" + volumes: + - ./envoy.yaml:/etc/envoy/envoy.yaml + - ./plugin.wasm:/etc/envoy/plugin.wasm + networks: + - envoymesh + httpbin: + image: mccutchen/go-httpbin + hostname: httpbin + ports: + - "8080:8080" + networks: + - envoymesh +networks: + envoymesh: {} \ No newline at end of file diff --git a/plugins/wasm-rust/example/http-dispatch-example/envoy.yaml b/plugins/wasm-rust/example/http-dispatch-example/envoy.yaml new file mode 100644 index 0000000000..65ee23f844 --- /dev/null +++ b/plugins/wasm-rust/example/http-dispatch-example/envoy.yaml @@ -0,0 +1,75 @@ +# Copyright (c) 2023 Alibaba Group Holding Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +static_resources: + listeners: + - name: listener_0 + address: + socket_address: + protocol: TCP + address: 0.0.0.0 + port_value: 10000 + filter_chains: + - filters: + - name: envoy.filters.network.http_connection_manager + typed_config: + "@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager + stat_prefix: ingress_http + route_config: + name: local_route + virtual_hosts: + - name: local_service + domains: ["*"] + routes: + - match: + prefix: "/" + route: + cluster: httpbin + http_filters: + - name: envoy.filters.http.wasm + typed_config: + "@type": type.googleapis.com/udpa.type.v1.TypedStruct + type_url: type.googleapis.com/envoy.extensions.filters.http.wasm.v3.Wasm + value: + config: + name: "http_body" + configuration: + "@type": type.googleapis.com/google.protobuf.StringValue + value: |- + { + "name": "htt-dispatch", + "_rules_": [] + } + vm_config: + runtime: "envoy.wasm.runtime.v8" + code: + local: + filename: "/etc/envoy/plugin.wasm" + - name: envoy.filters.http.router + typed_config: + "@type": type.googleapis.com/envoy.extensions.filters.http.router.v3.Router + clusters: + - name: httpbin + connect_timeout: 5s + type: STRICT_DNS + lb_policy: ROUND_ROBIN + load_assignment: + cluster_name: httpbin + endpoints: + - lb_endpoints: + - endpoint: + address: + socket_address: + address: httpbin + port_value: 8080 diff --git a/plugins/wasm-rust/scripts/gen.sh b/plugins/wasm-rust/scripts/gen.sh index 57bb3ed82c..894405f703 100644 --- a/plugins/wasm-rust/scripts/gen.sh +++ b/plugins/wasm-rust/scripts/gen.sh @@ -79,7 +79,7 @@ BUILD_OPTS="--release" .DEFAULT: build: rustup target add wasm32-wasi - cargo build --target wasm32-wasi ${BUILD_OPTS} + cargo build --target wasm32-wasi \${BUILD_OPTS} find target -name "*.wasm" -d 3 -exec cp "{}" plugin.wasm \; clean: @@ -147,6 +147,7 @@ struct $struct_root_ { struct $struct_ { log: Rc, rule_matcher: SharedRuleMatcher<$struct_config_>, + http_dispatcher: HttpDispatcher, } #[derive(Default, Clone, Debug, Deserialize)] @@ -177,6 +178,7 @@ impl RootContext for $struct_root_ { Some(Box::new($struct_ { log: self.log.clone(), rule_matcher: self.rule_matcher.clone(), + http_dispatcher: Default::default(), })) } @@ -185,7 +187,11 @@ impl RootContext for $struct_root_ { } } -impl Context for $struct_ {} +impl Context for $struct_ { + fn on_http_call_response(&mut self, _token_id: u32, _num_headers: usize, _body_size: usize, _num_trailers: usize) { + self.http_dispatcher.callback(_token_id, _num_headers, _body_size, _num_trailers) + } +} impl HttpContext for $struct_ {} EOF From 59e22b9e0ad3aff3f6a2b02f39ab625f70486084 Mon Sep 17 00:00:00 2001 From: jizhuozhi Date: Thu, 10 Oct 2024 22:21:24 +0800 Subject: [PATCH 09/10] feat: implements Promise for dispatch callback --- plugins/wasm-rust/scripts/gen.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/plugins/wasm-rust/scripts/gen.sh b/plugins/wasm-rust/scripts/gen.sh index 894405f703..516a36abc2 100644 --- a/plugins/wasm-rust/scripts/gen.sh +++ b/plugins/wasm-rust/scripts/gen.sh @@ -125,6 +125,7 @@ cat >"$srcdir"/lib.rs< Date: Thu, 10 Oct 2024 22:24:01 +0800 Subject: [PATCH 10/10] feat: implements Promise for dispatch callback --- .../{example => examples}/http-dispatch-example/Cargo.lock | 0 .../{example => examples}/http-dispatch-example/Cargo.toml | 0 .../{example => examples}/http-dispatch-example/Makefile | 0 .../{example => examples}/http-dispatch-example/README.md | 0 .../{example => examples}/http-dispatch-example/README_EN.md | 0 .../wasm-rust/{example => examples}/http-dispatch-example/VERSION | 0 .../http-dispatch-example/docker-compose.yaml | 0 .../{example => examples}/http-dispatch-example/envoy.yaml | 0 .../{example => examples}/http-dispatch-example/src/lib.rs | 0 9 files changed, 0 insertions(+), 0 deletions(-) rename plugins/wasm-rust/{example => examples}/http-dispatch-example/Cargo.lock (100%) rename plugins/wasm-rust/{example => examples}/http-dispatch-example/Cargo.toml (100%) rename plugins/wasm-rust/{example => examples}/http-dispatch-example/Makefile (100%) rename plugins/wasm-rust/{example => examples}/http-dispatch-example/README.md (100%) rename plugins/wasm-rust/{example => examples}/http-dispatch-example/README_EN.md (100%) rename plugins/wasm-rust/{example => examples}/http-dispatch-example/VERSION (100%) rename plugins/wasm-rust/{example => examples}/http-dispatch-example/docker-compose.yaml (100%) rename plugins/wasm-rust/{example => examples}/http-dispatch-example/envoy.yaml (100%) rename plugins/wasm-rust/{example => examples}/http-dispatch-example/src/lib.rs (100%) diff --git a/plugins/wasm-rust/example/http-dispatch-example/Cargo.lock b/plugins/wasm-rust/examples/http-dispatch-example/Cargo.lock similarity index 100% rename from plugins/wasm-rust/example/http-dispatch-example/Cargo.lock rename to plugins/wasm-rust/examples/http-dispatch-example/Cargo.lock diff --git a/plugins/wasm-rust/example/http-dispatch-example/Cargo.toml b/plugins/wasm-rust/examples/http-dispatch-example/Cargo.toml similarity index 100% rename from plugins/wasm-rust/example/http-dispatch-example/Cargo.toml rename to plugins/wasm-rust/examples/http-dispatch-example/Cargo.toml diff --git a/plugins/wasm-rust/example/http-dispatch-example/Makefile b/plugins/wasm-rust/examples/http-dispatch-example/Makefile similarity index 100% rename from plugins/wasm-rust/example/http-dispatch-example/Makefile rename to plugins/wasm-rust/examples/http-dispatch-example/Makefile diff --git a/plugins/wasm-rust/example/http-dispatch-example/README.md b/plugins/wasm-rust/examples/http-dispatch-example/README.md similarity index 100% rename from plugins/wasm-rust/example/http-dispatch-example/README.md rename to plugins/wasm-rust/examples/http-dispatch-example/README.md diff --git a/plugins/wasm-rust/example/http-dispatch-example/README_EN.md b/plugins/wasm-rust/examples/http-dispatch-example/README_EN.md similarity index 100% rename from plugins/wasm-rust/example/http-dispatch-example/README_EN.md rename to plugins/wasm-rust/examples/http-dispatch-example/README_EN.md diff --git a/plugins/wasm-rust/example/http-dispatch-example/VERSION b/plugins/wasm-rust/examples/http-dispatch-example/VERSION similarity index 100% rename from plugins/wasm-rust/example/http-dispatch-example/VERSION rename to plugins/wasm-rust/examples/http-dispatch-example/VERSION diff --git a/plugins/wasm-rust/example/http-dispatch-example/docker-compose.yaml b/plugins/wasm-rust/examples/http-dispatch-example/docker-compose.yaml similarity index 100% rename from plugins/wasm-rust/example/http-dispatch-example/docker-compose.yaml rename to plugins/wasm-rust/examples/http-dispatch-example/docker-compose.yaml diff --git a/plugins/wasm-rust/example/http-dispatch-example/envoy.yaml b/plugins/wasm-rust/examples/http-dispatch-example/envoy.yaml similarity index 100% rename from plugins/wasm-rust/example/http-dispatch-example/envoy.yaml rename to plugins/wasm-rust/examples/http-dispatch-example/envoy.yaml diff --git a/plugins/wasm-rust/example/http-dispatch-example/src/lib.rs b/plugins/wasm-rust/examples/http-dispatch-example/src/lib.rs similarity index 100% rename from plugins/wasm-rust/example/http-dispatch-example/src/lib.rs rename to plugins/wasm-rust/examples/http-dispatch-example/src/lib.rs