[e29cc2e] | 1 | "use strict";
|
---|
| 2 | var __importDefault = (this && this.__importDefault) || function (mod) {
|
---|
| 3 | return (mod && mod.__esModule) ? mod : { "default": mod };
|
---|
| 4 | };
|
---|
| 5 | Object.defineProperty(exports, "__esModule", { value: true });
|
---|
| 6 | exports.serveFile = exports.restoreAdapter = exports.patchAdapter = void 0;
|
---|
| 7 | const socket_io_adapter_1 = require("socket.io-adapter");
|
---|
| 8 | const fs_1 = require("fs");
|
---|
| 9 | const debug_1 = __importDefault(require("debug"));
|
---|
| 10 | const debug = (0, debug_1.default)("socket.io:adapter-uws");
|
---|
| 11 | const SEPARATOR = "\x1f"; // see https://en.wikipedia.org/wiki/Delimiter#ASCII_delimited_text
|
---|
| 12 | const { addAll, del, broadcast } = socket_io_adapter_1.Adapter.prototype;
|
---|
| 13 | function patchAdapter(app /* : TemplatedApp */) {
|
---|
| 14 | socket_io_adapter_1.Adapter.prototype.addAll = function (id, rooms) {
|
---|
| 15 | const isNew = !this.sids.has(id);
|
---|
| 16 | addAll.call(this, id, rooms);
|
---|
| 17 | const socket = this.nsp.sockets.get(id);
|
---|
| 18 | if (!socket) {
|
---|
| 19 | return;
|
---|
| 20 | }
|
---|
| 21 | if (socket.conn.transport.name === "websocket") {
|
---|
| 22 | subscribe(this.nsp.name, socket, isNew, rooms);
|
---|
| 23 | return;
|
---|
| 24 | }
|
---|
| 25 | if (isNew) {
|
---|
| 26 | socket.conn.on("upgrade", () => {
|
---|
| 27 | const rooms = this.sids.get(id);
|
---|
| 28 | subscribe(this.nsp.name, socket, isNew, rooms);
|
---|
| 29 | });
|
---|
| 30 | }
|
---|
| 31 | };
|
---|
| 32 | socket_io_adapter_1.Adapter.prototype.del = function (id, room) {
|
---|
| 33 | del.call(this, id, room);
|
---|
| 34 | const socket = this.nsp.sockets.get(id);
|
---|
| 35 | if (socket && socket.conn.transport.name === "websocket") {
|
---|
| 36 | // @ts-ignore
|
---|
| 37 | const sessionId = socket.conn.id;
|
---|
| 38 | // @ts-ignore
|
---|
| 39 | const websocket = socket.conn.transport.socket;
|
---|
| 40 | const topic = `${this.nsp.name}${SEPARATOR}${room}`;
|
---|
| 41 | debug("unsubscribe connection %s from topic %s", sessionId, topic);
|
---|
| 42 | websocket.unsubscribe(topic);
|
---|
| 43 | }
|
---|
| 44 | };
|
---|
| 45 | socket_io_adapter_1.Adapter.prototype.broadcast = function (packet, opts) {
|
---|
| 46 | const useFastPublish = opts.rooms.size <= 1 && opts.except.size === 0;
|
---|
| 47 | if (!useFastPublish) {
|
---|
| 48 | broadcast.call(this, packet, opts);
|
---|
| 49 | return;
|
---|
| 50 | }
|
---|
| 51 | const flags = opts.flags || {};
|
---|
| 52 | const basePacketOpts = {
|
---|
| 53 | preEncoded: true,
|
---|
| 54 | volatile: flags.volatile,
|
---|
| 55 | compress: flags.compress,
|
---|
| 56 | };
|
---|
| 57 | packet.nsp = this.nsp.name;
|
---|
| 58 | const encodedPackets = this.encoder.encode(packet);
|
---|
| 59 | const topic = opts.rooms.size === 0
|
---|
| 60 | ? this.nsp.name
|
---|
| 61 | : `${this.nsp.name}${SEPARATOR}${opts.rooms.keys().next().value}`;
|
---|
| 62 | debug("fast publish to %s", topic);
|
---|
| 63 | // fast publish for clients connected with WebSocket
|
---|
| 64 | encodedPackets.forEach((encodedPacket) => {
|
---|
| 65 | const isBinary = typeof encodedPacket !== "string";
|
---|
| 66 | // "4" being the message type in the Engine.IO protocol, see https://github.com/socketio/engine.io-protocol
|
---|
| 67 | app.publish(topic, isBinary ? encodedPacket : "4" + encodedPacket, isBinary);
|
---|
| 68 | });
|
---|
| 69 | this.apply(opts, (socket) => {
|
---|
| 70 | if (socket.conn.transport.name !== "websocket") {
|
---|
| 71 | // classic publish for clients connected with HTTP long-polling
|
---|
| 72 | socket.client.writeToEngine(encodedPackets, basePacketOpts);
|
---|
| 73 | }
|
---|
| 74 | });
|
---|
| 75 | };
|
---|
| 76 | }
|
---|
| 77 | exports.patchAdapter = patchAdapter;
|
---|
| 78 | function subscribe(namespaceName, socket, isNew, rooms) {
|
---|
| 79 | // @ts-ignore
|
---|
| 80 | const sessionId = socket.conn.id;
|
---|
| 81 | // @ts-ignore
|
---|
| 82 | const websocket = socket.conn.transport.socket;
|
---|
| 83 | if (isNew) {
|
---|
| 84 | debug("subscribe connection %s to topic %s", sessionId, namespaceName);
|
---|
| 85 | websocket.subscribe(namespaceName);
|
---|
| 86 | }
|
---|
| 87 | rooms.forEach((room) => {
|
---|
| 88 | const topic = `${namespaceName}${SEPARATOR}${room}`; // '#' can be used as wildcard
|
---|
| 89 | debug("subscribe connection %s to topic %s", sessionId, topic);
|
---|
| 90 | websocket.subscribe(topic);
|
---|
| 91 | });
|
---|
| 92 | }
|
---|
| 93 | function restoreAdapter() {
|
---|
| 94 | socket_io_adapter_1.Adapter.prototype.addAll = addAll;
|
---|
| 95 | socket_io_adapter_1.Adapter.prototype.del = del;
|
---|
| 96 | socket_io_adapter_1.Adapter.prototype.broadcast = broadcast;
|
---|
| 97 | }
|
---|
| 98 | exports.restoreAdapter = restoreAdapter;
|
---|
| 99 | const toArrayBuffer = (buffer) => {
|
---|
| 100 | const { buffer: arrayBuffer, byteOffset, byteLength } = buffer;
|
---|
| 101 | return arrayBuffer.slice(byteOffset, byteOffset + byteLength);
|
---|
| 102 | };
|
---|
| 103 | // imported from https://github.com/kolodziejczak-sz/uwebsocket-serve
|
---|
| 104 | function serveFile(res /* : HttpResponse */, filepath) {
|
---|
| 105 | const { size } = (0, fs_1.statSync)(filepath);
|
---|
| 106 | const readStream = (0, fs_1.createReadStream)(filepath);
|
---|
| 107 | const destroyReadStream = () => !readStream.destroyed && readStream.destroy();
|
---|
| 108 | const onError = (error) => {
|
---|
| 109 | destroyReadStream();
|
---|
| 110 | throw error;
|
---|
| 111 | };
|
---|
| 112 | const onDataChunk = (chunk) => {
|
---|
| 113 | const arrayBufferChunk = toArrayBuffer(chunk);
|
---|
| 114 | const lastOffset = res.getWriteOffset();
|
---|
| 115 | const [ok, done] = res.tryEnd(arrayBufferChunk, size);
|
---|
| 116 | if (!done && !ok) {
|
---|
| 117 | readStream.pause();
|
---|
| 118 | res.onWritable((offset) => {
|
---|
| 119 | const [ok, done] = res.tryEnd(arrayBufferChunk.slice(offset - lastOffset), size);
|
---|
| 120 | if (!done && ok) {
|
---|
| 121 | readStream.resume();
|
---|
| 122 | }
|
---|
| 123 | return ok;
|
---|
| 124 | });
|
---|
| 125 | }
|
---|
| 126 | };
|
---|
| 127 | res.onAborted(destroyReadStream);
|
---|
| 128 | readStream
|
---|
| 129 | .on("data", onDataChunk)
|
---|
| 130 | .on("error", onError)
|
---|
| 131 | .on("end", destroyReadStream);
|
---|
| 132 | }
|
---|
| 133 | exports.serveFile = serveFile;
|
---|