Skip to content

Commit

Permalink
dial/listen API change (denoland#3000)
Browse files Browse the repository at this point in the history
Previously: dial("tcp", "deno.land:80")
Now: dial({ hostname: "deno.land", port: 80, transport: "tcp" })
Similarly with listen().
  • Loading branch information
ry committed Sep 20, 2019
1 parent 93b7acf commit 97bb2bd
Show file tree
Hide file tree
Showing 14 changed files with 158 additions and 136 deletions.
25 changes: 15 additions & 10 deletions cli/ops/net.rs
Original file line number Diff line number Diff line change
Expand Up @@ -49,8 +49,9 @@ pub fn op_accept(

#[derive(Deserialize)]
struct DialArgs {
network: String,
address: String,
transport: String,
hostname: String,
port: u16,
}

pub fn op_dial(
Expand All @@ -59,9 +60,11 @@ pub fn op_dial(
_zero_copy: Option<PinnedBuf>,
) -> Result<JsonOp, ErrBox> {
let args: DialArgs = serde_json::from_value(args)?;
let network = args.network;
assert_eq!(network, "tcp"); // TODO Support others.
let address = args.address;
assert_eq!(args.transport, "tcp"); // TODO Support others.

// TODO(ry) Using format! is suboptimal here. Better would be if
// state.check_net and resolve_addr() took hostname and port directly.
let address = format!("{}:{}", args.hostname, args.port);

state.check_net(&address)?;

Expand Down Expand Up @@ -117,8 +120,9 @@ pub fn op_shutdown(

#[derive(Deserialize)]
struct ListenArgs {
network: String,
address: String,
transport: String,
hostname: String,
port: u16,
}

pub fn op_listen(
Expand All @@ -127,10 +131,11 @@ pub fn op_listen(
_zero_copy: Option<PinnedBuf>,
) -> Result<JsonOp, ErrBox> {
let args: ListenArgs = serde_json::from_value(args)?;
assert_eq!(args.transport, "tcp");

let network = args.network;
assert_eq!(network, "tcp");
let address = args.address;
// TODO(ry) Using format! is suboptimal here. Better would be if
// state.check_net and resolve_addr() took hostname and port directly.
let address = format!("{}:{}", args.hostname, args.port);

state.check_net(&address)?;

Expand Down
3 changes: 2 additions & 1 deletion cli/tests/echo_server.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
const { args, listen, copy } = Deno;
const addr = args[1] || "127.0.0.1:4544";
const listener = listen("tcp", addr);
const [hostname, port] = addr.split(":");
const listener = listen({ hostname, port: Number(port) });
console.log("listening on", addr);
listener.accept().then(
async (conn): Promise<void> => {
Expand Down
2 changes: 1 addition & 1 deletion js/deps/https/deno.land/std
Submodule std updated from 6663e6 to 43aafb
2 changes: 1 addition & 1 deletion js/fetch_test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -264,7 +264,7 @@ testPerm({ net: true }, async function fetchUserAgent(): Promise<void> {

/*
function bufferServer(addr: string): Deno.Buffer {
const listener = Deno.listen("tcp", addr);
const listener = Deno.listen(addr);
const buf = new Deno.Buffer();
listener.accept().then(async conn => {
const p1 = buf.readFrom(conn);
Expand Down
83 changes: 44 additions & 39 deletions js/lib.deno_runtime.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -914,11 +914,12 @@ declare namespace Deno {

// @url js/net.d.ts

type Network = "tcp";
type Transport = "tcp";
interface Addr {
network: Network;
transport: Transport;
address: string;
}

/** A Listener is a generic network listener for stream-oriented protocols. */
export interface Listener extends AsyncIterator<Conn> {
/** Waits for and resolves to the next connection to the `Listener`. */
Expand Down Expand Up @@ -947,52 +948,56 @@ declare namespace Deno {
*/
closeWrite(): void;
}
/** Listen announces on the local network address.

export interface ListenOptions {
port: number;
hostname?: string;
transport?: Transport;
}

/** Listen announces on the local transport address.
*
* The network must be `tcp`, `tcp4`, `tcp6`, `unix` or `unixpacket`.
* @param options
* @param options.port The port to connect to. (Required.)
* @param options.hostname A literal IP address or host name that can be
* resolved to an IP address. If not specified, defaults to 0.0.0.0
* @param options.transport Defaults to "tcp". Later we plan to add "tcp4",
* "tcp6", "udp", "udp4", "udp6", "ip", "ip4", "ip6", "unix", "unixgram" and
* "unixpacket".
*
* For TCP networks, if the host in the address parameter is empty or a literal
* unspecified IP address, `listen()` listens on all available unicast and
* anycast IP addresses of the local system. To only use IPv4, use network
* `tcp4`. The address can use a host name, but this is not recommended,
* because it will create a listener for at most one of the host's IP
* addresses. If the port in the address parameter is empty or `0`, as in
* `127.0.0.1:` or `[::1]:0`, a port number is automatically chosen. The
* `addr()` method of `Listener` can be used to discover the chosen port.
* Examples:
*
* See `dial()` for a description of the network and address parameters.
* listen({ port: 80 })
* listen({ hostname: "192.0.2.1", port: 80 })
* listen({ hostname: "[2001:db8::1]", port: 80 });
* listen({ hostname: "golang.org", port: 80, transport: "tcp" })
*/
export function listen(network: Network, address: string): Listener;
/** Dial connects to the address on the named network.
*
* Supported networks are only `tcp` currently.
*
* TODO: `tcp4` (IPv4-only), `tcp6` (IPv6-only), `udp`, `udp4` (IPv4-only),
* `udp6` (IPv6-only), `ip`, `ip4` (IPv4-only), `ip6` (IPv6-only), `unix`,
* `unixgram` and `unixpacket`.
export function listen(options: ListenOptions): Listener;

export interface DialOptions {
port: number;
hostname?: string;
transport?: Transport;
}

/** Dial connects to the address on the named transport.
*
* For TCP and UDP networks, the address has the form `host:port`. The host must
* be a literal IP address, or a host name that can be resolved to IP addresses.
* The port must be a literal port number or a service name. If the host is a
* literal IPv6 address it must be enclosed in square brackets, as in
* `[2001:db8::1]:80` or `[fe80::1%zone]:80`. The zone specifies the scope of
* the literal IPv6 address as defined in RFC 4007. The functions JoinHostPort
* and SplitHostPort manipulate a pair of host and port in this form. When using
* TCP, and the host resolves to multiple IP addresses, Dial will try each IP
* address in order until one succeeds.
* @param options
* @param options.port The port to connect to. (Required.)
* @param options.hostname A literal IP address or host name that can be
* resolved to an IP address. If not specified, defaults to 127.0.0.1
* @param options.transport Defaults to "tcp". Later we plan to add "tcp4",
* "tcp6", "udp", "udp4", "udp6", "ip", "ip4", "ip6", "unix", "unixgram" and
* "unixpacket".
*
* Examples:
*
* dial("tcp", "golang.org:http")
* dial("tcp", "192.0.2.1:http")
* dial("tcp", "198.51.100.1:80")
* dial("udp", "[2001:db8::1]:domain")
* dial("udp", "[fe80::1%lo0]:53")
* dial("tcp", ":80")
* dial({ port: 80 })
* dial({ hostname: "192.0.2.1", port: 80 })
* dial({ hostname: "[2001:db8::1]", port: 80 });
* dial({ hostname: "golang.org", port: 80, transport: "tcp" })
*/
export function dial(network: Network, address: string): Promise<Conn>;
/** **RESERVED** */
export function connect(_network: Network, _address: string): Promise<Conn>;
export function dial(options: DialOptions): Promise<Conn>;

// @url js/metrics.d.ts

Expand Down
100 changes: 55 additions & 45 deletions js/net.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,18 @@ import { read, write, close } from "./files.ts";
import * as dispatch from "./dispatch.ts";
import { sendSync, sendAsync } from "./dispatch_json.ts";

export type Network = "tcp";
export type Transport = "tcp";
// TODO support other types:
// export type Network = "tcp" | "tcp4" | "tcp6" | "unix" | "unixpacket";
// export type Transport = "tcp" | "tcp4" | "tcp6" | "unix" | "unixpacket";

// TODO(ry) Replace 'address' with 'hostname' and 'port', similar to DialOptions
// and ListenOptions.
export interface Addr {
network: Network;
transport: Transport;
address: string;
}

/** A Listener is a generic network listener for stream-oriented protocols. */
/** A Listener is a generic transport listener for stream-oriented protocols. */
export interface Listener extends AsyncIterator<Conn> {
/** Waits for and resolves to the next connection to the `Listener`. */
accept(): Promise<Conn>;
Expand Down Expand Up @@ -79,7 +81,7 @@ class ConnImpl implements Conn {
class ListenerImpl implements Listener {
constructor(
readonly rid: number,
private network: Network,
private transport: Transport,
private localAddr: string
) {}

Expand All @@ -94,7 +96,7 @@ class ListenerImpl implements Listener {

addr(): Addr {
return {
network: this.network,
transport: this.transport,
address: this.localAddr
};
}
Expand Down Expand Up @@ -128,62 +130,70 @@ export interface Conn extends Reader, Writer, Closer {
closeWrite(): void;
}

/** Listen announces on the local network address.
export interface ListenOptions {
port: number;
hostname?: string;
transport?: Transport;
}
const listenDefaults = { hostname: "0.0.0.0", transport: "tcp" };

/** Listen announces on the local transport address.
*
* The network must be `tcp`, `tcp4`, `tcp6`, `unix` or `unixpacket`.
* @param options
* @param options.port The port to connect to. (Required.)
* @param options.hostname A literal IP address or host name that can be
* resolved to an IP address. If not specified, defaults to 0.0.0.0
* @param options.transport Defaults to "tcp". Later we plan to add "tcp4",
* "tcp6", "udp", "udp4", "udp6", "ip", "ip4", "ip6", "unix", "unixgram" and
* "unixpacket".
*
* For TCP networks, if the host in the address parameter is empty or a literal
* unspecified IP address, `listen()` listens on all available unicast and
* anycast IP addresses of the local system. To only use IPv4, use network
* `tcp4`. The address can use a host name, but this is not recommended,
* because it will create a listener for at most one of the host's IP
* addresses. If the port in the address parameter is empty or `0`, as in
* `127.0.0.1:` or `[::1]:0`, a port number is automatically chosen. The
* `addr()` method of `Listener` can be used to discover the chosen port.
* Examples:
*
* See `dial()` for a description of the network and address parameters.
* listen({ port: 80 })
* listen({ hostname: "192.0.2.1", port: 80 })
* listen({ hostname: "[2001:db8::1]", port: 80 });
* listen({ hostname: "golang.org", port: 80, transport: "tcp" })
*/
export function listen(network: Network, address: string): Listener {
const res = sendSync(dispatch.OP_LISTEN, { network, address });
return new ListenerImpl(res.rid, network, res.localAddr);
export function listen(options: ListenOptions): Listener {
options = Object.assign(listenDefaults, options);
const res = sendSync(dispatch.OP_LISTEN, options);
return new ListenerImpl(res.rid, options.transport, res.localAddr);
}

/** Dial connects to the address on the named network.
*
* Supported networks are only `tcp` currently.
*
* TODO: `tcp4` (IPv4-only), `tcp6` (IPv6-only), `udp`, `udp4` (IPv4-only),
* `udp6` (IPv6-only), `ip`, `ip4` (IPv4-only), `ip6` (IPv6-only), `unix`,
* `unixgram` and `unixpacket`.
export interface DialOptions {
port: number;
hostname?: string;
transport?: Transport;
}
const dialDefaults = { hostname: "127.0.0.1", transport: "tcp" };

/** Dial connects to the address on the named transport.
*
* For TCP and UDP networks, the address has the form `host:port`. The host must
* be a literal IP address, or a host name that can be resolved to IP addresses.
* The port must be a literal port number or a service name. If the host is a
* literal IPv6 address it must be enclosed in square brackets, as in
* `[2001:db8::1]:80` or `[fe80::1%zone]:80`. The zone specifies the scope of
* the literal IPv6 address as defined in RFC 4007. The functions JoinHostPort
* and SplitHostPort manipulate a pair of host and port in this form. When using
* TCP, and the host resolves to multiple IP addresses, Dial will try each IP
* address in order until one succeeds.
* @param options
* @param options.port The port to connect to. (Required.)
* @param options.hostname A literal IP address or host name that can be
* resolved to an IP address. If not specified, defaults to 127.0.0.1
* @param options.transport Defaults to "tcp". Later we plan to add "tcp4",
* "tcp6", "udp", "udp4", "udp6", "ip", "ip4", "ip6", "unix", "unixgram" and
* "unixpacket".
*
* Examples:
*
* dial("tcp", "golang.org:http")
* dial("tcp", "192.0.2.1:http")
* dial("tcp", "198.51.100.1:80")
* dial("udp", "[2001:db8::1]:domain")
* dial("udp", "[fe80::1%lo0]:53")
* dial("tcp", ":80")
* dial({ port: 80 })
* dial({ hostname: "192.0.2.1", port: 80 })
* dial({ hostname: "[2001:db8::1]", port: 80 });
* dial({ hostname: "golang.org", port: 80, transport: "tcp" })
*/
export async function dial(network: Network, address: string): Promise<Conn> {
const res = await sendAsync(dispatch.OP_DIAL, { network, address });
export async function dial(options: DialOptions): Promise<Conn> {
options = Object.assign(dialDefaults, options);
const res = await sendAsync(dispatch.OP_DIAL, options);
// TODO(bartlomieju): add remoteAddr and localAddr on Rust side
return new ConnImpl(res.rid, res.remoteAddr!, res.localAddr!);
}

/** **RESERVED** */
export async function connect(
_network: Network,
_transport: Transport,
_address: string
): Promise<Conn> {
return notImplemented();
Expand Down
Loading

0 comments on commit 97bb2bd

Please sign in to comment.