@colyseus/uwebsockets-transport 0.17.7 → 0.17.8
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/build/uWebSocketsTransport.cjs +196 -90
- package/build/uWebSocketsTransport.cjs.map +3 -3
- package/build/uWebSocketsTransport.d.ts +5 -2
- package/build/uWebSocketsTransport.mjs +197 -91
- package/build/uWebSocketsTransport.mjs.map +2 -2
- package/package.json +9 -3
- package/src/uWebSocketsTransport.ts +421 -298
|
@@ -37,6 +37,10 @@ var import_querystring = __toESM(require("querystring"), 1);
|
|
|
37
37
|
var import_uWebSockets = __toESM(require("uWebSockets.js"), 1);
|
|
38
38
|
var import_core = require("@colyseus/core");
|
|
39
39
|
var import_uWebSocketClient = require("./uWebSocketClient.cjs");
|
|
40
|
+
var import_core2 = require("@colyseus/core");
|
|
41
|
+
var uWebSocketsExpress = new import_core2.Deferred();
|
|
42
|
+
var uWebSocketsExpressModule = void 0;
|
|
43
|
+
import("uwebsockets-express").then((module2) => uWebSocketsExpress.resolve(module2)).catch((error) => uWebSocketsExpress.reject(error));
|
|
40
44
|
var uWebSocketsTransport = class extends import_core.Transport {
|
|
41
45
|
constructor(options = {}, appOptions = {}) {
|
|
42
46
|
super();
|
|
@@ -56,9 +60,6 @@ var uWebSocketsTransport = class extends import_core.Transport {
|
|
|
56
60
|
if (options.sendPingsAutomatically === void 0) {
|
|
57
61
|
options.sendPingsAutomatically = true;
|
|
58
62
|
}
|
|
59
|
-
if (!this.server) {
|
|
60
|
-
this.server = new import_core.HttpServerMock();
|
|
61
|
-
}
|
|
62
63
|
this.app.ws("/*", {
|
|
63
64
|
...options,
|
|
64
65
|
upgrade: (res, req, context) => {
|
|
@@ -99,13 +100,116 @@ var uWebSocketsTransport = class extends import_core.Transport {
|
|
|
99
100
|
this.clientWrappers.get(ws)?.emit("message", Buffer.from(message));
|
|
100
101
|
}
|
|
101
102
|
});
|
|
102
|
-
|
|
103
|
+
}
|
|
104
|
+
getExpressApp() {
|
|
105
|
+
if (!this._expressApp) {
|
|
106
|
+
return new Promise(async (resolve, reject) => {
|
|
107
|
+
try {
|
|
108
|
+
const module2 = await uWebSocketsExpress;
|
|
109
|
+
uWebSocketsExpressModule = module2;
|
|
110
|
+
this._expressApp = module2.default(this.app);
|
|
111
|
+
resolve(this._expressApp);
|
|
112
|
+
} catch (error) {
|
|
113
|
+
console.warn("");
|
|
114
|
+
console.warn("\u274C could not initialize express");
|
|
115
|
+
console.warn("\u{1F449} npm install --save uwebsockets-express");
|
|
116
|
+
console.warn("");
|
|
117
|
+
reject(error);
|
|
118
|
+
}
|
|
119
|
+
});
|
|
120
|
+
}
|
|
121
|
+
return this._expressApp;
|
|
122
|
+
}
|
|
123
|
+
bindRouter(router) {
|
|
124
|
+
const writeHeaders = (res, requestHeaders) => {
|
|
125
|
+
if (res.aborted) {
|
|
126
|
+
return;
|
|
127
|
+
}
|
|
128
|
+
const headers = Object.assign(
|
|
129
|
+
{},
|
|
130
|
+
import_core.matchMaker.controller.DEFAULT_CORS_HEADERS,
|
|
131
|
+
import_core.matchMaker.controller.getCorsHeaders(requestHeaders)
|
|
132
|
+
);
|
|
133
|
+
for (const header in headers) {
|
|
134
|
+
res.writeHeader(header, headers[header].toString());
|
|
135
|
+
}
|
|
136
|
+
return true;
|
|
137
|
+
};
|
|
138
|
+
this.app.options("/*", (res, req) => {
|
|
139
|
+
res.onAborted(() => res.aborted = true);
|
|
140
|
+
const reqHeaders = new Headers();
|
|
141
|
+
req.forEach((key, value) => reqHeaders.set(key, value));
|
|
142
|
+
if (writeHeaders(res, reqHeaders)) {
|
|
143
|
+
res.writeStatus("204 No Content");
|
|
144
|
+
res.end();
|
|
145
|
+
}
|
|
146
|
+
});
|
|
147
|
+
this.app.any("/*", async (res, req) => {
|
|
148
|
+
const abortController = new AbortController();
|
|
149
|
+
res.onAborted(() => {
|
|
150
|
+
abortController.abort();
|
|
151
|
+
res.aborted = true;
|
|
152
|
+
});
|
|
153
|
+
const headers = new Headers();
|
|
154
|
+
req.forEach((key, value) => headers.set(key, value));
|
|
155
|
+
const requestInit = {
|
|
156
|
+
method: req.getMethod().toUpperCase(),
|
|
157
|
+
referrer: req.getHeader("referer"),
|
|
158
|
+
keepalive: req.getHeader("keep-alive") === "true",
|
|
159
|
+
headers,
|
|
160
|
+
signal: abortController.signal
|
|
161
|
+
};
|
|
162
|
+
const url = req.getUrl();
|
|
163
|
+
const query = req.getQuery();
|
|
164
|
+
const remoteAddress = res.getRemoteAddressAsText();
|
|
165
|
+
if (requestInit.method.toUpperCase() !== "GET" && requestInit.method.toUpperCase() !== "HEAD") {
|
|
166
|
+
let body = void 0;
|
|
167
|
+
await new Promise((resolve) => {
|
|
168
|
+
res.onData((ab, isLast) => {
|
|
169
|
+
const chunk = Buffer.from(ab);
|
|
170
|
+
if (body === void 0) {
|
|
171
|
+
body = Buffer.from(chunk);
|
|
172
|
+
} else {
|
|
173
|
+
body = Buffer.concat([body, chunk]);
|
|
174
|
+
}
|
|
175
|
+
if (isLast) {
|
|
176
|
+
resolve();
|
|
177
|
+
}
|
|
178
|
+
});
|
|
179
|
+
});
|
|
180
|
+
requestInit.body = body.buffer.slice(body.byteOffset, body.byteOffset + body.byteLength);
|
|
181
|
+
}
|
|
182
|
+
const fullUrl = `http://${headers.get("host") || "localhost"}${url}${query ? `?${query}` : ""}`;
|
|
183
|
+
const response = await router.handler(new Request(fullUrl, requestInit));
|
|
184
|
+
if (response.status === 404 && this._expressApp) {
|
|
185
|
+
const ereq = new uWebSocketsExpressModule.IncomingMessage(req, res, this._expressApp, {
|
|
186
|
+
headers: Object.fromEntries(headers.entries()),
|
|
187
|
+
method: requestInit.method,
|
|
188
|
+
url,
|
|
189
|
+
query,
|
|
190
|
+
remoteAddress
|
|
191
|
+
});
|
|
192
|
+
const eres = new uWebSocketsExpressModule.ServerResponse(res, req, this._expressApp);
|
|
193
|
+
this._expressApp["handle"](ereq, eres);
|
|
194
|
+
return;
|
|
195
|
+
}
|
|
196
|
+
if (res.aborted) {
|
|
197
|
+
return;
|
|
198
|
+
}
|
|
199
|
+
const responseBody = await response.arrayBuffer();
|
|
200
|
+
res.cork(() => {
|
|
201
|
+
res.writeStatus(`${response.status} ${response.statusText}`);
|
|
202
|
+
response.headers.forEach((value, key) => {
|
|
203
|
+
res.writeHeader(key, value);
|
|
204
|
+
});
|
|
205
|
+
res.end(responseBody);
|
|
206
|
+
});
|
|
207
|
+
});
|
|
103
208
|
}
|
|
104
209
|
listen(port, hostname, backlog, listeningListener) {
|
|
105
210
|
const callback = (listeningSocket) => {
|
|
106
211
|
this._listeningSocket = listeningSocket;
|
|
107
212
|
listeningListener?.();
|
|
108
|
-
this.server.emit("listening");
|
|
109
213
|
};
|
|
110
214
|
if (typeof port === "string") {
|
|
111
215
|
this.app.listen_unix(callback, port);
|
|
@@ -117,7 +221,6 @@ var uWebSocketsTransport = class extends import_core.Transport {
|
|
|
117
221
|
shutdown() {
|
|
118
222
|
if (this._listeningSocket) {
|
|
119
223
|
import_uWebSockets.default.us_listen_socket_close(this._listeningSocket);
|
|
120
|
-
this.server.emit("close");
|
|
121
224
|
}
|
|
122
225
|
}
|
|
123
226
|
simulateLatency(milliseconds) {
|
|
@@ -160,90 +263,93 @@ var uWebSocketsTransport = class extends import_core.Transport {
|
|
|
160
263
|
client.error(e.code, e.message, () => client.leave());
|
|
161
264
|
}
|
|
162
265
|
}
|
|
163
|
-
registerMatchMakeRequest() {
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
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
|
-
}
|
|
266
|
+
// protected registerMatchMakeRequest() {
|
|
267
|
+
// const matchmakeRoute = 'matchmake';
|
|
268
|
+
// const allowedRoomNameChars = /([a-zA-Z_\-0-9]+)/gi;
|
|
269
|
+
// const writeHeaders = (res: uWebSockets.HttpResponse, requestHeaders: Headers) => {
|
|
270
|
+
// // skip if aborted
|
|
271
|
+
// if (res.aborted) { return; }
|
|
272
|
+
// const headers = Object.assign(
|
|
273
|
+
// {},
|
|
274
|
+
// matchMaker.controller.DEFAULT_CORS_HEADERS,
|
|
275
|
+
// matchMaker.controller.getCorsHeaders(requestHeaders)
|
|
276
|
+
// );
|
|
277
|
+
// for (const header in headers) {
|
|
278
|
+
// res.writeHeader(header, headers[header].toString());
|
|
279
|
+
// }
|
|
280
|
+
// return true;
|
|
281
|
+
// }
|
|
282
|
+
// const writeError = (res: uWebSockets.HttpResponse, error: { code: number, error: string }) => {
|
|
283
|
+
// // skip if aborted
|
|
284
|
+
// if (res.aborted) { return; }
|
|
285
|
+
// res.cork(() => {
|
|
286
|
+
// res.writeStatus("406 Not Acceptable");
|
|
287
|
+
// res.end(JSON.stringify(error));
|
|
288
|
+
// });
|
|
289
|
+
// }
|
|
290
|
+
// const onAborted = (res: uWebSockets.HttpResponse) => {
|
|
291
|
+
// res.aborted = true;
|
|
292
|
+
// };
|
|
293
|
+
// this.app.options("/matchmake/*", (res, req) => {
|
|
294
|
+
// res.onAborted(() => onAborted(res));
|
|
295
|
+
// // cache all headers
|
|
296
|
+
// const reqHeaders = new Headers();
|
|
297
|
+
// req.forEach((key, value) => reqHeaders.set(key, value));
|
|
298
|
+
// if (writeHeaders(res, reqHeaders)) {
|
|
299
|
+
// res.writeStatus("204 No Content");
|
|
300
|
+
// res.end();
|
|
301
|
+
// }
|
|
302
|
+
// });
|
|
303
|
+
// // @ts-ignore
|
|
304
|
+
// this.app.post("/matchmake/*", (res, req) => {
|
|
305
|
+
// res.onAborted(() => onAborted(res));
|
|
306
|
+
// // do not accept matchmaking requests if already shutting down
|
|
307
|
+
// if (matchMaker.state === matchMaker.MatchMakerState.SHUTTING_DOWN) {
|
|
308
|
+
// return res.close();
|
|
309
|
+
// }
|
|
310
|
+
// // cache all headers
|
|
311
|
+
// const headers = new Headers();
|
|
312
|
+
// req.forEach((key, value) => headers.set(key, value));
|
|
313
|
+
// writeHeaders(res, headers);
|
|
314
|
+
// res.writeHeader('Content-Type', 'application/json');
|
|
315
|
+
// const url = req.getUrl();
|
|
316
|
+
// const matchedParams = url.match(allowedRoomNameChars);
|
|
317
|
+
// const matchmakeIndex = matchedParams.indexOf(matchmakeRoute);
|
|
318
|
+
// const token = getBearerToken(headers['authorization']);
|
|
319
|
+
// // read json body
|
|
320
|
+
// this.readJson(res, async (clientOptions) => {
|
|
321
|
+
// try {
|
|
322
|
+
// if (clientOptions === undefined) {
|
|
323
|
+
// throw new Error("invalid JSON input");
|
|
324
|
+
// }
|
|
325
|
+
// const method = matchedParams[matchmakeIndex + 1];
|
|
326
|
+
// const roomName = matchedParams[matchmakeIndex + 2] || '';
|
|
327
|
+
// const response = await matchMaker.controller.invokeMethod(
|
|
328
|
+
// method,
|
|
329
|
+
// roomName,
|
|
330
|
+
// clientOptions,
|
|
331
|
+
// {
|
|
332
|
+
// token,
|
|
333
|
+
// headers,
|
|
334
|
+
// ip: headers.get('x-real-ip') ?? headers.get('x-forwarded-for') ?? Buffer.from(res.getRemoteAddressAsText()).toString()
|
|
335
|
+
// }
|
|
336
|
+
// );
|
|
337
|
+
// if (!res.aborted) {
|
|
338
|
+
// res.cork(() => {
|
|
339
|
+
// res.writeStatus("200 OK");
|
|
340
|
+
// res.end(JSON.stringify(response));
|
|
341
|
+
// });
|
|
342
|
+
// }
|
|
343
|
+
// } catch (e: any) {
|
|
344
|
+
// debugAndPrintError(e);
|
|
345
|
+
// writeError(res, {
|
|
346
|
+
// code: e.code || ErrorCode.MATCHMAKE_UNHANDLED,
|
|
347
|
+
// error: e.message
|
|
348
|
+
// });
|
|
349
|
+
// }
|
|
350
|
+
// });
|
|
351
|
+
// });
|
|
352
|
+
// }
|
|
247
353
|
/* Helper function for reading a posted JSON body */
|
|
248
354
|
/* Extracted from https://github.com/uNetworking/uWebSockets.js/blob/master/examples/JsonPost.js */
|
|
249
355
|
readJson(res, cb) {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../src/uWebSocketsTransport.ts"],
|
|
4
|
-
"sourcesContent": ["import querystring, { type ParsedUrlQuery } from 'querystring';\nimport uWebSockets, { type WebSocket } from 'uWebSockets.js';\n\nimport { type AuthContext, Transport, HttpServerMock, ErrorCode, matchMaker, Protocol, getBearerToken, debugAndPrintError, spliceOne, connectClientToRoom } from '@colyseus/core';\nimport { uWebSocketClient, uWebSocketWrapper } from './uWebSocketClient.ts';\n\nexport type TransportOptions = Omit<uWebSockets.WebSocketBehavior<any>, \"upgrade\" | \"open\" | \"pong\" | \"close\" | \"message\">;\n\ntype RawWebSocketClient = uWebSockets.WebSocket<any> & {\n url: string,\n searchParams: ParsedUrlQuery,\n context: AuthContext,\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 private _originalRawSend: typeof uWebSocketClient.prototype.raw | null = null;\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 === undefined) {\n options.maxBackpressure = 1024 * 1024;\n }\n\n if (options.compression === undefined) {\n options.compression = uWebSockets.DISABLED;\n }\n\n if (options.maxPayloadLength === undefined) {\n options.maxPayloadLength = 4 * 1024;\n }\n\n if (options.sendPingsAutomatically === undefined) {\n options.sendPingsAutomatically = true;\n }\n\n // https://github.com/colyseus/colyseus/issues/458\n // Adding a mock object for Transport.server\n if(!this.server) {\n // @ts-ignore\n this.server = new HttpServerMock();\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 const searchParams = querystring.parse(req.getQuery());\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 searchParams,\n context: {\n token: searchParams._authToken ?? getBearerToken(req.getHeader('authorization')),\n headers,\n ip: headers['x-real-ip'] ?? headers['x-forwarded-for'] ?? 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: WebSocket<any>) => {\n // ws.pingCount = 0;\n await this.onConnection(ws as RawWebSocketClient);\n },\n\n // pong: (ws: RawWebSocketClient) => {\n // ws.pingCount = 0;\n // },\n\n close: (ws: WebSocket<any>, code: number, message: ArrayBuffer) => {\n // remove from client list\n spliceOne(this.clients, this.clients.indexOf(ws as RawWebSocketClient));\n\n const clientWrapper = this.clientWrappers.get(ws as RawWebSocketClient);\n if (clientWrapper) {\n this.clientWrappers.delete(ws as RawWebSocketClient);\n\n // emit 'close' on wrapper\n clientWrapper.emit('close', code);\n }\n },\n\n message: (ws: WebSocket<any>, message: ArrayBuffer, isBinary: boolean) => {\n // emit 'message' on wrapper\n this.clientWrappers.get(ws as RawWebSocketClient)?.emit('message', Buffer.from(message));\n },\n\n });\n\n this.registerMatchMakeRequest();\n }\n\n public listen(port: number, hostname?: string, backlog?: number, listeningListener?: () => void) {\n const callback = (listeningSocket: any) => {\n this._listeningSocket = listeningSocket;\n listeningListener?.();\n // @ts-ignore\n this.server.emit(\"listening\"); // Mocking Transport.server behaviour, https://github.com/colyseus/colyseus/issues/458\n };\n\n if (typeof(port) === \"string\") {\n // @ts-ignore\n this.app.listen_unix(callback, port);\n\n } else {\n this.app.listen(port, callback);\n\n }\n return this;\n }\n\n public shutdown() {\n if (this._listeningSocket) {\n uWebSockets.us_listen_socket_close(this._listeningSocket);\n // @ts-ignore\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 if (this._originalRawSend == null) {\n this._originalRawSend = uWebSocketClient.prototype.raw;\n }\n\n const originalRawSend = this._originalRawSend;\n uWebSocketClient.prototype.raw = milliseconds <= Number.EPSILON ? originalRawSend : function (...args: any[]) {\n // copy buffer\n let [buf, ...rest] = args;\n buf = Buffer.from(buf);\n // @ts-ignore\n setTimeout(() => originalRawSend.apply(this, [buf, ...rest]), 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 url = rawClient.url;\n const searchParams = rawClient.searchParams;\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 // If sessionId is not provided, allow ping-pong utility.\n if (!sessionId && !roomId) {\n // Disconnect automatically after 1 second if no message is received.\n const timeout = setTimeout(() => rawClient.close(), 1000);\n wrapper.on('message', (_) => rawClient.send(new Uint8Array([Protocol.PING]), true));\n wrapper.on('close', () => clearTimeout(timeout));\n return;\n }\n\n const room = matchMaker.getLocalRoomById(roomId);\n const client = new uWebSocketClient(sessionId, wrapper);\n const reconnectionToken = searchParams.reconnectionToken as string;\n const skipHandshake = (searchParams.skipHandshake !== undefined);\n\n try {\n await connectClientToRoom(room, client, rawClient.context, {\n reconnectionToken,\n skipHandshake\n });\n\n } catch (e: any) {\n debugAndPrintError(e);\n\n // send error code to client then terminate\n client.error(e.code, e.message, () => client.leave());\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 = (res: uWebSockets.HttpResponse, requestHeaders: Headers) => {\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(requestHeaders)\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.cork(() => {\n res.writeStatus(\"406 Not Acceptable\");\n res.end(JSON.stringify(error));\n });\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 // cache all headers\n const reqHeaders = new Headers();\n req.forEach((key, value) => reqHeaders.set(key, value));\n\n if (writeHeaders(res, reqHeaders)) {\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.state === matchMaker.MatchMakerState.SHUTTING_DOWN) {\n return res.close();\n }\n\n // cache all headers\n const headers = new Headers();\n req.forEach((key, value) => headers.set(key, value));\n\n writeHeaders(res, headers);\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 const token = getBearerToken(headers['authorization']);\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(\n method,\n roomName,\n clientOptions,\n {\n token,\n headers,\n ip: headers.get('x-real-ip') ?? headers.get('x-forwarded-for') ?? Buffer.from(res.getRemoteAddressAsText()).toString()\n }\n );\n\n if (!res.aborted) {\n res.cork(() => {\n res.writeStatus(\"200 OK\");\n res.end(JSON.stringify(response));\n });\n }\n\n } catch (e: any) {\n debugAndPrintError(e);\n writeError(res, {\n code: e.code || ErrorCode.MATCHMAKE_UNHANDLED,\n error: e.message\n });\n }\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: Buffer;\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": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,yBAAiD;AACjD,yBAA4C;
|
|
6
|
-
"names": ["uWebSockets", "querystring"]
|
|
4
|
+
"sourcesContent": ["import querystring, { type ParsedUrlQuery } from 'querystring';\nimport uWebSockets, { type WebSocket } from 'uWebSockets.js';\nimport type express from 'express';\n\nimport { type AuthContext, Transport, matchMaker, Protocol, getBearerToken, debugAndPrintError, spliceOne, connectClientToRoom, type Router } from '@colyseus/core';\nimport { uWebSocketClient, uWebSocketWrapper } from './uWebSocketClient.ts';\nimport { Deferred } from '@colyseus/core';\n\nconst uWebSocketsExpress = new Deferred<typeof import('uwebsockets-express')>;\nlet uWebSocketsExpressModule: typeof import('uwebsockets-express') | undefined = undefined;\nimport('uwebsockets-express')\n .then((module) => uWebSocketsExpress.resolve(module))\n .catch((error) => uWebSocketsExpress.reject(error));\n\nexport type TransportOptions = Omit<uWebSockets.WebSocketBehavior<any>, \"upgrade\" | \"open\" | \"pong\" | \"close\" | \"message\">;\n\ntype RawWebSocketClient = uWebSockets.WebSocket<any> & {\n url: string,\n searchParams: ParsedUrlQuery,\n context: AuthContext,\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 private _originalRawSend: typeof uWebSocketClient.prototype.raw | null = null;\n private _expressApp?: express.Application;\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 === undefined) {\n options.maxBackpressure = 1024 * 1024;\n }\n\n if (options.compression === undefined) {\n options.compression = uWebSockets.DISABLED;\n }\n\n if (options.maxPayloadLength === undefined) {\n options.maxPayloadLength = 4 * 1024;\n }\n\n if (options.sendPingsAutomatically === undefined) {\n options.sendPingsAutomatically = true;\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 const searchParams = querystring.parse(req.getQuery());\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 searchParams,\n context: {\n token: searchParams._authToken ?? getBearerToken(req.getHeader('authorization')),\n headers,\n ip: headers['x-real-ip'] ?? headers['x-forwarded-for'] ?? 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: WebSocket<any>) => {\n // ws.pingCount = 0;\n await this.onConnection(ws as RawWebSocketClient);\n },\n\n // pong: (ws: RawWebSocketClient) => {\n // ws.pingCount = 0;\n // },\n\n close: (ws: WebSocket<any>, code: number, message: ArrayBuffer) => {\n // remove from client list\n spliceOne(this.clients, this.clients.indexOf(ws as RawWebSocketClient));\n\n const clientWrapper = this.clientWrappers.get(ws as RawWebSocketClient);\n if (clientWrapper) {\n this.clientWrappers.delete(ws as RawWebSocketClient);\n\n // emit 'close' on wrapper\n clientWrapper.emit('close', code);\n }\n },\n\n message: (ws: WebSocket<any>, message: ArrayBuffer, isBinary: boolean) => {\n // emit 'message' on wrapper\n this.clientWrappers.get(ws as RawWebSocketClient)?.emit('message', Buffer.from(message));\n },\n\n });\n }\n\n public getExpressApp(): Promise<express.Application> | express.Application {\n if (!this._expressApp) {\n return new Promise(async (resolve, reject) => {\n try {\n const module = await uWebSocketsExpress;\n uWebSocketsExpressModule = module;\n this._expressApp = (module.default(this.app) as unknown) as express.Application;\n resolve(this._expressApp);\n } catch (error) {\n console.warn(\"\");\n console.warn(\"\u274C could not initialize express\");\n console.warn(\"\uD83D\uDC49 npm install --save uwebsockets-express\");\n console.warn(\"\");\n reject(error);\n }\n });\n }\n return this._expressApp;\n }\n\n public bindRouter(router: Router) {\n const writeHeaders = (res: uWebSockets.HttpResponse, requestHeaders: Headers) => {\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(requestHeaders)\n );\n\n for (const header in headers) {\n res.writeHeader(header, headers[header].toString());\n }\n\n return true;\n }\n\n this.app.options(\"/*\", (res, req) => {\n res.onAborted(() => res.aborted = true);\n\n // cache all headers\n const reqHeaders = new Headers();\n req.forEach((key, value) => reqHeaders.set(key, value));\n\n if (writeHeaders(res, reqHeaders)) {\n res.writeStatus(\"204 No Content\");\n res.end();\n }\n });\n\n this.app.any('/*', async (res, req) => {\n const abortController = new AbortController();\n\n res.onAborted(() => {\n abortController.abort();\n res.aborted = true;\n });\n\n const headers = new Headers();\n req.forEach((key, value) => headers.set(key, value));\n\n const requestInit: RequestInit = {\n method: req.getMethod().toUpperCase(),\n referrer: req.getHeader('referer'),\n keepalive: req.getHeader('keep-alive') === 'true',\n headers,\n signal: abortController.signal,\n };\n\n // Construct full URL (Request constructor requires absolute URL)\n const url = req.getUrl();\n const query = req.getQuery();\n const remoteAddress = res.getRemoteAddressAsText();\n\n // read request body\n if (requestInit.method.toUpperCase() !== \"GET\" && requestInit.method.toUpperCase() !== \"HEAD\") {\n let body: Buffer = undefined;\n\n // uWebSockets.js `HttpRequest` does not provide 'getData', must aggregate POST body via HttpResponse\n await new Promise<void>((resolve) => {\n res.onData((ab, isLast) => {\n const chunk = Buffer.from(ab);\n if (body === undefined) {\n body = Buffer.from(chunk);\n } else {\n body = Buffer.concat([body, chunk]);\n }\n if (isLast) {\n resolve();\n }\n });\n });\n\n requestInit.body = body.buffer.slice(body.byteOffset, body.byteOffset + body.byteLength) as ArrayBuffer;\n }\n\n const fullUrl = `http://${headers.get('host') || 'localhost'}${url}${(query ? `?${query}` : '')}`\n const response = await router.handler(new Request(fullUrl, requestInit));\n\n // fallback to express stack if 404\n if (response.status === 404 && this._expressApp) {\n const ereq = new uWebSocketsExpressModule.IncomingMessage(req, res, this._expressApp as any, {\n headers: Object.fromEntries(headers.entries()),\n method: requestInit.method,\n url,\n query,\n remoteAddress\n });\n const eres = new uWebSocketsExpressModule.ServerResponse(res, req, this._expressApp);\n this._expressApp['handle'](ereq, eres);\n return;\n }\n\n // skip if aborted\n if (res.aborted) { return; }\n\n // read response body before cork (cork callback must be synchronous)\n const responseBody = await response.arrayBuffer();\n\n res.cork(() => {\n res.writeStatus(`${response.status} ${response.statusText}`);\n response.headers.forEach((value, key) => {\n res.writeHeader(key, value);\n });\n res.end(responseBody);\n });\n });\n }\n\n public listen(port: number, hostname?: string, backlog?: number, listeningListener?: () => void) {\n const callback = (listeningSocket: any) => {\n this._listeningSocket = listeningSocket;\n listeningListener?.();\n };\n\n if (typeof (port) === \"string\") {\n this.app.listen_unix(callback, port);\n\n } else {\n this.app.listen(port, callback);\n\n }\n return this;\n }\n\n public shutdown() {\n if (this._listeningSocket) {\n uWebSockets.us_listen_socket_close(this._listeningSocket);\n }\n }\n\n public simulateLatency(milliseconds: number) {\n if (this._originalRawSend == null) {\n this._originalRawSend = uWebSocketClient.prototype.raw;\n }\n\n const originalRawSend = this._originalRawSend;\n uWebSocketClient.prototype.raw = milliseconds <= Number.EPSILON ? originalRawSend : function (...args: any[]) {\n // copy buffer\n let [buf, ...rest] = args;\n buf = Buffer.from(buf);\n // @ts-ignore\n setTimeout(() => originalRawSend.apply(this, [buf, ...rest]), 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 url = rawClient.url;\n const searchParams = rawClient.searchParams;\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 // If sessionId is not provided, allow ping-pong utility.\n if (!sessionId && !roomId) {\n // Disconnect automatically after 1 second if no message is received.\n const timeout = setTimeout(() => rawClient.close(), 1000);\n wrapper.on('message', (_) => rawClient.send(new Uint8Array([Protocol.PING]), true));\n wrapper.on('close', () => clearTimeout(timeout));\n return;\n }\n\n const room = matchMaker.getLocalRoomById(roomId);\n const client = new uWebSocketClient(sessionId, wrapper);\n const reconnectionToken = searchParams.reconnectionToken as string;\n const skipHandshake = (searchParams.skipHandshake !== undefined);\n\n try {\n await connectClientToRoom(room, client, rawClient.context, {\n reconnectionToken,\n skipHandshake\n });\n\n } catch (e: any) {\n debugAndPrintError(e);\n\n // send error code to client then terminate\n client.error(e.code, e.message, () => client.leave());\n }\n }\n\n // protected registerMatchMakeRequest() {\n // const matchmakeRoute = 'matchmake';\n // const allowedRoomNameChars = /([a-zA-Z_\\-0-9]+)/gi;\n\n // const writeHeaders = (res: uWebSockets.HttpResponse, requestHeaders: Headers) => {\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(requestHeaders)\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.cork(() => {\n // res.writeStatus(\"406 Not Acceptable\");\n // res.end(JSON.stringify(error));\n // });\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 // // cache all headers\n // const reqHeaders = new Headers();\n // req.forEach((key, value) => reqHeaders.set(key, value));\n\n // if (writeHeaders(res, reqHeaders)) {\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.state === matchMaker.MatchMakerState.SHUTTING_DOWN) {\n // return res.close();\n // }\n\n // // cache all headers\n // const headers = new Headers();\n // req.forEach((key, value) => headers.set(key, value));\n\n // writeHeaders(res, headers);\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 // const token = getBearerToken(headers['authorization']);\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(\n // method,\n // roomName,\n // clientOptions,\n // {\n // token,\n // headers,\n // ip: headers.get('x-real-ip') ?? headers.get('x-forwarded-for') ?? Buffer.from(res.getRemoteAddressAsText()).toString()\n // }\n // );\n\n // if (!res.aborted) {\n // res.cork(() => {\n // res.writeStatus(\"200 OK\");\n // res.end(JSON.stringify(response));\n // });\n // }\n\n // } catch (e: any) {\n // debugAndPrintError(e);\n // writeError(res, {\n // code: e.code || ErrorCode.MATCHMAKE_UNHANDLED,\n // error: e.message\n // });\n // }\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: Buffer;\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": ["import_core", "module", "uWebSockets", "querystring"]
|
|
7
7
|
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { type ParsedUrlQuery } from 'querystring';
|
|
2
2
|
import uWebSockets from 'uWebSockets.js';
|
|
3
|
-
import
|
|
3
|
+
import type express from 'express';
|
|
4
|
+
import { type AuthContext, Transport, type Router } from '@colyseus/core';
|
|
4
5
|
import { uWebSocketWrapper } from './uWebSocketClient.ts';
|
|
5
6
|
export type TransportOptions = Omit<uWebSockets.WebSocketBehavior<any>, "upgrade" | "open" | "pong" | "close" | "message">;
|
|
6
7
|
type RawWebSocketClient = uWebSockets.WebSocket<any> & {
|
|
@@ -14,12 +15,14 @@ export declare class uWebSocketsTransport extends Transport {
|
|
|
14
15
|
protected clientWrappers: WeakMap<RawWebSocketClient, uWebSocketWrapper>;
|
|
15
16
|
private _listeningSocket;
|
|
16
17
|
private _originalRawSend;
|
|
18
|
+
private _expressApp?;
|
|
17
19
|
constructor(options?: TransportOptions, appOptions?: uWebSockets.AppOptions);
|
|
20
|
+
getExpressApp(): Promise<express.Application> | express.Application;
|
|
21
|
+
bindRouter(router: Router): void;
|
|
18
22
|
listen(port: number, hostname?: string, backlog?: number, listeningListener?: () => void): this;
|
|
19
23
|
shutdown(): void;
|
|
20
24
|
simulateLatency(milliseconds: number): void;
|
|
21
25
|
protected onConnection(rawClient: RawWebSocketClient): Promise<void>;
|
|
22
|
-
protected registerMatchMakeRequest(): void;
|
|
23
26
|
private readJson;
|
|
24
27
|
}
|
|
25
28
|
export {};
|