@colyseus/uwebsockets-transport
Version:
<div align="center"> <a href="https://github.com/colyseus/colyseus"> <img src="media/logo.svg?raw=true" width="60%" height="300" /> </a> <br> <br> <a href="https://npmjs.com/package/colyseus"> <img src="https://img.shields.io/npm/dm/coly
8 lines (7 loc) • 21 kB
Source Map (JSON)
{
"version": 3,
"sources": ["../src/uWebSocketsTransport.ts"],
"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, CloseCode, isDevMode, 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\n // Temporarily stub `app.any` to prevent uwebsockets-express Application.init()\n // from registering its own catch-all handler \u2014 we manage HTTP routing ourselves\n // in bindRouter().\n const originalAny = this.app.any;\n this.app.any = (() => this.app) as any;\n this._expressApp = (module.default(this.app) as unknown) as express.Application;\n this.app.any = originalAny;\n resolve(this._expressApp);\n } catch (error) {\n reject(error);\n console.warn(\"\");\n console.warn(\"\u274C Error: could not initialize express.\");\n console.warn(\"\");\n console.warn(\" For Express v5, use:\");\n console.warn(\" \uD83D\uDC49 npm install --save uwebsockets-express@^2.0.1\");\n console.warn(\"\");\n console.warn(\" For Express v4, use:\");\n console.warn(\" \uD83D\uDC49 npm install --save uwebsockets-express@^1.4.1\");\n console.warn(\"\");\n process.exit();\n }\n });\n }\n return this._expressApp;\n }\n\n public bindRouter(router: Router) {\n const getCorsHeaders = (requestHeaders: Headers) => {\n return Object.assign(\n {},\n matchMaker.controller.DEFAULT_CORS_HEADERS,\n matchMaker.controller.getCorsHeaders(requestHeaders)\n );\n }\n\n const writeCorsHeaders = (res: uWebSockets.HttpResponse, requestHeaders: Headers) => {\n // skip if aborted\n if (res.aborted) { return; }\n\n const headers = getCorsHeaders(requestHeaders);\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 res.cork(() => {\n res.writeStatus(\"204 No Content\");\n writeCorsHeaders(res, reqHeaders);\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 // cache all headers and request info synchronously\n // (uWebSockets.js req is only valid in the synchronous callback scope)\n const headers = new Headers();\n req.forEach((key, value) => headers.set(key, value));\n\n const method = req.getMethod().toUpperCase();\n const url = req.getUrl();\n const query = req.getQuery();\n const remoteAddress = res.getRemoteAddressAsText();\n\n // check if the route is defined in the router\n // if so, use the router handler, otherwise fallback to express\n if (router.findRoute(method, url) !== undefined) {\n const requestInit: RequestInit = {\n method,\n referrer: headers.get('referer') || undefined,\n keepalive: headers.get('keep-alive') === 'true',\n headers,\n signal: abortController.signal,\n };\n\n // read request body\n if (method !== \"GET\" && method !== \"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 // 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 // writeStatus() must be called before writeHeader() in uWebSockets.js\n res.cork(() => {\n res.writeStatus(`${response.status} ${response.statusText}`);\n writeCorsHeaders(res, headers);\n response.headers.forEach((value, key) => {\n if (key.toLowerCase() !== 'content-length') {\n res.writeHeader(key, value);\n }\n });\n res.end(responseBody);\n });\n\n } else if (this._expressApp) {\n // skip if already aborted\n if (res.aborted) { return; }\n\n const corsHeaders = getCorsHeaders(headers);\n\n const ereq = new uWebSocketsExpressModule.IncomingMessage(req, res, this._expressApp as any, {\n headers: Object.fromEntries((headers as any).entries()),\n method,\n url,\n query,\n remoteAddress\n });\n const eres = new uWebSocketsExpressModule.ServerResponse(res, req, this._expressApp);\n\n // Propagate uWS abort to the Express response wrapper.\n // When the client disconnects, mark the wrapper as finished\n // so it won't try to write to the already-aborted uWS response.\n // (fixes: \"uWS.HttpResponse must not be accessed after onAborted callback\")\n abortController.signal.addEventListener('abort', () => {\n eres.finished = true;\n // @ts-ignore\n eres.writableEnded = true;\n });\n\n // Apply CORS headers through the Express response wrapper\n for (const header in corsHeaders) {\n eres.setHeader(header, corsHeaders[header].toString());\n }\n\n // Read the request body from uWebSockets before passing to express\n // (uWebSockets requires res.onData() to be called to consume the body)\n await ereq._readBody();\n\n // skip if aborted during body read\n if (res.aborted) { return; }\n\n this._expressApp['handle'](ereq, eres);\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 // uWS throws \"Invalid access of closed uWS.WebSocket\" if the socket closed between the readyState check and the end()/close() call.\n const timeout = setTimeout(() => {\n try { rawClient.close(); } catch (e: any) {}\n }, 1000);\n wrapper.on('message', (_) => {\n try { rawClient.send(new Uint8Array([Protocol.PING]), true); } catch (e: any) {}\n });\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, () => {\n // uWS throws \"Invalid access of closed uWS.WebSocket\" if the socket closed between the readyState check and the end()/close() call.\n // Use MAY_TRY_RECONNECT in devMode so the SDK retries \u2014 the seat\n // may not be reserved yet during HMR reload.\n try {\n rawClient.end(reconnectionToken\n ? (isDevMode)\n ? CloseCode.MAY_TRY_RECONNECT\n : CloseCode.FAILED_TO_RECONNECT\n : CloseCode.WITH_ERROR);\n } catch (e: any) {}\n });\n }\n }\n\n}\n"],
"mappings": "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",
"names": ["import_core", "module", "uWebSockets", "querystring", "e"]
}