diff options
author | Ryan Dahl <ry@tinyclouds.org> | 2018-09-05 22:13:36 -0400 |
---|---|---|
committer | Ryan Dahl <ry@tinyclouds.org> | 2018-09-09 18:47:22 -0400 |
commit | 0d03fafbfec4545098023b7147c5f8fb6ae06f99 (patch) | |
tree | f7c3e10ac0956c4a1ae19c91a711de54de677965 /js/fetch.ts | |
parent | ff6eefdf87560986274799132d44b00e0a288c21 (diff) |
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.
Diffstat (limited to 'js/fetch.ts')
-rw-r--r-- | js/fetch.ts | 109 |
1 files changed, 36 insertions, 73 deletions
diff --git a/js/fetch.ts b/js/fetch.ts index 2d57fa65c..20af1d03d 100644 --- a/js/fetch.ts +++ b/js/fetch.ts @@ -8,7 +8,7 @@ import { notImplemented } from "./util"; import { flatbuffers } from "flatbuffers"; -import { send } from "./fbs_util"; +import { sendAsync } from "./fbs_util"; import { deno as fbs } from "gen/msg_generated"; import { Headers, @@ -20,16 +20,6 @@ import { } from "./fetch_types"; import { TextDecoder } from "./text_encoding"; -/** @internal */ -export function onFetchRes(base: fbs.Base, msg: fbs.FetchRes) { - const id = msg.id(); - const req = fetchRequests.get(id); - assert(req != null, `Couldn't find FetchRequest id ${id}`); - req!.onMsg(base, msg); -} - -const fetchRequests = new Map<number, FetchRequest>(); - class DenoHeaders implements Headers { append(name: string, value: string): void { assert(false, "Implement me"); @@ -58,10 +48,9 @@ class DenoHeaders implements Headers { } class FetchResponse implements Response { - readonly url: string; + readonly url: string = ""; body: null; bodyUsed = false; // TODO - status = 0; statusText = "FIXME"; // TODO readonly type = "basic"; // TODO redirected = false; // TODO @@ -71,10 +60,12 @@ class FetchResponse implements Response { private first = true; private bodyWaiter: Resolvable<ArrayBuffer>; - constructor(readonly req: FetchRequest) { - this.url = req.url; + constructor(readonly status: number, readonly body_: ArrayBuffer) { this.bodyWaiter = createResolvable(); this.trailer = createResolvable(); + setTimeout(() => { + this.bodyWaiter.resolve(body_); + }, 0); } arrayBuffer(): Promise<ArrayBuffer> { @@ -114,78 +105,50 @@ class FetchResponse implements Response { onHeader?: (res: FetchResponse) => void; onError?: (error: Error) => void; - onMsg(base: fbs.Base, msg: fbs.FetchRes) { + 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; - this.status = msg.status(); - assert(this.onHeader != null); - this.onHeader!(this); - } else { - // Body message. Assuming it all comes in one message now. - const bodyArray = msg.bodyArray(); - assert(bodyArray != null); - const ab = typedArrayToArrayBuffer(bodyArray!); - this.bodyWaiter.resolve(ab); } } } -let nextFetchId = 0; -//TODO implements Request -class FetchRequest { - private readonly id: number; - response: FetchResponse; - constructor(readonly url: string) { - this.id = nextFetchId++; - fetchRequests.set(this.id, this); - this.response = new FetchResponse(this); - } - - onMsg(base: fbs.Base, msg: fbs.FetchRes) { - this.response.onMsg(base, msg); - } - - destroy() { - fetchRequests.delete(this.id); - } - - start() { - log("dispatch FETCH_REQ", this.id, this.url); - - // Send FetchReq message - const builder = new flatbuffers.Builder(); - const url = builder.createString(this.url); - fbs.FetchReq.startFetchReq(builder); - fbs.FetchReq.addId(builder, this.id); - fbs.FetchReq.addUrl(builder, url); - const msg = fbs.FetchReq.endFetchReq(builder); - send(builder, fbs.Any.FetchReq, msg); - } -} - -export function fetch( +export async function fetch( input?: Request | string, init?: RequestInit ): Promise<Response> { - const fetchReq = new FetchRequest(input as string); - const response = fetchReq.response; - const promise = new Promise<Response>((resolve, reject) => { - response.onHeader = (response: FetchResponse) => { - log("onHeader"); - resolve(response); - }; - response.onError = (error: Error) => { - log("onError", error); - reject(error); - }; - }); - fetchReq.start(); - return promise; + 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; } |