@colyseus/tools 0.16.7 → 0.16.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/loadenv.js +5 -1
- package/build/loadenv.js.map +2 -2
- package/build/loadenv.mjs +5 -1
- package/build/loadenv.mjs.map +2 -2
- package/package.json +3 -3
- package/system-boot.js +31 -22
package/build/loadenv.js
CHANGED
|
@@ -23,8 +23,12 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
23
23
|
var import_fs = __toESM(require("fs"));
|
|
24
24
|
var import_path = __toESM(require("path"));
|
|
25
25
|
var import_dotenv = __toESM(require("dotenv"));
|
|
26
|
+
function getEnvFromArgv() {
|
|
27
|
+
const envIndex = process.argv.indexOf("--env");
|
|
28
|
+
return envIndex !== -1 ? process.argv[envIndex + 1] : void 0;
|
|
29
|
+
}
|
|
26
30
|
function getNodeEnv() {
|
|
27
|
-
return process.env.NODE_ENV || "development";
|
|
31
|
+
return process.env.NODE_ENV || getEnvFromArgv() || "development";
|
|
28
32
|
}
|
|
29
33
|
function getRegion() {
|
|
30
34
|
return (process.env.REGION || "unknown").toLowerCase();
|
package/build/loadenv.js.map
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../src/loadenv.ts"],
|
|
4
|
-
"sourcesContent": ["import fs from 'fs';\nimport path from 'path';\nimport dotenv from 'dotenv';\n\nfunction getNodeEnv() {\n return process.env.NODE_ENV || \"development\";\n}\n\nfunction getRegion() {\n // EU, NA, AS, AF, AU, SA, UNKNOWN\n return (process.env.REGION || \"unknown\").toLowerCase();\n}\n\nfunction loadEnvFile(envFileOptions: string[], log: 'none' | 'success' | 'both' = 'none') {\n const envPaths = [];\n envFileOptions.forEach((envFilename) => {\n envPaths.push(path.resolve(path.dirname(require?.main?.filename || process.cwd()), \"..\", envFilename));\n envPaths.push(path.resolve(process.cwd(), envFilename));\n });\n\n // return the first .env path found\n const envPath = envPaths.find((envPath) => fs.existsSync(envPath));\n\n if (envPath) {\n dotenv.config({ path: envPath });\n\n if (log !== \"none\") {\n console.info(`\u2705 ${path.basename(envPath)} loaded.`);\n }\n\n } else if (log === \"both\") {\n console.info(`\u2139\uFE0F optional .env file not found: ${envFileOptions.join(\", \")}`);\n }\n}\n\n// load .env.cloud defined on admin panel\nif (process.env.COLYSEUS_CLOUD !== undefined) {\n loadEnvFile([`.env.cloud`]);\n}\n\n// (overrides previous env configs)\nloadEnvFile([`.env.${getNodeEnv()}`, `.env`], 'both');\n\nif (process.env.REGION !== undefined) {\n loadEnvFile([`.env.${getRegion()}.${getNodeEnv()}`], 'success');\n}"],
|
|
5
|
-
"mappings": ";;;;;;;;;;;;;;;;;;;;;;AAAA,gBAAe;AACf,kBAAiB;AACjB,oBAAmB;AAEnB,SAAS,aAAa;AACpB,SAAO,QAAQ,IAAI,YAAY;
|
|
4
|
+
"sourcesContent": ["import fs from 'fs';\nimport path from 'path';\nimport dotenv from 'dotenv';\n\nfunction getEnvFromArgv() {\n const envIndex = process.argv.indexOf(\"--env\");\n return (envIndex !== -1) ? process.argv[envIndex + 1] : undefined;\n}\n\nfunction getNodeEnv() {\n return process.env.NODE_ENV || getEnvFromArgv() || \"development\";\n}\n\nfunction getRegion() {\n // EU, NA, AS, AF, AU, SA, UNKNOWN\n return (process.env.REGION || \"unknown\").toLowerCase();\n}\n\nfunction loadEnvFile(envFileOptions: string[], log: 'none' | 'success' | 'both' = 'none') {\n const envPaths = [];\n envFileOptions.forEach((envFilename) => {\n envPaths.push(path.resolve(path.dirname(require?.main?.filename || process.cwd()), \"..\", envFilename));\n envPaths.push(path.resolve(process.cwd(), envFilename));\n });\n\n // return the first .env path found\n const envPath = envPaths.find((envPath) => fs.existsSync(envPath));\n\n if (envPath) {\n dotenv.config({ path: envPath });\n\n if (log !== \"none\") {\n console.info(`\u2705 ${path.basename(envPath)} loaded.`);\n }\n\n } else if (log === \"both\") {\n console.info(`\u2139\uFE0F optional .env file not found: ${envFileOptions.join(\", \")}`);\n }\n}\n\n// load .env.cloud defined on admin panel\nif (process.env.COLYSEUS_CLOUD !== undefined) {\n loadEnvFile([`.env.cloud`]);\n}\n\n// (overrides previous env configs)\nloadEnvFile([`.env.${getNodeEnv()}`, `.env`], 'both');\n\nif (process.env.REGION !== undefined) {\n loadEnvFile([`.env.${getRegion()}.${getNodeEnv()}`], 'success');\n}"],
|
|
5
|
+
"mappings": ";;;;;;;;;;;;;;;;;;;;;;AAAA,gBAAe;AACf,kBAAiB;AACjB,oBAAmB;AAEnB,SAAS,iBAAiB;AACxB,QAAM,WAAW,QAAQ,KAAK,QAAQ,OAAO;AAC7C,SAAQ,aAAa,KAAM,QAAQ,KAAK,WAAW,CAAC,IAAI;AAC1D;AAEA,SAAS,aAAa;AACpB,SAAO,QAAQ,IAAI,YAAY,eAAe,KAAK;AACrD;AAEA,SAAS,YAAY;AAEnB,UAAQ,QAAQ,IAAI,UAAU,WAAW,YAAY;AACvD;AAEA,SAAS,YAAY,gBAA0B,MAAoC,QAAQ;AACvF,QAAM,WAAW,CAAC;AAClB,iBAAe,QAAQ,CAAC,gBAAgB;AACtC,aAAS,KAAK,YAAAA,QAAK,QAAQ,YAAAA,QAAK,QAAQ,SAAS,MAAM,YAAY,QAAQ,IAAI,CAAC,GAAG,MAAM,WAAW,CAAC;AACrG,aAAS,KAAK,YAAAA,QAAK,QAAQ,QAAQ,IAAI,GAAG,WAAW,CAAC;AAAA,EACxD,CAAC;AAGD,QAAM,UAAU,SAAS,KAAK,CAACC,aAAY,UAAAC,QAAG,WAAWD,QAAO,CAAC;AAEjE,MAAI,SAAS;AACT,kBAAAE,QAAO,OAAO,EAAE,MAAM,QAAQ,CAAC;AAE/B,QAAI,QAAQ,QAAQ;AAChB,cAAQ,KAAK,UAAK,YAAAH,QAAK,SAAS,OAAO,CAAC,UAAU;AAAA,IACtD;AAAA,EAEJ,WAAW,QAAQ,QAAQ;AACvB,YAAQ,KAAK,+CAAqC,eAAe,KAAK,IAAI,CAAC,EAAE;AAAA,EACjF;AACJ;AAGA,IAAI,QAAQ,IAAI,mBAAmB,QAAW;AAC1C,cAAY,CAAC,YAAY,CAAC;AAC9B;AAGA,YAAY,CAAC,QAAQ,WAAW,CAAC,IAAI,MAAM,GAAG,MAAM;AAEpD,IAAI,QAAQ,IAAI,WAAW,QAAW;AACpC,cAAY,CAAC,QAAQ,UAAU,CAAC,IAAI,WAAW,CAAC,EAAE,GAAG,SAAS;AAChE;",
|
|
6
6
|
"names": ["path", "envPath", "fs", "dotenv"]
|
|
7
7
|
}
|
package/build/loadenv.mjs
CHANGED
|
@@ -9,8 +9,12 @@ var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require
|
|
|
9
9
|
import fs from "fs";
|
|
10
10
|
import path from "path";
|
|
11
11
|
import dotenv from "dotenv";
|
|
12
|
+
function getEnvFromArgv() {
|
|
13
|
+
const envIndex = process.argv.indexOf("--env");
|
|
14
|
+
return envIndex !== -1 ? process.argv[envIndex + 1] : void 0;
|
|
15
|
+
}
|
|
12
16
|
function getNodeEnv() {
|
|
13
|
-
return process.env.NODE_ENV || "development";
|
|
17
|
+
return process.env.NODE_ENV || getEnvFromArgv() || "development";
|
|
14
18
|
}
|
|
15
19
|
function getRegion() {
|
|
16
20
|
return (process.env.REGION || "unknown").toLowerCase();
|
package/build/loadenv.mjs.map
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../src/loadenv.ts"],
|
|
4
|
-
"sourcesContent": ["import fs from 'fs';\nimport path from 'path';\nimport dotenv from 'dotenv';\n\nfunction getNodeEnv() {\n return process.env.NODE_ENV || \"development\";\n}\n\nfunction getRegion() {\n // EU, NA, AS, AF, AU, SA, UNKNOWN\n return (process.env.REGION || \"unknown\").toLowerCase();\n}\n\nfunction loadEnvFile(envFileOptions: string[], log: 'none' | 'success' | 'both' = 'none') {\n const envPaths = [];\n envFileOptions.forEach((envFilename) => {\n envPaths.push(path.resolve(path.dirname(require?.main?.filename || process.cwd()), \"..\", envFilename));\n envPaths.push(path.resolve(process.cwd(), envFilename));\n });\n\n // return the first .env path found\n const envPath = envPaths.find((envPath) => fs.existsSync(envPath));\n\n if (envPath) {\n dotenv.config({ path: envPath });\n\n if (log !== \"none\") {\n console.info(`\u2705 ${path.basename(envPath)} loaded.`);\n }\n\n } else if (log === \"both\") {\n console.info(`\u2139\uFE0F optional .env file not found: ${envFileOptions.join(\", \")}`);\n }\n}\n\n// load .env.cloud defined on admin panel\nif (process.env.COLYSEUS_CLOUD !== undefined) {\n loadEnvFile([`.env.cloud`]);\n}\n\n// (overrides previous env configs)\nloadEnvFile([`.env.${getNodeEnv()}`, `.env`], 'both');\n\nif (process.env.REGION !== undefined) {\n loadEnvFile([`.env.${getRegion()}.${getNodeEnv()}`], 'success');\n}"],
|
|
5
|
-
"mappings": ";;;;;;;;AAAA,OAAO,QAAQ;AACf,OAAO,UAAU;AACjB,OAAO,YAAY;AAEnB,SAAS,aAAa;AACpB,SAAO,QAAQ,IAAI,YAAY;
|
|
4
|
+
"sourcesContent": ["import fs from 'fs';\nimport path from 'path';\nimport dotenv from 'dotenv';\n\nfunction getEnvFromArgv() {\n const envIndex = process.argv.indexOf(\"--env\");\n return (envIndex !== -1) ? process.argv[envIndex + 1] : undefined;\n}\n\nfunction getNodeEnv() {\n return process.env.NODE_ENV || getEnvFromArgv() || \"development\";\n}\n\nfunction getRegion() {\n // EU, NA, AS, AF, AU, SA, UNKNOWN\n return (process.env.REGION || \"unknown\").toLowerCase();\n}\n\nfunction loadEnvFile(envFileOptions: string[], log: 'none' | 'success' | 'both' = 'none') {\n const envPaths = [];\n envFileOptions.forEach((envFilename) => {\n envPaths.push(path.resolve(path.dirname(require?.main?.filename || process.cwd()), \"..\", envFilename));\n envPaths.push(path.resolve(process.cwd(), envFilename));\n });\n\n // return the first .env path found\n const envPath = envPaths.find((envPath) => fs.existsSync(envPath));\n\n if (envPath) {\n dotenv.config({ path: envPath });\n\n if (log !== \"none\") {\n console.info(`\u2705 ${path.basename(envPath)} loaded.`);\n }\n\n } else if (log === \"both\") {\n console.info(`\u2139\uFE0F optional .env file not found: ${envFileOptions.join(\", \")}`);\n }\n}\n\n// load .env.cloud defined on admin panel\nif (process.env.COLYSEUS_CLOUD !== undefined) {\n loadEnvFile([`.env.cloud`]);\n}\n\n// (overrides previous env configs)\nloadEnvFile([`.env.${getNodeEnv()}`, `.env`], 'both');\n\nif (process.env.REGION !== undefined) {\n loadEnvFile([`.env.${getRegion()}.${getNodeEnv()}`], 'success');\n}"],
|
|
5
|
+
"mappings": ";;;;;;;;AAAA,OAAO,QAAQ;AACf,OAAO,UAAU;AACjB,OAAO,YAAY;AAEnB,SAAS,iBAAiB;AACxB,QAAM,WAAW,QAAQ,KAAK,QAAQ,OAAO;AAC7C,SAAQ,aAAa,KAAM,QAAQ,KAAK,WAAW,CAAC,IAAI;AAC1D;AAEA,SAAS,aAAa;AACpB,SAAO,QAAQ,IAAI,YAAY,eAAe,KAAK;AACrD;AAEA,SAAS,YAAY;AAEnB,UAAQ,QAAQ,IAAI,UAAU,WAAW,YAAY;AACvD;AAEA,SAAS,YAAY,gBAA0B,MAAoC,QAAQ;AACvF,QAAM,WAAW,CAAC;AAClB,iBAAe,QAAQ,CAAC,gBAAgB;AACtC,aAAS,KAAK,KAAK,QAAQ,KAAK,QAAQ,WAAS,MAAM,YAAY,QAAQ,IAAI,CAAC,GAAG,MAAM,WAAW,CAAC;AACrG,aAAS,KAAK,KAAK,QAAQ,QAAQ,IAAI,GAAG,WAAW,CAAC;AAAA,EACxD,CAAC;AAGD,QAAM,UAAU,SAAS,KAAK,CAACA,aAAY,GAAG,WAAWA,QAAO,CAAC;AAEjE,MAAI,SAAS;AACT,WAAO,OAAO,EAAE,MAAM,QAAQ,CAAC;AAE/B,QAAI,QAAQ,QAAQ;AAChB,cAAQ,KAAK,UAAK,KAAK,SAAS,OAAO,CAAC,UAAU;AAAA,IACtD;AAAA,EAEJ,WAAW,QAAQ,QAAQ;AACvB,YAAQ,KAAK,+CAAqC,eAAe,KAAK,IAAI,CAAC,EAAE;AAAA,EACjF;AACJ;AAGA,IAAI,QAAQ,IAAI,mBAAmB,QAAW;AAC1C,cAAY,CAAC,YAAY,CAAC;AAC9B;AAGA,YAAY,CAAC,QAAQ,WAAW,CAAC,IAAI,MAAM,GAAG,MAAM;AAEpD,IAAI,QAAQ,IAAI,WAAW,QAAW;AACpC,cAAY,CAAC,QAAQ,UAAU,CAAC,IAAI,WAAW,CAAC,EAAE,GAAG,SAAS;AAChE;",
|
|
6
6
|
"names": ["envPath"]
|
|
7
7
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@colyseus/tools",
|
|
3
|
-
"version": "0.16.
|
|
3
|
+
"version": "0.16.9",
|
|
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",
|
|
@@ -50,9 +50,9 @@
|
|
|
50
50
|
"@types/cors": "^2.8.10",
|
|
51
51
|
"@types/dotenv": "^8.2.0",
|
|
52
52
|
"uwebsockets-express": "^1.1.10",
|
|
53
|
-
"@colyseus/core": "^0.16.
|
|
53
|
+
"@colyseus/core": "^0.16.18",
|
|
54
54
|
"@colyseus/ws-transport": "^0.16.5",
|
|
55
|
-
"@colyseus/uwebsockets-transport": "^0.16.
|
|
55
|
+
"@colyseus/uwebsockets-transport": "^0.16.9"
|
|
56
56
|
},
|
|
57
57
|
"peerDependencies": {
|
|
58
58
|
"@colyseus/core": "0.16.x",
|
package/system-boot.js
CHANGED
|
@@ -6,57 +6,63 @@ const { execSync } = require('child_process');
|
|
|
6
6
|
|
|
7
7
|
const NGINX_LIMITS_CONFIG_FILE = '/etc/nginx/colyseus_limits.conf';
|
|
8
8
|
const LIMITS_CONF_FILE = '/etc/security/limits.d/colyseus.conf';
|
|
9
|
-
const SYSCTL_FILE = '/etc/sysctl.d/local.conf'
|
|
9
|
+
const SYSCTL_FILE = '/etc/sysctl.d/local.conf';
|
|
10
10
|
|
|
11
|
-
const MAX_CCU_PER_CPU =
|
|
11
|
+
const MAX_CCU_PER_CPU = 5000;
|
|
12
12
|
|
|
13
13
|
/**
|
|
14
14
|
* System-wide limits configuration for high-CCU environments
|
|
15
15
|
* @param {Object} options
|
|
16
16
|
* @param {number} options.maxCCUPerCPU - Maximum concurrent users per CPU core
|
|
17
|
-
* @param {number} options.connectionsMultiplier - Multiplier for worker connections (default:
|
|
18
|
-
* @param {number} options.fileDescriptorMultiplier - Multiplier for max file descriptors (default:
|
|
17
|
+
* @param {number} options.connectionsMultiplier - Multiplier for worker connections (default: 2)
|
|
18
|
+
* @param {number} options.fileDescriptorMultiplier - Multiplier for max file descriptors (default: 6)
|
|
19
19
|
*/
|
|
20
20
|
function configureSystemLimits(options = {}) {
|
|
21
21
|
const {
|
|
22
|
-
connectionsMultiplier =
|
|
23
|
-
fileDescriptorMultiplier =
|
|
22
|
+
connectionsMultiplier = 2,
|
|
23
|
+
fileDescriptorMultiplier = 6
|
|
24
24
|
} = options;
|
|
25
25
|
|
|
26
26
|
const numCPU = os.cpus().length;
|
|
27
27
|
const maxCCU = numCPU * MAX_CCU_PER_CPU;
|
|
28
28
|
|
|
29
29
|
// Calculate limits
|
|
30
|
-
const workerConnections = maxCCU * connectionsMultiplier;
|
|
31
|
-
|
|
30
|
+
const workerConnections = Math.min(maxCCU * connectionsMultiplier, 65535); // Cap at max_socket_backlog (65535)
|
|
31
|
+
let maxFileDescriptors = maxCCU * fileDescriptorMultiplier;
|
|
32
|
+
const workerRlimitNofile = Math.ceil(workerConnections * 3.5); // Assume 3.5 file descriptors per connection for safety
|
|
32
33
|
|
|
33
|
-
//
|
|
34
|
-
const
|
|
34
|
+
// Calculate total file descriptors needed
|
|
35
|
+
const totalFileDescriptors = workerRlimitNofile * numCPU;
|
|
35
36
|
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
37
|
+
if (totalFileDescriptors > maxFileDescriptors) {
|
|
38
|
+
console.warn(`Warning: Total file descriptors (${totalFileDescriptors}) exceeds maxFileDescriptors (${maxFileDescriptors}). Increasing maxFileDescriptors.`);
|
|
39
|
+
maxFileDescriptors = totalFileDescriptors * 1.5; // 50% safety margin
|
|
39
40
|
}
|
|
40
41
|
|
|
41
|
-
|
|
42
|
-
|
|
42
|
+
// Check memory (rough estimate: 150 KB per connection)
|
|
43
|
+
const estimatedMemoryMB = (workerConnections * numCPU * 150) / 1024;
|
|
44
|
+
const totalMemoryMB = Number(execSync('free -m | awk \'/Mem:/ {print $2}\'').toString().trim());
|
|
45
|
+
if (estimatedMemoryMB > totalMemoryMB * 0.8) {
|
|
46
|
+
console.warn(`Warning: Estimated memory usage (${estimatedMemoryMB} MB) exceeds 80% of available memory (${totalMemoryMB} MB). Consider reducing MAX_CCU_PER_CPU.`);
|
|
43
47
|
}
|
|
44
48
|
|
|
45
49
|
if (process.argv.includes('--dry-run')) {
|
|
46
50
|
console.log({
|
|
51
|
+
numCPU,
|
|
47
52
|
maxCCU,
|
|
48
53
|
workerConnections,
|
|
49
54
|
maxFileDescriptors,
|
|
50
|
-
workerRlimitNofile
|
|
51
|
-
|
|
55
|
+
workerRlimitNofile,
|
|
56
|
+
totalFileDescriptors,
|
|
57
|
+
estimatedMemoryMB
|
|
58
|
+
});
|
|
52
59
|
process.exit();
|
|
53
60
|
}
|
|
54
61
|
|
|
55
62
|
// Configuration updates
|
|
56
63
|
try {
|
|
57
64
|
// Update Nginx limits
|
|
58
|
-
|
|
59
|
-
fs.writeFileSync(NGINX_LIMITS_CONFIG_FILE, `
|
|
65
|
+
fs.writeFileSync(NGINX_LIMITS_CONFIG_FILE, `
|
|
60
66
|
worker_rlimit_nofile ${workerRlimitNofile};
|
|
61
67
|
events {
|
|
62
68
|
use epoll;
|
|
@@ -64,7 +70,6 @@ events {
|
|
|
64
70
|
multi_accept on;
|
|
65
71
|
}
|
|
66
72
|
`);
|
|
67
|
-
}
|
|
68
73
|
|
|
69
74
|
// Update system-wide limits
|
|
70
75
|
fs.writeFileSync(LIMITS_CONF_FILE, `
|
|
@@ -74,7 +79,7 @@ nginx soft nofile ${maxFileDescriptors}
|
|
|
74
79
|
nginx hard nofile ${maxFileDescriptors}
|
|
75
80
|
`);
|
|
76
81
|
|
|
77
|
-
// Update sysctl
|
|
82
|
+
// Update sysctl
|
|
78
83
|
fs.writeFileSync(SYSCTL_FILE, `
|
|
79
84
|
# System-wide file descriptor limit
|
|
80
85
|
fs.file-max = ${maxFileDescriptors * 2}
|
|
@@ -99,7 +104,11 @@ net.ipv4.tcp_keepalive_probes = 3
|
|
|
99
104
|
`);
|
|
100
105
|
|
|
101
106
|
// Apply sysctl changes
|
|
102
|
-
execSync(
|
|
107
|
+
execSync('sysctl -p', { stdio: 'inherit' });
|
|
108
|
+
|
|
109
|
+
// Reload systemd
|
|
110
|
+
execSync('systemctl daemon-reload', { stdio: 'inherit' });
|
|
111
|
+
|
|
103
112
|
console.log(`System limits configured successfully for ${maxCCU} CCU (${MAX_CCU_PER_CPU}/CPU)`);
|
|
104
113
|
|
|
105
114
|
} catch (error) {
|