deno/cli/js/net.ts

189 lines
4.4 KiB
TypeScript
Raw Normal View History

2020-01-02 20:13:47 +00:00
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
import { errors } from "./errors.ts";
import { Reader, Writer, Closer } from "./io.ts";
import { read, write } from "./ops/io.ts";
import { close } from "./ops/resources.ts";
import * as netOps from "./ops/net.ts";
import { Addr } from "./ops/net.ts";
export { ShutdownMode, shutdown, NetAddr, UnixAddr } from "./ops/net.ts";
export interface DatagramConn extends AsyncIterable<[Uint8Array, Addr]> {
2020-02-21 16:26:54 +00:00
receive(p?: Uint8Array): Promise<[Uint8Array, Addr]>;
send(p: Uint8Array, addr: Addr): Promise<void>;
2020-02-21 16:26:54 +00:00
close(): void;
addr: Addr;
[Symbol.asyncIterator](): AsyncIterableIterator<[Uint8Array, Addr]>;
2020-02-21 16:26:54 +00:00
}
export interface Listener extends AsyncIterable<Conn> {
accept(): Promise<Conn>;
close(): void;
addr: Addr;
2019-05-01 20:58:09 +00:00
[Symbol.asyncIterator](): AsyncIterableIterator<Conn>;
}
export class ConnImpl implements Conn {
constructor(
2018-10-10 15:59:36 +00:00
readonly rid: number,
readonly remoteAddr: Addr,
readonly localAddr: Addr
) {}
write(p: Uint8Array): Promise<number> {
2018-10-10 15:59:36 +00:00
return write(this.rid, p);
}
read(p: Uint8Array): Promise<number | null> {
2018-10-10 15:59:36 +00:00
return read(this.rid, p);
}
close(): void {
2018-10-10 15:59:36 +00:00
close(this.rid);
}
// TODO(lucacasonato): make this unavailable in stable
closeWrite(): void {
netOps.shutdown(this.rid, netOps.ShutdownMode.Write);
}
}
2019-10-21 18:38:28 +00:00
export class ListenerImpl implements Listener {
constructor(readonly rid: number, readonly addr: Addr) {}
async accept(): Promise<Conn> {
const res = await netOps.accept(this.rid, this.addr.transport);
2019-08-27 15:35:32 +00:00
return new ConnImpl(res.rid, res.remoteAddr, res.localAddr);
}
async next(): Promise<IteratorResult<Conn>> {
let conn: 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?: Conn): Promise<IteratorResult<Conn>> {
this.close();
return Promise.resolve({ value, done: true });
}
close(): void {
close(this.rid);
}
[Symbol.asyncIterator](): AsyncIterableIterator<Conn> {
return this;
2019-05-01 20:58:09 +00:00
}
}
export class DatagramImpl implements DatagramConn {
2020-02-21 16:26:54 +00:00
constructor(
readonly rid: number,
readonly addr: Addr,
public bufSize: number = 1024
2020-02-21 16:26:54 +00:00
) {}
async receive(p?: Uint8Array): Promise<[Uint8Array, Addr]> {
const buf = p || new Uint8Array(this.bufSize);
const { size, remoteAddr } = await netOps.receive(
this.rid,
this.addr.transport,
buf
);
2020-02-21 16:26:54 +00:00
const sub = buf.subarray(0, size);
return [sub, remoteAddr];
}
async send(p: Uint8Array, addr: Addr): Promise<void> {
2020-05-13 12:03:04 +00:00
const remote = { hostname: "127.0.0.1", ...addr };
2020-02-21 16:26:54 +00:00
const args = { ...remote, rid: this.rid };
await netOps.send(args as netOps.SendRequest, p);
2020-02-21 16:26:54 +00:00
}
close(): void {
close(this.rid);
}
async *[Symbol.asyncIterator](): AsyncIterableIterator<[Uint8Array, Addr]> {
while (true) {
try {
yield await this.receive();
} catch (error) {
if (error instanceof errors.BadResource) {
break;
2020-02-21 16:26:54 +00:00
}
throw error;
}
}
2020-02-21 16:26:54 +00:00
}
}
export interface Conn extends Reader, Writer, Closer {
localAddr: Addr;
remoteAddr: Addr;
rid: number;
closeWrite(): void;
}
export interface ListenOptions {
port: number;
hostname?: string;
transport?: "tcp";
}
2020-02-21 16:26:54 +00:00
export function listen(
options: ListenOptions & { transport?: "tcp" }
): Listener;
export function listen(options: ListenOptions): Listener {
const res = netOps.listen({
transport: "tcp",
hostname: "0.0.0.0",
...(options as ListenOptions),
});
return new ListenerImpl(res.rid, res.localAddr);
}
export interface ConnectOptions {
port: number;
hostname?: string;
transport?: "tcp";
}
export interface UnixConnectOptions {
transport: "unix";
path: string;
}
export async function connect(options: UnixConnectOptions): Promise<Conn>;
export async function connect(options: ConnectOptions): Promise<Conn>;
export async function connect(
options: ConnectOptions | UnixConnectOptions
): Promise<Conn> {
let res;
if (options.transport === "unix") {
res = await netOps.connect(options);
} else {
res = await netOps.connect({
transport: "tcp",
hostname: "127.0.0.1",
...options,
});
}
2019-08-26 12:50:21 +00:00
return new ConnImpl(res.rid, res.remoteAddr!, res.localAddr!);
}