@colyseus/tools 0.16.18 → 0.17.0
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.js +79 -53
- package/build/index.js.map +3 -3
- package/build/index.mjs +76 -44
- package/build/index.mjs.map +2 -2
- package/build/loadenv.js +5 -4
- package/build/loadenv.js.map +2 -2
- package/build/loadenv.mjs +1 -1
- package/build/loadenv.mjs.map +2 -2
- package/build/src/index.d.ts +31 -0
- package/package.json +16 -13
- package/pm2/post-deploy-agent.js +18 -46
- package/pm2/shared.js +7 -94
- package/post-deploy.js +4 -8
- package/report-stats.js +0 -56
- package/system-boot.js +0 -83
- package/build/index.d.ts +0 -20
- package/pm2/ActionMethods.js +0 -47
- /package/build/{loadenv.d.ts → src/loadenv.d.ts} +0 -0
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import './loadenv.ts';
|
|
2
|
+
import express from 'express';
|
|
3
|
+
import { type ServerOptions, type SDKTypes, type Router, Server, Transport, RegisteredHandler } from '@colyseus/core';
|
|
4
|
+
export interface ConfigOptions<RoomTypes extends Record<string, RegisteredHandler> = any, Routes extends Router = any> extends SDKTypes<RoomTypes, Routes> {
|
|
5
|
+
options?: ServerOptions;
|
|
6
|
+
displayLogs?: boolean;
|
|
7
|
+
rooms?: RoomTypes;
|
|
8
|
+
routes?: Routes;
|
|
9
|
+
initializeTransport?: (options: any) => Transport;
|
|
10
|
+
initializeExpress?: (app: express.Express) => void;
|
|
11
|
+
initializeGameServer?: (app: Server) => void;
|
|
12
|
+
beforeListen?: () => void;
|
|
13
|
+
/**
|
|
14
|
+
* @deprecated getId() has no effect anymore.
|
|
15
|
+
*/
|
|
16
|
+
getId?: () => string;
|
|
17
|
+
}
|
|
18
|
+
export default function <RoomTypes extends Record<string, RegisteredHandler> = any, Routes extends Router = any>(options: Omit<ConfigOptions<RoomTypes, Routes>, '~rooms' | '~routes'>): ConfigOptions<RoomTypes, Routes>;
|
|
19
|
+
/**
|
|
20
|
+
* Expose server instance and listen on the port specified
|
|
21
|
+
* @param options Application options
|
|
22
|
+
* @param port Port number to bind Colyseus + Express
|
|
23
|
+
*/
|
|
24
|
+
export declare function listen<RoomTypes extends Record<string, RegisteredHandler> = any, Routes extends Router = any>(options: ConfigOptions<RoomTypes, Routes>, port?: number): Promise<Server<RoomTypes, Routes>>;
|
|
25
|
+
/**
|
|
26
|
+
* Expose server instance and listen on the port specified
|
|
27
|
+
* @param server Server instance
|
|
28
|
+
* @param port Port number to bind Colyseus + Express
|
|
29
|
+
*/
|
|
30
|
+
export declare function listen<RoomTypes extends Record<string, RegisteredHandler> = any, Routes extends Router = any>(server: Server<RoomTypes, Routes>, port?: number): Promise<Server<RoomTypes, Routes>>;
|
|
31
|
+
export declare function getTransport(options: ConfigOptions): Promise<Transport>;
|
package/package.json
CHANGED
|
@@ -1,16 +1,22 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@colyseus/tools",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.17.0",
|
|
4
|
+
"type": "module",
|
|
4
5
|
"description": "Simplify the development and production settings for your Colyseus project.",
|
|
5
6
|
"input": "./src/index.ts",
|
|
6
7
|
"main": "./build/index.js",
|
|
7
|
-
"module": "./
|
|
8
|
+
"module": "./src/index.ts",
|
|
8
9
|
"typings": "./build/index.d.ts",
|
|
9
10
|
"exports": {
|
|
10
11
|
".": {
|
|
11
12
|
"types": "./build/index.d.ts",
|
|
12
|
-
"import": "./
|
|
13
|
+
"import": "./src/index.ts",
|
|
13
14
|
"require": "./build/index.js"
|
|
15
|
+
},
|
|
16
|
+
"./*": {
|
|
17
|
+
"types": "./build/*.d.ts",
|
|
18
|
+
"import": "./src/*.ts",
|
|
19
|
+
"require": "./build/*.js"
|
|
14
20
|
}
|
|
15
21
|
},
|
|
16
22
|
"bin": {
|
|
@@ -49,15 +55,13 @@
|
|
|
49
55
|
"devDependencies": {
|
|
50
56
|
"@types/cors": "^2.8.10",
|
|
51
57
|
"@types/dotenv": "^8.2.0",
|
|
52
|
-
"pm2": "^6.0.14",
|
|
53
|
-
"mocha": "^11.7.5",
|
|
54
58
|
"uwebsockets-express": "^1.1.10",
|
|
55
|
-
"@colyseus/
|
|
56
|
-
"@colyseus/
|
|
57
|
-
"@colyseus/
|
|
58
|
-
"@colyseus/
|
|
59
|
-
"@colyseus/
|
|
60
|
-
"@colyseus/redis-
|
|
59
|
+
"@colyseus/ws-transport": "^0.17.0",
|
|
60
|
+
"@colyseus/core": "^0.17.0",
|
|
61
|
+
"@colyseus/bun-websockets": "^0.17.0",
|
|
62
|
+
"@colyseus/redis-presence": "^0.17.0",
|
|
63
|
+
"@colyseus/uwebsockets-transport": "^0.17.0",
|
|
64
|
+
"@colyseus/redis-driver": "^0.17.0"
|
|
61
65
|
},
|
|
62
66
|
"peerDependencies": {
|
|
63
67
|
"@colyseus/core": "0.16.x",
|
|
@@ -75,7 +79,6 @@
|
|
|
75
79
|
}
|
|
76
80
|
],
|
|
77
81
|
"scripts": {
|
|
78
|
-
"start": "tsx example/app.ts"
|
|
79
|
-
"test": "mocha --require tsx test/pm2-deployment.test.ts"
|
|
82
|
+
"start": "tsx example/app.ts"
|
|
80
83
|
}
|
|
81
84
|
}
|
package/pm2/post-deploy-agent.js
CHANGED
|
@@ -14,7 +14,8 @@ const io = require('@pm2/io');
|
|
|
14
14
|
const path = require('path');
|
|
15
15
|
const shared = require('./shared');
|
|
16
16
|
|
|
17
|
-
|
|
17
|
+
const opts = { env: process.env.NODE_ENV || "production", };
|
|
18
|
+
let config = undefined;
|
|
18
19
|
|
|
19
20
|
io.initModule({
|
|
20
21
|
pid: path.resolve('/var/run/colyseus-agent.pid'),
|
|
@@ -51,11 +52,9 @@ pm2.connect(function(err) {
|
|
|
51
52
|
}
|
|
52
53
|
|
|
53
54
|
try {
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
postDeploy(appConfig, onReply);
|
|
55
|
+
config = await shared.getAppConfig(ecosystemFilePath);
|
|
56
|
+
opts.cwd = cwd;
|
|
57
|
+
postDeploy(cwd, onReply);
|
|
59
58
|
|
|
60
59
|
} catch (err) {
|
|
61
60
|
onReply({ success: false, message: err?.message });
|
|
@@ -65,7 +64,7 @@ pm2.connect(function(err) {
|
|
|
65
64
|
|
|
66
65
|
const restartingAppIds = new Set();
|
|
67
66
|
|
|
68
|
-
function postDeploy(
|
|
67
|
+
function postDeploy(cwd, reply) {
|
|
69
68
|
shared.listApps(function(err, apps) {
|
|
70
69
|
if (err) {
|
|
71
70
|
console.error(err);
|
|
@@ -74,7 +73,7 @@ function postDeploy(config, reply) {
|
|
|
74
73
|
|
|
75
74
|
// first deploy, start all processes
|
|
76
75
|
if (apps.length === 0) {
|
|
77
|
-
return pm2.start(config, (err, result) => {
|
|
76
|
+
return pm2.start(config, {...opts}, (err, result) => {
|
|
78
77
|
reply({ success: !err, message: err?.message });
|
|
79
78
|
updateAndSave(err, result);
|
|
80
79
|
});
|
|
@@ -83,7 +82,7 @@ function postDeploy(config, reply) {
|
|
|
83
82
|
//
|
|
84
83
|
// detect if cwd has changed, and restart PM2 if it has
|
|
85
84
|
//
|
|
86
|
-
if (apps[0].pm2_env.pm_cwd !==
|
|
85
|
+
if (apps[0].pm2_env.pm_cwd !== cwd) {
|
|
87
86
|
console.log("App Root Directory changed. Restarting may take a bit longer...");
|
|
88
87
|
|
|
89
88
|
//
|
|
@@ -93,7 +92,7 @@ function postDeploy(config, reply) {
|
|
|
93
92
|
logIfError(err);
|
|
94
93
|
|
|
95
94
|
// start again
|
|
96
|
-
pm2.start(config, (err, result) => {
|
|
95
|
+
pm2.start(config, { ...opts }, (err, result) => {
|
|
97
96
|
reply({ success: !err, message: err?.message });
|
|
98
97
|
updateAndSave(err, result);
|
|
99
98
|
});
|
|
@@ -141,20 +140,6 @@ function postDeploy(config, reply) {
|
|
|
141
140
|
if (err) { return console.error(err); }
|
|
142
141
|
|
|
143
142
|
let numActiveApps = initialApps.length + restartingAppIds.size;
|
|
144
|
-
const maxActiveProcesses = config.instances;
|
|
145
|
-
|
|
146
|
-
// update config of newly spawned processes (memory limit, etc)
|
|
147
|
-
shared.listApps(function(err, apps) {
|
|
148
|
-
logIfError(err);
|
|
149
|
-
|
|
150
|
-
// get new processes excluding initialApps
|
|
151
|
-
const new_app_envs = shared.filterActiveApps(apps)
|
|
152
|
-
.map((app) => app.pm2_env)
|
|
153
|
-
.filter(app_env => !initialApps.find(init_app => init_app.pm_id === app_env.pm_id));
|
|
154
|
-
|
|
155
|
-
new_app_envs.forEach((app_env) =>
|
|
156
|
-
shared.updateProcessConfig(app_env.pm_id, appConfig, logIfError));
|
|
157
|
-
});
|
|
158
143
|
|
|
159
144
|
/**
|
|
160
145
|
* - Write NGINX config to expose only the new active process
|
|
@@ -172,7 +157,7 @@ function postDeploy(config, reply) {
|
|
|
172
157
|
// (They make take from minutes up to hours to stop)
|
|
173
158
|
//
|
|
174
159
|
appsToStop.forEach((app_env) => {
|
|
175
|
-
if (numActiveApps <
|
|
160
|
+
if (numActiveApps < shared.MAX_ACTIVE_PROCESSES) {
|
|
176
161
|
numActiveApps++;
|
|
177
162
|
|
|
178
163
|
restartingAppIds.add(app_env.pm_id);
|
|
@@ -182,9 +167,6 @@ function postDeploy(config, reply) {
|
|
|
182
167
|
|
|
183
168
|
// reset counter stats (restart_time=0)
|
|
184
169
|
pm2.reset(app_env.pm_id, logIfError);
|
|
185
|
-
|
|
186
|
-
// update process config (memory limit, etc)
|
|
187
|
-
shared.updateProcessConfig(app_env.pm_id, config, logIfError);
|
|
188
170
|
});
|
|
189
171
|
|
|
190
172
|
} else {
|
|
@@ -192,8 +174,8 @@ function postDeploy(config, reply) {
|
|
|
192
174
|
}
|
|
193
175
|
});
|
|
194
176
|
|
|
195
|
-
if (numActiveApps <
|
|
196
|
-
const missingOnlineApps =
|
|
177
|
+
if (numActiveApps < shared.MAX_ACTIVE_PROCESSES) {
|
|
178
|
+
const missingOnlineApps = shared.MAX_ACTIVE_PROCESSES - numActiveApps;
|
|
197
179
|
|
|
198
180
|
// console.log("Active apps is lower than MAX_ACTIVE_PROCESSES, will SCALE again =>", {
|
|
199
181
|
// missingOnlineApps,
|
|
@@ -201,12 +183,11 @@ function postDeploy(config, reply) {
|
|
|
201
183
|
// newNumTotalApps: numTotalApps + missingOnlineApps
|
|
202
184
|
// });
|
|
203
185
|
|
|
204
|
-
console.log("Scale up to", numTotalApps + missingOnlineApps);
|
|
205
186
|
pm2.scale(apps[0].name, numTotalApps + missingOnlineApps, updateAndSaveIfAllRunning);
|
|
206
187
|
}
|
|
207
188
|
};
|
|
208
189
|
|
|
209
|
-
const numHalfMaxActiveProcesses = Math.ceil(
|
|
190
|
+
const numHalfMaxActiveProcesses = Math.ceil(shared.MAX_ACTIVE_PROCESSES / 2);
|
|
210
191
|
|
|
211
192
|
/**
|
|
212
193
|
* Re-use previously stopped apps if available
|
|
@@ -225,7 +206,6 @@ function postDeploy(config, reply) {
|
|
|
225
206
|
|
|
226
207
|
// reset counter stats (restart_time=0)
|
|
227
208
|
pm2.reset(app_env.pm_id, logIfError);
|
|
228
|
-
shared.updateProcessConfig(app_env.pm_id, config, logIfError);
|
|
229
209
|
|
|
230
210
|
// TODO: set timeout here to exit if some processes are not restarting
|
|
231
211
|
|
|
@@ -249,8 +229,6 @@ function postDeploy(config, reply) {
|
|
|
249
229
|
|
|
250
230
|
numTotalApps = apps.length + numHalfMaxActiveProcesses;
|
|
251
231
|
|
|
252
|
-
console.log("Starting first half of new apps... pm2.scale(app, ", numTotalApps, ")");
|
|
253
|
-
|
|
254
232
|
// Ensure to scale to a number of processes where `numHalfMaxActiveProcesses` can start immediately.
|
|
255
233
|
pm2.scale(apps[0].name, numTotalApps, onFirstAppsStart.bind(undefined, initialApps));
|
|
256
234
|
}
|
|
@@ -266,12 +244,12 @@ function updateAndSaveIfAllRunning(err) {
|
|
|
266
244
|
if (err) { return console.error(err); }
|
|
267
245
|
|
|
268
246
|
updateAndReloadNginx((app_envs) => {
|
|
269
|
-
// console.log("updateAndExitIfAllRunning, app_ids (", app_envs.map(app_env => app_env.NODE_APP_INSTANCE) ,") => ", app_envs.length, "/",
|
|
247
|
+
// console.log("updateAndExitIfAllRunning, app_ids (", app_envs.map(app_env => app_env.NODE_APP_INSTANCE) ,") => ", app_envs.length, "/", shared.MAX_ACTIVE_PROCESSES);
|
|
270
248
|
|
|
271
249
|
//
|
|
272
250
|
// TODO: add timeout to exit here, in case some processes are not starting
|
|
273
251
|
//
|
|
274
|
-
if (app_envs.length ===
|
|
252
|
+
if (app_envs.length === shared.MAX_ACTIVE_PROCESSES) {
|
|
275
253
|
complete();
|
|
276
254
|
}
|
|
277
255
|
});
|
|
@@ -294,24 +272,18 @@ function updateAndReloadNginx(cb) {
|
|
|
294
272
|
if (apps.length === 0) { err = "no apps running."; }
|
|
295
273
|
if (err) { return console.error(err); }
|
|
296
274
|
|
|
297
|
-
const app_envs =
|
|
275
|
+
const app_envs = apps
|
|
276
|
+
.filter(app => app.pm2_env.status !== cst.STOPPING_STATUS && app.pm2_env.status !== cst.STOPPED_STATUS)
|
|
277
|
+
.map((app) => app.pm2_env);
|
|
298
278
|
|
|
299
279
|
writeNginxConfig(app_envs);
|
|
300
280
|
|
|
301
|
-
// update processes config (memory limit, etc)
|
|
302
|
-
app_envs.forEach((app_env) =>
|
|
303
|
-
shared.updateProcessConfig(app_env.pm_id, appConfig, logIfError));
|
|
304
|
-
|
|
305
281
|
cb?.(app_envs);
|
|
306
282
|
});
|
|
307
283
|
}
|
|
308
284
|
|
|
309
285
|
function writeNginxConfig(app_envs) {
|
|
310
286
|
// console.log("writeNginxConfig: ", app_envs.map(app_env => app_env.NODE_APP_INSTANCE));
|
|
311
|
-
if (!fs.existsSync(shared.NGINX_SERVERS_CONFIG_FILE)) {
|
|
312
|
-
console.warn(`NGINX config file not found at ${shared.NGINX_SERVERS_CONFIG_FILE}, skipping NGINX config update.`);
|
|
313
|
-
return;
|
|
314
|
-
}
|
|
315
287
|
|
|
316
288
|
const port = 2567;
|
|
317
289
|
const addresses = [];
|
package/pm2/shared.js
CHANGED
|
@@ -1,25 +1,12 @@
|
|
|
1
1
|
const pm2 = require('pm2');
|
|
2
|
-
const cst = require('pm2/constants');
|
|
3
2
|
const os = require('os');
|
|
4
3
|
|
|
5
4
|
const NAMESPACE = 'cloud';
|
|
6
|
-
const MAX_ACTIVE_PROCESSES =
|
|
7
|
-
|
|
8
|
-
const CONFIG_KEYS = [
|
|
9
|
-
'max_memory_restart',
|
|
10
|
-
'kill_timeout',
|
|
11
|
-
'kill_retry_time',
|
|
12
|
-
'wait_ready',
|
|
13
|
-
'merge_logs',
|
|
14
|
-
'cron_restart',
|
|
15
|
-
'autorestart',
|
|
16
|
-
'exp_backoff_restart_delay',
|
|
17
|
-
'restart_delay',
|
|
18
|
-
];
|
|
5
|
+
const MAX_ACTIVE_PROCESSES = os.cpus().length;
|
|
19
6
|
|
|
20
7
|
function listApps(callback) {
|
|
21
8
|
pm2.list((err, apps) => {
|
|
22
|
-
if (err) { return callback(err)
|
|
9
|
+
if (err) { return callback(err);; }
|
|
23
10
|
|
|
24
11
|
// Filter out @colyseus/tools module (PM2 post-deploy agent)
|
|
25
12
|
apps = apps.filter(app => app.name !== '@colyseus/tools');
|
|
@@ -29,10 +16,8 @@ function listApps(callback) {
|
|
|
29
16
|
}
|
|
30
17
|
|
|
31
18
|
async function getAppConfig(ecosystemFilePath) {
|
|
32
|
-
|
|
33
|
-
const
|
|
34
|
-
delete require.cache[resolvedPath];
|
|
35
|
-
const config = require(ecosystemFilePath);
|
|
19
|
+
const module = await import(ecosystemFilePath);
|
|
20
|
+
const config = module.default;
|
|
36
21
|
|
|
37
22
|
/**
|
|
38
23
|
* Tune PM2 app config
|
|
@@ -44,15 +29,7 @@ async function getAppConfig(ecosystemFilePath) {
|
|
|
44
29
|
app.namespace = NAMESPACE;
|
|
45
30
|
app.exec_mode = "fork";
|
|
46
31
|
|
|
47
|
-
|
|
48
|
-
if (app.instances === undefined) {
|
|
49
|
-
app.instances = MAX_ACTIVE_PROCESSES;
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
// default: restart if memory exceeds 512M
|
|
53
|
-
if (app.max_memory_restart === undefined) {
|
|
54
|
-
app.max_memory_restart = '512M';
|
|
55
|
-
}
|
|
32
|
+
app.instances = MAX_ACTIVE_PROCESSES;
|
|
56
33
|
|
|
57
34
|
app.time = true;
|
|
58
35
|
app.wait_ready = true;
|
|
@@ -73,74 +50,17 @@ async function getAppConfig(ecosystemFilePath) {
|
|
|
73
50
|
if (!app.kill_retry_time) {
|
|
74
51
|
app.kill_retry_time = 5000;
|
|
75
52
|
}
|
|
76
|
-
|
|
77
|
-
// Ensure these config values are also set in app.env so they take priority
|
|
78
|
-
// over inherited environment variables during PM2's Utility.extend() merge.
|
|
79
|
-
// This prevents the parent process's environment (e.g., @colyseus/tools agent)
|
|
80
|
-
// from overwriting the app's config values like max_memory_restart.
|
|
81
|
-
if (!app.env) {
|
|
82
|
-
app.env = {};
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
CONFIG_KEYS.forEach((key) => {
|
|
86
|
-
if (app[key] !== undefined) {
|
|
87
|
-
app.env[key] = convertValue(app[key]);
|
|
88
|
-
}
|
|
89
|
-
});
|
|
90
53
|
}
|
|
91
54
|
|
|
92
55
|
return config;
|
|
93
56
|
}
|
|
94
57
|
|
|
95
|
-
function convertValue(value) {
|
|
96
|
-
if (typeof value === 'string') {
|
|
97
|
-
const conversionUnit = {
|
|
98
|
-
// bytes
|
|
99
|
-
'G': 1024 * 1024 * 1024,
|
|
100
|
-
'M': 1024 * 1024,
|
|
101
|
-
'K': 1024,
|
|
102
|
-
// milliseconds
|
|
103
|
-
'h': 60 * 60 * 1000,
|
|
104
|
-
'm': 60 * 1000,
|
|
105
|
-
's': 1000
|
|
106
|
-
};
|
|
107
|
-
|
|
108
|
-
if (!conversionUnit[value.slice(-1)]) {
|
|
109
|
-
return parseInt(value, 10);
|
|
110
|
-
|
|
111
|
-
} else {
|
|
112
|
-
return parseFloat(value.slice(0, -1)) * (conversionUnit[value.slice(-1)]);
|
|
113
|
-
}
|
|
114
|
-
}
|
|
115
|
-
return value;
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
/**
|
|
119
|
-
* Update process configuration without restart.
|
|
120
|
-
* This patches pm2_env directly via a custom God method.
|
|
121
|
-
* @param {number|string} pm_id - Process ID to update
|
|
122
|
-
* @param {Object} config - Configuration object (e.g., { max_memory_restart: '512M', kill_timeout: 30000 })
|
|
123
|
-
* @param {Function} cb - Callback(err, updatedEnv)
|
|
124
|
-
*/
|
|
125
|
-
function updateProcessConfig(pm_id, config, cb) {
|
|
126
|
-
const env = {};
|
|
127
|
-
|
|
128
|
-
CONFIG_KEYS.forEach((key) => {
|
|
129
|
-
if (config[key] !== undefined) {
|
|
130
|
-
env[key] = convertValue(config[key]);
|
|
131
|
-
}
|
|
132
|
-
});
|
|
133
|
-
|
|
134
|
-
const opts = { id: pm_id, env, };
|
|
135
|
-
pm2.Client.executeRemote('updateProcessConfig', opts, cb);
|
|
136
|
-
}
|
|
137
|
-
|
|
138
58
|
module.exports = {
|
|
139
59
|
/**
|
|
140
60
|
* Constants
|
|
141
61
|
*/
|
|
142
|
-
NGINX_SERVERS_CONFIG_FILE:
|
|
143
|
-
PROCESS_UNIX_SOCK_PATH:
|
|
62
|
+
NGINX_SERVERS_CONFIG_FILE: '/etc/nginx/colyseus_servers.conf',
|
|
63
|
+
PROCESS_UNIX_SOCK_PATH: '/run/colyseus/',
|
|
144
64
|
|
|
145
65
|
MAX_ACTIVE_PROCESSES,
|
|
146
66
|
NAMESPACE,
|
|
@@ -150,11 +70,4 @@ module.exports = {
|
|
|
150
70
|
*/
|
|
151
71
|
listApps,
|
|
152
72
|
getAppConfig,
|
|
153
|
-
|
|
154
|
-
updateProcessConfig,
|
|
155
|
-
|
|
156
|
-
filterActiveApps: (apps) => apps.filter(app =>
|
|
157
|
-
app.pm2_env.status !== cst.STOPPING_STATUS &&
|
|
158
|
-
app.pm2_env.status !== cst.STOPPED_STATUS
|
|
159
|
-
),
|
|
160
73
|
}
|
package/post-deploy.js
CHANGED
|
@@ -90,11 +90,7 @@ function restartAll () {
|
|
|
90
90
|
});
|
|
91
91
|
}
|
|
92
92
|
|
|
93
|
-
|
|
94
|
-
// Read user's ecosystem config to get the desired number of instances
|
|
95
|
-
const config = await shared.getAppConfig(CONFIG_FILE_PATH);
|
|
96
|
-
const desiredInstances = config.apps?.[0]?.instances || shared.MAX_ACTIVE_PROCESSES;
|
|
97
|
-
|
|
93
|
+
function reloadAll(retry = 0) {
|
|
98
94
|
pm2.reload(CONFIG_FILE_PATH, { ...opts }, function (err, apps) {
|
|
99
95
|
if (err) {
|
|
100
96
|
//
|
|
@@ -114,9 +110,9 @@ async function reloadAll(retry = 0) {
|
|
|
114
110
|
const name = apps[0].name;
|
|
115
111
|
const reloadedAppIds = apps.map(app => app.pm_id);
|
|
116
112
|
|
|
117
|
-
// scale app to
|
|
118
|
-
if (apps.length !==
|
|
119
|
-
pm2.scale(name,
|
|
113
|
+
// scale app to use all CPUs available
|
|
114
|
+
if (apps.length !== shared.MAX_ACTIVE_PROCESSES) {
|
|
115
|
+
pm2.scale(name, shared.MAX_ACTIVE_PROCESSES, () => onAppRunning(reloadedAppIds));
|
|
120
116
|
|
|
121
117
|
} else {
|
|
122
118
|
onAppRunning(reloadedAppIds);
|
package/report-stats.js
CHANGED
|
@@ -3,18 +3,12 @@
|
|
|
3
3
|
const fs = require('fs');
|
|
4
4
|
const net = require('net');
|
|
5
5
|
const pm2 = require('pm2');
|
|
6
|
-
const dotenv = require('dotenv');
|
|
7
6
|
|
|
8
7
|
const COLYSEUS_CLOUD_URL = `${process.env.ENDPOINT}/vultr/stats`;
|
|
9
8
|
|
|
10
9
|
const FAILED_ATTEMPS_FILE = "/var/tmp/pm2-stats-attempts.txt";
|
|
11
10
|
const FETCH_TIMEOUT = 30000;
|
|
12
11
|
|
|
13
|
-
// load environment variables (Colyseus Cloud environment variables)
|
|
14
|
-
if (process.env.APP_ROOT_PATH) {
|
|
15
|
-
dotenv.config({ path: `${process.env.APP_ROOT_PATH}/.env.cloud` });
|
|
16
|
-
}
|
|
17
|
-
|
|
18
12
|
async function retryFailedAttempts() {
|
|
19
13
|
/**
|
|
20
14
|
* Retry cached failed attempts
|
|
@@ -133,9 +127,6 @@ pm2.Client.executeRemote('getMonitorData', {}, async function(err, list) {
|
|
|
133
127
|
version: 1,
|
|
134
128
|
ip,
|
|
135
129
|
time: new Date(),
|
|
136
|
-
statuses: {
|
|
137
|
-
driver: await checkDriverIsAccessible()
|
|
138
|
-
},
|
|
139
130
|
aggregate,
|
|
140
131
|
apps,
|
|
141
132
|
};
|
|
@@ -174,11 +165,6 @@ pm2.Client.executeRemote('getMonitorData', {}, async function(err, list) {
|
|
|
174
165
|
}
|
|
175
166
|
});
|
|
176
167
|
|
|
177
|
-
/**
|
|
178
|
-
* Check if a socket file is active
|
|
179
|
-
* @param {string} sockFilePath - The path to the socket file
|
|
180
|
-
* @returns {Promise<boolean>} true if the socket file is active, false otherwise
|
|
181
|
-
*/
|
|
182
168
|
function checkSocketIsActive(sockFilePath) {
|
|
183
169
|
return new Promise((resolve, _) => {
|
|
184
170
|
const client = net.createConnection({ path: sockFilePath, timeout: 5000 })
|
|
@@ -190,45 +176,3 @@ function checkSocketIsActive(sockFilePath) {
|
|
|
190
176
|
.on('timeout', () => resolve(false));
|
|
191
177
|
});
|
|
192
178
|
}
|
|
193
|
-
|
|
194
|
-
/**
|
|
195
|
-
* Check if the driver is accessible
|
|
196
|
-
* @returns {Promise<boolean | string>} returns true if the driver is accessible, false otherwise or the error message
|
|
197
|
-
*/
|
|
198
|
-
async function checkDriverIsAccessible() {
|
|
199
|
-
try {
|
|
200
|
-
if (process.env.REDIS_URI) {
|
|
201
|
-
const url = new URL(process.env.REDIS_URI);
|
|
202
|
-
return await isPortOpen({
|
|
203
|
-
host: url.hostname,
|
|
204
|
-
port: url.port
|
|
205
|
-
});
|
|
206
|
-
} else {
|
|
207
|
-
return true;
|
|
208
|
-
}
|
|
209
|
-
} catch (e) {
|
|
210
|
-
return e.message || false;
|
|
211
|
-
}
|
|
212
|
-
}
|
|
213
|
-
|
|
214
|
-
/**
|
|
215
|
-
* Check if a port is open
|
|
216
|
-
* @param {{ host: string, port: number, timeout?: number }} options - The options to check
|
|
217
|
-
* @returns {Promise<boolean | string>}
|
|
218
|
-
*/
|
|
219
|
-
function isPortOpen({ host, port, timeout = 2000 }) {
|
|
220
|
-
return new Promise((resolve) => {
|
|
221
|
-
const socket = new net.Socket();
|
|
222
|
-
const onError = (value) => {
|
|
223
|
-
socket.destroy();
|
|
224
|
-
resolve(value || false);
|
|
225
|
-
};
|
|
226
|
-
socket.setTimeout(timeout);
|
|
227
|
-
socket.once("error", (e) => onError(e.message));
|
|
228
|
-
socket.once("timeout", () => onError("timeout"));
|
|
229
|
-
socket.connect(port, host, () => {
|
|
230
|
-
socket.end(); // immediately close
|
|
231
|
-
resolve(true);
|
|
232
|
-
});
|
|
233
|
-
});
|
|
234
|
-
}
|
package/system-boot.js
CHANGED
|
@@ -2,88 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
const os = require('os');
|
|
4
4
|
const fs = require('fs');
|
|
5
|
-
const path = require('path');
|
|
6
5
|
const { execSync } = require('child_process');
|
|
7
6
|
|
|
8
|
-
/**
|
|
9
|
-
* Apply PM2 monkey-patch for custom functionality (e.g., updateProcessConfig)
|
|
10
|
-
* This patches the globally installed PM2 used by the system.
|
|
11
|
-
*
|
|
12
|
-
* Strategy: Rename ActionMethods.js -> ActionMethods_orig.js and replace with
|
|
13
|
-
* our wrapper that imports the original and adds custom methods.
|
|
14
|
-
*/
|
|
15
|
-
function applyPM2Patches() {
|
|
16
|
-
try {
|
|
17
|
-
// Find global PM2 installation
|
|
18
|
-
const globalPM2Path = execSync('npm root -g', { encoding: 'utf8' }).trim() + '/pm2';
|
|
19
|
-
|
|
20
|
-
if (!fs.existsSync(globalPM2Path)) {
|
|
21
|
-
console.log('[PM2 Patch] Global PM2 not found, skipping...');
|
|
22
|
-
return;
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
const godPath = path.join(globalPM2Path, 'lib/God');
|
|
26
|
-
const actionMethodsPath = path.join(godPath, 'ActionMethods.js');
|
|
27
|
-
const actionMethodsOrigPath = path.join(godPath, 'ActionMethods_orig.js');
|
|
28
|
-
const ourActionMethodsPath = path.join(__dirname, 'pm2', 'ActionMethods.js');
|
|
29
|
-
|
|
30
|
-
// Check if our patch file exists
|
|
31
|
-
if (!fs.existsSync(ourActionMethodsPath)) {
|
|
32
|
-
console.log('[PM2 Patch] Custom ActionMethods.js not found, skipping...');
|
|
33
|
-
return;
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
// Check if already patched (ActionMethods_orig.js exists)
|
|
37
|
-
if (!fs.existsSync(actionMethodsOrigPath)) {
|
|
38
|
-
// Rename original ActionMethods.js -> ActionMethods_orig.js
|
|
39
|
-
console.log('[PM2 Patch] Renaming original ActionMethods.js -> ActionMethods_orig.js');
|
|
40
|
-
fs.renameSync(actionMethodsPath, actionMethodsOrigPath);
|
|
41
|
-
|
|
42
|
-
} else {
|
|
43
|
-
console.log('[PM2 Patch] Already patched, skipping...');
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
// Copy our ActionMethods.js wrapper
|
|
47
|
-
console.log(`[PM2 Patch] Installing custom ActionMethods.js wrapper (${actionMethodsPath})`);
|
|
48
|
-
fs.copyFileSync(ourActionMethodsPath, actionMethodsPath);
|
|
49
|
-
|
|
50
|
-
// Patch Daemon.js to expose "updateProcessConfig" method
|
|
51
|
-
const daemonPath = path.join(globalPM2Path, 'lib/Daemon.js');
|
|
52
|
-
console.log(`[PM2 Patch] Patching Daemon.js to expose updateProcessConfig (${daemonPath})`);
|
|
53
|
-
if (fs.existsSync(daemonPath)) {
|
|
54
|
-
let daemonContent = fs.readFileSync(daemonPath, 'utf8');
|
|
55
|
-
|
|
56
|
-
// Check if updateProcessConfig is already exposed
|
|
57
|
-
if (!daemonContent.includes('updateProcessConfig')) {
|
|
58
|
-
// Find server.expose({ and add updateProcessConfig after it
|
|
59
|
-
const exposePattern = 'server.expose({';
|
|
60
|
-
const exposeIndex = daemonContent.indexOf(exposePattern);
|
|
61
|
-
|
|
62
|
-
if (exposeIndex !== -1) {
|
|
63
|
-
const insertPos = exposeIndex + exposePattern.length;
|
|
64
|
-
daemonContent = daemonContent.slice(0, insertPos) +
|
|
65
|
-
'\n updateProcessConfig : God.updateProcessConfig,' +
|
|
66
|
-
daemonContent.slice(insertPos);
|
|
67
|
-
fs.writeFileSync(daemonPath, daemonContent);
|
|
68
|
-
console.log(`[PM2 Patch] Daemon.js patched successfully.`);
|
|
69
|
-
} else {
|
|
70
|
-
console.warn('[PM2 Patch] Could not find server.expose pattern in Daemon.js');
|
|
71
|
-
}
|
|
72
|
-
} else {
|
|
73
|
-
console.log('[PM2 Patch] Daemon.js already has updateProcessConfig exposed.');
|
|
74
|
-
}
|
|
75
|
-
} else {
|
|
76
|
-
console.warn('[PM2 Patch] Daemon.js not found at', daemonPath);
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
console.log('[PM2 Patch] PM2 patches applied successfully.');
|
|
80
|
-
|
|
81
|
-
} catch (error) {
|
|
82
|
-
console.warn('[PM2 Patch] Failed to apply PM2 patches:', error.message);
|
|
83
|
-
// Don't exit - patches are optional enhancements
|
|
84
|
-
}
|
|
85
|
-
}
|
|
86
|
-
|
|
87
7
|
const NGINX_LIMITS_CONFIG_FILE = '/etc/nginx/colyseus_limits.conf';
|
|
88
8
|
const LIMITS_CONF_FILE = '/etc/security/limits.d/colyseus.conf';
|
|
89
9
|
const SYSCTL_FILE = '/etc/sysctl.d/local.conf';
|
|
@@ -197,7 +117,4 @@ net.ipv4.tcp_keepalive_probes = 3
|
|
|
197
117
|
}
|
|
198
118
|
}
|
|
199
119
|
|
|
200
|
-
// Apply PM2 patches before configuring system limits
|
|
201
|
-
applyPM2Patches();
|
|
202
|
-
|
|
203
120
|
configureSystemLimits();
|
package/build/index.d.ts
DELETED
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
import './loadenv.js';
|
|
2
|
-
import express from 'express';
|
|
3
|
-
import { Server, ServerOptions, Transport } from '@colyseus/core';
|
|
4
|
-
export interface ConfigOptions {
|
|
5
|
-
options?: ServerOptions;
|
|
6
|
-
displayLogs?: boolean;
|
|
7
|
-
getId?: () => string;
|
|
8
|
-
initializeTransport?: (options: any) => Transport;
|
|
9
|
-
initializeExpress?: (app: express.Express) => void;
|
|
10
|
-
initializeGameServer?: (app: Server) => void;
|
|
11
|
-
beforeListen?: () => void;
|
|
12
|
-
}
|
|
13
|
-
export default function (options: ConfigOptions): ConfigOptions;
|
|
14
|
-
/**
|
|
15
|
-
* Listen on your development environment
|
|
16
|
-
* @param options Application options
|
|
17
|
-
* @param port Port number to bind Colyseus + Express
|
|
18
|
-
*/
|
|
19
|
-
export declare function listen(options: ConfigOptions | Server, port?: number): Promise<Server>;
|
|
20
|
-
export declare function getTransport(options: ConfigOptions): Promise<Transport>;
|