0
0
Fork 0
mirror of https://github.com/denoland/deno.git synced 2025-02-02 04:38:21 -05:00
denoland-deno/js/fetch.ts
Ryan Dahl 0d03fafbfe Map promises onto futures.
Refactors handlers.rs

The idea is that all Deno "ops" (aka bindings) should map onto
a Rust Future. By setting the "sync" flag in the Base message
users can determine if the future is executed immediately or put
on the event loop.

In the case of async futures, a promise is automatically created.
Errors are automatically forwarded and raised.

TODO:

- The file system ops in src/handler.rs are not using the thread pool
  yet. This will be done in the future using tokio_threadpool::blocking.
  That is, if you try to call them asynchronously, you will get a promise
  and it will act asynchronous, but currently it will be blocking.
- Handlers in src/handler.rs returned boxed futures. This was to make
  it easy while developing. We should try to remove this allocation.
2018-09-09 18:47:22 -04:00

154 lines
3.5 KiB
TypeScript

// Copyright 2018 the Deno authors. All rights reserved. MIT license.
import {
assert,
log,
createResolvable,
Resolvable,
typedArrayToArrayBuffer,
notImplemented
} from "./util";
import { flatbuffers } from "flatbuffers";
import { sendAsync } from "./fbs_util";
import { deno as fbs } from "gen/msg_generated";
import {
Headers,
Request,
Response,
Blob,
RequestInit,
FormData
} from "./fetch_types";
import { TextDecoder } from "./text_encoding";
class DenoHeaders implements Headers {
append(name: string, value: string): void {
assert(false, "Implement me");
}
delete(name: string): void {
assert(false, "Implement me");
}
get(name: string): string | null {
assert(false, "Implement me");
return null;
}
has(name: string): boolean {
assert(false, "Implement me");
return false;
}
set(name: string, value: string): void {
assert(false, "Implement me");
}
forEach(
callbackfn: (value: string, key: string, parent: Headers) => void,
// tslint:disable-next-line:no-any
thisArg?: any
): void {
assert(false, "Implement me");
}
}
class FetchResponse implements Response {
readonly url: string = "";
body: null;
bodyUsed = false; // TODO
statusText = "FIXME"; // TODO
readonly type = "basic"; // TODO
redirected = false; // TODO
headers = new DenoHeaders();
readonly trailer: Promise<Headers>;
//private bodyChunks: Uint8Array[] = [];
private first = true;
private bodyWaiter: Resolvable<ArrayBuffer>;
constructor(readonly status: number, readonly body_: ArrayBuffer) {
this.bodyWaiter = createResolvable();
this.trailer = createResolvable();
setTimeout(() => {
this.bodyWaiter.resolve(body_);
}, 0);
}
arrayBuffer(): Promise<ArrayBuffer> {
return this.bodyWaiter;
}
async blob(): Promise<Blob> {
notImplemented();
return {} as Blob;
}
async formData(): Promise<FormData> {
notImplemented();
return {} as FormData;
}
async json(): Promise<object> {
const text = await this.text();
return JSON.parse(text);
}
async text(): Promise<string> {
const ab = await this.arrayBuffer();
const decoder = new TextDecoder("utf-8");
return decoder.decode(ab);
}
get ok(): boolean {
return 200 <= this.status && this.status < 300;
}
clone(): Response {
notImplemented();
return {} as Response;
}
onHeader?: (res: FetchResponse) => void;
onError?: (error: Error) => void;
onMsg(base: fbs.Base) {
/*
const error = base.error();
if (error != null) {
assert(this.onError != null);
this.onError!(new Error(error));
return;
}
*/
if (this.first) {
this.first = false;
}
}
}
export async function fetch(
input?: Request | string,
init?: RequestInit
): Promise<Response> {
const url = input as string;
log("dispatch FETCH_REQ", url);
// Send FetchReq message
const builder = new flatbuffers.Builder();
const url_ = builder.createString(url);
fbs.FetchReq.startFetchReq(builder);
fbs.FetchReq.addUrl(builder, url_);
const resBase = await sendAsync(
builder,
fbs.Any.FetchReq,
fbs.FetchReq.endFetchReq(builder)
);
// Decode FetchRes
assert(fbs.Any.FetchRes === resBase.msgType());
const msg = new fbs.FetchRes();
assert(resBase.msg(msg) != null);
const status = msg.status();
const bodyArray = msg.bodyArray();
assert(bodyArray != null);
const body = typedArrayToArrayBuffer(bodyArray!);
const response = new FetchResponse(status, body);
return response;
}