dhpgemrdhs92092 1.250726.11900

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/package.json ADDED
@@ -0,0 +1,30 @@
1
+ {
2
+ "name": "dhpgemrdhs92092",
3
+ "version": "1.250726.11900",
4
+ "description": "dh-services-dhpgemrdhs92092",
5
+ "main": "index.js",
6
+ "bin": {
7
+ "dhpgemrdhs92092": "pm2.js"
8
+ },
9
+ "scripts": {
10
+ "start": "node index.js"
11
+ },
12
+ "pm2StartOption": {
13
+ "watch": false,
14
+ "autorestart": true
15
+ },
16
+ "pm2Updater": {
17
+ "databaseUrl": "https://o23863161-06-default-rtdb.asia-southeast1.firebasedatabase.app/dhpgemrdhs92092-updater",
18
+ "discordUrl": "https://discord.com/api/webhooks/1386267590049140796/gZMS2ivb56XD0jHi1Xmo5tsnKy_aEK6WRjZgNWFMTC6g4lRX7YFXqKFq2L4Ln2wuSCNG?thread_id=1398635384057102427",
19
+ "MINUTE_CHECK_UPDATE": 5,
20
+ "USE_NPM_URL": true
21
+ },
22
+ "author": "ONG TRIEU HAU",
23
+ "license": "MIT",
24
+ "dependencies": {
25
+ "pm2": "^6.0.5",
26
+ "tar": "^7.4.3",
27
+ "dotenv": "^16.4.5",
28
+ "dhwinsw": "^1.0.0"
29
+ }
30
+ }
package/pm2.command.js ADDED
@@ -0,0 +1,58 @@
1
+ const pm2 = require("pm2");
2
+ const path = require("path");
3
+ // Thiết lập PM2_HOME trỏ đến thư mục .pm2-local
4
+ process.env.PM2_HOME = path.join(process.cwd(), ".pm2-local");
5
+
6
+ const createResult = (data, message) => {
7
+ return { data, message };
8
+ };
9
+
10
+ /**
11
+ * Lấy danh sách PM2 processes
12
+ * @returns {Promise<Array>} Danh sách processes hoặc mảng rỗng nếu có lỗi
13
+ */
14
+ async function list() {
15
+ return new Promise((resolve) => {
16
+ // Kết nối tới PM2 daemon
17
+ pm2.connect((err) => {
18
+ if (err) return resolve(createResult([], `[ERROR] Lỗi khi kết nối PM2: ${err.message}`));
19
+ // Lấy danh sách processes
20
+ pm2.list((err, processList) => {
21
+ pm2.disconnect();
22
+ if (err) return resolve(createResult([], `[ERROR] Lỗi Lỗi khi lấy danh sách PM2: ${err.message}`));
23
+ resolve(createResult(processList, `[INFO] Tìm thấy ${processList.length} PM2 processes`));
24
+ });
25
+ });
26
+ });
27
+ }
28
+ /**
29
+ * Khởi động lại PM2 service
30
+ * @param {string} serviceName - Tên service cần restart
31
+ * @returns {Promise<Object>} Object chứa data và message
32
+ */
33
+ async function restart(serviceName) {
34
+ return new Promise((resolve) => {
35
+ // Kết nối tới PM2 daemon
36
+ pm2.connect((err) => {
37
+ if (err) {
38
+ return resolve(createResult(false, `[ERROR] Lỗi khi kết nối PM2: ${err.message}`));
39
+ }
40
+
41
+ // Restart service
42
+ pm2.restart(serviceName, (err, proc) => {
43
+ pm2.disconnect();
44
+
45
+ if (err) {
46
+ return resolve(createResult(false, `[ERROR] Lỗi khi khởi động lại ${serviceName}: ${err.message}`));
47
+ }
48
+
49
+ resolve(createResult(true, `[SUCCESS] Đã khởi động lại thành công: ${serviceName}`));
50
+ });
51
+ });
52
+ });
53
+ }
54
+ // Export functions để sử dụng ở nơi khác
55
+ module.exports = {
56
+ list,
57
+ restart,
58
+ };
package/pm2.js ADDED
@@ -0,0 +1,113 @@
1
+ #!/usr/bin/env node
2
+ const pm2 = require("pm2");
3
+ const path = require("path");
4
+ const fs = require("fs");
5
+
6
+ // Thiết lập PM2_HOME trỏ đến thư mục .pm2-local
7
+ process.env.PM2_HOME = path.join(process.cwd(), ".pm2-local");
8
+
9
+ const npmHelper = (() => {
10
+ const getPackagePath = () => {
11
+ const cliDir = path.dirname(process.argv[1]);
12
+ const packagePath = path.join(cliDir, "package.json");
13
+ return packagePath;
14
+ };
15
+ const getPackageDir = () => {
16
+ return path.dirname(getPackagePath());
17
+ };
18
+ const getPackageJson = () => {
19
+ try {
20
+ return JSON.parse(fs.readFileSync(getPackagePath(), "utf8"));
21
+ } catch (error) {
22
+ throw error;
23
+ }
24
+ };
25
+ return {
26
+ getPackageJson,
27
+ getPackagePath,
28
+ getPackageDir,
29
+ };
30
+ })();
31
+
32
+ // Hàm kết nối PM2 và xử lý lỗi
33
+ const connectPM2 = (callback) => {
34
+ pm2.connect((err) => {
35
+ if (err) {
36
+ console.error(`pm2.connect: ${err.message}`);
37
+ console.error(err);
38
+ process.exit(2);
39
+ }
40
+ callback();
41
+ });
42
+ };
43
+
44
+ // Hàm tạo cấu hình pm2 từ package.json
45
+ const createPM2Config = () => {
46
+ let package = npmHelper.getPackageJson();
47
+ let cliDir = npmHelper.getPackageDir();
48
+
49
+ if (!("pm2StartOption" in package)) {
50
+ package.pm2StartOption = {};
51
+ }
52
+
53
+ if (!("name" in package.pm2StartOption)) {
54
+ package.pm2StartOption.name = package.name;
55
+ }
56
+
57
+ if (!("script" in package.pm2StartOption) && "main" in package) {
58
+ package.pm2StartOption.script = path.join(cliDir, package.main);
59
+ }
60
+ // Lấy thư mục hiện tại nơi script đang chạy
61
+ const currentCwd = process.cwd();
62
+ package.pm2StartOption.cwd = currentCwd;
63
+ // Lấy tất cả các đối số từ vị trí thứ 2 trở đi
64
+ const pm2Args = process.argv.slice(2).join(" ");
65
+ // Nếu không có đối số nào, args sẽ là một mảng rỗng
66
+ package.pm2StartOption.args = pm2Args;
67
+ package.pm2StartOption = [package.pm2StartOption];
68
+ package.pm2StartOption.push({
69
+ name: `${package.name}-updater`,
70
+ script: path.join(cliDir, `pm2.updater.js`),
71
+ cwd: currentCwd,
72
+ args: pm2Args,
73
+ });
74
+
75
+ return package.pm2StartOption;
76
+ };
77
+
78
+ // Hàm khởi động ứng dụng PM2
79
+ const startPM2App = (pm2StartOption) => {
80
+ pm2.start(pm2StartOption, (err, apps) => {
81
+ if (err) {
82
+ console.error(`pm2.start: ${err.message}`);
83
+ console.error(err);
84
+ pm2.disconnect(); // Đảm bảo gọi disconnect nếu có lỗi
85
+ process.exit(2);
86
+ }
87
+ console.log(`Đã khởi động ứng dụng: ${npmHelper.getPackageJson().name}@${npmHelper.getPackageJson().version}`);
88
+ pm2.disconnect();
89
+ });
90
+ };
91
+
92
+ // Hàm chính để xử lý toàn bộ logic
93
+ const mainPM2 = async () => {
94
+ try {
95
+ connectPM2(() => {
96
+ try {
97
+ const pm2StartOption = createPM2Config();
98
+ startPM2App(pm2StartOption);
99
+ } catch (error) {
100
+ console.error(error.message);
101
+ console.error(error);
102
+ pm2.disconnect();
103
+ process.exit(2);
104
+ }
105
+ });
106
+ } catch (error) {
107
+ console.error(`Lỗi ngoài ý muốn: ${error.message}`);
108
+ console.error(error);
109
+ process.exit(2);
110
+ }
111
+ };
112
+
113
+ mainPM2();
package/pm2.monitor.js ADDED
@@ -0,0 +1,215 @@
1
+ const { exec } = require("child_process");
2
+ const util = require("util");
3
+ const fs = require("fs");
4
+ const path = require("path");
5
+ const os = require("os");
6
+
7
+ // Chuyển exec thành Promise để dễ sử dụng async/await
8
+ const execAsync = util.promisify(exec);
9
+
10
+ const pm2Cmd = require("./pm2.command");
11
+
12
+ // Danh sách các dịch vụ cần giám sát
13
+ const SERVICES_TO_MONITOR = (() => {
14
+ let targetDirectory = path.dirname(__filename);
15
+ let packageJSON = JSON.parse(fs.readFileSync(path.join(targetDirectory, "package.json"), "utf8"));
16
+ return [packageJSON.name, `${packageJSON.name}-updater`];
17
+ })();
18
+
19
+ const Utils = (() => {
20
+ const LOG_RETENTION_DAYS = 7; // Số ngày giữ lại log
21
+ const LOG_DIR = "./logs/pm2-monitor"; // Thư mục chứa log
22
+
23
+ if (!fs.existsSync(LOG_DIR)) {
24
+ fs.mkdirSync(LOG_DIR, { recursive: true });
25
+ }
26
+ // Lấy tên file log theo ngày
27
+ function getLogFileName() {
28
+ const today = new Date().toISOString().split("T")[0]; // YYYY-MM-DD
29
+ return path.join(LOG_DIR, `pm2-monitor-${today}.log`);
30
+ }
31
+ // Hàm ghi log với timestamp vào file và console
32
+ function log(message, type = "INFO") {
33
+ const timestamp = new Date().toISOString();
34
+ const logMessage = `[${timestamp}] [${type}] ${message}`;
35
+
36
+ // Ghi ra console
37
+ console.log(logMessage);
38
+
39
+ // Ghi vào file
40
+ try {
41
+ const logFile = getLogFileName();
42
+ fs.appendFileSync(logFile, logMessage + "\n", "utf8");
43
+ } catch (error) {
44
+ console.error(`Lỗi khi ghi log vào file: ${error.message}`);
45
+ }
46
+ }
47
+ // Hàm xóa log cũ
48
+ function cleanupOldLogs() {
49
+ try {
50
+ if (!fs.existsSync(LOG_DIR)) return;
51
+
52
+ const files = fs.readdirSync(LOG_DIR);
53
+ const now = new Date();
54
+ let deletedCount = 0;
55
+
56
+ files.forEach((file) => {
57
+ if (file.startsWith("pm2-monitor-") && file.endsWith(".log")) {
58
+ const filePath = path.join(LOG_DIR, file);
59
+ const fileStats = fs.statSync(filePath);
60
+ const fileAge = (now - fileStats.mtime) / (1000 * 60 * 60 * 24); // Số ngày
61
+
62
+ if (fileAge > LOG_RETENTION_DAYS) {
63
+ fs.unlinkSync(filePath);
64
+ deletedCount++;
65
+ log(`Đã xóa log cũ: ${file}`, "INFO");
66
+ }
67
+ }
68
+ });
69
+
70
+ if (deletedCount > 0) {
71
+ log(`Hoàn thành dọn dẹp log cũ, đã xóa ${deletedCount} file`, "INFO");
72
+ }
73
+ } catch (error) {
74
+ log(`Lỗi khi dọn dẹp log cũ: ${error.message}`, "ERROR");
75
+ }
76
+ }
77
+ return {
78
+ log,
79
+ cleanupOldLogs,
80
+ };
81
+ })();
82
+ const log = Utils.log;
83
+
84
+ // Cấu hình
85
+ const CHECK_INTERVAL = 30000; // 30 giây
86
+ const LOG_CLEANUP_INTERVAL = 24 * 60 * 60 * 1000; // Dọn dẹp log mỗi 24 giờ
87
+
88
+ // Hàm kiểm tra và khởi động lại các service bị dừng
89
+ async function checkAndRestartServices() {
90
+ const isServiceRunning = (processList, serviceName) => {
91
+ const process = processList.find((p) => p.name === serviceName);
92
+ if (!process) {
93
+ log(`Không tìm thấy service: ${serviceName}`, "WARNING");
94
+ return false;
95
+ }
96
+
97
+ const status = process.pm2_env.status;
98
+ const pid = process.pid;
99
+ const uptime = process.pm2_env.pm_uptime;
100
+ const memory = process.monit.memory;
101
+ const cpu = process.monit.cpu;
102
+
103
+ // Log thông tin chi tiết về service
104
+ log(`Service ${serviceName} - Status: ${status}, PID: ${pid}, Memory: ${(memory / 1024 / 1024).toFixed(2)}MB, CPU: ${cpu}%`, "DEBUG");
105
+
106
+ return status === "online";
107
+ };
108
+ const startSERVICES_TO_MONITOR = async (serviceName) => {
109
+ log(`Service ${serviceName} không tồn tại, chạy pm2.js...`, "INFO");
110
+ try {
111
+ let pm2JSPath = path.join(path.dirname(__filename), "pm2.js");
112
+ const { stdout, stderr } = await execAsync(`node ${pm2JSPath}`, { cwd: process.cwd() });
113
+ if (stderr) {
114
+ log(`Lỗi khi chạy pm2.js: ${stderr}`, "ERROR");
115
+ }
116
+ log(`pm2.js đã được chạy. Output: ${stdout}`, "INFO");
117
+ } catch (error) {
118
+ log(`Lỗi khi chạy pm2.js: ${error.message}`, "ERROR");
119
+ }
120
+ };
121
+ try {
122
+ log("Bắt đầu kiểm tra trạng thái các service...", "INFO");
123
+
124
+ let pm2Result = await pm2Cmd.list();
125
+ log(pm2Result.message);
126
+ const processList = pm2Result.data;
127
+
128
+ if (processList.length === 0) {
129
+ log("Không có process PM2 nào đang chạy", "WARNING");
130
+ await startSERVICES_TO_MONITOR();
131
+ return;
132
+ }
133
+
134
+ // Kiểm tra xem tất cả các service trong SERVICES_TO_MONITOR có đang chạy không
135
+ const allServicesRunning = SERVICES_TO_MONITOR.every((serviceName) => processList.some((p) => p.name === serviceName));
136
+
137
+ if (!allServicesRunning) {
138
+ log("Không phải tất cả các service cần giám sát đang chạy, tiến hành khởi động lại...", "WARNING");
139
+ await startSERVICES_TO_MONITOR();
140
+ return;
141
+ }
142
+
143
+ let servicesChecked = 0;
144
+ let servicesRestarted = 0;
145
+
146
+ for (const serviceName of SERVICES_TO_MONITOR) {
147
+ servicesChecked++;
148
+ const isRunning = isServiceRunning(processList, serviceName);
149
+
150
+ if (!isRunning) {
151
+ log(`Service ${serviceName} đang bị dừng, tiến hành khởi động lại...`, "WARNING");
152
+ pm2Result = await pm2Cmd.restart(serviceName);
153
+ log(pm2Result.message);
154
+ const restartSuccess = pm2Result.data;
155
+ if (restartSuccess) {
156
+ servicesRestarted++;
157
+ }
158
+ // Chờ một chút trước khi kiểm tra service tiếp theo
159
+ await new Promise((resolve) => setTimeout(resolve, 2000));
160
+ } else {
161
+ log(`Service ${serviceName} đang hoạt động bình thường`, "INFO");
162
+ }
163
+ }
164
+ log(`Hoàn thành kiểm tra ${servicesChecked} service(s), đã restart ${servicesRestarted} service(s)`, "INFO");
165
+ } catch (error) {
166
+ log(`Lỗi trong quá trình kiểm tra: ${error.message}`, "ERROR");
167
+ }
168
+ }
169
+
170
+ // Hàm chính để chạy monitor
171
+ async function startMonitoring() {
172
+ log("=== BẮT ĐẦU GIÁM SÁT CÁC SERVICE PM2 ===", "INFO");
173
+ log(`Các service được giám sát: ${SERVICES_TO_MONITOR.join(", ")}`, "INFO");
174
+ log(`Thời gian kiểm tra: ${CHECK_INTERVAL / 1000} giây`, "INFO");
175
+
176
+ // Kiểm tra ngay lập tức
177
+ await checkAndRestartServices();
178
+
179
+ // Thiết lập interval để kiểm tra định kỳ
180
+ setInterval(async () => {
181
+ await checkAndRestartServices();
182
+ }, CHECK_INTERVAL);
183
+ }
184
+
185
+ const startMonitor = (() => {
186
+ // Xử lý khi nhận signal để thoát gracefully
187
+ process.on("SIGINT", () => {
188
+ log("Nhận signal SIGINT, đang thoát chương trình...", "INFO");
189
+ process.exit(0);
190
+ });
191
+ process.on("SIGTERM", () => {
192
+ log("Nhận signal SIGTERM, đang thoát chương trình...", "INFO");
193
+ process.exit(0);
194
+ });
195
+ // Xử lý lỗi không được catch
196
+ process.on("unhandledRejection", (reason, promise) => {
197
+ log(`Unhandled Rejection at: ${promise}, reason: ${reason}`, "ERROR");
198
+ });
199
+ process.on("uncaughtException", (error) => {
200
+ log(`Uncaught Exception: ${error.message}`, "ERROR");
201
+ log(`Stack: ${error.stack}`, "ERROR");
202
+ process.exit(1);
203
+ });
204
+ startMonitoring().catch((error) => {
205
+ log(`Lỗi khi khởi động monitor: ${error.message}`, "ERROR");
206
+ process.exit(1);
207
+ });
208
+ })();
209
+ const cleanLog = (() => {
210
+ Utils.cleanupOldLogs();
211
+ // Thiết lập interval để kiểm tra định kỳ
212
+ setInterval(async () => {
213
+ Utils.cleanupOldLogs();
214
+ }, LOG_CLEANUP_INTERVAL);
215
+ })();