Skip to content

Instantly share code, notes, and snippets.

@enjikaka
Created May 14, 2024 08:44
Show Gist options
  • Save enjikaka/ac6423e077a956a003d4660a35f8e3ca to your computer and use it in GitHub Desktop.
Save enjikaka/ac6423e077a956a003d4660a35f8e3ca to your computer and use it in GitHub Desktop.
import { serve } from "https://deno.land/std@0.177.0/http/server.ts";
const te = new TextEncoder();
const chat = new EventTarget();
async function chatPostHandler (req: Request) {
const formData = await req.formData();
chat.dispatchEvent(new CustomEvent('message', {
detail: {
name: formData.get('name'),
message: formData.get('message'),
ts: Date.now()
}
}));
return new Response(null, { status: 200 });
}
function chatGetHandler () {
const chatBody = new ReadableStream({
start(controller) {
chat.addEventListener('message', e => {
controller.enqueue(te.encode('event: message\r\ndata: ' + JSON.stringify(e.detail) + '\n\n'));
});
}
});
return new Response(chatBody, {
status: 200,
headers: new Headers({ 'content-type': 'text/event-stream' })
});
}
function indexHandler () {
return new Response(`
<style>.message {display: flex;align-items: center} .message p {flex: 1} .message strong {width: 128px}</style>
<strong>Snabbchatt</strong><br>
<form method="post" action="/chat">
Namn:<br><input type="text" name="name"><br><br>
Meddelande:<br><input type="text" name="message"><br><br>
<button>Skicka</button>
</form>
<hr>
<div id="output"></div>
<script src="https://unpkg.com/@github/relative-time-element@4.2.1/dist/bundle.js" type="module"></script>
<script>
const outputEl = document.getElementById('output');
const formEl = document.querySelector('form');
const inputMessage = document.querySelector('[name="message"]');
const es = new EventSource('/chat');
es.addEventListener('message', e => {
const { name, message, ts } = JSON.parse(e.data);
const isoDate = new Date(ts).toISOString();
const template = document.createElement('template');
template.innerHTML = '<div class="message"><strong>' + name + '</strong><p>' + message + '</p><relative-time datetime="' + isoDate + '">' + isoDate + '</relative-time></div><hr>';
if (outputEl.children.length === 0) {
outputEl.appendChild(template.content);
} else {
outputEl.insertBefore(template.content, outputEl.children[0]);
}
});
formEl.addEventListener('submit', e => {
e.preventDefault();
fetch(formEl.action, {
body: new FormData(formEl),
method: formEl.method
});
inputMessage.value = null;
return false;
});
</script>
`, {
status: 200,
headers: new Headers({ 'content-type': 'text/html' })
});
}
serve((req: Request) => {
const url = new URL(req.url);
if (url.pathname.includes('/chat')) {
if (req.method === 'GET') {
return chatGetHandler(req);
}
if (req.method === 'POST') {
return chatPostHandler(req);
}
}
return indexHandler(req);
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment