@colyseus/core 0.16.24 → 0.17.1
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/Debug.js +16 -4
- package/build/Debug.js.map +2 -2
- package/build/Debug.mjs +11 -1
- package/build/Debug.mjs.map +2 -2
- package/build/IPC.js +5 -3
- package/build/IPC.js.map +2 -2
- package/build/IPC.mjs +1 -0
- package/build/IPC.mjs.map +2 -2
- package/build/Logger.js +1 -0
- package/build/Logger.js.map +1 -1
- package/build/MatchMaker.js +148 -84
- package/build/MatchMaker.js.map +3 -3
- package/build/MatchMaker.mjs +130 -70
- package/build/MatchMaker.mjs.map +3 -3
- package/build/Protocol.js +54 -41
- package/build/Protocol.js.map +3 -3
- package/build/Protocol.mjs +52 -41
- package/build/Protocol.mjs.map +3 -3
- package/build/Room.js +430 -195
- package/build/Room.js.map +3 -3
- package/build/Room.mjs +417 -175
- package/build/Room.mjs.map +3 -3
- package/build/Server.js +49 -108
- package/build/Server.js.map +3 -3
- package/build/Server.mjs +40 -102
- package/build/Server.mjs.map +3 -3
- package/build/Stats.js +2 -1
- package/build/Stats.js.map +2 -2
- package/build/Stats.mjs.map +1 -1
- package/build/Transport.js +29 -11
- package/build/Transport.js.map +3 -3
- package/build/Transport.mjs +15 -9
- package/build/Transport.mjs.map +3 -3
- package/build/errors/RoomExceptions.js +9 -5
- package/build/errors/RoomExceptions.js.map +2 -2
- package/build/errors/RoomExceptions.mjs +8 -5
- package/build/errors/RoomExceptions.mjs.map +2 -2
- package/build/errors/SeatReservationError.js +1 -0
- package/build/errors/SeatReservationError.js.map +1 -1
- package/build/errors/ServerError.js +2 -1
- package/build/errors/ServerError.js.map +2 -2
- package/build/errors/ServerError.mjs.map +1 -1
- package/build/index.js +60 -26
- package/build/index.js.map +2 -2
- package/build/index.mjs +33 -7
- package/build/index.mjs.map +2 -2
- package/build/matchmaker/Lobby.js +13 -3
- package/build/matchmaker/Lobby.js.map +2 -2
- package/build/matchmaker/Lobby.mjs +11 -2
- package/build/matchmaker/Lobby.mjs.map +2 -2
- package/build/matchmaker/LocalDriver/LocalDriver.js +94 -0
- package/build/matchmaker/LocalDriver/LocalDriver.js.map +7 -0
- package/build/matchmaker/LocalDriver/LocalDriver.mjs +71 -0
- package/build/matchmaker/LocalDriver/LocalDriver.mjs.map +7 -0
- package/build/matchmaker/LocalDriver/Query.js +111 -0
- package/build/matchmaker/LocalDriver/Query.js.map +7 -0
- package/build/matchmaker/LocalDriver/Query.mjs +88 -0
- package/build/matchmaker/LocalDriver/Query.mjs.map +7 -0
- package/build/matchmaker/RegisteredHandler.js +57 -7
- package/build/matchmaker/RegisteredHandler.js.map +2 -2
- package/build/matchmaker/RegisteredHandler.mjs +54 -5
- package/build/matchmaker/RegisteredHandler.mjs.map +2 -2
- package/build/matchmaker/controller.js +8 -8
- package/build/matchmaker/controller.js.map +2 -2
- package/build/matchmaker/controller.mjs +4 -5
- package/build/matchmaker/controller.mjs.map +2 -2
- package/build/matchmaker/driver/api.js +21 -2
- package/build/matchmaker/driver/api.js.map +2 -2
- package/build/matchmaker/driver/api.mjs +18 -1
- package/build/matchmaker/driver/api.mjs.map +2 -2
- package/build/matchmaker/driver/local/LocalDriver.js +36 -7
- package/build/matchmaker/driver/local/LocalDriver.js.map +2 -2
- package/build/matchmaker/driver/local/LocalDriver.mjs +33 -5
- package/build/matchmaker/driver/local/LocalDriver.mjs.map +2 -2
- package/build/matchmaker/driver/local/Query.js +51 -18
- package/build/matchmaker/driver/local/Query.js.map +2 -2
- package/build/matchmaker/driver/local/Query.mjs +50 -18
- package/build/matchmaker/driver/local/Query.mjs.map +2 -2
- package/build/matchmaker/driver.js +44 -0
- package/build/matchmaker/driver.js.map +7 -0
- package/build/matchmaker/driver.mjs +20 -0
- package/build/matchmaker/driver.mjs.map +7 -0
- package/build/matchmaker/routes.js +79 -0
- package/build/matchmaker/routes.js.map +7 -0
- package/build/matchmaker/routes.mjs +45 -0
- package/build/matchmaker/routes.mjs.map +7 -0
- package/build/presence/LocalPresence.js +13 -27
- package/build/presence/LocalPresence.js.map +3 -3
- package/build/presence/LocalPresence.mjs +11 -16
- package/build/presence/LocalPresence.mjs.map +2 -2
- package/build/presence/Presence.js +37 -0
- package/build/presence/Presence.js.map +2 -2
- package/build/presence/Presence.mjs +29 -0
- package/build/presence/Presence.mjs.map +3 -3
- package/build/rooms/LobbyRoom.js +5 -5
- package/build/rooms/LobbyRoom.js.map +2 -2
- package/build/rooms/LobbyRoom.mjs +1 -2
- package/build/rooms/LobbyRoom.mjs.map +2 -2
- package/build/rooms/RankedQueueRoom.js +224 -0
- package/build/rooms/RankedQueueRoom.js.map +7 -0
- package/build/rooms/RankedQueueRoom.mjs +201 -0
- package/build/rooms/RankedQueueRoom.mjs.map +7 -0
- package/build/rooms/RelayRoom.js +6 -6
- package/build/rooms/RelayRoom.js.map +2 -2
- package/build/rooms/RelayRoom.mjs +4 -5
- package/build/rooms/RelayRoom.mjs.map +2 -2
- package/build/rooms/createRoom.js +51 -0
- package/build/rooms/createRoom.js.map +7 -0
- package/build/rooms/createRoom.mjs +28 -0
- package/build/rooms/createRoom.mjs.map +7 -0
- package/build/router/default_routes.js +79 -0
- package/build/router/default_routes.js.map +7 -0
- package/build/router/default_routes.mjs +45 -0
- package/build/router/default_routes.mjs.map +7 -0
- package/build/router/index.js +55 -0
- package/build/router/index.js.map +7 -0
- package/build/router/index.mjs +30 -0
- package/build/router/index.mjs.map +7 -0
- package/build/serializer/NoneSerializer.js +1 -0
- package/build/serializer/NoneSerializer.js.map +2 -2
- package/build/serializer/NoneSerializer.mjs.map +2 -2
- package/build/serializer/SchemaSerializer.js +6 -7
- package/build/serializer/SchemaSerializer.js.map +2 -2
- package/build/serializer/SchemaSerializer.mjs +3 -5
- package/build/serializer/SchemaSerializer.mjs.map +2 -2
- package/build/serializer/SchemaSerializerDebug.js +29 -0
- package/build/serializer/SchemaSerializerDebug.js.map +3 -3
- package/build/serializer/SchemaSerializerDebug.mjs +7 -0
- package/build/serializer/SchemaSerializerDebug.mjs.map +3 -3
- package/build/serializer/Serializer.js +1 -0
- package/build/serializer/Serializer.js.map +2 -2
- package/build/{Debug.d.ts → src/Debug.d.ts} +2 -1
- package/build/{IPC.d.ts → src/IPC.d.ts} +2 -2
- package/build/{MatchMaker.d.ts → src/MatchMaker.d.ts} +58 -33
- package/build/src/Protocol.d.ts +53 -0
- package/build/src/Room.d.ts +497 -0
- package/build/{Server.d.ts → src/Server.d.ts} +23 -25
- package/build/{Transport.d.ts → src/Transport.d.ts} +65 -22
- package/build/{errors → src/errors}/RoomExceptions.d.ts +8 -7
- package/build/src/index.d.ts +27 -0
- package/build/src/matchmaker/Lobby.d.ts +4 -0
- package/build/src/matchmaker/LocalDriver/LocalDriver.d.ts +17 -0
- package/build/src/matchmaker/LocalDriver/Query.d.ts +12 -0
- package/build/src/matchmaker/RegisteredHandler.d.ts +81 -0
- package/build/{matchmaker → src/matchmaker}/controller.d.ts +5 -6
- package/build/src/matchmaker/driver/api.d.ts +145 -0
- package/build/src/matchmaker/driver/local/LocalDriver.d.ts +17 -0
- package/build/src/matchmaker/driver/local/Query.d.ts +12 -0
- package/build/src/matchmaker/driver.d.ts +145 -0
- package/build/src/matchmaker/routes.d.ts +92 -0
- package/build/{presence → src/presence}/LocalPresence.d.ts +1 -1
- package/build/{presence → src/presence}/Presence.d.ts +2 -0
- package/build/{rooms → src/rooms}/LobbyRoom.d.ts +4 -4
- package/build/src/rooms/RankedQueueRoom.d.ts +125 -0
- package/build/{rooms → src/rooms}/RelayRoom.d.ts +5 -4
- package/build/src/rooms/createRoom.d.ts +65 -0
- package/build/src/router/default_routes.d.ts +103 -0
- package/build/src/router/index.d.ts +68 -0
- package/build/{serializer → src/serializer}/NoneSerializer.d.ts +2 -2
- package/build/{serializer → src/serializer}/SchemaSerializer.d.ts +9 -9
- package/build/{serializer → src/serializer}/Serializer.d.ts +3 -3
- package/build/{utils → src/utils}/DevMode.d.ts +5 -4
- package/build/{utils → src/utils}/StandardSchema.d.ts +1 -1
- package/build/{utils → src/utils}/Utils.d.ts +15 -4
- package/build/utils/DevMode.js +54 -26
- package/build/utils/DevMode.js.map +3 -3
- package/build/utils/DevMode.mjs +44 -19
- package/build/utils/DevMode.mjs.map +2 -2
- package/build/utils/StandardSchema.js.map +1 -1
- package/build/utils/StandardSchema.mjs.map +1 -1
- package/build/utils/Utils.js +8 -15
- package/build/utils/Utils.js.map +3 -3
- package/build/utils/Utils.mjs +6 -4
- package/build/utils/Utils.mjs.map +2 -2
- package/package.json +21 -16
- package/src/Debug.ts +37 -0
- package/src/IPC.ts +124 -0
- package/src/Logger.ts +30 -0
- package/src/MatchMaker.ts +1119 -0
- package/src/Protocol.ts +160 -0
- package/src/Room.ts +1797 -0
- package/src/Server.ts +325 -0
- package/src/Stats.ts +107 -0
- package/src/Transport.ts +207 -0
- package/src/errors/RoomExceptions.ts +141 -0
- package/src/errors/SeatReservationError.ts +5 -0
- package/src/errors/ServerError.ts +17 -0
- package/src/index.ts +81 -0
- package/src/matchmaker/Lobby.ts +68 -0
- package/src/matchmaker/LocalDriver/LocalDriver.ts +92 -0
- package/src/matchmaker/LocalDriver/Query.ts +94 -0
- package/src/matchmaker/RegisteredHandler.ts +172 -0
- package/src/matchmaker/controller.ts +64 -0
- package/src/matchmaker/driver.ts +191 -0
- package/src/presence/LocalPresence.ts +331 -0
- package/src/presence/Presence.ts +263 -0
- package/src/rooms/LobbyRoom.ts +135 -0
- package/src/rooms/RankedQueueRoom.ts +425 -0
- package/src/rooms/RelayRoom.ts +90 -0
- package/src/router/default_routes.ts +58 -0
- package/src/router/index.ts +43 -0
- package/src/serializer/NoneSerializer.ts +16 -0
- package/src/serializer/SchemaSerializer.ts +194 -0
- package/src/serializer/SchemaSerializerDebug.ts +148 -0
- package/src/serializer/Serializer.ts +9 -0
- package/src/utils/DevMode.ts +133 -0
- package/src/utils/StandardSchema.ts +20 -0
- package/src/utils/Utils.ts +169 -0
- package/src/utils/nanoevents.ts +20 -0
- package/build/Protocol.d.ts +0 -37
- package/build/Room.d.ts +0 -265
- package/build/discovery/index.d.ts +0 -8
- package/build/discovery/index.js +0 -50
- package/build/discovery/index.js.map +0 -7
- package/build/discovery/index.mjs +0 -26
- package/build/discovery/index.mjs.map +0 -7
- package/build/index.d.ts +0 -24
- package/build/matchmaker/Lobby.d.ts +0 -4
- package/build/matchmaker/RegisteredHandler.d.ts +0 -19
- package/build/matchmaker/driver/Query.d.ts +0 -8
- package/build/matchmaker/driver/Query.js +0 -68
- package/build/matchmaker/driver/Query.js.map +0 -7
- package/build/matchmaker/driver/Query.mjs +0 -45
- package/build/matchmaker/driver/Query.mjs.map +0 -7
- package/build/matchmaker/driver/RoomData.d.ts +0 -19
- package/build/matchmaker/driver/RoomData.js +0 -79
- package/build/matchmaker/driver/RoomData.js.map +0 -7
- package/build/matchmaker/driver/RoomData.mjs +0 -56
- package/build/matchmaker/driver/RoomData.mjs.map +0 -7
- package/build/matchmaker/driver/api.d.ts +0 -104
- package/build/matchmaker/driver/index.d.ts +0 -13
- package/build/matchmaker/driver/index.js +0 -64
- package/build/matchmaker/driver/index.js.map +0 -7
- package/build/matchmaker/driver/index.mjs +0 -42
- package/build/matchmaker/driver/index.mjs.map +0 -7
- package/build/matchmaker/driver/interfaces.d.ts +0 -73
- package/build/matchmaker/driver/interfaces.js +0 -15
- package/build/matchmaker/driver/interfaces.js.map +0 -7
- package/build/matchmaker/driver/interfaces.mjs +0 -0
- package/build/matchmaker/driver/interfaces.mjs.map +0 -7
- package/build/matchmaker/driver/local/LocalDriver.d.ts +0 -13
- package/build/matchmaker/driver/local/Query.d.ts +0 -9
- package/build/matchmaker/driver/local/RoomData.d.ts +0 -19
- package/build/matchmaker/driver/local/RoomData.js +0 -79
- package/build/matchmaker/driver/local/RoomData.js.map +0 -7
- package/build/matchmaker/driver/local/RoomData.mjs +0 -57
- package/build/matchmaker/driver/local/RoomData.mjs.map +0 -7
- package/build/utils/types.d.ts +0 -1
- package/build/utils/types.js +0 -15
- package/build/utils/types.js.map +0 -7
- package/build/utils/types.mjs +0 -0
- package/build/utils/types.mjs.map +0 -7
- /package/build/{Logger.d.ts → src/Logger.d.ts} +0 -0
- /package/build/{Stats.d.ts → src/Stats.d.ts} +0 -0
- /package/build/{errors → src/errors}/SeatReservationError.d.ts +0 -0
- /package/build/{errors → src/errors}/ServerError.d.ts +0 -0
- /package/build/{serializer → src/serializer}/SchemaSerializerDebug.d.ts +0 -0
- /package/build/{utils → src/utils}/nanoevents.d.ts +0 -0
package/build/Server.js.map
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../src/Server.ts"],
|
|
4
|
-
"sourcesContent": ["import http, { IncomingMessage, ServerResponse } from 'http';\nimport greeting from \"@colyseus/greeting-banner\";\n\nimport { debugAndPrintError, debugMatchMaking } from './Debug.js';\nimport * as matchMaker from './MatchMaker.js';\nimport { RegisteredHandler } from './matchmaker/RegisteredHandler.js';\nimport { Presence } from './presence/Presence.js';\n\nimport { Room } from './Room.js';\nimport { Type } from './utils/types.js';\nimport { getBearerToken, registerGracefulShutdown } from './utils/Utils.js';\n\nimport { registerNode, unregisterNode} from './discovery/index.js';\n\nimport { LocalPresence } from './presence/LocalPresence.js';\nimport { LocalDriver } from './matchmaker/driver/local/LocalDriver.js';\n\nimport { Transport } from './Transport.js';\nimport { logger, setLogger } from './Logger.js';\nimport { setDevMode, isDevMode } from './utils/DevMode.js';\n\nexport type ServerOptions = {\n publicAddress?: string,\n presence?: Presence,\n driver?: matchMaker.MatchMakerDriver,\n transport?: Transport,\n gracefullyShutdown?: boolean,\n logger?: any;\n\n /**\n * Custom function to determine which process should handle room creation.\n * Default: assign new rooms the process with least amount of rooms created\n */\n selectProcessIdToCreateRoom?: matchMaker.SelectProcessIdCallback;\n\n /**\n * If enabled, rooms are going to be restored in the server-side upon restart,\n * clients are going to automatically re-connect when server reboots.\n *\n * Beware of \"schema mismatch\" issues. When updating Schema structures and\n * reloading existing data, you may see \"schema mismatch\" errors in the\n * client-side.\n *\n * (This operation is costly and should not be used in a production\n * environment)\n */\n devMode?: boolean,\n\n /**\n * Display greeting message on server start.\n * Default: true\n */\n greet?: boolean,\n\n /**\n * Options below are now part of WebSocketTransport (@colyseus/ws-transport)\n * TODO: remove me on 0.15.0\n */\n /** @deprecated */\n pingInterval?: number,\n\n /** @deprecated */\n pingMaxRetries?: number,\n\n /** @deprecated */\n verifyClient?: any,\n\n /** @deprecated */\n server?: http.Server,\n};\n\nexport class Server {\n public transport: Transport;\n\n protected presence: Presence;\n protected driver: matchMaker.MatchMakerDriver;\n\n protected port: number;\n protected greet: boolean;\n\n //@ts-expect-error\n private _originalRoomOnMessage: typeof Room.prototype._onMessage | null = null;\n\n constructor(options: ServerOptions = {}) {\n const { gracefullyShutdown = true, greet = true } = options;\n\n setDevMode(options.devMode === true);\n\n this.presence = options.presence || new LocalPresence();\n this.driver = options.driver || new LocalDriver();\n this.greet = greet;\n\n this.attach(options);\n\n matchMaker.setup(\n this.presence,\n this.driver,\n options.publicAddress,\n options.selectProcessIdToCreateRoom,\n );\n\n if (gracefullyShutdown) {\n registerGracefulShutdown((err) => this.gracefullyShutdown(true, err));\n }\n\n if (options.logger) {\n setLogger(options.logger);\n }\n }\n\n public attach(options: ServerOptions) {\n /**\n * Display deprecation warnings for moved Transport options.\n * TODO: Remove me on 0.15\n */\n if (\n options.pingInterval !== undefined ||\n options.pingMaxRetries !== undefined ||\n options.server !== undefined ||\n options.verifyClient !== undefined\n ) {\n logger.warn(\"DEPRECATION WARNING: 'pingInterval', 'pingMaxRetries', 'server', and 'verifyClient' Server options will be permanently moved to WebSocketTransport on v0.15\");\n logger.warn(`new Server({\n transport: new WebSocketTransport({\n pingInterval: ...,\n pingMaxRetries: ...,\n server: ...,\n verifyClient: ...\n })\n})`);\n logger.warn(\"\uD83D\uDC49 Documentation: https://docs.colyseus.io/server/transport/\")\n }\n\n const transport = options.transport || this.getDefaultTransport(options);\n\n this.transport = transport;\n\n if (this.transport.server) {\n // @ts-ignore\n this.transport.server.once('listening', () => this.registerProcessForDiscovery());\n this.attachMatchMakingRoutes(this.transport.server as http.Server);\n }\n }\n\n /**\n * Bind the server into the port specified.\n *\n * @param port\n * @param hostname\n * @param backlog\n * @param listeningListener\n */\n public async listen(port: number, hostname?: string, backlog?: number, listeningListener?: Function) {\n this.port = port;\n\n //\n // Make sure matchmaker is ready before accepting connections\n // (isDevMode: matchmaker may take extra milliseconds to restore the rooms)\n //\n await matchMaker.accept();\n\n /**\n * Greetings!\n */\n if (this.greet) {\n console.log(greeting);\n }\n\n return new Promise<void>((resolve, reject) => {\n // @ts-ignore\n this.transport.server?.on('error', (err) => reject(err));\n this.transport.listen(port, hostname, backlog, (err) => {\n if (listeningListener) {\n listeningListener(err);\n }\n\n if (err) {\n reject(err);\n\n } else {\n resolve();\n }\n });\n });\n }\n\n public async registerProcessForDiscovery() {\n // register node for proxy/service discovery\n await registerNode(this.presence, {\n port: this.port,\n processId: matchMaker.processId,\n });\n }\n\n /**\n * Define a new type of room for matchmaking.\n *\n * @param name public room identifier for match-making.\n * @param roomClass Room class definition\n * @param defaultOptions default options for `onCreate`\n */\n public define<T extends Type<Room>>(\n roomClass: T,\n defaultOptions?: Parameters<NonNullable<InstanceType<T>['onCreate']>>[0],\n ): RegisteredHandler\n public define<T extends Type<Room>>(\n name: string,\n roomClass: T,\n defaultOptions?: Parameters<NonNullable<InstanceType<T>['onCreate']>>[0],\n ): RegisteredHandler\n public define<T extends Type<Room>>(\n nameOrHandler: string | T,\n handlerOrOptions: T | Parameters<NonNullable<InstanceType<T>['onCreate']>>[0],\n defaultOptions?: Parameters<NonNullable<InstanceType<T>['onCreate']>>[0],\n ): RegisteredHandler {\n const name = (typeof(nameOrHandler) === \"string\")\n ? nameOrHandler\n : nameOrHandler.name;\n\n const roomClass = (typeof(nameOrHandler) === \"string\")\n ? handlerOrOptions\n : nameOrHandler;\n\n const options = (typeof(nameOrHandler) === \"string\")\n ? defaultOptions\n : handlerOrOptions;\n\n return matchMaker.defineRoomType(name, roomClass, options);\n }\n\n /**\n * Remove a room definition from matchmaking.\n * This method does not destroy any room. It only dissallows matchmaking\n */\n public removeRoomType(name: string): void {\n matchMaker.removeRoomType(name);\n }\n\n public async gracefullyShutdown(exit: boolean = true, err?: Error) {\n if (matchMaker.state === matchMaker.MatchMakerState.SHUTTING_DOWN) {\n return;\n }\n\n await unregisterNode(this.presence, {\n port: this.port,\n processId: matchMaker.processId,\n });\n\n try {\n // custom \"before shutdown\" method\n await this.onBeforeShutdownCallback();\n\n await matchMaker.gracefullyShutdown();\n this.transport.shutdown();\n this.presence.shutdown();\n this.driver.shutdown();\n\n // custom \"after shutdown\" method\n await this.onShutdownCallback();\n\n } catch (e) {\n debugAndPrintError(`error during shutdown: ${e}`);\n\n } finally {\n if (exit) {\n process.exit((err && !isDevMode) ? 1 : 0);\n }\n }\n }\n\n /**\n * Add simulated latency between client and server.\n * @param milliseconds round trip latency in milliseconds.\n */\n public simulateLatency(milliseconds: number) {\n if (milliseconds > 0) {\n logger.warn(`\uD83D\uDCF6\uFE0F\u2757 Colyseus latency simulation enabled \u2192 ${milliseconds}ms latency for round trip.`);\n } else {\n logger.warn(`\uD83D\uDCF6\uFE0F\u2757 Colyseus latency simulation disabled.`);\n }\n\n const halfwayMS = (milliseconds / 2);\n this.transport.simulateLatency(halfwayMS);\n\n if (this._originalRoomOnMessage == null) {\n /* tslint:disable:no-string-literal */\n this._originalRoomOnMessage = Room.prototype['_onMessage'];\n }\n\n const originalOnMessage = this._originalRoomOnMessage;\n\n /* tslint:disable:no-string-literal */\n Room.prototype['_onMessage'] = milliseconds <= Number.EPSILON ? originalOnMessage : function (client, buffer) {\n // uWebSockets.js: duplicate buffer because it is cleared at native layer before the timeout.\n const cachedBuffer = Buffer.from(buffer);\n setTimeout(() => originalOnMessage.call(this, client, cachedBuffer), halfwayMS);\n };\n }\n\n /**\n * Register a callback that is going to be executed before the server shuts down.\n * @param callback\n */\n public onShutdown(callback: () => void | Promise<any>) {\n this.onShutdownCallback = callback;\n }\n\n public onBeforeShutdown(callback: () => void | Promise<any>) {\n this.onBeforeShutdownCallback = callback;\n }\n\n protected getDefaultTransport(_: any): Transport {\n throw new Error(\"Please provide a 'transport' layer. Default transport not set.\");\n }\n\n protected onShutdownCallback: () => void | Promise<any> =\n () => Promise.resolve()\n\n protected onBeforeShutdownCallback: () => void | Promise<any> =\n () => Promise.resolve()\n\n protected attachMatchMakingRoutes(server: http.Server) {\n const listeners = server.listeners('request').slice(0);\n server.removeAllListeners('request');\n\n server.on('request', (req, res) => {\n if (req.url.indexOf(`/${matchMaker.controller.matchmakeRoute}`) !== -1) {\n debugMatchMaking('received matchmake request: %s', req.url);\n this.handleMatchMakeRequest(req, res);\n\n } else {\n for (let i = 0, l = listeners.length; i < l; i++) {\n listeners[i].call(server, req, res);\n }\n }\n });\n }\n\n protected async handleMatchMakeRequest(req: IncomingMessage, res: ServerResponse) {\n // do not accept matchmaking requests if already shutting down\n if (matchMaker.state === matchMaker.MatchMakerState.SHUTTING_DOWN) {\n res.writeHead(503, {});\n res.end();\n return;\n }\n\n const headers = Object.assign(\n {},\n matchMaker.controller.DEFAULT_CORS_HEADERS,\n matchMaker.controller.getCorsHeaders.call(undefined, req)\n );\n\n if (req.method === 'OPTIONS') {\n res.writeHead(204, headers);\n res.end();\n\n } else if (req.method === 'POST') {\n const matchedParams = req.url.match(matchMaker.controller.allowedRoomNameChars);\n const matchmakeIndex = matchedParams.indexOf(matchMaker.controller.matchmakeRoute);\n const method = matchedParams[matchmakeIndex + 1];\n const roomName = matchedParams[matchmakeIndex + 2] || '';\n\n const data = [];\n req.on('data', (chunk) => data.push(chunk));\n req.on('end', async () => {\n headers['Content-Type'] = 'application/json';\n res.writeHead(200, headers);\n\n try {\n const clientOptions = JSON.parse(Buffer.concat(data).toString());\n const response = await matchMaker.controller.invokeMethod(\n method,\n roomName,\n clientOptions,\n {\n token: getBearerToken(req.headers['authorization']),\n headers: req.headers,\n ip: req.headers['x-real-ip'] ?? req.headers['x-forwarded-for'] ?? req.socket.remoteAddress,\n req,\n },\n );\n\n // specify protocol, if available.\n if (this.transport.protocol !== undefined) {\n response.protocol = this.transport.protocol;\n }\n\n res.write(JSON.stringify(response));\n\n } catch (e) {\n res.write(JSON.stringify({ code: e.code, error: e.message, }));\n }\n\n res.end();\n });\n\n } else if (req.method === 'GET') {\n res.writeHead(404, headers);\n res.end();\n }\n\n }\n\n\n}\n"],
|
|
5
|
-
"mappings": "
|
|
6
|
-
"names": ["greeting"]
|
|
4
|
+
"sourcesContent": ["import greeting from \"@colyseus/greeting-banner\";\n\nimport { debugAndPrintError } from './Debug.ts';\nimport * as matchMaker from './MatchMaker.ts';\nimport { RegisteredHandler } from './matchmaker/RegisteredHandler.ts';\n\nimport { type OnCreateOptions, Room } from './Room.ts';\nimport { registerGracefulShutdown, type Type } from './utils/Utils.ts';\n\nimport type { Presence } from \"./presence/Presence.ts\";\nimport { LocalPresence } from './presence/LocalPresence.ts';\nimport { LocalDriver } from './matchmaker/LocalDriver/LocalDriver.ts';\n\nimport { Transport } from './Transport.ts';\nimport { logger, setLogger } from './Logger.ts';\nimport { setDevMode, isDevMode } from './utils/DevMode.ts';\nimport { bindRouterToServer, type Router } from './router/index.ts';\nimport { getDefaultRouter } from \"./router/default_routes.ts\";\n\nexport type ServerOptions = {\n publicAddress?: string,\n presence?: Presence,\n driver?: matchMaker.MatchMakerDriver,\n transport?: Transport,\n gracefullyShutdown?: boolean,\n logger?: any;\n\n /**\n * Custom function to determine which process should handle room creation.\n * Default: assign new rooms the process with least amount of rooms created\n */\n selectProcessIdToCreateRoom?: matchMaker.SelectProcessIdCallback;\n\n /**\n * If enabled, rooms are going to be restored in the server-side upon restart,\n * clients are going to automatically re-connect when server reboots.\n *\n * Beware of \"schema mismatch\" issues. When updating Schema structures and\n * reloading existing data, you may see \"schema mismatch\" errors in the\n * client-side.\n *\n * (This operation is costly and should not be used in a production\n * environment)\n */\n devMode?: boolean,\n\n /**\n * Display greeting message on server start.\n * Default: true\n */\n greet?: boolean,\n};\n\n/**\n * Exposed types for the client-side SDK.\n */\nexport interface SDKTypes<\n RoomTypes extends Record<string, RegisteredHandler> = any,\n Routes extends Router = any\n> {\n '~rooms': RoomTypes;\n '~routes': Routes;\n}\n\nexport class Server<\n RoomTypes extends Record<string, RegisteredHandler> = any,\n Routes extends Router = any\n> implements SDKTypes<RoomTypes, Routes> {\n '~rooms': RoomTypes;\n '~routes': Routes;\n\n public transport: Transport;\n public router: Routes;\n public options: ServerOptions;\n\n protected presence: Presence;\n protected driver: matchMaker.MatchMakerDriver;\n\n protected port: number;\n protected greet: boolean;\n\n private _originalRoomOnMessage: typeof Room.prototype['_onMessage'] | null = null;\n\n constructor(options: ServerOptions = {}) {\n const {\n gracefullyShutdown = true,\n greet = true\n } = options;\n\n setDevMode(options.devMode === true);\n\n this.presence = options.presence || new LocalPresence();\n this.driver = options.driver || new LocalDriver();\n this.options = options;\n this.greet = greet;\n\n this.attach(options);\n\n matchMaker.setup(\n this.presence,\n this.driver,\n options.publicAddress,\n options.selectProcessIdToCreateRoom,\n );\n\n if (gracefullyShutdown) {\n registerGracefulShutdown((err) => this.gracefullyShutdown(true, err));\n }\n\n if (options.logger) {\n setLogger(options.logger);\n }\n }\n\n public attach(options: ServerOptions) {\n this.transport = options.transport || this.getDefaultTransport(options);\n delete options.transport;\n }\n\n /**\n * Bind the server into the port specified.\n *\n * @param port\n * @param hostname\n * @param backlog\n * @param listeningListener\n */\n public async listen(port: number, hostname?: string, backlog?: number, listeningListener?: Function) {\n this.port = port;\n\n //\n // Make sure matchmaker is ready before accepting connections\n // (isDevMode: matchmaker may take extra milliseconds to restore the rooms)\n //\n await matchMaker.accept();\n\n /**\n * Greetings!\n */\n if (this.greet) {\n console.log(greeting);\n }\n\n return new Promise<void>((resolve, reject) => {\n this.transport.listen(port, hostname, backlog, (err) => {\n const server = this.transport.server;\n\n // default router is used if no router is provided\n if (!this.router) {\n this.router = getDefaultRouter() as unknown as Routes;\n\n } else {\n // make sure default routes are included\n // https://github.com/Bekacru/better-call/pull/67\n this.router = this.router.extend({ ...getDefaultRouter().endpoints }) as unknown as Routes;\n }\n\n if (server) {\n server.on('error', (err) => reject(err));\n bindRouterToServer(server, this.router);\n }\n\n if (listeningListener) {\n listeningListener(err);\n }\n\n if (err) {\n reject(err);\n\n } else {\n resolve();\n }\n });\n });\n }\n\n /**\n * Define a new type of room for matchmaking.\n *\n * @param name public room identifier for match-making.\n * @param roomClass Room class definition\n * @param defaultOptions default options for `onCreate`\n */\n public define<T extends Type<Room>>(\n roomClass: T,\n defaultOptions?: OnCreateOptions<T>,\n ): RegisteredHandler\n public define<T extends Type<Room>>(\n name: string,\n roomClass: T,\n defaultOptions?: OnCreateOptions<T>,\n ): RegisteredHandler\n public define<T extends Type<Room>>(\n nameOrHandler: string | T,\n handlerOrOptions: T | OnCreateOptions<T>,\n defaultOptions?: OnCreateOptions<T>,\n ): RegisteredHandler {\n const name = (typeof(nameOrHandler) === \"string\")\n ? nameOrHandler\n : nameOrHandler.name;\n\n const roomClass = (typeof(nameOrHandler) === \"string\")\n ? handlerOrOptions\n : nameOrHandler;\n\n const options = (typeof(nameOrHandler) === \"string\")\n ? defaultOptions\n : handlerOrOptions;\n\n return matchMaker.defineRoomType(name, roomClass, options);\n }\n\n /**\n * Remove a room definition from matchmaking.\n * This method does not destroy any room. It only dissallows matchmaking\n */\n public removeRoomType(name: string): void {\n matchMaker.removeRoomType(name);\n }\n\n public async gracefullyShutdown(exit: boolean = true, err?: Error) {\n if (matchMaker.state === matchMaker.MatchMakerState.SHUTTING_DOWN) {\n return;\n }\n\n try {\n // custom \"before shutdown\" method\n await this.onBeforeShutdownCallback();\n\n // this is going to lock all rooms and wait for them to be disposed\n await matchMaker.gracefullyShutdown();\n\n this.transport.shutdown();\n this.presence.shutdown();\n await this.driver.shutdown();\n\n // custom \"after shutdown\" method\n await this.onShutdownCallback();\n\n } catch (e) {\n debugAndPrintError(`error during shutdown: ${e}`);\n\n } finally {\n if (exit) {\n process.exit((err && !isDevMode) ? 1 : 0);\n }\n }\n }\n\n /**\n * Add simulated latency between client and server.\n * @param milliseconds round trip latency in milliseconds.\n */\n public simulateLatency(milliseconds: number) {\n if (milliseconds > 0) {\n logger.warn(`\uD83D\uDCF6\uFE0F\u2757 Colyseus latency simulation enabled \u2192 ${milliseconds}ms latency for round trip.`);\n } else {\n logger.warn(`\uD83D\uDCF6\uFE0F\u2757 Colyseus latency simulation disabled.`);\n }\n\n const halfwayMS = (milliseconds / 2);\n this.transport.simulateLatency(halfwayMS);\n\n if (this._originalRoomOnMessage == null) {\n this._originalRoomOnMessage = Room.prototype['_onMessage'];\n }\n\n const originalOnMessage = this._originalRoomOnMessage;\n\n Room.prototype['_onMessage'] = milliseconds <= Number.EPSILON ? originalOnMessage : function (this: Room, client, buffer) {\n // uWebSockets.js: duplicate buffer because it is cleared at native layer before the timeout.\n const cachedBuffer = Buffer.from(buffer);\n setTimeout(() => originalOnMessage.call(this, client, cachedBuffer), halfwayMS);\n };\n }\n\n /**\n * Register a callback that is going to be executed before the server shuts down.\n * @param callback\n */\n public onShutdown(callback: () => void | Promise<any>) {\n this.onShutdownCallback = callback;\n }\n\n public onBeforeShutdown(callback: () => void | Promise<any>) {\n this.onBeforeShutdownCallback = callback;\n }\n\n protected getDefaultTransport(_: any): Transport {\n throw new Error(\"Please provide a 'transport' layer. Default transport not set.\");\n }\n\n protected onShutdownCallback: () => void | Promise<any> =\n () => Promise.resolve()\n\n protected onBeforeShutdownCallback: () => void | Promise<any> =\n () => Promise.resolve()\n}\n\nexport function defineServer<\n T extends Record<string, RegisteredHandler>,\n R extends Router\n>(\n roomHandlers: T,\n router?: R,\n serverOptions?: ServerOptions\n): Server<T, R> {\n const server = new Server<T, R>(serverOptions);\n\n server.router = router;\n\n for (const [name, handler] of Object.entries(roomHandlers)) {\n handler.name = name;\n matchMaker.addRoomType(handler);\n }\n\n return server;\n}\n\nexport function defineRoom<T extends Type<Room>>(\n roomKlass: T,\n defaultOptions?: Parameters<NonNullable<InstanceType<T>['onCreate']>>[0],\n): RegisteredHandler<T> {\n return new RegisteredHandler(roomKlass, defaultOptions);\n}"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": ["greeting", "err"]
|
|
7
7
|
}
|
package/build/Server.mjs
CHANGED
|
@@ -1,24 +1,30 @@
|
|
|
1
1
|
// packages/core/src/Server.ts
|
|
2
2
|
import greeting from "@colyseus/greeting-banner";
|
|
3
|
-
import { debugAndPrintError
|
|
3
|
+
import { debugAndPrintError } from "./Debug.mjs";
|
|
4
4
|
import * as matchMaker from "./MatchMaker.mjs";
|
|
5
|
+
import { RegisteredHandler } from "./matchmaker/RegisteredHandler.mjs";
|
|
5
6
|
import { Room } from "./Room.mjs";
|
|
6
|
-
import {
|
|
7
|
-
import { registerNode, unregisterNode } from "./discovery/index.mjs";
|
|
7
|
+
import { registerGracefulShutdown } from "./utils/Utils.mjs";
|
|
8
8
|
import { LocalPresence } from "./presence/LocalPresence.mjs";
|
|
9
|
-
import { LocalDriver } from "./matchmaker/
|
|
9
|
+
import { LocalDriver } from "./matchmaker/LocalDriver/LocalDriver.mjs";
|
|
10
|
+
import "./Transport.mjs";
|
|
10
11
|
import { logger, setLogger } from "./Logger.mjs";
|
|
11
12
|
import { setDevMode, isDevMode } from "./utils/DevMode.mjs";
|
|
13
|
+
import { bindRouterToServer } from "./router/index.mjs";
|
|
14
|
+
import { getDefaultRouter } from "./router/default_routes.mjs";
|
|
12
15
|
var Server = class {
|
|
13
16
|
constructor(options = {}) {
|
|
14
|
-
//@ts-expect-error
|
|
15
17
|
this._originalRoomOnMessage = null;
|
|
16
18
|
this.onShutdownCallback = () => Promise.resolve();
|
|
17
19
|
this.onBeforeShutdownCallback = () => Promise.resolve();
|
|
18
|
-
const {
|
|
20
|
+
const {
|
|
21
|
+
gracefullyShutdown: gracefullyShutdown2 = true,
|
|
22
|
+
greet = true
|
|
23
|
+
} = options;
|
|
19
24
|
setDevMode(options.devMode === true);
|
|
20
25
|
this.presence = options.presence || new LocalPresence();
|
|
21
26
|
this.driver = options.driver || new LocalDriver();
|
|
27
|
+
this.options = options;
|
|
22
28
|
this.greet = greet;
|
|
23
29
|
this.attach(options);
|
|
24
30
|
matchMaker.setup(
|
|
@@ -35,24 +41,8 @@ var Server = class {
|
|
|
35
41
|
}
|
|
36
42
|
}
|
|
37
43
|
attach(options) {
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
logger.warn(`new Server({
|
|
41
|
-
transport: new WebSocketTransport({
|
|
42
|
-
pingInterval: ...,
|
|
43
|
-
pingMaxRetries: ...,
|
|
44
|
-
server: ...,
|
|
45
|
-
verifyClient: ...
|
|
46
|
-
})
|
|
47
|
-
})`);
|
|
48
|
-
logger.warn("\u{1F449} Documentation: https://docs.colyseus.io/server/transport/");
|
|
49
|
-
}
|
|
50
|
-
const transport = options.transport || this.getDefaultTransport(options);
|
|
51
|
-
this.transport = transport;
|
|
52
|
-
if (this.transport.server) {
|
|
53
|
-
this.transport.server.once("listening", () => this.registerProcessForDiscovery());
|
|
54
|
-
this.attachMatchMakingRoutes(this.transport.server);
|
|
55
|
-
}
|
|
44
|
+
this.transport = options.transport || this.getDefaultTransport(options);
|
|
45
|
+
delete options.transport;
|
|
56
46
|
}
|
|
57
47
|
/**
|
|
58
48
|
* Bind the server into the port specified.
|
|
@@ -69,8 +59,17 @@ var Server = class {
|
|
|
69
59
|
console.log(greeting);
|
|
70
60
|
}
|
|
71
61
|
return new Promise((resolve, reject) => {
|
|
72
|
-
this.transport.server?.on("error", (err) => reject(err));
|
|
73
62
|
this.transport.listen(port, hostname, backlog, (err) => {
|
|
63
|
+
const server = this.transport.server;
|
|
64
|
+
if (!this.router) {
|
|
65
|
+
this.router = getDefaultRouter();
|
|
66
|
+
} else {
|
|
67
|
+
this.router = this.router.extend({ ...getDefaultRouter().endpoints });
|
|
68
|
+
}
|
|
69
|
+
if (server) {
|
|
70
|
+
server.on("error", (err2) => reject(err2));
|
|
71
|
+
bindRouterToServer(server, this.router);
|
|
72
|
+
}
|
|
74
73
|
if (listeningListener) {
|
|
75
74
|
listeningListener(err);
|
|
76
75
|
}
|
|
@@ -82,12 +81,6 @@ var Server = class {
|
|
|
82
81
|
});
|
|
83
82
|
});
|
|
84
83
|
}
|
|
85
|
-
async registerProcessForDiscovery() {
|
|
86
|
-
await registerNode(this.presence, {
|
|
87
|
-
port: this.port,
|
|
88
|
-
processId: matchMaker.processId
|
|
89
|
-
});
|
|
90
|
-
}
|
|
91
84
|
define(nameOrHandler, handlerOrOptions, defaultOptions) {
|
|
92
85
|
const name = typeof nameOrHandler === "string" ? nameOrHandler : nameOrHandler.name;
|
|
93
86
|
const roomClass = typeof nameOrHandler === "string" ? handlerOrOptions : nameOrHandler;
|
|
@@ -105,16 +98,12 @@ var Server = class {
|
|
|
105
98
|
if (matchMaker.state === matchMaker.MatchMakerState.SHUTTING_DOWN) {
|
|
106
99
|
return;
|
|
107
100
|
}
|
|
108
|
-
await unregisterNode(this.presence, {
|
|
109
|
-
port: this.port,
|
|
110
|
-
processId: matchMaker.processId
|
|
111
|
-
});
|
|
112
101
|
try {
|
|
113
102
|
await this.onBeforeShutdownCallback();
|
|
114
103
|
await matchMaker.gracefullyShutdown();
|
|
115
104
|
this.transport.shutdown();
|
|
116
105
|
this.presence.shutdown();
|
|
117
|
-
this.driver.shutdown();
|
|
106
|
+
await this.driver.shutdown();
|
|
118
107
|
await this.onShutdownCallback();
|
|
119
108
|
} catch (e) {
|
|
120
109
|
debugAndPrintError(`error during shutdown: ${e}`);
|
|
@@ -158,72 +147,21 @@ var Server = class {
|
|
|
158
147
|
getDefaultTransport(_) {
|
|
159
148
|
throw new Error("Please provide a 'transport' layer. Default transport not set.");
|
|
160
149
|
}
|
|
161
|
-
attachMatchMakingRoutes(server) {
|
|
162
|
-
const listeners = server.listeners("request").slice(0);
|
|
163
|
-
server.removeAllListeners("request");
|
|
164
|
-
server.on("request", (req, res) => {
|
|
165
|
-
if (req.url.indexOf(`/${matchMaker.controller.matchmakeRoute}`) !== -1) {
|
|
166
|
-
debugMatchMaking("received matchmake request: %s", req.url);
|
|
167
|
-
this.handleMatchMakeRequest(req, res);
|
|
168
|
-
} else {
|
|
169
|
-
for (let i = 0, l = listeners.length; i < l; i++) {
|
|
170
|
-
listeners[i].call(server, req, res);
|
|
171
|
-
}
|
|
172
|
-
}
|
|
173
|
-
});
|
|
174
|
-
}
|
|
175
|
-
async handleMatchMakeRequest(req, res) {
|
|
176
|
-
if (matchMaker.state === matchMaker.MatchMakerState.SHUTTING_DOWN) {
|
|
177
|
-
res.writeHead(503, {});
|
|
178
|
-
res.end();
|
|
179
|
-
return;
|
|
180
|
-
}
|
|
181
|
-
const headers = Object.assign(
|
|
182
|
-
{},
|
|
183
|
-
matchMaker.controller.DEFAULT_CORS_HEADERS,
|
|
184
|
-
matchMaker.controller.getCorsHeaders.call(void 0, req)
|
|
185
|
-
);
|
|
186
|
-
if (req.method === "OPTIONS") {
|
|
187
|
-
res.writeHead(204, headers);
|
|
188
|
-
res.end();
|
|
189
|
-
} else if (req.method === "POST") {
|
|
190
|
-
const matchedParams = req.url.match(matchMaker.controller.allowedRoomNameChars);
|
|
191
|
-
const matchmakeIndex = matchedParams.indexOf(matchMaker.controller.matchmakeRoute);
|
|
192
|
-
const method = matchedParams[matchmakeIndex + 1];
|
|
193
|
-
const roomName = matchedParams[matchmakeIndex + 2] || "";
|
|
194
|
-
const data = [];
|
|
195
|
-
req.on("data", (chunk) => data.push(chunk));
|
|
196
|
-
req.on("end", async () => {
|
|
197
|
-
headers["Content-Type"] = "application/json";
|
|
198
|
-
res.writeHead(200, headers);
|
|
199
|
-
try {
|
|
200
|
-
const clientOptions = JSON.parse(Buffer.concat(data).toString());
|
|
201
|
-
const response = await matchMaker.controller.invokeMethod(
|
|
202
|
-
method,
|
|
203
|
-
roomName,
|
|
204
|
-
clientOptions,
|
|
205
|
-
{
|
|
206
|
-
token: getBearerToken(req.headers["authorization"]),
|
|
207
|
-
headers: req.headers,
|
|
208
|
-
ip: req.headers["x-real-ip"] ?? req.headers["x-forwarded-for"] ?? req.socket.remoteAddress,
|
|
209
|
-
req
|
|
210
|
-
}
|
|
211
|
-
);
|
|
212
|
-
if (this.transport.protocol !== void 0) {
|
|
213
|
-
response.protocol = this.transport.protocol;
|
|
214
|
-
}
|
|
215
|
-
res.write(JSON.stringify(response));
|
|
216
|
-
} catch (e) {
|
|
217
|
-
res.write(JSON.stringify({ code: e.code, error: e.message }));
|
|
218
|
-
}
|
|
219
|
-
res.end();
|
|
220
|
-
});
|
|
221
|
-
} else if (req.method === "GET") {
|
|
222
|
-
res.writeHead(404, headers);
|
|
223
|
-
res.end();
|
|
224
|
-
}
|
|
225
|
-
}
|
|
226
150
|
};
|
|
151
|
+
function defineServer(roomHandlers, router, serverOptions) {
|
|
152
|
+
const server = new Server(serverOptions);
|
|
153
|
+
server.router = router;
|
|
154
|
+
for (const [name, handler] of Object.entries(roomHandlers)) {
|
|
155
|
+
handler.name = name;
|
|
156
|
+
matchMaker.addRoomType(handler);
|
|
157
|
+
}
|
|
158
|
+
return server;
|
|
159
|
+
}
|
|
160
|
+
function defineRoom(roomKlass, defaultOptions) {
|
|
161
|
+
return new RegisteredHandler(roomKlass, defaultOptions);
|
|
162
|
+
}
|
|
227
163
|
export {
|
|
228
|
-
Server
|
|
164
|
+
Server,
|
|
165
|
+
defineRoom,
|
|
166
|
+
defineServer
|
|
229
167
|
};
|
package/build/Server.mjs.map
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../src/Server.ts"],
|
|
4
|
-
"sourcesContent": ["import http, { IncomingMessage, ServerResponse } from 'http';\nimport greeting from \"@colyseus/greeting-banner\";\n\nimport { debugAndPrintError, debugMatchMaking } from './Debug.js';\nimport * as matchMaker from './MatchMaker.js';\nimport { RegisteredHandler } from './matchmaker/RegisteredHandler.js';\nimport { Presence } from './presence/Presence.js';\n\nimport { Room } from './Room.js';\nimport { Type } from './utils/types.js';\nimport { getBearerToken, registerGracefulShutdown } from './utils/Utils.js';\n\nimport { registerNode, unregisterNode} from './discovery/index.js';\n\nimport { LocalPresence } from './presence/LocalPresence.js';\nimport { LocalDriver } from './matchmaker/driver/local/LocalDriver.js';\n\nimport { Transport } from './Transport.js';\nimport { logger, setLogger } from './Logger.js';\nimport { setDevMode, isDevMode } from './utils/DevMode.js';\n\nexport type ServerOptions = {\n publicAddress?: string,\n presence?: Presence,\n driver?: matchMaker.MatchMakerDriver,\n transport?: Transport,\n gracefullyShutdown?: boolean,\n logger?: any;\n\n /**\n * Custom function to determine which process should handle room creation.\n * Default: assign new rooms the process with least amount of rooms created\n */\n selectProcessIdToCreateRoom?: matchMaker.SelectProcessIdCallback;\n\n /**\n * If enabled, rooms are going to be restored in the server-side upon restart,\n * clients are going to automatically re-connect when server reboots.\n *\n * Beware of \"schema mismatch\" issues. When updating Schema structures and\n * reloading existing data, you may see \"schema mismatch\" errors in the\n * client-side.\n *\n * (This operation is costly and should not be used in a production\n * environment)\n */\n devMode?: boolean,\n\n /**\n * Display greeting message on server start.\n * Default: true\n */\n greet?: boolean,\n\n /**\n * Options below are now part of WebSocketTransport (@colyseus/ws-transport)\n * TODO: remove me on 0.15.0\n */\n /** @deprecated */\n pingInterval?: number,\n\n /** @deprecated */\n pingMaxRetries?: number,\n\n /** @deprecated */\n verifyClient?: any,\n\n /** @deprecated */\n server?: http.Server,\n};\n\nexport class Server {\n public transport: Transport;\n\n protected presence: Presence;\n protected driver: matchMaker.MatchMakerDriver;\n\n protected port: number;\n protected greet: boolean;\n\n //@ts-expect-error\n private _originalRoomOnMessage: typeof Room.prototype._onMessage | null = null;\n\n constructor(options: ServerOptions = {}) {\n const { gracefullyShutdown = true, greet = true } = options;\n\n setDevMode(options.devMode === true);\n\n this.presence = options.presence || new LocalPresence();\n this.driver = options.driver || new LocalDriver();\n this.greet = greet;\n\n this.attach(options);\n\n matchMaker.setup(\n this.presence,\n this.driver,\n options.publicAddress,\n options.selectProcessIdToCreateRoom,\n );\n\n if (gracefullyShutdown) {\n registerGracefulShutdown((err) => this.gracefullyShutdown(true, err));\n }\n\n if (options.logger) {\n setLogger(options.logger);\n }\n }\n\n public attach(options: ServerOptions) {\n /**\n * Display deprecation warnings for moved Transport options.\n * TODO: Remove me on 0.15\n */\n if (\n options.pingInterval !== undefined ||\n options.pingMaxRetries !== undefined ||\n options.server !== undefined ||\n options.verifyClient !== undefined\n ) {\n logger.warn(\"DEPRECATION WARNING: 'pingInterval', 'pingMaxRetries', 'server', and 'verifyClient' Server options will be permanently moved to WebSocketTransport on v0.15\");\n logger.warn(`new Server({\n transport: new WebSocketTransport({\n pingInterval: ...,\n pingMaxRetries: ...,\n server: ...,\n verifyClient: ...\n })\n})`);\n logger.warn(\"\uD83D\uDC49 Documentation: https://docs.colyseus.io/server/transport/\")\n }\n\n const transport = options.transport || this.getDefaultTransport(options);\n\n this.transport = transport;\n\n if (this.transport.server) {\n // @ts-ignore\n this.transport.server.once('listening', () => this.registerProcessForDiscovery());\n this.attachMatchMakingRoutes(this.transport.server as http.Server);\n }\n }\n\n /**\n * Bind the server into the port specified.\n *\n * @param port\n * @param hostname\n * @param backlog\n * @param listeningListener\n */\n public async listen(port: number, hostname?: string, backlog?: number, listeningListener?: Function) {\n this.port = port;\n\n //\n // Make sure matchmaker is ready before accepting connections\n // (isDevMode: matchmaker may take extra milliseconds to restore the rooms)\n //\n await matchMaker.accept();\n\n /**\n * Greetings!\n */\n if (this.greet) {\n console.log(greeting);\n }\n\n return new Promise<void>((resolve, reject) => {\n // @ts-ignore\n this.transport.server?.on('error', (err) => reject(err));\n this.transport.listen(port, hostname, backlog, (err) => {\n if (listeningListener) {\n listeningListener(err);\n }\n\n if (err) {\n reject(err);\n\n } else {\n resolve();\n }\n });\n });\n }\n\n public async registerProcessForDiscovery() {\n // register node for proxy/service discovery\n await registerNode(this.presence, {\n port: this.port,\n processId: matchMaker.processId,\n });\n }\n\n /**\n * Define a new type of room for matchmaking.\n *\n * @param name public room identifier for match-making.\n * @param roomClass Room class definition\n * @param defaultOptions default options for `onCreate`\n */\n public define<T extends Type<Room>>(\n roomClass: T,\n defaultOptions?: Parameters<NonNullable<InstanceType<T>['onCreate']>>[0],\n ): RegisteredHandler\n public define<T extends Type<Room>>(\n name: string,\n roomClass: T,\n defaultOptions?: Parameters<NonNullable<InstanceType<T>['onCreate']>>[0],\n ): RegisteredHandler\n public define<T extends Type<Room>>(\n nameOrHandler: string | T,\n handlerOrOptions: T | Parameters<NonNullable<InstanceType<T>['onCreate']>>[0],\n defaultOptions?: Parameters<NonNullable<InstanceType<T>['onCreate']>>[0],\n ): RegisteredHandler {\n const name = (typeof(nameOrHandler) === \"string\")\n ? nameOrHandler\n : nameOrHandler.name;\n\n const roomClass = (typeof(nameOrHandler) === \"string\")\n ? handlerOrOptions\n : nameOrHandler;\n\n const options = (typeof(nameOrHandler) === \"string\")\n ? defaultOptions\n : handlerOrOptions;\n\n return matchMaker.defineRoomType(name, roomClass, options);\n }\n\n /**\n * Remove a room definition from matchmaking.\n * This method does not destroy any room. It only dissallows matchmaking\n */\n public removeRoomType(name: string): void {\n matchMaker.removeRoomType(name);\n }\n\n public async gracefullyShutdown(exit: boolean = true, err?: Error) {\n if (matchMaker.state === matchMaker.MatchMakerState.SHUTTING_DOWN) {\n return;\n }\n\n await unregisterNode(this.presence, {\n port: this.port,\n processId: matchMaker.processId,\n });\n\n try {\n // custom \"before shutdown\" method\n await this.onBeforeShutdownCallback();\n\n await matchMaker.gracefullyShutdown();\n this.transport.shutdown();\n this.presence.shutdown();\n this.driver.shutdown();\n\n // custom \"after shutdown\" method\n await this.onShutdownCallback();\n\n } catch (e) {\n debugAndPrintError(`error during shutdown: ${e}`);\n\n } finally {\n if (exit) {\n process.exit((err && !isDevMode) ? 1 : 0);\n }\n }\n }\n\n /**\n * Add simulated latency between client and server.\n * @param milliseconds round trip latency in milliseconds.\n */\n public simulateLatency(milliseconds: number) {\n if (milliseconds > 0) {\n logger.warn(`\uD83D\uDCF6\uFE0F\u2757 Colyseus latency simulation enabled \u2192 ${milliseconds}ms latency for round trip.`);\n } else {\n logger.warn(`\uD83D\uDCF6\uFE0F\u2757 Colyseus latency simulation disabled.`);\n }\n\n const halfwayMS = (milliseconds / 2);\n this.transport.simulateLatency(halfwayMS);\n\n if (this._originalRoomOnMessage == null) {\n /* tslint:disable:no-string-literal */\n this._originalRoomOnMessage = Room.prototype['_onMessage'];\n }\n\n const originalOnMessage = this._originalRoomOnMessage;\n\n /* tslint:disable:no-string-literal */\n Room.prototype['_onMessage'] = milliseconds <= Number.EPSILON ? originalOnMessage : function (client, buffer) {\n // uWebSockets.js: duplicate buffer because it is cleared at native layer before the timeout.\n const cachedBuffer = Buffer.from(buffer);\n setTimeout(() => originalOnMessage.call(this, client, cachedBuffer), halfwayMS);\n };\n }\n\n /**\n * Register a callback that is going to be executed before the server shuts down.\n * @param callback\n */\n public onShutdown(callback: () => void | Promise<any>) {\n this.onShutdownCallback = callback;\n }\n\n public onBeforeShutdown(callback: () => void | Promise<any>) {\n this.onBeforeShutdownCallback = callback;\n }\n\n protected getDefaultTransport(_: any): Transport {\n throw new Error(\"Please provide a 'transport' layer. Default transport not set.\");\n }\n\n protected onShutdownCallback: () => void | Promise<any> =\n () => Promise.resolve()\n\n protected onBeforeShutdownCallback: () => void | Promise<any> =\n () => Promise.resolve()\n\n protected attachMatchMakingRoutes(server: http.Server) {\n const listeners = server.listeners('request').slice(0);\n server.removeAllListeners('request');\n\n server.on('request', (req, res) => {\n if (req.url.indexOf(`/${matchMaker.controller.matchmakeRoute}`) !== -1) {\n debugMatchMaking('received matchmake request: %s', req.url);\n this.handleMatchMakeRequest(req, res);\n\n } else {\n for (let i = 0, l = listeners.length; i < l; i++) {\n listeners[i].call(server, req, res);\n }\n }\n });\n }\n\n protected async handleMatchMakeRequest(req: IncomingMessage, res: ServerResponse) {\n // do not accept matchmaking requests if already shutting down\n if (matchMaker.state === matchMaker.MatchMakerState.SHUTTING_DOWN) {\n res.writeHead(503, {});\n res.end();\n return;\n }\n\n const headers = Object.assign(\n {},\n matchMaker.controller.DEFAULT_CORS_HEADERS,\n matchMaker.controller.getCorsHeaders.call(undefined, req)\n );\n\n if (req.method === 'OPTIONS') {\n res.writeHead(204, headers);\n res.end();\n\n } else if (req.method === 'POST') {\n const matchedParams = req.url.match(matchMaker.controller.allowedRoomNameChars);\n const matchmakeIndex = matchedParams.indexOf(matchMaker.controller.matchmakeRoute);\n const method = matchedParams[matchmakeIndex + 1];\n const roomName = matchedParams[matchmakeIndex + 2] || '';\n\n const data = [];\n req.on('data', (chunk) => data.push(chunk));\n req.on('end', async () => {\n headers['Content-Type'] = 'application/json';\n res.writeHead(200, headers);\n\n try {\n const clientOptions = JSON.parse(Buffer.concat(data).toString());\n const response = await matchMaker.controller.invokeMethod(\n method,\n roomName,\n clientOptions,\n {\n token: getBearerToken(req.headers['authorization']),\n headers: req.headers,\n ip: req.headers['x-real-ip'] ?? req.headers['x-forwarded-for'] ?? req.socket.remoteAddress,\n req,\n },\n );\n\n // specify protocol, if available.\n if (this.transport.protocol !== undefined) {\n response.protocol = this.transport.protocol;\n }\n\n res.write(JSON.stringify(response));\n\n } catch (e) {\n res.write(JSON.stringify({ code: e.code, error: e.message, }));\n }\n\n res.end();\n });\n\n } else if (req.method === 'GET') {\n res.writeHead(404, headers);\n res.end();\n }\n\n }\n\n\n}\n"],
|
|
5
|
-
"mappings": ";
|
|
6
|
-
"names": ["gracefullyShutdown"]
|
|
4
|
+
"sourcesContent": ["import greeting from \"@colyseus/greeting-banner\";\n\nimport { debugAndPrintError } from './Debug.ts';\nimport * as matchMaker from './MatchMaker.ts';\nimport { RegisteredHandler } from './matchmaker/RegisteredHandler.ts';\n\nimport { type OnCreateOptions, Room } from './Room.ts';\nimport { registerGracefulShutdown, type Type } from './utils/Utils.ts';\n\nimport type { Presence } from \"./presence/Presence.ts\";\nimport { LocalPresence } from './presence/LocalPresence.ts';\nimport { LocalDriver } from './matchmaker/LocalDriver/LocalDriver.ts';\n\nimport { Transport } from './Transport.ts';\nimport { logger, setLogger } from './Logger.ts';\nimport { setDevMode, isDevMode } from './utils/DevMode.ts';\nimport { bindRouterToServer, type Router } from './router/index.ts';\nimport { getDefaultRouter } from \"./router/default_routes.ts\";\n\nexport type ServerOptions = {\n publicAddress?: string,\n presence?: Presence,\n driver?: matchMaker.MatchMakerDriver,\n transport?: Transport,\n gracefullyShutdown?: boolean,\n logger?: any;\n\n /**\n * Custom function to determine which process should handle room creation.\n * Default: assign new rooms the process with least amount of rooms created\n */\n selectProcessIdToCreateRoom?: matchMaker.SelectProcessIdCallback;\n\n /**\n * If enabled, rooms are going to be restored in the server-side upon restart,\n * clients are going to automatically re-connect when server reboots.\n *\n * Beware of \"schema mismatch\" issues. When updating Schema structures and\n * reloading existing data, you may see \"schema mismatch\" errors in the\n * client-side.\n *\n * (This operation is costly and should not be used in a production\n * environment)\n */\n devMode?: boolean,\n\n /**\n * Display greeting message on server start.\n * Default: true\n */\n greet?: boolean,\n};\n\n/**\n * Exposed types for the client-side SDK.\n */\nexport interface SDKTypes<\n RoomTypes extends Record<string, RegisteredHandler> = any,\n Routes extends Router = any\n> {\n '~rooms': RoomTypes;\n '~routes': Routes;\n}\n\nexport class Server<\n RoomTypes extends Record<string, RegisteredHandler> = any,\n Routes extends Router = any\n> implements SDKTypes<RoomTypes, Routes> {\n '~rooms': RoomTypes;\n '~routes': Routes;\n\n public transport: Transport;\n public router: Routes;\n public options: ServerOptions;\n\n protected presence: Presence;\n protected driver: matchMaker.MatchMakerDriver;\n\n protected port: number;\n protected greet: boolean;\n\n private _originalRoomOnMessage: typeof Room.prototype['_onMessage'] | null = null;\n\n constructor(options: ServerOptions = {}) {\n const {\n gracefullyShutdown = true,\n greet = true\n } = options;\n\n setDevMode(options.devMode === true);\n\n this.presence = options.presence || new LocalPresence();\n this.driver = options.driver || new LocalDriver();\n this.options = options;\n this.greet = greet;\n\n this.attach(options);\n\n matchMaker.setup(\n this.presence,\n this.driver,\n options.publicAddress,\n options.selectProcessIdToCreateRoom,\n );\n\n if (gracefullyShutdown) {\n registerGracefulShutdown((err) => this.gracefullyShutdown(true, err));\n }\n\n if (options.logger) {\n setLogger(options.logger);\n }\n }\n\n public attach(options: ServerOptions) {\n this.transport = options.transport || this.getDefaultTransport(options);\n delete options.transport;\n }\n\n /**\n * Bind the server into the port specified.\n *\n * @param port\n * @param hostname\n * @param backlog\n * @param listeningListener\n */\n public async listen(port: number, hostname?: string, backlog?: number, listeningListener?: Function) {\n this.port = port;\n\n //\n // Make sure matchmaker is ready before accepting connections\n // (isDevMode: matchmaker may take extra milliseconds to restore the rooms)\n //\n await matchMaker.accept();\n\n /**\n * Greetings!\n */\n if (this.greet) {\n console.log(greeting);\n }\n\n return new Promise<void>((resolve, reject) => {\n this.transport.listen(port, hostname, backlog, (err) => {\n const server = this.transport.server;\n\n // default router is used if no router is provided\n if (!this.router) {\n this.router = getDefaultRouter() as unknown as Routes;\n\n } else {\n // make sure default routes are included\n // https://github.com/Bekacru/better-call/pull/67\n this.router = this.router.extend({ ...getDefaultRouter().endpoints }) as unknown as Routes;\n }\n\n if (server) {\n server.on('error', (err) => reject(err));\n bindRouterToServer(server, this.router);\n }\n\n if (listeningListener) {\n listeningListener(err);\n }\n\n if (err) {\n reject(err);\n\n } else {\n resolve();\n }\n });\n });\n }\n\n /**\n * Define a new type of room for matchmaking.\n *\n * @param name public room identifier for match-making.\n * @param roomClass Room class definition\n * @param defaultOptions default options for `onCreate`\n */\n public define<T extends Type<Room>>(\n roomClass: T,\n defaultOptions?: OnCreateOptions<T>,\n ): RegisteredHandler\n public define<T extends Type<Room>>(\n name: string,\n roomClass: T,\n defaultOptions?: OnCreateOptions<T>,\n ): RegisteredHandler\n public define<T extends Type<Room>>(\n nameOrHandler: string | T,\n handlerOrOptions: T | OnCreateOptions<T>,\n defaultOptions?: OnCreateOptions<T>,\n ): RegisteredHandler {\n const name = (typeof(nameOrHandler) === \"string\")\n ? nameOrHandler\n : nameOrHandler.name;\n\n const roomClass = (typeof(nameOrHandler) === \"string\")\n ? handlerOrOptions\n : nameOrHandler;\n\n const options = (typeof(nameOrHandler) === \"string\")\n ? defaultOptions\n : handlerOrOptions;\n\n return matchMaker.defineRoomType(name, roomClass, options);\n }\n\n /**\n * Remove a room definition from matchmaking.\n * This method does not destroy any room. It only dissallows matchmaking\n */\n public removeRoomType(name: string): void {\n matchMaker.removeRoomType(name);\n }\n\n public async gracefullyShutdown(exit: boolean = true, err?: Error) {\n if (matchMaker.state === matchMaker.MatchMakerState.SHUTTING_DOWN) {\n return;\n }\n\n try {\n // custom \"before shutdown\" method\n await this.onBeforeShutdownCallback();\n\n // this is going to lock all rooms and wait for them to be disposed\n await matchMaker.gracefullyShutdown();\n\n this.transport.shutdown();\n this.presence.shutdown();\n await this.driver.shutdown();\n\n // custom \"after shutdown\" method\n await this.onShutdownCallback();\n\n } catch (e) {\n debugAndPrintError(`error during shutdown: ${e}`);\n\n } finally {\n if (exit) {\n process.exit((err && !isDevMode) ? 1 : 0);\n }\n }\n }\n\n /**\n * Add simulated latency between client and server.\n * @param milliseconds round trip latency in milliseconds.\n */\n public simulateLatency(milliseconds: number) {\n if (milliseconds > 0) {\n logger.warn(`\uD83D\uDCF6\uFE0F\u2757 Colyseus latency simulation enabled \u2192 ${milliseconds}ms latency for round trip.`);\n } else {\n logger.warn(`\uD83D\uDCF6\uFE0F\u2757 Colyseus latency simulation disabled.`);\n }\n\n const halfwayMS = (milliseconds / 2);\n this.transport.simulateLatency(halfwayMS);\n\n if (this._originalRoomOnMessage == null) {\n this._originalRoomOnMessage = Room.prototype['_onMessage'];\n }\n\n const originalOnMessage = this._originalRoomOnMessage;\n\n Room.prototype['_onMessage'] = milliseconds <= Number.EPSILON ? originalOnMessage : function (this: Room, client, buffer) {\n // uWebSockets.js: duplicate buffer because it is cleared at native layer before the timeout.\n const cachedBuffer = Buffer.from(buffer);\n setTimeout(() => originalOnMessage.call(this, client, cachedBuffer), halfwayMS);\n };\n }\n\n /**\n * Register a callback that is going to be executed before the server shuts down.\n * @param callback\n */\n public onShutdown(callback: () => void | Promise<any>) {\n this.onShutdownCallback = callback;\n }\n\n public onBeforeShutdown(callback: () => void | Promise<any>) {\n this.onBeforeShutdownCallback = callback;\n }\n\n protected getDefaultTransport(_: any): Transport {\n throw new Error(\"Please provide a 'transport' layer. Default transport not set.\");\n }\n\n protected onShutdownCallback: () => void | Promise<any> =\n () => Promise.resolve()\n\n protected onBeforeShutdownCallback: () => void | Promise<any> =\n () => Promise.resolve()\n}\n\nexport function defineServer<\n T extends Record<string, RegisteredHandler>,\n R extends Router\n>(\n roomHandlers: T,\n router?: R,\n serverOptions?: ServerOptions\n): Server<T, R> {\n const server = new Server<T, R>(serverOptions);\n\n server.router = router;\n\n for (const [name, handler] of Object.entries(roomHandlers)) {\n handler.name = name;\n matchMaker.addRoomType(handler);\n }\n\n return server;\n}\n\nexport function defineRoom<T extends Type<Room>>(\n roomKlass: T,\n defaultOptions?: Parameters<NonNullable<InstanceType<T>['onCreate']>>[0],\n): RegisteredHandler<T> {\n return new RegisteredHandler(roomKlass, defaultOptions);\n}"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": ["gracefullyShutdown", "err"]
|
|
7
7
|
}
|
package/build/Stats.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
"use strict";
|
|
1
2
|
var __create = Object.create;
|
|
2
3
|
var __defProp = Object.defineProperty;
|
|
3
4
|
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
@@ -37,7 +38,7 @@ __export(Stats_exports, {
|
|
|
37
38
|
setAutoPersistInterval: () => setAutoPersistInterval
|
|
38
39
|
});
|
|
39
40
|
module.exports = __toCommonJS(Stats_exports);
|
|
40
|
-
var import_MatchMaker = require("./MatchMaker.
|
|
41
|
+
var import_MatchMaker = require("./MatchMaker.ts");
|
|
41
42
|
let local = {
|
|
42
43
|
roomCount: 0,
|
|
43
44
|
ccu: 0
|
package/build/Stats.js.map
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../src/Stats.ts"],
|
|
4
|
-
"sourcesContent": ["import { MatchMakerState, presence, processId, state } from './MatchMaker.
|
|
5
|
-
"mappings": "
|
|
4
|
+
"sourcesContent": ["import { MatchMakerState, presence, processId, state } from './MatchMaker.ts';\n\nexport type Stats = {\n roomCount: number;\n ccu: number;\n}\n\nexport let local: Stats = {\n roomCount: 0,\n ccu: 0,\n};\n\nexport async function fetchAll() {\n // TODO: cache this value to avoid querying too often\n const allStats: Array<Stats & { processId: string }> = [];\n const allProcesses = await presence.hgetall(getRoomCountKey());\n\n for (let remoteProcessId in allProcesses) {\n if (remoteProcessId === processId) {\n allStats.push({ processId, roomCount: local.roomCount, ccu: local.ccu, });\n\n } else {\n const [roomCount, ccu] = allProcesses[remoteProcessId].split(',').map(Number);\n allStats.push({ processId: remoteProcessId, roomCount, ccu });\n }\n }\n\n return allStats;\n}\n\nlet lastPersisted = 0;\nlet persistTimeout = undefined;\nconst persistInterval = 1000;\n\nexport function persist(forceNow: boolean = false) {\n // skip if shutting down\n if (state === MatchMakerState.SHUTTING_DOWN) {\n return;\n }\n\n /**\n * Avoid persisting more than once per second.\n */\n const now = Date.now();\n\n if (forceNow || (now - lastPersisted > persistInterval)) {\n lastPersisted = now;\n return presence.hset(getRoomCountKey(), processId, `${local.roomCount},${local.ccu}`);\n\n } else {\n clearTimeout(persistTimeout);\n persistTimeout = setTimeout(persist, persistInterval);\n }\n}\n\nexport function reset(_persist: boolean = true) {\n local.roomCount = 0;\n local.ccu = 0;\n\n if (_persist) {\n lastPersisted = 0;\n clearTimeout(persistTimeout);\n persist();\n }\n\n //\n // Attach local metrics to PM2 (if available)\n //\n import('@pm2/io').then((io) => {\n io.default.metric({ id: 'app/stats/ccu', name: 'ccu', value: () => local.ccu });\n io.default.metric({ id: 'app/stats/roomcount', name: 'roomcount', value: () => local.roomCount });\n }).catch(() => { });\n}\n\nexport function excludeProcess(_processId: string) {\n return presence.hdel(getRoomCountKey(), _processId);\n}\n\nexport async function getGlobalCCU() {\n const allStats = await fetchAll();\n return allStats.reduce((prev, next) => prev + next.ccu, 0);\n}\n\n/**\n * Auto-persist every minute.\n */\nlet autoPersistInterval = undefined;\n\nexport function setAutoPersistInterval() {\n const interval = 60 * 1000;// 1 minute\n\n autoPersistInterval = setInterval(() => {\n const now = Date.now();\n\n if (now - lastPersisted > interval) {\n persist();\n }\n }, interval);\n}\n\nexport function clearAutoPersistInterval() {\n clearInterval(autoPersistInterval);\n}\n\nfunction getRoomCountKey() {\n return 'roomcount';\n}"],
|
|
5
|
+
"mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,wBAA4D;AAOrD,IAAI,QAAe;AAAA,EACxB,WAAW;AAAA,EACX,KAAK;AACP;AAEA,eAAsB,WAAW;AAE/B,QAAM,WAAiD,CAAC;AACxD,QAAM,eAAe,MAAM,2BAAS,QAAQ,gBAAgB,CAAC;AAE7D,WAAS,mBAAmB,cAAc;AACxC,QAAI,oBAAoB,6BAAW;AACjC,eAAS,KAAK,EAAE,wCAAW,WAAW,MAAM,WAAW,KAAK,MAAM,IAAK,CAAC;AAAA,IAE1E,OAAO;AACL,YAAM,CAAC,WAAW,GAAG,IAAI,aAAa,eAAe,EAAE,MAAM,GAAG,EAAE,IAAI,MAAM;AAC5E,eAAS,KAAK,EAAE,WAAW,iBAAiB,WAAW,IAAI,CAAC;AAAA,IAC9D;AAAA,EACF;AAEA,SAAO;AACT;AAEA,IAAI,gBAAgB;AACpB,IAAI,iBAAiB;AACrB,MAAM,kBAAkB;AAEjB,SAAS,QAAQ,WAAoB,OAAO;AAEjD,MAAI,4BAAU,kCAAgB,eAAe;AAC3C;AAAA,EACF;AAKA,QAAM,MAAM,KAAK,IAAI;AAErB,MAAI,YAAa,MAAM,gBAAgB,iBAAkB;AACvD,oBAAgB;AAChB,WAAO,2BAAS,KAAK,gBAAgB,GAAG,6BAAW,GAAG,MAAM,SAAS,IAAI,MAAM,GAAG,EAAE;AAAA,EAEtF,OAAO;AACL,iBAAa,cAAc;AAC3B,qBAAiB,WAAW,SAAS,eAAe;AAAA,EACtD;AACF;AAEO,SAAS,MAAM,WAAoB,MAAM;AAC9C,QAAM,YAAY;AAClB,QAAM,MAAM;AAEZ,MAAI,UAAU;AACZ,oBAAgB;AAChB,iBAAa,cAAc;AAC3B,YAAQ;AAAA,EACV;AAKA,SAAO,SAAS,EAAE,KAAK,CAAC,OAAO;AAC7B,OAAG,QAAQ,OAAO,EAAE,IAAI,iBAAiB,MAAM,OAAO,OAAO,MAAM,MAAM,IAAI,CAAC;AAC9E,OAAG,QAAQ,OAAO,EAAE,IAAI,uBAAuB,MAAM,aAAa,OAAO,MAAM,MAAM,UAAU,CAAC;AAAA,EAClG,CAAC,EAAE,MAAM,MAAM;AAAA,EAAE,CAAC;AACpB;AAEO,SAAS,eAAe,YAAoB;AACjD,SAAO,2BAAS,KAAK,gBAAgB,GAAG,UAAU;AACpD;AAEA,eAAsB,eAAe;AACnC,QAAM,WAAW,MAAM,SAAS;AAChC,SAAO,SAAS,OAAO,CAAC,MAAM,SAAS,OAAO,KAAK,KAAK,CAAC;AAC3D;AAKA,IAAI,sBAAsB;AAEnB,SAAS,yBAAyB;AACvC,QAAM,WAAW,KAAK;AAEtB,wBAAsB,YAAY,MAAM;AACtC,UAAM,MAAM,KAAK,IAAI;AAErB,QAAI,MAAM,gBAAgB,UAAU;AAClC,cAAQ;AAAA,IACV;AAAA,EACF,GAAG,QAAQ;AACb;AAEO,SAAS,2BAA2B;AACzC,gBAAc,mBAAmB;AACnC;AAEA,SAAS,kBAAkB;AACzB,SAAO;AACT;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
package/build/Stats.mjs.map
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../src/Stats.ts"],
|
|
4
|
-
"sourcesContent": ["import { MatchMakerState, presence, processId, state } from './MatchMaker.
|
|
4
|
+
"sourcesContent": ["import { MatchMakerState, presence, processId, state } from './MatchMaker.ts';\n\nexport type Stats = {\n roomCount: number;\n ccu: number;\n}\n\nexport let local: Stats = {\n roomCount: 0,\n ccu: 0,\n};\n\nexport async function fetchAll() {\n // TODO: cache this value to avoid querying too often\n const allStats: Array<Stats & { processId: string }> = [];\n const allProcesses = await presence.hgetall(getRoomCountKey());\n\n for (let remoteProcessId in allProcesses) {\n if (remoteProcessId === processId) {\n allStats.push({ processId, roomCount: local.roomCount, ccu: local.ccu, });\n\n } else {\n const [roomCount, ccu] = allProcesses[remoteProcessId].split(',').map(Number);\n allStats.push({ processId: remoteProcessId, roomCount, ccu });\n }\n }\n\n return allStats;\n}\n\nlet lastPersisted = 0;\nlet persistTimeout = undefined;\nconst persistInterval = 1000;\n\nexport function persist(forceNow: boolean = false) {\n // skip if shutting down\n if (state === MatchMakerState.SHUTTING_DOWN) {\n return;\n }\n\n /**\n * Avoid persisting more than once per second.\n */\n const now = Date.now();\n\n if (forceNow || (now - lastPersisted > persistInterval)) {\n lastPersisted = now;\n return presence.hset(getRoomCountKey(), processId, `${local.roomCount},${local.ccu}`);\n\n } else {\n clearTimeout(persistTimeout);\n persistTimeout = setTimeout(persist, persistInterval);\n }\n}\n\nexport function reset(_persist: boolean = true) {\n local.roomCount = 0;\n local.ccu = 0;\n\n if (_persist) {\n lastPersisted = 0;\n clearTimeout(persistTimeout);\n persist();\n }\n\n //\n // Attach local metrics to PM2 (if available)\n //\n import('@pm2/io').then((io) => {\n io.default.metric({ id: 'app/stats/ccu', name: 'ccu', value: () => local.ccu });\n io.default.metric({ id: 'app/stats/roomcount', name: 'roomcount', value: () => local.roomCount });\n }).catch(() => { });\n}\n\nexport function excludeProcess(_processId: string) {\n return presence.hdel(getRoomCountKey(), _processId);\n}\n\nexport async function getGlobalCCU() {\n const allStats = await fetchAll();\n return allStats.reduce((prev, next) => prev + next.ccu, 0);\n}\n\n/**\n * Auto-persist every minute.\n */\nlet autoPersistInterval = undefined;\n\nexport function setAutoPersistInterval() {\n const interval = 60 * 1000;// 1 minute\n\n autoPersistInterval = setInterval(() => {\n const now = Date.now();\n\n if (now - lastPersisted > interval) {\n persist();\n }\n }, interval);\n}\n\nexport function clearAutoPersistInterval() {\n clearInterval(autoPersistInterval);\n}\n\nfunction getRoomCountKey() {\n return 'roomcount';\n}"],
|
|
5
5
|
"mappings": ";AAAA,SAAS,iBAAiB,UAAU,WAAW,aAAa;AAOrD,IAAI,QAAe;AAAA,EACxB,WAAW;AAAA,EACX,KAAK;AACP;AAEA,eAAsB,WAAW;AAE/B,QAAM,WAAiD,CAAC;AACxD,QAAM,eAAe,MAAM,SAAS,QAAQ,gBAAgB,CAAC;AAE7D,WAAS,mBAAmB,cAAc;AACxC,QAAI,oBAAoB,WAAW;AACjC,eAAS,KAAK,EAAE,WAAW,WAAW,MAAM,WAAW,KAAK,MAAM,IAAK,CAAC;AAAA,IAE1E,OAAO;AACL,YAAM,CAAC,WAAW,GAAG,IAAI,aAAa,eAAe,EAAE,MAAM,GAAG,EAAE,IAAI,MAAM;AAC5E,eAAS,KAAK,EAAE,WAAW,iBAAiB,WAAW,IAAI,CAAC;AAAA,IAC9D;AAAA,EACF;AAEA,SAAO;AACT;AAEA,IAAI,gBAAgB;AACpB,IAAI,iBAAiB;AACrB,IAAM,kBAAkB;AAEjB,SAAS,QAAQ,WAAoB,OAAO;AAEjD,MAAI,UAAU,gBAAgB,eAAe;AAC3C;AAAA,EACF;AAKA,QAAM,MAAM,KAAK,IAAI;AAErB,MAAI,YAAa,MAAM,gBAAgB,iBAAkB;AACvD,oBAAgB;AAChB,WAAO,SAAS,KAAK,gBAAgB,GAAG,WAAW,GAAG,MAAM,SAAS,IAAI,MAAM,GAAG,EAAE;AAAA,EAEtF,OAAO;AACL,iBAAa,cAAc;AAC3B,qBAAiB,WAAW,SAAS,eAAe;AAAA,EACtD;AACF;AAEO,SAAS,MAAM,WAAoB,MAAM;AAC9C,QAAM,YAAY;AAClB,QAAM,MAAM;AAEZ,MAAI,UAAU;AACZ,oBAAgB;AAChB,iBAAa,cAAc;AAC3B,YAAQ;AAAA,EACV;AAKA,SAAO,SAAS,EAAE,KAAK,CAAC,OAAO;AAC7B,OAAG,QAAQ,OAAO,EAAE,IAAI,iBAAiB,MAAM,OAAO,OAAO,MAAM,MAAM,IAAI,CAAC;AAC9E,OAAG,QAAQ,OAAO,EAAE,IAAI,uBAAuB,MAAM,aAAa,OAAO,MAAM,MAAM,UAAU,CAAC;AAAA,EAClG,CAAC,EAAE,MAAM,MAAM;AAAA,EAAE,CAAC;AACpB;AAEO,SAAS,eAAe,YAAoB;AACjD,SAAO,SAAS,KAAK,gBAAgB,GAAG,UAAU;AACpD;AAEA,eAAsB,eAAe;AACnC,QAAM,WAAW,MAAM,SAAS;AAChC,SAAO,SAAS,OAAO,CAAC,MAAM,SAAS,OAAO,KAAK,KAAK,CAAC;AAC3D;AAKA,IAAI,sBAAsB;AAEnB,SAAS,yBAAyB;AACvC,QAAM,WAAW,KAAK;AAEtB,wBAAsB,YAAY,MAAM;AACtC,UAAM,MAAM,KAAK,IAAI;AAErB,QAAI,MAAM,gBAAgB,UAAU;AAClC,cAAQ;AAAA,IACV;AAAA,EACF,GAAG,QAAQ;AACb;AAEO,SAAS,2BAA2B;AACzC,gBAAc,mBAAmB;AACnC;AAEA,SAAS,kBAAkB;AACzB,SAAO;AACT;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
package/build/Transport.js
CHANGED
|
@@ -1,6 +1,9 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __create = Object.create;
|
|
1
3
|
var __defProp = Object.defineProperty;
|
|
2
4
|
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
3
5
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
4
7
|
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
5
8
|
var __export = (target, all) => {
|
|
6
9
|
for (var name in all)
|
|
@@ -14,25 +17,33 @@ var __copyProps = (to, from, except, desc) => {
|
|
|
14
17
|
}
|
|
15
18
|
return to;
|
|
16
19
|
};
|
|
20
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
21
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
22
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
23
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
24
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
25
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
26
|
+
mod
|
|
27
|
+
));
|
|
17
28
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
18
29
|
var Transport_exports = {};
|
|
19
30
|
__export(Transport_exports, {
|
|
20
31
|
ClientArray: () => ClientArray,
|
|
21
32
|
ClientState: () => ClientState,
|
|
22
|
-
Transport: () => Transport
|
|
33
|
+
Transport: () => Transport,
|
|
34
|
+
connectClientToRoom: () => connectClientToRoom
|
|
23
35
|
});
|
|
24
36
|
module.exports = __toCommonJS(Transport_exports);
|
|
25
|
-
var
|
|
37
|
+
var http = __toESM(require("http"), 1);
|
|
38
|
+
var https = __toESM(require("https"), 1);
|
|
39
|
+
var import_schema = require("@colyseus/schema");
|
|
40
|
+
var import_events = require("events");
|
|
41
|
+
var import_Utils = require("./utils/Utils.ts");
|
|
42
|
+
var import_ServerError = require("./errors/ServerError.ts");
|
|
43
|
+
var import_Protocol = require("./Protocol.ts");
|
|
26
44
|
class Transport {
|
|
27
45
|
}
|
|
28
|
-
|
|
29
|
-
ClientState2[ClientState2["JOINING"] = 0] = "JOINING";
|
|
30
|
-
ClientState2[ClientState2["JOINED"] = 1] = "JOINED";
|
|
31
|
-
ClientState2[ClientState2["RECONNECTED"] = 2] = "RECONNECTED";
|
|
32
|
-
ClientState2[ClientState2["LEAVING"] = 3] = "LEAVING";
|
|
33
|
-
ClientState2[ClientState2["CLOSED"] = 4] = "CLOSED";
|
|
34
|
-
return ClientState2;
|
|
35
|
-
})(ClientState || {});
|
|
46
|
+
const ClientState = { JOINING: 0, JOINED: 1, RECONNECTED: 2, LEAVING: 3, CLOSED: 4 };
|
|
36
47
|
class ClientArray extends Array {
|
|
37
48
|
getById(sessionId) {
|
|
38
49
|
return this.find((client) => client.sessionId === sessionId);
|
|
@@ -41,9 +52,16 @@ class ClientArray extends Array {
|
|
|
41
52
|
return (0, import_Utils.spliceOne)(this, this.indexOf(client));
|
|
42
53
|
}
|
|
43
54
|
}
|
|
55
|
+
async function connectClientToRoom(room, client, authContext, connectionOptions) {
|
|
56
|
+
if (!room || !room.hasReservedSeat(client.sessionId, connectionOptions.reconnectionToken)) {
|
|
57
|
+
throw new import_ServerError.ServerError(import_Protocol.ErrorCode.MATCHMAKE_EXPIRED, "seat reservation expired.");
|
|
58
|
+
}
|
|
59
|
+
await room["_onJoin"](client, authContext, connectionOptions);
|
|
60
|
+
}
|
|
44
61
|
// Annotate the CommonJS export names for ESM import in node:
|
|
45
62
|
0 && (module.exports = {
|
|
46
63
|
ClientArray,
|
|
47
64
|
ClientState,
|
|
48
|
-
Transport
|
|
65
|
+
Transport,
|
|
66
|
+
connectClientToRoom
|
|
49
67
|
});
|
package/build/Transport.js.map
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../src/Transport.ts"],
|
|
4
|
-
"sourcesContent": ["import * as http from 'http';\nimport * as https from 'https';\
|
|
5
|
-
"mappings": "
|
|
6
|
-
"names": [
|
|
4
|
+
"sourcesContent": ["import * as http from 'http';\nimport * as https from 'https';\n\nimport { StateView } from '@colyseus/schema';\nimport { EventEmitter } from 'events';\nimport { spliceOne } from './utils/Utils.ts';\nimport { ServerError } from './errors/ServerError.ts';\nimport { ErrorCode } from './Protocol.ts';\nimport type { Room } from './Room.ts';\n\nexport abstract class Transport {\n public protocol?: string;\n public server?: http.Server | https.Server;\n\n public abstract listen(port?: number, hostname?: string, backlog?: number, listeningListener?: Function): this;\n public abstract shutdown(): void;\n\n public abstract simulateLatency(milliseconds: number): void;\n}\n\nexport type AuthContext = {\n token?: string,\n headers: Headers,\n ip: string | string[];\n // FIXME: each transport may have its own specific properties.\n // \"req\" only applies to WebSocketTransport.\n req?: any;\n};\n\nexport interface ISendOptions {\n afterNextPatch?: boolean;\n}\n\nexport const ClientState = { JOINING: 0, JOINED: 1, RECONNECTED: 2, LEAVING: 3, CLOSED: 4 } as const;\nexport type ClientState = (typeof ClientState)[keyof typeof ClientState];\n\n// Helper types to extract properties from the Client type parameter\ntype ExtractClientUserData<T> = T extends { userData: infer U } ? U : T;\ntype ExtractClientAuth<T> = T extends { auth: infer A } ? A : any;\ntype ExtractClientMessages<T> = T extends { messages: infer M } ? M : any;\n\n// Helper type to make message required when the message type demands it\nexport type MessageArgs<M, Options> =\n unknown extends M ? [message?: M, options?: Options] : // Handle 'any' type (backwards compatibility)\n [M] extends [never] ? [message?: M, options?: Options] :\n [M] extends [void] ? [message?: M, options?: Options] :\n [M] extends [undefined] ? [message?: M, options?: Options] :\n undefined extends M ? [message?: M, options?: Options] :\n [message: M, options?: Options];\n\n/**\n * The client instance from the server-side is responsible for the transport layer between the server and the client.\n * It should not be confused with the Client from the client-side SDK, as they have completely different purposes!\n * You operate on client instances from `this.clients`, `Room#onJoin()`, `Room#onLeave()` and `Room#onMessage()`.\n *\n * - This is the raw WebSocket connection coming from the `ws` package. There are more methods available which aren't\n * encouraged to use along with Colyseus.\n */\nexport interface Client<T extends { userData?: any, auth?: any, messages?: Record<string | number, any> } = any> {\n '~messages': ExtractClientMessages<T>;\n\n ref: EventEmitter;\n\n /**\n * @deprecated use `sessionId` instead.\n */\n id: string;\n\n /**\n * Unique id per session.\n */\n sessionId: string; // TODO: remove sessionId on version 1.0.0\n\n /**\n * Connection state\n */\n state: ClientState;\n\n /**\n * Optional: when using `@view()` decorator in your state properties, this will be the view instance for this client.\n */\n view?: StateView;\n\n /**\n * User-defined data can be attached to the Client instance through this variable.\n * - Can be used to store custom data about the client's connection. userData is not synchronized with the client,\n * and should be used only to keep player-specific with its connection.\n */\n userData?: ExtractClientUserData<T>;\n\n /**\n * auth data provided by your `onAuth`\n */\n auth?: ExtractClientAuth<T>;\n\n /**\n * Reconnection token used to re-join the room after onLeave + allowReconnection().\n *\n * IMPORTANT:\n * This is not the full reconnection token the client provides for the server.\n * The format provided by .reconnect() from the client-side must follow: \"${roomId}:${reconnectionToken}\"\n */\n reconnectionToken: string;\n\n // TODO: move these to ClientPrivate\n raw(data: Uint8Array | Buffer, options?: ISendOptions, cb?: (err?: Error) => void): void;\n enqueueRaw(data: Uint8Array | Buffer, options?: ISendOptions): void;\n\n /**\n * Send a type of message to the client. Messages are encoded with MsgPack and can hold any\n * JSON-serializable data structure.\n *\n * @param type String or Number identifier the client SDK will use to receive this message\n * @param message Message payload. (automatically encoded with msgpack.)\n * @param options\n */\n send<K extends keyof this['~messages']>(\n type: K,\n ...args: MessageArgs<this['~messages'][K], ISendOptions>\n ): void;\n\n /**\n * Send raw bytes to this specific client.\n *\n * @param type String or Number identifier the client SDK will use to receive this message\n * @param bytes Raw byte array payload\n * @param options\n */\n sendBytes(type: string | number, bytes: Buffer | Uint8Array, options?: ISendOptions): void;\n\n /**\n * Disconnect this client from the room.\n *\n * @param code Custom close code. Default value is 1000.\n * @param data\n * @see [Leave room](https://docs.colyseus.io/room#leave-room)\n */\n leave(code?: number, data?: string): void;\n\n /**\n * @deprecated Use .leave() instead.\n */\n close(code?: number, data?: string): void;\n\n /**\n * Triggers `onError` with specified code to the client-side.\n *\n * @param code\n * @param message\n */\n error(code: number, message?: string): void;\n}\n\n/**\n * Private properties of the Client instance.\n * Only accessible internally by the framework, should not be encouraged/auto-completed for the user.\n *\n * TODO: refactor this.\n * @private\n */\nexport interface ClientPrivate {\n readyState: number; // TODO: remove readyState on version 1.0.0. Use only \"state\" instead.\n _enqueuedMessages?: any[];\n _afterNextPatchQueue: Array<[string | number | Client, ArrayLike<any>]>;\n _joinedAt: number; // \"elapsedTime\" when the client joined the room.\n\n /**\n * Used for rate limiting via maxMessagesPerSecond.\n */\n _numMessagesLastSecond?: number;\n _lastMessageTime?: number;\n}\n\nexport class ClientArray<C extends Client = Client> extends Array<C> {\n public getById(sessionId: string): C | undefined {\n return this.find((client) => client.sessionId === sessionId);\n }\n\n public delete(client: C): boolean {\n return spliceOne(this, this.indexOf(client));\n }\n}\n\n/**\n * Shared internal method to connect a Client into a Room.\n * Validates seat reservation and joins the client to the room.\n *\n * @remarks\n * **\u26A0\uFE0F This is an internal API and not intended for end-user use.**\n *\n * @internal\n */\nexport async function connectClientToRoom(\n room: Room | undefined,\n client: Client & ClientPrivate,\n authContext: AuthContext,\n connectionOptions: {\n reconnectionToken?: string;\n skipHandshake?: boolean;\n },\n): Promise<void> {\n if (!room || !room.hasReservedSeat(client.sessionId, connectionOptions.reconnectionToken)) {\n throw new ServerError(ErrorCode.MATCHMAKE_EXPIRED, 'seat reservation expired.');\n }\n\n await room['_onJoin'](client, authContext, connectionOptions);\n}"],
|
|
5
|
+
"mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,WAAsB;AACtB,YAAuB;AAEvB,oBAA0B;AAC1B,oBAA6B;AAC7B,mBAA0B;AAC1B,yBAA4B;AAC5B,sBAA0B;AAGnB,MAAe,UAAU;AAQhC;AAeO,MAAM,cAAc,EAAE,SAAS,GAAG,QAAQ,GAAG,aAAa,GAAG,SAAS,GAAG,QAAQ,EAAE;AA4InF,MAAM,oBAA+C,MAAS;AAAA,EAC5D,QAAQ,WAAkC;AAC/C,WAAO,KAAK,KAAK,CAAC,WAAW,OAAO,cAAc,SAAS;AAAA,EAC7D;AAAA,EAEO,OAAO,QAAoB;AAChC,eAAO,wBAAU,MAAM,KAAK,QAAQ,MAAM,CAAC;AAAA,EAC7C;AACF;AAWA,eAAsB,oBACpB,MACA,QACA,aACA,mBAIe;AACf,MAAI,CAAC,QAAQ,CAAC,KAAK,gBAAgB,OAAO,WAAW,kBAAkB,iBAAiB,GAAG;AACzF,UAAM,IAAI,+BAAY,0BAAU,mBAAmB,2BAA2B;AAAA,EAChF;AAEA,QAAM,KAAK,SAAS,EAAE,QAAQ,aAAa,iBAAiB;AAC9D;",
|
|
6
|
+
"names": []
|
|
7
7
|
}
|
package/build/Transport.mjs
CHANGED
|
@@ -1,15 +1,14 @@
|
|
|
1
1
|
// packages/core/src/Transport.ts
|
|
2
|
+
import "http";
|
|
3
|
+
import "https";
|
|
4
|
+
import "@colyseus/schema";
|
|
5
|
+
import "events";
|
|
2
6
|
import { spliceOne } from "./utils/Utils.mjs";
|
|
7
|
+
import { ServerError } from "./errors/ServerError.mjs";
|
|
8
|
+
import { ErrorCode } from "./Protocol.mjs";
|
|
3
9
|
var Transport = class {
|
|
4
10
|
};
|
|
5
|
-
var ClientState =
|
|
6
|
-
ClientState2[ClientState2["JOINING"] = 0] = "JOINING";
|
|
7
|
-
ClientState2[ClientState2["JOINED"] = 1] = "JOINED";
|
|
8
|
-
ClientState2[ClientState2["RECONNECTED"] = 2] = "RECONNECTED";
|
|
9
|
-
ClientState2[ClientState2["LEAVING"] = 3] = "LEAVING";
|
|
10
|
-
ClientState2[ClientState2["CLOSED"] = 4] = "CLOSED";
|
|
11
|
-
return ClientState2;
|
|
12
|
-
})(ClientState || {});
|
|
11
|
+
var ClientState = { JOINING: 0, JOINED: 1, RECONNECTED: 2, LEAVING: 3, CLOSED: 4 };
|
|
13
12
|
var ClientArray = class extends Array {
|
|
14
13
|
getById(sessionId) {
|
|
15
14
|
return this.find((client) => client.sessionId === sessionId);
|
|
@@ -18,8 +17,15 @@ var ClientArray = class extends Array {
|
|
|
18
17
|
return spliceOne(this, this.indexOf(client));
|
|
19
18
|
}
|
|
20
19
|
};
|
|
20
|
+
async function connectClientToRoom(room, client, authContext, connectionOptions) {
|
|
21
|
+
if (!room || !room.hasReservedSeat(client.sessionId, connectionOptions.reconnectionToken)) {
|
|
22
|
+
throw new ServerError(ErrorCode.MATCHMAKE_EXPIRED, "seat reservation expired.");
|
|
23
|
+
}
|
|
24
|
+
await room["_onJoin"](client, authContext, connectionOptions);
|
|
25
|
+
}
|
|
21
26
|
export {
|
|
22
27
|
ClientArray,
|
|
23
28
|
ClientState,
|
|
24
|
-
Transport
|
|
29
|
+
Transport,
|
|
30
|
+
connectClientToRoom
|
|
25
31
|
};
|