@colyseus/core 0.15.32 → 0.15.34
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/build/MatchMaker.d.ts +9 -0
- package/build/MatchMaker.js +25 -5
- package/build/MatchMaker.js.map +3 -3
- package/build/MatchMaker.mjs +23 -5
- package/build/MatchMaker.mjs.map +3 -3
- package/build/Stats.d.ts +1 -1
- package/build/Stats.js +6 -4
- package/build/Stats.js.map +2 -2
- package/build/Stats.mjs +6 -4
- package/build/Stats.mjs.map +2 -2
- package/package.json +1 -1
package/build/MatchMaker.d.ts
CHANGED
|
@@ -25,6 +25,15 @@ export declare let driver: MatchMakerDriver;
|
|
|
25
25
|
export declare let selectProcessIdToCreateRoom: SelectProcessIdCallback;
|
|
26
26
|
export declare let isGracefullyShuttingDown: boolean;
|
|
27
27
|
export declare let onReady: Deferred;
|
|
28
|
+
export declare enum MatchMakerState {
|
|
29
|
+
INITIALIZING = 0,
|
|
30
|
+
READY = 1,
|
|
31
|
+
SHUTTING_DOWN = 2
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Internal MatchMaker state
|
|
35
|
+
*/
|
|
36
|
+
export declare let state: MatchMakerState;
|
|
28
37
|
/**
|
|
29
38
|
* @private
|
|
30
39
|
*/
|
package/build/MatchMaker.js
CHANGED
|
@@ -23,6 +23,7 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
23
23
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
24
24
|
var MatchMaker_exports = {};
|
|
25
25
|
__export(MatchMaker_exports, {
|
|
26
|
+
MatchMakerState: () => MatchMakerState,
|
|
26
27
|
accept: () => accept,
|
|
27
28
|
cleanupStaleRooms: () => cleanupStaleRooms,
|
|
28
29
|
controller: () => import_controller.default,
|
|
@@ -53,6 +54,7 @@ __export(MatchMaker_exports, {
|
|
|
53
54
|
reserveSeatFor: () => reserveSeatFor,
|
|
54
55
|
selectProcessIdToCreateRoom: () => selectProcessIdToCreateRoom,
|
|
55
56
|
setup: () => setup,
|
|
57
|
+
state: () => state,
|
|
56
58
|
stats: () => stats
|
|
57
59
|
});
|
|
58
60
|
module.exports = __toCommonJS(MatchMaker_exports);
|
|
@@ -80,13 +82,22 @@ let driver;
|
|
|
80
82
|
let selectProcessIdToCreateRoom;
|
|
81
83
|
let isGracefullyShuttingDown;
|
|
82
84
|
let onReady = new import_Utils.Deferred();
|
|
85
|
+
var MatchMakerState = /* @__PURE__ */ ((MatchMakerState2) => {
|
|
86
|
+
MatchMakerState2[MatchMakerState2["INITIALIZING"] = 0] = "INITIALIZING";
|
|
87
|
+
MatchMakerState2[MatchMakerState2["READY"] = 1] = "READY";
|
|
88
|
+
MatchMakerState2[MatchMakerState2["SHUTTING_DOWN"] = 2] = "SHUTTING_DOWN";
|
|
89
|
+
return MatchMakerState2;
|
|
90
|
+
})(MatchMakerState || {});
|
|
91
|
+
let state;
|
|
83
92
|
async function setup(_presence, _driver, _publicAddress, _selectProcessIdToCreateRoom) {
|
|
84
93
|
if (onReady === void 0) {
|
|
85
94
|
onReady = new import_Utils.Deferred();
|
|
86
95
|
}
|
|
96
|
+
state = 0 /* INITIALIZING */;
|
|
87
97
|
presence = _presence || new import_LocalPresence.LocalPresence();
|
|
88
98
|
driver = _driver || new import_driver.LocalDriver();
|
|
89
99
|
publicAddress = _publicAddress;
|
|
100
|
+
stats.reset(false);
|
|
90
101
|
if (import_DevMode.isDevMode) {
|
|
91
102
|
processId = await (0, import_DevMode.getPreviousProcessId)(await (0, import_discovery.getHostname)());
|
|
92
103
|
}
|
|
@@ -129,7 +140,8 @@ async function accept() {
|
|
|
129
140
|
}
|
|
130
141
|
}));
|
|
131
142
|
}
|
|
132
|
-
|
|
143
|
+
state = 1 /* READY */;
|
|
144
|
+
await stats.persist();
|
|
133
145
|
if (import_DevMode.isDevMode) {
|
|
134
146
|
await (0, import_DevMode.reloadFromCache)();
|
|
135
147
|
}
|
|
@@ -261,9 +273,11 @@ function getRoomClass(roomName) {
|
|
|
261
273
|
return handlers[roomName]?.klass;
|
|
262
274
|
}
|
|
263
275
|
async function createRoom(roomName, clientOptions) {
|
|
264
|
-
const selectedProcessId = await selectProcessIdToCreateRoom(roomName, clientOptions);
|
|
276
|
+
const selectedProcessId = state === 1 /* READY */ ? await selectProcessIdToCreateRoom(roomName, clientOptions) : processId;
|
|
265
277
|
let room;
|
|
266
|
-
if (selectedProcessId ===
|
|
278
|
+
if (selectedProcessId === void 0) {
|
|
279
|
+
throw new import_ServerError.ServerError(import_Protocol.ErrorCode.MATCHMAKE_UNHANDLED, `no processId available to create room ${roomName}`);
|
|
280
|
+
} else if (selectedProcessId === processId) {
|
|
267
281
|
room = await handleCreateRoom(roomName, clientOptions);
|
|
268
282
|
} else {
|
|
269
283
|
try {
|
|
@@ -355,7 +369,9 @@ function disconnectAll(closeCode) {
|
|
|
355
369
|
if (!rooms.hasOwnProperty(roomId)) {
|
|
356
370
|
continue;
|
|
357
371
|
}
|
|
358
|
-
|
|
372
|
+
const room = rooms[roomId];
|
|
373
|
+
room._events.removeAllListeners("leave");
|
|
374
|
+
promises.push(room.disconnect(closeCode));
|
|
359
375
|
}
|
|
360
376
|
return promises;
|
|
361
377
|
}
|
|
@@ -364,12 +380,14 @@ async function gracefullyShutdown() {
|
|
|
364
380
|
return Promise.reject("already_shutting_down");
|
|
365
381
|
}
|
|
366
382
|
isGracefullyShuttingDown = true;
|
|
383
|
+
state = 2 /* SHUTTING_DOWN */;
|
|
367
384
|
onReady = void 0;
|
|
368
385
|
(0, import_Debug.debugMatchMaking)(`${processId} is shutting down!`);
|
|
369
386
|
if (import_DevMode.isDevMode) {
|
|
370
387
|
await (0, import_DevMode.cacheRoomHistory)(rooms);
|
|
371
388
|
}
|
|
372
389
|
await stats.excludeProcess(processId);
|
|
390
|
+
await removeRoomsByProcessId(processId);
|
|
373
391
|
presence.unsubscribe(getProcessChannel());
|
|
374
392
|
return Promise.all(disconnectAll(
|
|
375
393
|
import_DevMode.isDevMode ? import_Protocol.Protocol.WS_CLOSE_DEVMODE_RESTART : void 0
|
|
@@ -388,7 +406,7 @@ async function reserveSeatFor(room, options, authData) {
|
|
|
388
406
|
successfulSeatReservation = await remoteRoomCall(room.roomId, "_reserveSeat", [sessionId, options, authData]);
|
|
389
407
|
} catch (e) {
|
|
390
408
|
(0, import_Debug.debugMatchMaking)(e);
|
|
391
|
-
|
|
409
|
+
throw e;
|
|
392
410
|
}
|
|
393
411
|
if (!successfulSeatReservation) {
|
|
394
412
|
throw new import_SeatReservationError.SeatReservationError(`${room.roomId} is already full.`);
|
|
@@ -500,6 +518,7 @@ function getProcessChannel(id = processId) {
|
|
|
500
518
|
}
|
|
501
519
|
// Annotate the CommonJS export names for ESM import in node:
|
|
502
520
|
0 && (module.exports = {
|
|
521
|
+
MatchMakerState,
|
|
503
522
|
accept,
|
|
504
523
|
cleanupStaleRooms,
|
|
505
524
|
controller,
|
|
@@ -530,5 +549,6 @@ function getProcessChannel(id = processId) {
|
|
|
530
549
|
reserveSeatFor,
|
|
531
550
|
selectProcessIdToCreateRoom,
|
|
532
551
|
setup,
|
|
552
|
+
state,
|
|
533
553
|
stats
|
|
534
554
|
});
|
package/build/MatchMaker.js.map
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../src/MatchMaker.ts"],
|
|
4
|
-
"sourcesContent": ["import { ErrorCode, Protocol } from './Protocol';\n\nimport { requestFromIPC, subscribeIPC } from './IPC';\n\nimport { Deferred, generateId, merge, REMOTE_ROOM_SHORT_TIMEOUT, retry } from './utils/Utils';\nimport { isDevMode, cacheRoomHistory, getPreviousProcessId, getRoomRestoreListKey, reloadFromCache } from './utils/DevMode';\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, RoomListingData, LocalDriver, MatchMakerDriver } from './matchmaker/driver';\nimport controller from './matchmaker/controller';\nimport * as stats from \"./Stats\";\n\nimport { logger } from './Logger';\nimport { Client } from './Transport';\nimport { Type } from './utils/types';\nimport { getHostname } from \"./discovery\";\n\nexport { controller, stats, type MatchMakerDriver };\n\nexport type ClientOptions = any;\nexport type AuthOptions = { token?: string, request?: any };\nexport type SelectProcessIdCallback = (roomName: string, clientOptions: ClientOptions) => Promise<string>;\n\nexport interface SeatReservation {\n sessionId: string;\n room: RoomListingData;\n devMode?: boolean;\n}\n\nconst handlers: {[id: string]: RegisteredHandler} = {};\nconst rooms: {[roomId: string]: Room} = {};\n\nexport let publicAddress: string;\nexport let processId: string;\nexport let presence: Presence;\nexport let driver: MatchMakerDriver;\nexport let selectProcessIdToCreateRoom: SelectProcessIdCallback;\n\nexport let isGracefullyShuttingDown: boolean;\nexport let onReady: Deferred = new Deferred(); // onReady needs to be immediately available to @colyseus/auth integration.\n\n/**\n * @private\n */\nexport async function setup(\n _presence?: Presence,\n _driver?: MatchMakerDriver,\n _publicAddress?: string,\n _selectProcessIdToCreateRoom?: SelectProcessIdCallback,\n) {\n if (onReady === undefined) {\n //\n // for testing purposes only: onReady is turned into undefined on shutdown\n // (needs refactoring.)\n //\n onReady = new Deferred();\n }\n\n presence = _presence || new LocalPresence();\n\n driver = _driver || new LocalDriver();\n publicAddress = _publicAddress;\n\n // devMode: try to retrieve previous processId\n if (isDevMode) { processId = await getPreviousProcessId(await getHostname()); }\n\n // ensure processId is set\n if (!processId) { processId = generateId(); }\n\n isGracefullyShuttingDown = false;\n\n /**\n * Define default `assignRoomToProcessId` method.\n * By default, return the process with least amount of rooms created\n */\n selectProcessIdToCreateRoom = _selectProcessIdToCreateRoom || async function () {\n return (await stats.fetchAll())\n .sort((p1, p2) => p1.roomCount > p2.roomCount ? 1 : -1)[0]?.processId || processId;\n };\n\n onReady.resolve();\n}\n\n/**\n * - Accept receiving remote room creation requests\n * - Check for leftover/invalid processId's on startup\n * @private\n */\nexport async function accept() {\n await onReady; // make sure \"processId\" is available\n\n /**\n * Process-level subscription\n * - handle remote process healthcheck\n * - handle remote room creation\n */\n await subscribeIPC(presence, processId, getProcessChannel(), (method, args) => {\n if (method === 'healthcheck') {\n // health check for this processId\n return true;\n\n } else {\n // handle room creation\n return handleCreateRoom.apply(undefined, args);\n }\n });\n\n /**\n * Check for leftover/invalid processId's on startup\n */\n const previousStats = await stats.fetchAll();\n if (previousStats.length > 0) {\n logger.debug(`${previousStats.length} previous processId(s) found, health-checking...`);\n await Promise.all(previousStats.map(async (stat) => {\n try {\n await requestFromIPC<RoomListingData>(\n presence,\n getProcessChannel(stat.processId),\n 'healthcheck',\n [],\n REMOTE_ROOM_SHORT_TIMEOUT,\n );\n // process succeeded to respond - nothing to do\n } catch (e) {\n // process failed to respond - remove it from stats\n logger.debug(`process ${stat.processId} failed to respond. excluding from stats`);\n const isProcessExcluded = await stats.excludeProcess(stat.processId);\n\n // clean-up possibly stale room ids\n if (isProcessExcluded && !isDevMode) {\n await removeRoomsByProcessId(stat.processId);\n }\n }\n }));\n }\n\n await stats.reset();\n\n if (isDevMode) {\n await reloadFromCache();\n }\n}\n\n/**\n * Join or create into a room and return seat reservation\n */\nexport async function joinOrCreate(roomName: string, clientOptions: ClientOptions = {}, authOptions?: AuthOptions) {\n return await retry<Promise<SeatReservation>>(async () => {\n const authData = await callOnAuth(roomName, authOptions);\n let room = await findOneRoomAvailable(roomName, clientOptions);\n\n //\n // TODO [?]\n // should we expose the \"creator\" auth data of the room during `onCreate()`?\n // it would be useful, though it could be accessed via `onJoin()` for now.\n //\n\n if (!room) {\n room = await createRoom(roomName, clientOptions);\n }\n\n return await reserveSeatFor(room, clientOptions, authData);\n }, 5, [SeatReservationError]);\n}\n\n/**\n * Create a room and return seat reservation\n */\nexport async function create(roomName: string, clientOptions: ClientOptions = {}, authOptions?: AuthOptions) {\n const authData = await callOnAuth(roomName, authOptions);\n const room = await createRoom(roomName, clientOptions);\n return reserveSeatFor(room, clientOptions, authData);\n}\n\n/**\n * Join a room and return seat reservation\n */\nexport async function join(roomName: string, clientOptions: ClientOptions = {}, authOptions?: AuthOptions) {\n return await retry<Promise<SeatReservation>>(async () => {\n const authData = await callOnAuth(roomName, authOptions);\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, authData);\n });\n}\n\n/**\n * Join a room by id and return seat reservation\n */\nexport async function reconnect(roomId: string, clientOptions: ClientOptions = {}) {\n const room = await driver.findOne({ roomId });\n if (!room) {\n // TODO: support a \"logLevel\" out of the box?\n if (process.env.NODE_ENV !== 'production') {\n logger.info(`\u274C room \"${roomId}\" has been disposed. Did you missed .allowReconnection()?\\n\uD83D\uDC49 https://docs.colyseus.io/server/room/#allowreconnection-client-seconds`);\n }\n\n throw new ServerError(ErrorCode.MATCHMAKE_INVALID_ROOM_ID, `room \"${roomId}\" has been disposed.`);\n }\n\n // check for reconnection\n const reconnectionToken = clientOptions.reconnectionToken;\n if (!reconnectionToken) { throw new ServerError(ErrorCode.MATCHMAKE_UNHANDLED, `'reconnectionToken' must be provided for reconnection.`); }\n\n\n // respond to re-connection!\n const sessionId = await remoteRoomCall(room.roomId, 'checkReconnectionToken', [reconnectionToken]);\n if (sessionId) {\n return { room, sessionId };\n\n } else {\n // TODO: support a \"logLevel\" out of the box?\n if (process.env.NODE_ENV !== 'production') {\n logger.info(`\u274C reconnection token invalid or expired. Did you missed .allowReconnection()?\\n\uD83D\uDC49 https://docs.colyseus.io/server/room/#allowreconnection-client-seconds`);\n }\n throw new ServerError(ErrorCode.MATCHMAKE_EXPIRED, `reconnection token invalid or expired.`);\n }\n}\n\n/**\n * Join a room by id and return client seat reservation. An exception is thrown if a room is not found for roomId.\n *\n * @param roomId - The Id of the specific room instance.\n * @param clientOptions - Options for the client seat reservation (for `onJoin`/`onAuth`)\n * @param authOptions - Optional authentication token\n *\n * @returns Promise<SeatReservation> - A promise which contains `sessionId` and `RoomListingData`.\n */\nexport async function joinById(roomId: string, clientOptions: ClientOptions = {}, authOptions?: AuthOptions) {\n const room = await driver.findOne({ roomId });\n\n if (!room) {\n throw new ServerError(ErrorCode.MATCHMAKE_INVALID_ROOM_ID, `room \"${roomId}\" not found`);\n\n } else if (room.locked) {\n throw new ServerError(ErrorCode.MATCHMAKE_INVALID_ROOM_ID, `room \"${roomId}\" is locked`);\n }\n\n const authData = await callOnAuth(room.name, authOptions);\n\n return reserveSeatFor(room, clientOptions, authData);\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 *\n * @param roomName - The Id of the specific room.\n * @param clientOptions - Options for the client seat reservation (for `onJoin`/`onAuth`).\n *\n * @returns Promise<RoomListingData> - A promise contaning an object which includes room metadata and configurations.\n */\nexport async function findOneRoomAvailable(roomName: string, clientOptions: ClientOptions): Promise<RoomListingData> {\n return await awaitRoomAvailable(roomName, async () => {\n const handler = getHandler(roomName);\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 *\n * @param roomId - The Id of the specific room instance.\n * @param method - Method or attribute to call or retrive.\n * @param args - Array of arguments for the method\n *\n * @returns Promise<any> - Returned value from the called or retrieved method/attribute.\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, rejectionTimeout);\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 && JSON.parse(JSON.stringify(args))));\n }\n}\n\nexport function defineRoomType<T extends Type<Room>>(\n roomName: string,\n klass: T,\n defaultOptions?: Parameters<NonNullable<InstanceType<T>['onCreate']>>[0],\n) {\n const registeredHandler = new RegisteredHandler(klass, defaultOptions);\n\n handlers[roomName] = registeredHandler;\n\n if (klass.prototype['onAuth'] !== Room.prototype['onAuth']) {\n // TODO: soft-deprecate instance level `onAuth` on 0.16\n // logger.warn(\"DEPRECATION WARNING: onAuth() at the instance level will be deprecated soon. Please use static onAuth() instead.\");\n\n if (klass['onAuth'] !== Room['onAuth']) {\n logger.info(`\u274C \"${roomName}\"'s onAuth() defined at the instance level will be ignored.`);\n }\n }\n\n if (!isDevMode) {\n cleanupStaleRooms(roomName);\n }\n\n return registeredHandler;\n}\n\nexport function removeRoomType(roomName: string) {\n delete handlers[roomName];\n\n if (!isDevMode) {\n cleanupStaleRooms(roomName);\n }\n}\n\n// TODO: legacy; remove me on 1.0\nexport function hasHandler(roomName: string) {\n logger.warn(\"hasHandler() is deprecated. Use getHandler() instead.\");\n return handlers[roomName] !== undefined;\n}\n\nexport function getHandler(roomName: string) {\n const handler = handlers[roomName];\n\n if (!handler) {\n throw new ServerError(ErrorCode.MATCHMAKE_NO_HANDLER, `provided room name \"${roomName}\" not defined`);\n }\n\n return handler;\n}\n\nexport function getRoomClass(roomName: string): Type<Room> {\n return handlers[roomName]?.klass;\n}\n\n\n/**\n * Creates a new room.\n *\n * @param roomName - The identifier you defined on `gameServer.define()`\n * @param clientOptions - Options for `onCreate`\n *\n * @returns Promise<RoomListingData> - A promise contaning an object which includes room metadata and configurations.\n */\nexport async function createRoom(roomName: string, clientOptions: ClientOptions): Promise<RoomListingData> {\n const selectedProcessId = await selectProcessIdToCreateRoom(roomName, clientOptions);\n\n let room: RoomListingData;\n if (selectedProcessId === processId) {\n // create the room on this process!\n room = await handleCreateRoom(roomName, clientOptions);\n\n } else {\n // ask other process to create the room!\n try {\n room = await requestFromIPC<RoomListingData>(\n presence,\n getProcessChannel(selectedProcessId),\n undefined,\n [roomName, clientOptions],\n REMOTE_ROOM_SHORT_TIMEOUT,\n );\n\n } catch (e) {\n if (e.message === \"ipc_timeout\") {\n debugAndPrintError(`${e.message}: create room request timed out for ${roomName} on processId ${selectedProcessId}.`);\n\n //\n // clean-up possibly stale process from redis.\n // when a process disconnects ungracefully, it may leave its previous processId under \"roomcount\"\n // if the process is still alive, it will re-add itself shortly after the load-balancer selects it again.\n //\n await stats.excludeProcess(selectedProcessId);\n\n // if other process failed to respond, create the room on this process\n room = await handleCreateRoom(roomName, clientOptions);\n\n } else {\n // re-throw intentional exception thrown during remote onCreate()\n throw e;\n }\n }\n }\n\n if (isDevMode) {\n presence.hset(getRoomRestoreListKey(), room.roomId, JSON.stringify({\n \"clientOptions\": clientOptions,\n \"roomName\": roomName,\n \"processId\": processId\n }));\n }\n\n return room;\n}\n\nexport async function handleCreateRoom(roomName: string, clientOptions: ClientOptions, restoringRoomId?: string): Promise<RoomListingData> {\n const handler = getHandler(roomName);\n const room = new handler.klass();\n\n // set room public attributes\n if (restoringRoomId && isDevMode) {\n room.roomId = restoringRoomId;\n\n } else {\n room.roomId = generateId();\n }\n\n room.roomName = roomName;\n room.presence = presence;\n\n const additionalListingData: any = handler.getFilterOptions(clientOptions);\n\n // assign public host\n if (publicAddress) {\n additionalListingData.publicAddress = publicAddress;\n }\n\n // create a RoomCache reference.\n room.listing = driver.createInstance({\n name: roomName,\n processId,\n ...additionalListingData\n });\n\n if (room.onCreate) {\n try {\n await room.onCreate(merge({}, clientOptions, handler.options));\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 // increment amount of rooms this process is handling\n stats.local.roomCount++;\n stats.persist();\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.on('visibility-change', onVisibilityChange.bind(this, room));\n room._events.once('dispose', disposeRoom.bind(this, roomName, room));\n\n // when disconnect()'ing, keep only join/leave events for stat counting\n room._events.once('disconnect', () => {\n room._events.removeAllListeners('lock');\n room._events.removeAllListeners('unlock');\n room._events.removeAllListeners('visibility-change');\n room._events.removeAllListeners('dispose');\n });\n\n // room always start unlocked\n await createRoomReferences(room, true);\n await room.listing.save();\n\n handler.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(closeCode?: number) {\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(closeCode));\n }\n\n return promises;\n}\n\nexport async function gracefullyShutdown(): Promise<any> {\n if (isGracefullyShuttingDown) {\n return Promise.reject('already_shutting_down');\n }\n\n isGracefullyShuttingDown = true;\n onReady = undefined;\n\n debugMatchMaking(`${processId} is shutting down!`);\n\n if (isDevMode) {\n await cacheRoomHistory(rooms);\n }\n\n // remove processId from room count key\n await stats.excludeProcess(processId);\n\n // unsubscribe from process id channel\n presence.unsubscribe(getProcessChannel());\n\n return Promise.all(disconnectAll(\n (isDevMode)\n ? Protocol.WS_CLOSE_DEVMODE_RESTART\n : undefined\n ));\n}\n\n/**\n * Reserve a seat for a client in a room\n */\nexport async function reserveSeatFor(room: RoomListingData, options: ClientOptions, authData?: 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, authData]);\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 const response: SeatReservation = { room, sessionId };\n\n if (isDevMode) {\n response.devMode = isDevMode;\n }\n\n return response;\n}\n\nfunction callOnAuth(roomName: string, authOptions?: AuthOptions) {\n const roomClass = getRoomClass(roomName);\n return (roomClass && roomClass['onAuth'] && roomClass['onAuth'] !== Room['onAuth'])\n ? roomClass['onAuth'](authOptions.token, authOptions.request)\n : undefined;\n}\n\nexport async function cleanupStaleRooms(roomName: string) {\n // remove connecting counts\n await presence.del(getHandlerConcurrencyKey(roomName));\n}\n\nasync function removeRoomsByProcessId(processId: 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 if (typeof(driver.cleanup) === \"function\") {\n await driver.cleanup(processId);\n\n } else {\n //\n // TODO: remove this block on 1.0.\n //\n // driver.cleanup() has been added mid-way through 0.15\n // some users may still be using older versions of the driver.\n //\n const cachedRooms = await driver.find({ processId }, { _id: 1 });\n logger.debug(\"removing stale rooms by processId:\", processId, `(${cachedRooms.length} rooms found)`);\n cachedRooms.forEach((room) => room.remove());\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 //\n // avoid having too long timeout if 10+ clients ask to join at the same time\n //\n // TODO: we need a better solution here. either a lock or queue system should be implemented instead.\n // https://github.com/colyseus/colyseus/issues/466\n //\n const concurrencyTimeout = Math.min(concurrency * 100, 500);\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 // increment local CCU\n stats.local.ccu++;\n stats.persist();\n\n handlers[room.roomName].emit('join', room, client);\n}\n\nfunction onClientLeaveRoom(room: Room, client: Client, willDispose: boolean) {\n // decrement local CCU\n stats.local.ccu--;\n stats.persist();\n\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\nfunction onVisibilityChange(room: Room, isInvisible: boolean): void {\n handlers[room.roomName].emit('visibility-change', room, isInvisible);\n}\n\nasync function disposeRoom(roomName: string, room: Room) {\n debugMatchMaking('disposing \\'%s\\' (%s) on processId \\'%s\\' (graceful shutdown: %s)', roomName, room.roomId, processId, isGracefullyShuttingDown);\n\n // decrease amount of rooms this process is handling\n if (!isGracefullyShuttingDown) {\n stats.local.roomCount--;\n stats.persist();\n\n // remove from devMode restore list\n if (isDevMode) {\n await presence.hdel(getRoomRestoreListKey(), room.roomId);\n }\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//\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"],
|
|
5
|
-
"mappings": "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",
|
|
6
|
-
"names": ["controller", "processId"]
|
|
4
|
+
"sourcesContent": ["import { ErrorCode, Protocol } from './Protocol';\n\nimport { requestFromIPC, subscribeIPC } from './IPC';\n\nimport { Deferred, generateId, merge, REMOTE_ROOM_SHORT_TIMEOUT, retry } from './utils/Utils';\nimport { isDevMode, cacheRoomHistory, getPreviousProcessId, getRoomRestoreListKey, reloadFromCache } from './utils/DevMode';\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, RoomListingData, LocalDriver, MatchMakerDriver } from './matchmaker/driver';\nimport controller from './matchmaker/controller';\nimport * as stats from \"./Stats\";\n\nimport { logger } from './Logger';\nimport { Client } from './Transport';\nimport { Type } from './utils/types';\nimport { getHostname } from \"./discovery\";\n\nexport { controller, stats, type MatchMakerDriver };\n\nexport type ClientOptions = any;\nexport type AuthOptions = { token?: string, request?: any };\nexport type SelectProcessIdCallback = (roomName: string, clientOptions: ClientOptions) => Promise<string>;\n\nexport interface SeatReservation {\n sessionId: string;\n room: RoomListingData;\n devMode?: boolean;\n}\n\nconst handlers: {[id: string]: RegisteredHandler} = {};\nconst rooms: {[roomId: string]: Room} = {};\n\nexport let publicAddress: string;\nexport let processId: string;\nexport let presence: Presence;\nexport let driver: MatchMakerDriver;\nexport let selectProcessIdToCreateRoom: SelectProcessIdCallback;\n\nexport let isGracefullyShuttingDown: boolean; // TODO: remove me on 1.0, use 'state' instead\nexport let onReady: Deferred = new Deferred(); // onReady needs to be immediately available to @colyseus/auth integration.\n\nexport enum MatchMakerState {\n INITIALIZING,\n READY,\n SHUTTING_DOWN\n}\n\n/**\n * Internal MatchMaker state\n */\nexport let state: MatchMakerState;\n\n/**\n * @private\n */\nexport async function setup(\n _presence?: Presence,\n _driver?: MatchMakerDriver,\n _publicAddress?: string,\n _selectProcessIdToCreateRoom?: SelectProcessIdCallback,\n) {\n if (onReady === undefined) {\n //\n // for testing purposes only: onReady is turned into undefined on shutdown\n // (needs refactoring.)\n //\n onReady = new Deferred();\n }\n\n state = MatchMakerState.INITIALIZING;\n\n presence = _presence || new LocalPresence();\n\n driver = _driver || new LocalDriver();\n publicAddress = _publicAddress;\n\n stats.reset(false);\n\n // devMode: try to retrieve previous processId\n if (isDevMode) { processId = await getPreviousProcessId(await getHostname()); }\n\n // ensure processId is set\n if (!processId) { processId = generateId(); }\n\n isGracefullyShuttingDown = false;\n\n /**\n * Define default `assignRoomToProcessId` method.\n * By default, return the process with least amount of rooms created\n */\n selectProcessIdToCreateRoom = _selectProcessIdToCreateRoom || async function () {\n return (await stats.fetchAll())\n .sort((p1, p2) => p1.roomCount > p2.roomCount ? 1 : -1)[0]?.processId || processId;\n };\n\n onReady.resolve();\n}\n\n/**\n * - Accept receiving remote room creation requests\n * - Check for leftover/invalid processId's on startup\n * @private\n */\nexport async function accept() {\n await onReady; // make sure \"processId\" is available\n\n /**\n * Process-level subscription\n * - handle remote process healthcheck\n * - handle remote room creation\n */\n await subscribeIPC(presence, processId, getProcessChannel(), (method, args) => {\n if (method === 'healthcheck') {\n // health check for this processId\n return true;\n\n } else {\n // handle room creation\n return handleCreateRoom.apply(undefined, args);\n }\n });\n\n /**\n * Check for leftover/invalid processId's on startup\n */\n const previousStats = await stats.fetchAll();\n if (previousStats.length > 0) {\n logger.debug(`${previousStats.length} previous processId(s) found, health-checking...`);\n await Promise.all(previousStats.map(async (stat) => {\n try {\n await requestFromIPC<RoomListingData>(\n presence,\n getProcessChannel(stat.processId),\n 'healthcheck',\n [],\n REMOTE_ROOM_SHORT_TIMEOUT,\n );\n // process succeeded to respond - nothing to do\n } catch (e) {\n // process failed to respond - remove it from stats\n logger.debug(`process ${stat.processId} failed to respond. excluding from stats`);\n const isProcessExcluded = await stats.excludeProcess(stat.processId);\n\n // clean-up possibly stale room ids\n if (isProcessExcluded && !isDevMode) {\n await removeRoomsByProcessId(stat.processId);\n }\n }\n }));\n }\n\n state = MatchMakerState.READY;\n\n await stats.persist();\n\n if (isDevMode) {\n await reloadFromCache();\n }\n}\n\n/**\n * Join or create into a room and return seat reservation\n */\nexport async function joinOrCreate(roomName: string, clientOptions: ClientOptions = {}, authOptions?: AuthOptions) {\n return await retry<Promise<SeatReservation>>(async () => {\n const authData = await callOnAuth(roomName, authOptions);\n let room = await findOneRoomAvailable(roomName, clientOptions);\n\n //\n // TODO [?]\n // should we expose the \"creator\" auth data of the room during `onCreate()`?\n // it would be useful, though it could be accessed via `onJoin()` for now.\n //\n\n if (!room) {\n room = await createRoom(roomName, clientOptions);\n }\n\n return await reserveSeatFor(room, clientOptions, authData);\n }, 5, [SeatReservationError]);\n}\n\n/**\n * Create a room and return seat reservation\n */\nexport async function create(roomName: string, clientOptions: ClientOptions = {}, authOptions?: AuthOptions) {\n const authData = await callOnAuth(roomName, authOptions);\n const room = await createRoom(roomName, clientOptions);\n return reserveSeatFor(room, clientOptions, authData);\n}\n\n/**\n * Join a room and return seat reservation\n */\nexport async function join(roomName: string, clientOptions: ClientOptions = {}, authOptions?: AuthOptions) {\n return await retry<Promise<SeatReservation>>(async () => {\n const authData = await callOnAuth(roomName, authOptions);\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, authData);\n });\n}\n\n/**\n * Join a room by id and return seat reservation\n */\nexport async function reconnect(roomId: string, clientOptions: ClientOptions = {}) {\n const room = await driver.findOne({ roomId });\n if (!room) {\n // TODO: support a \"logLevel\" out of the box?\n if (process.env.NODE_ENV !== 'production') {\n logger.info(`\u274C room \"${roomId}\" has been disposed. Did you missed .allowReconnection()?\\n\uD83D\uDC49 https://docs.colyseus.io/server/room/#allowreconnection-client-seconds`);\n }\n\n throw new ServerError(ErrorCode.MATCHMAKE_INVALID_ROOM_ID, `room \"${roomId}\" has been disposed.`);\n }\n\n // check for reconnection\n const reconnectionToken = clientOptions.reconnectionToken;\n if (!reconnectionToken) { throw new ServerError(ErrorCode.MATCHMAKE_UNHANDLED, `'reconnectionToken' must be provided for reconnection.`); }\n\n\n // respond to re-connection!\n const sessionId = await remoteRoomCall(room.roomId, 'checkReconnectionToken', [reconnectionToken]);\n if (sessionId) {\n return { room, sessionId };\n\n } else {\n // TODO: support a \"logLevel\" out of the box?\n if (process.env.NODE_ENV !== 'production') {\n logger.info(`\u274C reconnection token invalid or expired. Did you missed .allowReconnection()?\\n\uD83D\uDC49 https://docs.colyseus.io/server/room/#allowreconnection-client-seconds`);\n }\n throw new ServerError(ErrorCode.MATCHMAKE_EXPIRED, `reconnection token invalid or expired.`);\n }\n}\n\n/**\n * Join a room by id and return client seat reservation. An exception is thrown if a room is not found for roomId.\n *\n * @param roomId - The Id of the specific room instance.\n * @param clientOptions - Options for the client seat reservation (for `onJoin`/`onAuth`)\n * @param authOptions - Optional authentication token\n *\n * @returns Promise<SeatReservation> - A promise which contains `sessionId` and `RoomListingData`.\n */\nexport async function joinById(roomId: string, clientOptions: ClientOptions = {}, authOptions?: AuthOptions) {\n const room = await driver.findOne({ roomId });\n\n if (!room) {\n throw new ServerError(ErrorCode.MATCHMAKE_INVALID_ROOM_ID, `room \"${roomId}\" not found`);\n\n } else if (room.locked) {\n throw new ServerError(ErrorCode.MATCHMAKE_INVALID_ROOM_ID, `room \"${roomId}\" is locked`);\n }\n\n const authData = await callOnAuth(room.name, authOptions);\n\n return reserveSeatFor(room, clientOptions, authData);\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 *\n * @param roomName - The Id of the specific room.\n * @param clientOptions - Options for the client seat reservation (for `onJoin`/`onAuth`).\n *\n * @returns Promise<RoomListingData> - A promise contaning an object which includes room metadata and configurations.\n */\nexport async function findOneRoomAvailable(roomName: string, clientOptions: ClientOptions): Promise<RoomListingData> {\n return await awaitRoomAvailable(roomName, async () => {\n const handler = getHandler(roomName);\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 *\n * @param roomId - The Id of the specific room instance.\n * @param method - Method or attribute to call or retrive.\n * @param args - Array of arguments for the method\n *\n * @returns Promise<any> - Returned value from the called or retrieved method/attribute.\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, rejectionTimeout);\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 && JSON.parse(JSON.stringify(args))));\n }\n}\n\nexport function defineRoomType<T extends Type<Room>>(\n roomName: string,\n klass: T,\n defaultOptions?: Parameters<NonNullable<InstanceType<T>['onCreate']>>[0],\n) {\n const registeredHandler = new RegisteredHandler(klass, defaultOptions);\n\n handlers[roomName] = registeredHandler;\n\n if (klass.prototype['onAuth'] !== Room.prototype['onAuth']) {\n // TODO: soft-deprecate instance level `onAuth` on 0.16\n // logger.warn(\"DEPRECATION WARNING: onAuth() at the instance level will be deprecated soon. Please use static onAuth() instead.\");\n\n if (klass['onAuth'] !== Room['onAuth']) {\n logger.info(`\u274C \"${roomName}\"'s onAuth() defined at the instance level will be ignored.`);\n }\n }\n\n if (!isDevMode) {\n cleanupStaleRooms(roomName);\n }\n\n return registeredHandler;\n}\n\nexport function removeRoomType(roomName: string) {\n delete handlers[roomName];\n\n if (!isDevMode) {\n cleanupStaleRooms(roomName);\n }\n}\n\n// TODO: legacy; remove me on 1.0\nexport function hasHandler(roomName: string) {\n logger.warn(\"hasHandler() is deprecated. Use getHandler() instead.\");\n return handlers[roomName] !== undefined;\n}\n\nexport function getHandler(roomName: string) {\n const handler = handlers[roomName];\n\n if (!handler) {\n throw new ServerError(ErrorCode.MATCHMAKE_NO_HANDLER, `provided room name \"${roomName}\" not defined`);\n }\n\n return handler;\n}\n\nexport function getRoomClass(roomName: string): Type<Room> {\n return handlers[roomName]?.klass;\n}\n\n\n/**\n * Creates a new room.\n *\n * @param roomName - The identifier you defined on `gameServer.define()`\n * @param clientOptions - Options for `onCreate`\n *\n * @returns Promise<RoomListingData> - A promise contaning an object which includes room metadata and configurations.\n */\nexport async function createRoom(roomName: string, clientOptions: ClientOptions): Promise<RoomListingData> {\n //\n // - select a process to create the room\n // - use local processId if MatchMaker is not ready yet\n //\n const selectedProcessId = (state === MatchMakerState.READY)\n ? await selectProcessIdToCreateRoom(roomName, clientOptions)\n : processId;\n\n let room: RoomListingData;\n if (selectedProcessId === undefined) {\n throw new ServerError(ErrorCode.MATCHMAKE_UNHANDLED, `no processId available to create room ${roomName}`);\n\n } else if (selectedProcessId === processId) {\n // create the room on this process!\n room = await handleCreateRoom(roomName, clientOptions);\n\n } else {\n // ask other process to create the room!\n try {\n room = await requestFromIPC<RoomListingData>(\n presence,\n getProcessChannel(selectedProcessId),\n undefined,\n [roomName, clientOptions],\n REMOTE_ROOM_SHORT_TIMEOUT,\n );\n\n } catch (e) {\n if (e.message === \"ipc_timeout\") {\n debugAndPrintError(`${e.message}: create room request timed out for ${roomName} on processId ${selectedProcessId}.`);\n\n //\n // clean-up possibly stale process from redis.\n // when a process disconnects ungracefully, it may leave its previous processId under \"roomcount\"\n // if the process is still alive, it will re-add itself shortly after the load-balancer selects it again.\n //\n await stats.excludeProcess(selectedProcessId);\n\n // if other process failed to respond, create the room on this process\n room = await handleCreateRoom(roomName, clientOptions);\n\n } else {\n // re-throw intentional exception thrown during remote onCreate()\n throw e;\n }\n }\n }\n\n if (isDevMode) {\n presence.hset(getRoomRestoreListKey(), room.roomId, JSON.stringify({\n \"clientOptions\": clientOptions,\n \"roomName\": roomName,\n \"processId\": processId\n }));\n }\n\n return room;\n}\n\nexport async function handleCreateRoom(roomName: string, clientOptions: ClientOptions, restoringRoomId?: string): Promise<RoomListingData> {\n const handler = getHandler(roomName);\n const room = new handler.klass();\n\n // set room public attributes\n if (restoringRoomId && isDevMode) {\n room.roomId = restoringRoomId;\n\n } else {\n room.roomId = generateId();\n }\n\n room.roomName = roomName;\n room.presence = presence;\n\n const additionalListingData: any = handler.getFilterOptions(clientOptions);\n\n // assign public host\n if (publicAddress) {\n additionalListingData.publicAddress = publicAddress;\n }\n\n // create a RoomCache reference.\n room.listing = driver.createInstance({\n name: roomName,\n processId,\n ...additionalListingData\n });\n\n if (room.onCreate) {\n try {\n await room.onCreate(merge({}, clientOptions, handler.options));\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 // increment amount of rooms this process is handling\n stats.local.roomCount++;\n stats.persist();\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.on('visibility-change', onVisibilityChange.bind(this, room));\n room._events.once('dispose', disposeRoom.bind(this, roomName, room));\n\n // when disconnect()'ing, keep only join/leave events for stat counting\n room._events.once('disconnect', () => {\n room._events.removeAllListeners('lock');\n room._events.removeAllListeners('unlock');\n room._events.removeAllListeners('visibility-change');\n room._events.removeAllListeners('dispose');\n });\n\n // room always start unlocked\n await createRoomReferences(room, true);\n await room.listing.save();\n\n handler.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(closeCode?: number) {\n const promises: Array<Promise<any>> = [];\n\n for (const roomId in rooms) {\n if (!rooms.hasOwnProperty(roomId)) {\n continue;\n }\n\n const room = rooms[roomId];\n\n // prevent touching stats when process is shutting down\n room._events.removeAllListeners(\"leave\");\n\n promises.push(room.disconnect(closeCode));\n }\n\n return promises;\n}\n\nexport async function gracefullyShutdown(): Promise<any> {\n if (isGracefullyShuttingDown) {\n return Promise.reject('already_shutting_down');\n }\n\n isGracefullyShuttingDown = true;\n state = MatchMakerState.SHUTTING_DOWN;\n\n onReady = undefined;\n\n debugMatchMaking(`${processId} is shutting down!`);\n\n if (isDevMode) {\n await cacheRoomHistory(rooms);\n }\n\n // remove processId from room count key\n await stats.excludeProcess(processId);\n\n // remove cached rooms of this process\n await removeRoomsByProcessId(processId);\n\n // unsubscribe from process id channel\n presence.unsubscribe(getProcessChannel());\n\n return Promise.all(disconnectAll(\n (isDevMode)\n ? Protocol.WS_CLOSE_DEVMODE_RESTART\n : undefined\n ));\n}\n\n/**\n * Reserve a seat for a client in a room\n */\nexport async function reserveSeatFor(room: RoomListingData, options: ClientOptions, authData?: 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, authData]);\n\n } catch (e) {\n // throwing here generally means a room cache from an unavailable process is\n // being used (room from a process not gracefully shut down)\n debugMatchMaking(e);\n throw e;\n }\n\n if (!successfulSeatReservation) {\n throw new SeatReservationError(`${room.roomId} is already full.`);\n }\n\n const response: SeatReservation = { room, sessionId };\n\n if (isDevMode) {\n response.devMode = isDevMode;\n }\n\n return response;\n}\n\nfunction callOnAuth(roomName: string, authOptions?: AuthOptions) {\n const roomClass = getRoomClass(roomName);\n return (roomClass && roomClass['onAuth'] && roomClass['onAuth'] !== Room['onAuth'])\n ? roomClass['onAuth'](authOptions.token, authOptions.request)\n : undefined;\n}\n\nexport async function cleanupStaleRooms(roomName: string) {\n // remove connecting counts\n await presence.del(getHandlerConcurrencyKey(roomName));\n}\n\nasync function removeRoomsByProcessId(processId: 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 if (typeof(driver.cleanup) === \"function\") {\n await driver.cleanup(processId);\n\n } else {\n //\n // TODO: remove this block on 1.0.\n //\n // driver.cleanup() has been added mid-way through 0.15\n // some users may still be using older versions of the driver.\n //\n const cachedRooms = await driver.find({ processId }, { _id: 1 });\n logger.debug(\"removing stale rooms by processId:\", processId, `(${cachedRooms.length} rooms found)`);\n cachedRooms.forEach((room) => room.remove());\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 //\n // avoid having too long timeout if 10+ clients ask to join at the same time\n //\n // TODO: we need a better solution here. either a lock or queue system should be implemented instead.\n // https://github.com/colyseus/colyseus/issues/466\n //\n const concurrencyTimeout = Math.min(concurrency * 100, 500);\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 // increment local CCU\n stats.local.ccu++;\n stats.persist();\n\n handlers[room.roomName].emit('join', room, client);\n}\n\nfunction onClientLeaveRoom(room: Room, client: Client, willDispose: boolean) {\n // decrement local CCU\n stats.local.ccu--;\n stats.persist();\n\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\nfunction onVisibilityChange(room: Room, isInvisible: boolean): void {\n handlers[room.roomName].emit('visibility-change', room, isInvisible);\n}\n\nasync function disposeRoom(roomName: string, room: Room) {\n debugMatchMaking('disposing \\'%s\\' (%s) on processId \\'%s\\' (graceful shutdown: %s)', roomName, room.roomId, processId, isGracefullyShuttingDown);\n\n // decrease amount of rooms this process is handling\n if (!isGracefullyShuttingDown) {\n stats.local.roomCount--;\n stats.persist();\n\n // remove from devMode restore list\n if (isDevMode) {\n await presence.hdel(getRoomRestoreListKey(), room.roomId);\n }\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//\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"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": ["controller", "MatchMakerState", "processId"]
|
|
7
7
|
}
|
package/build/MatchMaker.mjs
CHANGED
|
@@ -22,13 +22,22 @@ let driver;
|
|
|
22
22
|
let selectProcessIdToCreateRoom;
|
|
23
23
|
let isGracefullyShuttingDown;
|
|
24
24
|
let onReady = new Deferred();
|
|
25
|
+
var MatchMakerState = /* @__PURE__ */ ((MatchMakerState2) => {
|
|
26
|
+
MatchMakerState2[MatchMakerState2["INITIALIZING"] = 0] = "INITIALIZING";
|
|
27
|
+
MatchMakerState2[MatchMakerState2["READY"] = 1] = "READY";
|
|
28
|
+
MatchMakerState2[MatchMakerState2["SHUTTING_DOWN"] = 2] = "SHUTTING_DOWN";
|
|
29
|
+
return MatchMakerState2;
|
|
30
|
+
})(MatchMakerState || {});
|
|
31
|
+
let state;
|
|
25
32
|
async function setup(_presence, _driver, _publicAddress, _selectProcessIdToCreateRoom) {
|
|
26
33
|
if (onReady === void 0) {
|
|
27
34
|
onReady = new Deferred();
|
|
28
35
|
}
|
|
36
|
+
state = 0 /* INITIALIZING */;
|
|
29
37
|
presence = _presence || new LocalPresence();
|
|
30
38
|
driver = _driver || new LocalDriver();
|
|
31
39
|
publicAddress = _publicAddress;
|
|
40
|
+
stats.reset(false);
|
|
32
41
|
if (isDevMode) {
|
|
33
42
|
processId = await getPreviousProcessId(await getHostname());
|
|
34
43
|
}
|
|
@@ -71,7 +80,8 @@ async function accept() {
|
|
|
71
80
|
}
|
|
72
81
|
}));
|
|
73
82
|
}
|
|
74
|
-
|
|
83
|
+
state = 1 /* READY */;
|
|
84
|
+
await stats.persist();
|
|
75
85
|
if (isDevMode) {
|
|
76
86
|
await reloadFromCache();
|
|
77
87
|
}
|
|
@@ -203,9 +213,11 @@ function getRoomClass(roomName) {
|
|
|
203
213
|
return handlers[roomName]?.klass;
|
|
204
214
|
}
|
|
205
215
|
async function createRoom(roomName, clientOptions) {
|
|
206
|
-
const selectedProcessId = await selectProcessIdToCreateRoom(roomName, clientOptions);
|
|
216
|
+
const selectedProcessId = state === 1 /* READY */ ? await selectProcessIdToCreateRoom(roomName, clientOptions) : processId;
|
|
207
217
|
let room;
|
|
208
|
-
if (selectedProcessId ===
|
|
218
|
+
if (selectedProcessId === void 0) {
|
|
219
|
+
throw new ServerError(ErrorCode.MATCHMAKE_UNHANDLED, `no processId available to create room ${roomName}`);
|
|
220
|
+
} else if (selectedProcessId === processId) {
|
|
209
221
|
room = await handleCreateRoom(roomName, clientOptions);
|
|
210
222
|
} else {
|
|
211
223
|
try {
|
|
@@ -297,7 +309,9 @@ function disconnectAll(closeCode) {
|
|
|
297
309
|
if (!rooms.hasOwnProperty(roomId)) {
|
|
298
310
|
continue;
|
|
299
311
|
}
|
|
300
|
-
|
|
312
|
+
const room = rooms[roomId];
|
|
313
|
+
room._events.removeAllListeners("leave");
|
|
314
|
+
promises.push(room.disconnect(closeCode));
|
|
301
315
|
}
|
|
302
316
|
return promises;
|
|
303
317
|
}
|
|
@@ -306,12 +320,14 @@ async function gracefullyShutdown() {
|
|
|
306
320
|
return Promise.reject("already_shutting_down");
|
|
307
321
|
}
|
|
308
322
|
isGracefullyShuttingDown = true;
|
|
323
|
+
state = 2 /* SHUTTING_DOWN */;
|
|
309
324
|
onReady = void 0;
|
|
310
325
|
debugMatchMaking(`${processId} is shutting down!`);
|
|
311
326
|
if (isDevMode) {
|
|
312
327
|
await cacheRoomHistory(rooms);
|
|
313
328
|
}
|
|
314
329
|
await stats.excludeProcess(processId);
|
|
330
|
+
await removeRoomsByProcessId(processId);
|
|
315
331
|
presence.unsubscribe(getProcessChannel());
|
|
316
332
|
return Promise.all(disconnectAll(
|
|
317
333
|
isDevMode ? Protocol.WS_CLOSE_DEVMODE_RESTART : void 0
|
|
@@ -330,7 +346,7 @@ async function reserveSeatFor(room, options, authData) {
|
|
|
330
346
|
successfulSeatReservation = await remoteRoomCall(room.roomId, "_reserveSeat", [sessionId, options, authData]);
|
|
331
347
|
} catch (e) {
|
|
332
348
|
debugMatchMaking(e);
|
|
333
|
-
|
|
349
|
+
throw e;
|
|
334
350
|
}
|
|
335
351
|
if (!successfulSeatReservation) {
|
|
336
352
|
throw new SeatReservationError(`${room.roomId} is already full.`);
|
|
@@ -441,6 +457,7 @@ function getProcessChannel(id = processId) {
|
|
|
441
457
|
return `p:${id}`;
|
|
442
458
|
}
|
|
443
459
|
export {
|
|
460
|
+
MatchMakerState,
|
|
444
461
|
accept,
|
|
445
462
|
cleanupStaleRooms,
|
|
446
463
|
controller,
|
|
@@ -471,5 +488,6 @@ export {
|
|
|
471
488
|
reserveSeatFor,
|
|
472
489
|
selectProcessIdToCreateRoom,
|
|
473
490
|
setup,
|
|
491
|
+
state,
|
|
474
492
|
stats
|
|
475
493
|
};
|
package/build/MatchMaker.mjs.map
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../src/MatchMaker.ts"],
|
|
4
|
-
"sourcesContent": ["import { ErrorCode, Protocol } from './Protocol';\n\nimport { requestFromIPC, subscribeIPC } from './IPC';\n\nimport { Deferred, generateId, merge, REMOTE_ROOM_SHORT_TIMEOUT, retry } from './utils/Utils';\nimport { isDevMode, cacheRoomHistory, getPreviousProcessId, getRoomRestoreListKey, reloadFromCache } from './utils/DevMode';\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, RoomListingData, LocalDriver, MatchMakerDriver } from './matchmaker/driver';\nimport controller from './matchmaker/controller';\nimport * as stats from \"./Stats\";\n\nimport { logger } from './Logger';\nimport { Client } from './Transport';\nimport { Type } from './utils/types';\nimport { getHostname } from \"./discovery\";\n\nexport { controller, stats, type MatchMakerDriver };\n\nexport type ClientOptions = any;\nexport type AuthOptions = { token?: string, request?: any };\nexport type SelectProcessIdCallback = (roomName: string, clientOptions: ClientOptions) => Promise<string>;\n\nexport interface SeatReservation {\n sessionId: string;\n room: RoomListingData;\n devMode?: boolean;\n}\n\nconst handlers: {[id: string]: RegisteredHandler} = {};\nconst rooms: {[roomId: string]: Room} = {};\n\nexport let publicAddress: string;\nexport let processId: string;\nexport let presence: Presence;\nexport let driver: MatchMakerDriver;\nexport let selectProcessIdToCreateRoom: SelectProcessIdCallback;\n\nexport let isGracefullyShuttingDown: boolean;\nexport let onReady: Deferred = new Deferred(); // onReady needs to be immediately available to @colyseus/auth integration.\n\n/**\n * @private\n */\nexport async function setup(\n _presence?: Presence,\n _driver?: MatchMakerDriver,\n _publicAddress?: string,\n _selectProcessIdToCreateRoom?: SelectProcessIdCallback,\n) {\n if (onReady === undefined) {\n //\n // for testing purposes only: onReady is turned into undefined on shutdown\n // (needs refactoring.)\n //\n onReady = new Deferred();\n }\n\n presence = _presence || new LocalPresence();\n\n driver = _driver || new LocalDriver();\n publicAddress = _publicAddress;\n\n // devMode: try to retrieve previous processId\n if (isDevMode) { processId = await getPreviousProcessId(await getHostname()); }\n\n // ensure processId is set\n if (!processId) { processId = generateId(); }\n\n isGracefullyShuttingDown = false;\n\n /**\n * Define default `assignRoomToProcessId` method.\n * By default, return the process with least amount of rooms created\n */\n selectProcessIdToCreateRoom = _selectProcessIdToCreateRoom || async function () {\n return (await stats.fetchAll())\n .sort((p1, p2) => p1.roomCount > p2.roomCount ? 1 : -1)[0]?.processId || processId;\n };\n\n onReady.resolve();\n}\n\n/**\n * - Accept receiving remote room creation requests\n * - Check for leftover/invalid processId's on startup\n * @private\n */\nexport async function accept() {\n await onReady; // make sure \"processId\" is available\n\n /**\n * Process-level subscription\n * - handle remote process healthcheck\n * - handle remote room creation\n */\n await subscribeIPC(presence, processId, getProcessChannel(), (method, args) => {\n if (method === 'healthcheck') {\n // health check for this processId\n return true;\n\n } else {\n // handle room creation\n return handleCreateRoom.apply(undefined, args);\n }\n });\n\n /**\n * Check for leftover/invalid processId's on startup\n */\n const previousStats = await stats.fetchAll();\n if (previousStats.length > 0) {\n logger.debug(`${previousStats.length} previous processId(s) found, health-checking...`);\n await Promise.all(previousStats.map(async (stat) => {\n try {\n await requestFromIPC<RoomListingData>(\n presence,\n getProcessChannel(stat.processId),\n 'healthcheck',\n [],\n REMOTE_ROOM_SHORT_TIMEOUT,\n );\n // process succeeded to respond - nothing to do\n } catch (e) {\n // process failed to respond - remove it from stats\n logger.debug(`process ${stat.processId} failed to respond. excluding from stats`);\n const isProcessExcluded = await stats.excludeProcess(stat.processId);\n\n // clean-up possibly stale room ids\n if (isProcessExcluded && !isDevMode) {\n await removeRoomsByProcessId(stat.processId);\n }\n }\n }));\n }\n\n await stats.reset();\n\n if (isDevMode) {\n await reloadFromCache();\n }\n}\n\n/**\n * Join or create into a room and return seat reservation\n */\nexport async function joinOrCreate(roomName: string, clientOptions: ClientOptions = {}, authOptions?: AuthOptions) {\n return await retry<Promise<SeatReservation>>(async () => {\n const authData = await callOnAuth(roomName, authOptions);\n let room = await findOneRoomAvailable(roomName, clientOptions);\n\n //\n // TODO [?]\n // should we expose the \"creator\" auth data of the room during `onCreate()`?\n // it would be useful, though it could be accessed via `onJoin()` for now.\n //\n\n if (!room) {\n room = await createRoom(roomName, clientOptions);\n }\n\n return await reserveSeatFor(room, clientOptions, authData);\n }, 5, [SeatReservationError]);\n}\n\n/**\n * Create a room and return seat reservation\n */\nexport async function create(roomName: string, clientOptions: ClientOptions = {}, authOptions?: AuthOptions) {\n const authData = await callOnAuth(roomName, authOptions);\n const room = await createRoom(roomName, clientOptions);\n return reserveSeatFor(room, clientOptions, authData);\n}\n\n/**\n * Join a room and return seat reservation\n */\nexport async function join(roomName: string, clientOptions: ClientOptions = {}, authOptions?: AuthOptions) {\n return await retry<Promise<SeatReservation>>(async () => {\n const authData = await callOnAuth(roomName, authOptions);\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, authData);\n });\n}\n\n/**\n * Join a room by id and return seat reservation\n */\nexport async function reconnect(roomId: string, clientOptions: ClientOptions = {}) {\n const room = await driver.findOne({ roomId });\n if (!room) {\n // TODO: support a \"logLevel\" out of the box?\n if (process.env.NODE_ENV !== 'production') {\n logger.info(`\u274C room \"${roomId}\" has been disposed. Did you missed .allowReconnection()?\\n\uD83D\uDC49 https://docs.colyseus.io/server/room/#allowreconnection-client-seconds`);\n }\n\n throw new ServerError(ErrorCode.MATCHMAKE_INVALID_ROOM_ID, `room \"${roomId}\" has been disposed.`);\n }\n\n // check for reconnection\n const reconnectionToken = clientOptions.reconnectionToken;\n if (!reconnectionToken) { throw new ServerError(ErrorCode.MATCHMAKE_UNHANDLED, `'reconnectionToken' must be provided for reconnection.`); }\n\n\n // respond to re-connection!\n const sessionId = await remoteRoomCall(room.roomId, 'checkReconnectionToken', [reconnectionToken]);\n if (sessionId) {\n return { room, sessionId };\n\n } else {\n // TODO: support a \"logLevel\" out of the box?\n if (process.env.NODE_ENV !== 'production') {\n logger.info(`\u274C reconnection token invalid or expired. Did you missed .allowReconnection()?\\n\uD83D\uDC49 https://docs.colyseus.io/server/room/#allowreconnection-client-seconds`);\n }\n throw new ServerError(ErrorCode.MATCHMAKE_EXPIRED, `reconnection token invalid or expired.`);\n }\n}\n\n/**\n * Join a room by id and return client seat reservation. An exception is thrown if a room is not found for roomId.\n *\n * @param roomId - The Id of the specific room instance.\n * @param clientOptions - Options for the client seat reservation (for `onJoin`/`onAuth`)\n * @param authOptions - Optional authentication token\n *\n * @returns Promise<SeatReservation> - A promise which contains `sessionId` and `RoomListingData`.\n */\nexport async function joinById(roomId: string, clientOptions: ClientOptions = {}, authOptions?: AuthOptions) {\n const room = await driver.findOne({ roomId });\n\n if (!room) {\n throw new ServerError(ErrorCode.MATCHMAKE_INVALID_ROOM_ID, `room \"${roomId}\" not found`);\n\n } else if (room.locked) {\n throw new ServerError(ErrorCode.MATCHMAKE_INVALID_ROOM_ID, `room \"${roomId}\" is locked`);\n }\n\n const authData = await callOnAuth(room.name, authOptions);\n\n return reserveSeatFor(room, clientOptions, authData);\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 *\n * @param roomName - The Id of the specific room.\n * @param clientOptions - Options for the client seat reservation (for `onJoin`/`onAuth`).\n *\n * @returns Promise<RoomListingData> - A promise contaning an object which includes room metadata and configurations.\n */\nexport async function findOneRoomAvailable(roomName: string, clientOptions: ClientOptions): Promise<RoomListingData> {\n return await awaitRoomAvailable(roomName, async () => {\n const handler = getHandler(roomName);\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 *\n * @param roomId - The Id of the specific room instance.\n * @param method - Method or attribute to call or retrive.\n * @param args - Array of arguments for the method\n *\n * @returns Promise<any> - Returned value from the called or retrieved method/attribute.\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, rejectionTimeout);\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 && JSON.parse(JSON.stringify(args))));\n }\n}\n\nexport function defineRoomType<T extends Type<Room>>(\n roomName: string,\n klass: T,\n defaultOptions?: Parameters<NonNullable<InstanceType<T>['onCreate']>>[0],\n) {\n const registeredHandler = new RegisteredHandler(klass, defaultOptions);\n\n handlers[roomName] = registeredHandler;\n\n if (klass.prototype['onAuth'] !== Room.prototype['onAuth']) {\n // TODO: soft-deprecate instance level `onAuth` on 0.16\n // logger.warn(\"DEPRECATION WARNING: onAuth() at the instance level will be deprecated soon. Please use static onAuth() instead.\");\n\n if (klass['onAuth'] !== Room['onAuth']) {\n logger.info(`\u274C \"${roomName}\"'s onAuth() defined at the instance level will be ignored.`);\n }\n }\n\n if (!isDevMode) {\n cleanupStaleRooms(roomName);\n }\n\n return registeredHandler;\n}\n\nexport function removeRoomType(roomName: string) {\n delete handlers[roomName];\n\n if (!isDevMode) {\n cleanupStaleRooms(roomName);\n }\n}\n\n// TODO: legacy; remove me on 1.0\nexport function hasHandler(roomName: string) {\n logger.warn(\"hasHandler() is deprecated. Use getHandler() instead.\");\n return handlers[roomName] !== undefined;\n}\n\nexport function getHandler(roomName: string) {\n const handler = handlers[roomName];\n\n if (!handler) {\n throw new ServerError(ErrorCode.MATCHMAKE_NO_HANDLER, `provided room name \"${roomName}\" not defined`);\n }\n\n return handler;\n}\n\nexport function getRoomClass(roomName: string): Type<Room> {\n return handlers[roomName]?.klass;\n}\n\n\n/**\n * Creates a new room.\n *\n * @param roomName - The identifier you defined on `gameServer.define()`\n * @param clientOptions - Options for `onCreate`\n *\n * @returns Promise<RoomListingData> - A promise contaning an object which includes room metadata and configurations.\n */\nexport async function createRoom(roomName: string, clientOptions: ClientOptions): Promise<RoomListingData> {\n const selectedProcessId = await selectProcessIdToCreateRoom(roomName, clientOptions);\n\n let room: RoomListingData;\n if (selectedProcessId === processId) {\n // create the room on this process!\n room = await handleCreateRoom(roomName, clientOptions);\n\n } else {\n // ask other process to create the room!\n try {\n room = await requestFromIPC<RoomListingData>(\n presence,\n getProcessChannel(selectedProcessId),\n undefined,\n [roomName, clientOptions],\n REMOTE_ROOM_SHORT_TIMEOUT,\n );\n\n } catch (e) {\n if (e.message === \"ipc_timeout\") {\n debugAndPrintError(`${e.message}: create room request timed out for ${roomName} on processId ${selectedProcessId}.`);\n\n //\n // clean-up possibly stale process from redis.\n // when a process disconnects ungracefully, it may leave its previous processId under \"roomcount\"\n // if the process is still alive, it will re-add itself shortly after the load-balancer selects it again.\n //\n await stats.excludeProcess(selectedProcessId);\n\n // if other process failed to respond, create the room on this process\n room = await handleCreateRoom(roomName, clientOptions);\n\n } else {\n // re-throw intentional exception thrown during remote onCreate()\n throw e;\n }\n }\n }\n\n if (isDevMode) {\n presence.hset(getRoomRestoreListKey(), room.roomId, JSON.stringify({\n \"clientOptions\": clientOptions,\n \"roomName\": roomName,\n \"processId\": processId\n }));\n }\n\n return room;\n}\n\nexport async function handleCreateRoom(roomName: string, clientOptions: ClientOptions, restoringRoomId?: string): Promise<RoomListingData> {\n const handler = getHandler(roomName);\n const room = new handler.klass();\n\n // set room public attributes\n if (restoringRoomId && isDevMode) {\n room.roomId = restoringRoomId;\n\n } else {\n room.roomId = generateId();\n }\n\n room.roomName = roomName;\n room.presence = presence;\n\n const additionalListingData: any = handler.getFilterOptions(clientOptions);\n\n // assign public host\n if (publicAddress) {\n additionalListingData.publicAddress = publicAddress;\n }\n\n // create a RoomCache reference.\n room.listing = driver.createInstance({\n name: roomName,\n processId,\n ...additionalListingData\n });\n\n if (room.onCreate) {\n try {\n await room.onCreate(merge({}, clientOptions, handler.options));\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 // increment amount of rooms this process is handling\n stats.local.roomCount++;\n stats.persist();\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.on('visibility-change', onVisibilityChange.bind(this, room));\n room._events.once('dispose', disposeRoom.bind(this, roomName, room));\n\n // when disconnect()'ing, keep only join/leave events for stat counting\n room._events.once('disconnect', () => {\n room._events.removeAllListeners('lock');\n room._events.removeAllListeners('unlock');\n room._events.removeAllListeners('visibility-change');\n room._events.removeAllListeners('dispose');\n });\n\n // room always start unlocked\n await createRoomReferences(room, true);\n await room.listing.save();\n\n handler.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(closeCode?: number) {\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(closeCode));\n }\n\n return promises;\n}\n\nexport async function gracefullyShutdown(): Promise<any> {\n if (isGracefullyShuttingDown) {\n return Promise.reject('already_shutting_down');\n }\n\n isGracefullyShuttingDown = true;\n onReady = undefined;\n\n debugMatchMaking(`${processId} is shutting down!`);\n\n if (isDevMode) {\n await cacheRoomHistory(rooms);\n }\n\n // remove processId from room count key\n await stats.excludeProcess(processId);\n\n // unsubscribe from process id channel\n presence.unsubscribe(getProcessChannel());\n\n return Promise.all(disconnectAll(\n (isDevMode)\n ? Protocol.WS_CLOSE_DEVMODE_RESTART\n : undefined\n ));\n}\n\n/**\n * Reserve a seat for a client in a room\n */\nexport async function reserveSeatFor(room: RoomListingData, options: ClientOptions, authData?: 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, authData]);\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 const response: SeatReservation = { room, sessionId };\n\n if (isDevMode) {\n response.devMode = isDevMode;\n }\n\n return response;\n}\n\nfunction callOnAuth(roomName: string, authOptions?: AuthOptions) {\n const roomClass = getRoomClass(roomName);\n return (roomClass && roomClass['onAuth'] && roomClass['onAuth'] !== Room['onAuth'])\n ? roomClass['onAuth'](authOptions.token, authOptions.request)\n : undefined;\n}\n\nexport async function cleanupStaleRooms(roomName: string) {\n // remove connecting counts\n await presence.del(getHandlerConcurrencyKey(roomName));\n}\n\nasync function removeRoomsByProcessId(processId: 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 if (typeof(driver.cleanup) === \"function\") {\n await driver.cleanup(processId);\n\n } else {\n //\n // TODO: remove this block on 1.0.\n //\n // driver.cleanup() has been added mid-way through 0.15\n // some users may still be using older versions of the driver.\n //\n const cachedRooms = await driver.find({ processId }, { _id: 1 });\n logger.debug(\"removing stale rooms by processId:\", processId, `(${cachedRooms.length} rooms found)`);\n cachedRooms.forEach((room) => room.remove());\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 //\n // avoid having too long timeout if 10+ clients ask to join at the same time\n //\n // TODO: we need a better solution here. either a lock or queue system should be implemented instead.\n // https://github.com/colyseus/colyseus/issues/466\n //\n const concurrencyTimeout = Math.min(concurrency * 100, 500);\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 // increment local CCU\n stats.local.ccu++;\n stats.persist();\n\n handlers[room.roomName].emit('join', room, client);\n}\n\nfunction onClientLeaveRoom(room: Room, client: Client, willDispose: boolean) {\n // decrement local CCU\n stats.local.ccu--;\n stats.persist();\n\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\nfunction onVisibilityChange(room: Room, isInvisible: boolean): void {\n handlers[room.roomName].emit('visibility-change', room, isInvisible);\n}\n\nasync function disposeRoom(roomName: string, room: Room) {\n debugMatchMaking('disposing \\'%s\\' (%s) on processId \\'%s\\' (graceful shutdown: %s)', roomName, room.roomId, processId, isGracefullyShuttingDown);\n\n // decrease amount of rooms this process is handling\n if (!isGracefullyShuttingDown) {\n stats.local.roomCount--;\n stats.persist();\n\n // remove from devMode restore list\n if (isDevMode) {\n await presence.hdel(getRoomRestoreListKey(), room.roomId);\n }\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//\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"],
|
|
5
|
-
"mappings": "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",
|
|
6
|
-
"names": ["processId"]
|
|
4
|
+
"sourcesContent": ["import { ErrorCode, Protocol } from './Protocol';\n\nimport { requestFromIPC, subscribeIPC } from './IPC';\n\nimport { Deferred, generateId, merge, REMOTE_ROOM_SHORT_TIMEOUT, retry } from './utils/Utils';\nimport { isDevMode, cacheRoomHistory, getPreviousProcessId, getRoomRestoreListKey, reloadFromCache } from './utils/DevMode';\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, RoomListingData, LocalDriver, MatchMakerDriver } from './matchmaker/driver';\nimport controller from './matchmaker/controller';\nimport * as stats from \"./Stats\";\n\nimport { logger } from './Logger';\nimport { Client } from './Transport';\nimport { Type } from './utils/types';\nimport { getHostname } from \"./discovery\";\n\nexport { controller, stats, type MatchMakerDriver };\n\nexport type ClientOptions = any;\nexport type AuthOptions = { token?: string, request?: any };\nexport type SelectProcessIdCallback = (roomName: string, clientOptions: ClientOptions) => Promise<string>;\n\nexport interface SeatReservation {\n sessionId: string;\n room: RoomListingData;\n devMode?: boolean;\n}\n\nconst handlers: {[id: string]: RegisteredHandler} = {};\nconst rooms: {[roomId: string]: Room} = {};\n\nexport let publicAddress: string;\nexport let processId: string;\nexport let presence: Presence;\nexport let driver: MatchMakerDriver;\nexport let selectProcessIdToCreateRoom: SelectProcessIdCallback;\n\nexport let isGracefullyShuttingDown: boolean; // TODO: remove me on 1.0, use 'state' instead\nexport let onReady: Deferred = new Deferred(); // onReady needs to be immediately available to @colyseus/auth integration.\n\nexport enum MatchMakerState {\n INITIALIZING,\n READY,\n SHUTTING_DOWN\n}\n\n/**\n * Internal MatchMaker state\n */\nexport let state: MatchMakerState;\n\n/**\n * @private\n */\nexport async function setup(\n _presence?: Presence,\n _driver?: MatchMakerDriver,\n _publicAddress?: string,\n _selectProcessIdToCreateRoom?: SelectProcessIdCallback,\n) {\n if (onReady === undefined) {\n //\n // for testing purposes only: onReady is turned into undefined on shutdown\n // (needs refactoring.)\n //\n onReady = new Deferred();\n }\n\n state = MatchMakerState.INITIALIZING;\n\n presence = _presence || new LocalPresence();\n\n driver = _driver || new LocalDriver();\n publicAddress = _publicAddress;\n\n stats.reset(false);\n\n // devMode: try to retrieve previous processId\n if (isDevMode) { processId = await getPreviousProcessId(await getHostname()); }\n\n // ensure processId is set\n if (!processId) { processId = generateId(); }\n\n isGracefullyShuttingDown = false;\n\n /**\n * Define default `assignRoomToProcessId` method.\n * By default, return the process with least amount of rooms created\n */\n selectProcessIdToCreateRoom = _selectProcessIdToCreateRoom || async function () {\n return (await stats.fetchAll())\n .sort((p1, p2) => p1.roomCount > p2.roomCount ? 1 : -1)[0]?.processId || processId;\n };\n\n onReady.resolve();\n}\n\n/**\n * - Accept receiving remote room creation requests\n * - Check for leftover/invalid processId's on startup\n * @private\n */\nexport async function accept() {\n await onReady; // make sure \"processId\" is available\n\n /**\n * Process-level subscription\n * - handle remote process healthcheck\n * - handle remote room creation\n */\n await subscribeIPC(presence, processId, getProcessChannel(), (method, args) => {\n if (method === 'healthcheck') {\n // health check for this processId\n return true;\n\n } else {\n // handle room creation\n return handleCreateRoom.apply(undefined, args);\n }\n });\n\n /**\n * Check for leftover/invalid processId's on startup\n */\n const previousStats = await stats.fetchAll();\n if (previousStats.length > 0) {\n logger.debug(`${previousStats.length} previous processId(s) found, health-checking...`);\n await Promise.all(previousStats.map(async (stat) => {\n try {\n await requestFromIPC<RoomListingData>(\n presence,\n getProcessChannel(stat.processId),\n 'healthcheck',\n [],\n REMOTE_ROOM_SHORT_TIMEOUT,\n );\n // process succeeded to respond - nothing to do\n } catch (e) {\n // process failed to respond - remove it from stats\n logger.debug(`process ${stat.processId} failed to respond. excluding from stats`);\n const isProcessExcluded = await stats.excludeProcess(stat.processId);\n\n // clean-up possibly stale room ids\n if (isProcessExcluded && !isDevMode) {\n await removeRoomsByProcessId(stat.processId);\n }\n }\n }));\n }\n\n state = MatchMakerState.READY;\n\n await stats.persist();\n\n if (isDevMode) {\n await reloadFromCache();\n }\n}\n\n/**\n * Join or create into a room and return seat reservation\n */\nexport async function joinOrCreate(roomName: string, clientOptions: ClientOptions = {}, authOptions?: AuthOptions) {\n return await retry<Promise<SeatReservation>>(async () => {\n const authData = await callOnAuth(roomName, authOptions);\n let room = await findOneRoomAvailable(roomName, clientOptions);\n\n //\n // TODO [?]\n // should we expose the \"creator\" auth data of the room during `onCreate()`?\n // it would be useful, though it could be accessed via `onJoin()` for now.\n //\n\n if (!room) {\n room = await createRoom(roomName, clientOptions);\n }\n\n return await reserveSeatFor(room, clientOptions, authData);\n }, 5, [SeatReservationError]);\n}\n\n/**\n * Create a room and return seat reservation\n */\nexport async function create(roomName: string, clientOptions: ClientOptions = {}, authOptions?: AuthOptions) {\n const authData = await callOnAuth(roomName, authOptions);\n const room = await createRoom(roomName, clientOptions);\n return reserveSeatFor(room, clientOptions, authData);\n}\n\n/**\n * Join a room and return seat reservation\n */\nexport async function join(roomName: string, clientOptions: ClientOptions = {}, authOptions?: AuthOptions) {\n return await retry<Promise<SeatReservation>>(async () => {\n const authData = await callOnAuth(roomName, authOptions);\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, authData);\n });\n}\n\n/**\n * Join a room by id and return seat reservation\n */\nexport async function reconnect(roomId: string, clientOptions: ClientOptions = {}) {\n const room = await driver.findOne({ roomId });\n if (!room) {\n // TODO: support a \"logLevel\" out of the box?\n if (process.env.NODE_ENV !== 'production') {\n logger.info(`\u274C room \"${roomId}\" has been disposed. Did you missed .allowReconnection()?\\n\uD83D\uDC49 https://docs.colyseus.io/server/room/#allowreconnection-client-seconds`);\n }\n\n throw new ServerError(ErrorCode.MATCHMAKE_INVALID_ROOM_ID, `room \"${roomId}\" has been disposed.`);\n }\n\n // check for reconnection\n const reconnectionToken = clientOptions.reconnectionToken;\n if (!reconnectionToken) { throw new ServerError(ErrorCode.MATCHMAKE_UNHANDLED, `'reconnectionToken' must be provided for reconnection.`); }\n\n\n // respond to re-connection!\n const sessionId = await remoteRoomCall(room.roomId, 'checkReconnectionToken', [reconnectionToken]);\n if (sessionId) {\n return { room, sessionId };\n\n } else {\n // TODO: support a \"logLevel\" out of the box?\n if (process.env.NODE_ENV !== 'production') {\n logger.info(`\u274C reconnection token invalid or expired. Did you missed .allowReconnection()?\\n\uD83D\uDC49 https://docs.colyseus.io/server/room/#allowreconnection-client-seconds`);\n }\n throw new ServerError(ErrorCode.MATCHMAKE_EXPIRED, `reconnection token invalid or expired.`);\n }\n}\n\n/**\n * Join a room by id and return client seat reservation. An exception is thrown if a room is not found for roomId.\n *\n * @param roomId - The Id of the specific room instance.\n * @param clientOptions - Options for the client seat reservation (for `onJoin`/`onAuth`)\n * @param authOptions - Optional authentication token\n *\n * @returns Promise<SeatReservation> - A promise which contains `sessionId` and `RoomListingData`.\n */\nexport async function joinById(roomId: string, clientOptions: ClientOptions = {}, authOptions?: AuthOptions) {\n const room = await driver.findOne({ roomId });\n\n if (!room) {\n throw new ServerError(ErrorCode.MATCHMAKE_INVALID_ROOM_ID, `room \"${roomId}\" not found`);\n\n } else if (room.locked) {\n throw new ServerError(ErrorCode.MATCHMAKE_INVALID_ROOM_ID, `room \"${roomId}\" is locked`);\n }\n\n const authData = await callOnAuth(room.name, authOptions);\n\n return reserveSeatFor(room, clientOptions, authData);\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 *\n * @param roomName - The Id of the specific room.\n * @param clientOptions - Options for the client seat reservation (for `onJoin`/`onAuth`).\n *\n * @returns Promise<RoomListingData> - A promise contaning an object which includes room metadata and configurations.\n */\nexport async function findOneRoomAvailable(roomName: string, clientOptions: ClientOptions): Promise<RoomListingData> {\n return await awaitRoomAvailable(roomName, async () => {\n const handler = getHandler(roomName);\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 *\n * @param roomId - The Id of the specific room instance.\n * @param method - Method or attribute to call or retrive.\n * @param args - Array of arguments for the method\n *\n * @returns Promise<any> - Returned value from the called or retrieved method/attribute.\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, rejectionTimeout);\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 && JSON.parse(JSON.stringify(args))));\n }\n}\n\nexport function defineRoomType<T extends Type<Room>>(\n roomName: string,\n klass: T,\n defaultOptions?: Parameters<NonNullable<InstanceType<T>['onCreate']>>[0],\n) {\n const registeredHandler = new RegisteredHandler(klass, defaultOptions);\n\n handlers[roomName] = registeredHandler;\n\n if (klass.prototype['onAuth'] !== Room.prototype['onAuth']) {\n // TODO: soft-deprecate instance level `onAuth` on 0.16\n // logger.warn(\"DEPRECATION WARNING: onAuth() at the instance level will be deprecated soon. Please use static onAuth() instead.\");\n\n if (klass['onAuth'] !== Room['onAuth']) {\n logger.info(`\u274C \"${roomName}\"'s onAuth() defined at the instance level will be ignored.`);\n }\n }\n\n if (!isDevMode) {\n cleanupStaleRooms(roomName);\n }\n\n return registeredHandler;\n}\n\nexport function removeRoomType(roomName: string) {\n delete handlers[roomName];\n\n if (!isDevMode) {\n cleanupStaleRooms(roomName);\n }\n}\n\n// TODO: legacy; remove me on 1.0\nexport function hasHandler(roomName: string) {\n logger.warn(\"hasHandler() is deprecated. Use getHandler() instead.\");\n return handlers[roomName] !== undefined;\n}\n\nexport function getHandler(roomName: string) {\n const handler = handlers[roomName];\n\n if (!handler) {\n throw new ServerError(ErrorCode.MATCHMAKE_NO_HANDLER, `provided room name \"${roomName}\" not defined`);\n }\n\n return handler;\n}\n\nexport function getRoomClass(roomName: string): Type<Room> {\n return handlers[roomName]?.klass;\n}\n\n\n/**\n * Creates a new room.\n *\n * @param roomName - The identifier you defined on `gameServer.define()`\n * @param clientOptions - Options for `onCreate`\n *\n * @returns Promise<RoomListingData> - A promise contaning an object which includes room metadata and configurations.\n */\nexport async function createRoom(roomName: string, clientOptions: ClientOptions): Promise<RoomListingData> {\n //\n // - select a process to create the room\n // - use local processId if MatchMaker is not ready yet\n //\n const selectedProcessId = (state === MatchMakerState.READY)\n ? await selectProcessIdToCreateRoom(roomName, clientOptions)\n : processId;\n\n let room: RoomListingData;\n if (selectedProcessId === undefined) {\n throw new ServerError(ErrorCode.MATCHMAKE_UNHANDLED, `no processId available to create room ${roomName}`);\n\n } else if (selectedProcessId === processId) {\n // create the room on this process!\n room = await handleCreateRoom(roomName, clientOptions);\n\n } else {\n // ask other process to create the room!\n try {\n room = await requestFromIPC<RoomListingData>(\n presence,\n getProcessChannel(selectedProcessId),\n undefined,\n [roomName, clientOptions],\n REMOTE_ROOM_SHORT_TIMEOUT,\n );\n\n } catch (e) {\n if (e.message === \"ipc_timeout\") {\n debugAndPrintError(`${e.message}: create room request timed out for ${roomName} on processId ${selectedProcessId}.`);\n\n //\n // clean-up possibly stale process from redis.\n // when a process disconnects ungracefully, it may leave its previous processId under \"roomcount\"\n // if the process is still alive, it will re-add itself shortly after the load-balancer selects it again.\n //\n await stats.excludeProcess(selectedProcessId);\n\n // if other process failed to respond, create the room on this process\n room = await handleCreateRoom(roomName, clientOptions);\n\n } else {\n // re-throw intentional exception thrown during remote onCreate()\n throw e;\n }\n }\n }\n\n if (isDevMode) {\n presence.hset(getRoomRestoreListKey(), room.roomId, JSON.stringify({\n \"clientOptions\": clientOptions,\n \"roomName\": roomName,\n \"processId\": processId\n }));\n }\n\n return room;\n}\n\nexport async function handleCreateRoom(roomName: string, clientOptions: ClientOptions, restoringRoomId?: string): Promise<RoomListingData> {\n const handler = getHandler(roomName);\n const room = new handler.klass();\n\n // set room public attributes\n if (restoringRoomId && isDevMode) {\n room.roomId = restoringRoomId;\n\n } else {\n room.roomId = generateId();\n }\n\n room.roomName = roomName;\n room.presence = presence;\n\n const additionalListingData: any = handler.getFilterOptions(clientOptions);\n\n // assign public host\n if (publicAddress) {\n additionalListingData.publicAddress = publicAddress;\n }\n\n // create a RoomCache reference.\n room.listing = driver.createInstance({\n name: roomName,\n processId,\n ...additionalListingData\n });\n\n if (room.onCreate) {\n try {\n await room.onCreate(merge({}, clientOptions, handler.options));\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 // increment amount of rooms this process is handling\n stats.local.roomCount++;\n stats.persist();\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.on('visibility-change', onVisibilityChange.bind(this, room));\n room._events.once('dispose', disposeRoom.bind(this, roomName, room));\n\n // when disconnect()'ing, keep only join/leave events for stat counting\n room._events.once('disconnect', () => {\n room._events.removeAllListeners('lock');\n room._events.removeAllListeners('unlock');\n room._events.removeAllListeners('visibility-change');\n room._events.removeAllListeners('dispose');\n });\n\n // room always start unlocked\n await createRoomReferences(room, true);\n await room.listing.save();\n\n handler.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(closeCode?: number) {\n const promises: Array<Promise<any>> = [];\n\n for (const roomId in rooms) {\n if (!rooms.hasOwnProperty(roomId)) {\n continue;\n }\n\n const room = rooms[roomId];\n\n // prevent touching stats when process is shutting down\n room._events.removeAllListeners(\"leave\");\n\n promises.push(room.disconnect(closeCode));\n }\n\n return promises;\n}\n\nexport async function gracefullyShutdown(): Promise<any> {\n if (isGracefullyShuttingDown) {\n return Promise.reject('already_shutting_down');\n }\n\n isGracefullyShuttingDown = true;\n state = MatchMakerState.SHUTTING_DOWN;\n\n onReady = undefined;\n\n debugMatchMaking(`${processId} is shutting down!`);\n\n if (isDevMode) {\n await cacheRoomHistory(rooms);\n }\n\n // remove processId from room count key\n await stats.excludeProcess(processId);\n\n // remove cached rooms of this process\n await removeRoomsByProcessId(processId);\n\n // unsubscribe from process id channel\n presence.unsubscribe(getProcessChannel());\n\n return Promise.all(disconnectAll(\n (isDevMode)\n ? Protocol.WS_CLOSE_DEVMODE_RESTART\n : undefined\n ));\n}\n\n/**\n * Reserve a seat for a client in a room\n */\nexport async function reserveSeatFor(room: RoomListingData, options: ClientOptions, authData?: 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, authData]);\n\n } catch (e) {\n // throwing here generally means a room cache from an unavailable process is\n // being used (room from a process not gracefully shut down)\n debugMatchMaking(e);\n throw e;\n }\n\n if (!successfulSeatReservation) {\n throw new SeatReservationError(`${room.roomId} is already full.`);\n }\n\n const response: SeatReservation = { room, sessionId };\n\n if (isDevMode) {\n response.devMode = isDevMode;\n }\n\n return response;\n}\n\nfunction callOnAuth(roomName: string, authOptions?: AuthOptions) {\n const roomClass = getRoomClass(roomName);\n return (roomClass && roomClass['onAuth'] && roomClass['onAuth'] !== Room['onAuth'])\n ? roomClass['onAuth'](authOptions.token, authOptions.request)\n : undefined;\n}\n\nexport async function cleanupStaleRooms(roomName: string) {\n // remove connecting counts\n await presence.del(getHandlerConcurrencyKey(roomName));\n}\n\nasync function removeRoomsByProcessId(processId: 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 if (typeof(driver.cleanup) === \"function\") {\n await driver.cleanup(processId);\n\n } else {\n //\n // TODO: remove this block on 1.0.\n //\n // driver.cleanup() has been added mid-way through 0.15\n // some users may still be using older versions of the driver.\n //\n const cachedRooms = await driver.find({ processId }, { _id: 1 });\n logger.debug(\"removing stale rooms by processId:\", processId, `(${cachedRooms.length} rooms found)`);\n cachedRooms.forEach((room) => room.remove());\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 //\n // avoid having too long timeout if 10+ clients ask to join at the same time\n //\n // TODO: we need a better solution here. either a lock or queue system should be implemented instead.\n // https://github.com/colyseus/colyseus/issues/466\n //\n const concurrencyTimeout = Math.min(concurrency * 100, 500);\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 // increment local CCU\n stats.local.ccu++;\n stats.persist();\n\n handlers[room.roomName].emit('join', room, client);\n}\n\nfunction onClientLeaveRoom(room: Room, client: Client, willDispose: boolean) {\n // decrement local CCU\n stats.local.ccu--;\n stats.persist();\n\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\nfunction onVisibilityChange(room: Room, isInvisible: boolean): void {\n handlers[room.roomName].emit('visibility-change', room, isInvisible);\n}\n\nasync function disposeRoom(roomName: string, room: Room) {\n debugMatchMaking('disposing \\'%s\\' (%s) on processId \\'%s\\' (graceful shutdown: %s)', roomName, room.roomId, processId, isGracefullyShuttingDown);\n\n // decrease amount of rooms this process is handling\n if (!isGracefullyShuttingDown) {\n stats.local.roomCount--;\n stats.persist();\n\n // remove from devMode restore list\n if (isDevMode) {\n await presence.hdel(getRoomRestoreListKey(), room.roomId);\n }\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//\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"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": ["MatchMakerState", "processId"]
|
|
7
7
|
}
|
package/build/Stats.d.ts
CHANGED
|
@@ -7,6 +7,6 @@ export declare function fetchAll(): Promise<(Stats & {
|
|
|
7
7
|
processId: string;
|
|
8
8
|
})[]>;
|
|
9
9
|
export declare function persist(): any;
|
|
10
|
-
export declare function reset():
|
|
10
|
+
export declare function reset(_persist?: boolean): void;
|
|
11
11
|
export declare function excludeProcess(_processId: string): boolean | Promise<boolean>;
|
|
12
12
|
export declare function getGlobalCCU(): Promise<number>;
|
package/build/Stats.js
CHANGED
|
@@ -56,12 +56,14 @@ function persist() {
|
|
|
56
56
|
persistTimeout = setTimeout(persist, persistInterval);
|
|
57
57
|
}
|
|
58
58
|
}
|
|
59
|
-
function reset() {
|
|
60
|
-
lastPersisted = 0;
|
|
61
|
-
clearTimeout(persistTimeout);
|
|
59
|
+
function reset(_persist = true) {
|
|
62
60
|
local.roomCount = 0;
|
|
63
61
|
local.ccu = 0;
|
|
64
|
-
|
|
62
|
+
if (_persist) {
|
|
63
|
+
lastPersisted = 0;
|
|
64
|
+
clearTimeout(persistTimeout);
|
|
65
|
+
persist();
|
|
66
|
+
}
|
|
65
67
|
}
|
|
66
68
|
function excludeProcess(_processId) {
|
|
67
69
|
return import_MatchMaker.presence.hdel(getRoomCountKey(), _processId);
|
package/build/Stats.js.map
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../src/Stats.ts"],
|
|
4
|
-
"sourcesContent": ["import { presence, processId } from \"./MatchMaker\";\n\nexport type Stats = {\n roomCount: number;\n ccu: number;\n}\n\nexport let local: Stats = {\n roomCount: 0,\n ccu: 0,\n};\n\nexport async function fetchAll() {\n // TODO: cache this value to avoid querying too often\n const allStats: Array<Stats & { processId: string }> = [];\n const allProcesses = await presence.hgetall(getRoomCountKey());\n for (let remoteProcessId in allProcesses) {\n if (remoteProcessId === processId) {\n allStats.push({ processId, roomCount: local.roomCount, ccu: local.ccu, });\n\n } else {\n const [roomCount, ccu] = allProcesses[remoteProcessId].split(',').map(Number);\n allStats.push({ processId: remoteProcessId, roomCount, ccu });\n }\n }\n return allStats;\n}\n\nlet lastPersisted = 0;\nlet persistTimeout = undefined;\nconst persistInterval = 1000;\n\nexport function persist() {\n /**\n * Avoid persisting too often.\n */\n const now = Date.now();\n\n if (now - lastPersisted > persistInterval) {\n lastPersisted = now;\n return presence.hset(getRoomCountKey(), processId, `${local.roomCount},${local.ccu}`);\n\n } else {\n clearTimeout(persistTimeout);\n persistTimeout = setTimeout(persist, persistInterval);\n }\n}\n\nexport function reset() {\n
|
|
5
|
-
"mappings": ";;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,wBAAoC;AAO7B,IAAI,QAAe;AAAA,EACxB,WAAW;AAAA,EACX,KAAK;AACP;AAEA,eAAsB,WAAW;AAE/B,QAAM,WAAiD,CAAC;AACxD,QAAM,eAAe,MAAM,2BAAS,QAAQ,gBAAgB,CAAC;AAC7D,WAAS,mBAAmB,cAAc;AACxC,QAAI,oBAAoB,6BAAW;AACjC,eAAS,KAAK,EAAE,wCAAW,WAAW,MAAM,WAAW,KAAK,MAAM,IAAK,CAAC;AAAA,IAE1E,OAAO;AACL,YAAM,CAAC,WAAW,GAAG,IAAI,aAAa,iBAAiB,MAAM,GAAG,EAAE,IAAI,MAAM;AAC5E,eAAS,KAAK,EAAE,WAAW,iBAAiB,WAAW,IAAI,CAAC;AAAA,IAC9D;AAAA,EACF;AACA,SAAO;AACT;AAEA,IAAI,gBAAgB;AACpB,IAAI,iBAAiB;AACrB,MAAM,kBAAkB;AAEjB,SAAS,UAAU;AAIxB,QAAM,MAAM,KAAK,IAAI;AAErB,MAAI,MAAM,gBAAgB,iBAAiB;AACzC,oBAAgB;AAChB,WAAO,2BAAS,KAAK,gBAAgB,GAAG,6BAAW,GAAG,MAAM,aAAa,MAAM,KAAK;AAAA,EAEtF,OAAO;AACL,iBAAa,cAAc;AAC3B,qBAAiB,WAAW,SAAS,eAAe;AAAA,EACtD;AACF;AAEO,SAAS,
|
|
4
|
+
"sourcesContent": ["import { presence, processId } from \"./MatchMaker\";\n\nexport type Stats = {\n roomCount: number;\n ccu: number;\n}\n\nexport let local: Stats = {\n roomCount: 0,\n ccu: 0,\n};\n\nexport async function fetchAll() {\n // TODO: cache this value to avoid querying too often\n const allStats: Array<Stats & { processId: string }> = [];\n const allProcesses = await presence.hgetall(getRoomCountKey());\n for (let remoteProcessId in allProcesses) {\n if (remoteProcessId === processId) {\n allStats.push({ processId, roomCount: local.roomCount, ccu: local.ccu, });\n\n } else {\n const [roomCount, ccu] = allProcesses[remoteProcessId].split(',').map(Number);\n allStats.push({ processId: remoteProcessId, roomCount, ccu });\n }\n }\n return allStats;\n}\n\nlet lastPersisted = 0;\nlet persistTimeout = undefined;\nconst persistInterval = 1000;\n\nexport function persist() {\n /**\n * Avoid persisting too often.\n */\n const now = Date.now();\n\n if (now - lastPersisted > persistInterval) {\n lastPersisted = now;\n return presence.hset(getRoomCountKey(), processId, `${local.roomCount},${local.ccu}`);\n\n } else {\n clearTimeout(persistTimeout);\n persistTimeout = setTimeout(persist, persistInterval);\n }\n}\n\nexport function reset(_persist: boolean = true) {\n local.roomCount = 0;\n local.ccu = 0;\n\n if (_persist) {\n lastPersisted = 0;\n clearTimeout(persistTimeout);\n persist();\n }\n}\n\nexport function excludeProcess(_processId: string) {\n return presence.hdel(getRoomCountKey(), _processId);\n}\n\nexport async function getGlobalCCU() {\n const allStats = await fetchAll();\n return allStats.reduce((prev, next) => prev + next.ccu, 0);\n}\n\nfunction getRoomCountKey() {\n return 'roomcount';\n}"],
|
|
5
|
+
"mappings": ";;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,wBAAoC;AAO7B,IAAI,QAAe;AAAA,EACxB,WAAW;AAAA,EACX,KAAK;AACP;AAEA,eAAsB,WAAW;AAE/B,QAAM,WAAiD,CAAC;AACxD,QAAM,eAAe,MAAM,2BAAS,QAAQ,gBAAgB,CAAC;AAC7D,WAAS,mBAAmB,cAAc;AACxC,QAAI,oBAAoB,6BAAW;AACjC,eAAS,KAAK,EAAE,wCAAW,WAAW,MAAM,WAAW,KAAK,MAAM,IAAK,CAAC;AAAA,IAE1E,OAAO;AACL,YAAM,CAAC,WAAW,GAAG,IAAI,aAAa,iBAAiB,MAAM,GAAG,EAAE,IAAI,MAAM;AAC5E,eAAS,KAAK,EAAE,WAAW,iBAAiB,WAAW,IAAI,CAAC;AAAA,IAC9D;AAAA,EACF;AACA,SAAO;AACT;AAEA,IAAI,gBAAgB;AACpB,IAAI,iBAAiB;AACrB,MAAM,kBAAkB;AAEjB,SAAS,UAAU;AAIxB,QAAM,MAAM,KAAK,IAAI;AAErB,MAAI,MAAM,gBAAgB,iBAAiB;AACzC,oBAAgB;AAChB,WAAO,2BAAS,KAAK,gBAAgB,GAAG,6BAAW,GAAG,MAAM,aAAa,MAAM,KAAK;AAAA,EAEtF,OAAO;AACL,iBAAa,cAAc;AAC3B,qBAAiB,WAAW,SAAS,eAAe;AAAA,EACtD;AACF;AAEO,SAAS,MAAM,WAAoB,MAAM;AAC9C,QAAM,YAAY;AAClB,QAAM,MAAM;AAEZ,MAAI,UAAU;AACZ,oBAAgB;AAChB,iBAAa,cAAc;AAC3B,YAAQ;AAAA,EACV;AACF;AAEO,SAAS,eAAe,YAAoB;AACjD,SAAO,2BAAS,KAAK,gBAAgB,GAAG,UAAU;AACpD;AAEA,eAAsB,eAAe;AACnC,QAAM,WAAW,MAAM,SAAS;AAChC,SAAO,SAAS,OAAO,CAAC,MAAM,SAAS,OAAO,KAAK,KAAK,CAAC;AAC3D;AAEA,SAAS,kBAAkB;AACzB,SAAO;AACT;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
package/build/Stats.mjs
CHANGED
|
@@ -29,12 +29,14 @@ function persist() {
|
|
|
29
29
|
persistTimeout = setTimeout(persist, persistInterval);
|
|
30
30
|
}
|
|
31
31
|
}
|
|
32
|
-
function reset() {
|
|
33
|
-
lastPersisted = 0;
|
|
34
|
-
clearTimeout(persistTimeout);
|
|
32
|
+
function reset(_persist = true) {
|
|
35
33
|
local.roomCount = 0;
|
|
36
34
|
local.ccu = 0;
|
|
37
|
-
|
|
35
|
+
if (_persist) {
|
|
36
|
+
lastPersisted = 0;
|
|
37
|
+
clearTimeout(persistTimeout);
|
|
38
|
+
persist();
|
|
39
|
+
}
|
|
38
40
|
}
|
|
39
41
|
function excludeProcess(_processId) {
|
|
40
42
|
return presence.hdel(getRoomCountKey(), _processId);
|
package/build/Stats.mjs.map
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../src/Stats.ts"],
|
|
4
|
-
"sourcesContent": ["import { presence, processId } from \"./MatchMaker\";\n\nexport type Stats = {\n roomCount: number;\n ccu: number;\n}\n\nexport let local: Stats = {\n roomCount: 0,\n ccu: 0,\n};\n\nexport async function fetchAll() {\n // TODO: cache this value to avoid querying too often\n const allStats: Array<Stats & { processId: string }> = [];\n const allProcesses = await presence.hgetall(getRoomCountKey());\n for (let remoteProcessId in allProcesses) {\n if (remoteProcessId === processId) {\n allStats.push({ processId, roomCount: local.roomCount, ccu: local.ccu, });\n\n } else {\n const [roomCount, ccu] = allProcesses[remoteProcessId].split(',').map(Number);\n allStats.push({ processId: remoteProcessId, roomCount, ccu });\n }\n }\n return allStats;\n}\n\nlet lastPersisted = 0;\nlet persistTimeout = undefined;\nconst persistInterval = 1000;\n\nexport function persist() {\n /**\n * Avoid persisting too often.\n */\n const now = Date.now();\n\n if (now - lastPersisted > persistInterval) {\n lastPersisted = now;\n return presence.hset(getRoomCountKey(), processId, `${local.roomCount},${local.ccu}`);\n\n } else {\n clearTimeout(persistTimeout);\n persistTimeout = setTimeout(persist, persistInterval);\n }\n}\n\nexport function reset() {\n
|
|
5
|
-
"mappings": "AAAA,SAAS,UAAU,iBAAiB;AAO7B,IAAI,QAAe;AAAA,EACxB,WAAW;AAAA,EACX,KAAK;AACP;AAEA,eAAsB,WAAW;AAE/B,QAAM,WAAiD,CAAC;AACxD,QAAM,eAAe,MAAM,SAAS,QAAQ,gBAAgB,CAAC;AAC7D,WAAS,mBAAmB,cAAc;AACxC,QAAI,oBAAoB,WAAW;AACjC,eAAS,KAAK,EAAE,WAAW,WAAW,MAAM,WAAW,KAAK,MAAM,IAAK,CAAC;AAAA,IAE1E,OAAO;AACL,YAAM,CAAC,WAAW,GAAG,IAAI,aAAa,iBAAiB,MAAM,GAAG,EAAE,IAAI,MAAM;AAC5E,eAAS,KAAK,EAAE,WAAW,iBAAiB,WAAW,IAAI,CAAC;AAAA,IAC9D;AAAA,EACF;AACA,SAAO;AACT;AAEA,IAAI,gBAAgB;AACpB,IAAI,iBAAiB;AACrB,MAAM,kBAAkB;AAEjB,SAAS,UAAU;AAIxB,QAAM,MAAM,KAAK,IAAI;AAErB,MAAI,MAAM,gBAAgB,iBAAiB;AACzC,oBAAgB;AAChB,WAAO,SAAS,KAAK,gBAAgB,GAAG,WAAW,GAAG,MAAM,aAAa,MAAM,KAAK;AAAA,EAEtF,OAAO;AACL,iBAAa,cAAc;AAC3B,qBAAiB,WAAW,SAAS,eAAe;AAAA,EACtD;AACF;AAEO,SAAS,
|
|
4
|
+
"sourcesContent": ["import { presence, processId } from \"./MatchMaker\";\n\nexport type Stats = {\n roomCount: number;\n ccu: number;\n}\n\nexport let local: Stats = {\n roomCount: 0,\n ccu: 0,\n};\n\nexport async function fetchAll() {\n // TODO: cache this value to avoid querying too often\n const allStats: Array<Stats & { processId: string }> = [];\n const allProcesses = await presence.hgetall(getRoomCountKey());\n for (let remoteProcessId in allProcesses) {\n if (remoteProcessId === processId) {\n allStats.push({ processId, roomCount: local.roomCount, ccu: local.ccu, });\n\n } else {\n const [roomCount, ccu] = allProcesses[remoteProcessId].split(',').map(Number);\n allStats.push({ processId: remoteProcessId, roomCount, ccu });\n }\n }\n return allStats;\n}\n\nlet lastPersisted = 0;\nlet persistTimeout = undefined;\nconst persistInterval = 1000;\n\nexport function persist() {\n /**\n * Avoid persisting too often.\n */\n const now = Date.now();\n\n if (now - lastPersisted > persistInterval) {\n lastPersisted = now;\n return presence.hset(getRoomCountKey(), processId, `${local.roomCount},${local.ccu}`);\n\n } else {\n clearTimeout(persistTimeout);\n persistTimeout = setTimeout(persist, persistInterval);\n }\n}\n\nexport function reset(_persist: boolean = true) {\n local.roomCount = 0;\n local.ccu = 0;\n\n if (_persist) {\n lastPersisted = 0;\n clearTimeout(persistTimeout);\n persist();\n }\n}\n\nexport function excludeProcess(_processId: string) {\n return presence.hdel(getRoomCountKey(), _processId);\n}\n\nexport async function getGlobalCCU() {\n const allStats = await fetchAll();\n return allStats.reduce((prev, next) => prev + next.ccu, 0);\n}\n\nfunction getRoomCountKey() {\n return 'roomcount';\n}"],
|
|
5
|
+
"mappings": "AAAA,SAAS,UAAU,iBAAiB;AAO7B,IAAI,QAAe;AAAA,EACxB,WAAW;AAAA,EACX,KAAK;AACP;AAEA,eAAsB,WAAW;AAE/B,QAAM,WAAiD,CAAC;AACxD,QAAM,eAAe,MAAM,SAAS,QAAQ,gBAAgB,CAAC;AAC7D,WAAS,mBAAmB,cAAc;AACxC,QAAI,oBAAoB,WAAW;AACjC,eAAS,KAAK,EAAE,WAAW,WAAW,MAAM,WAAW,KAAK,MAAM,IAAK,CAAC;AAAA,IAE1E,OAAO;AACL,YAAM,CAAC,WAAW,GAAG,IAAI,aAAa,iBAAiB,MAAM,GAAG,EAAE,IAAI,MAAM;AAC5E,eAAS,KAAK,EAAE,WAAW,iBAAiB,WAAW,IAAI,CAAC;AAAA,IAC9D;AAAA,EACF;AACA,SAAO;AACT;AAEA,IAAI,gBAAgB;AACpB,IAAI,iBAAiB;AACrB,MAAM,kBAAkB;AAEjB,SAAS,UAAU;AAIxB,QAAM,MAAM,KAAK,IAAI;AAErB,MAAI,MAAM,gBAAgB,iBAAiB;AACzC,oBAAgB;AAChB,WAAO,SAAS,KAAK,gBAAgB,GAAG,WAAW,GAAG,MAAM,aAAa,MAAM,KAAK;AAAA,EAEtF,OAAO;AACL,iBAAa,cAAc;AAC3B,qBAAiB,WAAW,SAAS,eAAe;AAAA,EACtD;AACF;AAEO,SAAS,MAAM,WAAoB,MAAM;AAC9C,QAAM,YAAY;AAClB,QAAM,MAAM;AAEZ,MAAI,UAAU;AACZ,oBAAgB;AAChB,iBAAa,cAAc;AAC3B,YAAQ;AAAA,EACV;AACF;AAEO,SAAS,eAAe,YAAoB;AACjD,SAAO,SAAS,KAAK,gBAAgB,GAAG,UAAU;AACpD;AAEA,eAAsB,eAAe;AACnC,QAAM,WAAW,MAAM,SAAS;AAChC,SAAO,SAAS,OAAO,CAAC,MAAM,SAAS,OAAO,KAAK,KAAK,CAAC;AAC3D;AAEA,SAAS,kBAAkB;AACzB,SAAO;AACT;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|