Reqwest wasm example (#43)
* Fixed cloudevents sdk to compile with wasm Signed-off-by: Francesco Guardiani <francescoguard@gmail.com> * Fixed warning Signed-off-by: Francesco Guardiani <francescoguard@gmail.com> * cargo fmt Signed-off-by: Francesco Guardiani <francescoguard@gmail.com> * Fixed Signed-off-by: Francesco Guardiani <francescoguard@gmail.com> * Added cors to actix-web example Signed-off-by: Francesco Guardiani <francescoguard@gmail.com> * Added reqwest wasm example Signed-off-by: Francesco Guardiani <francescoguard@gmail.com>
This commit is contained in:
parent
2586322a68
commit
594e0a5467
|
@ -17,6 +17,7 @@ jobs:
|
|||
target:
|
||||
- x86_64-unknown-linux-gnu
|
||||
- x86_64-unknown-linux-musl
|
||||
- wasm32-unknown-unknown
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- run: sudo apt-get update
|
||||
|
@ -44,12 +45,22 @@ jobs:
|
|||
target: ${{ matrix.target }}
|
||||
override: true
|
||||
- uses: actions-rs/cargo@v1
|
||||
if: matrix.target != 'wasm32-unknown-unknown'
|
||||
with:
|
||||
command: build
|
||||
toolchain: ${{ matrix.toolchain }}
|
||||
args: --target ${{ matrix.target }} --all
|
||||
- uses: actions-rs/cargo@v1
|
||||
if: matrix.target != 'wasm32-unknown-unknown'
|
||||
with:
|
||||
command: test
|
||||
toolchain: ${{ matrix.toolchain }}
|
||||
args: --target ${{ matrix.target }} --all
|
||||
|
||||
# If wasm, then we don't need to compile --all
|
||||
- uses: actions-rs/cargo@v1
|
||||
if: matrix.target == 'wasm32-unknown-unknown'
|
||||
with:
|
||||
command: build
|
||||
toolchain: ${{ matrix.toolchain }}
|
||||
args: --target wasm32-unknown-unknown
|
||||
|
|
13
Cargo.toml
13
Cargo.toml
|
@ -16,13 +16,19 @@ serde_json = "^1.0"
|
|||
serde-value = "^0.6"
|
||||
chrono = { version = "^0.4", features = ["serde"] }
|
||||
delegate = "^0.4"
|
||||
uuid = { version = "^0.8", features = ["serde", "v4"] }
|
||||
hostname = "^0.1"
|
||||
base64 = "^0.12"
|
||||
url = { version = "^2.1", features = ["serde"] }
|
||||
snafu = "^0.6"
|
||||
lazy_static = "1.4.0"
|
||||
|
||||
[target."cfg(not(target_arch = \"wasm32\"))".dependencies]
|
||||
hostname = "^0.3"
|
||||
uuid = { version = "^0.8", features = ["v4"] }
|
||||
|
||||
[target.'cfg(target_arch = "wasm32")'.dependencies]
|
||||
web-sys = { version = "^0.3", features = ["Window", "Location"] }
|
||||
uuid = { version = "^0.8", features = ["v4", "wasm-bindgen"] }
|
||||
|
||||
[dev-dependencies]
|
||||
rstest = "0.6"
|
||||
claim = "0.3.1"
|
||||
|
@ -37,5 +43,6 @@ members = [
|
|||
"cloudevents-sdk-reqwest"
|
||||
]
|
||||
exclude = [
|
||||
"example-projects/actix-web-example"
|
||||
"example-projects/actix-web-example",
|
||||
"example-projects/reqwest-wasm-example"
|
||||
]
|
|
@ -14,4 +14,6 @@ lazy_static = "1.4.0"
|
|||
bytes = "^0.5"
|
||||
futures = "^0.3"
|
||||
serde_json = "^1.0"
|
||||
|
||||
[dev-dependencies]
|
||||
url = { version = "^2.1", features = ["serde"] }
|
|
@ -11,7 +11,6 @@ cloudevents-sdk = { path = ".." }
|
|||
lazy_static = "1.4.0"
|
||||
bytes = "^0.5"
|
||||
serde_json = "^1.0"
|
||||
url = { version = "^2.1", features = ["serde"] }
|
||||
|
||||
[dependencies.reqwest]
|
||||
version = "0.10.4"
|
||||
|
@ -20,4 +19,5 @@ features = ["rustls-tls"]
|
|||
|
||||
[dev-dependencies]
|
||||
mockito = "0.25.1"
|
||||
tokio = { version = "^0.2", features = ["full"] }
|
||||
tokio = { version = "^0.2", features = ["full"] }
|
||||
url = { version = "^2.1" }
|
|
@ -9,6 +9,7 @@ cloudevents-sdk = { path = "../.." }
|
|||
cloudevents-sdk-actix-web = { path = "../../cloudevents-sdk-actix-web" }
|
||||
actix-web = "2"
|
||||
actix-rt = "1"
|
||||
actix-cors = "^0.2.0"
|
||||
lazy_static = "1.4.0"
|
||||
bytes = "^0.5"
|
||||
futures = "^0.3"
|
||||
|
|
|
@ -35,10 +35,11 @@ async fn main() -> std::io::Result<()> {
|
|||
HttpServer::new(|| {
|
||||
App::new()
|
||||
.wrap(actix_web::middleware::Logger::default())
|
||||
.wrap(actix_cors::Cors::new().finish())
|
||||
.service(post_event)
|
||||
.service(get_event)
|
||||
})
|
||||
.bind("127.0.0.1:8080")?
|
||||
.bind("127.0.0.1:9000")?
|
||||
.workers(1)
|
||||
.run()
|
||||
.await
|
||||
|
|
|
@ -0,0 +1,4 @@
|
|||
**/node_modules
|
||||
pkg
|
||||
*.swp
|
||||
**/dist
|
|
@ -0,0 +1,21 @@
|
|||
[package]
|
||||
name = "reqwest-wasm-example"
|
||||
version = "0.1.0"
|
||||
authors = ["Francesco Guardiani <francescoguard@gmail.com>"]
|
||||
edition = "2018"
|
||||
|
||||
# Config mostly pulled from: https://github.com/rustwasm/wasm-bindgen/blob/master/examples/fetch/Cargo.toml
|
||||
|
||||
[lib]
|
||||
crate-type = ["cdylib"]
|
||||
|
||||
[dependencies]
|
||||
reqwest = "0.10.4"
|
||||
cloudevents-sdk = { path = "../.." }
|
||||
cloudevents-sdk-reqwest = { path = "../../cloudevents-sdk-reqwest" }
|
||||
url = { version = "^2.1" }
|
||||
web-sys = { version = "0.3.39", features = ["Window", "Location"] }
|
||||
wasm-bindgen-futures = "0.4.12"
|
||||
wasm-bindgen = { version = "0.2.62", features = ["serde-serialize"] }
|
||||
|
||||
[workspace]
|
|
@ -0,0 +1,13 @@
|
|||
## Example usage of CLoudEvents sdk/Reqwest from WASM
|
||||
|
||||
Install the dependencies with:
|
||||
|
||||
npm install
|
||||
|
||||
Then build the example locally with:
|
||||
|
||||
npm run serve
|
||||
|
||||
and then visiting http://localhost:8080 in a browser should run the example!
|
||||
|
||||
This example is loosely based off of [this example](https://github.com/rustwasm/wasm-bindgen/blob/master/examples/fetch/src/lib.rs), an example usage of `fetch` from `wasm-bindgen`, and from [reqwest repo](https://github.com/seanmonstar/reqwest/tree/master/examples/wasm_header).
|
|
@ -0,0 +1,57 @@
|
|||
<html>
|
||||
<head>
|
||||
<meta content="text/html;charset=utf-8" http-equiv="Content-Type"/>
|
||||
</head>
|
||||
<body>
|
||||
<form class="form-horizontal">
|
||||
<fieldset>
|
||||
|
||||
<!-- Form Name -->
|
||||
<legend>CloudEvents sender</legend>
|
||||
|
||||
<!-- Text input-->
|
||||
<div class="form-group">
|
||||
<label class="col-md-4 control-label" for="event_target">Target</label>
|
||||
<div class="col-md-4">
|
||||
<input id="event_target" name="event_target" type="text" placeholder="http://localhost:9000" class="form-control input-md" required="">
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Text input-->
|
||||
<div class="form-group">
|
||||
<label class="col-md-4 control-label" for="event_type">Event Type</label>
|
||||
<div class="col-md-4">
|
||||
<input id="event_type" name="event_type" type="text" placeholder="example" class="form-control input-md" required="">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Text input-->
|
||||
<div class="form-group">
|
||||
<label class="col-md-4 control-label" for="event_datacontenttype">Event Data Content Type</label>
|
||||
<div class="col-md-4">
|
||||
<input id="event_datacontenttype" name="event_datacontenttype" type="text" placeholder="application/json" class="form-control input-md" required="">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Textarea -->
|
||||
<div class="form-group">
|
||||
<label class="col-md-4 control-label" for="event_data">Event Data</label>
|
||||
<div class="col-md-4">
|
||||
<textarea class="form-control" id="event_data" name="event_data">{"hello":"world"}</textarea>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Button -->
|
||||
<div class="form-group">
|
||||
<label class="col-md-4 control-label" for="send">Send Event</label>
|
||||
<div class="col-md-4">
|
||||
<button id="send" name="send" class="btn btn-primary" type="button">Send</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</fieldset>
|
||||
</form>
|
||||
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,17 @@
|
|||
import $ from 'jquery';
|
||||
|
||||
import 'bootstrap/dist/css/bootstrap.min.css';
|
||||
import 'bootstrap';
|
||||
|
||||
import("./pkg").then(rustModule => {
|
||||
$(document).ready(function () {
|
||||
$("#send").click(function () {
|
||||
let target = $("#event_target").val()
|
||||
let ty = $("#event_type").val()
|
||||
let dataContentType = $("#event_datacontenttype").val()
|
||||
let data = $("#event_data").val()
|
||||
|
||||
rustModule.run(target, ty, dataContentType, data).catch(console.error);
|
||||
});
|
||||
})
|
||||
}).catch(console.error);
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,21 @@
|
|||
{
|
||||
"scripts": {
|
||||
"build": "webpack",
|
||||
"serve": "webpack-dev-server"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@wasm-tool/wasm-pack-plugin": "^1.3.1",
|
||||
"css-loader": "^3.5.3",
|
||||
"html-webpack-plugin": "^3.2.0",
|
||||
"style-loader": "^1.2.1",
|
||||
"text-encoding": "^0.7.0",
|
||||
"webpack": "^4.29.4",
|
||||
"webpack-cli": "^3.1.1",
|
||||
"webpack-dev-server": "^3.1.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"bootstrap": "^4.5.0",
|
||||
"jquery": "^3.5.1",
|
||||
"popper.js": "^1.16.1"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
use wasm_bindgen::prelude::*;
|
||||
|
||||
#[wasm_bindgen]
|
||||
pub async fn run(target: String, ty: String, datacontenttype: String, data: String) -> Result<(), String> {
|
||||
let event = cloudevents::EventBuilder::new()
|
||||
.ty(ty)
|
||||
.data(datacontenttype, data)
|
||||
.build();
|
||||
|
||||
println!("Going to send event: {:?}", event);
|
||||
|
||||
cloudevents_sdk_reqwest::event_to_request(event, reqwest::Client::new().post(&target))
|
||||
.map_err(|e| e.to_string())?
|
||||
.header("Access-Control-Allow-Origin", "*")
|
||||
.send()
|
||||
.await
|
||||
.map_err(|e| e.to_string())?;
|
||||
|
||||
Ok(())
|
||||
}
|
|
@ -0,0 +1,39 @@
|
|||
const path = require('path');
|
||||
const HtmlWebpackPlugin = require('html-webpack-plugin');
|
||||
const webpack = require('webpack');
|
||||
const WasmPackPlugin = require("@wasm-tool/wasm-pack-plugin");
|
||||
|
||||
module.exports = {
|
||||
entry: './index.js',
|
||||
output: {
|
||||
path: path.resolve(__dirname, 'dist'),
|
||||
filename: 'index.js',
|
||||
},
|
||||
module: {
|
||||
rules: [
|
||||
{
|
||||
test: /\.css$/,
|
||||
use: ['style-loader', 'css-loader']
|
||||
}
|
||||
]
|
||||
},
|
||||
plugins: [
|
||||
new HtmlWebpackPlugin({
|
||||
template: 'index.html'
|
||||
}),
|
||||
new WasmPackPlugin({
|
||||
crateDirectory: path.resolve(__dirname, ".")
|
||||
}),
|
||||
// Have this example work in Edge which doesn't ship `TextEncoder` or
|
||||
// `TextDecoder` at this time.
|
||||
new webpack.ProvidePlugin({
|
||||
TextDecoder: ['text-encoding', 'TextDecoder'],
|
||||
TextEncoder: ['text-encoding', 'TextEncoder']
|
||||
}),
|
||||
new webpack.ProvidePlugin({
|
||||
$: "jquery",
|
||||
jQuery: "jquery"
|
||||
})
|
||||
],
|
||||
mode: 'development'
|
||||
};
|
|
@ -193,3 +193,33 @@ impl Attributes {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
pub(crate) fn default_hostname() -> Url {
|
||||
Url::parse(
|
||||
format!(
|
||||
"http://{}",
|
||||
hostname::get()
|
||||
.ok()
|
||||
.map(|s| s.into_string().ok())
|
||||
.flatten()
|
||||
.unwrap_or(String::from("localhost".to_string()))
|
||||
)
|
||||
.as_ref(),
|
||||
)
|
||||
.unwrap()
|
||||
}
|
||||
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
pub(crate) fn default_hostname() -> Url {
|
||||
use std::str::FromStr;
|
||||
|
||||
Url::from_str(
|
||||
web_sys::window()
|
||||
.map(|w| w.location().host().ok())
|
||||
.flatten()
|
||||
.unwrap_or(String::from("http://localhost"))
|
||||
.as_str(),
|
||||
)
|
||||
.unwrap()
|
||||
}
|
||||
|
|
|
@ -1,8 +1,9 @@
|
|||
use crate::event::attributes::{AttributeValue, AttributesConverter, DataAttributesWriter};
|
||||
use crate::event::attributes::{
|
||||
default_hostname, AttributeValue, AttributesConverter, DataAttributesWriter,
|
||||
};
|
||||
use crate::event::AttributesV10;
|
||||
use crate::event::{AttributesReader, AttributesWriter, SpecVersion};
|
||||
use chrono::{DateTime, Utc};
|
||||
use hostname::get_hostname;
|
||||
use url::Url;
|
||||
use uuid::Uuid;
|
||||
|
||||
|
@ -153,14 +154,7 @@ impl Default for Attributes {
|
|||
Attributes {
|
||||
id: Uuid::new_v4().to_string(),
|
||||
ty: "type".to_string(),
|
||||
source: Url::parse(
|
||||
format!(
|
||||
"http://{}",
|
||||
get_hostname().unwrap_or("localhost".to_string())
|
||||
)
|
||||
.as_ref(),
|
||||
)
|
||||
.unwrap(),
|
||||
source: default_hostname(),
|
||||
datacontenttype: None,
|
||||
schemaurl: None,
|
||||
subject: None,
|
||||
|
@ -193,7 +187,7 @@ mod tests {
|
|||
use chrono::NaiveDateTime;
|
||||
|
||||
#[test]
|
||||
fn iterator_test_V03() {
|
||||
fn iterator_test_v03() {
|
||||
let a = Attributes {
|
||||
id: String::from("1"),
|
||||
ty: String::from("someType"),
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
use crate::event::attributes::{AttributeValue, AttributesConverter, DataAttributesWriter};
|
||||
use crate::event::attributes::{
|
||||
default_hostname, AttributeValue, AttributesConverter, DataAttributesWriter,
|
||||
};
|
||||
use crate::event::{AttributesReader, AttributesV03, AttributesWriter, SpecVersion};
|
||||
use chrono::{DateTime, Utc};
|
||||
use hostname::get_hostname;
|
||||
use url::Url;
|
||||
use uuid::Uuid;
|
||||
|
||||
|
@ -152,14 +153,7 @@ impl Default for Attributes {
|
|||
Attributes {
|
||||
id: Uuid::new_v4().to_string(),
|
||||
ty: "type".to_string(),
|
||||
source: Url::parse(
|
||||
format!(
|
||||
"http://{}",
|
||||
get_hostname().unwrap_or("localhost".to_string())
|
||||
)
|
||||
.as_ref(),
|
||||
)
|
||||
.unwrap(),
|
||||
source: default_hostname(),
|
||||
datacontenttype: None,
|
||||
dataschema: None,
|
||||
subject: None,
|
||||
|
@ -192,7 +186,7 @@ mod tests {
|
|||
use chrono::NaiveDateTime;
|
||||
|
||||
#[test]
|
||||
fn iterator_test_V10() {
|
||||
fn iterator_test_v10() {
|
||||
let a = Attributes {
|
||||
id: String::from("1"),
|
||||
ty: String::from("someType"),
|
||||
|
|
Loading…
Reference in New Issue