Download bridge.js from HelloSun/dosmqtt: direct link, hf CLI and curl.
- Browser
- Download file 5.76 kB
-
https://huggingface.co/spaces/HelloSun/dosmqtt/resolve/main/bridge.js
- Command line
-
hf download hf://spaces/HelloSun/dosmqtt/bridge.js
-
curl -L -o bridge.js https://huggingface.co/spaces/HelloSun/dosmqtt/resolve/main/bridge.js
5.76 kB
| /* | |
| * In-page TCP -> WebSocket bridge for v86 guests. | |
| * | |
| * A DOS machine talks real TCP/IP through its emulated NE2000 card. v86's "wisp" | |
| * network backend terminates the guest's TCP streams and forwards the bytes as | |
| * WISP frames over a WebSocket. This file plays the WISP *server* inside the page | |
| * (no backend needed): every TCP stream the guest opens to port 1883 is relayed, | |
| * byte for byte, to a public MQTT-over-WebSocket broker. MQTT is identical on both | |
| * transports, so the DOS program speaks genuine MQTT 3.1.1 over its own TCP stack. | |
| * | |
| * Install with MqttBridge.install(); then give v86 `relay_url: "wisp://mqttbridge.invalid/"`. | |
| */ | |
| (function () { | |
| 'use strict'; | |
| const RealWebSocket = window.WebSocket; | |
| const FAKE_HOST = 'mqttbridge.invalid'; | |
| const WINDOW = 128; // WISP flow-control credit handed to the guest per stream | |
| const bridge = { | |
| brokerUrl: 'wss://broker.emqx.io:8084/mqtt', | |
| onEvent: null, | |
| verbose: false, | |
| stats: { streams: 0, toBroker: 0, toGuest: 0 }, | |
| }; | |
| function emit(machine, text) { | |
| if (typeof bridge.onEvent === 'function') bridge.onEvent(machine, text); | |
| } | |
| const u32 = (n) => [n & 255, (n >> 8) & 255, (n >> 16) & 255, (n >>> 24) & 255]; | |
| function frame(type, streamId, payload) { | |
| const body = payload || []; | |
| const out = new Uint8Array(5 + body.length); | |
| out[0] = type; | |
| out.set(u32(streamId), 1); | |
| out.set(body, 5); | |
| return out; | |
| } | |
| class FakeWispServer { | |
| constructor(url) { | |
| this.url = url; | |
| this.machine = (/[?&]m=([^&]+)/.exec(url) || [])[1] || 'dos'; | |
| this.binaryType = 'arraybuffer'; | |
| this.readyState = 0; // CONNECTING | |
| this.streams = new Map(); | |
| this.onopen = this.onmessage = this.onclose = this.onerror = null; | |
| setTimeout(() => { | |
| this.readyState = 1; // OPEN | |
| if (this.onopen) this.onopen({ type: 'open' }); | |
| this.reply(frame(3, 0, u32(WINDOW))); // CONTINUE for stream 0: initial credit | |
| }, 0); | |
| } | |
| reply(bytes) { | |
| if (this.readyState !== 1 || !this.onmessage) return; | |
| this.onmessage({ data: bytes.buffer.slice(bytes.byteOffset, bytes.byteOffset + bytes.byteLength) }); | |
| } | |
| send(data) { | |
| const f = new Uint8Array(data.buffer ? data.buffer.slice(data.byteOffset, data.byteOffset + data.byteLength) : data); | |
| const type = f[0]; | |
| const id = new DataView(f.buffer).getUint32(1, true); | |
| if (type === 1) this.connect(id, f); | |
| else if (type === 2) this.data(id, f.subarray(5)); | |
| else if (type === 4) this.closeStream(id, false); | |
| } | |
| connect(id, f) { | |
| const port = f[6] | (f[7] << 8); | |
| const host = new TextDecoder().decode(f.subarray(8)); | |
| if (port !== 1883) { | |
| emit(this.machine, `TCP ${host}:${port} refused (bridge only relays MQTT port 1883)`); | |
| this.reply(frame(4, id, [0x44])); // CLOSE: connection refused | |
| return; | |
| } | |
| bridge.stats.streams += 1; | |
| emit(this.machine, `DOS opened TCP ${host}:${port} -> relaying to ${bridge.brokerUrl}`); | |
| const s = { ws: new RealWebSocket(bridge.brokerUrl, 'mqtt'), queue: [], open: false, done: false }; | |
| s.ws.binaryType = 'arraybuffer'; | |
| s.ws.onopen = () => { | |
| s.open = true; | |
| emit(this.machine, 'WSS to broker is open'); | |
| s.queue.forEach((chunk) => s.ws.send(chunk)); | |
| s.queue = []; | |
| }; | |
| s.ws.onmessage = (ev) => { | |
| const bytes = new Uint8Array(ev.data); | |
| bridge.stats.toGuest += bytes.length; | |
| if (bridge.verbose) emit(this.machine, `broker -> DOS ${bytes.length} bytes (${Array.from(bytes.subarray(0, 4)).map((b) => b.toString(16)).join(' ')})`); | |
| // The guest TCP stack segments large writes itself; keep frames modest anyway. | |
| for (let o = 0; o < bytes.length; o += 1024) this.reply(frame(2, id, bytes.subarray(o, o + 1024))); | |
| }; | |
| const finish = (why) => { | |
| if (s.done) return; | |
| s.done = true; | |
| emit(this.machine, `broker connection closed (${why})`); | |
| if (this.streams.has(id)) { this.streams.delete(id); this.reply(frame(4, id, [0x02])); } | |
| }; | |
| s.ws.onclose = () => finish('close'); | |
| s.ws.onerror = () => finish('error'); | |
| this.streams.set(id, s); | |
| } | |
| data(id, bytes) { | |
| const s = this.streams.get(id); | |
| if (!s) return; | |
| const chunk = bytes.slice(); | |
| bridge.stats.toBroker += chunk.length; | |
| if (bridge.verbose) emit(this.machine, `DOS -> broker ${chunk.length} bytes (${Array.from(chunk.subarray(0, 4)).map((b) => b.toString(16)).join(' ')})${s.open ? '' : ' [queued until WSS opens]'}`); | |
| if (s.open) s.ws.send(chunk); else s.queue.push(chunk); | |
| this.reply(frame(3, id, u32(WINDOW))); // replenish the guest's send credit | |
| } | |
| closeStream(id) { | |
| const s = this.streams.get(id); | |
| if (!s) return; | |
| this.streams.delete(id); | |
| s.done = true; | |
| try { s.ws.close(); } catch (e) { /* already closed */ } | |
| emit(this.machine, 'DOS closed its TCP connection'); | |
| } | |
| close() { | |
| this.readyState = 3; | |
| for (const id of Array.from(this.streams.keys())) this.closeStream(id); | |
| if (this.onclose) this.onclose({ type: 'close' }); | |
| } | |
| } | |
| bridge.install = function (opts) { | |
| Object.assign(bridge, opts || {}); | |
| if (window.WebSocket.__mqttBridge) return; | |
| const patched = new Proxy(RealWebSocket, { | |
| construct(target, args) { | |
| if (String(args[0]).indexOf(FAKE_HOST) >= 0) return new FakeWispServer(String(args[0])); | |
| return Reflect.construct(target, args); | |
| }, | |
| }); | |
| patched.__mqttBridge = true; | |
| window.WebSocket = patched; | |
| }; | |
| bridge.relayUrl = (machine) => `wisp://${FAKE_HOST}/?m=${encodeURIComponent(machine)}`; | |
| window.MqttBridge = bridge; | |
| })(); | |