Skip to content

Instantly share code, notes, and snippets.

@ZacharyL2
Created April 9, 2023 06:35
Show Gist options
  • Save ZacharyL2/719e226c1e5fc8df1780186ab1bb89ee to your computer and use it in GitHub Desktop.
Save ZacharyL2/719e226c1e5fc8df1780186ab1bb89ee to your computer and use it in GitHub Desktop.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<style>
@keyframes cursorBlink {
0% {
border-right-color: initial;
}
to {
border-right-color: transparent;
}
}
#block {
border-width: 0;
border-style: solid;
border-color: black;
border-right-width: 8px;
white-space: pre-wrap;
animation: cursorBlink 0.6s ease-in-out infinite alternate;
}
</style>
</head>
<body>
<span id="block"></span>
<script>
const parseLine = (str) => {
const match = /^(.*?):\s?(.*)$/.exec(str);
if (!match) {
return [null, str];
}
return [match[1], match[2]].map((i) => i ?? null);
};
const createParseChunkFn = (onParse) => {
let buffer = '';
const parseBuffer = () => {
let eventName = null;
let eventId = null;
for (const line of buffer.split('\n')) {
if (!line || line.startsWith(':')) {
} else {
const [field, value] = parseLine(line);
switch (field) {
case 'event':
eventName = value;
break;
case 'id':
eventId = value;
break;
case 'data':
onParse({
type: 'event',
event: eventName,
id: eventId,
data: value,
});
break;
case 'retry':
const retry = Number(value);
if (!Number.isNaN(retry)) {
onParse({ type: 'retry', value: retry });
}
break;
default:
break;
}
}
}
};
return (chunk) => {
buffer += chunk;
if (buffer.endsWith('\n\n')) {
parseBuffer();
buffer = '';
}
};
};
const main = async (onMessage) => {
const res = await fetch('/sse', {
method: 'POST',
body: JSON.stringify({ message: 'hello!' }),
});
if (!res.ok) {
throw new Error('Fetch sse error');
}
const parseChunk = createParseChunkFn((event) => {
if (event.type === 'event') {
onMessage(event.data);
}
});
const reader = res.body?.getReader();
if (reader) {
void (function read() {
reader.read().then(({ done, value }) => {
if (done) {
return;
}
const chunk = new TextDecoder().decode(value);
parseChunk(chunk);
read();
});
})();
}
};
const typedText = document.getElementById('block');
main((contents) => {
if (typedText) {
typedText.innerHTML += contents;
}
});
</script>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment