Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add preventCloseOnEOF option #24247

Open
wants to merge 1 commit into
base: main
Choose a base branch
from

Conversation

lucacasonato
Copy link
Member

@lucacasonato lucacasonato commented Jun 18, 2024

This commit adds a preventCloseOnEOF option to Deno.open, Deno.create,
Deno.connect, Deno.connectTls, and Deno.startTls. It ensures that readable
streams returned from the objects' readable properties do not automatically
close the underlying resource when EOF is reached.

This option is described here: #22258 (comment)

Additionally it adds a bunch of docs for readable and writable, also
outlining some common footguns.

As a drive by fix, one can now also pass mode to Deno.create, like you
already can for Deno.open.

Fixes #22258
Fixes #15442 (by adding docs)
And helps with #17828

This commit adds the `preventCloseOnEOF` option to `Deno.open`, `Deno.create`, `Deno.connect`, `Deno.connectTls`, and `Deno.startTls`. It ensures that readable streams returned from the objects' `readable` properties do not automatically close the underlying resource when EOF is reached.

Additionally it adds a bunch of docs for `readable` and `writable`, also outlining some common footguns.

As a drive by fix, one can now also pass `mode` to `Deno.create`, like you already can for `Deno.open`.
@lucacasonato
Copy link
Member Author

Still needs tests

@haochuan9421
Copy link

haochuan9421 commented Jun 28, 2024

I think Deno.listen should also support this option, if we use conn.read() to retrive data from client, it won't auto close write side when all data is readed out. But, if we iterate the conn.readable to get out all incoming data, the write side will be auto closed and a BadResource: Bad resource ID error will throw. it's odd that when using different read method, they have inconsistent behavior on write. Maybe we should add a allowHalfOpen option like Node.js net.createServer() does to align the behavior. Here is demo code:

// server.ts
const listener = Deno.listen({
  hostname: "127.0.0.1",
  port: 8000,
  transport: "tcp",
});

for await (const conn of listener) {
  handleConn(conn).catch(console.error);
}

async function handleConn(conn: Deno.TcpConn) {
  while (true) {
    const chunk = new Uint8Array(65536);
    const readed = await conn.read(chunk);
    if (readed == null) {
      break;
    }
    console.log(chunk.subarray(0, readed));
  }

  //// If we comment the above while loop and use this code, it will cause write side auto close.
  // for await (const chunk of conn.readable) {
  //   console.log(chunk);
  // }

  const reply = new TextEncoder().encode("Hello Client!");
  let sended = 0;
  while (sended < reply.byteLength) {
    sended += await conn.write(reply.subarray(sended));
  }
  await conn.closeWrite();
}
// client.ts
const conn = await Deno.connect({
  hostname: "127.0.0.1",
  port: 8000,
  transport: "tcp",
});

const msg = new TextEncoder().encode("Hello Server!");
let sended = 0;
while (sended < msg.byteLength) {
  sended += await conn.write(msg.subarray(sended));
}
await conn.closeWrite();
console.log("msg write end");

for await (const chunk of conn.readable) {
  console.log("receive", chunk);
}
console.log("reply read end");

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
2 participants