@@ 1,9 @@
+# deno chat
+
+this is just copy and pasted from deno.land/std/examples, because cloning down std is apparently a huge mysterious programming challenge at the moment
+
+to run
+
+```
+deno run server.ts
+```
@@ 1,81 @@
+<html lang="en">
+ <head>
+ <meta charset="UTF-8" />
+ <title>ws chat example</title>
+ </head>
+ <body>
+ <div>
+ <input type="text" id="input" />
+ <button id="sendButton" disabled>send</button>
+ <button id="connectButton" disabled>connect</button>
+ <button id="closeButton" disabled>close</button>
+ </div>
+ <div id="status"></div>
+ <ul id="timeline"></ul>
+ <script>
+ let ws;
+ function messageDom(msg) {
+ const div = document.createElement("li");
+ div.className = "message";
+ div.innerText = msg;
+ return div;
+ }
+ const timeline = document.getElementById("timeline");
+ const sendButton = document.getElementById("sendButton");
+ sendButton.onclick = send;
+ const closeButton =document.getElementById("closeButton");
+ closeButton.onclick=close;
+ const connectButton = document.getElementById("connectButton");
+ connectButton.onclick=connect;
+ const status = document.getElementById("status");
+ const input = document.getElementById("input");
+ input.addEventListener("keydown", keyDownEvent);
+ function send() {
+ const msg = input.value;
+ ws.send(msg);
+ applyState({inputValue: ""});
+ }
+ function keyDownEvent(e) {
+ if (e.keyCode === 13) return send();
+ }
+ function connect() {
+ if (ws) ws.close();
+ ws = new WebSocket(`ws://${location.host}/ws`);
+ ws.addEventListener("open", () => {
+ console.log("open", ws);
+ applyState({connected: true});
+ });
+ ws.addEventListener("message", ({data}) => {
+ timeline.appendChild(messageDom(data));
+ });
+ ws.addEventListener("close", () => {
+ applyState({connect: false});
+ });
+ }
+ function close() {
+ ws.close();
+ applyState({connected: false});
+ }
+ function applyState({connected, status, inputValue}) {
+ if (inputValue != null) {
+ input.value = inputValue;
+ }
+ if(status != null) {
+ status.innerText = status;
+ }
+ if (connected != null) {
+ if (connected) {
+ sendButton.disabled = false;
+ connectButton.disabled = true;
+ closeButton.disabled= false;
+ } else {
+ sendButton.disabled= true;
+ connectButton.disabled=false;
+ closeButton.disabled=true;
+ }
+ }
+ }
+ connect();
+ </script>
+ </body>
+</html>
@@ 1,80 @@
+import { listenAndServe } from "https://deno.land/std/http/server.ts";
+import {
+ acceptWebSocket,
+ acceptable,
+ WebSocket,
+ isWebSocketCloseEvent,
+} from "https://deno.land/std/ws/mod.ts";
+import { fromFileUrl } from "https://deno.land/std/path/mod.ts";
+
+const clients = new Map<number, WebSocket>();
+let clientId = 0;
+function dispatch(msg: string): void {
+ for (const client of clients.values()) {
+ client.send(msg);
+ }
+}
+async function wsHandler(ws: WebSocket): Promise<void> {
+ const id = ++clientId;
+ clients.set(id, ws);
+ dispatch(`Connected: [${id}]`);
+ for await (const msg of ws) {
+ console.log(`msg:${id}`, msg);
+ if (typeof msg === "string") {
+ dispatch(`[${id}]: ${msg}`);
+ } else if (isWebSocketCloseEvent(msg)) {
+ clients.delete(id);
+ dispatch(`Closed: [${id}]`);
+ break;
+ }
+ }
+}
+
+listenAndServe({ port: 8080 }, async (req) => {
+ if (req.method === "GET" && req.url === "/") {
+ //Serve with hack
+ const u = new URL("./index.html", import.meta.url);
+ if (u.protocol.startsWith("http")) {
+ // server launched by deno run http(s)://.../server.ts,
+ fetch(u.href).then(async (resp) => {
+ const body = new Uint8Array(await resp.arrayBuffer());
+ return req.respond({
+ status: resp.status,
+ headers: new Headers({
+ "content-type": "text/html",
+ }),
+ body,
+ });
+ });
+ } else {
+ // server launched by deno run ./server.ts
+ const file = await Deno.open(fromFileUrl(u));
+ req.respond({
+ status: 200,
+ headers: new Headers({
+ "content-type": "text/html",
+ }),
+ body: file,
+ });
+ }
+ }
+ if (req.method === "GET" && req.url === "/favicon.ico") {
+ req.respond({
+ status: 302,
+ headers: new Headers({
+ location: "https://deno.land/favicon.ico",
+ }),
+ });
+ }
+ if (req.method === "GET" && req.url === "/ws") {
+ if (acceptable(req)) {
+ acceptWebSocket({
+ conn: req.conn,
+ bufReader: req.r,
+ bufWriter: req.w,
+ headers: req.headers,
+ }).then(wsHandler);
+ }
+ }
+});
+console.log("chat server starting on :8080....");