@colyseus/core 0.14.34 → 0.14.36

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.
@@ -136,7 +136,7 @@ async function remoteRoomCall(roomId, method, args, rejectionTimeout = Utils.REM
136
136
  else {
137
137
  return (!args && typeof (room[method]) !== 'function')
138
138
  ? room[method]
139
- : (await room[method].apply(room, args));
139
+ : (await room[method].apply(room, args && args.map((arg) => JSON.parse(JSON.stringify(arg)))));
140
140
  }
141
141
  }
142
142
  function defineRoomType(name, klass, defaultOptions) {
@@ -1 +1 @@
1
- {"version":3,"file":"MatchMaker.js","sources":["../src/MatchMaker.ts"],"sourcesContent":["import { ErrorCode } from './Protocol';\n\nimport { requestFromIPC, subscribeIPC } from './IPC';\nimport { generateId, merge, REMOTE_ROOM_SHORT_TIMEOUT, retry } from './Utils';\n\nimport { RegisteredHandler } from './matchmaker/RegisteredHandler';\nimport { Room, RoomInternalState } from './Room';\n\nimport { LocalPresence } from './presence/LocalPresence';\nimport { Presence } from './presence/Presence';\n\nimport { debugAndPrintError, debugMatchMaking } from './Debug';\nimport { SeatReservationError } from './errors/SeatReservationError';\nimport { ServerError } from './errors/ServerError';\n\nimport { IRoomListingData, MatchMakerDriver, RoomListingData, LocalDriver } from './matchmaker/driver';\nimport * as controller from './matchmaker/controller';\n\nimport { Client } from './Transport';\nimport { Type } from './types';\n\nexport { MatchMakerDriver, controller };\n\nexport type ClientOptions = any;\n\nexport interface SeatReservation {\n sessionId: string;\n room: RoomListingData;\n}\n\nconst handlers: {[id: string]: RegisteredHandler} = {};\nconst rooms: {[roomId: string]: Room} = {};\n\nexport let processId: string;\nexport let presence: Presence;\nexport let driver: MatchMakerDriver;\n\nlet isGracefullyShuttingDown: boolean;\n\nexport function setup(_presence?: Presence, _driver?: MatchMakerDriver, _processId?: string) {\n presence = _presence || new LocalPresence();\n driver = _driver || new LocalDriver();\n processId = _processId;\n isGracefullyShuttingDown = false;\n\n /**\n * Subscribe to remote `handleCreateRoom` calls.\n */\n subscribeIPC(presence, processId, getProcessChannel(), (_, args) => {\n return handleCreateRoom.apply(undefined, args);\n });\n\n presence.hset(getRoomCountKey(), processId, '0');\n}\n\n/**\n * Join or create into a room and return seat reservation\n */\nexport async function joinOrCreate(roomName: string, clientOptions: ClientOptions = {}) {\n return await retry<Promise<SeatReservation>>(async () => {\n let room = await findOneRoomAvailable(roomName, clientOptions);\n\n if (!room) {\n room = await createRoom(roomName, clientOptions);\n }\n\n return await reserveSeatFor(room, clientOptions);\n }, 5, [SeatReservationError]);\n}\n\n/**\n * Create a room and return seat reservation\n */\nexport async function create(roomName: string, clientOptions: ClientOptions = {}) {\n const room = await createRoom(roomName, clientOptions);\n return reserveSeatFor(room, clientOptions);\n}\n\n/**\n * Join a room and return seat reservation\n */\nexport async function join(roomName: string, clientOptions: ClientOptions = {}) {\n return await retry<Promise<SeatReservation>>(async () => {\n const room = await findOneRoomAvailable(roomName, clientOptions);\n\n if (!room) {\n throw new ServerError(ErrorCode.MATCHMAKE_INVALID_CRITERIA, `no rooms found with provided criteria`);\n }\n\n return reserveSeatFor(room, clientOptions);\n });\n}\n\n/**\n * Join a room by id and return seat reservation\n */\nexport async function joinById(roomId: string, clientOptions: ClientOptions = {}) {\n const room = await driver.findOne({ roomId });\n\n if (room) {\n const rejoinSessionId = clientOptions.sessionId;\n\n if (rejoinSessionId) {\n // handle re-connection!\n const hasReservedSeat = await remoteRoomCall(room.roomId, 'hasReservedSeat', [rejoinSessionId]);\n\n if (hasReservedSeat) {\n return { room, sessionId: rejoinSessionId };\n\n } else {\n throw new ServerError(ErrorCode.MATCHMAKE_EXPIRED, `session expired: ${rejoinSessionId}`);\n\n }\n\n } else if (!room.locked) {\n return reserveSeatFor(room, clientOptions);\n\n } else {\n throw new ServerError( ErrorCode.MATCHMAKE_INVALID_ROOM_ID, `room \"${roomId}\" is locked`);\n\n }\n\n } else {\n throw new ServerError( ErrorCode.MATCHMAKE_INVALID_ROOM_ID, `room \"${roomId}\" not found`);\n }\n\n}\n\n/**\n * Perform a query for all cached rooms\n */\nexport async function query(conditions: Partial<IRoomListingData> = {}) {\n return await driver.find(conditions);\n}\n\n/**\n * Find for a public and unlocked room available\n */\nexport async function findOneRoomAvailable(roomName: string, clientOptions: ClientOptions): Promise<RoomListingData> {\n return await awaitRoomAvailable(roomName, async () => {\n const handler = handlers[roomName];\n if (!handler) {\n throw new ServerError( ErrorCode.MATCHMAKE_NO_HANDLER, `provided room name \"${roomName}\" not defined`);\n }\n\n const roomQuery = driver.findOne({\n locked: false,\n name: roomName,\n private: false,\n ...handler.getFilterOptions(clientOptions),\n });\n\n if (handler.sortOptions) {\n roomQuery.sort(handler.sortOptions);\n }\n\n return await roomQuery;\n });\n}\n\n/**\n * Call a method or return a property on a remote room.\n */\nexport async function remoteRoomCall<R= any>(\n roomId: string,\n method: string,\n args?: any[],\n rejectionTimeout = REMOTE_ROOM_SHORT_TIMEOUT,\n): Promise<R> {\n const room = rooms[roomId];\n\n if (!room) {\n try {\n return await requestFromIPC<R>(presence, getRoomChannel(roomId), method, args);\n\n } catch (e) {\n const request = `${method}${args && ' with args ' + JSON.stringify(args) || ''}`;\n throw new ServerError(\n ErrorCode.MATCHMAKE_UNHANDLED,\n `remote room (${roomId}) timed out, requesting \"${request}\". (${rejectionTimeout}ms exceeded)`,\n );\n }\n\n } else {\n return (!args && typeof (room[method]) !== 'function')\n ? room[method]\n : (await room[method].apply(room, args));\n }\n}\n\nexport function defineRoomType<T extends Type<Room>>(\n name: string,\n klass: T,\n defaultOptions?: Parameters<NonNullable<InstanceType<T>['onCreate']>>[0],\n) {\n const registeredHandler = new RegisteredHandler(klass, defaultOptions);\n\n handlers[name] = registeredHandler;\n\n cleanupStaleRooms(name);\n\n return registeredHandler;\n}\n\nexport function removeRoomType(name: string) {\n delete handlers[name];\n cleanupStaleRooms(name);\n}\n\nexport function hasHandler(name: string) {\n return handlers[ name ] !== undefined;\n}\n\n/**\n * Create a room\n */\nexport async function createRoom(roomName: string, clientOptions: ClientOptions): Promise<RoomListingData> {\n const roomsSpawnedByProcessId = await presence.hgetall(getRoomCountKey());\n\n const processIdWithFewerRooms = (\n Object.keys(roomsSpawnedByProcessId).sort((p1, p2) => {\n return (Number(roomsSpawnedByProcessId[p1]) > Number(roomsSpawnedByProcessId[p2]))\n ? 1\n : -1;\n })[0]\n ) || processId;\n\n if (processIdWithFewerRooms === processId) {\n // create the room on this process!\n return await handleCreateRoom(roomName, clientOptions);\n\n } else {\n // ask other process to create the room!\n let room: RoomListingData;\n\n try {\n room = await requestFromIPC<RoomListingData>(\n presence,\n getProcessChannel(processIdWithFewerRooms),\n undefined,\n [roomName, clientOptions],\n REMOTE_ROOM_SHORT_TIMEOUT,\n );\n\n } catch (e) {\n // if other process failed to respond, create the room on this process\n debugAndPrintError(e);\n room = await handleCreateRoom(roomName, clientOptions);\n }\n\n return room;\n }\n}\n\nasync function handleCreateRoom(roomName: string, clientOptions: ClientOptions): Promise<RoomListingData> {\n const registeredHandler = handlers[roomName];\n\n if (!registeredHandler) {\n throw new ServerError( ErrorCode.MATCHMAKE_NO_HANDLER, `provided room name \"${roomName}\" not defined`);\n }\n\n const room = new registeredHandler.klass();\n\n // set room public attributes\n room.roomId = generateId();\n room.roomName = roomName;\n room.presence = presence;\n\n // create a RoomCache reference.\n room.listing = driver.createInstance({\n name: roomName,\n processId,\n ...registeredHandler.getFilterOptions(clientOptions),\n });\n\n if (room.onCreate) {\n try {\n await room.onCreate(merge({}, clientOptions, registeredHandler.options));\n\n // increment amount of rooms this process is handling\n presence.hincrby(getRoomCountKey(), processId, 1);\n\n } catch (e) {\n debugAndPrintError(e);\n throw new ServerError(\n e.code || ErrorCode.MATCHMAKE_UNHANDLED,\n e.message,\n );\n }\n }\n\n room.internalState = RoomInternalState.CREATED;\n\n room.listing.roomId = room.roomId;\n room.listing.maxClients = room.maxClients;\n\n // imediatelly ask client to join the room\n debugMatchMaking('spawning \\'%s\\', roomId: %s, processId: %s', roomName, room.roomId, processId);\n\n room._events.on('lock', lockRoom.bind(this, room));\n room._events.on('unlock', unlockRoom.bind(this, room));\n room._events.on('join', onClientJoinRoom.bind(this, room));\n room._events.on('leave', onClientLeaveRoom.bind(this, room));\n room._events.once('dispose', disposeRoom.bind(this, roomName, room));\n room._events.once('disconnect', () => room._events.removeAllListeners());\n\n // room always start unlocked\n await createRoomReferences(room, true);\n await room.listing.save();\n\n registeredHandler.emit('create', room);\n\n return room.listing;\n}\n\nexport function getRoomById(roomId: string) {\n return rooms[roomId];\n}\n\n/**\n * Disconnects every client on every room in the current process.\n */\nexport function disconnectAll() {\n const promises: Array<Promise<any>> = [];\n\n for (const roomId in rooms) {\n if (!rooms.hasOwnProperty(roomId)) { continue; }\n promises.push(rooms[roomId].disconnect());\n }\n\n return promises;\n}\n\nexport function gracefullyShutdown(): Promise<any> {\n if (isGracefullyShuttingDown) {\n return Promise.reject('already_shutting_down');\n }\n\n isGracefullyShuttingDown = true;\n\n debugMatchMaking(`${processId} is shutting down!`);\n\n // remove processId from room count key\n presence.hdel(getRoomCountKey(), processId);\n\n // unsubscribe from process id channel\n presence.unsubscribe(getProcessChannel());\n\n return Promise.all(disconnectAll());\n}\n\n/**\n * Reserve a seat for a client in a room\n */\nexport async function reserveSeatFor(room: RoomListingData, options: any) {\n const sessionId: string = generateId();\n\n debugMatchMaking(\n 'reserving seat. sessionId: \\'%s\\', roomId: \\'%s\\', processId: \\'%s\\'',\n sessionId, room.roomId, processId,\n );\n\n let successfulSeatReservation: boolean;\n\n try {\n successfulSeatReservation = await remoteRoomCall(room.roomId, '_reserveSeat', [sessionId, options]);\n\n } catch (e) {\n debugMatchMaking(e);\n successfulSeatReservation = false;\n }\n\n if (!successfulSeatReservation) {\n throw new SeatReservationError(`${room.roomId} is already full.`);\n }\n\n return { room, sessionId };\n}\n\nasync function cleanupStaleRooms(roomName: string) {\n //\n // clean-up possibly stale room ids\n // (ungraceful shutdowns using Redis can result on stale room ids still on memory.)\n //\n const cachedRooms = await driver.find({ name: roomName }, { _id: 1 });\n\n // remove connecting counts\n await presence.del(getHandlerConcurrencyKey(roomName));\n\n await Promise.all(cachedRooms.map(async (room) => {\n try {\n // use hardcoded short timeout for cleaning up stale rooms.\n await remoteRoomCall(room.roomId, 'roomId');\n\n } catch (e) {\n debugMatchMaking(`cleaning up stale room '${roomName}', roomId: ${room.roomId}`);\n room.remove();\n }\n }));\n}\n\nasync function createRoomReferences(room: Room, init: boolean = false): Promise<boolean> {\n rooms[room.roomId] = room;\n\n if (init) {\n await subscribeIPC(\n presence,\n processId,\n getRoomChannel(room.roomId),\n (method, args) => {\n return (!args && typeof (room[method]) !== 'function')\n ? room[method]\n : room[method].apply(room, args);\n },\n );\n }\n\n return true;\n}\n\nasync function awaitRoomAvailable(roomToJoin: string, callback: Function): Promise<RoomListingData> {\n return new Promise(async (resolve, reject) => {\n const concurrencyKey = getHandlerConcurrencyKey(roomToJoin);\n const concurrency = await presence.incr(concurrencyKey) - 1;\n\n // avoid having too long timeout if 10+ clients ask to join at the same time\n const concurrencyTimeout = Math.min(concurrency * 100, REMOTE_ROOM_SHORT_TIMEOUT);\n\n if (concurrency > 0) {\n debugMatchMaking(\n 'receiving %d concurrent requests for joining \\'%s\\' (waiting %d ms)',\n concurrency, roomToJoin, concurrencyTimeout,\n );\n }\n\n setTimeout(async () => {\n try {\n const result = await callback();\n resolve(result);\n\n } catch (e) {\n reject(e);\n\n } finally {\n await presence.decr(concurrencyKey);\n }\n }, concurrencyTimeout);\n });\n}\n\nfunction onClientJoinRoom(room: Room, client: Client) {\n handlers[room.roomName].emit('join', room, client);\n}\n\nfunction onClientLeaveRoom(room: Room, client: Client, willDispose: boolean) {\n handlers[room.roomName].emit('leave', room, client, willDispose);\n}\n\nfunction lockRoom(room: Room): void {\n // emit public event on registered handler\n handlers[room.roomName].emit('lock', room);\n}\n\nasync function unlockRoom(room: Room) {\n if (await createRoomReferences(room)) {\n // emit public event on registered handler\n handlers[room.roomName].emit('unlock', room);\n }\n}\n\nasync function disposeRoom(roomName: string, room: Room) {\n debugMatchMaking('disposing \\'%s\\' (%s) on processId \\'%s\\'', roomName, room.roomId, processId);\n\n // decrease amount of rooms this process is handling\n if (!isGracefullyShuttingDown) {\n presence.hincrby(getRoomCountKey(), processId, -1);\n }\n\n // remove from room listing (already removed if `disconnect()` has been called)\n if (room.internalState !== RoomInternalState.DISCONNECTING) {\n await room.listing.remove();\n }\n\n // emit disposal on registered session handler\n handlers[roomName].emit('dispose', room);\n\n // remove concurrency key\n presence.del(getHandlerConcurrencyKey(roomName));\n\n // unsubscribe from remote connections\n presence.unsubscribe(getRoomChannel(room.roomId));\n\n // remove actual room reference\n delete rooms[room.roomId];\n}\n\n//\n// Presence keys\n//\n\nfunction getRoomChannel(roomId: string) {\n return `$${roomId}`;\n}\n\nfunction getHandlerConcurrencyKey(name: string) {\n return `c:${name}`;\n}\n\nfunction getProcessChannel(id: string = processId) {\n return `p:${id}`;\n}\n\nfunction getRoomCountKey() {\n return 'roomcount';\n}\n"],"names":["processId","presence","driver","LocalPresence","LocalDriver","subscribeIPC","retry","SeatReservationError","ServerError","ErrorCode","REMOTE_ROOM_SHORT_TIMEOUT","requestFromIPC","RegisteredHandler","debugAndPrintError","generateId","merge","RoomInternalState","debugMatchMaking"],"mappings":"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"}
1
+ {"version":3,"file":"MatchMaker.js","sources":["../src/MatchMaker.ts"],"sourcesContent":["import { ErrorCode } from './Protocol';\n\nimport { requestFromIPC, subscribeIPC } from './IPC';\nimport { generateId, merge, REMOTE_ROOM_SHORT_TIMEOUT, retry } from './Utils';\n\nimport { RegisteredHandler } from './matchmaker/RegisteredHandler';\nimport { Room, RoomInternalState } from './Room';\n\nimport { LocalPresence } from './presence/LocalPresence';\nimport { Presence } from './presence/Presence';\n\nimport { debugAndPrintError, debugMatchMaking } from './Debug';\nimport { SeatReservationError } from './errors/SeatReservationError';\nimport { ServerError } from './errors/ServerError';\n\nimport { IRoomListingData, MatchMakerDriver, RoomListingData, LocalDriver } from './matchmaker/driver';\nimport * as controller from './matchmaker/controller';\n\nimport { Client } from './Transport';\nimport { Type } from './types';\n\nexport { MatchMakerDriver, controller };\n\nexport type ClientOptions = any;\n\nexport interface SeatReservation {\n sessionId: string;\n room: RoomListingData;\n}\n\nconst handlers: {[id: string]: RegisteredHandler} = {};\nconst rooms: {[roomId: string]: Room} = {};\n\nexport let processId: string;\nexport let presence: Presence;\nexport let driver: MatchMakerDriver;\n\nlet isGracefullyShuttingDown: boolean;\n\nexport function setup(_presence?: Presence, _driver?: MatchMakerDriver, _processId?: string) {\n presence = _presence || new LocalPresence();\n driver = _driver || new LocalDriver();\n processId = _processId;\n isGracefullyShuttingDown = false;\n\n /**\n * Subscribe to remote `handleCreateRoom` calls.\n */\n subscribeIPC(presence, processId, getProcessChannel(), (_, args) => {\n return handleCreateRoom.apply(undefined, args);\n });\n\n presence.hset(getRoomCountKey(), processId, '0');\n}\n\n/**\n * Join or create into a room and return seat reservation\n */\nexport async function joinOrCreate(roomName: string, clientOptions: ClientOptions = {}) {\n return await retry<Promise<SeatReservation>>(async () => {\n let room = await findOneRoomAvailable(roomName, clientOptions);\n\n if (!room) {\n room = await createRoom(roomName, clientOptions);\n }\n\n return await reserveSeatFor(room, clientOptions);\n }, 5, [SeatReservationError]);\n}\n\n/**\n * Create a room and return seat reservation\n */\nexport async function create(roomName: string, clientOptions: ClientOptions = {}) {\n const room = await createRoom(roomName, clientOptions);\n return reserveSeatFor(room, clientOptions);\n}\n\n/**\n * Join a room and return seat reservation\n */\nexport async function join(roomName: string, clientOptions: ClientOptions = {}) {\n return await retry<Promise<SeatReservation>>(async () => {\n const room = await findOneRoomAvailable(roomName, clientOptions);\n\n if (!room) {\n throw new ServerError(ErrorCode.MATCHMAKE_INVALID_CRITERIA, `no rooms found with provided criteria`);\n }\n\n return reserveSeatFor(room, clientOptions);\n });\n}\n\n/**\n * Join a room by id and return seat reservation\n */\nexport async function joinById(roomId: string, clientOptions: ClientOptions = {}) {\n const room = await driver.findOne({ roomId });\n\n if (room) {\n const rejoinSessionId = clientOptions.sessionId;\n\n if (rejoinSessionId) {\n // handle re-connection!\n const hasReservedSeat = await remoteRoomCall(room.roomId, 'hasReservedSeat', [rejoinSessionId]);\n\n if (hasReservedSeat) {\n return { room, sessionId: rejoinSessionId };\n\n } else {\n throw new ServerError(ErrorCode.MATCHMAKE_EXPIRED, `session expired: ${rejoinSessionId}`);\n\n }\n\n } else if (!room.locked) {\n return reserveSeatFor(room, clientOptions);\n\n } else {\n throw new ServerError( ErrorCode.MATCHMAKE_INVALID_ROOM_ID, `room \"${roomId}\" is locked`);\n\n }\n\n } else {\n throw new ServerError( ErrorCode.MATCHMAKE_INVALID_ROOM_ID, `room \"${roomId}\" not found`);\n }\n\n}\n\n/**\n * Perform a query for all cached rooms\n */\nexport async function query(conditions: Partial<IRoomListingData> = {}) {\n return await driver.find(conditions);\n}\n\n/**\n * Find for a public and unlocked room available\n */\nexport async function findOneRoomAvailable(roomName: string, clientOptions: ClientOptions): Promise<RoomListingData> {\n return await awaitRoomAvailable(roomName, async () => {\n const handler = handlers[roomName];\n if (!handler) {\n throw new ServerError( ErrorCode.MATCHMAKE_NO_HANDLER, `provided room name \"${roomName}\" not defined`);\n }\n\n const roomQuery = driver.findOne({\n locked: false,\n name: roomName,\n private: false,\n ...handler.getFilterOptions(clientOptions),\n });\n\n if (handler.sortOptions) {\n roomQuery.sort(handler.sortOptions);\n }\n\n return await roomQuery;\n });\n}\n\n/**\n * Call a method or return a property on a remote room.\n */\nexport async function remoteRoomCall<R= any>(\n roomId: string,\n method: string,\n args?: any[],\n rejectionTimeout = REMOTE_ROOM_SHORT_TIMEOUT,\n): Promise<R> {\n const room = rooms[roomId];\n\n if (!room) {\n try {\n return await requestFromIPC<R>(presence, getRoomChannel(roomId), method, args);\n\n } catch (e) {\n const request = `${method}${args && ' with args ' + JSON.stringify(args) || ''}`;\n throw new ServerError(\n ErrorCode.MATCHMAKE_UNHANDLED,\n `remote room (${roomId}) timed out, requesting \"${request}\". (${rejectionTimeout}ms exceeded)`,\n );\n }\n\n } else {\n return (!args && typeof (room[method]) !== 'function')\n ? room[method]\n : (await room[method].apply(room, args && args.map((arg) => JSON.parse(JSON.stringify(arg)))));\n }\n}\n\nexport function defineRoomType<T extends Type<Room>>(\n name: string,\n klass: T,\n defaultOptions?: Parameters<NonNullable<InstanceType<T>['onCreate']>>[0],\n) {\n const registeredHandler = new RegisteredHandler(klass, defaultOptions);\n\n handlers[name] = registeredHandler;\n\n cleanupStaleRooms(name);\n\n return registeredHandler;\n}\n\nexport function removeRoomType(name: string) {\n delete handlers[name];\n cleanupStaleRooms(name);\n}\n\nexport function hasHandler(name: string) {\n return handlers[ name ] !== undefined;\n}\n\n/**\n * Create a room\n */\nexport async function createRoom(roomName: string, clientOptions: ClientOptions): Promise<RoomListingData> {\n const roomsSpawnedByProcessId = await presence.hgetall(getRoomCountKey());\n\n const processIdWithFewerRooms = (\n Object.keys(roomsSpawnedByProcessId).sort((p1, p2) => {\n return (Number(roomsSpawnedByProcessId[p1]) > Number(roomsSpawnedByProcessId[p2]))\n ? 1\n : -1;\n })[0]\n ) || processId;\n\n if (processIdWithFewerRooms === processId) {\n // create the room on this process!\n return await handleCreateRoom(roomName, clientOptions);\n\n } else {\n // ask other process to create the room!\n let room: RoomListingData;\n\n try {\n room = await requestFromIPC<RoomListingData>(\n presence,\n getProcessChannel(processIdWithFewerRooms),\n undefined,\n [roomName, clientOptions],\n REMOTE_ROOM_SHORT_TIMEOUT,\n );\n\n } catch (e) {\n // if other process failed to respond, create the room on this process\n debugAndPrintError(e);\n room = await handleCreateRoom(roomName, clientOptions);\n }\n\n return room;\n }\n}\n\nasync function handleCreateRoom(roomName: string, clientOptions: ClientOptions): Promise<RoomListingData> {\n const registeredHandler = handlers[roomName];\n\n if (!registeredHandler) {\n throw new ServerError( ErrorCode.MATCHMAKE_NO_HANDLER, `provided room name \"${roomName}\" not defined`);\n }\n\n const room = new registeredHandler.klass();\n\n // set room public attributes\n room.roomId = generateId();\n room.roomName = roomName;\n room.presence = presence;\n\n // create a RoomCache reference.\n room.listing = driver.createInstance({\n name: roomName,\n processId,\n ...registeredHandler.getFilterOptions(clientOptions),\n });\n\n if (room.onCreate) {\n try {\n await room.onCreate(merge({}, clientOptions, registeredHandler.options));\n\n // increment amount of rooms this process is handling\n presence.hincrby(getRoomCountKey(), processId, 1);\n\n } catch (e) {\n debugAndPrintError(e);\n throw new ServerError(\n e.code || ErrorCode.MATCHMAKE_UNHANDLED,\n e.message,\n );\n }\n }\n\n room.internalState = RoomInternalState.CREATED;\n\n room.listing.roomId = room.roomId;\n room.listing.maxClients = room.maxClients;\n\n // imediatelly ask client to join the room\n debugMatchMaking('spawning \\'%s\\', roomId: %s, processId: %s', roomName, room.roomId, processId);\n\n room._events.on('lock', lockRoom.bind(this, room));\n room._events.on('unlock', unlockRoom.bind(this, room));\n room._events.on('join', onClientJoinRoom.bind(this, room));\n room._events.on('leave', onClientLeaveRoom.bind(this, room));\n room._events.once('dispose', disposeRoom.bind(this, roomName, room));\n room._events.once('disconnect', () => room._events.removeAllListeners());\n\n // room always start unlocked\n await createRoomReferences(room, true);\n await room.listing.save();\n\n registeredHandler.emit('create', room);\n\n return room.listing;\n}\n\nexport function getRoomById(roomId: string) {\n return rooms[roomId];\n}\n\n/**\n * Disconnects every client on every room in the current process.\n */\nexport function disconnectAll() {\n const promises: Array<Promise<any>> = [];\n\n for (const roomId in rooms) {\n if (!rooms.hasOwnProperty(roomId)) { continue; }\n promises.push(rooms[roomId].disconnect());\n }\n\n return promises;\n}\n\nexport function gracefullyShutdown(): Promise<any> {\n if (isGracefullyShuttingDown) {\n return Promise.reject('already_shutting_down');\n }\n\n isGracefullyShuttingDown = true;\n\n debugMatchMaking(`${processId} is shutting down!`);\n\n // remove processId from room count key\n presence.hdel(getRoomCountKey(), processId);\n\n // unsubscribe from process id channel\n presence.unsubscribe(getProcessChannel());\n\n return Promise.all(disconnectAll());\n}\n\n/**\n * Reserve a seat for a client in a room\n */\nexport async function reserveSeatFor(room: RoomListingData, options: any) {\n const sessionId: string = generateId();\n\n debugMatchMaking(\n 'reserving seat. sessionId: \\'%s\\', roomId: \\'%s\\', processId: \\'%s\\'',\n sessionId, room.roomId, processId,\n );\n\n let successfulSeatReservation: boolean;\n\n try {\n successfulSeatReservation = await remoteRoomCall(room.roomId, '_reserveSeat', [sessionId, options]);\n\n } catch (e) {\n debugMatchMaking(e);\n successfulSeatReservation = false;\n }\n\n if (!successfulSeatReservation) {\n throw new SeatReservationError(`${room.roomId} is already full.`);\n }\n\n return { room, sessionId };\n}\n\nasync function cleanupStaleRooms(roomName: string) {\n //\n // clean-up possibly stale room ids\n // (ungraceful shutdowns using Redis can result on stale room ids still on memory.)\n //\n const cachedRooms = await driver.find({ name: roomName }, { _id: 1 });\n\n // remove connecting counts\n await presence.del(getHandlerConcurrencyKey(roomName));\n\n await Promise.all(cachedRooms.map(async (room) => {\n try {\n // use hardcoded short timeout for cleaning up stale rooms.\n await remoteRoomCall(room.roomId, 'roomId');\n\n } catch (e) {\n debugMatchMaking(`cleaning up stale room '${roomName}', roomId: ${room.roomId}`);\n room.remove();\n }\n }));\n}\n\nasync function createRoomReferences(room: Room, init: boolean = false): Promise<boolean> {\n rooms[room.roomId] = room;\n\n if (init) {\n await subscribeIPC(\n presence,\n processId,\n getRoomChannel(room.roomId),\n (method, args) => {\n return (!args && typeof (room[method]) !== 'function')\n ? room[method]\n : room[method].apply(room, args);\n },\n );\n }\n\n return true;\n}\n\nasync function awaitRoomAvailable(roomToJoin: string, callback: Function): Promise<RoomListingData> {\n return new Promise(async (resolve, reject) => {\n const concurrencyKey = getHandlerConcurrencyKey(roomToJoin);\n const concurrency = await presence.incr(concurrencyKey) - 1;\n\n // avoid having too long timeout if 10+ clients ask to join at the same time\n const concurrencyTimeout = Math.min(concurrency * 100, REMOTE_ROOM_SHORT_TIMEOUT);\n\n if (concurrency > 0) {\n debugMatchMaking(\n 'receiving %d concurrent requests for joining \\'%s\\' (waiting %d ms)',\n concurrency, roomToJoin, concurrencyTimeout,\n );\n }\n\n setTimeout(async () => {\n try {\n const result = await callback();\n resolve(result);\n\n } catch (e) {\n reject(e);\n\n } finally {\n await presence.decr(concurrencyKey);\n }\n }, concurrencyTimeout);\n });\n}\n\nfunction onClientJoinRoom(room: Room, client: Client) {\n handlers[room.roomName].emit('join', room, client);\n}\n\nfunction onClientLeaveRoom(room: Room, client: Client, willDispose: boolean) {\n handlers[room.roomName].emit('leave', room, client, willDispose);\n}\n\nfunction lockRoom(room: Room): void {\n // emit public event on registered handler\n handlers[room.roomName].emit('lock', room);\n}\n\nasync function unlockRoom(room: Room) {\n if (await createRoomReferences(room)) {\n // emit public event on registered handler\n handlers[room.roomName].emit('unlock', room);\n }\n}\n\nasync function disposeRoom(roomName: string, room: Room) {\n debugMatchMaking('disposing \\'%s\\' (%s) on processId \\'%s\\'', roomName, room.roomId, processId);\n\n // decrease amount of rooms this process is handling\n if (!isGracefullyShuttingDown) {\n presence.hincrby(getRoomCountKey(), processId, -1);\n }\n\n // remove from room listing (already removed if `disconnect()` has been called)\n if (room.internalState !== RoomInternalState.DISCONNECTING) {\n await room.listing.remove();\n }\n\n // emit disposal on registered session handler\n handlers[roomName].emit('dispose', room);\n\n // remove concurrency key\n presence.del(getHandlerConcurrencyKey(roomName));\n\n // unsubscribe from remote connections\n presence.unsubscribe(getRoomChannel(room.roomId));\n\n // remove actual room reference\n delete rooms[room.roomId];\n}\n\n//\n// Presence keys\n//\n\nfunction getRoomChannel(roomId: string) {\n return `$${roomId}`;\n}\n\nfunction getHandlerConcurrencyKey(name: string) {\n return `c:${name}`;\n}\n\nfunction getProcessChannel(id: string = processId) {\n return `p:${id}`;\n}\n\nfunction getRoomCountKey() {\n return 'roomcount';\n}\n"],"names":["processId","presence","driver","LocalPresence","LocalDriver","subscribeIPC","retry","SeatReservationError","ServerError","ErrorCode","REMOTE_ROOM_SHORT_TIMEOUT","requestFromIPC","RegisteredHandler","debugAndPrintError","generateId","merge","RoomInternalState","debugMatchMaking"],"mappings":"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"}
@@ -133,7 +133,7 @@ async function remoteRoomCall(roomId, method, args, rejectionTimeout = REMOTE_RO
133
133
  else {
134
134
  return (!args && typeof (room[method]) !== 'function')
135
135
  ? room[method]
136
- : (await room[method].apply(room, args));
136
+ : (await room[method].apply(room, args && args.map((arg) => JSON.parse(JSON.stringify(arg)))));
137
137
  }
138
138
  }
139
139
  function defineRoomType(name, klass, defaultOptions) {
@@ -1 +1 @@
1
- {"version":3,"file":"MatchMaker.mjs","sources":["../src/MatchMaker.ts"],"sourcesContent":["import { ErrorCode } from './Protocol';\n\nimport { requestFromIPC, subscribeIPC } from './IPC';\nimport { generateId, merge, REMOTE_ROOM_SHORT_TIMEOUT, retry } from './Utils';\n\nimport { RegisteredHandler } from './matchmaker/RegisteredHandler';\nimport { Room, RoomInternalState } from './Room';\n\nimport { LocalPresence } from './presence/LocalPresence';\nimport { Presence } from './presence/Presence';\n\nimport { debugAndPrintError, debugMatchMaking } from './Debug';\nimport { SeatReservationError } from './errors/SeatReservationError';\nimport { ServerError } from './errors/ServerError';\n\nimport { IRoomListingData, MatchMakerDriver, RoomListingData, LocalDriver } from './matchmaker/driver';\nimport * as controller from './matchmaker/controller';\n\nimport { Client } from './Transport';\nimport { Type } from './types';\n\nexport { MatchMakerDriver, controller };\n\nexport type ClientOptions = any;\n\nexport interface SeatReservation {\n sessionId: string;\n room: RoomListingData;\n}\n\nconst handlers: {[id: string]: RegisteredHandler} = {};\nconst rooms: {[roomId: string]: Room} = {};\n\nexport let processId: string;\nexport let presence: Presence;\nexport let driver: MatchMakerDriver;\n\nlet isGracefullyShuttingDown: boolean;\n\nexport function setup(_presence?: Presence, _driver?: MatchMakerDriver, _processId?: string) {\n presence = _presence || new LocalPresence();\n driver = _driver || new LocalDriver();\n processId = _processId;\n isGracefullyShuttingDown = false;\n\n /**\n * Subscribe to remote `handleCreateRoom` calls.\n */\n subscribeIPC(presence, processId, getProcessChannel(), (_, args) => {\n return handleCreateRoom.apply(undefined, args);\n });\n\n presence.hset(getRoomCountKey(), processId, '0');\n}\n\n/**\n * Join or create into a room and return seat reservation\n */\nexport async function joinOrCreate(roomName: string, clientOptions: ClientOptions = {}) {\n return await retry<Promise<SeatReservation>>(async () => {\n let room = await findOneRoomAvailable(roomName, clientOptions);\n\n if (!room) {\n room = await createRoom(roomName, clientOptions);\n }\n\n return await reserveSeatFor(room, clientOptions);\n }, 5, [SeatReservationError]);\n}\n\n/**\n * Create a room and return seat reservation\n */\nexport async function create(roomName: string, clientOptions: ClientOptions = {}) {\n const room = await createRoom(roomName, clientOptions);\n return reserveSeatFor(room, clientOptions);\n}\n\n/**\n * Join a room and return seat reservation\n */\nexport async function join(roomName: string, clientOptions: ClientOptions = {}) {\n return await retry<Promise<SeatReservation>>(async () => {\n const room = await findOneRoomAvailable(roomName, clientOptions);\n\n if (!room) {\n throw new ServerError(ErrorCode.MATCHMAKE_INVALID_CRITERIA, `no rooms found with provided criteria`);\n }\n\n return reserveSeatFor(room, clientOptions);\n });\n}\n\n/**\n * Join a room by id and return seat reservation\n */\nexport async function joinById(roomId: string, clientOptions: ClientOptions = {}) {\n const room = await driver.findOne({ roomId });\n\n if (room) {\n const rejoinSessionId = clientOptions.sessionId;\n\n if (rejoinSessionId) {\n // handle re-connection!\n const hasReservedSeat = await remoteRoomCall(room.roomId, 'hasReservedSeat', [rejoinSessionId]);\n\n if (hasReservedSeat) {\n return { room, sessionId: rejoinSessionId };\n\n } else {\n throw new ServerError(ErrorCode.MATCHMAKE_EXPIRED, `session expired: ${rejoinSessionId}`);\n\n }\n\n } else if (!room.locked) {\n return reserveSeatFor(room, clientOptions);\n\n } else {\n throw new ServerError( ErrorCode.MATCHMAKE_INVALID_ROOM_ID, `room \"${roomId}\" is locked`);\n\n }\n\n } else {\n throw new ServerError( ErrorCode.MATCHMAKE_INVALID_ROOM_ID, `room \"${roomId}\" not found`);\n }\n\n}\n\n/**\n * Perform a query for all cached rooms\n */\nexport async function query(conditions: Partial<IRoomListingData> = {}) {\n return await driver.find(conditions);\n}\n\n/**\n * Find for a public and unlocked room available\n */\nexport async function findOneRoomAvailable(roomName: string, clientOptions: ClientOptions): Promise<RoomListingData> {\n return await awaitRoomAvailable(roomName, async () => {\n const handler = handlers[roomName];\n if (!handler) {\n throw new ServerError( ErrorCode.MATCHMAKE_NO_HANDLER, `provided room name \"${roomName}\" not defined`);\n }\n\n const roomQuery = driver.findOne({\n locked: false,\n name: roomName,\n private: false,\n ...handler.getFilterOptions(clientOptions),\n });\n\n if (handler.sortOptions) {\n roomQuery.sort(handler.sortOptions);\n }\n\n return await roomQuery;\n });\n}\n\n/**\n * Call a method or return a property on a remote room.\n */\nexport async function remoteRoomCall<R= any>(\n roomId: string,\n method: string,\n args?: any[],\n rejectionTimeout = REMOTE_ROOM_SHORT_TIMEOUT,\n): Promise<R> {\n const room = rooms[roomId];\n\n if (!room) {\n try {\n return await requestFromIPC<R>(presence, getRoomChannel(roomId), method, args);\n\n } catch (e) {\n const request = `${method}${args && ' with args ' + JSON.stringify(args) || ''}`;\n throw new ServerError(\n ErrorCode.MATCHMAKE_UNHANDLED,\n `remote room (${roomId}) timed out, requesting \"${request}\". (${rejectionTimeout}ms exceeded)`,\n );\n }\n\n } else {\n return (!args && typeof (room[method]) !== 'function')\n ? room[method]\n : (await room[method].apply(room, args));\n }\n}\n\nexport function defineRoomType<T extends Type<Room>>(\n name: string,\n klass: T,\n defaultOptions?: Parameters<NonNullable<InstanceType<T>['onCreate']>>[0],\n) {\n const registeredHandler = new RegisteredHandler(klass, defaultOptions);\n\n handlers[name] = registeredHandler;\n\n cleanupStaleRooms(name);\n\n return registeredHandler;\n}\n\nexport function removeRoomType(name: string) {\n delete handlers[name];\n cleanupStaleRooms(name);\n}\n\nexport function hasHandler(name: string) {\n return handlers[ name ] !== undefined;\n}\n\n/**\n * Create a room\n */\nexport async function createRoom(roomName: string, clientOptions: ClientOptions): Promise<RoomListingData> {\n const roomsSpawnedByProcessId = await presence.hgetall(getRoomCountKey());\n\n const processIdWithFewerRooms = (\n Object.keys(roomsSpawnedByProcessId).sort((p1, p2) => {\n return (Number(roomsSpawnedByProcessId[p1]) > Number(roomsSpawnedByProcessId[p2]))\n ? 1\n : -1;\n })[0]\n ) || processId;\n\n if (processIdWithFewerRooms === processId) {\n // create the room on this process!\n return await handleCreateRoom(roomName, clientOptions);\n\n } else {\n // ask other process to create the room!\n let room: RoomListingData;\n\n try {\n room = await requestFromIPC<RoomListingData>(\n presence,\n getProcessChannel(processIdWithFewerRooms),\n undefined,\n [roomName, clientOptions],\n REMOTE_ROOM_SHORT_TIMEOUT,\n );\n\n } catch (e) {\n // if other process failed to respond, create the room on this process\n debugAndPrintError(e);\n room = await handleCreateRoom(roomName, clientOptions);\n }\n\n return room;\n }\n}\n\nasync function handleCreateRoom(roomName: string, clientOptions: ClientOptions): Promise<RoomListingData> {\n const registeredHandler = handlers[roomName];\n\n if (!registeredHandler) {\n throw new ServerError( ErrorCode.MATCHMAKE_NO_HANDLER, `provided room name \"${roomName}\" not defined`);\n }\n\n const room = new registeredHandler.klass();\n\n // set room public attributes\n room.roomId = generateId();\n room.roomName = roomName;\n room.presence = presence;\n\n // create a RoomCache reference.\n room.listing = driver.createInstance({\n name: roomName,\n processId,\n ...registeredHandler.getFilterOptions(clientOptions),\n });\n\n if (room.onCreate) {\n try {\n await room.onCreate(merge({}, clientOptions, registeredHandler.options));\n\n // increment amount of rooms this process is handling\n presence.hincrby(getRoomCountKey(), processId, 1);\n\n } catch (e) {\n debugAndPrintError(e);\n throw new ServerError(\n e.code || ErrorCode.MATCHMAKE_UNHANDLED,\n e.message,\n );\n }\n }\n\n room.internalState = RoomInternalState.CREATED;\n\n room.listing.roomId = room.roomId;\n room.listing.maxClients = room.maxClients;\n\n // imediatelly ask client to join the room\n debugMatchMaking('spawning \\'%s\\', roomId: %s, processId: %s', roomName, room.roomId, processId);\n\n room._events.on('lock', lockRoom.bind(this, room));\n room._events.on('unlock', unlockRoom.bind(this, room));\n room._events.on('join', onClientJoinRoom.bind(this, room));\n room._events.on('leave', onClientLeaveRoom.bind(this, room));\n room._events.once('dispose', disposeRoom.bind(this, roomName, room));\n room._events.once('disconnect', () => room._events.removeAllListeners());\n\n // room always start unlocked\n await createRoomReferences(room, true);\n await room.listing.save();\n\n registeredHandler.emit('create', room);\n\n return room.listing;\n}\n\nexport function getRoomById(roomId: string) {\n return rooms[roomId];\n}\n\n/**\n * Disconnects every client on every room in the current process.\n */\nexport function disconnectAll() {\n const promises: Array<Promise<any>> = [];\n\n for (const roomId in rooms) {\n if (!rooms.hasOwnProperty(roomId)) { continue; }\n promises.push(rooms[roomId].disconnect());\n }\n\n return promises;\n}\n\nexport function gracefullyShutdown(): Promise<any> {\n if (isGracefullyShuttingDown) {\n return Promise.reject('already_shutting_down');\n }\n\n isGracefullyShuttingDown = true;\n\n debugMatchMaking(`${processId} is shutting down!`);\n\n // remove processId from room count key\n presence.hdel(getRoomCountKey(), processId);\n\n // unsubscribe from process id channel\n presence.unsubscribe(getProcessChannel());\n\n return Promise.all(disconnectAll());\n}\n\n/**\n * Reserve a seat for a client in a room\n */\nexport async function reserveSeatFor(room: RoomListingData, options: any) {\n const sessionId: string = generateId();\n\n debugMatchMaking(\n 'reserving seat. sessionId: \\'%s\\', roomId: \\'%s\\', processId: \\'%s\\'',\n sessionId, room.roomId, processId,\n );\n\n let successfulSeatReservation: boolean;\n\n try {\n successfulSeatReservation = await remoteRoomCall(room.roomId, '_reserveSeat', [sessionId, options]);\n\n } catch (e) {\n debugMatchMaking(e);\n successfulSeatReservation = false;\n }\n\n if (!successfulSeatReservation) {\n throw new SeatReservationError(`${room.roomId} is already full.`);\n }\n\n return { room, sessionId };\n}\n\nasync function cleanupStaleRooms(roomName: string) {\n //\n // clean-up possibly stale room ids\n // (ungraceful shutdowns using Redis can result on stale room ids still on memory.)\n //\n const cachedRooms = await driver.find({ name: roomName }, { _id: 1 });\n\n // remove connecting counts\n await presence.del(getHandlerConcurrencyKey(roomName));\n\n await Promise.all(cachedRooms.map(async (room) => {\n try {\n // use hardcoded short timeout for cleaning up stale rooms.\n await remoteRoomCall(room.roomId, 'roomId');\n\n } catch (e) {\n debugMatchMaking(`cleaning up stale room '${roomName}', roomId: ${room.roomId}`);\n room.remove();\n }\n }));\n}\n\nasync function createRoomReferences(room: Room, init: boolean = false): Promise<boolean> {\n rooms[room.roomId] = room;\n\n if (init) {\n await subscribeIPC(\n presence,\n processId,\n getRoomChannel(room.roomId),\n (method, args) => {\n return (!args && typeof (room[method]) !== 'function')\n ? room[method]\n : room[method].apply(room, args);\n },\n );\n }\n\n return true;\n}\n\nasync function awaitRoomAvailable(roomToJoin: string, callback: Function): Promise<RoomListingData> {\n return new Promise(async (resolve, reject) => {\n const concurrencyKey = getHandlerConcurrencyKey(roomToJoin);\n const concurrency = await presence.incr(concurrencyKey) - 1;\n\n // avoid having too long timeout if 10+ clients ask to join at the same time\n const concurrencyTimeout = Math.min(concurrency * 100, REMOTE_ROOM_SHORT_TIMEOUT);\n\n if (concurrency > 0) {\n debugMatchMaking(\n 'receiving %d concurrent requests for joining \\'%s\\' (waiting %d ms)',\n concurrency, roomToJoin, concurrencyTimeout,\n );\n }\n\n setTimeout(async () => {\n try {\n const result = await callback();\n resolve(result);\n\n } catch (e) {\n reject(e);\n\n } finally {\n await presence.decr(concurrencyKey);\n }\n }, concurrencyTimeout);\n });\n}\n\nfunction onClientJoinRoom(room: Room, client: Client) {\n handlers[room.roomName].emit('join', room, client);\n}\n\nfunction onClientLeaveRoom(room: Room, client: Client, willDispose: boolean) {\n handlers[room.roomName].emit('leave', room, client, willDispose);\n}\n\nfunction lockRoom(room: Room): void {\n // emit public event on registered handler\n handlers[room.roomName].emit('lock', room);\n}\n\nasync function unlockRoom(room: Room) {\n if (await createRoomReferences(room)) {\n // emit public event on registered handler\n handlers[room.roomName].emit('unlock', room);\n }\n}\n\nasync function disposeRoom(roomName: string, room: Room) {\n debugMatchMaking('disposing \\'%s\\' (%s) on processId \\'%s\\'', roomName, room.roomId, processId);\n\n // decrease amount of rooms this process is handling\n if (!isGracefullyShuttingDown) {\n presence.hincrby(getRoomCountKey(), processId, -1);\n }\n\n // remove from room listing (already removed if `disconnect()` has been called)\n if (room.internalState !== RoomInternalState.DISCONNECTING) {\n await room.listing.remove();\n }\n\n // emit disposal on registered session handler\n handlers[roomName].emit('dispose', room);\n\n // remove concurrency key\n presence.del(getHandlerConcurrencyKey(roomName));\n\n // unsubscribe from remote connections\n presence.unsubscribe(getRoomChannel(room.roomId));\n\n // remove actual room reference\n delete rooms[room.roomId];\n}\n\n//\n// Presence keys\n//\n\nfunction getRoomChannel(roomId: string) {\n return `$${roomId}`;\n}\n\nfunction getHandlerConcurrencyKey(name: string) {\n return `c:${name}`;\n}\n\nfunction getProcessChannel(id: string = processId) {\n return `p:${id}`;\n}\n\nfunction getRoomCountKey() {\n return 'roomcount';\n}\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"MatchMaker.mjs","sources":["../src/MatchMaker.ts"],"sourcesContent":["import { ErrorCode } from './Protocol';\n\nimport { requestFromIPC, subscribeIPC } from './IPC';\nimport { generateId, merge, REMOTE_ROOM_SHORT_TIMEOUT, retry } from './Utils';\n\nimport { RegisteredHandler } from './matchmaker/RegisteredHandler';\nimport { Room, RoomInternalState } from './Room';\n\nimport { LocalPresence } from './presence/LocalPresence';\nimport { Presence } from './presence/Presence';\n\nimport { debugAndPrintError, debugMatchMaking } from './Debug';\nimport { SeatReservationError } from './errors/SeatReservationError';\nimport { ServerError } from './errors/ServerError';\n\nimport { IRoomListingData, MatchMakerDriver, RoomListingData, LocalDriver } from './matchmaker/driver';\nimport * as controller from './matchmaker/controller';\n\nimport { Client } from './Transport';\nimport { Type } from './types';\n\nexport { MatchMakerDriver, controller };\n\nexport type ClientOptions = any;\n\nexport interface SeatReservation {\n sessionId: string;\n room: RoomListingData;\n}\n\nconst handlers: {[id: string]: RegisteredHandler} = {};\nconst rooms: {[roomId: string]: Room} = {};\n\nexport let processId: string;\nexport let presence: Presence;\nexport let driver: MatchMakerDriver;\n\nlet isGracefullyShuttingDown: boolean;\n\nexport function setup(_presence?: Presence, _driver?: MatchMakerDriver, _processId?: string) {\n presence = _presence || new LocalPresence();\n driver = _driver || new LocalDriver();\n processId = _processId;\n isGracefullyShuttingDown = false;\n\n /**\n * Subscribe to remote `handleCreateRoom` calls.\n */\n subscribeIPC(presence, processId, getProcessChannel(), (_, args) => {\n return handleCreateRoom.apply(undefined, args);\n });\n\n presence.hset(getRoomCountKey(), processId, '0');\n}\n\n/**\n * Join or create into a room and return seat reservation\n */\nexport async function joinOrCreate(roomName: string, clientOptions: ClientOptions = {}) {\n return await retry<Promise<SeatReservation>>(async () => {\n let room = await findOneRoomAvailable(roomName, clientOptions);\n\n if (!room) {\n room = await createRoom(roomName, clientOptions);\n }\n\n return await reserveSeatFor(room, clientOptions);\n }, 5, [SeatReservationError]);\n}\n\n/**\n * Create a room and return seat reservation\n */\nexport async function create(roomName: string, clientOptions: ClientOptions = {}) {\n const room = await createRoom(roomName, clientOptions);\n return reserveSeatFor(room, clientOptions);\n}\n\n/**\n * Join a room and return seat reservation\n */\nexport async function join(roomName: string, clientOptions: ClientOptions = {}) {\n return await retry<Promise<SeatReservation>>(async () => {\n const room = await findOneRoomAvailable(roomName, clientOptions);\n\n if (!room) {\n throw new ServerError(ErrorCode.MATCHMAKE_INVALID_CRITERIA, `no rooms found with provided criteria`);\n }\n\n return reserveSeatFor(room, clientOptions);\n });\n}\n\n/**\n * Join a room by id and return seat reservation\n */\nexport async function joinById(roomId: string, clientOptions: ClientOptions = {}) {\n const room = await driver.findOne({ roomId });\n\n if (room) {\n const rejoinSessionId = clientOptions.sessionId;\n\n if (rejoinSessionId) {\n // handle re-connection!\n const hasReservedSeat = await remoteRoomCall(room.roomId, 'hasReservedSeat', [rejoinSessionId]);\n\n if (hasReservedSeat) {\n return { room, sessionId: rejoinSessionId };\n\n } else {\n throw new ServerError(ErrorCode.MATCHMAKE_EXPIRED, `session expired: ${rejoinSessionId}`);\n\n }\n\n } else if (!room.locked) {\n return reserveSeatFor(room, clientOptions);\n\n } else {\n throw new ServerError( ErrorCode.MATCHMAKE_INVALID_ROOM_ID, `room \"${roomId}\" is locked`);\n\n }\n\n } else {\n throw new ServerError( ErrorCode.MATCHMAKE_INVALID_ROOM_ID, `room \"${roomId}\" not found`);\n }\n\n}\n\n/**\n * Perform a query for all cached rooms\n */\nexport async function query(conditions: Partial<IRoomListingData> = {}) {\n return await driver.find(conditions);\n}\n\n/**\n * Find for a public and unlocked room available\n */\nexport async function findOneRoomAvailable(roomName: string, clientOptions: ClientOptions): Promise<RoomListingData> {\n return await awaitRoomAvailable(roomName, async () => {\n const handler = handlers[roomName];\n if (!handler) {\n throw new ServerError( ErrorCode.MATCHMAKE_NO_HANDLER, `provided room name \"${roomName}\" not defined`);\n }\n\n const roomQuery = driver.findOne({\n locked: false,\n name: roomName,\n private: false,\n ...handler.getFilterOptions(clientOptions),\n });\n\n if (handler.sortOptions) {\n roomQuery.sort(handler.sortOptions);\n }\n\n return await roomQuery;\n });\n}\n\n/**\n * Call a method or return a property on a remote room.\n */\nexport async function remoteRoomCall<R= any>(\n roomId: string,\n method: string,\n args?: any[],\n rejectionTimeout = REMOTE_ROOM_SHORT_TIMEOUT,\n): Promise<R> {\n const room = rooms[roomId];\n\n if (!room) {\n try {\n return await requestFromIPC<R>(presence, getRoomChannel(roomId), method, args);\n\n } catch (e) {\n const request = `${method}${args && ' with args ' + JSON.stringify(args) || ''}`;\n throw new ServerError(\n ErrorCode.MATCHMAKE_UNHANDLED,\n `remote room (${roomId}) timed out, requesting \"${request}\". (${rejectionTimeout}ms exceeded)`,\n );\n }\n\n } else {\n return (!args && typeof (room[method]) !== 'function')\n ? room[method]\n : (await room[method].apply(room, args && args.map((arg) => JSON.parse(JSON.stringify(arg)))));\n }\n}\n\nexport function defineRoomType<T extends Type<Room>>(\n name: string,\n klass: T,\n defaultOptions?: Parameters<NonNullable<InstanceType<T>['onCreate']>>[0],\n) {\n const registeredHandler = new RegisteredHandler(klass, defaultOptions);\n\n handlers[name] = registeredHandler;\n\n cleanupStaleRooms(name);\n\n return registeredHandler;\n}\n\nexport function removeRoomType(name: string) {\n delete handlers[name];\n cleanupStaleRooms(name);\n}\n\nexport function hasHandler(name: string) {\n return handlers[ name ] !== undefined;\n}\n\n/**\n * Create a room\n */\nexport async function createRoom(roomName: string, clientOptions: ClientOptions): Promise<RoomListingData> {\n const roomsSpawnedByProcessId = await presence.hgetall(getRoomCountKey());\n\n const processIdWithFewerRooms = (\n Object.keys(roomsSpawnedByProcessId).sort((p1, p2) => {\n return (Number(roomsSpawnedByProcessId[p1]) > Number(roomsSpawnedByProcessId[p2]))\n ? 1\n : -1;\n })[0]\n ) || processId;\n\n if (processIdWithFewerRooms === processId) {\n // create the room on this process!\n return await handleCreateRoom(roomName, clientOptions);\n\n } else {\n // ask other process to create the room!\n let room: RoomListingData;\n\n try {\n room = await requestFromIPC<RoomListingData>(\n presence,\n getProcessChannel(processIdWithFewerRooms),\n undefined,\n [roomName, clientOptions],\n REMOTE_ROOM_SHORT_TIMEOUT,\n );\n\n } catch (e) {\n // if other process failed to respond, create the room on this process\n debugAndPrintError(e);\n room = await handleCreateRoom(roomName, clientOptions);\n }\n\n return room;\n }\n}\n\nasync function handleCreateRoom(roomName: string, clientOptions: ClientOptions): Promise<RoomListingData> {\n const registeredHandler = handlers[roomName];\n\n if (!registeredHandler) {\n throw new ServerError( ErrorCode.MATCHMAKE_NO_HANDLER, `provided room name \"${roomName}\" not defined`);\n }\n\n const room = new registeredHandler.klass();\n\n // set room public attributes\n room.roomId = generateId();\n room.roomName = roomName;\n room.presence = presence;\n\n // create a RoomCache reference.\n room.listing = driver.createInstance({\n name: roomName,\n processId,\n ...registeredHandler.getFilterOptions(clientOptions),\n });\n\n if (room.onCreate) {\n try {\n await room.onCreate(merge({}, clientOptions, registeredHandler.options));\n\n // increment amount of rooms this process is handling\n presence.hincrby(getRoomCountKey(), processId, 1);\n\n } catch (e) {\n debugAndPrintError(e);\n throw new ServerError(\n e.code || ErrorCode.MATCHMAKE_UNHANDLED,\n e.message,\n );\n }\n }\n\n room.internalState = RoomInternalState.CREATED;\n\n room.listing.roomId = room.roomId;\n room.listing.maxClients = room.maxClients;\n\n // imediatelly ask client to join the room\n debugMatchMaking('spawning \\'%s\\', roomId: %s, processId: %s', roomName, room.roomId, processId);\n\n room._events.on('lock', lockRoom.bind(this, room));\n room._events.on('unlock', unlockRoom.bind(this, room));\n room._events.on('join', onClientJoinRoom.bind(this, room));\n room._events.on('leave', onClientLeaveRoom.bind(this, room));\n room._events.once('dispose', disposeRoom.bind(this, roomName, room));\n room._events.once('disconnect', () => room._events.removeAllListeners());\n\n // room always start unlocked\n await createRoomReferences(room, true);\n await room.listing.save();\n\n registeredHandler.emit('create', room);\n\n return room.listing;\n}\n\nexport function getRoomById(roomId: string) {\n return rooms[roomId];\n}\n\n/**\n * Disconnects every client on every room in the current process.\n */\nexport function disconnectAll() {\n const promises: Array<Promise<any>> = [];\n\n for (const roomId in rooms) {\n if (!rooms.hasOwnProperty(roomId)) { continue; }\n promises.push(rooms[roomId].disconnect());\n }\n\n return promises;\n}\n\nexport function gracefullyShutdown(): Promise<any> {\n if (isGracefullyShuttingDown) {\n return Promise.reject('already_shutting_down');\n }\n\n isGracefullyShuttingDown = true;\n\n debugMatchMaking(`${processId} is shutting down!`);\n\n // remove processId from room count key\n presence.hdel(getRoomCountKey(), processId);\n\n // unsubscribe from process id channel\n presence.unsubscribe(getProcessChannel());\n\n return Promise.all(disconnectAll());\n}\n\n/**\n * Reserve a seat for a client in a room\n */\nexport async function reserveSeatFor(room: RoomListingData, options: any) {\n const sessionId: string = generateId();\n\n debugMatchMaking(\n 'reserving seat. sessionId: \\'%s\\', roomId: \\'%s\\', processId: \\'%s\\'',\n sessionId, room.roomId, processId,\n );\n\n let successfulSeatReservation: boolean;\n\n try {\n successfulSeatReservation = await remoteRoomCall(room.roomId, '_reserveSeat', [sessionId, options]);\n\n } catch (e) {\n debugMatchMaking(e);\n successfulSeatReservation = false;\n }\n\n if (!successfulSeatReservation) {\n throw new SeatReservationError(`${room.roomId} is already full.`);\n }\n\n return { room, sessionId };\n}\n\nasync function cleanupStaleRooms(roomName: string) {\n //\n // clean-up possibly stale room ids\n // (ungraceful shutdowns using Redis can result on stale room ids still on memory.)\n //\n const cachedRooms = await driver.find({ name: roomName }, { _id: 1 });\n\n // remove connecting counts\n await presence.del(getHandlerConcurrencyKey(roomName));\n\n await Promise.all(cachedRooms.map(async (room) => {\n try {\n // use hardcoded short timeout for cleaning up stale rooms.\n await remoteRoomCall(room.roomId, 'roomId');\n\n } catch (e) {\n debugMatchMaking(`cleaning up stale room '${roomName}', roomId: ${room.roomId}`);\n room.remove();\n }\n }));\n}\n\nasync function createRoomReferences(room: Room, init: boolean = false): Promise<boolean> {\n rooms[room.roomId] = room;\n\n if (init) {\n await subscribeIPC(\n presence,\n processId,\n getRoomChannel(room.roomId),\n (method, args) => {\n return (!args && typeof (room[method]) !== 'function')\n ? room[method]\n : room[method].apply(room, args);\n },\n );\n }\n\n return true;\n}\n\nasync function awaitRoomAvailable(roomToJoin: string, callback: Function): Promise<RoomListingData> {\n return new Promise(async (resolve, reject) => {\n const concurrencyKey = getHandlerConcurrencyKey(roomToJoin);\n const concurrency = await presence.incr(concurrencyKey) - 1;\n\n // avoid having too long timeout if 10+ clients ask to join at the same time\n const concurrencyTimeout = Math.min(concurrency * 100, REMOTE_ROOM_SHORT_TIMEOUT);\n\n if (concurrency > 0) {\n debugMatchMaking(\n 'receiving %d concurrent requests for joining \\'%s\\' (waiting %d ms)',\n concurrency, roomToJoin, concurrencyTimeout,\n );\n }\n\n setTimeout(async () => {\n try {\n const result = await callback();\n resolve(result);\n\n } catch (e) {\n reject(e);\n\n } finally {\n await presence.decr(concurrencyKey);\n }\n }, concurrencyTimeout);\n });\n}\n\nfunction onClientJoinRoom(room: Room, client: Client) {\n handlers[room.roomName].emit('join', room, client);\n}\n\nfunction onClientLeaveRoom(room: Room, client: Client, willDispose: boolean) {\n handlers[room.roomName].emit('leave', room, client, willDispose);\n}\n\nfunction lockRoom(room: Room): void {\n // emit public event on registered handler\n handlers[room.roomName].emit('lock', room);\n}\n\nasync function unlockRoom(room: Room) {\n if (await createRoomReferences(room)) {\n // emit public event on registered handler\n handlers[room.roomName].emit('unlock', room);\n }\n}\n\nasync function disposeRoom(roomName: string, room: Room) {\n debugMatchMaking('disposing \\'%s\\' (%s) on processId \\'%s\\'', roomName, room.roomId, processId);\n\n // decrease amount of rooms this process is handling\n if (!isGracefullyShuttingDown) {\n presence.hincrby(getRoomCountKey(), processId, -1);\n }\n\n // remove from room listing (already removed if `disconnect()` has been called)\n if (room.internalState !== RoomInternalState.DISCONNECTING) {\n await room.listing.remove();\n }\n\n // emit disposal on registered session handler\n handlers[roomName].emit('dispose', room);\n\n // remove concurrency key\n presence.del(getHandlerConcurrencyKey(roomName));\n\n // unsubscribe from remote connections\n presence.unsubscribe(getRoomChannel(room.roomId));\n\n // remove actual room reference\n delete rooms[room.roomId];\n}\n\n//\n// Presence keys\n//\n\nfunction getRoomChannel(roomId: string) {\n return `$${roomId}`;\n}\n\nfunction getHandlerConcurrencyKey(name: string) {\n return `c:${name}`;\n}\n\nfunction getProcessChannel(id: string = processId) {\n return `p:${id}`;\n}\n\nfunction getRoomCountKey() {\n return 'roomcount';\n}\n"],"names":[],"mappings":"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"}
package/build/Server.js CHANGED
@@ -2,6 +2,7 @@
2
2
 
3
3
  Object.defineProperty(exports, '__esModule', { value: true });
4
4
 
5
+ var greeting = require('@colyseus/greeting-banner');
5
6
  var Debug = require('./Debug.js');
6
7
  var MatchMaker = require('./MatchMaker.js');
7
8
  var Room = require('./Room.js');
@@ -17,6 +18,10 @@ require('@colyseus/schema');
17
18
  require('./rooms/RelayRoom.js');
18
19
  var controller = require('./matchmaker/controller.js');
19
20
 
21
+ function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
22
+
23
+ var greeting__default = /*#__PURE__*/_interopDefaultLegacy(greeting);
24
+
20
25
  class Server {
21
26
  transport;
22
27
  presence;
@@ -79,10 +84,10 @@ class Server {
79
84
  async listen(port, hostname, backlog, listeningListener) {
80
85
  this.port = port;
81
86
  /**
82
- * Display greeting log
87
+ * Greetings!
83
88
  */
84
89
  if (this.greet) {
85
- console.log();
90
+ console.log(greeting__default['default']);
86
91
  }
87
92
  return new Promise((resolve, reject) => {
88
93
  this.transport.server?.on('error', (err) => reject(err));
@@ -1 +1 @@
1
- {"version":3,"file":"Server.js","sources":["../src/Server.ts"],"sourcesContent":["import http, { IncomingMessage, ServerResponse } from 'http';\n\nimport { debugAndPrintError, debugMatchMaking } from './Debug';\nimport * as matchMaker from './MatchMaker';\nimport { RegisteredHandler } from './matchmaker/RegisteredHandler';\nimport { Presence } from './presence/Presence';\n\nimport { Room } from './Room';\nimport { Type } from './types';\nimport { registerGracefulShutdown } from './Utils';\n\nimport { generateId } from '.';\nimport { registerNode, unregisterNode } from './discovery';\n\nimport { LocalPresence } from './presence/LocalPresence';\nimport { LocalDriver } from './matchmaker/driver';\n\nimport { Transport } from './Transport';\n\n// IServerOptions &\nexport type ServerOptions = {\n presence?: Presence,\n driver?: matchMaker.MatchMakerDriver,\n transport?: Transport,\n gracefullyShutdown?: 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 port: number;\n protected driver: matchMaker.MatchMakerDriver;\n protected processId: string = generateId();\n\n protected greet: boolean;\n\n private matchmakeRoute = 'matchmake';\n private allowedRoomNameChars = /([a-zA-Z_\\-0-9]+)/gi;\n\n constructor(options: ServerOptions = {}) {\n const { gracefullyShutdown = true, greet = true } = options;\n\n this.presence = options.presence || new LocalPresence();\n this.driver = options.driver || new LocalDriver();\n this.greet = greet;\n\n // setup matchmaker\n matchMaker.setup(this.presence, this.driver, this.processId);\n\n // \"presence\" option is not used from now on\n delete options.presence;\n\n this.attach(options);\n\n if (gracefullyShutdown) {\n registerGracefulShutdown((err) => this.gracefullyShutdown(true, err));\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 console.warn(\"DEPRECATION WARNING: 'pingInterval', 'pingMaxRetries', 'server', and 'verifyClient' Server options will be permanently moved to WebSocketTransport on v0.15\");\n console.warn(`new Server({\n transport: new WebSocketTransport({\n pingInterval: ...,\n pingMaxRetries: ...,\n server: ...,\n verifyClient: ...\n })\n})`);\n console.warn(\"👉 Documentation: https://docs.colyseus.io/server/transport/\")\n }\n\n const transport = options.transport || this.getDefaultTransport(options);\n delete options.transport;\n\n this.transport = transport;\n\n if (this.transport.server) {\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 * Display greeting log\n */\n if (this.greet) {\n console.log();\n }\n\n return new Promise<void>((resolve, reject) => {\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 registerProcessForDiscovery() {\n // register node for proxy/service discovery\n registerNode(this.presence, {\n port: this.port,\n processId: this.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 handler Room class definition\n * @param defaultOptions default options for `onCreate`\n */\n public define<T extends Type<Room>>(\n name: string,\n handler: T,\n defaultOptions?: Parameters<NonNullable<InstanceType<T>['onCreate']>>[0],\n ): RegisteredHandler {\n return matchMaker.defineRoomType(name, handler, defaultOptions);\n }\n\n public async gracefullyShutdown(exit: boolean = true, err?: Error) {\n try {\n await this.onShutdownCallback();\n\n await unregisterNode(this.presence, {\n port: this.port,\n processId: this.processId,\n });\n\n await matchMaker.gracefullyShutdown();\n\n this.transport.shutdown();\n this.presence.shutdown();\n this.driver.shutdown();\n\n } catch (e) {\n debugAndPrintError(`error during shutdown: ${e}`);\n\n } finally {\n if (exit) {\n process.exit(err ? 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 console.warn(`📶️❗ Colyseus latency simulation enabled → ${milliseconds}ms latency for round trip.`);\n\n const halfwayMS = (milliseconds / 2);\n this.transport.simulateLatency(halfwayMS);\n\n /* tslint:disable:no-string-literal */\n const _onMessage = Room.prototype['_onMessage'];\n /* tslint:disable:no-string-literal */\n Room.prototype['_onMessage'] = 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(() => _onMessage.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 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 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(`/${this.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 const headers = {\n 'Access-Control-Allow-Headers': 'Origin, X-Requested-With, Content-Type, Accept',\n 'Access-Control-Allow-Methods': 'OPTIONS, POST, GET',\n 'Access-Control-Allow-Origin': '*',\n 'Access-Control-Max-Age': 2592000,\n // ...\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(this.allowedRoomNameChars);\n const matchmakeIndex = matchedParams.indexOf(this.matchmakeRoute);\n const method = matchedParams[matchmakeIndex + 1];\n const name = 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(method, name, clientOptions);\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 const matchedParams = req.url.match(this.allowedRoomNameChars);\n const roomName = matchedParams.length > 1 ? matchedParams[matchedParams.length - 1] : \"\";\n\n headers['Content-Type'] = 'application/json';\n res.writeHead(200, headers);\n res.write(JSON.stringify(await matchMaker.controller.getAvailableRooms(roomName)));\n res.end();\n }\n\n }\n\n}\n"],"names":["generateId","LocalPresence","LocalDriver","matchMaker.setup","registerGracefulShutdown","registerNode","matchMaker.defineRoomType","unregisterNode","matchMaker.gracefullyShutdown","debugAndPrintError","Room","debugMatchMaking","matchMaker.controller.invokeMethod","matchMaker.controller.getAvailableRooms"],"mappings":"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"}
1
+ {"version":3,"file":"Server.js","sources":["../src/Server.ts"],"sourcesContent":["import http, { IncomingMessage, ServerResponse } from 'http';\nimport greeting from \"@colyseus/greeting-banner\";\n\nimport { debugAndPrintError, debugMatchMaking } from './Debug';\nimport * as matchMaker from './MatchMaker';\nimport { RegisteredHandler } from './matchmaker/RegisteredHandler';\nimport { Presence } from './presence/Presence';\n\nimport { Room } from './Room';\nimport { Type } from './types';\nimport { registerGracefulShutdown } from './Utils';\n\nimport { generateId } from '.';\nimport { registerNode, unregisterNode } from './discovery';\n\nimport { LocalPresence } from './presence/LocalPresence';\nimport { LocalDriver } from './matchmaker/driver';\n\nimport { Transport } from './Transport';\n\n// IServerOptions &\nexport type ServerOptions = {\n presence?: Presence,\n driver?: matchMaker.MatchMakerDriver,\n transport?: Transport,\n gracefullyShutdown?: 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 port: number;\n protected driver: matchMaker.MatchMakerDriver;\n protected processId: string = generateId();\n\n protected greet: boolean;\n\n private matchmakeRoute = 'matchmake';\n private allowedRoomNameChars = /([a-zA-Z_\\-0-9]+)/gi;\n\n constructor(options: ServerOptions = {}) {\n const { gracefullyShutdown = true, greet = true } = options;\n\n this.presence = options.presence || new LocalPresence();\n this.driver = options.driver || new LocalDriver();\n this.greet = greet;\n\n // setup matchmaker\n matchMaker.setup(this.presence, this.driver, this.processId);\n\n // \"presence\" option is not used from now on\n delete options.presence;\n\n this.attach(options);\n\n if (gracefullyShutdown) {\n registerGracefulShutdown((err) => this.gracefullyShutdown(true, err));\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 console.warn(\"DEPRECATION WARNING: 'pingInterval', 'pingMaxRetries', 'server', and 'verifyClient' Server options will be permanently moved to WebSocketTransport on v0.15\");\n console.warn(`new Server({\n transport: new WebSocketTransport({\n pingInterval: ...,\n pingMaxRetries: ...,\n server: ...,\n verifyClient: ...\n })\n})`);\n console.warn(\"👉 Documentation: https://docs.colyseus.io/server/transport/\")\n }\n\n const transport = options.transport || this.getDefaultTransport(options);\n delete options.transport;\n\n this.transport = transport;\n\n if (this.transport.server) {\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 * Greetings!\n */\n if (this.greet) {\n console.log(greeting);\n }\n\n return new Promise<void>((resolve, reject) => {\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 registerProcessForDiscovery() {\n // register node for proxy/service discovery\n registerNode(this.presence, {\n port: this.port,\n processId: this.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 handler Room class definition\n * @param defaultOptions default options for `onCreate`\n */\n public define<T extends Type<Room>>(\n name: string,\n handler: T,\n defaultOptions?: Parameters<NonNullable<InstanceType<T>['onCreate']>>[0],\n ): RegisteredHandler {\n return matchMaker.defineRoomType(name, handler, defaultOptions);\n }\n\n public async gracefullyShutdown(exit: boolean = true, err?: Error) {\n try {\n await this.onShutdownCallback();\n\n await unregisterNode(this.presence, {\n port: this.port,\n processId: this.processId,\n });\n\n await matchMaker.gracefullyShutdown();\n\n this.transport.shutdown();\n this.presence.shutdown();\n this.driver.shutdown();\n\n } catch (e) {\n debugAndPrintError(`error during shutdown: ${e}`);\n\n } finally {\n if (exit) {\n process.exit(err ? 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 console.warn(`📶️❗ Colyseus latency simulation enabled → ${milliseconds}ms latency for round trip.`);\n\n const halfwayMS = (milliseconds / 2);\n this.transport.simulateLatency(halfwayMS);\n\n /* tslint:disable:no-string-literal */\n const _onMessage = Room.prototype['_onMessage'];\n /* tslint:disable:no-string-literal */\n Room.prototype['_onMessage'] = 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(() => _onMessage.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 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 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(`/${this.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 const headers = {\n 'Access-Control-Allow-Headers': 'Origin, X-Requested-With, Content-Type, Accept',\n 'Access-Control-Allow-Methods': 'OPTIONS, POST, GET',\n 'Access-Control-Allow-Origin': '*',\n 'Access-Control-Max-Age': 2592000,\n // ...\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(this.allowedRoomNameChars);\n const matchmakeIndex = matchedParams.indexOf(this.matchmakeRoute);\n const method = matchedParams[matchmakeIndex + 1];\n const name = 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(method, name, clientOptions);\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 const matchedParams = req.url.match(this.allowedRoomNameChars);\n const roomName = matchedParams.length > 1 ? matchedParams[matchedParams.length - 1] : \"\";\n\n headers['Content-Type'] = 'application/json';\n res.writeHead(200, headers);\n res.write(JSON.stringify(await matchMaker.controller.getAvailableRooms(roomName)));\n res.end();\n }\n\n }\n\n}\n"],"names":["generateId","LocalPresence","LocalDriver","matchMaker.setup","registerGracefulShutdown","greeting","registerNode","matchMaker.defineRoomType","unregisterNode","matchMaker.gracefullyShutdown","debugAndPrintError","Room","debugMatchMaking","matchMaker.controller.invokeMethod","matchMaker.controller.getAvailableRooms"],"mappings":"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"}
package/build/Server.mjs CHANGED
@@ -1,3 +1,4 @@
1
+ import greeting from '@colyseus/greeting-banner';
1
2
  import { debugAndPrintError, debugMatchMaking } from './Debug.mjs';
2
3
  import { setup, defineRoomType, gracefullyShutdown } from './MatchMaker.mjs';
3
4
  import { Room } from './Room.mjs';
@@ -75,10 +76,10 @@ class Server {
75
76
  async listen(port, hostname, backlog, listeningListener) {
76
77
  this.port = port;
77
78
  /**
78
- * Display greeting log
79
+ * Greetings!
79
80
  */
80
81
  if (this.greet) {
81
- console.log();
82
+ console.log(greeting);
82
83
  }
83
84
  return new Promise((resolve, reject) => {
84
85
  this.transport.server?.on('error', (err) => reject(err));
@@ -1 +1 @@
1
- {"version":3,"file":"Server.mjs","sources":["../src/Server.ts"],"sourcesContent":["import http, { IncomingMessage, ServerResponse } from 'http';\n\nimport { debugAndPrintError, debugMatchMaking } from './Debug';\nimport * as matchMaker from './MatchMaker';\nimport { RegisteredHandler } from './matchmaker/RegisteredHandler';\nimport { Presence } from './presence/Presence';\n\nimport { Room } from './Room';\nimport { Type } from './types';\nimport { registerGracefulShutdown } from './Utils';\n\nimport { generateId } from '.';\nimport { registerNode, unregisterNode } from './discovery';\n\nimport { LocalPresence } from './presence/LocalPresence';\nimport { LocalDriver } from './matchmaker/driver';\n\nimport { Transport } from './Transport';\n\n// IServerOptions &\nexport type ServerOptions = {\n presence?: Presence,\n driver?: matchMaker.MatchMakerDriver,\n transport?: Transport,\n gracefullyShutdown?: 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 port: number;\n protected driver: matchMaker.MatchMakerDriver;\n protected processId: string = generateId();\n\n protected greet: boolean;\n\n private matchmakeRoute = 'matchmake';\n private allowedRoomNameChars = /([a-zA-Z_\\-0-9]+)/gi;\n\n constructor(options: ServerOptions = {}) {\n const { gracefullyShutdown = true, greet = true } = options;\n\n this.presence = options.presence || new LocalPresence();\n this.driver = options.driver || new LocalDriver();\n this.greet = greet;\n\n // setup matchmaker\n matchMaker.setup(this.presence, this.driver, this.processId);\n\n // \"presence\" option is not used from now on\n delete options.presence;\n\n this.attach(options);\n\n if (gracefullyShutdown) {\n registerGracefulShutdown((err) => this.gracefullyShutdown(true, err));\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 console.warn(\"DEPRECATION WARNING: 'pingInterval', 'pingMaxRetries', 'server', and 'verifyClient' Server options will be permanently moved to WebSocketTransport on v0.15\");\n console.warn(`new Server({\n transport: new WebSocketTransport({\n pingInterval: ...,\n pingMaxRetries: ...,\n server: ...,\n verifyClient: ...\n })\n})`);\n console.warn(\"👉 Documentation: https://docs.colyseus.io/server/transport/\")\n }\n\n const transport = options.transport || this.getDefaultTransport(options);\n delete options.transport;\n\n this.transport = transport;\n\n if (this.transport.server) {\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 * Display greeting log\n */\n if (this.greet) {\n console.log();\n }\n\n return new Promise<void>((resolve, reject) => {\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 registerProcessForDiscovery() {\n // register node for proxy/service discovery\n registerNode(this.presence, {\n port: this.port,\n processId: this.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 handler Room class definition\n * @param defaultOptions default options for `onCreate`\n */\n public define<T extends Type<Room>>(\n name: string,\n handler: T,\n defaultOptions?: Parameters<NonNullable<InstanceType<T>['onCreate']>>[0],\n ): RegisteredHandler {\n return matchMaker.defineRoomType(name, handler, defaultOptions);\n }\n\n public async gracefullyShutdown(exit: boolean = true, err?: Error) {\n try {\n await this.onShutdownCallback();\n\n await unregisterNode(this.presence, {\n port: this.port,\n processId: this.processId,\n });\n\n await matchMaker.gracefullyShutdown();\n\n this.transport.shutdown();\n this.presence.shutdown();\n this.driver.shutdown();\n\n } catch (e) {\n debugAndPrintError(`error during shutdown: ${e}`);\n\n } finally {\n if (exit) {\n process.exit(err ? 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 console.warn(`📶️❗ Colyseus latency simulation enabled → ${milliseconds}ms latency for round trip.`);\n\n const halfwayMS = (milliseconds / 2);\n this.transport.simulateLatency(halfwayMS);\n\n /* tslint:disable:no-string-literal */\n const _onMessage = Room.prototype['_onMessage'];\n /* tslint:disable:no-string-literal */\n Room.prototype['_onMessage'] = 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(() => _onMessage.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 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 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(`/${this.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 const headers = {\n 'Access-Control-Allow-Headers': 'Origin, X-Requested-With, Content-Type, Accept',\n 'Access-Control-Allow-Methods': 'OPTIONS, POST, GET',\n 'Access-Control-Allow-Origin': '*',\n 'Access-Control-Max-Age': 2592000,\n // ...\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(this.allowedRoomNameChars);\n const matchmakeIndex = matchedParams.indexOf(this.matchmakeRoute);\n const method = matchedParams[matchmakeIndex + 1];\n const name = 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(method, name, clientOptions);\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 const matchedParams = req.url.match(this.allowedRoomNameChars);\n const roomName = matchedParams.length > 1 ? matchedParams[matchedParams.length - 1] : \"\";\n\n headers['Content-Type'] = 'application/json';\n res.writeHead(200, headers);\n res.write(JSON.stringify(await matchMaker.controller.getAvailableRooms(roomName)));\n res.end();\n }\n\n }\n\n}\n"],"names":["matchMaker.setup","matchMaker.defineRoomType","matchMaker.gracefullyShutdown","matchMaker.controller.invokeMethod","matchMaker.controller.getAvailableRooms"],"mappings":"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"}
1
+ {"version":3,"file":"Server.mjs","sources":["../src/Server.ts"],"sourcesContent":["import http, { IncomingMessage, ServerResponse } from 'http';\nimport greeting from \"@colyseus/greeting-banner\";\n\nimport { debugAndPrintError, debugMatchMaking } from './Debug';\nimport * as matchMaker from './MatchMaker';\nimport { RegisteredHandler } from './matchmaker/RegisteredHandler';\nimport { Presence } from './presence/Presence';\n\nimport { Room } from './Room';\nimport { Type } from './types';\nimport { registerGracefulShutdown } from './Utils';\n\nimport { generateId } from '.';\nimport { registerNode, unregisterNode } from './discovery';\n\nimport { LocalPresence } from './presence/LocalPresence';\nimport { LocalDriver } from './matchmaker/driver';\n\nimport { Transport } from './Transport';\n\n// IServerOptions &\nexport type ServerOptions = {\n presence?: Presence,\n driver?: matchMaker.MatchMakerDriver,\n transport?: Transport,\n gracefullyShutdown?: 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 port: number;\n protected driver: matchMaker.MatchMakerDriver;\n protected processId: string = generateId();\n\n protected greet: boolean;\n\n private matchmakeRoute = 'matchmake';\n private allowedRoomNameChars = /([a-zA-Z_\\-0-9]+)/gi;\n\n constructor(options: ServerOptions = {}) {\n const { gracefullyShutdown = true, greet = true } = options;\n\n this.presence = options.presence || new LocalPresence();\n this.driver = options.driver || new LocalDriver();\n this.greet = greet;\n\n // setup matchmaker\n matchMaker.setup(this.presence, this.driver, this.processId);\n\n // \"presence\" option is not used from now on\n delete options.presence;\n\n this.attach(options);\n\n if (gracefullyShutdown) {\n registerGracefulShutdown((err) => this.gracefullyShutdown(true, err));\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 console.warn(\"DEPRECATION WARNING: 'pingInterval', 'pingMaxRetries', 'server', and 'verifyClient' Server options will be permanently moved to WebSocketTransport on v0.15\");\n console.warn(`new Server({\n transport: new WebSocketTransport({\n pingInterval: ...,\n pingMaxRetries: ...,\n server: ...,\n verifyClient: ...\n })\n})`);\n console.warn(\"👉 Documentation: https://docs.colyseus.io/server/transport/\")\n }\n\n const transport = options.transport || this.getDefaultTransport(options);\n delete options.transport;\n\n this.transport = transport;\n\n if (this.transport.server) {\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 * Greetings!\n */\n if (this.greet) {\n console.log(greeting);\n }\n\n return new Promise<void>((resolve, reject) => {\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 registerProcessForDiscovery() {\n // register node for proxy/service discovery\n registerNode(this.presence, {\n port: this.port,\n processId: this.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 handler Room class definition\n * @param defaultOptions default options for `onCreate`\n */\n public define<T extends Type<Room>>(\n name: string,\n handler: T,\n defaultOptions?: Parameters<NonNullable<InstanceType<T>['onCreate']>>[0],\n ): RegisteredHandler {\n return matchMaker.defineRoomType(name, handler, defaultOptions);\n }\n\n public async gracefullyShutdown(exit: boolean = true, err?: Error) {\n try {\n await this.onShutdownCallback();\n\n await unregisterNode(this.presence, {\n port: this.port,\n processId: this.processId,\n });\n\n await matchMaker.gracefullyShutdown();\n\n this.transport.shutdown();\n this.presence.shutdown();\n this.driver.shutdown();\n\n } catch (e) {\n debugAndPrintError(`error during shutdown: ${e}`);\n\n } finally {\n if (exit) {\n process.exit(err ? 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 console.warn(`📶️❗ Colyseus latency simulation enabled → ${milliseconds}ms latency for round trip.`);\n\n const halfwayMS = (milliseconds / 2);\n this.transport.simulateLatency(halfwayMS);\n\n /* tslint:disable:no-string-literal */\n const _onMessage = Room.prototype['_onMessage'];\n /* tslint:disable:no-string-literal */\n Room.prototype['_onMessage'] = 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(() => _onMessage.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 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 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(`/${this.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 const headers = {\n 'Access-Control-Allow-Headers': 'Origin, X-Requested-With, Content-Type, Accept',\n 'Access-Control-Allow-Methods': 'OPTIONS, POST, GET',\n 'Access-Control-Allow-Origin': '*',\n 'Access-Control-Max-Age': 2592000,\n // ...\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(this.allowedRoomNameChars);\n const matchmakeIndex = matchedParams.indexOf(this.matchmakeRoute);\n const method = matchedParams[matchmakeIndex + 1];\n const name = 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(method, name, clientOptions);\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 const matchedParams = req.url.match(this.allowedRoomNameChars);\n const roomName = matchedParams.length > 1 ? matchedParams[matchedParams.length - 1] : \"\";\n\n headers['Content-Type'] = 'application/json';\n res.writeHead(200, headers);\n res.write(JSON.stringify(await matchMaker.controller.getAvailableRooms(roomName)));\n res.end();\n }\n\n }\n\n}\n"],"names":["matchMaker.setup","matchMaker.defineRoomType","matchMaker.gracefullyShutdown","matchMaker.controller.invokeMethod","matchMaker.controller.getAvailableRooms"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@colyseus/core",
3
- "version": "0.14.34",
3
+ "version": "0.14.36",
4
4
  "description": "Multiplayer Framework for Node.js.",
5
5
  "input": "./src/index.ts",
6
6
  "main": "./build/index.js",
@@ -45,5 +45,5 @@
45
45
  "publishConfig": {
46
46
  "access": "public"
47
47
  },
48
- "gitHead": "d7a378d80bdf9f4a8f7260c407ba2bb64c226832"
48
+ "gitHead": "91bf2cb492d33c314c2ccb90ee8d3c7dfad7ad58"
49
49
  }