@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.
@@ -1,8 +1,12 @@
1
1
  // packages/transport/uwebsockets-transport/src/uWebSocketsTransport.ts
2
2
  import querystring from "querystring";
3
3
  import uWebSockets from "uWebSockets.js";
4
- import { Transport, HttpServerMock, ErrorCode, matchMaker, Protocol, getBearerToken, debugAndPrintError, spliceOne, connectClientToRoom } from "@colyseus/core";
4
+ import { Transport, matchMaker, Protocol, getBearerToken, debugAndPrintError, spliceOne, connectClientToRoom } from "@colyseus/core";
5
5
  import { uWebSocketClient, uWebSocketWrapper } from "./uWebSocketClient.mjs";
6
+ import { Deferred } from "@colyseus/core";
7
+ var uWebSocketsExpress = new Deferred();
8
+ var uWebSocketsExpressModule = void 0;
9
+ import("uwebsockets-express").then((module) => uWebSocketsExpress.resolve(module)).catch((error) => uWebSocketsExpress.reject(error));
6
10
  var uWebSocketsTransport = class extends Transport {
7
11
  constructor(options = {}, appOptions = {}) {
8
12
  super();
@@ -22,9 +26,6 @@ var uWebSocketsTransport = class extends Transport {
22
26
  if (options.sendPingsAutomatically === void 0) {
23
27
  options.sendPingsAutomatically = true;
24
28
  }
25
- if (!this.server) {
26
- this.server = new HttpServerMock();
27
- }
28
29
  this.app.ws("/*", {
29
30
  ...options,
30
31
  upgrade: (res, req, context) => {
@@ -65,13 +66,116 @@ var uWebSocketsTransport = class extends Transport {
65
66
  this.clientWrappers.get(ws)?.emit("message", Buffer.from(message));
66
67
  }
67
68
  });
68
- this.registerMatchMakeRequest();
69
+ }
70
+ getExpressApp() {
71
+ if (!this._expressApp) {
72
+ return new Promise(async (resolve, reject) => {
73
+ try {
74
+ const module = await uWebSocketsExpress;
75
+ uWebSocketsExpressModule = module;
76
+ this._expressApp = module.default(this.app);
77
+ resolve(this._expressApp);
78
+ } catch (error) {
79
+ console.warn("");
80
+ console.warn("\u274C could not initialize express");
81
+ console.warn("\u{1F449} npm install --save uwebsockets-express");
82
+ console.warn("");
83
+ reject(error);
84
+ }
85
+ });
86
+ }
87
+ return this._expressApp;
88
+ }
89
+ bindRouter(router) {
90
+ const writeHeaders = (res, requestHeaders) => {
91
+ if (res.aborted) {
92
+ return;
93
+ }
94
+ const headers = Object.assign(
95
+ {},
96
+ matchMaker.controller.DEFAULT_CORS_HEADERS,
97
+ matchMaker.controller.getCorsHeaders(requestHeaders)
98
+ );
99
+ for (const header in headers) {
100
+ res.writeHeader(header, headers[header].toString());
101
+ }
102
+ return true;
103
+ };
104
+ this.app.options("/*", (res, req) => {
105
+ res.onAborted(() => res.aborted = true);
106
+ const reqHeaders = new Headers();
107
+ req.forEach((key, value) => reqHeaders.set(key, value));
108
+ if (writeHeaders(res, reqHeaders)) {
109
+ res.writeStatus("204 No Content");
110
+ res.end();
111
+ }
112
+ });
113
+ this.app.any("/*", async (res, req) => {
114
+ const abortController = new AbortController();
115
+ res.onAborted(() => {
116
+ abortController.abort();
117
+ res.aborted = true;
118
+ });
119
+ const headers = new Headers();
120
+ req.forEach((key, value) => headers.set(key, value));
121
+ const requestInit = {
122
+ method: req.getMethod().toUpperCase(),
123
+ referrer: req.getHeader("referer"),
124
+ keepalive: req.getHeader("keep-alive") === "true",
125
+ headers,
126
+ signal: abortController.signal
127
+ };
128
+ const url = req.getUrl();
129
+ const query = req.getQuery();
130
+ const remoteAddress = res.getRemoteAddressAsText();
131
+ if (requestInit.method.toUpperCase() !== "GET" && requestInit.method.toUpperCase() !== "HEAD") {
132
+ let body = void 0;
133
+ await new Promise((resolve) => {
134
+ res.onData((ab, isLast) => {
135
+ const chunk = Buffer.from(ab);
136
+ if (body === void 0) {
137
+ body = Buffer.from(chunk);
138
+ } else {
139
+ body = Buffer.concat([body, chunk]);
140
+ }
141
+ if (isLast) {
142
+ resolve();
143
+ }
144
+ });
145
+ });
146
+ requestInit.body = body.buffer.slice(body.byteOffset, body.byteOffset + body.byteLength);
147
+ }
148
+ const fullUrl = `http://${headers.get("host") || "localhost"}${url}${query ? `?${query}` : ""}`;
149
+ const response = await router.handler(new Request(fullUrl, requestInit));
150
+ if (response.status === 404 && this._expressApp) {
151
+ const ereq = new uWebSocketsExpressModule.IncomingMessage(req, res, this._expressApp, {
152
+ headers: Object.fromEntries(headers.entries()),
153
+ method: requestInit.method,
154
+ url,
155
+ query,
156
+ remoteAddress
157
+ });
158
+ const eres = new uWebSocketsExpressModule.ServerResponse(res, req, this._expressApp);
159
+ this._expressApp["handle"](ereq, eres);
160
+ return;
161
+ }
162
+ if (res.aborted) {
163
+ return;
164
+ }
165
+ const responseBody = await response.arrayBuffer();
166
+ res.cork(() => {
167
+ res.writeStatus(`${response.status} ${response.statusText}`);
168
+ response.headers.forEach((value, key) => {
169
+ res.writeHeader(key, value);
170
+ });
171
+ res.end(responseBody);
172
+ });
173
+ });
69
174
  }
70
175
  listen(port, hostname, backlog, listeningListener) {
71
176
  const callback = (listeningSocket) => {
72
177
  this._listeningSocket = listeningSocket;
73
178
  listeningListener?.();
74
- this.server.emit("listening");
75
179
  };
76
180
  if (typeof port === "string") {
77
181
  this.app.listen_unix(callback, port);
@@ -83,7 +187,6 @@ var uWebSocketsTransport = class extends Transport {
83
187
  shutdown() {
84
188
  if (this._listeningSocket) {
85
189
  uWebSockets.us_listen_socket_close(this._listeningSocket);
86
- this.server.emit("close");
87
190
  }
88
191
  }
89
192
  simulateLatency(milliseconds) {
@@ -126,90 +229,93 @@ var uWebSocketsTransport = class extends Transport {
126
229
  client.error(e.code, e.message, () => client.leave());
127
230
  }
128
231
  }
129
- registerMatchMakeRequest() {
130
- const matchmakeRoute = "matchmake";
131
- const allowedRoomNameChars = /([a-zA-Z_\-0-9]+)/gi;
132
- const writeHeaders = (res, requestHeaders) => {
133
- if (res.aborted) {
134
- return;
135
- }
136
- const headers = Object.assign(
137
- {},
138
- matchMaker.controller.DEFAULT_CORS_HEADERS,
139
- matchMaker.controller.getCorsHeaders(requestHeaders)
140
- );
141
- for (const header in headers) {
142
- res.writeHeader(header, headers[header].toString());
143
- }
144
- return true;
145
- };
146
- const writeError = (res, error) => {
147
- if (res.aborted) {
148
- return;
149
- }
150
- res.cork(() => {
151
- res.writeStatus("406 Not Acceptable");
152
- res.end(JSON.stringify(error));
153
- });
154
- };
155
- const onAborted = (res) => {
156
- res.aborted = true;
157
- };
158
- this.app.options("/matchmake/*", (res, req) => {
159
- res.onAborted(() => onAborted(res));
160
- const reqHeaders = new Headers();
161
- req.forEach((key, value) => reqHeaders.set(key, value));
162
- if (writeHeaders(res, reqHeaders)) {
163
- res.writeStatus("204 No Content");
164
- res.end();
165
- }
166
- });
167
- this.app.post("/matchmake/*", (res, req) => {
168
- res.onAborted(() => onAborted(res));
169
- if (matchMaker.state === matchMaker.MatchMakerState.SHUTTING_DOWN) {
170
- return res.close();
171
- }
172
- const headers = new Headers();
173
- req.forEach((key, value) => headers.set(key, value));
174
- writeHeaders(res, headers);
175
- res.writeHeader("Content-Type", "application/json");
176
- const url = req.getUrl();
177
- const matchedParams = url.match(allowedRoomNameChars);
178
- const matchmakeIndex = matchedParams.indexOf(matchmakeRoute);
179
- const token = getBearerToken(headers["authorization"]);
180
- this.readJson(res, async (clientOptions) => {
181
- try {
182
- if (clientOptions === void 0) {
183
- throw new Error("invalid JSON input");
184
- }
185
- const method = matchedParams[matchmakeIndex + 1];
186
- const roomName = matchedParams[matchmakeIndex + 2] || "";
187
- const response = await matchMaker.controller.invokeMethod(
188
- method,
189
- roomName,
190
- clientOptions,
191
- {
192
- token,
193
- headers,
194
- ip: headers.get("x-real-ip") ?? headers.get("x-forwarded-for") ?? Buffer.from(res.getRemoteAddressAsText()).toString()
195
- }
196
- );
197
- if (!res.aborted) {
198
- res.cork(() => {
199
- res.writeStatus("200 OK");
200
- res.end(JSON.stringify(response));
201
- });
202
- }
203
- } catch (e) {
204
- debugAndPrintError(e);
205
- writeError(res, {
206
- code: e.code || ErrorCode.MATCHMAKE_UNHANDLED,
207
- error: e.message
208
- });
209
- }
210
- });
211
- });
212
- }
232
+ // protected registerMatchMakeRequest() {
233
+ // const matchmakeRoute = 'matchmake';
234
+ // const allowedRoomNameChars = /([a-zA-Z_\-0-9]+)/gi;
235
+ // const writeHeaders = (res: uWebSockets.HttpResponse, requestHeaders: Headers) => {
236
+ // // skip if aborted
237
+ // if (res.aborted) { return; }
238
+ // const headers = Object.assign(
239
+ // {},
240
+ // matchMaker.controller.DEFAULT_CORS_HEADERS,
241
+ // matchMaker.controller.getCorsHeaders(requestHeaders)
242
+ // );
243
+ // for (const header in headers) {
244
+ // res.writeHeader(header, headers[header].toString());
245
+ // }
246
+ // return true;
247
+ // }
248
+ // const writeError = (res: uWebSockets.HttpResponse, error: { code: number, error: string }) => {
249
+ // // skip if aborted
250
+ // if (res.aborted) { return; }
251
+ // res.cork(() => {
252
+ // res.writeStatus("406 Not Acceptable");
253
+ // res.end(JSON.stringify(error));
254
+ // });
255
+ // }
256
+ // const onAborted = (res: uWebSockets.HttpResponse) => {
257
+ // res.aborted = true;
258
+ // };
259
+ // this.app.options("/matchmake/*", (res, req) => {
260
+ // res.onAborted(() => onAborted(res));
261
+ // // cache all headers
262
+ // const reqHeaders = new Headers();
263
+ // req.forEach((key, value) => reqHeaders.set(key, value));
264
+ // if (writeHeaders(res, reqHeaders)) {
265
+ // res.writeStatus("204 No Content");
266
+ // res.end();
267
+ // }
268
+ // });
269
+ // // @ts-ignore
270
+ // this.app.post("/matchmake/*", (res, req) => {
271
+ // res.onAborted(() => onAborted(res));
272
+ // // do not accept matchmaking requests if already shutting down
273
+ // if (matchMaker.state === matchMaker.MatchMakerState.SHUTTING_DOWN) {
274
+ // return res.close();
275
+ // }
276
+ // // cache all headers
277
+ // const headers = new Headers();
278
+ // req.forEach((key, value) => headers.set(key, value));
279
+ // writeHeaders(res, headers);
280
+ // res.writeHeader('Content-Type', 'application/json');
281
+ // const url = req.getUrl();
282
+ // const matchedParams = url.match(allowedRoomNameChars);
283
+ // const matchmakeIndex = matchedParams.indexOf(matchmakeRoute);
284
+ // const token = getBearerToken(headers['authorization']);
285
+ // // read json body
286
+ // this.readJson(res, async (clientOptions) => {
287
+ // try {
288
+ // if (clientOptions === undefined) {
289
+ // throw new Error("invalid JSON input");
290
+ // }
291
+ // const method = matchedParams[matchmakeIndex + 1];
292
+ // const roomName = matchedParams[matchmakeIndex + 2] || '';
293
+ // const response = await matchMaker.controller.invokeMethod(
294
+ // method,
295
+ // roomName,
296
+ // clientOptions,
297
+ // {
298
+ // token,
299
+ // headers,
300
+ // ip: headers.get('x-real-ip') ?? headers.get('x-forwarded-for') ?? Buffer.from(res.getRemoteAddressAsText()).toString()
301
+ // }
302
+ // );
303
+ // if (!res.aborted) {
304
+ // res.cork(() => {
305
+ // res.writeStatus("200 OK");
306
+ // res.end(JSON.stringify(response));
307
+ // });
308
+ // }
309
+ // } catch (e: any) {
310
+ // debugAndPrintError(e);
311
+ // writeError(res, {
312
+ // code: e.code || ErrorCode.MATCHMAKE_UNHANDLED,
313
+ // error: e.message
314
+ // });
315
+ // }
316
+ // });
317
+ // });
318
+ // }
213
319
  /* Helper function for reading a posted JSON body */
214
320
  /* Extracted from https://github.com/uNetworking/uWebSockets.js/blob/master/examples/JsonPost.js */
215
321
  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": "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",
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
6
  "names": []
7
7
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@colyseus/uwebsockets-transport",
3
- "version": "0.17.7",
3
+ "version": "0.17.8",
4
4
  "type": "module",
5
5
  "input": "./src/index.ts",
6
6
  "main": "./build/index.cjs",
@@ -24,10 +24,16 @@
24
24
  "uWebSockets.js": "github:uNetworking/uWebSockets.js#v20.57.0"
25
25
  },
26
26
  "devDependencies": {
27
- "@colyseus/core": "^0.17.17"
27
+ "@colyseus/core": "^0.17.18"
28
28
  },
29
29
  "peerDependencies": {
30
- "@colyseus/core": "0.17.x"
30
+ "@colyseus/core": "0.17.x",
31
+ "uwebsockets-express": "^1.4.1 || ^2.0.1"
32
+ },
33
+ "peerDependenciesMeta": {
34
+ "uwebsockets-express": {
35
+ "optional": true
36
+ }
31
37
  },
32
38
  "author": "Endel Dreyer",
33
39
  "license": "MIT",