@colyseus/uwebsockets-transport 0.15.0-preview.1 → 0.15.0-preview.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +41 -59
- package/build/index.js +32 -12
- package/build/index.js.map +7 -1
- package/build/index.mjs +7 -3
- package/build/index.mjs.map +7 -1
- package/build/uWebSocketClient.d.ts +6 -4
- package/build/uWebSocketClient.js +122 -98
- package/build/uWebSocketClient.js.map +7 -1
- package/build/uWebSocketClient.mjs +90 -88
- package/build/uWebSocketClient.mjs.map +7 -1
- package/build/uWebSocketsTransport.d.ts +2 -2
- package/build/uWebSocketsTransport.js +247 -255
- package/build/uWebSocketsTransport.js.map +7 -1
- package/build/uWebSocketsTransport.mjs +217 -245
- package/build/uWebSocketsTransport.mjs.map +7 -1
- package/package.json +6 -4
- package/build/node_modules/tslib/tslib.es6.js +0 -31
- package/build/node_modules/tslib/tslib.es6.js.map +0 -1
- package/build/packages/transport/uwebsockets-transport/src/index.js +0 -10
- package/build/packages/transport/uwebsockets-transport/src/index.js.map +0 -1
- package/build/packages/transport/uwebsockets-transport/src/uWebSocketClient.js +0 -91
- package/build/packages/transport/uwebsockets-transport/src/uWebSocketClient.js.map +0 -1
- package/build/packages/transport/uwebsockets-transport/src/uWebSocketsTransport.js +0 -249
- package/build/packages/transport/uwebsockets-transport/src/uWebSocketsTransport.js.map +0 -1
|
@@ -1,265 +1,257 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
var
|
|
6
|
-
var
|
|
7
|
-
var
|
|
8
|
-
var
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
const headers = {};
|
|
44
|
-
req.forEach((key, value) => headers[key] = value);
|
|
45
|
-
/* This immediately calls open handler, you must not use res after this call */
|
|
46
|
-
/* Spell these correctly */
|
|
47
|
-
res.upgrade({
|
|
48
|
-
url: req.getUrl(),
|
|
49
|
-
query: req.getQuery(),
|
|
50
|
-
// compatibility with @colyseus/ws-transport
|
|
51
|
-
headers,
|
|
52
|
-
connection: {
|
|
53
|
-
remoteAddress: Buffer.from(res.getRemoteAddressAsText()).toString()
|
|
54
|
-
}
|
|
55
|
-
}, req.getHeader('sec-websocket-key'), req.getHeader('sec-websocket-protocol'), req.getHeader('sec-websocket-extensions'), context);
|
|
56
|
-
},
|
|
57
|
-
open: async (ws) => {
|
|
58
|
-
// ws.pingCount = 0;
|
|
59
|
-
await this.onConnection(ws);
|
|
60
|
-
},
|
|
61
|
-
// pong: (ws: RawWebSocketClient) => {
|
|
62
|
-
// ws.pingCount = 0;
|
|
63
|
-
// },
|
|
64
|
-
close: (ws, code, message) => {
|
|
65
|
-
// remove from client list
|
|
66
|
-
core.spliceOne(this.clients, this.clients.indexOf(ws));
|
|
67
|
-
const clientWrapper = this.clientWrappers.get(ws);
|
|
68
|
-
if (clientWrapper) {
|
|
69
|
-
this.clientWrappers.delete(ws);
|
|
70
|
-
// emit 'close' on wrapper
|
|
71
|
-
clientWrapper.emit('close', code);
|
|
72
|
-
}
|
|
73
|
-
},
|
|
74
|
-
message: (ws, message, isBinary) => {
|
|
75
|
-
// emit 'close' on wrapper
|
|
76
|
-
this.clientWrappers.get(ws)?.emit('message', Buffer.from(message.slice(0)));
|
|
77
|
-
},
|
|
78
|
-
});
|
|
79
|
-
this.registerMatchMakeRequest();
|
|
1
|
+
var __create = Object.create;
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
6
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
7
|
+
var __export = (target, all) => {
|
|
8
|
+
for (var name in all)
|
|
9
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
10
|
+
};
|
|
11
|
+
var __copyProps = (to, from, except, desc) => {
|
|
12
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
13
|
+
for (let key of __getOwnPropNames(from))
|
|
14
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
15
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
16
|
+
}
|
|
17
|
+
return to;
|
|
18
|
+
};
|
|
19
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
20
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
21
|
+
mod
|
|
22
|
+
));
|
|
23
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
24
|
+
var uWebSocketsTransport_exports = {};
|
|
25
|
+
__export(uWebSocketsTransport_exports, {
|
|
26
|
+
uWebSocketsTransport: () => uWebSocketsTransport
|
|
27
|
+
});
|
|
28
|
+
module.exports = __toCommonJS(uWebSocketsTransport_exports);
|
|
29
|
+
var import_querystring = __toESM(require("querystring"));
|
|
30
|
+
var import_uWebSockets = __toESM(require("uWebSockets.js"));
|
|
31
|
+
var import_core = require("@colyseus/core");
|
|
32
|
+
var import_uWebSocketClient = require("./uWebSocketClient");
|
|
33
|
+
class uWebSocketsTransport extends import_core.Transport {
|
|
34
|
+
app;
|
|
35
|
+
clients = [];
|
|
36
|
+
clientWrappers = /* @__PURE__ */ new WeakMap();
|
|
37
|
+
_listeningSocket;
|
|
38
|
+
constructor(options = {}, appOptions = {}) {
|
|
39
|
+
super();
|
|
40
|
+
this.app = appOptions.cert_file_name && appOptions.key_file_name ? import_uWebSockets.default.SSLApp(appOptions) : import_uWebSockets.default.App(appOptions);
|
|
41
|
+
if (!options.maxBackpressure) {
|
|
42
|
+
options.maxBackpressure = 1024 * 1024;
|
|
80
43
|
}
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
this._listeningSocket = listeningSocket;
|
|
84
|
-
listeningListener?.();
|
|
85
|
-
this.server.emit("listening"); // Mocking Transport.server behaviour, https://github.com/colyseus/colyseus/issues/458
|
|
86
|
-
});
|
|
87
|
-
return this;
|
|
44
|
+
if (!options.compression) {
|
|
45
|
+
options.compression = import_uWebSockets.default.DISABLED;
|
|
88
46
|
}
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
uWebSockets__default['default'].us_listen_socket_close(this._listeningSocket);
|
|
92
|
-
this.server.emit("close"); // Mocking Transport.server behaviour, https://github.com/colyseus/colyseus/issues/458
|
|
93
|
-
}
|
|
47
|
+
if (!options.maxPayloadLength) {
|
|
48
|
+
options.maxPayloadLength = 1024 * 1024;
|
|
94
49
|
}
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
uWebSocketClient.uWebSocketClient.prototype.raw = function () {
|
|
98
|
-
setTimeout(() => originalRawSend.apply(this, arguments), milliseconds);
|
|
99
|
-
};
|
|
50
|
+
if (!this.server) {
|
|
51
|
+
this.server = new import_core.DummyServer();
|
|
100
52
|
}
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
const client = new uWebSocketClient.uWebSocketClient(sessionId, wrapper);
|
|
114
|
-
//
|
|
115
|
-
// TODO: DRY code below with all transports
|
|
116
|
-
//
|
|
117
|
-
try {
|
|
118
|
-
if (!room || !room.hasReservedSeat(sessionId, searchParams.reconnectionToken)) {
|
|
119
|
-
throw new Error('seat reservation expired.');
|
|
53
|
+
this.app.ws("/*", {
|
|
54
|
+
...options,
|
|
55
|
+
upgrade: (res, req, context) => {
|
|
56
|
+
const headers = {};
|
|
57
|
+
req.forEach((key, value) => headers[key] = value);
|
|
58
|
+
res.upgrade(
|
|
59
|
+
{
|
|
60
|
+
url: req.getUrl(),
|
|
61
|
+
query: req.getQuery(),
|
|
62
|
+
headers,
|
|
63
|
+
connection: {
|
|
64
|
+
remoteAddress: Buffer.from(res.getRemoteAddressAsText()).toString()
|
|
120
65
|
}
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
66
|
+
},
|
|
67
|
+
req.getHeader("sec-websocket-key"),
|
|
68
|
+
req.getHeader("sec-websocket-protocol"),
|
|
69
|
+
req.getHeader("sec-websocket-extensions"),
|
|
70
|
+
context
|
|
71
|
+
);
|
|
72
|
+
},
|
|
73
|
+
open: async (ws) => {
|
|
74
|
+
await this.onConnection(ws);
|
|
75
|
+
},
|
|
76
|
+
close: (ws, code, message) => {
|
|
77
|
+
(0, import_core.spliceOne)(this.clients, this.clients.indexOf(ws));
|
|
78
|
+
const clientWrapper = this.clientWrappers.get(ws);
|
|
79
|
+
if (clientWrapper) {
|
|
80
|
+
this.clientWrappers.delete(ws);
|
|
81
|
+
clientWrapper.emit("close", code);
|
|
127
82
|
}
|
|
83
|
+
},
|
|
84
|
+
message: (ws, message, isBinary) => {
|
|
85
|
+
this.clientWrappers.get(ws)?.emit("message", Buffer.from(message.slice(0)));
|
|
86
|
+
}
|
|
87
|
+
});
|
|
88
|
+
this.registerMatchMakeRequest();
|
|
89
|
+
}
|
|
90
|
+
listen(port, hostname, backlog, listeningListener) {
|
|
91
|
+
this.app.listen(port, (listeningSocket) => {
|
|
92
|
+
this._listeningSocket = listeningSocket;
|
|
93
|
+
listeningListener?.();
|
|
94
|
+
this.server.emit("listening");
|
|
95
|
+
});
|
|
96
|
+
return this;
|
|
97
|
+
}
|
|
98
|
+
shutdown() {
|
|
99
|
+
if (this._listeningSocket) {
|
|
100
|
+
import_uWebSockets.default.us_listen_socket_close(this._listeningSocket);
|
|
101
|
+
this.server.emit("close");
|
|
128
102
|
}
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
res.writeStatus("204 No Content");
|
|
159
|
-
res.end();
|
|
160
|
-
}
|
|
161
|
-
});
|
|
162
|
-
this.app.post("/matchmake/*", (res, req) => {
|
|
163
|
-
res.onAborted(() => onAborted(res));
|
|
164
|
-
writeHeaders(req, res);
|
|
165
|
-
res.writeHeader('Content-Type', 'application/json');
|
|
166
|
-
const url = req.getUrl();
|
|
167
|
-
const matchedParams = url.match(allowedRoomNameChars);
|
|
168
|
-
const matchmakeIndex = matchedParams.indexOf(matchmakeRoute);
|
|
169
|
-
// read json body
|
|
170
|
-
this.readJson(res, async (clientOptions) => {
|
|
171
|
-
const method = matchedParams[matchmakeIndex + 1];
|
|
172
|
-
const roomName = matchedParams[matchmakeIndex + 2] || '';
|
|
173
|
-
try {
|
|
174
|
-
const response = await core.matchMaker.controller.invokeMethod(method, roomName, clientOptions);
|
|
175
|
-
if (!res.aborted) {
|
|
176
|
-
res.writeStatus("200 OK");
|
|
177
|
-
res.end(JSON.stringify(response));
|
|
178
|
-
}
|
|
179
|
-
}
|
|
180
|
-
catch (e) {
|
|
181
|
-
core.debugAndPrintError(e);
|
|
182
|
-
writeError(res, {
|
|
183
|
-
code: e.code || core.ErrorCode.MATCHMAKE_UNHANDLED,
|
|
184
|
-
error: e.message
|
|
185
|
-
});
|
|
186
|
-
}
|
|
187
|
-
});
|
|
188
|
-
});
|
|
189
|
-
// this.app.any("/*", (res, req) => {
|
|
190
|
-
// res.onAborted(() => onAborted(req));
|
|
191
|
-
// res.writeStatus("200 OK");
|
|
192
|
-
// });
|
|
193
|
-
this.app.get("/matchmake/*", async (res, req) => {
|
|
194
|
-
res.onAborted(() => onAborted(res));
|
|
195
|
-
writeHeaders(req, res);
|
|
196
|
-
res.writeHeader('Content-Type', 'application/json');
|
|
197
|
-
const url = req.getUrl();
|
|
198
|
-
const matchedParams = url.match(allowedRoomNameChars);
|
|
199
|
-
const roomName = matchedParams.length > 1 ? matchedParams[matchedParams.length - 1] : "";
|
|
200
|
-
try {
|
|
201
|
-
const response = await core.matchMaker.controller.getAvailableRooms(roomName || '');
|
|
202
|
-
if (!res.aborted) {
|
|
203
|
-
res.writeStatus("200 OK");
|
|
204
|
-
res.end(JSON.stringify(response));
|
|
205
|
-
}
|
|
206
|
-
}
|
|
207
|
-
catch (e) {
|
|
208
|
-
core.debugAndPrintError(e);
|
|
209
|
-
writeError(res, {
|
|
210
|
-
code: e.code || core.ErrorCode.MATCHMAKE_UNHANDLED,
|
|
211
|
-
error: e.message
|
|
212
|
-
});
|
|
213
|
-
}
|
|
214
|
-
});
|
|
103
|
+
}
|
|
104
|
+
simulateLatency(milliseconds) {
|
|
105
|
+
const originalRawSend = import_uWebSocketClient.uWebSocketClient.prototype.raw;
|
|
106
|
+
import_uWebSocketClient.uWebSocketClient.prototype.raw = function() {
|
|
107
|
+
setTimeout(() => originalRawSend.apply(this, arguments), milliseconds);
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
async onConnection(rawClient) {
|
|
111
|
+
const wrapper = new import_uWebSocketClient.uWebSocketWrapper(rawClient);
|
|
112
|
+
this.clients.push(rawClient);
|
|
113
|
+
this.clientWrappers.set(rawClient, wrapper);
|
|
114
|
+
console.log("QUERY?? =>", rawClient.query);
|
|
115
|
+
console.log("URL?? =>", rawClient.url);
|
|
116
|
+
const query = rawClient.query;
|
|
117
|
+
const url = rawClient.url;
|
|
118
|
+
const searchParams = import_querystring.default.parse(query);
|
|
119
|
+
const sessionId = searchParams.sessionId;
|
|
120
|
+
const processAndRoomId = url.match(/\/[a-zA-Z0-9_\-]+\/([a-zA-Z0-9_\-]+)$/);
|
|
121
|
+
const roomId = processAndRoomId && processAndRoomId[1];
|
|
122
|
+
const room = import_core.matchMaker.getRoomById(roomId);
|
|
123
|
+
const client = new import_uWebSocketClient.uWebSocketClient(sessionId, wrapper);
|
|
124
|
+
try {
|
|
125
|
+
if (!room || !room.hasReservedSeat(sessionId, searchParams.reconnectionToken)) {
|
|
126
|
+
throw new Error("seat reservation expired.");
|
|
127
|
+
}
|
|
128
|
+
await room._onJoin(client, rawClient);
|
|
129
|
+
} catch (e) {
|
|
130
|
+
(0, import_core.debugAndPrintError)(e);
|
|
131
|
+
client.error(e.code, e.message, () => rawClient.close());
|
|
215
132
|
}
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
133
|
+
}
|
|
134
|
+
registerMatchMakeRequest() {
|
|
135
|
+
const matchmakeRoute = "matchmake";
|
|
136
|
+
const allowedRoomNameChars = /([a-zA-Z_\-0-9]+)/gi;
|
|
137
|
+
const writeHeaders = (req, res) => {
|
|
138
|
+
if (res.aborted) {
|
|
139
|
+
return;
|
|
140
|
+
}
|
|
141
|
+
const headers = Object.assign(
|
|
142
|
+
{},
|
|
143
|
+
import_core.matchMaker.controller.DEFAULT_CORS_HEADERS,
|
|
144
|
+
import_core.matchMaker.controller.getCorsHeaders.call(void 0, req)
|
|
145
|
+
);
|
|
146
|
+
for (const header in headers) {
|
|
147
|
+
res.writeHeader(header, headers[header].toString());
|
|
148
|
+
}
|
|
149
|
+
return true;
|
|
150
|
+
};
|
|
151
|
+
const writeError = (res, error) => {
|
|
152
|
+
if (res.aborted) {
|
|
153
|
+
return;
|
|
154
|
+
}
|
|
155
|
+
res.writeStatus("406 Not Acceptable");
|
|
156
|
+
res.end(JSON.stringify(error));
|
|
157
|
+
};
|
|
158
|
+
const onAborted = (res) => {
|
|
159
|
+
res.aborted = true;
|
|
160
|
+
};
|
|
161
|
+
this.app.options("/matchmake/*", (res, req) => {
|
|
162
|
+
res.onAborted(() => onAborted(res));
|
|
163
|
+
if (writeHeaders(req, res)) {
|
|
164
|
+
res.writeStatus("204 No Content");
|
|
165
|
+
res.end();
|
|
166
|
+
}
|
|
167
|
+
});
|
|
168
|
+
this.app.post("/matchmake/*", (res, req) => {
|
|
169
|
+
res.onAborted(() => onAborted(res));
|
|
170
|
+
if (import_core.matchMaker.isGracefullyShuttingDown) {
|
|
171
|
+
return res.close();
|
|
172
|
+
}
|
|
173
|
+
writeHeaders(req, res);
|
|
174
|
+
res.writeHeader("Content-Type", "application/json");
|
|
175
|
+
const url = req.getUrl();
|
|
176
|
+
const matchedParams = url.match(allowedRoomNameChars);
|
|
177
|
+
const matchmakeIndex = matchedParams.indexOf(matchmakeRoute);
|
|
178
|
+
this.readJson(res, async (clientOptions) => {
|
|
179
|
+
try {
|
|
180
|
+
if (clientOptions === void 0) {
|
|
181
|
+
throw new Error("invalid JSON input");
|
|
182
|
+
}
|
|
183
|
+
const method = matchedParams[matchmakeIndex + 1];
|
|
184
|
+
const roomName = matchedParams[matchmakeIndex + 2] || "";
|
|
185
|
+
const response = await import_core.matchMaker.controller.invokeMethod(method, roomName, clientOptions);
|
|
186
|
+
if (!res.aborted) {
|
|
187
|
+
res.writeStatus("200 OK");
|
|
188
|
+
res.end(JSON.stringify(response));
|
|
189
|
+
}
|
|
190
|
+
} catch (e) {
|
|
191
|
+
(0, import_core.debugAndPrintError)(e);
|
|
192
|
+
writeError(res, {
|
|
193
|
+
code: e.code || import_core.ErrorCode.MATCHMAKE_UNHANDLED,
|
|
194
|
+
error: e.message
|
|
195
|
+
});
|
|
196
|
+
}
|
|
197
|
+
});
|
|
198
|
+
});
|
|
199
|
+
this.app.get("/matchmake/*", async (res, req) => {
|
|
200
|
+
res.onAborted(() => onAborted(res));
|
|
201
|
+
writeHeaders(req, res);
|
|
202
|
+
res.writeHeader("Content-Type", "application/json");
|
|
203
|
+
const url = req.getUrl();
|
|
204
|
+
const matchedParams = url.match(allowedRoomNameChars);
|
|
205
|
+
const roomName = matchedParams.length > 1 ? matchedParams[matchedParams.length - 1] : "";
|
|
206
|
+
try {
|
|
207
|
+
const response = await import_core.matchMaker.controller.getAvailableRooms(roomName || "");
|
|
208
|
+
if (!res.aborted) {
|
|
209
|
+
res.writeStatus("200 OK");
|
|
210
|
+
res.end(JSON.stringify(response));
|
|
211
|
+
}
|
|
212
|
+
} catch (e) {
|
|
213
|
+
(0, import_core.debugAndPrintError)(e);
|
|
214
|
+
writeError(res, {
|
|
215
|
+
code: e.code || import_core.ErrorCode.MATCHMAKE_UNHANDLED,
|
|
216
|
+
error: e.message
|
|
260
217
|
});
|
|
261
|
-
|
|
218
|
+
}
|
|
219
|
+
});
|
|
220
|
+
}
|
|
221
|
+
readJson(res, cb) {
|
|
222
|
+
let buffer;
|
|
223
|
+
res.onData((ab, isLast) => {
|
|
224
|
+
let chunk = Buffer.from(ab);
|
|
225
|
+
if (isLast) {
|
|
226
|
+
let json;
|
|
227
|
+
if (buffer) {
|
|
228
|
+
try {
|
|
229
|
+
json = JSON.parse(Buffer.concat([buffer, chunk]));
|
|
230
|
+
} catch (e) {
|
|
231
|
+
cb(void 0);
|
|
232
|
+
return;
|
|
233
|
+
}
|
|
234
|
+
cb(json);
|
|
235
|
+
} else {
|
|
236
|
+
try {
|
|
237
|
+
json = JSON.parse(chunk);
|
|
238
|
+
} catch (e) {
|
|
239
|
+
cb(void 0);
|
|
240
|
+
return;
|
|
241
|
+
}
|
|
242
|
+
cb(json);
|
|
243
|
+
}
|
|
244
|
+
} else {
|
|
245
|
+
if (buffer) {
|
|
246
|
+
buffer = Buffer.concat([buffer, chunk]);
|
|
247
|
+
} else {
|
|
248
|
+
buffer = Buffer.concat([chunk]);
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
});
|
|
252
|
+
}
|
|
262
253
|
}
|
|
263
|
-
|
|
264
|
-
exports
|
|
265
|
-
|
|
254
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
255
|
+
0 && (module.exports = {
|
|
256
|
+
uWebSocketsTransport
|
|
257
|
+
});
|
|
@@ -1 +1,7 @@
|
|
|
1
|
-
{"version":3,"file":"uWebSocketsTransport.js","sources":["../src/uWebSocketsTransport.ts"],"sourcesContent":["import http from 'http';\nimport querystring from 'querystring';\nimport uWebSockets from 'uWebSockets.js';\n\nimport { DummyServer, ErrorCode, matchMaker, Transport, debugAndPrintError, spliceOne } from '@colyseus/core';\nimport { uWebSocketClient, uWebSocketWrapper } from './uWebSocketClient';\n\nexport type TransportOptions = Omit<uWebSockets.WebSocketBehavior, \"upgrade\" | \"open\" | \"pong\" | \"close\" | \"message\">;\n\ntype RawWebSocketClient = uWebSockets.WebSocket & {\n headers: {[key: string]: string},\n connection: { remoteAddress: string },\n};\n\nexport class uWebSocketsTransport extends Transport {\n public app: uWebSockets.TemplatedApp;\n\n protected clients: RawWebSocketClient[] = [];\n protected clientWrappers = new WeakMap<RawWebSocketClient, uWebSocketWrapper>();\n\n private _listeningSocket: any;\n\n constructor(options: TransportOptions = {}, appOptions: uWebSockets.AppOptions = {}) {\n super();\n\n this.app = (appOptions.cert_file_name && appOptions.key_file_name)\n ? uWebSockets.SSLApp(appOptions)\n : uWebSockets.App(appOptions);\n\n if (!options.maxBackpressure) {\n options.maxBackpressure = 1024 * 1024;\n }\n\n if (!options.compression) {\n options.compression = uWebSockets.DISABLED;\n }\n\n if (!options.maxPayloadLength) {\n options.maxPayloadLength = 1024 * 1024;\n }\n\n // https://github.com/colyseus/colyseus/issues/458\n // Adding a mock object for Transport.server\n if(!this.server) {\n this.server = new DummyServer();\n }\n\n this.app.ws('/*', {\n ...options,\n\n upgrade: (res, req, context) => {\n // get all headers\n const headers: {[id: string]: string} = {};\n req.forEach((key, value) => headers[key] = value);\n\n /* This immediately calls open handler, you must not use res after this call */\n /* Spell these correctly */\n res.upgrade(\n {\n url: req.getUrl(),\n query: req.getQuery(),\n\n // compatibility with @colyseus/ws-transport\n headers,\n connection: {\n remoteAddress: Buffer.from(res.getRemoteAddressAsText()).toString()\n }\n },\n req.getHeader('sec-websocket-key'),\n req.getHeader('sec-websocket-protocol'),\n req.getHeader('sec-websocket-extensions'),\n context\n );\n },\n\n open: async (ws: RawWebSocketClient) => {\n // ws.pingCount = 0;\n await this.onConnection(ws);\n },\n\n // pong: (ws: RawWebSocketClient) => {\n // ws.pingCount = 0;\n // },\n\n close: (ws: RawWebSocketClient, code: number, message: ArrayBuffer) => {\n // remove from client list\n spliceOne(this.clients, this.clients.indexOf(ws));\n\n const clientWrapper = this.clientWrappers.get(ws);\n if (clientWrapper) {\n this.clientWrappers.delete(ws);\n\n // emit 'close' on wrapper\n clientWrapper.emit('close', code);\n }\n },\n\n message: (ws: RawWebSocketClient, message: ArrayBuffer, isBinary: boolean) => {\n // emit 'close' on wrapper\n this.clientWrappers.get(ws)?.emit('message', Buffer.from(message.slice(0)));\n },\n\n });\n\n this.registerMatchMakeRequest();\n }\n\n public listen(port: number, hostname?: string, backlog?: number, listeningListener?: () => void) {\n this.app.listen(port, (listeningSocket: any) => {\n this._listeningSocket = listeningSocket;\n listeningListener?.();\n this.server.emit(\"listening\"); // Mocking Transport.server behaviour, https://github.com/colyseus/colyseus/issues/458\n });\n return this;\n }\n\n public shutdown() {\n if (this._listeningSocket) {\n uWebSockets.us_listen_socket_close(this._listeningSocket);\n this.server.emit(\"close\"); // Mocking Transport.server behaviour, https://github.com/colyseus/colyseus/issues/458\n }\n }\n\n public simulateLatency(milliseconds: number) {\n const originalRawSend = uWebSocketClient.prototype.raw;\n uWebSocketClient.prototype.raw = function() {\n setTimeout(() => originalRawSend.apply(this, arguments), milliseconds);\n }\n }\n\n protected async onConnection(rawClient: RawWebSocketClient) {\n const wrapper = new uWebSocketWrapper(rawClient);\n // keep reference to client and its wrapper\n this.clients.push(rawClient);\n this.clientWrappers.set(rawClient, wrapper);\n\n const query = rawClient.query;\n const url = rawClient.url;\n const searchParams = querystring.parse(query);\n\n const sessionId = searchParams.sessionId as string;\n const processAndRoomId = url.match(/\\/[a-zA-Z0-9_\\-]+\\/([a-zA-Z0-9_\\-]+)$/);\n const roomId = processAndRoomId && processAndRoomId[1];\n\n const room = matchMaker.getRoomById(roomId);\n const client = new uWebSocketClient(sessionId, wrapper);\n\n //\n // TODO: DRY code below with all transports\n //\n\n try {\n if (!room || !room.hasReservedSeat(sessionId, searchParams.reconnectionToken as string)) {\n throw new Error('seat reservation expired.');\n }\n\n await room._onJoin(client, rawClient as unknown as http.IncomingMessage);\n\n } catch (e) {\n debugAndPrintError(e);\n\n // send error code to client then terminate\n client.error(e.code, e.message, () => rawClient.close());\n }\n }\n\n protected registerMatchMakeRequest() {\n\n // TODO: DRY with Server.ts\n const matchmakeRoute = 'matchmake';\n const allowedRoomNameChars = /([a-zA-Z_\\-0-9]+)/gi;\n\n const writeHeaders = (req: uWebSockets.HttpRequest, res: uWebSockets.HttpResponse) => {\n // skip if aborted\n if (res.aborted) { return; }\n\n const headers = Object.assign(\n {},\n matchMaker.controller.DEFAULT_CORS_HEADERS,\n matchMaker.controller.getCorsHeaders.call(undefined, req)\n );\n\n for (const header in headers) {\n res.writeHeader(header, headers[header].toString());\n }\n\n return true;\n }\n\n const writeError = (res: uWebSockets.HttpResponse, error: { code: number, error: string }) => {\n // skip if aborted\n if (res.aborted) { return; }\n\n res.writeStatus(\"406 Not Acceptable\");\n res.end(JSON.stringify(error));\n }\n\n const onAborted = (res: uWebSockets.HttpResponse) => {\n res.aborted = true;\n };\n\n this.app.options(\"/matchmake/*\", (res, req) => {\n res.onAborted(() => onAborted(res));\n\n if (writeHeaders(req, res)) {\n res.writeStatus(\"204 No Content\");\n res.end();\n }\n });\n\n this.app.post(\"/matchmake/*\", (res, req) => {\n res.onAborted(() => onAborted(res));\n\n writeHeaders(req, res);\n res.writeHeader('Content-Type', 'application/json');\n\n const url = req.getUrl();\n const matchedParams = url.match(allowedRoomNameChars);\n const matchmakeIndex = matchedParams.indexOf(matchmakeRoute);\n\n // read json body\n this.readJson(res, async (clientOptions) => {\n const method = matchedParams[matchmakeIndex + 1];\n const roomName = matchedParams[matchmakeIndex + 2] || '';\n\n try {\n const response = await matchMaker.controller.invokeMethod(method, roomName, clientOptions);\n if (!res.aborted) {\n res.writeStatus(\"200 OK\");\n res.end(JSON.stringify(response));\n }\n\n } catch (e) {\n debugAndPrintError(e);\n writeError(res, {\n code: e.code || ErrorCode.MATCHMAKE_UNHANDLED,\n error: e.message\n });\n }\n\n });\n });\n\n // this.app.any(\"/*\", (res, req) => {\n // res.onAborted(() => onAborted(req));\n // res.writeStatus(\"200 OK\");\n // });\n\n this.app.get(\"/matchmake/*\", async (res, req) => {\n res.onAborted(() => onAborted(res));\n\n writeHeaders(req, res);\n res.writeHeader('Content-Type', 'application/json');\n\n const url = req.getUrl();\n const matchedParams = url.match(allowedRoomNameChars);\n const roomName = matchedParams.length > 1 ? matchedParams[matchedParams.length - 1] : \"\";\n\n try {\n const response = await matchMaker.controller.getAvailableRooms(roomName || '')\n if (!res.aborted) {\n res.writeStatus(\"200 OK\");\n res.end(JSON.stringify(response));\n }\n\n } catch (e) {\n debugAndPrintError(e);\n writeError(res, {\n code: e.code || ErrorCode.MATCHMAKE_UNHANDLED,\n error: e.message\n });\n }\n });\n }\n\n /* Helper function for reading a posted JSON body */\n /* Extracted from https://github.com/uNetworking/uWebSockets.js/blob/master/examples/JsonPost.js */\n private readJson(res: uWebSockets.HttpResponse, cb: (json: any) => void) {\n let buffer: any;\n /* Register data cb */\n res.onData((ab, isLast) => {\n let chunk = Buffer.from(ab);\n if (isLast) {\n let json;\n if (buffer) {\n try {\n // @ts-ignore\n json = JSON.parse(Buffer.concat([buffer, chunk]));\n } catch (e) {\n /* res.close calls onAborted */\n res.close();\n cb(undefined);\n return;\n }\n cb(json);\n } else {\n try {\n // @ts-ignore\n json = JSON.parse(chunk);\n } catch (e) {\n /* res.close calls onAborted */\n res.close();\n cb(undefined);\n return;\n }\n cb(json);\n }\n } else {\n if (buffer) {\n buffer = Buffer.concat([buffer, chunk]);\n } else {\n buffer = Buffer.concat([chunk]);\n }\n }\n });\n }\n}\n"],"names":["Transport","uWebSockets","DummyServer","spliceOne","uWebSocketClient","uWebSocketWrapper","querystring","matchMaker","debugAndPrintError","ErrorCode"],"mappings":"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"}
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../src/uWebSocketsTransport.ts"],
|
|
4
|
+
"sourcesContent": ["import http from 'http';\nimport querystring from 'querystring';\nimport uWebSockets from 'uWebSockets.js';\n\nimport { DummyServer, ErrorCode, matchMaker, Transport, debugAndPrintError, spliceOne } from '@colyseus/core';\nimport { uWebSocketClient, uWebSocketWrapper } from './uWebSocketClient';\n\nexport type TransportOptions = Omit<uWebSockets.WebSocketBehavior<any>, \"upgrade\" | \"open\" | \"pong\" | \"close\" | \"message\">;\n\ntype RawWebSocketClient = uWebSockets.WebSocket<any> & {\n headers: {[key: string]: string},\n connection: { remoteAddress: string },\n};\n\nexport class uWebSocketsTransport extends Transport {\n public app: uWebSockets.TemplatedApp;\n\n protected clients: RawWebSocketClient[] = [];\n protected clientWrappers = new WeakMap<RawWebSocketClient, uWebSocketWrapper>();\n\n private _listeningSocket: any;\n\n constructor(options: TransportOptions = {}, appOptions: uWebSockets.AppOptions = {}) {\n super();\n\n this.app = (appOptions.cert_file_name && appOptions.key_file_name)\n ? uWebSockets.SSLApp(appOptions)\n : uWebSockets.App(appOptions);\n\n if (!options.maxBackpressure) {\n options.maxBackpressure = 1024 * 1024;\n }\n\n if (!options.compression) {\n options.compression = uWebSockets.DISABLED;\n }\n\n if (!options.maxPayloadLength) {\n options.maxPayloadLength = 1024 * 1024;\n }\n\n // https://github.com/colyseus/colyseus/issues/458\n // Adding a mock object for Transport.server\n if(!this.server) {\n this.server = new DummyServer();\n }\n\n this.app.ws('/*', {\n ...options,\n\n upgrade: (res, req, context) => {\n // get all headers\n const headers: {[id: string]: string} = {};\n req.forEach((key, value) => headers[key] = value);\n\n /* This immediately calls open handler, you must not use res after this call */\n /* Spell these correctly */\n res.upgrade(\n {\n url: req.getUrl(),\n query: req.getQuery(),\n\n // compatibility with @colyseus/ws-transport\n headers,\n connection: {\n remoteAddress: Buffer.from(res.getRemoteAddressAsText()).toString()\n }\n },\n req.getHeader('sec-websocket-key'),\n req.getHeader('sec-websocket-protocol'),\n req.getHeader('sec-websocket-extensions'),\n context\n );\n },\n\n open: async (ws: RawWebSocketClient) => {\n // ws.pingCount = 0;\n await this.onConnection(ws);\n },\n\n // pong: (ws: RawWebSocketClient) => {\n // ws.pingCount = 0;\n // },\n\n close: (ws: RawWebSocketClient, code: number, message: ArrayBuffer) => {\n // remove from client list\n spliceOne(this.clients, this.clients.indexOf(ws));\n\n const clientWrapper = this.clientWrappers.get(ws);\n if (clientWrapper) {\n this.clientWrappers.delete(ws);\n\n // emit 'close' on wrapper\n clientWrapper.emit('close', code);\n }\n },\n\n message: (ws: RawWebSocketClient, message: ArrayBuffer, isBinary: boolean) => {\n // emit 'close' on wrapper\n this.clientWrappers.get(ws)?.emit('message', Buffer.from(message.slice(0)));\n },\n\n });\n\n this.registerMatchMakeRequest();\n }\n\n public listen(port: number, hostname?: string, backlog?: number, listeningListener?: () => void) {\n this.app.listen(port, (listeningSocket: any) => {\n this._listeningSocket = listeningSocket;\n listeningListener?.();\n this.server.emit(\"listening\"); // Mocking Transport.server behaviour, https://github.com/colyseus/colyseus/issues/458\n });\n return this;\n }\n\n public shutdown() {\n if (this._listeningSocket) {\n uWebSockets.us_listen_socket_close(this._listeningSocket);\n this.server.emit(\"close\"); // Mocking Transport.server behaviour, https://github.com/colyseus/colyseus/issues/458\n }\n }\n\n public simulateLatency(milliseconds: number) {\n const originalRawSend = uWebSocketClient.prototype.raw;\n uWebSocketClient.prototype.raw = function() {\n setTimeout(() => originalRawSend.apply(this, arguments), milliseconds);\n }\n }\n\n protected async onConnection(rawClient: RawWebSocketClient) {\n const wrapper = new uWebSocketWrapper(rawClient);\n // keep reference to client and its wrapper\n this.clients.push(rawClient);\n this.clientWrappers.set(rawClient, wrapper);\n\n // @ts-ignore\n console.log(\"QUERY?? =>\", rawClient.query);\n // @ts-ignore\n console.log(\"URL?? =>\", rawClient.url);\n\n // @ts-ignore\n const query = rawClient.query;\n // @ts-ignore\n const url = rawClient.url;\n const searchParams = querystring.parse(query);\n\n const sessionId = searchParams.sessionId as string;\n const processAndRoomId = url.match(/\\/[a-zA-Z0-9_\\-]+\\/([a-zA-Z0-9_\\-]+)$/);\n const roomId = processAndRoomId && processAndRoomId[1];\n\n const room = matchMaker.getRoomById(roomId);\n const client = new uWebSocketClient(sessionId, wrapper);\n\n //\n // TODO: DRY code below with all transports\n //\n\n try {\n if (!room || !room.hasReservedSeat(sessionId, searchParams.reconnectionToken as string)) {\n throw new Error('seat reservation expired.');\n }\n\n await room._onJoin(client, rawClient as unknown as http.IncomingMessage);\n\n } catch (e) {\n debugAndPrintError(e);\n\n // send error code to client then terminate\n client.error(e.code, e.message, () => rawClient.close());\n }\n }\n\n protected registerMatchMakeRequest() {\n\n // TODO: DRY with Server.ts\n const matchmakeRoute = 'matchmake';\n const allowedRoomNameChars = /([a-zA-Z_\\-0-9]+)/gi;\n\n const writeHeaders = (req: uWebSockets.HttpRequest, res: uWebSockets.HttpResponse) => {\n // skip if aborted\n if (res.aborted) { return; }\n\n const headers = Object.assign(\n {},\n matchMaker.controller.DEFAULT_CORS_HEADERS,\n matchMaker.controller.getCorsHeaders.call(undefined, req)\n );\n\n for (const header in headers) {\n res.writeHeader(header, headers[header].toString());\n }\n\n return true;\n }\n\n const writeError = (res: uWebSockets.HttpResponse, error: { code: number, error: string }) => {\n // skip if aborted\n if (res.aborted) { return; }\n\n res.writeStatus(\"406 Not Acceptable\");\n res.end(JSON.stringify(error));\n }\n\n const onAborted = (res: uWebSockets.HttpResponse) => {\n res.aborted = true;\n };\n\n this.app.options(\"/matchmake/*\", (res, req) => {\n res.onAborted(() => onAborted(res));\n\n if (writeHeaders(req, res)) {\n res.writeStatus(\"204 No Content\");\n res.end();\n }\n });\n\n\n // @ts-ignore\n this.app.post(\"/matchmake/*\", (res, req) => {\n res.onAborted(() => onAborted(res));\n\n // do not accept matchmaking requests if already shutting down\n if (matchMaker.isGracefullyShuttingDown) {\n return res.close();\n }\n\n writeHeaders(req, res);\n res.writeHeader('Content-Type', 'application/json');\n\n const url = req.getUrl();\n const matchedParams = url.match(allowedRoomNameChars);\n const matchmakeIndex = matchedParams.indexOf(matchmakeRoute);\n\n // read json body\n this.readJson(res, async (clientOptions) => {\n try {\n if (clientOptions === undefined) {\n throw new Error(\"invalid JSON input\");\n }\n\n const method = matchedParams[matchmakeIndex + 1];\n const roomName = matchedParams[matchmakeIndex + 2] || '';\n\n const response = await matchMaker.controller.invokeMethod(method, roomName, clientOptions);\n if (!res.aborted) {\n res.writeStatus(\"200 OK\");\n res.end(JSON.stringify(response));\n }\n\n } catch (e) {\n debugAndPrintError(e);\n writeError(res, {\n code: e.code || ErrorCode.MATCHMAKE_UNHANDLED,\n error: e.message\n });\n }\n\n });\n });\n\n // this.app.any(\"/*\", (res, req) => {\n // res.onAborted(() => onAborted(req));\n // res.writeStatus(\"200 OK\");\n // });\n\n this.app.get(\"/matchmake/*\", async (res, req) => {\n res.onAborted(() => onAborted(res));\n\n writeHeaders(req, res);\n res.writeHeader('Content-Type', 'application/json');\n\n const url = req.getUrl();\n const matchedParams = url.match(allowedRoomNameChars);\n const roomName = matchedParams.length > 1 ? matchedParams[matchedParams.length - 1] : \"\";\n\n try {\n const response = await matchMaker.controller.getAvailableRooms(roomName || '')\n if (!res.aborted) {\n res.writeStatus(\"200 OK\");\n res.end(JSON.stringify(response));\n }\n\n } catch (e) {\n debugAndPrintError(e);\n writeError(res, {\n code: e.code || ErrorCode.MATCHMAKE_UNHANDLED,\n error: e.message\n });\n }\n });\n }\n\n /* Helper function for reading a posted JSON body */\n /* Extracted from https://github.com/uNetworking/uWebSockets.js/blob/master/examples/JsonPost.js */\n private readJson(res: uWebSockets.HttpResponse, cb: (json: any) => void) {\n let buffer: any;\n /* Register data cb */\n res.onData((ab, isLast) => {\n let chunk = Buffer.from(ab);\n if (isLast) {\n let json;\n if (buffer) {\n try {\n // @ts-ignore\n json = JSON.parse(Buffer.concat([buffer, chunk]));\n } catch (e) {\n /* res.close calls onAborted */\n // res.close();\n cb(undefined);\n return;\n }\n cb(json);\n } else {\n try {\n // @ts-ignore\n json = JSON.parse(chunk);\n } catch (e) {\n /* res.close calls onAborted */\n // res.close();\n cb(undefined);\n return;\n }\n cb(json);\n }\n } else {\n if (buffer) {\n buffer = Buffer.concat([buffer, chunk]);\n } else {\n buffer = Buffer.concat([chunk]);\n }\n }\n });\n }\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": ["uWebSockets", "querystring"]
|
|
7
|
+
}
|