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;
|
---|