@colyseus/tools 0.16.0-preview.2 → 0.16.0-preview.4

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/README.md CHANGED
@@ -7,19 +7,19 @@
7
7
  <a href="https://npmjs.com/package/colyseus">
8
8
  <img src="https://img.shields.io/npm/dm/colyseus.svg?style=for-the-badge&logo=data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAQAAAC1+jfqAAAABGdBTUEAALGPC/xhBQAAACBjSFJNAAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAAAAmJLR0QAAKqNIzIAAAAJcEhZcwAADsQAAA7EAZUrDhsAAAAHdElNRQfjAgETESWYxR33AAAAtElEQVQoz4WQMQrCQBRE38Z0QoTcwF4Qg1h4BO0sxGOk80iCtViksrIQRRBTewWxMI1mbELYjYu+4rPMDPtn12ChMT3gavb4US5Jym0tcBIta3oDHv4Gwmr7nC4QAxBrCdzM2q6XqUnm9m9r59h7Rc0n2pFv24k4ttGMUXW+sGELTJjSr7QDKuqLS6UKFChVWWuFkZw9Z2AAvAirKT+JTlppIRnd6XgaP4goefI2Shj++OnjB3tBmHYK8z9zAAAAJXRFWHRkYXRlOmNyZWF0ZQAyMDE5LTAyLTAxVDE4OjE3OjM3KzAxOjAwGQQixQAAACV0RVh0ZGF0ZTptb2RpZnkAMjAxOS0wMi0wMVQxODoxNzozNyswMTowMGhZmnkAAAAZdEVYdFNvZnR3YXJlAHd3dy5pbmtzY2FwZS5vcmeb7jwaAAAAAElFTkSuQmCC">
9
9
  </a>
10
- <a href="http://chat.colyseus.io">
11
- <img src="https://img.shields.io/discord/525739117951320081.svg?style=for-the-badge&colorB=7581dc&logo=discord&logoColor=white">
12
- </a>
13
10
  <a href="https://github.com/colyseus/colyseus/discussions" title="Discuss on Forum">
14
11
  <img src="https://img.shields.io/badge/discuss-on%20forum-brightgreen.svg?style=for-the-badge&colorB=0069b8&logo=data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAQAAAC1+jfqAAAABGdBTUEAALGPC/xhBQAAACBjSFJNAAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAAAAmJLR0QAAKqNIzIAAAAJcEhZcwAADsQAAA7EAZUrDhsAAAAHdElNRQfjAgETDROxCNUzAAABB0lEQVQoz4WRvyvEARjGP193CnWRH+dHQmGwKZtFGcSmxHAL400GN95ktIpV2dzlLzDJgsGgGNRdDAzoQueS/PgY3HXHyT3T+/Y87/s89UANBKXBdoZo5J6L4K1K5ZxHfnjnlQUf3bKvkgy57a0r9hS3cXfMO1kWJMza++tj3Ac7/LY343x1NA9cNmYMwnSS/SP8JVFuSJmr44iFqvtmpjhmhBCrOOazCesq6H4P3bPBjFoIBydOk2bUA17I080Es+wSZ51B4DIA2zgjSpYcEe44Js01G0XjRcCU+y4ZMrDeLmfc9EnVd5M/o0VMeu6nJZxWJivLmhyw1WHTvrr2b4+2OFqra+ALwouTMDcqmjMAAAAldEVYdGRhdGU6Y3JlYXRlADIwMTktMDItMDFUMTg6MTM6MTkrMDE6MDAC9f6fAAAAJXRFWHRkYXRlOm1vZGlmeQAyMDE5LTAyLTAxVDE4OjEzOjE5KzAxOjAwc6hGIwAAABl0RVh0U29mdHdhcmUAd3d3Lmlua3NjYXBlLm9yZ5vuPBoAAAAASUVORK5CYII=" alt="Discussion forum" />
15
12
  </a>
13
+ <a href="http://chat.colyseus.io">
14
+ <img src="https://img.shields.io/discord/525739117951320081.svg?style=for-the-badge&colorB=7581dc&logo=discord&logoColor=white">
15
+ </a>
16
16
  <h3>
17
17
  Multiplayer Framework for Node.js. <br /><a href="https://docs.colyseus.io/">View documentation</a>
18
18
  </h3>
19
19
  </div>
20
20
 
21
- Colyseus is an Authoritative Multiplayer Framework for Node.js, with SDKs
22
- available for the Web, Unity, Defold, Haxe, Cocos and Construct3. ([See official SDKs](https://docs.colyseus.io/client/))
21
+ Colyseus is an Authoritative Multiplayer Framework for Node.js, with clients
22
+ available for the Web, Unity3d, Defold, Haxe, and Cocos. ([See official clients](#%EF%B8%8F-official-client-integration))
23
23
 
24
24
  The project focuses on providing synchronizable data structures for realtime and
25
25
  turn-based games, matchmaking, and ease of usage both on the server-side and
package/build/index.d.ts CHANGED
@@ -16,5 +16,5 @@ export default function (options: ConfigOptions): ConfigOptions;
16
16
  * @param options Application options
17
17
  * @param port Port number to bind Colyseus + Express
18
18
  */
19
- export declare function listen(options: ConfigOptions, port?: number): Promise<Server>;
19
+ export declare function listen(options: ConfigOptions | Server, port?: number): Promise<Server>;
20
20
  export declare function getTransport(options: ConfigOptions): Promise<Transport>;
package/build/index.js CHANGED
@@ -34,10 +34,11 @@ __export(src_exports, {
34
34
  module.exports = __toCommonJS(src_exports);
35
35
  var import_loadenv = require("./loadenv.js");
36
36
  var import_os = __toESM(require("os"));
37
+ var import_fs = __toESM(require("fs"));
38
+ var import_net = __toESM(require("net"));
37
39
  var import_http = __toESM(require("http"));
38
40
  var import_cors = __toESM(require("cors"));
39
41
  var import_express = __toESM(require("express"));
40
- var import_node_os_utils = __toESM(require("node-os-utils"));
41
42
  var import_core = require("@colyseus/core");
42
43
  var import_ws_transport = require("@colyseus/ws-transport");
43
44
  let BunWebSockets = void 0;
@@ -64,13 +65,40 @@ function src_default(options) {
64
65
  return options;
65
66
  }
66
67
  async function listen(options, port = Number(process.env.PORT || 2567)) {
67
- const serverOptions = options.options || {};
68
- options.displayLogs = options.displayLogs ?? true;
69
68
  if (process.env.COLYSEUS_CLOUD !== void 0) {
70
69
  port = 2567;
71
70
  }
72
71
  const processNumber = Number(process.env.NODE_APP_INSTANCE || "0");
73
72
  port += processNumber;
73
+ let gameServer;
74
+ let displayLogs = true;
75
+ if (options instanceof import_core.Server) {
76
+ gameServer = options;
77
+ } else {
78
+ gameServer = await buildServerFromOptions(options, port);
79
+ displayLogs = options.displayLogs;
80
+ await options.initializeGameServer?.(gameServer);
81
+ await import_core.matchMaker.onReady;
82
+ await options.beforeListen?.();
83
+ }
84
+ if (process.env.COLYSEUS_CLOUD !== void 0) {
85
+ const socketPath = `/run/colyseus/${port}.sock`;
86
+ await checkInactiveSocketFile(socketPath);
87
+ await gameServer.listen(socketPath);
88
+ } else {
89
+ await gameServer.listen(port);
90
+ }
91
+ if (typeof process.send === "function") {
92
+ process.send("ready");
93
+ }
94
+ if (displayLogs) {
95
+ import_core.logger.info(`\u2694\uFE0F Listening on http://localhost:${port}`);
96
+ }
97
+ return gameServer;
98
+ }
99
+ async function buildServerFromOptions(options, port) {
100
+ const serverOptions = options.options || {};
101
+ options.displayLogs = options.displayLogs ?? true;
74
102
  if (process.env.COLYSEUS_CLOUD !== void 0) {
75
103
  const useRedisConfig = import_os.default.cpus().length > 1 || process.env.REDIS_URI !== void 0;
76
104
  if (!serverOptions.driver && useRedisConfig) {
@@ -103,25 +131,10 @@ async function listen(options, port = Number(process.env.PORT || 2567)) {
103
131
  }
104
132
  }
105
133
  const transport = await getTransport(options);
106
- const gameServer = new import_core.Server({
134
+ return new import_core.Server({
107
135
  ...serverOptions,
108
136
  transport
109
137
  });
110
- await options.initializeGameServer?.(gameServer);
111
- await import_core.matchMaker.onReady;
112
- await options.beforeListen?.();
113
- if (process.env.COLYSEUS_CLOUD !== void 0) {
114
- await gameServer.listen(`/run/colyseus/${port}.sock`);
115
- } else {
116
- await gameServer.listen(port);
117
- }
118
- if (typeof process.send === "function") {
119
- process.send("ready");
120
- }
121
- if (options.displayLogs) {
122
- import_core.logger.info(`\u2694\uFE0F Listening on http://localhost:${port}`);
123
- }
124
- return gameServer;
125
138
  }
126
139
  async function getTransport(options) {
127
140
  let transport;
@@ -147,31 +160,22 @@ async function getTransport(options) {
147
160
  app.get("/__healthcheck", (req, res) => {
148
161
  res.status(200).end();
149
162
  });
150
- app.get("/__cloudstats", async (req, res) => {
151
- if (process.env.CLOUD_SECRET && req.headers.authorization !== process.env.CLOUD_SECRET) {
152
- res.status(401).end();
153
- return;
154
- }
155
- const rooms = (await import_core.matchMaker.stats.fetchAll()).reduce((prev, curr) => {
156
- return prev + curr.roomCount;
157
- }, 0);
158
- const ccu = await import_core.matchMaker.stats.getGlobalCCU();
159
- const mem = await import_node_os_utils.default.mem.used();
160
- const cpu = await import_node_os_utils.default.cpu.usage() / 100;
161
- res.json({
162
- version: 1,
163
- mem: mem.usedMemMb / mem.totalMemMb,
164
- cpu,
165
- ccu,
166
- rooms
167
- });
168
- });
169
163
  if (options.displayLogs) {
170
164
  import_core.logger.info("\u2705 Express initialized");
171
165
  }
172
166
  }
173
167
  return transport;
174
168
  }
169
+ function checkInactiveSocketFile(sockFilePath) {
170
+ return new Promise((resolve, reject) => {
171
+ const client = import_net.default.createConnection({ path: sockFilePath }).on("connect", () => {
172
+ client.end();
173
+ throw new Error(`EADDRINUSE: Already listening on '${sockFilePath}'`);
174
+ }).on("error", () => {
175
+ import_fs.default.unlink(sockFilePath, () => resolve(true));
176
+ });
177
+ });
178
+ }
175
179
  // Annotate the CommonJS export names for ESM import in node:
176
180
  0 && (module.exports = {
177
181
  getTransport,
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../src/index.ts"],
4
- "sourcesContent": ["import './loadenv.js';\nimport os from 'os';\nimport http from 'http';\nimport cors from 'cors';\nimport express from 'express';\nimport osUtils from 'node-os-utils';\nimport { logger, Server, ServerOptions, Transport, matchMaker } from '@colyseus/core';\nimport { WebSocketTransport } from '@colyseus/ws-transport';\n\nlet BunWebSockets: any = undefined;\n\n// @ts-ignore\nimport('@colyseus/bun-websockets')\n .then((module) => BunWebSockets = module)\n .catch(() => { });\n\nexport interface ConfigOptions {\n options?: ServerOptions,\n displayLogs?: boolean,\n getId?: () => string,\n initializeTransport?: (options: any) => Transport,\n initializeExpress?: (app: express.Express) => void,\n initializeGameServer?: (app: Server) => void,\n beforeListen?: () => void,\n}\n\nconst ALLOWED_KEYS: { [key in keyof ConfigOptions]: string } = {\n 'displayLogs': \"boolean\",\n 'options': \"object\",\n 'getId': \"function\",\n 'initializeTransport': \"function\",\n 'initializeExpress': \"function\",\n 'initializeGameServer': \"function\",\n 'beforeListen': \"function\"\n};\n\nexport default function (options: ConfigOptions) {\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\n return options;\n}\n\n/**\n * Listen on your development environment\n * @param options Application options\n * @param port Port number to bind Colyseus + Express\n */\nexport async function listen(\n options: ConfigOptions,\n port: number = Number(process.env.PORT || 2567),\n) {\n const serverOptions = options.options || {};\n options.displayLogs = options.displayLogs ?? true;\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 // automatically configure for production under Colyseus Cloud\n if (process.env.COLYSEUS_CLOUD !== undefined) {\n // special configuration is required when using multiple processes\n const useRedisConfig = (os.cpus().length > 1) || (process.env.REDIS_URI !== undefined);\n\n if (!serverOptions.driver && useRedisConfig) {\n let RedisDriver: any = undefined;\n try {\n RedisDriver = require('@colyseus/redis-driver').RedisDriver;\n serverOptions.driver = new RedisDriver(process.env.REDIS_URI);\n } catch (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 (!serverOptions.presence && useRedisConfig) {\n let RedisPresence: any = undefined;\n try {\n RedisPresence = require('@colyseus/redis-presence').RedisPresence;\n serverOptions.presence = new RedisPresence(process.env.REDIS_URI);\n } catch (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 if (useRedisConfig) {\n // force \"publicAddress\" when more than 1 process is available\n serverOptions.publicAddress = process.env.SUBDOMAIN + \".\" + process.env.SERVER_NAME;\n\n // nginx is responsible for forwarding /{port}/ to this process\n serverOptions.publicAddress += \"/\" + port;\n }\n }\n\n const transport = await getTransport(options);\n const gameServer = new Server({\n ...serverOptions,\n transport,\n });\n await options.initializeGameServer?.(gameServer);\n await matchMaker.onReady;\n await options.beforeListen?.();\n\n if (process.env.COLYSEUS_CLOUD !== undefined) {\n // listening on socket\n // @ts-ignore\n await gameServer.listen(`/run/colyseus/${port}.sock`);\n\n } else {\n // listening on port\n await gameServer.listen(port);\n }\n\n // notify process manager (production)\n if (typeof(process.send) === \"function\") {\n process.send('ready');\n }\n\n if (options.displayLogs) {\n logger.info(`\u2694\uFE0F Listening on http://localhost:${port}`);\n }\n return gameServer;\n}\n\n\nexport async function getTransport(options: ConfigOptions) {\n let transport: Transport;\n\n if (!options.initializeTransport) {\n if (BunWebSockets !== undefined) {\n // @colyseus/bun-websockets\n options.initializeTransport = (options: any) => new BunWebSockets.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 // Enable JSON parsing.\n app.use(express.json());\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 app.get(\"/__cloudstats\", async (req, res) => {\n if (\n process.env.CLOUD_SECRET &&\n req.headers.authorization !== process.env.CLOUD_SECRET\n ) {\n res.status(401).end();\n return;\n }\n\n // count rooms per process\n const rooms = (await matchMaker.stats.fetchAll()).reduce((prev, curr) => {\n return prev + curr.roomCount;\n }, 0);\n\n const ccu = await matchMaker.stats.getGlobalCCU();\n const mem = await osUtils.mem.used();\n const cpu = (await osUtils.cpu.usage()) / 100;\n\n res.json({\n version: 1,\n mem: (mem.usedMemMb / mem.totalMemMb),\n cpu,\n ccu,\n rooms,\n });\n });\n\n if (options.displayLogs) {\n logger.info(\"\u2705 Express initialized\");\n }\n }\n\n return transport;\n}\n"],
5
- "mappings": "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",
6
- "names": ["module", "os", "options", "express", "http", "cors", "osUtils"]
4
+ "sourcesContent": ["import './loadenv.js';\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 { logger, Server, ServerOptions, Transport, matchMaker } from '@colyseus/core';\nimport { WebSocketTransport } from '@colyseus/ws-transport';\n\nlet BunWebSockets: any = undefined;\n\n// @ts-ignore\nimport('@colyseus/bun-websockets')\n .then((module) => BunWebSockets = module)\n .catch(() => { });\n\nexport interface ConfigOptions {\n options?: ServerOptions,\n displayLogs?: boolean,\n getId?: () => string,\n initializeTransport?: (options: any) => Transport,\n initializeExpress?: (app: express.Express) => void,\n initializeGameServer?: (app: Server) => void,\n beforeListen?: () => void,\n}\n\nconst ALLOWED_KEYS: { [key in keyof ConfigOptions]: string } = {\n 'displayLogs': \"boolean\",\n 'options': \"object\",\n 'getId': \"function\",\n 'initializeTransport': \"function\",\n 'initializeExpress': \"function\",\n 'initializeGameServer': \"function\",\n 'beforeListen': \"function\"\n};\n\nexport default function (options: ConfigOptions) {\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\n return options;\n}\n\n/**\n * Listen on your development environment\n * @param options Application options\n * @param port Port number to bind Colyseus + Express\n */\nexport async function listen(\n options: ConfigOptions | Server,\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 gameServer: Server;\n let displayLogs = true;\n\n if (options instanceof Server) {\n gameServer = options;\n\n } else {\n gameServer = await buildServerFromOptions(options, port);\n displayLogs = options.displayLogs;\n\n await options.initializeGameServer?.(gameServer);\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\n // check if .sock file is active\n // (fixes \"ADDRINUSE\" issue when restarting the server)\n await checkInactiveSocketFile(socketPath);\n\n await gameServer.listen(socketPath);\n\n } else {\n // listening on port\n await gameServer.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 gameServer;\n}\n\nasync function buildServerFromOptions(options: ConfigOptions, 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\n // special configuration is required when using multiple processes\n const useRedisConfig = (os.cpus().length > 1) || (process.env.REDIS_URI !== undefined);\n\n if (!serverOptions.driver && useRedisConfig) {\n let RedisDriver: any = undefined;\n try {\n RedisDriver = require('@colyseus/redis-driver').RedisDriver;\n serverOptions.driver = new RedisDriver(process.env.REDIS_URI);\n } catch (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 (!serverOptions.presence && useRedisConfig) {\n let RedisPresence: any = undefined;\n try {\n RedisPresence = require('@colyseus/redis-presence').RedisPresence;\n serverOptions.presence = new RedisPresence(process.env.REDIS_URI);\n } catch (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 if (useRedisConfig) {\n // force \"publicAddress\" when more than 1 process is available\n serverOptions.publicAddress = process.env.SUBDOMAIN + \".\" + process.env.SERVER_NAME;\n\n // nginx is responsible for forwarding /{port}/ to this process\n serverOptions.publicAddress += \"/\" + port;\n }\n }\n\n const transport = await getTransport(options);\n return new Server({\n ...serverOptions,\n transport,\n });\n}\n\nexport async function getTransport(options: ConfigOptions) {\n let transport: Transport;\n\n if (!options.initializeTransport) {\n if (BunWebSockets !== undefined) {\n // @colyseus/bun-websockets\n options.initializeTransport = (options: any) => new BunWebSockets.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 // Enable JSON parsing.\n app.use(express.json());\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 * 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": "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",
6
+ "names": ["module", "os", "options", "express", "http", "cors", "net", "fs"]
7
7
  }
package/build/index.mjs CHANGED
@@ -8,10 +8,11 @@ var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require
8
8
  // packages/tools/src/index.ts
9
9
  import "./loadenv.mjs";
10
10
  import os from "os";
11
+ import fs from "fs";
12
+ import net from "net";
11
13
  import http from "http";
12
14
  import cors from "cors";
13
15
  import express from "express";
14
- import osUtils from "node-os-utils";
15
16
  import { logger, Server, matchMaker } from "@colyseus/core";
16
17
  import { WebSocketTransport } from "@colyseus/ws-transport";
17
18
  var BunWebSockets = void 0;
@@ -38,13 +39,40 @@ function src_default(options) {
38
39
  return options;
39
40
  }
40
41
  async function listen(options, port = Number(process.env.PORT || 2567)) {
41
- const serverOptions = options.options || {};
42
- options.displayLogs = options.displayLogs ?? true;
43
42
  if (process.env.COLYSEUS_CLOUD !== void 0) {
44
43
  port = 2567;
45
44
  }
46
45
  const processNumber = Number(process.env.NODE_APP_INSTANCE || "0");
47
46
  port += processNumber;
47
+ let gameServer;
48
+ let displayLogs = true;
49
+ if (options instanceof Server) {
50
+ gameServer = options;
51
+ } else {
52
+ gameServer = await buildServerFromOptions(options, port);
53
+ displayLogs = options.displayLogs;
54
+ await options.initializeGameServer?.(gameServer);
55
+ await matchMaker.onReady;
56
+ await options.beforeListen?.();
57
+ }
58
+ if (process.env.COLYSEUS_CLOUD !== void 0) {
59
+ const socketPath = `/run/colyseus/${port}.sock`;
60
+ await checkInactiveSocketFile(socketPath);
61
+ await gameServer.listen(socketPath);
62
+ } else {
63
+ await gameServer.listen(port);
64
+ }
65
+ if (typeof process.send === "function") {
66
+ process.send("ready");
67
+ }
68
+ if (displayLogs) {
69
+ logger.info(`\u2694\uFE0F Listening on http://localhost:${port}`);
70
+ }
71
+ return gameServer;
72
+ }
73
+ async function buildServerFromOptions(options, port) {
74
+ const serverOptions = options.options || {};
75
+ options.displayLogs = options.displayLogs ?? true;
48
76
  if (process.env.COLYSEUS_CLOUD !== void 0) {
49
77
  const useRedisConfig = os.cpus().length > 1 || process.env.REDIS_URI !== void 0;
50
78
  if (!serverOptions.driver && useRedisConfig) {
@@ -77,25 +105,10 @@ async function listen(options, port = Number(process.env.PORT || 2567)) {
77
105
  }
78
106
  }
79
107
  const transport = await getTransport(options);
80
- const gameServer = new Server({
108
+ return new Server({
81
109
  ...serverOptions,
82
110
  transport
83
111
  });
84
- await options.initializeGameServer?.(gameServer);
85
- await matchMaker.onReady;
86
- await options.beforeListen?.();
87
- if (process.env.COLYSEUS_CLOUD !== void 0) {
88
- await gameServer.listen(`/run/colyseus/${port}.sock`);
89
- } else {
90
- await gameServer.listen(port);
91
- }
92
- if (typeof process.send === "function") {
93
- process.send("ready");
94
- }
95
- if (options.displayLogs) {
96
- logger.info(`\u2694\uFE0F Listening on http://localhost:${port}`);
97
- }
98
- return gameServer;
99
112
  }
100
113
  async function getTransport(options) {
101
114
  let transport;
@@ -121,31 +134,22 @@ async function getTransport(options) {
121
134
  app.get("/__healthcheck", (req, res) => {
122
135
  res.status(200).end();
123
136
  });
124
- app.get("/__cloudstats", async (req, res) => {
125
- if (process.env.CLOUD_SECRET && req.headers.authorization !== process.env.CLOUD_SECRET) {
126
- res.status(401).end();
127
- return;
128
- }
129
- const rooms = (await matchMaker.stats.fetchAll()).reduce((prev, curr) => {
130
- return prev + curr.roomCount;
131
- }, 0);
132
- const ccu = await matchMaker.stats.getGlobalCCU();
133
- const mem = await osUtils.mem.used();
134
- const cpu = await osUtils.cpu.usage() / 100;
135
- res.json({
136
- version: 1,
137
- mem: mem.usedMemMb / mem.totalMemMb,
138
- cpu,
139
- ccu,
140
- rooms
141
- });
142
- });
143
137
  if (options.displayLogs) {
144
138
  logger.info("\u2705 Express initialized");
145
139
  }
146
140
  }
147
141
  return transport;
148
142
  }
143
+ function checkInactiveSocketFile(sockFilePath) {
144
+ return new Promise((resolve, reject) => {
145
+ const client = net.createConnection({ path: sockFilePath }).on("connect", () => {
146
+ client.end();
147
+ throw new Error(`EADDRINUSE: Already listening on '${sockFilePath}'`);
148
+ }).on("error", () => {
149
+ fs.unlink(sockFilePath, () => resolve(true));
150
+ });
151
+ });
152
+ }
149
153
  export {
150
154
  src_default as default,
151
155
  getTransport,
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../src/index.ts"],
4
- "sourcesContent": ["import './loadenv.js';\nimport os from 'os';\nimport http from 'http';\nimport cors from 'cors';\nimport express from 'express';\nimport osUtils from 'node-os-utils';\nimport { logger, Server, ServerOptions, Transport, matchMaker } from '@colyseus/core';\nimport { WebSocketTransport } from '@colyseus/ws-transport';\n\nlet BunWebSockets: any = undefined;\n\n// @ts-ignore\nimport('@colyseus/bun-websockets')\n .then((module) => BunWebSockets = module)\n .catch(() => { });\n\nexport interface ConfigOptions {\n options?: ServerOptions,\n displayLogs?: boolean,\n getId?: () => string,\n initializeTransport?: (options: any) => Transport,\n initializeExpress?: (app: express.Express) => void,\n initializeGameServer?: (app: Server) => void,\n beforeListen?: () => void,\n}\n\nconst ALLOWED_KEYS: { [key in keyof ConfigOptions]: string } = {\n 'displayLogs': \"boolean\",\n 'options': \"object\",\n 'getId': \"function\",\n 'initializeTransport': \"function\",\n 'initializeExpress': \"function\",\n 'initializeGameServer': \"function\",\n 'beforeListen': \"function\"\n};\n\nexport default function (options: ConfigOptions) {\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\n return options;\n}\n\n/**\n * Listen on your development environment\n * @param options Application options\n * @param port Port number to bind Colyseus + Express\n */\nexport async function listen(\n options: ConfigOptions,\n port: number = Number(process.env.PORT || 2567),\n) {\n const serverOptions = options.options || {};\n options.displayLogs = options.displayLogs ?? true;\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 // automatically configure for production under Colyseus Cloud\n if (process.env.COLYSEUS_CLOUD !== undefined) {\n // special configuration is required when using multiple processes\n const useRedisConfig = (os.cpus().length > 1) || (process.env.REDIS_URI !== undefined);\n\n if (!serverOptions.driver && useRedisConfig) {\n let RedisDriver: any = undefined;\n try {\n RedisDriver = require('@colyseus/redis-driver').RedisDriver;\n serverOptions.driver = new RedisDriver(process.env.REDIS_URI);\n } catch (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 (!serverOptions.presence && useRedisConfig) {\n let RedisPresence: any = undefined;\n try {\n RedisPresence = require('@colyseus/redis-presence').RedisPresence;\n serverOptions.presence = new RedisPresence(process.env.REDIS_URI);\n } catch (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 if (useRedisConfig) {\n // force \"publicAddress\" when more than 1 process is available\n serverOptions.publicAddress = process.env.SUBDOMAIN + \".\" + process.env.SERVER_NAME;\n\n // nginx is responsible for forwarding /{port}/ to this process\n serverOptions.publicAddress += \"/\" + port;\n }\n }\n\n const transport = await getTransport(options);\n const gameServer = new Server({\n ...serverOptions,\n transport,\n });\n await options.initializeGameServer?.(gameServer);\n await matchMaker.onReady;\n await options.beforeListen?.();\n\n if (process.env.COLYSEUS_CLOUD !== undefined) {\n // listening on socket\n // @ts-ignore\n await gameServer.listen(`/run/colyseus/${port}.sock`);\n\n } else {\n // listening on port\n await gameServer.listen(port);\n }\n\n // notify process manager (production)\n if (typeof(process.send) === \"function\") {\n process.send('ready');\n }\n\n if (options.displayLogs) {\n logger.info(`\u2694\uFE0F Listening on http://localhost:${port}`);\n }\n return gameServer;\n}\n\n\nexport async function getTransport(options: ConfigOptions) {\n let transport: Transport;\n\n if (!options.initializeTransport) {\n if (BunWebSockets !== undefined) {\n // @colyseus/bun-websockets\n options.initializeTransport = (options: any) => new BunWebSockets.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 // Enable JSON parsing.\n app.use(express.json());\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 app.get(\"/__cloudstats\", async (req, res) => {\n if (\n process.env.CLOUD_SECRET &&\n req.headers.authorization !== process.env.CLOUD_SECRET\n ) {\n res.status(401).end();\n return;\n }\n\n // count rooms per process\n const rooms = (await matchMaker.stats.fetchAll()).reduce((prev, curr) => {\n return prev + curr.roomCount;\n }, 0);\n\n const ccu = await matchMaker.stats.getGlobalCCU();\n const mem = await osUtils.mem.used();\n const cpu = (await osUtils.cpu.usage()) / 100;\n\n res.json({\n version: 1,\n mem: (mem.usedMemMb / mem.totalMemMb),\n cpu,\n ccu,\n rooms,\n });\n });\n\n if (options.displayLogs) {\n logger.info(\"\u2705 Express initialized\");\n }\n }\n\n return transport;\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["import './loadenv.js';\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 { logger, Server, ServerOptions, Transport, matchMaker } from '@colyseus/core';\nimport { WebSocketTransport } from '@colyseus/ws-transport';\n\nlet BunWebSockets: any = undefined;\n\n// @ts-ignore\nimport('@colyseus/bun-websockets')\n .then((module) => BunWebSockets = module)\n .catch(() => { });\n\nexport interface ConfigOptions {\n options?: ServerOptions,\n displayLogs?: boolean,\n getId?: () => string,\n initializeTransport?: (options: any) => Transport,\n initializeExpress?: (app: express.Express) => void,\n initializeGameServer?: (app: Server) => void,\n beforeListen?: () => void,\n}\n\nconst ALLOWED_KEYS: { [key in keyof ConfigOptions]: string } = {\n 'displayLogs': \"boolean\",\n 'options': \"object\",\n 'getId': \"function\",\n 'initializeTransport': \"function\",\n 'initializeExpress': \"function\",\n 'initializeGameServer': \"function\",\n 'beforeListen': \"function\"\n};\n\nexport default function (options: ConfigOptions) {\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\n return options;\n}\n\n/**\n * Listen on your development environment\n * @param options Application options\n * @param port Port number to bind Colyseus + Express\n */\nexport async function listen(\n options: ConfigOptions | Server,\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 gameServer: Server;\n let displayLogs = true;\n\n if (options instanceof Server) {\n gameServer = options;\n\n } else {\n gameServer = await buildServerFromOptions(options, port);\n displayLogs = options.displayLogs;\n\n await options.initializeGameServer?.(gameServer);\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\n // check if .sock file is active\n // (fixes \"ADDRINUSE\" issue when restarting the server)\n await checkInactiveSocketFile(socketPath);\n\n await gameServer.listen(socketPath);\n\n } else {\n // listening on port\n await gameServer.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 gameServer;\n}\n\nasync function buildServerFromOptions(options: ConfigOptions, 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\n // special configuration is required when using multiple processes\n const useRedisConfig = (os.cpus().length > 1) || (process.env.REDIS_URI !== undefined);\n\n if (!serverOptions.driver && useRedisConfig) {\n let RedisDriver: any = undefined;\n try {\n RedisDriver = require('@colyseus/redis-driver').RedisDriver;\n serverOptions.driver = new RedisDriver(process.env.REDIS_URI);\n } catch (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 (!serverOptions.presence && useRedisConfig) {\n let RedisPresence: any = undefined;\n try {\n RedisPresence = require('@colyseus/redis-presence').RedisPresence;\n serverOptions.presence = new RedisPresence(process.env.REDIS_URI);\n } catch (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 if (useRedisConfig) {\n // force \"publicAddress\" when more than 1 process is available\n serverOptions.publicAddress = process.env.SUBDOMAIN + \".\" + process.env.SERVER_NAME;\n\n // nginx is responsible for forwarding /{port}/ to this process\n serverOptions.publicAddress += \"/\" + port;\n }\n }\n\n const transport = await getTransport(options);\n return new Server({\n ...serverOptions,\n transport,\n });\n}\n\nexport async function getTransport(options: ConfigOptions) {\n let transport: Transport;\n\n if (!options.initializeTransport) {\n if (BunWebSockets !== undefined) {\n // @colyseus/bun-websockets\n options.initializeTransport = (options: any) => new BunWebSockets.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 // Enable JSON parsing.\n app.use(express.json());\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 * 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": "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",
6
6
  "names": ["options"]
7
7
  }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@colyseus/tools",
3
- "version": "0.16.0-preview.2",
4
- "description": "Colyseus Tools for Production",
3
+ "version": "0.16.0-preview.4",
4
+ "description": "Simplify the development and production settings for your Colyseus project.",
5
5
  "input": "./src/index.ts",
6
6
  "main": "./build/index.js",
7
7
  "module": "./build/index.mjs",
@@ -14,7 +14,8 @@
14
14
  },
15
15
  "bin": {
16
16
  "colyseus-system-boot": "system-boot.js",
17
- "colyseus-post-deploy": "post-deploy.js"
17
+ "colyseus-post-deploy": "post-deploy.js",
18
+ "colyseus-report-stats": "report-stats.js"
18
19
  },
19
20
  "repository": {
20
21
  "type": "git",
@@ -31,29 +32,43 @@
31
32
  "url": "https://github.com/colyseus/colyseus/issues"
32
33
  },
33
34
  "files": [
35
+ "pm2",
34
36
  "html",
35
37
  "build",
36
38
  "LICENSE",
37
39
  "README.md"
38
40
  ],
39
- "homepage": "https:/colyseus.io",
41
+ "homepage": "https://colyseus.io",
42
+ "dependencies": {
43
+ "@pm2/io": "^6.0.1",
44
+ "cors": "^2.8.5",
45
+ "dotenv": "^8.2.0",
46
+ "express": "^4.16.2"
47
+ },
40
48
  "devDependencies": {
41
49
  "@types/cors": "^2.8.10",
42
50
  "@types/dotenv": "^8.2.0",
43
- "uwebsockets-express": "^1.1.10"
51
+ "uwebsockets-express": "^1.1.10",
52
+ "@colyseus/core": "^0.16.0-preview.36",
53
+ "@colyseus/ws-transport": "^0.16.0-preview.8",
54
+ "@colyseus/uwebsockets-transport": "^0.16.0-preview.13"
44
55
  },
45
- "dependencies": {
46
- "node-os-utils": "^1.3.7",
47
- "cors": "^2.8.5",
48
- "dotenv": "^8.2.0",
49
- "express": "^4.16.2",
50
- "@colyseus/core": "^0.16.0-preview.30",
51
- "@colyseus/ws-transport": "^0.16.0-preview.7"
56
+ "peerDependencies": {
57
+ "@colyseus/core": "0.15.x",
58
+ "@colyseus/ws-transport": "0.15.x"
52
59
  },
53
60
  "publishConfig": {
54
61
  "access": "public"
55
62
  },
63
+ "apps": [
64
+ {
65
+ "merge_logs": true,
66
+ "max_memory_restart": "256M",
67
+ "script": "./pm2/post-deploy-agent.js",
68
+ "instance_var": "INSTANCE_ID"
69
+ }
70
+ ],
56
71
  "scripts": {
57
- "start": "ts-node-dev example/app.ts"
72
+ "start": "tsx example/app.ts"
58
73
  }
59
74
  }