diff --git a/examples/webtransport/.gitignore b/examples/webtransport/.gitignore new file mode 100644 index 00000000..cfaad761 --- /dev/null +++ b/examples/webtransport/.gitignore @@ -0,0 +1 @@ +*.pem diff --git a/examples/webtransport/README.md b/examples/webtransport/README.md new file mode 100644 index 00000000..d7d0e36b --- /dev/null +++ b/examples/webtransport/README.md @@ -0,0 +1,18 @@ + +# Socket.IO WebTransport example + +## How to use + +```shell +# generate a self-signed certificate +$ ./generate_cert.sh + +# install dependencies +$ npm i + +# start the server +$ node index.js + +# open a Chrome browser +$ ./open_chrome.sh +``` diff --git a/examples/webtransport/generate_cert.sh b/examples/webtransport/generate_cert.sh new file mode 100755 index 00000000..72d8198a --- /dev/null +++ b/examples/webtransport/generate_cert.sh @@ -0,0 +1,8 @@ +#!/bin/bash +openssl req -new -x509 -nodes \ + -out cert.pem \ + -keyout key.pem \ + -newkey ec \ + -pkeyopt ec_paramgen_curve:prime256v1 \ + -subj '/CN=127.0.0.1' \ + -days 14 diff --git a/examples/webtransport/index.html b/examples/webtransport/index.html new file mode 100644 index 00000000..4909653e --- /dev/null +++ b/examples/webtransport/index.html @@ -0,0 +1,35 @@ + + + + + Socket.IO WebTransport exampleqg + + + + + + diff --git a/examples/webtransport/index.js b/examples/webtransport/index.js new file mode 100644 index 00000000..75aab49b --- /dev/null +++ b/examples/webtransport/index.js @@ -0,0 +1,68 @@ +import { readFileSync } from "node:fs"; +import { createServer } from "node:https"; +import { Server } from "socket.io"; +import { Http3Server } from "@fails-components/webtransport"; + +const key = readFileSync("./key.pem"); +const cert = readFileSync("./cert.pem"); + +const httpsServer = createServer({ + key, + cert +}, (req, res) => { + if (req.method === "GET" && req.url === "/") { + const content = readFileSync("./index.html"); + res.writeHead(200, { + "content-type": "text/html" + }); + res.write(content); + res.end(); + } else { + res.writeHead(404).end(); + } +}); + +const io = new Server(httpsServer, { + transports: ["polling", "websocket", "webtransport"] +}); + +const port = process.env.PORT || 3000; + +io.on("connection", (socket) => { + console.log(`connect ${socket.id}`); + + socket.conn.on("upgrade", (transport) => { + console.log(`transport upgraded to ${transport.name}`); + }); + + socket.on("disconnect", (reason) => { + console.log(`disconnect ${socket.id} due to ${reason}`); + }); +}); + +httpsServer.listen(port, () => { + console.log(`server listening at https://localhost:${port}`); +}); + +const h3Server = new Http3Server({ + port, + host: "0.0.0.0", + secret: "changeit", + cert, + privKey: key, +}); + +(async () => { + const stream = await h3Server.sessionStream("/socket.io/"); + const sessionReader = stream.getReader(); + + while (true) { + const { done, value } = await sessionReader.read(); + if (done) { + break; + } + io.engine.onWebTransportSession(value); + } +})(); + +h3Server.startServer(); diff --git a/examples/webtransport/open_chrome.sh b/examples/webtransport/open_chrome.sh new file mode 100755 index 00000000..de3b8435 --- /dev/null +++ b/examples/webtransport/open_chrome.sh @@ -0,0 +1,10 @@ +#!/bin/bash +HASH=`openssl x509 -pubkey -noout -in cert.pem | + openssl pkey -pubin -outform der | + openssl dgst -sha256 -binary | + base64` + +/opt/google/chrome/chrome \ + --origin-to-force-quic-on=127.0.0.1:3000 \ + --ignore-certificate-errors-spki-list=$HASH \ + https://localhost:3000 diff --git a/examples/webtransport/package.json b/examples/webtransport/package.json new file mode 100644 index 00000000..8e600642 --- /dev/null +++ b/examples/webtransport/package.json @@ -0,0 +1,11 @@ +{ + "name": "webtransport", + "version": "0.0.1", + "description": "", + "private": true, + "type": "module", + "dependencies": { + "@fails-components/webtransport": "^0.1.7", + "socket.io": "^4.7.1" + } +}