UNPKG

@colyseus/core

Version:

Multiplayer Framework for Node.js.

117 lines (116 loc) 4.76 kB
// packages/core/src/utils/DevMode.ts import fs from "fs"; import path from "path"; import { $changes } from "@colyseus/schema"; import { logger } from "../Logger.mjs"; import { debugAndPrintError, debugDevMode } from "../Debug.mjs"; import { getLocalRoomById, handleCreateRoom, presence, remoteRoomCall } from "../MatchMaker.mjs"; var DEVMODE_CACHE_FILE_PATH = path.resolve(".devmode.json"); var isDevMode = false; function hasDevModeCache() { return fs.existsSync(DEVMODE_CACHE_FILE_PATH); } function getDevModeCache() { return JSON.parse(fs.readFileSync(DEVMODE_CACHE_FILE_PATH, "utf8")) || {}; } function writeDevModeCache(cache) { fs.writeFileSync(DEVMODE_CACHE_FILE_PATH, JSON.stringify(cache, null, 2), "utf8"); } function setDevMode(bool) { isDevMode = bool; } async function reloadFromCache() { const roomHistoryList = Object.entries(await presence.hgetall(getRoomRestoreListKey())); debugDevMode("rooms to restore: %i", roomHistoryList.length); for (const [roomId, value] of roomHistoryList) { const roomHistory = JSON.parse(value); debugDevMode("restoring room %s (%s)", roomHistory.roomName, roomId); const recreatedRoomListing = await handleCreateRoom(roomHistory.roomName, roomHistory.clientOptions, roomId); const recreatedRoom = getLocalRoomById(recreatedRoomListing.roomId); if (roomHistory.hasOwnProperty("state")) { try { const rawState = JSON.parse(roomHistory.state); logger.debug(`\u{1F4CB} room '${roomId}' state =>`, rawState); recreatedRoom.state.restore(rawState); if (roomHistory.nextRefId !== void 0) { const encoderRoot = recreatedRoom.state[$changes]?.root; if (encoderRoot && roomHistory.nextRefId > encoderRoot["nextUniqueId"]) { encoderRoot["nextUniqueId"] = roomHistory.nextRefId; } } } catch (e) { debugAndPrintError(`\u274C couldn't restore room '${roomId}' state: ${e.stack}`); } } if (roomHistory.clients) { for (const clientData of roomHistory.clients) { const { sessionId, reconnectionToken } = clientData; if (!reconnectionToken) { continue; } await remoteRoomCall(recreatedRoomListing.roomId, "_reserveSeat", [sessionId, {}, {}, recreatedRoom.seatReservationTimeout, false, reconnectionToken]); } } recreatedRoom.onRestoreRoom?.(roomHistory["cache"]); logger.debug(`\u{1F504} room '${roomId}' has been restored with ${roomHistory.clients?.length || 0} reserved seats: ${roomHistory.clients?.map((c) => c.sessionId).join(", ")}`); } if (roomHistoryList.length > 0) { logger.debug("\u2705", roomHistoryList.length, "room(s) have been restored."); } } async function cacheRoomHistory(rooms) { for (const room of Object.values(rooms)) { const roomHistoryResult = await presence.hget(getRoomRestoreListKey(), room.roomId); if (roomHistoryResult) { try { const roomHistory = JSON.parse(roomHistoryResult); roomHistory["cache"] = room.onCacheRoom?.(); debugDevMode("caching room %s (%s)", room.roomName, room.roomId); if (room.state) { roomHistory["state"] = JSON.stringify(room.state); const encoderRoot = room.state[$changes]?.root; if (encoderRoot) { roomHistory["nextRefId"] = encoderRoot["nextUniqueId"]; } } const activeClients = room.clients.map((client) => ({ sessionId: client.sessionId, reconnectionToken: client.reconnectionToken })); const activeSessionIds = new Set(activeClients.map((c) => c.sessionId)); const reservedSeats = Object.keys(room["_reservedSeats"]).filter((sessionId) => !activeSessionIds.has(sessionId)).map((sessionId) => ({ sessionId, reconnectionToken: void 0 })); roomHistory["clients"] = activeClients.concat(reservedSeats); await presence.hset(getRoomRestoreListKey(), room.roomId, JSON.stringify(roomHistory)); logger.debug(`\u{1F4BE} caching room '${room.roomId}' (clients: ${room.clients.length}, has state: ${roomHistory["state"] !== void 0 ? "yes" : "no"})`); } catch (e) { debugAndPrintError(`\u274C couldn't cache room '${room.roomId}', due to: ${e.stack}`); } } } } async function getPreviousProcessId(hostname = "") { return await presence.hget(getProcessRestoreKey(), hostname); } function getRoomRestoreListKey() { return "roomhistory"; } function getProcessRestoreKey() { return "processhistory"; } export { cacheRoomHistory, getDevModeCache, getPreviousProcessId, getProcessRestoreKey, getRoomRestoreListKey, hasDevModeCache, isDevMode, reloadFromCache, setDevMode, writeDevModeCache };