Neale Pickett
·
2024-10-22
protocol-demo.html
1<!DOCTYPE html>
2<html>
3 <head>
4 <title>Vail Protocol Demo</title>
5 <style>
6body {
7 font-family: sans-serif;
8}
9
10.log {
11 font-family: monospace;
12 max-height: 10em;
13 overflow: scroll;
14}
15 </style>
16 <script>
17const Millisecond = 1
18const Second = 1000 * Millisecond
19
20class Vail extends EventTarget {
21 constructor(repeater, protocols=["json.vail.woozle.org"]) {
22 super()
23 this.url = new URL("wss://vail.woozle.org/chat")
24 this.url.searchParams.set("repeater", repeater)
25 this.protocols = protocols
26 this.transmitters = 0
27 this.reopen()
28 }
29
30 reopen() {
31 /** Number of clients connected */
32 this.clients = 0
33
34 /** Timestamp offset for incoming messages */
35 this.offset = 0
36
37 this.socket = new WebSocket(this.url, this.protocols)
38 this.socket.addEventListener("open", event => {
39 switch (this.socket.protocol) {
40 case "json.vail.woozle.org":
41 this.socket.addEventListener("message", event => this.jsonMessage(event))
42 break
43 case "binary.vail.woozle.org":
44 this.socket.addEventListener("message", event => this.binaryMessage(event))
45 break
46 default:
47 console.error("Unrecognized protocol:", this.socket.protocol)
48 }
49 })
50 this.socket.addEventListener("close", event => {
51 setTimeout(() => this.reopen(), 3 * Second)
52 })
53 }
54
55 jsonMessage(event) {
56 log("#json", event.data)
57 }
58
59 async binaryMessage(event) {
60 let buf = await event.data.arrayBuffer()
61 let view = new DataView(buf)
62 let ts = view.getBigUint64(0)
63 let clients = view.getUint16(8)
64 let durations = []
65 for (let i = 10; i < view.byteLength; i += 2) {
66 durations.push(view.getUint16(i))
67 }
68 let raw = [...new Uint8Array(buf)].map(x => x.toString(16).padStart(2, 0)).join(" ")
69
70 log("#binary", `${raw} ts=${ts} cli=${clients} dur=${durations}`)
71 }
72}
73
74function log(selector, text) {
75 let el = document.querySelector(selector)
76 if (!el) {
77 console.error("No match for selector", selector)
78 return
79 }
80 let log = el.querySelector(".log")
81 let line = log.appendChild(document.createElement("div"))
82 line.textContent = text
83 line.scrollIntoView()
84}
85
86function init(repeater) {
87 let cliJson = new Vail(repeater, ["json.vail.woozle.org"])
88 let cliBin = new Vail(repeater, ["binary.vail.woozle.org"])
89}
90
91init("demo")
92 </script>
93 </head>
94 <body>
95 <h1>Vail Protocol Demo</h1>
96
97 <div id="json">
98 <h2>JSON</h2>
99 <div class="log"></div>
100 </div>
101
102 <div id="binary">
103 <h2>Binary</h2>
104 <div class="log"></div>
105 </div>
106 </body>
107</html>