deno/cli/rt/30_net.js
Bartek Iwańczuk bda9379385
refactor: move op_resources and op_close to deno_core (#7539)
Moves op_close and op_resources to deno_core::ops and exports them.
Adds serde dependency to deno_core and reexports it.

Moves JS implementation of those ops to Deno.core and reexports them in Deno.
2020-09-17 18:09:50 +02:00

246 lines
4.4 KiB
JavaScript

// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
((window) => {
const core = window.Deno.core;
const { errors } = window.__bootstrap.errors;
const { read, write } = window.__bootstrap.io;
const ShutdownMode = {
// See http://man7.org/linux/man-pages/man2/shutdown.2.html
// Corresponding to SHUT_RD, SHUT_WR, SHUT_RDWR
0: "Read",
1: "Write",
2: "ReadWrite",
Read: 0,
Write: 1,
ReadWrite: 2, // unused
};
function shutdown(rid, how) {
core.jsonOpSync("op_shutdown", { rid, how });
return Promise.resolve();
}
function opAccept(
rid,
transport,
) {
return core.jsonOpAsync("op_accept", { rid, transport });
}
function opListen(args) {
return core.jsonOpSync("op_listen", args);
}
function opConnect(args) {
return core.jsonOpAsync("op_connect", args);
}
function opReceive(
rid,
transport,
zeroCopy,
) {
return core.jsonOpAsync(
"op_datagram_receive",
{ rid, transport },
zeroCopy,
);
}
function opSend(args, zeroCopy) {
return core.jsonOpAsync("op_datagram_send", args, zeroCopy);
}
class Conn {
#rid = 0;
#remoteAddr = null;
#localAddr = null;
constructor(
rid,
remoteAddr,
localAddr,
) {
this.#rid = rid;
this.#remoteAddr = remoteAddr;
this.#localAddr = localAddr;
}
get rid() {
return this.#rid;
}
get remoteAddr() {
return this.#remoteAddr;
}
get localAddr() {
return this.#localAddr;
}
write(p) {
return write(this.rid, p);
}
read(p) {
return read(this.rid, p);
}
close() {
core.close(this.rid);
}
// TODO(lucacasonato): make this unavailable in stable
closeWrite() {
shutdown(this.rid, ShutdownMode.Write);
}
}
class Listener {
#rid = 0;
#addr = null;
constructor(rid, addr) {
this.#rid = rid;
this.#addr = addr;
}
get rid() {
return this.#rid;
}
get addr() {
return this.#addr;
}
async accept() {
const res = await opAccept(this.rid, this.addr.transport);
return new Conn(res.rid, res.remoteAddr, res.localAddr);
}
async next() {
let conn;
try {
conn = await this.accept();
} catch (error) {
if (error instanceof errors.BadResource) {
return { value: undefined, done: true };
}
throw error;
}
return { value: conn, done: false };
}
return(value) {
this.close();
return Promise.resolve({ value, done: true });
}
close() {
core.close(this.rid);
}
[Symbol.asyncIterator]() {
return this;
}
}
class Datagram {
#rid = 0;
#addr = null;
constructor(
rid,
addr,
bufSize = 1024,
) {
this.#rid = rid;
this.#addr = addr;
this.bufSize = bufSize;
}
get rid() {
return this.#rid;
}
get addr() {
return this.#addr;
}
async receive(p) {
const buf = p || new Uint8Array(this.bufSize);
const { size, remoteAddr } = await opReceive(
this.rid,
this.addr.transport,
buf,
);
const sub = buf.subarray(0, size);
return [sub, remoteAddr];
}
send(p, addr) {
const remote = { hostname: "127.0.0.1", ...addr };
const args = { ...remote, rid: this.rid };
return opSend(args, p);
}
close() {
core.close(this.rid);
}
async *[Symbol.asyncIterator]() {
while (true) {
try {
yield await this.receive();
} catch (err) {
if (err instanceof errors.BadResource) {
break;
}
throw err;
}
}
}
}
function listen(options) {
const res = opListen({
transport: "tcp",
hostname: "0.0.0.0",
...options,
});
return new Listener(res.rid, res.localAddr);
}
async function connect(
options,
) {
let res;
if (options.transport === "unix") {
res = await opConnect(options);
} else {
res = await opConnect({
transport: "tcp",
hostname: "127.0.0.1",
...options,
});
}
return new Conn(res.rid, res.remoteAddr, res.localAddr);
}
window.__bootstrap.net = {
connect,
Conn,
opConnect,
listen,
opListen,
Listener,
shutdown,
ShutdownMode,
Datagram,
};
})(this);