@colyseus/tools 0.16.17 → 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 -47
- 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/core": "^0.
|
|
57
|
-
"@colyseus/
|
|
58
|
-
"@colyseus/redis-
|
|
59
|
-
"@colyseus/
|
|
60
|
-
"@colyseus/
|
|
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,8 +73,7 @@ function postDeploy(config, reply) {
|
|
|
74
73
|
|
|
75
74
|
// first deploy, start all processes
|
|
76
75
|
if (apps.length === 0) {
|
|
77
|
-
|
|
78
|
-
return pm2.start(config, (err, result) => {
|
|
76
|
+
return pm2.start(config, {...opts}, (err, result) => {
|
|
79
77
|
reply({ success: !err, message: err?.message });
|
|
80
78
|
updateAndSave(err, result);
|
|
81
79
|
});
|
|
@@ -84,7 +82,7 @@ function postDeploy(config, reply) {
|
|
|
84
82
|
//
|
|
85
83
|
// detect if cwd has changed, and restart PM2 if it has
|
|
86
84
|
//
|
|
87
|
-
if (apps[0].pm2_env.pm_cwd !==
|
|
85
|
+
if (apps[0].pm2_env.pm_cwd !== cwd) {
|
|
88
86
|
console.log("App Root Directory changed. Restarting may take a bit longer...");
|
|
89
87
|
|
|
90
88
|
//
|
|
@@ -94,7 +92,7 @@ function postDeploy(config, reply) {
|
|
|
94
92
|
logIfError(err);
|
|
95
93
|
|
|
96
94
|
// start again
|
|
97
|
-
pm2.start(config, (err, result) => {
|
|
95
|
+
pm2.start(config, { ...opts }, (err, result) => {
|
|
98
96
|
reply({ success: !err, message: err?.message });
|
|
99
97
|
updateAndSave(err, result);
|
|
100
98
|
});
|
|
@@ -142,20 +140,6 @@ function postDeploy(config, reply) {
|
|
|
142
140
|
if (err) { return console.error(err); }
|
|
143
141
|
|
|
144
142
|
let numActiveApps = initialApps.length + restartingAppIds.size;
|
|
145
|
-
const maxActiveProcesses = config.instances;
|
|
146
|
-
|
|
147
|
-
// update config of newly spawned processes (memory limit, etc)
|
|
148
|
-
shared.listApps(function(err, apps) {
|
|
149
|
-
logIfError(err);
|
|
150
|
-
|
|
151
|
-
// get new processes excluding initialApps
|
|
152
|
-
const new_app_envs = shared.filterActiveApps(apps)
|
|
153
|
-
.map((app) => app.pm2_env)
|
|
154
|
-
.filter(app_env => !initialApps.find(init_app => init_app.pm_id === app_env.pm_id));
|
|
155
|
-
|
|
156
|
-
new_app_envs.forEach((app_env) =>
|
|
157
|
-
shared.updateProcessConfig(app_env.pm_id, appConfig, logIfError));
|
|
158
|
-
});
|
|
159
143
|
|
|
160
144
|
/**
|
|
161
145
|
* - Write NGINX config to expose only the new active process
|
|
@@ -173,7 +157,7 @@ function postDeploy(config, reply) {
|
|
|
173
157
|
// (They make take from minutes up to hours to stop)
|
|
174
158
|
//
|
|
175
159
|
appsToStop.forEach((app_env) => {
|
|
176
|
-
if (numActiveApps <
|
|
160
|
+
if (numActiveApps < shared.MAX_ACTIVE_PROCESSES) {
|
|
177
161
|
numActiveApps++;
|
|
178
162
|
|
|
179
163
|
restartingAppIds.add(app_env.pm_id);
|
|
@@ -183,9 +167,6 @@ function postDeploy(config, reply) {
|
|
|
183
167
|
|
|
184
168
|
// reset counter stats (restart_time=0)
|
|
185
169
|
pm2.reset(app_env.pm_id, logIfError);
|
|
186
|
-
|
|
187
|
-
// update process config (memory limit, etc)
|
|
188
|
-
shared.updateProcessConfig(app_env.pm_id, config, logIfError);
|
|
189
170
|
});
|
|
190
171
|
|
|
191
172
|
} else {
|
|
@@ -193,8 +174,8 @@ function postDeploy(config, reply) {
|
|
|
193
174
|
}
|
|
194
175
|
});
|
|
195
176
|
|
|
196
|
-
if (numActiveApps <
|
|
197
|
-
const missingOnlineApps =
|
|
177
|
+
if (numActiveApps < shared.MAX_ACTIVE_PROCESSES) {
|
|
178
|
+
const missingOnlineApps = shared.MAX_ACTIVE_PROCESSES - numActiveApps;
|
|
198
179
|
|
|
199
180
|
// console.log("Active apps is lower than MAX_ACTIVE_PROCESSES, will SCALE again =>", {
|
|
200
181
|
// missingOnlineApps,
|
|
@@ -202,12 +183,11 @@ function postDeploy(config, reply) {
|
|
|
202
183
|
// newNumTotalApps: numTotalApps + missingOnlineApps
|
|
203
184
|
// });
|
|
204
185
|
|
|
205
|
-
console.log("Scale up to", numTotalApps + missingOnlineApps);
|
|
206
186
|
pm2.scale(apps[0].name, numTotalApps + missingOnlineApps, updateAndSaveIfAllRunning);
|
|
207
187
|
}
|
|
208
188
|
};
|
|
209
189
|
|
|
210
|
-
const numHalfMaxActiveProcesses = Math.ceil(
|
|
190
|
+
const numHalfMaxActiveProcesses = Math.ceil(shared.MAX_ACTIVE_PROCESSES / 2);
|
|
211
191
|
|
|
212
192
|
/**
|
|
213
193
|
* Re-use previously stopped apps if available
|
|
@@ -226,7 +206,6 @@ function postDeploy(config, reply) {
|
|
|
226
206
|
|
|
227
207
|
// reset counter stats (restart_time=0)
|
|
228
208
|
pm2.reset(app_env.pm_id, logIfError);
|
|
229
|
-
shared.updateProcessConfig(app_env.pm_id, config, logIfError);
|
|
230
209
|
|
|
231
210
|
// TODO: set timeout here to exit if some processes are not restarting
|
|
232
211
|
|
|
@@ -250,8 +229,6 @@ function postDeploy(config, reply) {
|
|
|
250
229
|
|
|
251
230
|
numTotalApps = apps.length + numHalfMaxActiveProcesses;
|
|
252
231
|
|
|
253
|
-
console.log("Starting first half of new apps... pm2.scale(app, ", numTotalApps, ")");
|
|
254
|
-
|
|
255
232
|
// Ensure to scale to a number of processes where `numHalfMaxActiveProcesses` can start immediately.
|
|
256
233
|
pm2.scale(apps[0].name, numTotalApps, onFirstAppsStart.bind(undefined, initialApps));
|
|
257
234
|
}
|
|
@@ -267,12 +244,12 @@ function updateAndSaveIfAllRunning(err) {
|
|
|
267
244
|
if (err) { return console.error(err); }
|
|
268
245
|
|
|
269
246
|
updateAndReloadNginx((app_envs) => {
|
|
270
|
-
// 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);
|
|
271
248
|
|
|
272
249
|
//
|
|
273
250
|
// TODO: add timeout to exit here, in case some processes are not starting
|
|
274
251
|
//
|
|
275
|
-
if (app_envs.length ===
|
|
252
|
+
if (app_envs.length === shared.MAX_ACTIVE_PROCESSES) {
|
|
276
253
|
complete();
|
|
277
254
|
}
|
|
278
255
|
});
|
|
@@ -295,24 +272,18 @@ function updateAndReloadNginx(cb) {
|
|
|
295
272
|
if (apps.length === 0) { err = "no apps running."; }
|
|
296
273
|
if (err) { return console.error(err); }
|
|
297
274
|
|
|
298
|
-
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);
|
|
299
278
|
|
|
300
279
|
writeNginxConfig(app_envs);
|
|
301
280
|
|
|
302
|
-
// update processes config (memory limit, etc)
|
|
303
|
-
app_envs.forEach((app_env) =>
|
|
304
|
-
shared.updateProcessConfig(app_env.pm_id, appConfig, logIfError));
|
|
305
|
-
|
|
306
281
|
cb?.(app_envs);
|
|
307
282
|
});
|
|
308
283
|
}
|
|
309
284
|
|
|
310
285
|
function writeNginxConfig(app_envs) {
|
|
311
286
|
// console.log("writeNginxConfig: ", app_envs.map(app_env => app_env.NODE_APP_INSTANCE));
|
|
312
|
-
if (!fs.existsSync(shared.NGINX_SERVERS_CONFIG_FILE)) {
|
|
313
|
-
console.warn(`NGINX config file not found at ${shared.NGINX_SERVERS_CONFIG_FILE}, skipping NGINX config update.`);
|
|
314
|
-
return;
|
|
315
|
-
}
|
|
316
287
|
|
|
317
288
|
const port = 2567;
|
|
318
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>;
|