@colyseus/tools 0.17.7 → 0.17.9
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/index.cjs +5 -18
- package/build/index.cjs.map +3 -3
- package/build/index.mjs +6 -21
- package/build/index.mjs.map +2 -2
- package/package.json +2 -4
- package/src/index.ts +8 -30
package/build/index.cjs
CHANGED
|
@@ -40,7 +40,6 @@ var import_os = __toESM(require("os"), 1);
|
|
|
40
40
|
var import_fs = __toESM(require("fs"), 1);
|
|
41
41
|
var import_net = __toESM(require("net"), 1);
|
|
42
42
|
var import_http = __toESM(require("http"), 1);
|
|
43
|
-
var import_cors = __toESM(require("cors"), 1);
|
|
44
43
|
var import_express = __toESM(require("express"), 1);
|
|
45
44
|
var import_core = require("@colyseus/core");
|
|
46
45
|
var import_ws_transport = require("@colyseus/ws-transport");
|
|
@@ -86,18 +85,6 @@ async function listen(options, port = Number(process.env.PORT || 2567)) {
|
|
|
86
85
|
let displayLogs = true;
|
|
87
86
|
if (options instanceof import_core.Server) {
|
|
88
87
|
server = options;
|
|
89
|
-
if (process.env.COLYSEUS_CLOUD !== void 0) {
|
|
90
|
-
const isLocalDriver = import_core.matchMaker.driver instanceof import_core.LocalDriver;
|
|
91
|
-
const isLocalPresence = import_core.matchMaker.presence instanceof import_core.LocalPresence;
|
|
92
|
-
const cloudConfig = await getColyseusCloudConfig(
|
|
93
|
-
port,
|
|
94
|
-
isLocalDriver ? void 0 : import_core.matchMaker.driver,
|
|
95
|
-
isLocalPresence ? void 0 : import_core.matchMaker.presence
|
|
96
|
-
);
|
|
97
|
-
if (cloudConfig && (isLocalDriver || isLocalPresence)) {
|
|
98
|
-
await import_core.matchMaker.setup(cloudConfig.presence, cloudConfig.driver, cloudConfig.publicAddress);
|
|
99
|
-
}
|
|
100
|
-
}
|
|
101
88
|
} else {
|
|
102
89
|
server = await buildServerFromOptions(options, port);
|
|
103
90
|
displayLogs = options.displayLogs;
|
|
@@ -108,7 +95,11 @@ async function listen(options, port = Number(process.env.PORT || 2567)) {
|
|
|
108
95
|
if (process.env.COLYSEUS_CLOUD !== void 0) {
|
|
109
96
|
const socketPath = `/run/colyseus/${port}.sock`;
|
|
110
97
|
await checkInactiveSocketFile(socketPath);
|
|
111
|
-
await server.listen(
|
|
98
|
+
await server.listen(
|
|
99
|
+
socketPath,
|
|
100
|
+
0
|
|
101
|
+
// workaround to allow using @colyseus/core's .listen() directly on Colyseus Cloud
|
|
102
|
+
);
|
|
112
103
|
} else {
|
|
113
104
|
await server.listen(port);
|
|
114
105
|
}
|
|
@@ -161,13 +152,9 @@ async function getTransport(options) {
|
|
|
161
152
|
app = transport["expressApp"];
|
|
162
153
|
}
|
|
163
154
|
if (app) {
|
|
164
|
-
app.use((0, import_cors.default)({ origin: true, credentials: true }));
|
|
165
155
|
if (options.initializeExpress) {
|
|
166
156
|
await options.initializeExpress(app);
|
|
167
157
|
}
|
|
168
|
-
app.get("/__healthcheck", (req, res) => {
|
|
169
|
-
res.status(200).end();
|
|
170
|
-
});
|
|
171
158
|
if (options.displayLogs) {
|
|
172
159
|
import_core.logger.info("\u2705 Express initialized");
|
|
173
160
|
}
|
package/build/index.cjs.map
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../src/index.ts"],
|
|
4
|
-
"sourcesContent": ["import './loadenv.ts';\nimport os from 'os';\nimport fs from \"fs\";\nimport net from \"net\";\nimport http from 'http';\nimport cors from 'cors';\nimport express from 'express';\nimport {\n type ServerOptions,\n type SDKTypes,\n type Router,\n logger,\n Server,\n Transport,\n matchMaker,\n RegisteredHandler,\n defineServer,\n LocalDriver,\n LocalPresence\n} from '@colyseus/core';\nimport { WebSocketTransport } from '@colyseus/ws-transport';\n\nconst BunWebSockets = import('@colyseus/bun-websockets'); BunWebSockets.catch(() => {});\nconst RedisDriver = import('@colyseus/redis-driver'); RedisDriver.catch(() => {});\nconst RedisPresence = import('@colyseus/redis-presence'); RedisPresence.catch(() => {});\n\nexport interface ConfigOptions<\n RoomTypes extends Record<string, RegisteredHandler> = any,\n Routes extends Router = any\n> extends SDKTypes<RoomTypes, Routes> {\n options?: ServerOptions,\n displayLogs?: boolean,\n rooms?: RoomTypes,\n routes?: Routes,\n initializeTransport?: (options: any) => Transport,\n initializeExpress?: (app: express.Express) => void,\n initializeGameServer?: (app: Server) => void,\n beforeListen?: () => void,\n /**\n * @deprecated getId() has no effect anymore.\n */\n getId?: () => string,\n}\n\nconst ALLOWED_KEYS: { [key in keyof Partial<ConfigOptions>]: string } = {\n 'displayLogs': \"boolean\",\n 'options': \"object\",\n 'rooms': \"object\",\n 'routes': \"object\",\n 'initializeTransport': \"function\",\n 'initializeExpress': \"function\",\n 'initializeGameServer': \"function\",\n 'beforeListen': \"function\",\n // deprecated options (will be removed in the next major version)\n 'getId': \"function\",\n};\n\nexport default function <\n RoomTypes extends Record<string, RegisteredHandler> = any,\n Routes extends Router = any\n>(options: Omit<ConfigOptions<RoomTypes, Routes>, '~rooms' | '~routes'>) {\n for (const option in options) {\n if (!ALLOWED_KEYS[option]) {\n throw new Error(`\u274C Invalid option '${option}'. Allowed options are: ${Object.keys(ALLOWED_KEYS).join(\", \")}`);\n }\n if(options[option] !== undefined && typeof(options[option]) !== ALLOWED_KEYS[option]) {\n throw new Error(`\u274C Invalid type for ${option}: please provide a ${ALLOWED_KEYS[option]} value.`);\n }\n }\n return options as ConfigOptions<RoomTypes, Routes>;\n}\n\n/**\n * Expose server instance and listen on the port specified\n * @param options Application options\n * @param port Port number to bind Colyseus + Express\n */\nexport async function listen<\n RoomTypes extends Record<string, RegisteredHandler> = any,\n Routes extends Router = any\n>(\n options: ConfigOptions<RoomTypes, Routes>,\n port?: number,\n): Promise<Server<RoomTypes, Routes>>;\n\n/**\n * Expose server instance and listen on the port specified\n * @param server Server instance\n * @param port Port number to bind Colyseus + Express\n */\nexport async function listen<\n RoomTypes extends Record<string, RegisteredHandler> = any,\n Routes extends Router = any\n>(\n server: Server<RoomTypes, Routes>,\n port?: number,\n): Promise<Server<RoomTypes, Routes>>;\n\nexport async function listen<\n RoomTypes extends Record<string, RegisteredHandler> = any,\n Routes extends Router = any\n>(\n options: ConfigOptions<RoomTypes, Routes> | Server<RoomTypes, Routes>,\n port: number = Number(process.env.PORT || 2567),\n) {\n // Force 2567 port on Colyseus Cloud\n if (process.env.COLYSEUS_CLOUD !== undefined) {\n port = 2567;\n }\n\n //\n // Handling multiple processes\n // Use NODE_APP_INSTANCE to play nicely with pm2\n //\n const processNumber = Number(process.env.NODE_APP_INSTANCE || \"0\");\n port += processNumber;\n\n let server: Server<RoomTypes, Routes>;\n let displayLogs = true;\n\n if (options instanceof Server) {\n server = options;\n\n // automatically configure for production under Colyseus Cloud\n if (process.env.COLYSEUS_CLOUD !== undefined) {\n // check if local driver/presence are being used (defaults)\n const isLocalDriver = matchMaker.driver instanceof LocalDriver;\n const isLocalPresence = matchMaker.presence instanceof LocalPresence;\n\n const cloudConfig = await getColyseusCloudConfig(\n port,\n isLocalDriver ? undefined : matchMaker.driver,\n isLocalPresence ? undefined : matchMaker.presence,\n );\n\n // re-setup matchMaker with Redis driver/presence\n if (cloudConfig && (isLocalDriver || isLocalPresence)) {\n await matchMaker.setup(cloudConfig.presence, cloudConfig.driver, cloudConfig.publicAddress);\n }\n }\n\n } else {\n server = await buildServerFromOptions<RoomTypes, Routes>(options, port);\n displayLogs = options.displayLogs;\n\n await options.initializeGameServer?.(server);\n await matchMaker.onReady;\n await options.beforeListen?.();\n }\n\n if (process.env.COLYSEUS_CLOUD !== undefined) {\n // listening on socket\n const socketPath: any = `/run/colyseus/${port}.sock`;\n // const socketPath: any = `/tmp/${port}.sock`;\n\n // check if .sock file is active\n // (fixes \"ADDRINUSE\" issue when restarting the server)\n await checkInactiveSocketFile(socketPath);\n\n await server.listen(socketPath);\n\n } else {\n // listening on port\n await server.listen(port);\n }\n\n // notify process manager (production)\n if (typeof(process.send) === \"function\") {\n process.send('ready');\n }\n\n if (displayLogs) {\n logger.info(`\u2694\uFE0F Listening on http://localhost:${port}`);\n }\n\n return server;\n}\n\nasync function buildServerFromOptions<\n RoomTypes extends Record<string, RegisteredHandler> = any,\n Routes extends Router = any\n>(options: ConfigOptions<RoomTypes, Routes>, port: number) {\n const serverOptions = options.options || {};\n options.displayLogs = options.displayLogs ?? true;\n\n // automatically configure for production under Colyseus Cloud\n if (process.env.COLYSEUS_CLOUD !== undefined) {\n const cloudConfig = await getColyseusCloudConfig(port, serverOptions.driver, serverOptions.presence);\n if (cloudConfig) {\n serverOptions.driver = cloudConfig.driver;\n serverOptions.presence = cloudConfig.presence;\n serverOptions.publicAddress = cloudConfig.publicAddress;\n }\n }\n\n return defineServer<RoomTypes, Routes>({\n rooms: options.rooms || {} as RoomTypes,\n routes: options.routes,\n ...serverOptions,\n transport: await getTransport(options),\n });\n}\n\nexport async function getTransport(options: ConfigOptions) {\n let transport: Transport;\n\n if (!options.initializeTransport) {\n // @ts-ignore\n if (typeof Bun !== \"undefined\") {\n // @colyseus/bun-websockets\n BunWebSockets.catch(() => {\n logger.warn(\"\");\n logger.warn(\"\u274C could not initialize BunWebSockets.\");\n logger.warn(\"\uD83D\uDC49 npm install --save @colyseus/bun-websockets\");\n logger.warn(\"\");\n })\n const module = await BunWebSockets;\n options.initializeTransport = (options: any) => new module.BunWebSockets(options);\n\n } else {\n // use WebSocketTransport by default\n options.initializeTransport = (options: any) => new WebSocketTransport(options);\n }\n }\n\n let app: express.Express | undefined = express();\n let server = http.createServer(app);\n\n transport = await options.initializeTransport({ server, app });\n\n //\n // TODO: refactor me!\n // BunWebSockets: There's no need to instantiate \"app\" and \"server\" above\n //\n if (transport['expressApp']) {\n app = transport['expressApp'];\n }\n\n if (app) {\n // Enable CORS\n app.use(cors({ origin: true, credentials: true, }));\n\n if (options.initializeExpress) {\n await options.initializeExpress(app);\n }\n\n // health check for load balancers\n app.get(\"/__healthcheck\", (req, res) => {\n res.status(200).end();\n });\n\n if (options.displayLogs) {\n logger.info(\"\u2705 Express initialized\");\n }\n }\n\n return transport;\n}\n\n/**\n * Configure Redis driver/presence for Colyseus Cloud when needed.\n * Returns configured driver, presence, and publicAddress.\n */\nasync function getColyseusCloudConfig(port: number, currentDriver?: any, currentPresence?: any) {\n const useRedisConfig = (os.cpus().length > 1) || (process.env.REDIS_URI !== undefined);\n\n if (!useRedisConfig) {\n return null;\n }\n\n let driver = currentDriver;\n let presence = currentPresence;\n const publicAddress = process.env.SUBDOMAIN + \".\" + process.env.SERVER_NAME + \"/\" + port;\n\n if (!driver) {\n try {\n const module = await RedisDriver;\n driver = new module.RedisDriver(process.env.REDIS_URI);\n } catch (e) {\n console.error(e);\n logger.warn(\"\");\n logger.warn(\"\u274C could not initialize RedisDriver.\");\n logger.warn(\"\uD83D\uDC49 npm install --save @colyseus/redis-driver\");\n logger.warn(\"\");\n }\n }\n\n if (!presence) {\n try {\n const module = await RedisPresence;\n presence = new module.RedisPresence(process.env.REDIS_URI);\n } catch (e) {\n console.error(e);\n logger.warn(\"\");\n logger.warn(\"\u274C could not initialize RedisPresence.\");\n logger.warn(\"\uD83D\uDC49 npm install --save @colyseus/redis-presence\");\n logger.warn(\"\");\n }\n }\n\n return { driver, presence, publicAddress };\n}\n\n/**\n * Check if a socket file is active and remove it if it's not.\n */\nfunction checkInactiveSocketFile(sockFilePath: string) {\n return new Promise((resolve, reject) => {\n const client = net.createConnection({ path: sockFilePath })\n .on('connect', () => {\n // socket file is active, close the connection\n client.end();\n throw new Error(`EADDRINUSE: Already listening on '${sockFilePath}'`);\n })\n .on('error', () => {\n // socket file is inactive, remove it\n fs.unlink(sockFilePath, () => resolve(true));\n });\n });\n}"],
|
|
5
|
-
"mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,qBAAO;AACP,gBAAe;AACf,gBAAe;AACf,iBAAgB;AAChB,kBAAiB;AACjB,
|
|
6
|
-
"names": ["module", "options", "express", "http", "
|
|
4
|
+
"sourcesContent": ["import './loadenv.ts';\nimport os from 'os';\nimport fs from \"fs\";\nimport net from \"net\";\nimport http from 'http';\nimport express from 'express';\nimport {\n type ServerOptions,\n type SDKTypes,\n type Router,\n logger,\n Server,\n Transport,\n matchMaker,\n RegisteredHandler,\n defineServer,\n} from '@colyseus/core';\nimport { WebSocketTransport } from '@colyseus/ws-transport';\n\nconst BunWebSockets = import('@colyseus/bun-websockets'); BunWebSockets.catch(() => {});\nconst RedisDriver = import('@colyseus/redis-driver'); RedisDriver.catch(() => {});\nconst RedisPresence = import('@colyseus/redis-presence'); RedisPresence.catch(() => {});\n\nexport interface ConfigOptions<\n RoomTypes extends Record<string, RegisteredHandler> = any,\n Routes extends Router = any\n> extends SDKTypes<RoomTypes, Routes> {\n options?: ServerOptions,\n displayLogs?: boolean,\n rooms?: RoomTypes,\n routes?: Routes,\n initializeTransport?: (options: any) => Transport,\n initializeExpress?: (app: express.Express) => void,\n initializeGameServer?: (app: Server) => void,\n beforeListen?: () => void,\n /**\n * @deprecated getId() has no effect anymore.\n */\n getId?: () => string,\n}\n\nconst ALLOWED_KEYS: { [key in keyof Partial<ConfigOptions>]: string } = {\n 'displayLogs': \"boolean\",\n 'options': \"object\",\n 'rooms': \"object\",\n 'routes': \"object\",\n 'initializeTransport': \"function\",\n 'initializeExpress': \"function\",\n 'initializeGameServer': \"function\",\n 'beforeListen': \"function\",\n // deprecated options (will be removed in the next major version)\n 'getId': \"function\",\n};\n\nexport default function <\n RoomTypes extends Record<string, RegisteredHandler> = any,\n Routes extends Router = any\n>(options: Omit<ConfigOptions<RoomTypes, Routes>, '~rooms' | '~routes'>) {\n for (const option in options) {\n if (!ALLOWED_KEYS[option]) {\n throw new Error(`\u274C Invalid option '${option}'. Allowed options are: ${Object.keys(ALLOWED_KEYS).join(\", \")}`);\n }\n if(options[option] !== undefined && typeof(options[option]) !== ALLOWED_KEYS[option]) {\n throw new Error(`\u274C Invalid type for ${option}: please provide a ${ALLOWED_KEYS[option]} value.`);\n }\n }\n return options as ConfigOptions<RoomTypes, Routes>;\n}\n\n/**\n * Expose server instance and listen on the port specified\n * @param options Application options\n * @param port Port number to bind Colyseus + Express\n */\nexport async function listen<\n RoomTypes extends Record<string, RegisteredHandler> = any,\n Routes extends Router = any\n>(\n options: ConfigOptions<RoomTypes, Routes>,\n port?: number,\n): Promise<Server<RoomTypes, Routes>>;\n\n/**\n * Expose server instance and listen on the port specified\n * @param server Server instance\n * @param port Port number to bind Colyseus + Express\n */\nexport async function listen<\n RoomTypes extends Record<string, RegisteredHandler> = any,\n Routes extends Router = any\n>(\n server: Server<RoomTypes, Routes>,\n port?: number,\n): Promise<Server<RoomTypes, Routes>>;\n\nexport async function listen<\n RoomTypes extends Record<string, RegisteredHandler> = any,\n Routes extends Router = any\n>(\n options: ConfigOptions<RoomTypes, Routes> | Server<RoomTypes, Routes>,\n port: number = Number(process.env.PORT || 2567),\n) {\n // Force 2567 port on Colyseus Cloud\n if (process.env.COLYSEUS_CLOUD !== undefined) {\n port = 2567;\n }\n\n //\n // Handling multiple processes\n // Use NODE_APP_INSTANCE to play nicely with pm2\n //\n const processNumber = Number(process.env.NODE_APP_INSTANCE || \"0\");\n port += processNumber;\n\n let server: Server<RoomTypes, Routes>;\n let displayLogs = true;\n\n if (options instanceof Server) {\n server = options;\n\n // automatically configure for production under Colyseus Cloud\n // if on Colyseus Cloud, the matchMaker should have been configured by the time we get here\n // See @colyseus/core src/utils/Env.ts\n\n } else {\n server = await buildServerFromOptions<RoomTypes, Routes>(options, port);\n displayLogs = options.displayLogs;\n\n await options.initializeGameServer?.(server);\n await matchMaker.onReady;\n await options.beforeListen?.();\n }\n\n if (process.env.COLYSEUS_CLOUD !== undefined) {\n // listening on socket\n const socketPath = `/run/colyseus/${port}.sock`;\n // const socketPath: any = `/tmp/${port}.sock`;\n\n // check if .sock file is active\n // (fixes \"ADDRINUSE\" issue when restarting the server)\n await checkInactiveSocketFile(socketPath);\n\n await server.listen(\n socketPath,\n 0 as any // workaround to allow using @colyseus/core's .listen() directly on Colyseus Cloud\n );\n\n } else {\n // listening on port\n await server.listen(port);\n }\n\n // notify process manager (production)\n if (typeof(process.send) === \"function\") {\n process.send('ready');\n }\n\n if (displayLogs) {\n logger.info(`\u2694\uFE0F Listening on http://localhost:${port}`);\n }\n\n return server;\n}\n\nasync function buildServerFromOptions<\n RoomTypes extends Record<string, RegisteredHandler> = any,\n Routes extends Router = any\n>(options: ConfigOptions<RoomTypes, Routes>, port: number) {\n const serverOptions = options.options || {};\n options.displayLogs = options.displayLogs ?? true;\n\n // automatically configure for production under Colyseus Cloud\n if (process.env.COLYSEUS_CLOUD !== undefined) {\n const cloudConfig = await getColyseusCloudConfig(port, serverOptions.driver, serverOptions.presence);\n if (cloudConfig) {\n serverOptions.driver = cloudConfig.driver;\n serverOptions.presence = cloudConfig.presence;\n serverOptions.publicAddress = cloudConfig.publicAddress;\n }\n }\n\n return defineServer<RoomTypes, Routes>({\n rooms: options.rooms || {} as RoomTypes,\n routes: options.routes,\n ...serverOptions,\n transport: await getTransport(options),\n });\n}\n\nexport async function getTransport(options: ConfigOptions) {\n let transport: Transport;\n\n if (!options.initializeTransport) {\n // @ts-ignore\n if (typeof Bun !== \"undefined\") {\n // @colyseus/bun-websockets\n BunWebSockets.catch(() => {\n logger.warn(\"\");\n logger.warn(\"\u274C could not initialize BunWebSockets.\");\n logger.warn(\"\uD83D\uDC49 npm install --save @colyseus/bun-websockets\");\n logger.warn(\"\");\n })\n const module = await BunWebSockets;\n options.initializeTransport = (options: any) => new module.BunWebSockets(options);\n\n } else {\n // use WebSocketTransport by default\n options.initializeTransport = (options: any) => new WebSocketTransport(options);\n }\n }\n\n let app: express.Express | undefined = express();\n let server = http.createServer(app);\n\n transport = await options.initializeTransport({ server, app });\n\n //\n // TODO: refactor me!\n // BunWebSockets: There's no need to instantiate \"app\" and \"server\" above\n //\n if (transport['expressApp']) {\n app = transport['expressApp'];\n }\n\n if (app) {\n if (options.initializeExpress) {\n await options.initializeExpress(app);\n }\n\n if (options.displayLogs) {\n logger.info(\"\u2705 Express initialized\");\n }\n }\n\n return transport;\n}\n\n/**\n * Configure Redis driver/presence for Colyseus Cloud when needed.\n * Returns configured driver, presence, and publicAddress.\n */\nasync function getColyseusCloudConfig(port: number, currentDriver?: any, currentPresence?: any) {\n const useRedisConfig = (os.cpus().length > 1) || (process.env.REDIS_URI !== undefined);\n\n if (!useRedisConfig) {\n return null;\n }\n\n let driver = currentDriver;\n let presence = currentPresence;\n const publicAddress = process.env.SUBDOMAIN + \".\" + process.env.SERVER_NAME + \"/\" + port;\n\n if (!driver) {\n try {\n const module = await RedisDriver;\n driver = new module.RedisDriver(process.env.REDIS_URI);\n } catch (e) {\n console.error(e);\n logger.warn(\"\");\n logger.warn(\"\u274C could not initialize RedisDriver.\");\n logger.warn(\"\uD83D\uDC49 npm install --save @colyseus/redis-driver\");\n logger.warn(\"\");\n }\n }\n\n if (!presence) {\n try {\n const module = await RedisPresence;\n presence = new module.RedisPresence(process.env.REDIS_URI);\n } catch (e) {\n console.error(e);\n logger.warn(\"\");\n logger.warn(\"\u274C could not initialize RedisPresence.\");\n logger.warn(\"\uD83D\uDC49 npm install --save @colyseus/redis-presence\");\n logger.warn(\"\");\n }\n }\n\n return { driver, presence, publicAddress };\n}\n\n/**\n * Check if a socket file is active and remove it if it's not.\n */\nfunction checkInactiveSocketFile(sockFilePath: string) {\n return new Promise((resolve, reject) => {\n const client = net.createConnection({ path: sockFilePath })\n .on('connect', () => {\n // socket file is active, close the connection\n client.end();\n throw new Error(`EADDRINUSE: Already listening on '${sockFilePath}'`);\n })\n .on('error', () => {\n // socket file is inactive, remove it\n fs.unlink(sockFilePath, () => resolve(true));\n });\n });\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": ["module", "options", "express", "http", "os", "net", "fs"]
|
|
7
7
|
}
|
package/build/index.mjs
CHANGED
|
@@ -4,15 +4,12 @@ import os from "os";
|
|
|
4
4
|
import fs from "fs";
|
|
5
5
|
import net from "net";
|
|
6
6
|
import http from "http";
|
|
7
|
-
import cors from "cors";
|
|
8
7
|
import express from "express";
|
|
9
8
|
import {
|
|
10
9
|
logger,
|
|
11
10
|
Server,
|
|
12
11
|
matchMaker,
|
|
13
|
-
defineServer
|
|
14
|
-
LocalDriver,
|
|
15
|
-
LocalPresence
|
|
12
|
+
defineServer
|
|
16
13
|
} from "@colyseus/core";
|
|
17
14
|
import { WebSocketTransport } from "@colyseus/ws-transport";
|
|
18
15
|
var BunWebSockets = import("@colyseus/bun-websockets");
|
|
@@ -57,18 +54,6 @@ async function listen(options, port = Number(process.env.PORT || 2567)) {
|
|
|
57
54
|
let displayLogs = true;
|
|
58
55
|
if (options instanceof Server) {
|
|
59
56
|
server = options;
|
|
60
|
-
if (process.env.COLYSEUS_CLOUD !== void 0) {
|
|
61
|
-
const isLocalDriver = matchMaker.driver instanceof LocalDriver;
|
|
62
|
-
const isLocalPresence = matchMaker.presence instanceof LocalPresence;
|
|
63
|
-
const cloudConfig = await getColyseusCloudConfig(
|
|
64
|
-
port,
|
|
65
|
-
isLocalDriver ? void 0 : matchMaker.driver,
|
|
66
|
-
isLocalPresence ? void 0 : matchMaker.presence
|
|
67
|
-
);
|
|
68
|
-
if (cloudConfig && (isLocalDriver || isLocalPresence)) {
|
|
69
|
-
await matchMaker.setup(cloudConfig.presence, cloudConfig.driver, cloudConfig.publicAddress);
|
|
70
|
-
}
|
|
71
|
-
}
|
|
72
57
|
} else {
|
|
73
58
|
server = await buildServerFromOptions(options, port);
|
|
74
59
|
displayLogs = options.displayLogs;
|
|
@@ -79,7 +64,11 @@ async function listen(options, port = Number(process.env.PORT || 2567)) {
|
|
|
79
64
|
if (process.env.COLYSEUS_CLOUD !== void 0) {
|
|
80
65
|
const socketPath = `/run/colyseus/${port}.sock`;
|
|
81
66
|
await checkInactiveSocketFile(socketPath);
|
|
82
|
-
await server.listen(
|
|
67
|
+
await server.listen(
|
|
68
|
+
socketPath,
|
|
69
|
+
0
|
|
70
|
+
// workaround to allow using @colyseus/core's .listen() directly on Colyseus Cloud
|
|
71
|
+
);
|
|
83
72
|
} else {
|
|
84
73
|
await server.listen(port);
|
|
85
74
|
}
|
|
@@ -132,13 +121,9 @@ async function getTransport(options) {
|
|
|
132
121
|
app = transport["expressApp"];
|
|
133
122
|
}
|
|
134
123
|
if (app) {
|
|
135
|
-
app.use(cors({ origin: true, credentials: true }));
|
|
136
124
|
if (options.initializeExpress) {
|
|
137
125
|
await options.initializeExpress(app);
|
|
138
126
|
}
|
|
139
|
-
app.get("/__healthcheck", (req, res) => {
|
|
140
|
-
res.status(200).end();
|
|
141
|
-
});
|
|
142
127
|
if (options.displayLogs) {
|
|
143
128
|
logger.info("\u2705 Express initialized");
|
|
144
129
|
}
|
package/build/index.mjs.map
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../src/index.ts"],
|
|
4
|
-
"sourcesContent": ["import './loadenv.ts';\nimport os from 'os';\nimport fs from \"fs\";\nimport net from \"net\";\nimport http from 'http';\nimport cors from 'cors';\nimport express from 'express';\nimport {\n type ServerOptions,\n type SDKTypes,\n type Router,\n logger,\n Server,\n Transport,\n matchMaker,\n RegisteredHandler,\n defineServer,\n LocalDriver,\n LocalPresence\n} from '@colyseus/core';\nimport { WebSocketTransport } from '@colyseus/ws-transport';\n\nconst BunWebSockets = import('@colyseus/bun-websockets'); BunWebSockets.catch(() => {});\nconst RedisDriver = import('@colyseus/redis-driver'); RedisDriver.catch(() => {});\nconst RedisPresence = import('@colyseus/redis-presence'); RedisPresence.catch(() => {});\n\nexport interface ConfigOptions<\n RoomTypes extends Record<string, RegisteredHandler> = any,\n Routes extends Router = any\n> extends SDKTypes<RoomTypes, Routes> {\n options?: ServerOptions,\n displayLogs?: boolean,\n rooms?: RoomTypes,\n routes?: Routes,\n initializeTransport?: (options: any) => Transport,\n initializeExpress?: (app: express.Express) => void,\n initializeGameServer?: (app: Server) => void,\n beforeListen?: () => void,\n /**\n * @deprecated getId() has no effect anymore.\n */\n getId?: () => string,\n}\n\nconst ALLOWED_KEYS: { [key in keyof Partial<ConfigOptions>]: string } = {\n 'displayLogs': \"boolean\",\n 'options': \"object\",\n 'rooms': \"object\",\n 'routes': \"object\",\n 'initializeTransport': \"function\",\n 'initializeExpress': \"function\",\n 'initializeGameServer': \"function\",\n 'beforeListen': \"function\",\n // deprecated options (will be removed in the next major version)\n 'getId': \"function\",\n};\n\nexport default function <\n RoomTypes extends Record<string, RegisteredHandler> = any,\n Routes extends Router = any\n>(options: Omit<ConfigOptions<RoomTypes, Routes>, '~rooms' | '~routes'>) {\n for (const option in options) {\n if (!ALLOWED_KEYS[option]) {\n throw new Error(`\u274C Invalid option '${option}'. Allowed options are: ${Object.keys(ALLOWED_KEYS).join(\", \")}`);\n }\n if(options[option] !== undefined && typeof(options[option]) !== ALLOWED_KEYS[option]) {\n throw new Error(`\u274C Invalid type for ${option}: please provide a ${ALLOWED_KEYS[option]} value.`);\n }\n }\n return options as ConfigOptions<RoomTypes, Routes>;\n}\n\n/**\n * Expose server instance and listen on the port specified\n * @param options Application options\n * @param port Port number to bind Colyseus + Express\n */\nexport async function listen<\n RoomTypes extends Record<string, RegisteredHandler> = any,\n Routes extends Router = any\n>(\n options: ConfigOptions<RoomTypes, Routes>,\n port?: number,\n): Promise<Server<RoomTypes, Routes>>;\n\n/**\n * Expose server instance and listen on the port specified\n * @param server Server instance\n * @param port Port number to bind Colyseus + Express\n */\nexport async function listen<\n RoomTypes extends Record<string, RegisteredHandler> = any,\n Routes extends Router = any\n>(\n server: Server<RoomTypes, Routes>,\n port?: number,\n): Promise<Server<RoomTypes, Routes>>;\n\nexport async function listen<\n RoomTypes extends Record<string, RegisteredHandler> = any,\n Routes extends Router = any\n>(\n options: ConfigOptions<RoomTypes, Routes> | Server<RoomTypes, Routes>,\n port: number = Number(process.env.PORT || 2567),\n) {\n // Force 2567 port on Colyseus Cloud\n if (process.env.COLYSEUS_CLOUD !== undefined) {\n port = 2567;\n }\n\n //\n // Handling multiple processes\n // Use NODE_APP_INSTANCE to play nicely with pm2\n //\n const processNumber = Number(process.env.NODE_APP_INSTANCE || \"0\");\n port += processNumber;\n\n let server: Server<RoomTypes, Routes>;\n let displayLogs = true;\n\n if (options instanceof Server) {\n server = options;\n\n // automatically configure for production under Colyseus Cloud\n if (process.env.COLYSEUS_CLOUD !== undefined) {\n // check if local driver/presence are being used (defaults)\n const isLocalDriver = matchMaker.driver instanceof LocalDriver;\n const isLocalPresence = matchMaker.presence instanceof LocalPresence;\n\n const cloudConfig = await getColyseusCloudConfig(\n port,\n isLocalDriver ? undefined : matchMaker.driver,\n isLocalPresence ? undefined : matchMaker.presence,\n );\n\n // re-setup matchMaker with Redis driver/presence\n if (cloudConfig && (isLocalDriver || isLocalPresence)) {\n await matchMaker.setup(cloudConfig.presence, cloudConfig.driver, cloudConfig.publicAddress);\n }\n }\n\n } else {\n server = await buildServerFromOptions<RoomTypes, Routes>(options, port);\n displayLogs = options.displayLogs;\n\n await options.initializeGameServer?.(server);\n await matchMaker.onReady;\n await options.beforeListen?.();\n }\n\n if (process.env.COLYSEUS_CLOUD !== undefined) {\n // listening on socket\n const socketPath: any = `/run/colyseus/${port}.sock`;\n // const socketPath: any = `/tmp/${port}.sock`;\n\n // check if .sock file is active\n // (fixes \"ADDRINUSE\" issue when restarting the server)\n await checkInactiveSocketFile(socketPath);\n\n await server.listen(socketPath);\n\n } else {\n // listening on port\n await server.listen(port);\n }\n\n // notify process manager (production)\n if (typeof(process.send) === \"function\") {\n process.send('ready');\n }\n\n if (displayLogs) {\n logger.info(`\u2694\uFE0F Listening on http://localhost:${port}`);\n }\n\n return server;\n}\n\nasync function buildServerFromOptions<\n RoomTypes extends Record<string, RegisteredHandler> = any,\n Routes extends Router = any\n>(options: ConfigOptions<RoomTypes, Routes>, port: number) {\n const serverOptions = options.options || {};\n options.displayLogs = options.displayLogs ?? true;\n\n // automatically configure for production under Colyseus Cloud\n if (process.env.COLYSEUS_CLOUD !== undefined) {\n const cloudConfig = await getColyseusCloudConfig(port, serverOptions.driver, serverOptions.presence);\n if (cloudConfig) {\n serverOptions.driver = cloudConfig.driver;\n serverOptions.presence = cloudConfig.presence;\n serverOptions.publicAddress = cloudConfig.publicAddress;\n }\n }\n\n return defineServer<RoomTypes, Routes>({\n rooms: options.rooms || {} as RoomTypes,\n routes: options.routes,\n ...serverOptions,\n transport: await getTransport(options),\n });\n}\n\nexport async function getTransport(options: ConfigOptions) {\n let transport: Transport;\n\n if (!options.initializeTransport) {\n // @ts-ignore\n if (typeof Bun !== \"undefined\") {\n // @colyseus/bun-websockets\n BunWebSockets.catch(() => {\n logger.warn(\"\");\n logger.warn(\"\u274C could not initialize BunWebSockets.\");\n logger.warn(\"\uD83D\uDC49 npm install --save @colyseus/bun-websockets\");\n logger.warn(\"\");\n })\n const module = await BunWebSockets;\n options.initializeTransport = (options: any) => new module.BunWebSockets(options);\n\n } else {\n // use WebSocketTransport by default\n options.initializeTransport = (options: any) => new WebSocketTransport(options);\n }\n }\n\n let app: express.Express | undefined = express();\n let server = http.createServer(app);\n\n transport = await options.initializeTransport({ server, app });\n\n //\n // TODO: refactor me!\n // BunWebSockets: There's no need to instantiate \"app\" and \"server\" above\n //\n if (transport['expressApp']) {\n app = transport['expressApp'];\n }\n\n if (app) {\n // Enable CORS\n app.use(cors({ origin: true, credentials: true, }));\n\n if (options.initializeExpress) {\n await options.initializeExpress(app);\n }\n\n // health check for load balancers\n app.get(\"/__healthcheck\", (req, res) => {\n res.status(200).end();\n });\n\n if (options.displayLogs) {\n logger.info(\"\u2705 Express initialized\");\n }\n }\n\n return transport;\n}\n\n/**\n * Configure Redis driver/presence for Colyseus Cloud when needed.\n * Returns configured driver, presence, and publicAddress.\n */\nasync function getColyseusCloudConfig(port: number, currentDriver?: any, currentPresence?: any) {\n const useRedisConfig = (os.cpus().length > 1) || (process.env.REDIS_URI !== undefined);\n\n if (!useRedisConfig) {\n return null;\n }\n\n let driver = currentDriver;\n let presence = currentPresence;\n const publicAddress = process.env.SUBDOMAIN + \".\" + process.env.SERVER_NAME + \"/\" + port;\n\n if (!driver) {\n try {\n const module = await RedisDriver;\n driver = new module.RedisDriver(process.env.REDIS_URI);\n } catch (e) {\n console.error(e);\n logger.warn(\"\");\n logger.warn(\"\u274C could not initialize RedisDriver.\");\n logger.warn(\"\uD83D\uDC49 npm install --save @colyseus/redis-driver\");\n logger.warn(\"\");\n }\n }\n\n if (!presence) {\n try {\n const module = await RedisPresence;\n presence = new module.RedisPresence(process.env.REDIS_URI);\n } catch (e) {\n console.error(e);\n logger.warn(\"\");\n logger.warn(\"\u274C could not initialize RedisPresence.\");\n logger.warn(\"\uD83D\uDC49 npm install --save @colyseus/redis-presence\");\n logger.warn(\"\");\n }\n }\n\n return { driver, presence, publicAddress };\n}\n\n/**\n * Check if a socket file is active and remove it if it's not.\n */\nfunction checkInactiveSocketFile(sockFilePath: string) {\n return new Promise((resolve, reject) => {\n const client = net.createConnection({ path: sockFilePath })\n .on('connect', () => {\n // socket file is active, close the connection\n client.end();\n throw new Error(`EADDRINUSE: Already listening on '${sockFilePath}'`);\n })\n .on('error', () => {\n // socket file is inactive, remove it\n fs.unlink(sockFilePath, () => resolve(true));\n });\n });\n}"],
|
|
5
|
-
"mappings": ";AAAA,OAAO;AACP,OAAO,QAAQ;AACf,OAAO,QAAQ;AACf,OAAO,SAAS;AAChB,OAAO,UAAU;AACjB,OAAO,
|
|
4
|
+
"sourcesContent": ["import './loadenv.ts';\nimport os from 'os';\nimport fs from \"fs\";\nimport net from \"net\";\nimport http from 'http';\nimport express from 'express';\nimport {\n type ServerOptions,\n type SDKTypes,\n type Router,\n logger,\n Server,\n Transport,\n matchMaker,\n RegisteredHandler,\n defineServer,\n} from '@colyseus/core';\nimport { WebSocketTransport } from '@colyseus/ws-transport';\n\nconst BunWebSockets = import('@colyseus/bun-websockets'); BunWebSockets.catch(() => {});\nconst RedisDriver = import('@colyseus/redis-driver'); RedisDriver.catch(() => {});\nconst RedisPresence = import('@colyseus/redis-presence'); RedisPresence.catch(() => {});\n\nexport interface ConfigOptions<\n RoomTypes extends Record<string, RegisteredHandler> = any,\n Routes extends Router = any\n> extends SDKTypes<RoomTypes, Routes> {\n options?: ServerOptions,\n displayLogs?: boolean,\n rooms?: RoomTypes,\n routes?: Routes,\n initializeTransport?: (options: any) => Transport,\n initializeExpress?: (app: express.Express) => void,\n initializeGameServer?: (app: Server) => void,\n beforeListen?: () => void,\n /**\n * @deprecated getId() has no effect anymore.\n */\n getId?: () => string,\n}\n\nconst ALLOWED_KEYS: { [key in keyof Partial<ConfigOptions>]: string } = {\n 'displayLogs': \"boolean\",\n 'options': \"object\",\n 'rooms': \"object\",\n 'routes': \"object\",\n 'initializeTransport': \"function\",\n 'initializeExpress': \"function\",\n 'initializeGameServer': \"function\",\n 'beforeListen': \"function\",\n // deprecated options (will be removed in the next major version)\n 'getId': \"function\",\n};\n\nexport default function <\n RoomTypes extends Record<string, RegisteredHandler> = any,\n Routes extends Router = any\n>(options: Omit<ConfigOptions<RoomTypes, Routes>, '~rooms' | '~routes'>) {\n for (const option in options) {\n if (!ALLOWED_KEYS[option]) {\n throw new Error(`\u274C Invalid option '${option}'. Allowed options are: ${Object.keys(ALLOWED_KEYS).join(\", \")}`);\n }\n if(options[option] !== undefined && typeof(options[option]) !== ALLOWED_KEYS[option]) {\n throw new Error(`\u274C Invalid type for ${option}: please provide a ${ALLOWED_KEYS[option]} value.`);\n }\n }\n return options as ConfigOptions<RoomTypes, Routes>;\n}\n\n/**\n * Expose server instance and listen on the port specified\n * @param options Application options\n * @param port Port number to bind Colyseus + Express\n */\nexport async function listen<\n RoomTypes extends Record<string, RegisteredHandler> = any,\n Routes extends Router = any\n>(\n options: ConfigOptions<RoomTypes, Routes>,\n port?: number,\n): Promise<Server<RoomTypes, Routes>>;\n\n/**\n * Expose server instance and listen on the port specified\n * @param server Server instance\n * @param port Port number to bind Colyseus + Express\n */\nexport async function listen<\n RoomTypes extends Record<string, RegisteredHandler> = any,\n Routes extends Router = any\n>(\n server: Server<RoomTypes, Routes>,\n port?: number,\n): Promise<Server<RoomTypes, Routes>>;\n\nexport async function listen<\n RoomTypes extends Record<string, RegisteredHandler> = any,\n Routes extends Router = any\n>(\n options: ConfigOptions<RoomTypes, Routes> | Server<RoomTypes, Routes>,\n port: number = Number(process.env.PORT || 2567),\n) {\n // Force 2567 port on Colyseus Cloud\n if (process.env.COLYSEUS_CLOUD !== undefined) {\n port = 2567;\n }\n\n //\n // Handling multiple processes\n // Use NODE_APP_INSTANCE to play nicely with pm2\n //\n const processNumber = Number(process.env.NODE_APP_INSTANCE || \"0\");\n port += processNumber;\n\n let server: Server<RoomTypes, Routes>;\n let displayLogs = true;\n\n if (options instanceof Server) {\n server = options;\n\n // automatically configure for production under Colyseus Cloud\n // if on Colyseus Cloud, the matchMaker should have been configured by the time we get here\n // See @colyseus/core src/utils/Env.ts\n\n } else {\n server = await buildServerFromOptions<RoomTypes, Routes>(options, port);\n displayLogs = options.displayLogs;\n\n await options.initializeGameServer?.(server);\n await matchMaker.onReady;\n await options.beforeListen?.();\n }\n\n if (process.env.COLYSEUS_CLOUD !== undefined) {\n // listening on socket\n const socketPath = `/run/colyseus/${port}.sock`;\n // const socketPath: any = `/tmp/${port}.sock`;\n\n // check if .sock file is active\n // (fixes \"ADDRINUSE\" issue when restarting the server)\n await checkInactiveSocketFile(socketPath);\n\n await server.listen(\n socketPath,\n 0 as any // workaround to allow using @colyseus/core's .listen() directly on Colyseus Cloud\n );\n\n } else {\n // listening on port\n await server.listen(port);\n }\n\n // notify process manager (production)\n if (typeof(process.send) === \"function\") {\n process.send('ready');\n }\n\n if (displayLogs) {\n logger.info(`\u2694\uFE0F Listening on http://localhost:${port}`);\n }\n\n return server;\n}\n\nasync function buildServerFromOptions<\n RoomTypes extends Record<string, RegisteredHandler> = any,\n Routes extends Router = any\n>(options: ConfigOptions<RoomTypes, Routes>, port: number) {\n const serverOptions = options.options || {};\n options.displayLogs = options.displayLogs ?? true;\n\n // automatically configure for production under Colyseus Cloud\n if (process.env.COLYSEUS_CLOUD !== undefined) {\n const cloudConfig = await getColyseusCloudConfig(port, serverOptions.driver, serverOptions.presence);\n if (cloudConfig) {\n serverOptions.driver = cloudConfig.driver;\n serverOptions.presence = cloudConfig.presence;\n serverOptions.publicAddress = cloudConfig.publicAddress;\n }\n }\n\n return defineServer<RoomTypes, Routes>({\n rooms: options.rooms || {} as RoomTypes,\n routes: options.routes,\n ...serverOptions,\n transport: await getTransport(options),\n });\n}\n\nexport async function getTransport(options: ConfigOptions) {\n let transport: Transport;\n\n if (!options.initializeTransport) {\n // @ts-ignore\n if (typeof Bun !== \"undefined\") {\n // @colyseus/bun-websockets\n BunWebSockets.catch(() => {\n logger.warn(\"\");\n logger.warn(\"\u274C could not initialize BunWebSockets.\");\n logger.warn(\"\uD83D\uDC49 npm install --save @colyseus/bun-websockets\");\n logger.warn(\"\");\n })\n const module = await BunWebSockets;\n options.initializeTransport = (options: any) => new module.BunWebSockets(options);\n\n } else {\n // use WebSocketTransport by default\n options.initializeTransport = (options: any) => new WebSocketTransport(options);\n }\n }\n\n let app: express.Express | undefined = express();\n let server = http.createServer(app);\n\n transport = await options.initializeTransport({ server, app });\n\n //\n // TODO: refactor me!\n // BunWebSockets: There's no need to instantiate \"app\" and \"server\" above\n //\n if (transport['expressApp']) {\n app = transport['expressApp'];\n }\n\n if (app) {\n if (options.initializeExpress) {\n await options.initializeExpress(app);\n }\n\n if (options.displayLogs) {\n logger.info(\"\u2705 Express initialized\");\n }\n }\n\n return transport;\n}\n\n/**\n * Configure Redis driver/presence for Colyseus Cloud when needed.\n * Returns configured driver, presence, and publicAddress.\n */\nasync function getColyseusCloudConfig(port: number, currentDriver?: any, currentPresence?: any) {\n const useRedisConfig = (os.cpus().length > 1) || (process.env.REDIS_URI !== undefined);\n\n if (!useRedisConfig) {\n return null;\n }\n\n let driver = currentDriver;\n let presence = currentPresence;\n const publicAddress = process.env.SUBDOMAIN + \".\" + process.env.SERVER_NAME + \"/\" + port;\n\n if (!driver) {\n try {\n const module = await RedisDriver;\n driver = new module.RedisDriver(process.env.REDIS_URI);\n } catch (e) {\n console.error(e);\n logger.warn(\"\");\n logger.warn(\"\u274C could not initialize RedisDriver.\");\n logger.warn(\"\uD83D\uDC49 npm install --save @colyseus/redis-driver\");\n logger.warn(\"\");\n }\n }\n\n if (!presence) {\n try {\n const module = await RedisPresence;\n presence = new module.RedisPresence(process.env.REDIS_URI);\n } catch (e) {\n console.error(e);\n logger.warn(\"\");\n logger.warn(\"\u274C could not initialize RedisPresence.\");\n logger.warn(\"\uD83D\uDC49 npm install --save @colyseus/redis-presence\");\n logger.warn(\"\");\n }\n }\n\n return { driver, presence, publicAddress };\n}\n\n/**\n * Check if a socket file is active and remove it if it's not.\n */\nfunction checkInactiveSocketFile(sockFilePath: string) {\n return new Promise((resolve, reject) => {\n const client = net.createConnection({ path: sockFilePath })\n .on('connect', () => {\n // socket file is active, close the connection\n client.end();\n throw new Error(`EADDRINUSE: Already listening on '${sockFilePath}'`);\n })\n .on('error', () => {\n // socket file is inactive, remove it\n fs.unlink(sockFilePath, () => resolve(true));\n });\n });\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": ["options"]
|
|
7
7
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@colyseus/tools",
|
|
3
|
-
"version": "0.17.
|
|
3
|
+
"version": "0.17.9",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Simplify the development and production settings for your Colyseus project.",
|
|
6
6
|
"input": "./src/index.ts",
|
|
@@ -49,16 +49,14 @@
|
|
|
49
49
|
"homepage": "https://colyseus.io",
|
|
50
50
|
"dependencies": {
|
|
51
51
|
"@pm2/io": "^6.0.1",
|
|
52
|
-
"cors": "^2.8.5",
|
|
53
52
|
"dotenv": ">=14.1.0",
|
|
54
53
|
"express": ">=4.16.0"
|
|
55
54
|
},
|
|
56
55
|
"devDependencies": {
|
|
57
|
-
"@types/cors": "^2.8.10",
|
|
58
56
|
"@types/dotenv": "^8.2.0",
|
|
59
57
|
"uwebsockets-express": "^1.1.10",
|
|
60
|
-
"@colyseus/core": "^0.17.11",
|
|
61
58
|
"@colyseus/bun-websockets": "^0.17.5",
|
|
59
|
+
"@colyseus/core": "^0.17.15",
|
|
62
60
|
"@colyseus/redis-driver": "^0.17.5",
|
|
63
61
|
"@colyseus/redis-presence": "^0.17.5",
|
|
64
62
|
"@colyseus/uwebsockets-transport": "^0.17.6",
|
package/src/index.ts
CHANGED
|
@@ -3,7 +3,6 @@ import os from 'os';
|
|
|
3
3
|
import fs from "fs";
|
|
4
4
|
import net from "net";
|
|
5
5
|
import http from 'http';
|
|
6
|
-
import cors from 'cors';
|
|
7
6
|
import express from 'express';
|
|
8
7
|
import {
|
|
9
8
|
type ServerOptions,
|
|
@@ -15,8 +14,6 @@ import {
|
|
|
15
14
|
matchMaker,
|
|
16
15
|
RegisteredHandler,
|
|
17
16
|
defineServer,
|
|
18
|
-
LocalDriver,
|
|
19
|
-
LocalPresence
|
|
20
17
|
} from '@colyseus/core';
|
|
21
18
|
import { WebSocketTransport } from '@colyseus/ws-transport';
|
|
22
19
|
|
|
@@ -122,22 +119,8 @@ export async function listen<
|
|
|
122
119
|
server = options;
|
|
123
120
|
|
|
124
121
|
// automatically configure for production under Colyseus Cloud
|
|
125
|
-
if
|
|
126
|
-
|
|
127
|
-
const isLocalDriver = matchMaker.driver instanceof LocalDriver;
|
|
128
|
-
const isLocalPresence = matchMaker.presence instanceof LocalPresence;
|
|
129
|
-
|
|
130
|
-
const cloudConfig = await getColyseusCloudConfig(
|
|
131
|
-
port,
|
|
132
|
-
isLocalDriver ? undefined : matchMaker.driver,
|
|
133
|
-
isLocalPresence ? undefined : matchMaker.presence,
|
|
134
|
-
);
|
|
135
|
-
|
|
136
|
-
// re-setup matchMaker with Redis driver/presence
|
|
137
|
-
if (cloudConfig && (isLocalDriver || isLocalPresence)) {
|
|
138
|
-
await matchMaker.setup(cloudConfig.presence, cloudConfig.driver, cloudConfig.publicAddress);
|
|
139
|
-
}
|
|
140
|
-
}
|
|
122
|
+
// if on Colyseus Cloud, the matchMaker should have been configured by the time we get here
|
|
123
|
+
// See @colyseus/core src/utils/Env.ts
|
|
141
124
|
|
|
142
125
|
} else {
|
|
143
126
|
server = await buildServerFromOptions<RoomTypes, Routes>(options, port);
|
|
@@ -150,14 +133,17 @@ export async function listen<
|
|
|
150
133
|
|
|
151
134
|
if (process.env.COLYSEUS_CLOUD !== undefined) {
|
|
152
135
|
// listening on socket
|
|
153
|
-
const socketPath
|
|
136
|
+
const socketPath = `/run/colyseus/${port}.sock`;
|
|
154
137
|
// const socketPath: any = `/tmp/${port}.sock`;
|
|
155
138
|
|
|
156
139
|
// check if .sock file is active
|
|
157
140
|
// (fixes "ADDRINUSE" issue when restarting the server)
|
|
158
141
|
await checkInactiveSocketFile(socketPath);
|
|
159
142
|
|
|
160
|
-
await server.listen(
|
|
143
|
+
await server.listen(
|
|
144
|
+
socketPath,
|
|
145
|
+
0 as any // workaround to allow using @colyseus/core's .listen() directly on Colyseus Cloud
|
|
146
|
+
);
|
|
161
147
|
|
|
162
148
|
} else {
|
|
163
149
|
// listening on port
|
|
@@ -237,18 +223,10 @@ export async function getTransport(options: ConfigOptions) {
|
|
|
237
223
|
}
|
|
238
224
|
|
|
239
225
|
if (app) {
|
|
240
|
-
// Enable CORS
|
|
241
|
-
app.use(cors({ origin: true, credentials: true, }));
|
|
242
|
-
|
|
243
226
|
if (options.initializeExpress) {
|
|
244
227
|
await options.initializeExpress(app);
|
|
245
228
|
}
|
|
246
229
|
|
|
247
|
-
// health check for load balancers
|
|
248
|
-
app.get("/__healthcheck", (req, res) => {
|
|
249
|
-
res.status(200).end();
|
|
250
|
-
});
|
|
251
|
-
|
|
252
230
|
if (options.displayLogs) {
|
|
253
231
|
logger.info("✅ Express initialized");
|
|
254
232
|
}
|
|
@@ -317,4 +295,4 @@ function checkInactiveSocketFile(sockFilePath: string) {
|
|
|
317
295
|
fs.unlink(sockFilePath, () => resolve(true));
|
|
318
296
|
});
|
|
319
297
|
});
|
|
320
|
-
}
|
|
298
|
+
}
|