diff --git a/__wasm/wit-bindgen-sample/container/src/main.rs b/__wasm/wit-bindgen-sample/container/src/main.rs index 05f88ca..4d9b4ff 100644 --- a/__wasm/wit-bindgen-sample/container/src/main.rs +++ b/__wasm/wit-bindgen-sample/container/src/main.rs @@ -1,155 +1,20 @@ extern crate core; -use std::collections::BTreeMap; -use std::io::{ErrorKind, Read, Write}; -use std::time::Duration; - use anyhow::Result; -use reqwest::Method; -use serde::{Deserialize, Serialize}; -use serde_json::{Map, Number, Value}; +use serde_json::Value; use wasmtime::{Config, Engine, Instance, Linker, Module, Store}; +mod fn_common; +mod fn_fetch; + wit_bindgen_wasmtime::export!("../container.wit"); -#[derive(Clone, Debug, Serialize, Deserialize)] -struct FetchResult { - error: Option, - result: Option, -} - -impl FetchResult { - fn fail(message: impl Into) -> Self { - FetchResult { - result: None, - error: Some(message.into()), - } - } - - fn success(result: String) -> Self { - FetchResult { - result: Some(result), - error: None, - } - } - - fn to_json(&self) -> String { - serde_json::to_string(&self).expect("JSResult to json error") - } -} - -impl Into for FetchResult { - fn into(self) -> String { - self.to_json() - } -} - -#[derive(Clone, Debug, Serialize, Deserialize)] -struct FetchParams { - url: String, - options: Option, -} - -#[derive(Clone, Debug, Serialize, Deserialize)] -struct FetchOptions { - method: Option, - headers: Option>, - body: Option, -} - #[derive(Default)] pub struct MyContainer; impl container::Container for MyContainer { fn fetch(&mut self, params: &str) -> String { - let fetch_params: FetchParams = match serde_json::from_str(params) { - Err(e) => return FetchResult::fail(format!("Fetch param parse error: {}, raw params: {}", e, params)).to_json(), - Ok(params) => params, - }; - if fetch_params.url.is_empty() { - return FetchResult::fail("Param url cannot be empty").to_json(); - } - let client = match reqwest::blocking::Client::builder() - .timeout(Duration::from_secs(8)) - .connect_timeout(Duration::from_secs(3)) - // .proxy(reqwest::Proxy::all("http://127.0.0.1:1086").expect("to proxy failed")) - .build() { - Err(e) => return FetchResult::fail(format!("Create client failed: {}", e)).to_json(), - Ok(client) => client, - }; - let method = fetch_params.options.as_ref().map(|options| options.method.as_ref().map(|m| m.to_uppercase())).flatten(); - let method_str = method.as_ref().map(|m| m.as_str()).unwrap_or_else(|| "GET"); - let request_method = match method_str { - "GET" => Method::GET, - "POST" => Method::POST, - m => return FetchResult::fail(format!("Unsupported method: {}", m)).to_json(), - }; - let mut request_builder = client.request(request_method.clone(), &fetch_params.url); - if let Some(options) = &fetch_params.options { - let mut has_user_agent = false; - if let Some(headers) = &options.headers { - for (k, v) in headers { - if k.to_lowercase() == "user-agent" { - has_user_agent = true; - } - request_builder = request_builder.header(k.to_string(), v.to_string()); - } - } - if !has_user_agent { - request_builder = request_builder.header("User-Agent", "JavaScriptSandboxContainer/0.1"); - } - - if let Some(body) = &options.body { - if Method::POST == request_method { - let body = reqwest::blocking::Body::from(body.to_string()); - request_builder = request_builder.body(body); - } - } - } - - let mut fetch_response = match request_builder.send() { - Err(e) => return FetchResult::fail(format!("Send request failed: {}", e)).to_json(), - Ok(fetch_response) => fetch_response, - }; - - let status = fetch_response.status().as_u16(); - let headers = fetch_response.headers().clone(); - - let mut body_buff = Vec::new(); - let mut buff = [0_u8; 1024]; - loop { - match fetch_response.read(&mut buff) { - Err(e) if e.kind() == ErrorKind::Interrupted => continue, - Err(e) => return FetchResult::fail(format!("Fetch response failed: {}", e)).to_json(), - Ok(len) => if len == 0 { - break; - } else { - if let Err(e) = body_buff.write_all(&buff[0..len]) { - return FetchResult::fail(format!("Fetch response failed: {}", e)).to_json(); - } - if body_buff.len() > 1024 * 1024 { - return FetchResult::fail(format!("Fetch response too large, {} more than 1MB", body_buff.len())).to_json(); - } - } - } - } - - let mut result_map = Map::new(); - result_map.insert("status".to_string(), Value::Number(Number::from(status))); - let mut header_map = Map::new(); - for (k, v) in headers { - let header_key = k.map(|n| n.as_str().to_string()).unwrap_or_else(|| "".to_string()); - let header_value = match v.to_str() { - Err(_) => continue, - Ok(v) => v.to_string(), - }; - header_map.insert(header_key, Value::String(header_value)); - } - result_map.insert("headers".to_string(), Value::Object(header_map)); - result_map.insert("body".to_string(), Value::String(String::from_utf8_lossy(&body_buff).to_string())); - - - FetchResult::success(format!("{}", Value::Object(result_map))).to_json() + fn_fetch::do_fetch(params).to_json() } } @@ -165,15 +30,15 @@ fn main() -> Result<()> { )?; let a = exports.eval_javascript(&mut store, r##" function hi(name) { return "hi: " + name; } - // let a = []; - // a.push(fetch('https://hatter.ink/util/print_request.action')); - // for (let i = 0; i < 3; i++) { a.push(i); } - // a.push({ - // id: 1, name: 'hatter' - // }); - // a.push(hi('001')); - // a.push(hi('002')); - let a = fetch('https://hatter.ink/util/print_request.action'); + let a = []; + a.push(fetch('https://hatter.ink/util/print_request.action')); + for (let i = 0; i < 3; i++) { a.push(i); } + a.push({ + id: 1, name: 'hatter' + }); + a.push(hi('001')); + a.push(hi('002')); + // let a = fetch('https://hatter.ink/util/print_request.action'); JSON.stringify(a) // a "##);