Skip to content
This repository has been archived by the owner on Feb 22, 2024. It is now read-only.

Commit

Permalink
Merge pull request #43 from jedisct1/newapi
Browse files Browse the repository at this point in the history
Change the API to allow streaming & no callback to alloc
  • Loading branch information
Radu M authored Mar 30, 2021
2 parents b19cabf + 67b5f2c commit 0cf7496
Show file tree
Hide file tree
Showing 16 changed files with 796 additions and 636 deletions.
10 changes: 5 additions & 5 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,11 @@ anyhow = "1.0"
futures = "0.3"
http = "0.2"
reqwest = { version = "0.11", default-features = true, features = ["json", "blocking"] }
tokio = { version = "1.1", features = ["full"] }
wasmtime = "0.24"
wasmtime-wasi = "0.24"
wasi-common = "0.24"
wasi-cap-std-sync = "0.24"
tokio = { version = "1.4.0", features = ["full"] }
wasmtime = "0.25.0"
wasmtime-wasi = "0.25.0"
wasi-common = "0.25.0"
wasi-cap-std-sync = "0.25.0"
wasi-experimental-http = { path = "crates/wasi-experimental-http" }
wasi-experimental-http-wasmtime = { path = "crates/wasi-experimental-http-wasmtime" }

Expand Down
171 changes: 90 additions & 81 deletions crates/as/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,20 +14,57 @@ export function request(req: Request): Response {
export class Response {
/** The HTTP response status code. */
public status: StatusCode;
/** The HTTP response headers. */
public headers: Map<string, string>;
/** The response body as a byte array.
*
* It should be decoded by the consumer accordingly.
* If expecting a UTF string, use the built-in functions
* to decode.
*/
public body: ArrayBuffer;

constructor(status: u16, headers: Map<string, string>, body: ArrayBuffer) {
/** The response handle */
public handle: u32;

constructor(status: u16, handle: u32) {
this.status = status;
this.headers = headers;
this.body = body;
this.handle = handle;
}

public bodyRead(buffer: ArrayBuffer): usize {
let buf_read_ptr = memory.data(8);
if (body_read(this.handle, changetype<usize>(buffer), buffer.byteLength, buf_read_ptr) != 0) {
return 0;
}
return load<isize>(buf_read_ptr);
}

public bodyReadAll(): Uint8Array {
let chunk = new Uint8Array(4096);
let buf = new Array<u8>();
while (true) {
let count = this.bodyRead(chunk.buffer);
if (count <= 0) {
return changetype<Uint8Array>(buf);
}
for (let i: u32 = 0; i < (count as u32); i++) {
buf.push(chunk[i]);
}
}
}

public headerGet(name: string): string {
let name_buf = String.UTF8.encode(name);
let name_ptr = changetype<usize>(name_buf);
let name_len = name_buf.byteLength;

let value_buf = new Uint8Array(4096);
let value_buf_ptr = changetype<usize>(value_buf.buffer);
let value_buf_len = value_buf.byteLength;
let value_len_ptr = memory.data(8);

if (header_get(this.handle, name_ptr, name_len, value_buf_ptr, value_buf_len, value_len_ptr) != 0) {
return "";
}
let value = value_buf.subarray(0, load<u32>(value_len_ptr));
return String.UTF8.decode(value.buffer);
}

public close(): void {
close(this.handle);

}
}

Expand Down Expand Up @@ -69,7 +106,7 @@ export class Request {
.send();
Console.log(res.status.toString())
Console.log(res.headers);
let result = String.UTF8.decode(res.body);
let result = String.UTF8.decode(res.bodyReadAll().buffer);
Console.log(result);
* ```
*/
Expand Down Expand Up @@ -111,17 +148,38 @@ export class RequestBuilder {
url_len_ptr: usize,
method_ptr: usize,
method_len_ptr: usize,
req_headers_ptr: usize,
req_headers_len_ptr: usize,
req_body_ptr: usize,
req_body_len_ptr: usize,
heders_ptr: usize,
headers_len_ptr: usize,
body_res_ptr: usize,
body_written_ptr: usize,
headers_written_ptr: usize,
headers_res_ptr: usize,
status_code_ptr: usize,
err_ptr: usize,
err_written_ptr: usize
res_handle_ptr: usize,
): u32;

// @ts-ignore: decorator
@external("wasi_experimental_http", "close")
@unsafe declare function close(
handle: usize
): u32;

// @ts-ignore: decorator
@external("wasi_experimental_http", "header_get")
@unsafe declare function header_get(
handle: usize,
name_ptr: usize,
name_len: usize,
value_ptr: usize,
value_len: usize,
value_written_ptr: usize,
): u32;

// @ts-ignore: decorator
@external("wasi_experimental_http", "body_read")
@unsafe declare function body_read(
handle: usize,
buf_ptr: usize,
buf_len: usize,
but_read_ptr: usize
): u32;

function raw_request(
Expand All @@ -130,7 +188,6 @@ function raw_request(
headers: string,
body: ArrayBuffer
): Response {

let url_buf = String.UTF8.encode(url);
let url_ptr = changetype<usize>(url_buf);
let url_len = url_buf.byteLength;
Expand All @@ -139,69 +196,42 @@ function raw_request(
let method_ptr = changetype<usize>(method_buf);
let method_len = method_buf.byteLength;

let headers_buf = String.UTF8.encode(headers);
let headers_ptr = changetype<usize>(headers_buf);
let headers_len = headers_buf.byteLength;
let req_headers_buf = String.UTF8.encode(headers);
let req_headers_ptr = changetype<usize>(req_headers_buf);
let req_headers_len = req_headers_buf.byteLength;

let req_body_ptr = changetype<usize>(body);
let req_body_len = body.byteLength;

let body_res_ptr = memory.data(8);
let body_written_ptr = memory.data(8);
let headers_res_ptr = memory.data(8);
let headers_written_ptr = memory.data(8);
let status_code_ptr = memory.data(8);
let err_ptr = memory.data(8);
let err_written_ptr = memory.data(8);
let res_handle_ptr = memory.data(8);

let err = req(
url_ptr,
url_len,
method_ptr,
method_len,
req_headers_ptr,
req_headers_len,
req_body_ptr,
req_body_len,
headers_ptr,
headers_len,
body_res_ptr,
body_written_ptr,
headers_res_ptr,
headers_written_ptr,
status_code_ptr,
err_ptr,
err_written_ptr
res_handle_ptr,
);

if (err != 0) {
// Based on the error code, read and log the error.
Console.log("ERROR CODE: " + err.toString());

// Error code 1 means no error message was written.
if (err == 1) {
Console.log("Runtime error: cannot find exported alloc function or memory");
abort();
}

// An error code was written. Read it, then abort.
let err_len = load<usize>(err_written_ptr) as u32;
let err_buf = new ArrayBuffer(err_len);
memory.copy(changetype<usize>(err_buf), err_ptr, err_len);
Console.log("Runtime error: " + String.UTF8.decode(err_buf));
// An error code was written. Read it, then abort.
Console.log("Runtime error: " + err.toString());
abort();
}

let status = load<usize>(status_code_ptr) as u16;
let handle = load<usize>(res_handle_ptr) as u32;

let body_size = load<usize>(body_written_ptr) as u32;
let body_res = new ArrayBuffer(body_size);
memory.copy(changetype<usize>(body_res), load<usize>(body_res_ptr), body_size);

let headers_length = load<usize>(headers_written_ptr) as u32;
let headers_res_buf = new ArrayBuffer(headers_length);
memory.copy(changetype<usize>(headers_res_buf), load<usize>(headers_res_ptr), headers_length);
let headers_res = String.UTF8.decode(headers_res_buf);

return new Response(status, stringToHeaderMap(headers_res), body_res);
return new Response(status, handle);
}

/** Transform the header map into a string. */
Expand All @@ -215,19 +245,6 @@ function headersToString(headers: Map<string, string>): string {
return res;
}

/** Transform the string representation of the headers into a map. */
function stringToHeaderMap(headersStr: string): Map<string, string> {
let res = new Map<string, string>();
let parts = headersStr.split("\n");
// the result of the split contains an empty part as well
for (let index = 0, len = parts.length - 1; index < len; index++) {
let p = parts[index].split(":");
res.set(p[0], p[1]);
}

return res;
}

/** The standard HTTP methods. */
export enum Method {
GET,
Expand Down Expand Up @@ -268,14 +285,6 @@ function methodEnumToString(m: Method): string {
}
}

/** Allocate memory for a new byte array of size `len`
* and return the offset into the module's linear memory
* to the start of the block. */
export function alloc(len: i32): usize {
let buf = new ArrayBuffer(len);
return changetype<usize>(buf);
}

/** The standard HTTP status codes. */
export enum StatusCode {
CONTINUE = 100,
Expand Down
69 changes: 58 additions & 11 deletions crates/as/package-lock.json

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

2 changes: 1 addition & 1 deletion crates/as/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,6 @@
},
"dependencies": {
"as-wasi": "0.4.4",
"assemblyscript": "^0.18.12"
"assemblyscript": "^0.18.16"
}
}
6 changes: 2 additions & 4 deletions crates/as/readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@ import {
RequestBuilder,
Response,
} from "@deislabs/wasi-experimental-http";
export { alloc } from "@deislabs/wasi-experimental-http";

export function post(): void {
let body = String.UTF8.encode("testing the body");
Expand All @@ -32,14 +31,13 @@ export function post(): void {
.body(body)
.send();

let result = String.UTF8.decode(res.body);
print(res);
}

function print(res: Response): void {
Console.log(res.status.toString());
Console.log(res.headers);
let result = String.UTF8.decode(res.body);
Console.log(res.getHeader("Content-Type"));
let result = String.UTF8.decode(res.bodyReadAll().buffer);
Console.log(result);
}
```
Expand Down
Loading

0 comments on commit 0cf7496

Please sign in to comment.