Skip to content

Commit

Permalink
fix(as-sdk): correctly serialise request bodies
Browse files Browse the repository at this point in the history
Closes: #72
  • Loading branch information
Thomasvdam committed Aug 30, 2024
1 parent e3230b6 commit 02c6530
Show file tree
Hide file tree
Showing 6 changed files with 111 additions and 54 deletions.
27 changes: 27 additions & 0 deletions libs/as-sdk-integration-tests/assembly/http.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,3 +35,30 @@ export class TestHttpSuccess extends OracleProgram {
Process.error(Bytes.fromString('Something went wrong..'), 20);
}
}

export class TestPostHttpSuccess extends OracleProgram {
execution(): void {
const headers = new Map<string, string>();
headers.set('content-type', 'application/json');

const response = httpFetch('https://jsonplaceholder.typicode.com/posts', {
body: Bytes.fromString(
`{"title":"Test SDK","body":"Don't forget to test some integrations."}`
),
method: 'POST',
headers,
});
const fulfilled = response.fulfilled;
const rejected = response.rejected;

if (fulfilled !== null) {
Process.success(fulfilled.bytes);
}

if (rejected !== null) {
Process.error(rejected.bytes);
}

Process.error(Bytes.fromString('Something went wrong..'), 20);
}
}
4 changes: 3 additions & 1 deletion libs/as-sdk-integration-tests/assembly/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { Process, Bytes } from '../../as-sdk/assembly/index';
import { TestHttpRejection, TestHttpSuccess } from './http';
import { TestHttpRejection, TestHttpSuccess, TestPostHttpSuccess} from './http';
import { testProxyHttpFetch } from './proxy-http';
import { TestTallyVmReveals, TestTallyVmRevealsFiltered } from './tally';
import { TestTallyVmHttp, TestTallyVmMode } from './vm-tests';
Expand All @@ -10,6 +10,8 @@ if (args === 'testHttpRejection') {
new TestHttpRejection().run();
} else if (args === 'testHttpSuccess') {
new TestHttpSuccess().run();
} else if (args === 'testPostHttpSuccess') {
new TestPostHttpSuccess().run();
} else if (args === 'testTallyVmMode') {
new TestTallyVmMode().run();
} else if (args === 'testTallyVmHttp') {
Expand Down
31 changes: 30 additions & 1 deletion libs/as-sdk-integration-tests/src/http.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,10 @@ describe('Http', () => {
const wasmBinary = await readFile(
'dist/libs/as-sdk-integration-tests/debug.wasm'
);
const result = await executeDrWasm(wasmBinary, Buffer.from('testHttpSuccess'));
const result = await executeDrWasm(
wasmBinary,
Buffer.from('testHttpSuccess')
);

expect(result.exitCode).toBe(0);
expect(result.result).toEqual(
Expand All @@ -67,6 +70,32 @@ describe('Http', () => {
);
});

// Possibly flakey as it relies on internet connectivity and an external service
it.only('Test SDK HTTP POST Success', async () => {
const wasmBinary = await readFile(
'dist/libs/as-sdk-integration-tests/debug.wasm'
);
const result = await executeDrWasm(
wasmBinary,
Buffer.from('testPostHttpSuccess')
);

expect(result.exitCode).toBe(0);
expect(result.result).toEqual(
new TextEncoder().encode(
JSON.stringify(
{
title: 'Test SDK',
body: "Don't forget to test some integrations.",
id: 101,
},
undefined,
2
)
)
);
});

it('should exit when an invalid WASM binary is given', async () => {
const result = await executeDrWasm(
Buffer.from(new Uint8Array([0, 97, 115, 109])),
Expand Down
54 changes: 22 additions & 32 deletions libs/as-sdk/assembly/http.ts
Original file line number Diff line number Diff line change
@@ -1,28 +1,19 @@
import { JSON } from 'json-as/assembly';
import { call_result_write, http_fetch } from './bindings/seda_v1';
import { jsonArrToUint8Array } from './json-utils';
import { jsonArrToUint8Array, bytesToJsonArray } from './json-utils';
import { PromiseStatus, FromBuffer } from './promise';
import { Bytes } from './bytes';
import { Console } from './console';

@json
export class InnerHttpResponse {
export class SerializableHttpResponse {
bytes!: u8[];
content_length!: i64;
status!: i64;
url!: string;
headers!: Map<string, string>;
}

@json
export class HttpResponseDisplay {
type: string = "HttpResponseDisplay";
bytes!: Bytes;
contentLength!: i64;
url!: string;
status!: i64;
headers!: Map<string, string>;
}

/**
* Response of an httpFetch call
*/
Expand All @@ -49,7 +40,7 @@ export class HttpResponse implements FromBuffer<HttpResponse> {
*/
public headers: Map<string, string> = new Map();

static fromInner(value: InnerHttpResponse): HttpResponse {
static fromSerializable(value: SerializableHttpResponse): HttpResponse {
const response = new HttpResponse();

if (value.bytes) {
Expand Down Expand Up @@ -86,21 +77,9 @@ export class HttpResponse implements FromBuffer<HttpResponse> {
}

fromBuffer(buffer: Uint8Array): HttpResponse {
const value = JSON.parse<InnerHttpResponse>(String.UTF8.decode(buffer.buffer));
const value = JSON.parse<SerializableHttpResponse>(String.UTF8.decode(buffer.buffer));

return HttpResponse.fromInner(value);
}

toString(): string {
const response = new HttpResponseDisplay();

response.bytes = this.bytes;
response.contentLength = this.contentLength;
response.headers = this.headers;
response.status = this.status;
response.url = this.url;

return JSON.stringify(response);
return HttpResponse.fromSerializable(value);
}
}

Expand Down Expand Up @@ -142,13 +121,24 @@ export class HttpFetchOptions {
}

@json
export class HttpFetch {
class SerializableHttpFetchOptions {
method!: string;
headers!: Map<string, string>;
body: u8[] = [];
}

@json
export class HttpFetchAction {
url: string;
options: HttpFetchOptions;
options: SerializableHttpFetchOptions;

constructor(url: string, options: HttpFetchOptions = new HttpFetchOptions()) {
constructor(url: string, options: HttpFetchOptions) {
this.url = url;
this.options = options;
this.options = new SerializableHttpFetchOptions();

this.options.method = options.method;
this.options.headers = options.headers;
this.options.body = bytesToJsonArray(options.body)
}
}

Expand All @@ -175,7 +165,7 @@ export function httpFetch(
url: string,
options: HttpFetchOptions = new HttpFetchOptions()
): PromiseStatus<HttpResponse, HttpResponse> {
const action = new HttpFetch(url, options);
const action = new HttpFetchAction(url, options);
const actionStr = JSON.stringify(action);

const buffer = String.UTF8.encode(actionStr);
Expand Down
12 changes: 9 additions & 3 deletions libs/as-sdk/assembly/json-utils.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,21 @@
import { Bytes } from "./bytes";

export function jsonArrToUint8Array(array: u8[]): Uint8Array {
const result = new Uint8Array(array.length);
result.set(array);

return result;
}

export function uint8arrayToJsonArray(input: Uint8Array): u8[] {
export function bytesToJsonArray(input: Bytes | null): u8[] {
const result: u8[] = [];

for (let i = 0; i < input.length; i++) {
result.push(input[i]);
if (input === null) {
return result;
}

for (let i = 0; i < input.value.length; i++) {
result.push(input.value[i]);
}

return result;
Expand Down
37 changes: 20 additions & 17 deletions libs/as-sdk/assembly/proxy-http.ts
Original file line number Diff line number Diff line change
@@ -1,26 +1,29 @@
import { JSON } from 'json-as/assembly';
import { HttpFetchOptions, HttpFetch, HttpResponse } from "./http";
import { HttpFetchOptions, HttpFetchAction, HttpResponse } from './http';
import { call_result_write, proxy_http_fetch } from './bindings/seda_v1';
import { PromiseStatus } from './promise';

export function proxyHttpFetch(url: string, options: HttpFetchOptions = new HttpFetchOptions()): PromiseStatus<HttpResponse, HttpResponse> {
const action = new HttpFetch(url, options);
const actionStr = JSON.stringify(action);
export function proxyHttpFetch(
url: string,
options: HttpFetchOptions = new HttpFetchOptions()
): PromiseStatus<HttpResponse, HttpResponse> {
const action = new HttpFetchAction(url, options);
const actionStr = JSON.stringify(action);

const buffer = String.UTF8.encode(actionStr);
const utf8ptr = changetype<usize>(buffer);
const buffer = String.UTF8.encode(actionStr);
const utf8ptr = changetype<usize>(buffer);

const responseLength = proxy_http_fetch(utf8ptr, buffer.byteLength);
const responseBuffer = new ArrayBuffer(responseLength);
const responseBufferPtr = changetype<usize>(responseBuffer);
const responseLength = proxy_http_fetch(utf8ptr, buffer.byteLength);
const responseBuffer = new ArrayBuffer(responseLength);
const responseBufferPtr = changetype<usize>(responseBuffer);

call_result_write(responseBufferPtr, responseLength);
call_result_write(responseBufferPtr, responseLength);

const response = String.UTF8.decode(responseBuffer);
const response = String.UTF8.decode(responseBuffer);

return PromiseStatus.fromStr(
response,
new HttpResponse(),
new HttpResponse(),
);
}
return PromiseStatus.fromStr(
response,
new HttpResponse(),
new HttpResponse()
);
}

0 comments on commit 02c6530

Please sign in to comment.