WASI example (#228)
* feat: wasi-example Signed-off-by: Anton Whalley <anton@venshare.com> * fix: remove line end Signed-off-by: Anton Whalley <anton@venshare.com> --------- Signed-off-by: Anton Whalley <anton@venshare.com>
This commit is contained in:
parent
13c36fdbfe
commit
2f57c3ce36
|
@ -115,6 +115,14 @@ jobs:
|
|||
env:
|
||||
CARGO_TARGET_WASM32_WASI_RUNNER: wasmedge
|
||||
# Build examples
|
||||
- uses: actions-rs/cargo@v1
|
||||
name: "Build wasi-example"
|
||||
if: matrix.target == 'wasm32-wasi' && matrix.toolchain == 'stable'
|
||||
with:
|
||||
command: build
|
||||
toolchain: ${{ matrix.toolchain }}
|
||||
args: --target ${{ matrix.target }} --manifest-path ./example-projects/wasi-example/Cargo.toml
|
||||
|
||||
- uses: actions-rs/cargo@v1
|
||||
name: "Build reqwest-wasm-example"
|
||||
if: matrix.target == 'wasm32-unknown-unknown' && matrix.toolchain == 'stable'
|
||||
|
@ -170,3 +178,4 @@ jobs:
|
|||
command: build
|
||||
toolchain: ${{ matrix.toolchain }}
|
||||
args: --target ${{ matrix.target }} --manifest-path ./example-projects/nats-example/Cargo.toml
|
||||
|
||||
|
|
|
@ -0,0 +1,17 @@
|
|||
[package]
|
||||
name = "wasi-example"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
anyhow = "1.0"
|
||||
cloudevents-sdk = { path = "../..", features = ["http-binding", "hyper_wasi", "hyper" ] }
|
||||
hyper_wasi = { version = "0.15", features = ["full"] }
|
||||
log = "0.4.21"
|
||||
tokio_wasi = { version = "1", features = ["io-util", "fs", "net", "time", "rt", "macros"] }
|
||||
serde_json = " 1.0.116"
|
||||
|
||||
[dev-dependencies]
|
||||
bytes = "1.6.0"
|
||||
http-body-util = "0.1.1"
|
||||
chrono = "*"
|
|
@ -0,0 +1,26 @@
|
|||
Install WASMEdge:
|
||||
|
||||
https://wasmedge.org/docs/start/install/
|
||||
|
||||
To run the server:
|
||||
```console
|
||||
cargo run --target wasm32-wasi
|
||||
```
|
||||
|
||||
To test a GET:
|
||||
|
||||
```console
|
||||
curl -sw '%{http_code}\n' http://localhost:9000/health/readiness
|
||||
```
|
||||
|
||||
To test a POST:
|
||||
|
||||
```console
|
||||
curl -d '{"name": "wasi-womble"}' \
|
||||
-H'content-type: application/json' \
|
||||
-H'ce-specversion: 1.0' \
|
||||
-H'ce-id: 1' \
|
||||
-H'ce-source: http://cloudevents.io' \
|
||||
-H'ce-type: dev.knative.example' \
|
||||
http://localhost:9000
|
||||
```
|
|
@ -0,0 +1,39 @@
|
|||
use cloudevents::{event::Data, Event, EventBuilder, EventBuilderV10};
|
||||
use log::info;
|
||||
use serde_json::{from_slice, from_str, json};
|
||||
|
||||
pub async fn handle_event(event: Event) -> Result<Event, anyhow::Error> {
|
||||
info!("event: {}", event);
|
||||
|
||||
let input = match event.data() {
|
||||
Some(Data::Binary(v)) => from_slice(v)?,
|
||||
Some(Data::String(v)) => from_str(v)?,
|
||||
Some(Data::Json(v)) => v.to_owned(),
|
||||
None => json!({ "name": "default" }),
|
||||
};
|
||||
|
||||
EventBuilderV10::from(event)
|
||||
.source("func://handler")
|
||||
.ty("func.example")
|
||||
.data("application/json", json!({ "hello": input["name"] }))
|
||||
.build()
|
||||
.map_err(|err| err.into())
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
#[tokio::test]
|
||||
async fn post_test() -> Result<(), anyhow::Error> {
|
||||
let reqevt = Event::default();
|
||||
let respevt = handle_event(reqevt).await?;
|
||||
let output = match respevt.data() {
|
||||
Some(Data::Binary(v)) => from_slice(v)?,
|
||||
Some(Data::String(v)) => from_str(v)?,
|
||||
Some(Data::Json(v)) => v.to_owned(),
|
||||
None => json!({ "name": "default" }),
|
||||
};
|
||||
assert_eq!(output, json!({ "hello": "default" }));
|
||||
Ok(())
|
||||
}
|
||||
}
|
|
@ -0,0 +1,45 @@
|
|||
use cloudevents::binding::http::builder::adapter::to_response;
|
||||
use cloudevents::binding::http::to_event;
|
||||
|
||||
use hyper::service::{make_service_fn, service_fn};
|
||||
use hyper::Server;
|
||||
use hyper::{Body, Method, Request, Response, StatusCode};
|
||||
use std::convert::Infallible;
|
||||
use std::net::SocketAddr;
|
||||
use std::result::Result;
|
||||
|
||||
mod handler;
|
||||
|
||||
#[allow(clippy::redundant_closure)]
|
||||
#[tokio::main(flavor = "current_thread")]
|
||||
async fn main() -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
|
||||
let addr = SocketAddr::from(([0, 0, 0, 0], 9000));
|
||||
let make_svc = make_service_fn(|_| async move {
|
||||
Ok::<_, Infallible>(service_fn(move |req| handle_request(req)))
|
||||
});
|
||||
let server = Server::bind(&addr).serve(make_svc);
|
||||
if let Err(e) = server.await {
|
||||
eprintln!("server error: {}", e);
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
async fn handle_request(req: Request<Body>) -> Result<Response<Body>, anyhow::Error> {
|
||||
match (req.method(), req.uri().path()) {
|
||||
(&Method::POST, "/") => {
|
||||
let headers = req.headers().clone();
|
||||
let body_bytes = hyper::body::to_bytes(req.into_body()).await?;
|
||||
let body = body_bytes.to_vec();
|
||||
let reqevt = to_event(&headers, body)?;
|
||||
let _respevt = handler::handle_event(reqevt).await?;
|
||||
|
||||
to_response(_respevt).map_err(|err| err.into())
|
||||
}
|
||||
(&Method::GET, "/health/readiness") => Ok(Response::new(Body::from(""))),
|
||||
(&Method::GET, "/health/liveness") => Ok(Response::new(Body::from(""))),
|
||||
_ => {
|
||||
let mut not_found = Response::default();
|
||||
*not_found.status_mut() = StatusCode::NOT_FOUND;
|
||||
Ok(not_found)
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue