Skip to content

Commit

Permalink
sdk: add ExecutionCtx to handle asyncio task
Browse files Browse the repository at this point in the history
  • Loading branch information
fuxiaohei committed Aug 23, 2024
1 parent dec0a9a commit 9d21d60
Show file tree
Hide file tree
Showing 21 changed files with 843 additions and 65 deletions.
3 changes: 1 addition & 2 deletions .github/workflows/tests.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -36,5 +36,4 @@ jobs:
shared-key: "build"
- name: test hello-wasm
run: |
cargo build -p hello-wasm --target wasm32-wasi --release
cargo test -p land-wasm-host --release
bash ./tests/test_examples.sh
36 changes: 23 additions & 13 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
[workspace.package]
version = "0.5.0-rc.2"
version = "0.5.0-rc.6"
edition = "2021"
authors = ["fuxiaohei <[email protected]>"]

Expand All @@ -18,6 +18,7 @@ members = [
"lib/wasm-host",
"lib/wasm-server",
"tests/hello-wasm",
"tests/wait-until",
]
default-members = ["land-cli"]
resolver = "2"
Expand Down
73 changes: 64 additions & 9 deletions lib/sdk-macro/src/http_handler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -182,6 +182,57 @@ pub mod land {
pub mod exports {
#[allow(dead_code)]
pub mod land {
#[allow(dead_code)]
pub mod asyncio {
#[allow(dead_code, clippy::all)]
pub mod context {
#[used]
#[doc(hidden)]
static __FORCE_SECTION_REF: fn() = super::super::super::super::__link_custom_section_describing_imports;
use super::super::super::super::_rt;
#[doc(hidden)]
#[allow(non_snake_case)]
pub unsafe fn _export_is_pending_cabi<T: Guest>() -> i32 {
#[cfg(target_arch = "wasm32")] _rt::run_ctors_once();
let result0 = T::is_pending();
match result0 {
true => 1,
false => 0,
}
}
#[doc(hidden)]
#[allow(non_snake_case)]
pub unsafe fn _export_select_cabi<T: Guest>() -> i32 {
#[cfg(target_arch = "wasm32")] _rt::run_ctors_once();
let result0 = T::select();
match result0 {
true => 1,
false => 0,
}
}
pub trait Guest {
/// is ctx pending
fn is_pending() -> bool;
/// select one task to run, if no task is ready, return false
fn select() -> bool;
}
#[doc(hidden)]
#[macro_export]
macro_rules! __export_land_asyncio_context_cabi {
($ty:ident with_types_in $($path_to_types:tt)*) => {
const _ : () = { #[export_name =
"land:asyncio/context#is-pending"] unsafe extern "C" fn
export_is_pending() -> i32 { $($path_to_types)*::
_export_is_pending_cabi::<$ty > () } #[export_name =
"land:asyncio/context#select"] unsafe extern "C" fn
export_select() -> i32 { $($path_to_types)*::
_export_select_cabi::<$ty > () } };
};
}
#[doc(hidden)]
pub use __export_land_asyncio_context_cabi;
}
}
#[allow(dead_code)]
pub mod http {
#[allow(dead_code, clippy::all)]
Expand Down Expand Up @@ -462,13 +513,16 @@ macro_rules! __export_http_handler_impl {
($ty:ident with_types_in $($path_to_types_root:tt)*) => {
$($path_to_types_root)*::
exports::land::http::incoming::__export_land_http_incoming_cabi!($ty
with_types_in $($path_to_types_root)*:: exports::land::http::incoming); const _ :
() = { #[cfg(target_arch = "wasm32")] #[link_section =
with_types_in $($path_to_types_root)*:: exports::land::http::incoming);
$($path_to_types_root)*::
exports::land::asyncio::context::__export_land_asyncio_context_cabi!($ty
with_types_in $($path_to_types_root)*:: exports::land::asyncio::context); const _
: () = { #[cfg(target_arch = "wasm32")] #[link_section =
"component-type:wit-bindgen:0.30.0:http-handler:imports and exports"]
#[doc(hidden)] pub static __WIT_BINDGEN_COMPONENT_TYPE : [u8; 692] = *
#[doc(hidden)] pub static __WIT_BINDGEN_COMPONENT_TYPE : [u8; 751] = *
b"\
\0asm\x0d\0\x01\0\0\x19\x16wit-component-encoding\x04\0\x07\xb1\x04\x01A\x02\x01\
A\x06\x01B\x16\x01{\x04\0\x0bstatus-code\x03\0\0\x01s\x04\0\x06method\x03\0\x02\x01\
\0asm\x0d\0\x01\0\0\x19\x16wit-component-encoding\x04\0\x07\xec\x04\x01A\x02\x01\
A\x08\x01B\x16\x01{\x04\0\x0bstatus-code\x03\0\0\x01s\x04\0\x06method\x03\0\x02\x01\
o\x02ss\x01p\x04\x04\0\x07headers\x03\0\x05\x01s\x04\0\x03uri\x03\0\x07\x01y\x04\
\0\x0bbody-handle\x03\0\x09\x01k\x0a\x01r\x04\x06method\x03\x03uri\x08\x07header\
s\x06\x04body\x0b\x04\0\x07request\x03\0\x0c\x01r\x03\x06status\x01\x07headers\x06\
Expand All @@ -479,10 +533,11 @@ eout\0\0\x0binvalid-url\0\0\x17destination-not-allowed\0\0\x11too-many-requests\
edirect\x13\x04\0\x0frequest-options\x03\0\x14\x03\x01\x0fland:http/types\x05\0\x02\
\x03\0\0\x07request\x02\x03\0\0\x08response\x01B\x06\x02\x03\x02\x01\x01\x04\0\x07\
request\x03\0\0\x02\x03\x02\x01\x02\x04\0\x08response\x03\0\x02\x01@\x01\x03req\x01\
\0\x03\x04\0\x0ehandle-request\x01\x04\x04\x01\x12land:http/incoming\x05\x03\x04\
\x01\x18land:worker/http-handler\x04\0\x0b\x12\x01\0\x0chttp-handler\x03\0\0\0G\x09\
producers\x01\x0cprocessed-by\x02\x0dwit-component\x070.215.0\x10wit-bindgen-rus\
t\x060.30.0";
\0\x03\x04\0\x0ehandle-request\x01\x04\x04\x01\x12land:http/incoming\x05\x03\x01\
B\x03\x01@\0\0\x7f\x04\0\x0ais-pending\x01\0\x04\0\x06select\x01\0\x04\x01\x14la\
nd:asyncio/context\x05\x04\x04\x01\x18land:worker/http-handler\x04\0\x0b\x12\x01\
\0\x0chttp-handler\x03\0\0\0G\x09producers\x01\x0cprocessed-by\x02\x0dwit-compon\
ent\x070.215.0\x10wit-bindgen-rust\x060.30.0";
};
};
}
Expand Down
78 changes: 76 additions & 2 deletions lib/sdk-macro/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ static HTTP_SRC_INCLUDE: AtomicBool = AtomicBool::new(false);
pub fn http_main(_attr: TokenStream, item: TokenStream) -> TokenStream {
let func = syn::parse_macro_input!(item as syn::ItemFn);
let func_name = func.sig.ident.clone();
let func_args_len = func.sig.inputs.len();

let src_http_handler = if HTTP_SRC_INCLUDE.load(std::sync::atomic::Ordering::Relaxed) {
String::new()
Expand All @@ -52,6 +53,7 @@ pub fn http_main(_attr: TokenStream, item: TokenStream) -> TokenStream {
let iface_impl = quote!(

use exports::land::http::incoming;
use exports::land::asyncio::context;

struct WorkerHttpImpl;

Expand Down Expand Up @@ -92,6 +94,39 @@ pub fn http_main(_attr: TokenStream, item: TokenStream) -> TokenStream {
}
}

);

// if func args len is 1, it means that the function has one argument, no ExecutionCtx
// so context::Guest should not be used
let mut async_impl = quote!(
impl context::Guest for WorkerHttpImpl {
fn is_pending() -> bool{
return false
}

fn select() -> bool {
return false
}
}
);
if func_args_len == 2 {
async_impl = quote!(
impl context::Guest for WorkerHttpImpl {
fn is_pending() -> bool{
let ctx = ExecutionCtx::get();
ctx.is_pending()
}

fn select() -> bool {
let mut ctx = ExecutionCtx::get();
ctx.execute();
ctx.is_pending()
}
}
);
}

let mut iface_impl2 = quote!(
impl incoming::Guest for WorkerHttpImpl {
fn handle_request(req: incoming::Request) -> incoming::Response {
#func
Expand Down Expand Up @@ -120,11 +155,50 @@ pub fn http_main(_attr: TokenStream, item: TokenStream) -> TokenStream {
}
}
}
);

export!(WorkerHttpImpl);
// if func args len is 2, it means that the function has two arguments,
// the first one is the request, the second one is the context
if func_args_len == 2 {
iface_impl2 = quote!(
impl incoming::Guest for WorkerHttpImpl {
fn handle_request(req: incoming::Request) -> incoming::Response {
#func

// get execution context
let mut ctx = ExecutionCtx::get();
// convert wasm_request to sdk_request
let sdk_request: Request = req.try_into().unwrap();
let sdk_response = match #func_name(sdk_request, ctx){
Ok(r) => r,
Err(e) => {
land_sdk::http::error_response(
http::StatusCode::INTERNAL_SERVER_ERROR,
e.to_string(),
)
}
};

let sdk_response_body_handle = sdk_response.body().body_handle();
// convert sdk_response to wasm_response
match sdk_response.try_into() {
Ok(r) => r,
Err(_e) => incoming::Response {
status: 500,
headers: vec![],
body: Some(sdk_response_body_handle),
},
}
}
}
);
}

let iface_impl3 = quote!(
export!(WorkerHttpImpl);
);
let user_code_comment = "// User code start";
let value = format!("{iface}\n\n{user_code_comment}\n\n{iface_impl}");
let value =
format!("{iface}\n\n{user_code_comment}\n\n{iface_impl}\n\n{async_impl}\n\n{iface_impl2}\n\n{iface_impl3}");
value.parse().unwrap()
}
Loading

0 comments on commit 9d21d60

Please sign in to comment.