1
0
Fork 0
mirror of https://github.com/denoland/deno.git synced 2024-11-22 15:06:54 -05:00

refactor: use primordials for extensions/websocket (#11240)

This commit is contained in:
Divy Srivastava 2021-07-04 21:08:04 +05:30 committed by GitHub
parent a8f9ac654d
commit ffd28e7d67
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23

View file

@ -1,12 +1,37 @@
// Copyright 2018-2021 the Deno authors. All rights reserved. MIT license.
"use strict";
/// <reference path="../../core/internal.d.ts" />
((window) => {
const core = window.Deno.core;
const { URL } = window.__bootstrap.url;
const webidl = window.__bootstrap.webidl;
const { HTTP_TOKEN_CODE_POINT_RE } = window.__bootstrap.infra;
const { DOMException } = window.__bootstrap.domException;
const { Blob } = globalThis.__bootstrap.file;
const {
ArrayBuffer,
ArrayBufferIsView,
ArrayPrototypeJoin,
DataView,
ErrorPrototypeToString,
ObjectDefineProperty,
Map,
MapPrototypeGet,
MapPrototypeSet,
Set,
Symbol,
String,
StringPrototypeToLowerCase,
StringPrototypeEndsWith,
FunctionPrototypeCall,
RegExpPrototypeTest,
ObjectDefineProperties,
ArrayPrototypeMap,
ArrayPrototypeSome,
PromisePrototypeThen,
} = window.__bootstrap.primordials;
webidl.converters["sequence<DOMString> or DOMString"] = (V, opts) => {
// Union for (sequence<DOMString> or DOMString)
@ -24,10 +49,11 @@
return webidl.converters["Blob"](V, opts);
}
if (typeof V === "object") {
// TODO(littledivy): use primordial for SharedArrayBuffer
if (V instanceof ArrayBuffer || V instanceof SharedArrayBuffer) {
return webidl.converters["ArrayBuffer"](V, opts);
}
if (ArrayBuffer.isView(V)) {
if (ArrayBufferIsView(V)) {
return webidl.converters["ArrayBufferView"](V, opts);
}
}
@ -58,7 +84,7 @@
if (typeof wrappedHandler.handler !== "function") {
return;
}
return wrappedHandler.handler.call(this, ...args);
return FunctionPrototypeCall(wrappedHandler.handler, this, ...args);
}
wrappedHandler.handler = handler;
return wrappedHandler;
@ -66,22 +92,25 @@
// TODO(lucacasonato) reuse when we can reuse code between web crates
function defineEventHandler(emitter, name) {
// HTML specification section 8.1.5.1
Object.defineProperty(emitter, `on${name}`, {
ObjectDefineProperty(emitter, `on${name}`, {
get() {
return this[handlerSymbol]?.get(name)?.handler;
if (!this[handlerSymbol]) {
return null;
}
return MapPrototypeGet(this[handlerSymbol], name)?.handler;
},
set(value) {
if (!this[handlerSymbol]) {
this[handlerSymbol] = new Map();
}
let handlerWrapper = this[handlerSymbol]?.get(name);
let handlerWrapper = MapPrototypeGet(this[handlerSymbol], name);
if (handlerWrapper) {
handlerWrapper.handler = value;
} else {
handlerWrapper = makeWrappedHandler(value);
this.addEventListener(name, handlerWrapper);
}
this[handlerSymbol].set(name, handlerWrapper);
MapPrototypeSet(this[handlerSymbol], name, handlerWrapper);
},
configurable: true,
enumerable: true,
@ -194,7 +223,7 @@
);
}
if (wsURL.hash !== "" || wsURL.href.endsWith("#")) {
if (wsURL.hash !== "" || StringPrototypeEndsWith(wsURL.href, "#")) {
throw new DOMException(
"Fragments are not allowed in a WebSocket URL.",
"SyntaxError",
@ -210,7 +239,10 @@
}
if (
protocols.length !== new Set(protocols.map((p) => p.toLowerCase())).size
protocols.length !==
new Set(
ArrayPrototypeMap(protocols, (p) => StringPrototypeToLowerCase(p)),
).size
) {
throw new DOMException(
"Can't supply multiple times the same protocol.",
@ -219,7 +251,11 @@
}
if (
protocols.some((protocol) => !HTTP_TOKEN_CODE_POINT_RE.test(protocol))
ArrayPrototypeSome(
protocols,
(protocol) =>
!RegExpPrototypeTest(HTTP_TOKEN_CODE_POINT_RE, protocol),
)
) {
throw new DOMException(
"Invalid protocol value.",
@ -227,46 +263,53 @@
);
}
core.opAsync("op_ws_create", {
url: wsURL.href,
protocols: protocols.join(", "),
}).then((create) => {
this[_rid] = create.rid;
this[_extensions] = create.extensions;
this[_protocol] = create.protocol;
PromisePrototypeThen(
core.opAsync("op_ws_create", {
url: wsURL.href,
protocols: ArrayPrototypeJoin(protocols, ", "),
}),
(create) => {
this[_rid] = create.rid;
this[_extensions] = create.extensions;
this[_protocol] = create.protocol;
if (this[_readyState] === CLOSING) {
core.opAsync("op_ws_close", {
rid: this[_rid],
}).then(() => {
this[_readyState] = CLOSED;
if (this[_readyState] === CLOSING) {
PromisePrototypeThen(
core.opAsync("op_ws_close", {
rid: this[_rid],
}),
() => {
this[_readyState] = CLOSED;
const errEvent = new ErrorEvent("error");
this.dispatchEvent(errEvent);
const errEvent = new ErrorEvent("error");
this.dispatchEvent(errEvent);
const event = new CloseEvent("close");
const event = new CloseEvent("close");
this.dispatchEvent(event);
tryClose(this[_rid]);
},
);
} else {
this[_readyState] = OPEN;
const event = new Event("open");
this.dispatchEvent(event);
tryClose(this[_rid]);
});
} else {
this[_readyState] = OPEN;
const event = new Event("open");
this.dispatchEvent(event);
this.#eventLoop();
}
}).catch((err) => {
this[_readyState] = CLOSED;
this.#eventLoop();
}
},
(err) => {
this[_readyState] = CLOSED;
const errorEv = new ErrorEvent(
"error",
{ error: err, message: err.toString() },
);
this.dispatchEvent(errorEv);
const errorEv = new ErrorEvent(
"error",
{ error: err, message: ErrorPrototypeToString(err) },
);
this.dispatchEvent(errorEv);
const closeEv = new CloseEvent("close");
this.dispatchEvent(closeEv);
});
const closeEv = new CloseEvent("close");
this.dispatchEvent(closeEv);
},
);
}
send(data) {
@ -287,19 +330,23 @@
const sendTypedArray = (ta) => {
this[_bufferedAmount] += ta.byteLength;
core.opAsync("op_ws_send", {
rid: this[_rid],
kind: "binary",
}, ta).then(() => {
this[_bufferedAmount] -= ta.byteLength;
});
PromisePrototypeThen(
core.opAsync("op_ws_send", {
rid: this[_rid],
kind: "binary",
}, ta),
() => {
this[_bufferedAmount] -= ta.byteLength;
},
);
};
if (data instanceof Blob) {
data.slice().arrayBuffer().then((ab) =>
sendTypedArray(new DataView(ab))
PromisePrototypeThen(
data.slice().arrayBuffer(),
(ab) => sendTypedArray(new DataView(ab)),
);
} else if (ArrayBuffer.isView(data)) {
} else if (ArrayBufferIsView(data)) {
sendTypedArray(data);
} else if (data instanceof ArrayBuffer) {
sendTypedArray(new DataView(data));
@ -307,13 +354,16 @@
const string = String(data);
const d = core.encode(string);
this[_bufferedAmount] += d.byteLength;
core.opAsync("op_ws_send", {
rid: this[_rid],
kind: "text",
text: string,
}).then(() => {
this[_bufferedAmount] -= d.byteLength;
});
PromisePrototypeThen(
core.opAsync("op_ws_send", {
rid: this[_rid],
kind: "text",
text: string,
}),
() => {
this[_bufferedAmount] -= d.byteLength;
},
);
}
}
@ -357,20 +407,23 @@
} else if (this[_readyState] === OPEN) {
this[_readyState] = CLOSING;
core.opAsync("op_ws_close", {
rid: this[_rid],
code,
reason,
}).then(() => {
this[_readyState] = CLOSED;
const event = new CloseEvent("close", {
wasClean: true,
code: code ?? 1005,
PromisePrototypeThen(
core.opAsync("op_ws_close", {
rid: this[_rid],
code,
reason,
});
this.dispatchEvent(event);
tryClose(this[_rid]);
});
}),
() => {
this[_readyState] = CLOSED;
const event = new CloseEvent("close", {
wasClean: true,
code: code ?? 1005,
reason,
});
this.dispatchEvent(event);
tryClose(this[_rid]);
},
);
}
}
@ -443,7 +496,7 @@
}
}
Object.defineProperties(WebSocket, {
ObjectDefineProperties(WebSocket, {
CONNECTING: {
value: 0,
},