Path: blob/main/src/client/requests/websocket.js
305 views
import EventEmitter from "events";1import HookEvent from "../hook.js";23/**4* @typedef {import('../index').default} UVClient5*/67class WebSocketApi extends EventEmitter {8/**9*10* @param {UVClient} ctx11*/12constructor(ctx) {13super();14this.ctx = ctx;15this.window = ctx.window;16this.WebSocket = this.window.WebSocket || {};17this.wsProto = this.WebSocket.prototype;18this.CONNECTING = WebSocket.CONNECTING;19this.OPEN = WebSocket.OPEN;20this.CLOSING = WebSocket.CLOSING;21this.CLOSED = WebSocket.CLOSED;22this.socketmap = new WeakMap();23}24overrideWebSocket(client) {25this.ctx.override(26this.window,27"WebSocket",28(target, that, args) => {29const fakeWebSocket = new EventTarget();30Object.setPrototypeOf(fakeWebSocket, this.wsProto);31fakeWebSocket.constructor = this.WebSocket;3233const barews = client.createWebSocket(args[0], args[1], null, {34"User-Agent": navigator.userAgent,35Origin: __uv.meta.url.origin,36});3738const state = {39extensions: "",40protocol: "",41url: args[0],42binaryType: "blob",43barews,4445onclose: null,46onerror: null,47onmessage: null,48onopen: null,49};5051function fakeEventSend(fakeev) {52state["on" + fakeev.type]?.(fakeev);53fakeWebSocket.dispatchEvent(fakeev);54}5556barews.addEventListener("open", () => {57fakeEventSend(new Event("open"));58});59barews.addEventListener("close", (ev) => {60fakeEventSend(new CloseEvent("close", ev));61});62barews.addEventListener("message", async (ev) => {63let payload = ev.data;64if (typeof payload === "string") {65// DO NOTHING66} else if ("byteLength" in payload) {67// arraybuffer, convert to blob if needed or set the proper prototype68if (state.binaryType === "blob") {69payload = new Blob([payload]);70} else {71Object.setPrototypeOf(payload, ArrayBuffer.prototype);72}73} else if ("arrayBuffer" in payload) {74// blob, convert to arraybuffer if neccesary.75if (state.binaryType === "arraybuffer") {76payload = await payload.arrayBuffer();77Object.setPrototypeOf(payload, ArrayBuffer.prototype);78}79}80const fakeev = new MessageEvent("message", {81data: payload,82origin: ev.origin,83lastEventId: ev.lastEventId,84source: ev.source,85ports: ev.ports,86});8788fakeEventSend(fakeev);89});90barews.addEventListener("error", () => {91fakeEventSend(new Event("error"));92});9394this.socketmap.set(fakeWebSocket, state);95return fakeWebSocket;96},97true98);99100this.ctx.overrideDescriptor(this.wsProto, "binaryType", {101get: (target, that) => {102const ws = this.socketmap.get(that);103104return ws.binaryType;105},106set: (target, that, value) => {107const ws = this.socketmap.get(that);108if (value[0] === "blob" || value[0] === "arraybuffer")109ws.binaryType = value[0];110},111});112113this.ctx.overrideDescriptor(this.wsProto, "bufferedAmount", {114get: (target, that) => {115return 0;116},117});118119this.ctx.overrideDescriptor(this.wsProto, "extensions", {120get: (target, that) => {121const ws = this.socketmap.get(that); // get the WebSocket from socketmap122123return ws.extensions;124},125});126127this.ctx.overrideDescriptor(this.wsProto, "onclose", {128get: (target, that) => {129const ws = this.socketmap.get(that);130131return ws.onclose;132},133set: (target, that, value) => {134const ws = this.socketmap.get(that);135136ws.onclose = value[0];137},138});139140this.ctx.overrideDescriptor(this.wsProto, "onerror", {141get: (target, that) => {142const ws = this.socketmap.get(that);143144return ws.onerror;145},146set: (target, that, value) => {147const ws = this.socketmap.get(that);148149ws.onerror = value[0];150},151});152153this.ctx.overrideDescriptor(this.wsProto, "onmessage", {154get: (target, that) => {155const ws = this.socketmap.get(that);156157return ws.onmessage;158},159set: (target, that, value) => {160const ws = this.socketmap.get(that);161162ws.onmessage = value[0];163},164});165166this.ctx.overrideDescriptor(this.wsProto, "onopen", {167get: (target, that) => {168const ws = this.socketmap.get(that);169170return ws.onopen;171},172set: (target, that, value) => {173const ws = this.socketmap.get(that);174175ws.onopen = value[0];176},177});178179this.ctx.overrideDescriptor(this.wsProto, "url", {180get: (target, that) => {181const ws = this.socketmap.get(that);182183return ws.url;184},185});186187this.ctx.overrideDescriptor(this.wsProto, "protocol", {188get: (target, that) => {189const ws = this.socketmap.get(that);190191return ws.protocol;192},193});194195this.ctx.overrideDescriptor(this.wsProto, "readyState", {196get: (target, that) => {197const ws = this.socketmap.get(that);198199return ws.barews.readyState;200},201});202203this.ctx.override(204this.wsProto,205"send",206(target, that, args) => {207const ws = this.socketmap.get(that);208209return ws.barews.send(args[0]);210},211false212);213this.ctx.override(214this.wsProto,215"close",216(target, that, args) => {217const ws = this.socketmap.get(that);218if (args[0] === undefined) args[0] = 1000;219if (args[1] === undefined) args[1] = "";220return ws.barews.close(args[0], args[1]);221},222false223);224}225}226227export default WebSocketApi;228229230