Title: Byte stream support for Socket readableWebStream · Issue #56004 · nodejs/node · GitHub
Open Graph Title: Byte stream support for Socket readableWebStream · Issue #56004 · nodejs/node
X Title: Byte stream support for Socket readableWebStream · Issue #56004 · nodejs/node
Description: What is the problem this feature will solve? As mentioned by the winterCG it is reasonable to assume that most TCP cases are bytes oriented. And my case (MQTT server/client) is one of them. However: import { createConnection } from "node...
Open Graph Description: What is the problem this feature will solve? As mentioned by the winterCG it is reasonable to assume that most TCP cases are bytes oriented. And my case (MQTT server/client) is one of them. However...
X Description: What is the problem this feature will solve? As mentioned by the winterCG it is reasonable to assume that most TCP cases are bytes oriented. And my case (MQTT server/client) is one of them. However...
Opengraph URL: https://github.com/nodejs/node/issues/56004
X: @github
Domain: github.com
{"@context":"https://schema.org","@type":"DiscussionForumPosting","headline":"Byte stream support for Socket readableWebStream","articleBody":"### What is the problem this feature will solve?\r\n\r\nAs mentioned by the [winterCG](https://sockets-api.proposal.wintercg.org/#readable-attribute/) it is reasonable to assume that most TCP cases are bytes oriented. And my case (MQTT server/client) is one of them.\r\n\r\nHowever: \r\n```javascript\r\nimport { createConnection } from \"node:net\";\r\nimport { Readable } from \"node:stream\";\r\n\r\nconst socket = createConnection({ port:1883, host: \"localhost\" }, () =\u003e {\r\n const readable= Readable.toWeb(socket);\r\n const reader = readable.getReader({ mode: \"byob\" });\r\n});\r\n``` \r\n\r\nGives me:\r\n```\r\n node:internal/webstreams/readablestream:2280\r\n throw new ERR_INVALID_ARG_VALUE('stream', stream, 'must be a byte stream');\r\n ^\r\n\r\nTypeError [ERR_INVALID_ARG_VALUE]: The argument 'stream' must be a byte stream. Received ReadableStream { locked: false, state: 'readable', supportsBYOB: false }\r\n at setupReadableStreamBYOBReader (node:internal/webstreams/readablestream:2280:11)\r\n at new ReadableStreamBYOBReader (node:internal/webstreams/readablestream:935:5)\r\n at ReadableStream.getReader (node:internal/webstreams/readablestream:346:12)\r\n at Socket.\u003canonymous\u003e (file:///home/hansklunder/github/opifex/tmp.js:6:29)\r\n at Object.onceWrapper (node:events:632:28)\r\n at Socket.emit (node:events:518:28)\r\n at TCPConnectWrap.afterConnect [as oncomplete] (node:net:1595:10) {\r\n code: 'ERR_INVALID_ARG_VALUE'\r\n}\r\n```\r\n\r\nWhich makes sense in its current implementation.\r\n\r\nSolving this would bring better compatibility with the WinterCG standards and would make it easier to implement TCP bytestream protocols in NodeJS.\r\n\r\n \r\n\r\n### What is the feature you are proposing to solve the problem?\r\n\r\nIt would be nice if I could signal either at the creation of the socket or the Readable.toWeb() that I want a ReadableByteStream instead of ReadableDefaultStream.\r\n\r\nEven more brilliant would be if I could skip the `Readable.toWeb()` call also somehow, e.g. by importing `node:sockets` or something similar.\r\n\r\n### What alternatives have you considered?\r\n\r\nI've currently hacked my own layer on top of the socket event API:\r\n\r\n``` javascript\r\nimport { Writable } from \"node:stream\";\r\nfunction closer(sock) {\r\n if (!sock.closed) {\r\n sock.end();\r\n }\r\n}\r\nexport function wrapNodeSocket(socket) {\r\n const readable = new ReadableStream({\r\n type: \"bytes\",\r\n start(controller) {\r\n socket.on(\"data\", (data) =\u003e {\r\n controller.enqueue(data);\r\n const desiredSize = controller.desiredSize ?? 0;\r\n if (desiredSize \u003c= 0) {\r\n // The internal queue is full, so propagate\r\n // the backpressure signal to the underlying source.\r\n socket.pause();\r\n }\r\n });\r\n socket.on(\"error\", (err) =\u003e controller.error(err));\r\n socket.on(\"end\", () =\u003e {\r\n // close the controller\r\n controller.close();\r\n // and unlock the last BYOB read request\r\n controller.byobRequest?.respond(0);\r\n });\r\n },\r\n pull: () =\u003e {\r\n socket.resume();\r\n },\r\n cancel: () =\u003e {\r\n socket.end();\r\n },\r\n });\r\n const writable = Writable.toWeb(socket);\r\n const remoteAddr = {\r\n hostname: socket.remoteAddress || \"\",\r\n port: socket.remotePort || 0,\r\n };\r\n const conn = {\r\n readable: readable,\r\n writable: writable,\r\n close: () =\u003e closer(socket),\r\n remoteAddr,\r\n };\r\n return conn;\r\n}\r\n```\r\nThis works, but it would be nice if it was part of standard NodeJS functionality.\r\n","author":{"url":"https://github.com/seriousme","@type":"Person","name":"seriousme"},"datePublished":"2024-11-26T18:09:57.000Z","interactionStatistic":{"@type":"InteractionCounter","interactionType":"https://schema.org/CommentAction","userInteractionCount":4},"url":"https://github.com/56004/node/issues/56004"}
| route-pattern | /_view_fragments/issues/show/:user_id/:repository/:id/issue_layout(.:format) |
| route-controller | voltron_issues_fragments |
| route-action | issue_layout |
| fetch-nonce | v2:bfeff61f-0496-0d31-3b63-09bdd7e4c5e3 |
| current-catalog-service-hash | 81bb79d38c15960b92d99bca9288a9108c7a47b18f2423d0f6438c5b7bcd2114 |
| request-id | A68E:AAFC3:ECA298:140DE74:6A4C6772 |
| html-safe-nonce | 2db8165727cfbe1222ea0fc8cf4a7c527d5540afe88b66851a4876570d584211 |
| visitor-payload | eyJyZWZlcnJlciI6IiIsInJlcXVlc3RfaWQiOiJBNjhFOkFBRkMzOkVDQTI5ODoxNDBERTc0OjZBNEM2NzcyIiwidmlzaXRvcl9pZCI6IjI0MjY4MTkyMzM0MzUwOTM2MiIsInJlZ2lvbl9lZGdlIjoiaWFkIiwicmVnaW9uX3JlbmRlciI6ImlhZCJ9 |
| visitor-hmac | dfcc6b6eed1789cfd65206b0daa433834222d079e8f758082a33c9f54e9f164f |
| hovercard-subject-tag | issue:2695639132 |
| github-keyboard-shortcuts | repository,issues,copilot |
| google-site-verification | Apib7-x98H0j5cPqHWwSMm6dNU4GmODRoqxLiDzdx9I |
| octolytics-url | https://collector.github.com/github/collect |
| analytics-location | / |
| fb:app_id | 1401488693436528 |
| apple-itunes-app | app-id=1477376905, app-argument=https://github.com/_view_fragments/issues/show/nodejs/node/56004/issue_layout |
| twitter:image | https://opengraph.githubassets.com/71693406eb98186318d2f5c391ef8ceae94897c3a25f59aaac11172bcbee79d4/nodejs/node/issues/56004 |
| twitter:card | summary_large_image |
| og:image | https://opengraph.githubassets.com/71693406eb98186318d2f5c391ef8ceae94897c3a25f59aaac11172bcbee79d4/nodejs/node/issues/56004 |
| og:image:alt | What is the problem this feature will solve? As mentioned by the winterCG it is reasonable to assume that most TCP cases are bytes oriented. And my case (MQTT server/client) is one of them. However... |
| og:image:width | 1200 |
| og:image:height | 600 |
| og:site_name | GitHub |
| og:type | object |
| og:author:username | seriousme |
| hostname | github.com |
| expected-hostname | github.com |
| None | 3d11bb817438277de2a940854450e83a7d32b6aeb5014e9e6b00a6423900251c |
| turbo-cache-control | no-preview |
| go-import | github.com/nodejs/node git https://github.com/nodejs/node.git |
| octolytics-dimension-user_id | 9950313 |
| octolytics-dimension-user_login | nodejs |
| octolytics-dimension-repository_id | 27193779 |
| octolytics-dimension-repository_nwo | nodejs/node |
| octolytics-dimension-repository_public | true |
| octolytics-dimension-repository_is_fork | false |
| octolytics-dimension-repository_network_root_id | 27193779 |
| octolytics-dimension-repository_network_root_nwo | nodejs/node |
| turbo-body-classes | logged-out env-production page-responsive |
| disable-turbo | false |
| browser-stats-url | https://api.github.com/_private/browser/stats |
| browser-errors-url | https://api.github.com/_private/browser/errors |
| release | 14099438da5379150f15a2892474c7c7e6c0e55e |
| ui-target | full |
| theme-color | #1e2327 |
| color-scheme | light dark |
Links:
Viewport: width=device-width