Skip to content

Instantly share code, notes, and snippets.

@FND
Last active March 31, 2023 17:14
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save FND/bd5e0307dc762e0fcd428c675a6e64e0 to your computer and use it in GitHub Desktop.
Save FND/bd5e0307dc762e0fcd428c675a6e64e0 to your computer and use it in GitHub Desktop.
SSE client & server
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>exploring browsers' limits WRT event frequency</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<style>
*,
*::before,
*::after {
box-sizing: border-box;
}
body {
--h-size: 60ch;
--spacing: 0.5rem;
max-width: calc(var(--h-size) + 2 * var(--spacing));
margin: 1rem auto;
padding-left: var(--spacing);
padding-right: var(--spacing);
font-family: system-ui, sans-serif;
line-height: 1.5;
}
</style>
</head>
<body>
<h1>exploring browsers' limits WRT event frequency</h1>
<p>receiving data via Server-Sent Events</p>
<p>check console for details</p>
<script type="module">
let URI = "/stream";
let THRESHOLD = 100;
let count = 0;
let t0;
console.log("trying to establish SSE connection (this might take a few seconds)");
let sse = new EventSource(URI);
sse.addEventListener("open", ev => {
console.log("[SSE] connection established");
});
sse.addEventListener("message", onMessage);
sse.addEventListener("start", onStatus);
sse.addEventListener("end", onStatus);
sse.addEventListener("error", ev => {
console.error("[SSE] unexpected error:", ev);
});
function onStatus(ev) {
console.log(`[SSE] ${ev.type}:`, ev.data);
}
function onMessage(ev) {
if(count === 0) {
t0 = Date.now();
var delta = 0;
} else {
delta = Date.now() - t0;
}
count++;
if(delta > THRESHOLD) {
console.log(`[SSE] received ${count} messages in ${delta} ms`);
console.log(`[SSE] ... latest message was`, ev.data);
count = 0;
}
}
</script>
</body>
</html>
{
"scripts": {
"start": "node ./server.js"
},
"type": "module"
}
import http from "node:http";
import { readFile } from "node:fs/promises";
import { fileURLToPath } from "node:url";
import { resolve, dirname } from "node:path";
let HOST = "localhost";
let PORT = 3000;
let HTML = "index.html";
let COUNT = 100 * 1000;
let DEPTH = 2;
let BREADTH = 3;
let ROOT = dirname(fileURLToPath(import.meta.url));
let CRLF = "\r\n";
let server = http.createServer(handleRequest).listen(PORT, HOST, () => {
let { address, port } = server.address();
console.error(`→ http://${address}:${port}`);
});
async function handleRequest(req, res) {
switch(req.url) {
case "/": {
let filepath = resolve(ROOT, HTML);
res.writeHead(200, { "Content-Type": "text/html" });
let html = await readFile(filepath, "utf8");
res.end(html);
}
case "/stream":
return sse(req, res);
default:
res.writeHead(404);
res.end("not found");
return;
}
}
function sse(req, res) {
let { socket } = res;
socket.write("HTTP/1.1 200 OK" + CRLF);
socket.write("Content-Type: text/event-stream" + CRLF);
socket.write("Cache-Control: no-cache" + CRLF);
socket.write(CRLF);
socket.write(`
event: start
data: ${new Date().toISOString()}
`.trim() + "\n\n");
let events = generateEvents(COUNT, { breadth: BREADTH, depth: DEPTH });
console.error("emitting data");
let t0 = Date.now();
for(let ev of events) {
socket.write(ev);
}
console.error(`done; took ${Date.now() - t0} ms`);
socket.write(`
event: end
data: ${new Date().toISOString()}
`.trim() + "\n\n");
}
function generateEvents(count, { breadth, depth }) {
console.error("generating data", { count, breadth, depth });
let items = [];
let t0 = Date.now();
for(let i = 0; i < count; i++) {
let item = generateObject(breadth, depth);
item = `event: message\ndata: ${JSON.stringify(item)}\n\n`;
items.push(item);
}
console.error(`... took ${Date.now() - t0} ms`);
return items;
}
function randomKey(len) {
return new Array(len).fill(0).
map(() => Math.floor(Math.random() * 16).toString(16)).
join("");
}
// adapted from surma <https://bugzilla.mozilla.org/show_bug.cgi?id=1564880>
function generateObject(breadth, depth, len = 16) {
if(depth == 0) {
return randomKey(len);
}
let obj = {};
for(let i = 0; i < breadth; i++) {
obj[randomKey(len)] = generateObject(breadth, depth - 1, len);
}
return obj;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment