ezpm2gui 1.1.0 → 1.2.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/dist/server/config/project-configs.json +236 -0
- package/dist/server/index.js +30 -5
- package/dist/server/logs/deployment.log +12 -0
- package/dist/server/routes/deployApplication.js +174 -27
- package/dist/server/routes/logStreaming.js +174 -0
- package/dist/server/routes/remoteConnections.d.ts +3 -0
- package/dist/server/routes/remoteConnections.js +634 -0
- package/dist/server/services/ProjectSetupService.d.ts +72 -0
- package/dist/server/services/ProjectSetupService.js +327 -0
- package/dist/server/utils/dialog.d.ts +1 -0
- package/dist/server/utils/dialog.js +16 -0
- package/dist/server/utils/encryption.d.ts +12 -0
- package/dist/server/utils/encryption.js +72 -0
- package/dist/server/utils/remote-connection.d.ts +152 -0
- package/dist/server/utils/remote-connection.js +590 -0
- package/dist/server/utils/upload.d.ts +3 -0
- package/dist/server/utils/upload.js +39 -0
- package/package.json +65 -63
- package/src/client/build/asset-manifest.json +3 -3
- package/src/client/build/favicon.ico +2 -0
- package/src/client/build/index.html +1 -1
- package/src/client/build/logo192.svg +7 -0
- package/src/client/build/logo512.svg +7 -0
- package/src/client/build/manifest.json +5 -6
- package/src/client/build/static/js/{main.1d7f99ff.js → main.31323a04.js} +13 -13
- package/src/client/build/static/js/main.31323a04.js.map +1 -0
- package/src/client/build/static/js/main.1d7f99ff.js.map +0 -1
- /package/src/client/build/static/js/{main.1d7f99ff.js.LICENSE.txt → main.31323a04.js.LICENSE.txt} +0 -0
|
@@ -8,9 +8,11 @@ const express_1 = require("express");
|
|
|
8
8
|
const pm2_1 = __importDefault(require("pm2"));
|
|
9
9
|
const fs_1 = __importDefault(require("fs"));
|
|
10
10
|
const child_process_1 = require("child_process");
|
|
11
|
+
const remote_connection_1 = require("../utils/remote-connection");
|
|
11
12
|
const router = (0, express_1.Router)();
|
|
12
13
|
// This variable will hold references to active log streams
|
|
13
14
|
const activeStreams = {};
|
|
15
|
+
const activeRemoteStreams = {};
|
|
14
16
|
// Get active stream (or create a new one)
|
|
15
17
|
const getLogStream = (io, processId, logType) => {
|
|
16
18
|
const streamKey = `${processId}-${logType}`;
|
|
@@ -57,6 +59,137 @@ const getLogStream = (io, processId, logType) => {
|
|
|
57
59
|
});
|
|
58
60
|
});
|
|
59
61
|
};
|
|
62
|
+
// Get remote log stream (or create a new one)
|
|
63
|
+
const getRemoteLogStream = async (io, connectionId, processId) => {
|
|
64
|
+
const streamKey = `${connectionId}-${processId}`;
|
|
65
|
+
// If stream already exists, return it
|
|
66
|
+
if (activeRemoteStreams[streamKey]) {
|
|
67
|
+
return activeRemoteStreams[streamKey];
|
|
68
|
+
}
|
|
69
|
+
const connection = remote_connection_1.remoteConnectionManager.getConnection(connectionId);
|
|
70
|
+
if (!connection || !connection.isConnected()) {
|
|
71
|
+
throw new Error('Connection not found or not connected');
|
|
72
|
+
}
|
|
73
|
+
// Get process info to find log paths
|
|
74
|
+
console.log(`Getting process info for: ${processId}`);
|
|
75
|
+
const processInfoResult = await connection.executeCommand(`pm2 jlist`, false); // Don't use sudo for listing
|
|
76
|
+
if (processInfoResult.code !== 0) {
|
|
77
|
+
throw new Error(`Failed to get process list: ${processInfoResult.stderr}`);
|
|
78
|
+
}
|
|
79
|
+
let processInfo;
|
|
80
|
+
try {
|
|
81
|
+
const processList = JSON.parse(processInfoResult.stdout);
|
|
82
|
+
console.log(`Found ${processList.length} processes`);
|
|
83
|
+
// Find the process by ID
|
|
84
|
+
processInfo = processList.find((proc) => proc.pm_id === parseInt(processId));
|
|
85
|
+
if (!processInfo) {
|
|
86
|
+
throw new Error(`Process with ID ${processId} not found`);
|
|
87
|
+
}
|
|
88
|
+
console.log(`Found process: ${processInfo.name} (ID: ${processInfo.pm_id})`);
|
|
89
|
+
}
|
|
90
|
+
catch (parseError) {
|
|
91
|
+
console.error('Parse error:', parseError);
|
|
92
|
+
throw new Error(`Failed to parse process list: ${parseError}`);
|
|
93
|
+
}
|
|
94
|
+
const processName = processInfo.name;
|
|
95
|
+
// Create streams using pm2 logs instead of tail for better permission handling
|
|
96
|
+
const streams = {};
|
|
97
|
+
try {
|
|
98
|
+
console.log(`Setting up pm2 logs stream for process: ${processName} (ID: ${processId})`);
|
|
99
|
+
// Use pm2 logs with --lines 0 --raw to stream only new logs
|
|
100
|
+
// Use sudo since PM2 processes are running as root
|
|
101
|
+
const pm2LogsCommand = `pm2 logs ${processId} --lines 0 --raw`;
|
|
102
|
+
console.log(`About to create pm2 log stream with command: ${pm2LogsCommand} (using sudo)`);
|
|
103
|
+
const logStream = await connection.createLogStream(pm2LogsCommand, true);
|
|
104
|
+
console.log(`Successfully created pm2 logs stream for ${processName}`);
|
|
105
|
+
logStream.on('data', (data) => {
|
|
106
|
+
console.log(`Raw pm2 logs data received for ${processName}:`, data);
|
|
107
|
+
const lines = data.toString().split('\n').filter((line) => line.trim() !== '');
|
|
108
|
+
lines.forEach((line) => {
|
|
109
|
+
// Skip PM2 startup messages, system messages, and errors
|
|
110
|
+
if (line.trim() === '' ||
|
|
111
|
+
line.includes('PM2') ||
|
|
112
|
+
line.includes('---') ||
|
|
113
|
+
line.includes('watching') ||
|
|
114
|
+
line.includes('change detected') ||
|
|
115
|
+
line.includes('Runtime Edition') ||
|
|
116
|
+
line.includes('Production Process Manager') ||
|
|
117
|
+
line.includes('built-in Load Balancer') ||
|
|
118
|
+
line.includes('$ pm2') ||
|
|
119
|
+
line.includes('http://pm2.io') ||
|
|
120
|
+
line.includes('Start and Daemonize') ||
|
|
121
|
+
line.includes('Load Balance') ||
|
|
122
|
+
line.includes('Monitor in production') ||
|
|
123
|
+
line.includes('Make pm2 auto-boot') ||
|
|
124
|
+
line.includes('To go further') ||
|
|
125
|
+
line.includes('ENOENT') ||
|
|
126
|
+
line.includes('module_conf.json') ||
|
|
127
|
+
line.includes('pm2.log') ||
|
|
128
|
+
line.includes('node:fs:') ||
|
|
129
|
+
line.includes('at Object.') ||
|
|
130
|
+
line.includes('at Client.') ||
|
|
131
|
+
line.includes('at processTicksAndRejections') ||
|
|
132
|
+
line.includes('errno:') ||
|
|
133
|
+
line.includes('syscall:') ||
|
|
134
|
+
line.includes('Node.js v') ||
|
|
135
|
+
line.startsWith(' at ') ||
|
|
136
|
+
line.match(/^\s*\^?\s*$/) ||
|
|
137
|
+
line.match(/^[\s_\/\\|]+$/)) {
|
|
138
|
+
console.log(`Skipping PM2 system/error line: "${line}"`);
|
|
139
|
+
return;
|
|
140
|
+
}
|
|
141
|
+
// Parse PM2 log format: timestamp | app-name | message
|
|
142
|
+
// PM2 logs typically come in format like: "2023-01-01T12:00:00: PM2 log: [TAILING]"
|
|
143
|
+
// or just the raw log content depending on version
|
|
144
|
+
let logType = 'stdout'; // Default to stdout
|
|
145
|
+
let cleanLine = line;
|
|
146
|
+
// Try to detect if this is stderr (PM2 usually prefixes with different indicators)
|
|
147
|
+
if (line.includes('ERROR') || line.includes('error') || line.includes('stderr')) {
|
|
148
|
+
logType = 'stderr';
|
|
149
|
+
}
|
|
150
|
+
// Clean up the line by removing PM2 prefixes if present
|
|
151
|
+
// PM2 log format can vary, but often includes timestamps and app names
|
|
152
|
+
const logMatch = line.match(/^.*?\|\s*(.+)$/);
|
|
153
|
+
if (logMatch) {
|
|
154
|
+
cleanLine = logMatch[1];
|
|
155
|
+
}
|
|
156
|
+
console.log(`Emitting remote-log-line for ${connectionId}-${processId} (${logType}):`, cleanLine);
|
|
157
|
+
io.emit('remote-log-line', {
|
|
158
|
+
connectionId,
|
|
159
|
+
processId,
|
|
160
|
+
processName,
|
|
161
|
+
logType,
|
|
162
|
+
line: cleanLine
|
|
163
|
+
});
|
|
164
|
+
});
|
|
165
|
+
});
|
|
166
|
+
logStream.on('error', (error) => {
|
|
167
|
+
console.error(`Error in pm2 logs stream for ${processName}:`, error);
|
|
168
|
+
io.emit('remote-log-error', {
|
|
169
|
+
connectionId,
|
|
170
|
+
processId,
|
|
171
|
+
processName,
|
|
172
|
+
error: error.message
|
|
173
|
+
});
|
|
174
|
+
});
|
|
175
|
+
logStream.on('close', (code) => {
|
|
176
|
+
console.log(`PM2 logs stream closed for ${processName} with code:`, code);
|
|
177
|
+
});
|
|
178
|
+
streams.combined = logStream;
|
|
179
|
+
}
|
|
180
|
+
catch (error) {
|
|
181
|
+
console.error(`Failed to create pm2 logs stream for ${processName}:`, error);
|
|
182
|
+
io.emit('remote-log-error', {
|
|
183
|
+
connectionId,
|
|
184
|
+
processId,
|
|
185
|
+
processName,
|
|
186
|
+
error: `Failed to start log streaming: ${error}`
|
|
187
|
+
});
|
|
188
|
+
}
|
|
189
|
+
// Store the streams
|
|
190
|
+
activeRemoteStreams[streamKey] = streams;
|
|
191
|
+
return streams;
|
|
192
|
+
};
|
|
60
193
|
// Setup socket.io handlers for log streaming
|
|
61
194
|
const setupLogStreaming = (io) => {
|
|
62
195
|
io.on('connection', (socket) => {
|
|
@@ -95,6 +228,47 @@ const setupLogStreaming = (io) => {
|
|
|
95
228
|
// Cleanup on disconnect
|
|
96
229
|
socket.on('disconnect', () => {
|
|
97
230
|
console.log('Client disconnected from log streaming');
|
|
231
|
+
}); // Subscribe to remote log stream
|
|
232
|
+
socket.on('subscribe-remote-logs', async ({ connectionId, processId }) => {
|
|
233
|
+
try {
|
|
234
|
+
console.log(`Subscribing to remote logs - Connection: ${connectionId}, Process: ${processId}`);
|
|
235
|
+
const streamKey = `${connectionId}-${processId}`;
|
|
236
|
+
// Add socket to a room for this specific log stream
|
|
237
|
+
socket.join(streamKey);
|
|
238
|
+
console.log(`Client subscribed to remote logs: ${streamKey}`);
|
|
239
|
+
// Get or create the remote log stream
|
|
240
|
+
await getRemoteLogStream(io, connectionId, processId);
|
|
241
|
+
}
|
|
242
|
+
catch (error) {
|
|
243
|
+
console.error('Error subscribing to remote logs:', error);
|
|
244
|
+
socket.emit('remote-log-error', {
|
|
245
|
+
connectionId,
|
|
246
|
+
processId,
|
|
247
|
+
error: error instanceof Error ? error.message : 'Unknown error'
|
|
248
|
+
});
|
|
249
|
+
}
|
|
250
|
+
});
|
|
251
|
+
// Unsubscribe from remote log stream
|
|
252
|
+
socket.on('unsubscribe-remote-logs', ({ connectionId, processId }) => {
|
|
253
|
+
const streamKey = `${connectionId}-${processId}`;
|
|
254
|
+
// Remove socket from the room
|
|
255
|
+
socket.leave(streamKey);
|
|
256
|
+
console.log(`Client unsubscribed from remote logs: ${streamKey}`);
|
|
257
|
+
// If no more clients in this room, stop the streams
|
|
258
|
+
const room = io.sockets.adapter.rooms.get(streamKey);
|
|
259
|
+
if (!room || room.size === 0) {
|
|
260
|
+
const streams = activeRemoteStreams[streamKey];
|
|
261
|
+
if (streams) {
|
|
262
|
+
console.log(`Stopping remote log streams: ${streamKey}`);
|
|
263
|
+
if (streams.stdout && streams.stdout.kill) {
|
|
264
|
+
streams.stdout.kill();
|
|
265
|
+
}
|
|
266
|
+
if (streams.stderr && streams.stderr.kill) {
|
|
267
|
+
streams.stderr.kill();
|
|
268
|
+
}
|
|
269
|
+
delete activeRemoteStreams[streamKey];
|
|
270
|
+
}
|
|
271
|
+
}
|
|
98
272
|
});
|
|
99
273
|
});
|
|
100
274
|
};
|