Deno: Add TCP server API

Created on 10 Sep 2018  路  6Comments  路  Source: denoland/deno

Generally should follow the Go API.
Here is an echo server:

import * as deno from "deno";
const listener = deno.listen("tcp", ":8080");
for (;;) {
  const conn = await listener.accept();
  deno.copy(conn, conn);
}

Most helpful comment

Async iteration is idiomatic to JS/TS and would allow:

for await (const conn of listener.accept()) {
  await deno.copy(conn, conn);
  if (something) break;
}

Deno could hook into break by implementing .return() on the iterator to perform any cleanup. Also these things naturally handle back pressure and can be composed/pipelined in various interesting ways.

[edit] Did a quick test and confirmed that both throw and return inside the loop body also call .return() on the iterator.

let things = [
  { value: 0, done: false },
  { value: 1, done: false },
  { value: 2, done: false },
  { done: true },
];

const ait = {
  [Symbol.asyncIterator]() {
    return this;
  },
  next() {
    return Promise.resolve(things.shift());
  },
  return() {
    console.log('EARLY RETURN');
    return Promise.resolve({ value: 'too soon', done: true });
  },
};

(async() => {
  for await (const x of ait) {
    console.log('ITERATE', x);
    // break;
    // return;
    // throw new Error('oops');
    // await Promise.reject(new Error('oops'));
  }
})().catch(err => console.error(err.stack));

No early exit:

ITERATE 0
ITERATE 1
ITERATE 2

uncomment return

ITERATE 0
EARLY RETURN

uncomment break

ITERATE 0
EARLY RETURN

uncomment throw

ITERATE 0
EARLY RETURN
Error: oops
    at /Users/greimer/deleteme/test.js:26:11
    at process._tickCallback (internal/process/next_tick.js:68:7)
    at Function.Module.runMain (internal/modules/cjs/loader.js:745:11)
    at startup (internal/bootstrap/node.js:279:19)
    at bootstrapNodeJSCore (internal/bootstrap/node.js:696:3)

uncomment rejection

ITERATE 0
EARLY RETURN
Error: oops
    at /Users/greimer/deleteme/test.js:27:26
    at process._tickCallback (internal/process/next_tick.js:68:7)
    at Function.Module.runMain (internal/modules/cjs/loader.js:745:11)
    at startup (internal/bootstrap/node.js:279:19)
    at bootstrapNodeJSCore (internal/bootstrap/node.js:696:3)

All 6 comments

Not quite sure whether I understand the API design.

Is copy(a, b) sync or is it async (but the returned promise is not awaited so it doesn't block in the example)?

Instead of for (;;) { const conn = await accept(); /* do stuff */ } wouldn't it make sense to use async iteration here, as in for await (const conn = accept()) { /* do stuff */ }?

@MarkTiedemann copy() is async and defined the Roadmap, I've pulled it out here: https://gist.github.com/ry/5b60ef3aa032a8460a3264aeb671fc64

Regarding async iterators: *shrug*

Async iteration is idiomatic to JS/TS and would allow:

for await (const conn of listener.accept()) {
  await deno.copy(conn, conn);
  if (something) break;
}

Deno could hook into break by implementing .return() on the iterator to perform any cleanup. Also these things naturally handle back pressure and can be composed/pipelined in various interesting ways.

[edit] Did a quick test and confirmed that both throw and return inside the loop body also call .return() on the iterator.

let things = [
  { value: 0, done: false },
  { value: 1, done: false },
  { value: 2, done: false },
  { done: true },
];

const ait = {
  [Symbol.asyncIterator]() {
    return this;
  },
  next() {
    return Promise.resolve(things.shift());
  },
  return() {
    console.log('EARLY RETURN');
    return Promise.resolve({ value: 'too soon', done: true });
  },
};

(async() => {
  for await (const x of ait) {
    console.log('ITERATE', x);
    // break;
    // return;
    // throw new Error('oops');
    // await Promise.reject(new Error('oops'));
  }
})().catch(err => console.error(err.stack));

No early exit:

ITERATE 0
ITERATE 1
ITERATE 2

uncomment return

ITERATE 0
EARLY RETURN

uncomment break

ITERATE 0
EARLY RETURN

uncomment throw

ITERATE 0
EARLY RETURN
Error: oops
    at /Users/greimer/deleteme/test.js:26:11
    at process._tickCallback (internal/process/next_tick.js:68:7)
    at Function.Module.runMain (internal/modules/cjs/loader.js:745:11)
    at startup (internal/bootstrap/node.js:279:19)
    at bootstrapNodeJSCore (internal/bootstrap/node.js:696:3)

uncomment rejection

ITERATE 0
EARLY RETURN
Error: oops
    at /Users/greimer/deleteme/test.js:27:26
    at process._tickCallback (internal/process/next_tick.js:68:7)
    at Function.Module.runMain (internal/modules/cjs/loader.js:745:11)
    at startup (internal/bootstrap/node.js:279:19)
    at bootstrapNodeJSCore (internal/bootstrap/node.js:696:3)

Is anyone working on it? if not can someone help me in getting started?

@kanishkarj It's a big project. We're working towards it. #721 needs to happen first to establish the file descriptor table where sockets will be stored. We'll probably will have that by the end of the week.

I see. @ry thanks for the information..

Was this page helpful?
0 / 5 - 0 ratings

Related issues

kyeotic picture kyeotic  路  3Comments

motss picture motss  路  3Comments

somombo picture somombo  路  3Comments

doutchnugget picture doutchnugget  路  3Comments

ry picture ry  路  3Comments