@imenam/self-register-proxy 1.0.46 → 1.0.48
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/README.md +6 -0
- package/config.js +72 -72
- package/meta-config.js +336 -336
- package/package.json +2 -3
- package/routes/metaConfig.js +180 -180
- package/routes/registration.js +240 -240
- package/services/healthCheck.js +95 -95
- package/services/portManager.js +137 -137
- package/services/proxyRouter.js +99 -99
- package/services/registry.js +41 -41
- package/terminal-server.js +154 -154
package/terminal-server.js
CHANGED
|
@@ -1,154 +1,154 @@
|
|
|
1
|
-
const os = require('os');
|
|
2
|
-
const { execSync } = require('child_process');
|
|
3
|
-
const pty = require('node-pty');
|
|
4
|
-
const { WebSocketServer } = require('ws');
|
|
5
|
-
|
|
6
|
-
const DEFAULT_SHELL = os.platform() === 'win32' ? 'powershell.exe' : 'bash';
|
|
7
|
-
|
|
8
|
-
class TerminalServer {
|
|
9
|
-
/**
|
|
10
|
-
* @param {import('http').Server} httpServer
|
|
11
|
-
* @param {object} [options]
|
|
12
|
-
* @param {string} [options.shell] - Shell to spawn (default: auto-detected)
|
|
13
|
-
* @param {string[]} [options.shellArgs] - Shell arguments (default: [])
|
|
14
|
-
* @param {object} [options.ptyOptions] - node-pty spawn options overrides
|
|
15
|
-
* @param {number} [options.ptyOptions.cols] - Initial columns (default: 80)
|
|
16
|
-
* @param {number} [options.ptyOptions.rows] - Initial rows (default: 24)
|
|
17
|
-
* @param {string} [options.ptyOptions.cwd] - Working directory (default: user home)
|
|
18
|
-
* @param {object} [options.ptyOptions.env] - Environment variables (default: process.env)
|
|
19
|
-
* @param {string} [options.command] - Command to execute automatically after spawn
|
|
20
|
-
* @param {string} [options.path] - WebSocket endpoint path (default: '/terminal')
|
|
21
|
-
* @param {object} [options.wsOptions] - WebSocketServer options overrides
|
|
22
|
-
*/
|
|
23
|
-
constructor(httpServer, options = {}) {
|
|
24
|
-
this.shell = options.shell || DEFAULT_SHELL;
|
|
25
|
-
this.shellArgs = options.shellArgs || [];
|
|
26
|
-
this.command = options.command || '';
|
|
27
|
-
this.ptyOptions = {
|
|
28
|
-
name: 'xterm-color',
|
|
29
|
-
cols: 80,
|
|
30
|
-
rows: 24,
|
|
31
|
-
cwd: process.env.HOME || process.env.USERPROFILE,
|
|
32
|
-
env: process.env,
|
|
33
|
-
...options.ptyOptions,
|
|
34
|
-
};
|
|
35
|
-
|
|
36
|
-
this.connections = new Set();
|
|
37
|
-
|
|
38
|
-
this.wss = new WebSocketServer({
|
|
39
|
-
server: httpServer,
|
|
40
|
-
path: options.path || '/terminal',
|
|
41
|
-
...options.wsOptions,
|
|
42
|
-
});
|
|
43
|
-
this.wss.on('connection', (ws, req) => this._handleConnection(ws, req));
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
_handleConnection(ws, req) {
|
|
47
|
-
const cwd = this.ptyOptions.cwd;
|
|
48
|
-
|
|
49
|
-
let ptyProcess;
|
|
50
|
-
try {
|
|
51
|
-
ptyProcess = pty.spawn(this.shell, this.shellArgs, {
|
|
52
|
-
...this.ptyOptions,
|
|
53
|
-
cwd,
|
|
54
|
-
});
|
|
55
|
-
} catch (err) {
|
|
56
|
-
console.error(`[TERMINAL] Failed to spawn PTY (cwd: ${cwd}):`, err.message);
|
|
57
|
-
ws.close(1011, 'Failed to spawn terminal');
|
|
58
|
-
return;
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
const connection = { ws, ptyProcess };
|
|
62
|
-
this.connections.add(connection);
|
|
63
|
-
|
|
64
|
-
ptyProcess.onData((data) => {
|
|
65
|
-
try {
|
|
66
|
-
ws.send(data);
|
|
67
|
-
} catch (e) {
|
|
68
|
-
// WebSocket already closed
|
|
69
|
-
}
|
|
70
|
-
});
|
|
71
|
-
|
|
72
|
-
ws.on('message', (data) => {
|
|
73
|
-
const message = data.toString();
|
|
74
|
-
try {
|
|
75
|
-
const msg = JSON.parse(message);
|
|
76
|
-
if (msg.type === 'resize') {
|
|
77
|
-
ptyProcess.resize(msg.cols, msg.rows);
|
|
78
|
-
return;
|
|
79
|
-
}
|
|
80
|
-
} catch (e) {
|
|
81
|
-
// Not JSON, treat as terminal input
|
|
82
|
-
}
|
|
83
|
-
ptyProcess.write(message);
|
|
84
|
-
});
|
|
85
|
-
|
|
86
|
-
ws.on('close', () => {
|
|
87
|
-
this._gracefulKill(ptyProcess);
|
|
88
|
-
this.connections.delete(connection);
|
|
89
|
-
});
|
|
90
|
-
|
|
91
|
-
// Exécuter automatiquement la commande configurée
|
|
92
|
-
if (this.command) {
|
|
93
|
-
// Petit délai pour laisser le shell s'initialiser
|
|
94
|
-
setTimeout(() => {
|
|
95
|
-
ptyProcess.write(this.command + '\r');
|
|
96
|
-
console.log(`[TERMINAL] Auto-executed command: ${this.command}`);
|
|
97
|
-
}, 500);
|
|
98
|
-
}
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
/**
|
|
102
|
-
* Arrêt gracieux : envoie Ctrl+C deux fois pour interrompre proprement
|
|
103
|
-
* le programme en cours, attend qu'il se termine, puis tue le shell.
|
|
104
|
-
* @param {import('node-pty').IPty} ptyProcess
|
|
105
|
-
*/
|
|
106
|
-
_gracefulKill(ptyProcess) {
|
|
107
|
-
const pid = ptyProcess.pid;
|
|
108
|
-
console.log(`[TERMINAL] Graceful shutdown (PID: ${pid})...`);
|
|
109
|
-
|
|
110
|
-
// 1er Ctrl+C
|
|
111
|
-
try { ptyProcess.write('\x03'); } catch (_) { /* ignore */ }
|
|
112
|
-
|
|
113
|
-
setTimeout(() => {
|
|
114
|
-
// 2e Ctrl+C
|
|
115
|
-
try { ptyProcess.write('\x03'); } catch (_) { /* ignore */ }
|
|
116
|
-
|
|
117
|
-
setTimeout(() => {
|
|
118
|
-
// Tuer tout l'arbre de processus
|
|
119
|
-
this._killProcessTree(pid);
|
|
120
|
-
}, 1000);
|
|
121
|
-
}, 500);
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
/**
|
|
125
|
-
* Tue l'arbre de processus par PID.
|
|
126
|
-
* Sur Windows : taskkill /F /T /PID
|
|
127
|
-
* Sur Linux/macOS : kill du groupe de processus
|
|
128
|
-
* @param {number} pid
|
|
129
|
-
*/
|
|
130
|
-
_killProcessTree(pid) {
|
|
131
|
-
try {
|
|
132
|
-
if (os.platform() === 'win32') {
|
|
133
|
-
execSync(`taskkill /F /T /PID ${pid}`, { stdio: 'ignore' });
|
|
134
|
-
} else {
|
|
135
|
-
process.kill(-pid, 'SIGKILL');
|
|
136
|
-
}
|
|
137
|
-
console.log(`[TERMINAL] Killed process tree (PID: ${pid})`);
|
|
138
|
-
} catch (e) {
|
|
139
|
-
// Le processus est peut-être déjà terminé
|
|
140
|
-
console.log(`[TERMINAL] Process tree already exited (PID: ${pid})`);
|
|
141
|
-
}
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
dispose() {
|
|
145
|
-
for (const { ws, ptyProcess } of this.connections) {
|
|
146
|
-
this._gracefulKill(ptyProcess);
|
|
147
|
-
ws.close();
|
|
148
|
-
}
|
|
149
|
-
this.connections.clear();
|
|
150
|
-
this.wss.close();
|
|
151
|
-
}
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
module.exports = { TerminalServer };
|
|
1
|
+
const os = require('os');
|
|
2
|
+
const { execSync } = require('child_process');
|
|
3
|
+
const pty = require('node-pty');
|
|
4
|
+
const { WebSocketServer } = require('ws');
|
|
5
|
+
|
|
6
|
+
const DEFAULT_SHELL = os.platform() === 'win32' ? 'powershell.exe' : 'bash';
|
|
7
|
+
|
|
8
|
+
class TerminalServer {
|
|
9
|
+
/**
|
|
10
|
+
* @param {import('http').Server} httpServer
|
|
11
|
+
* @param {object} [options]
|
|
12
|
+
* @param {string} [options.shell] - Shell to spawn (default: auto-detected)
|
|
13
|
+
* @param {string[]} [options.shellArgs] - Shell arguments (default: [])
|
|
14
|
+
* @param {object} [options.ptyOptions] - node-pty spawn options overrides
|
|
15
|
+
* @param {number} [options.ptyOptions.cols] - Initial columns (default: 80)
|
|
16
|
+
* @param {number} [options.ptyOptions.rows] - Initial rows (default: 24)
|
|
17
|
+
* @param {string} [options.ptyOptions.cwd] - Working directory (default: user home)
|
|
18
|
+
* @param {object} [options.ptyOptions.env] - Environment variables (default: process.env)
|
|
19
|
+
* @param {string} [options.command] - Command to execute automatically after spawn
|
|
20
|
+
* @param {string} [options.path] - WebSocket endpoint path (default: '/terminal')
|
|
21
|
+
* @param {object} [options.wsOptions] - WebSocketServer options overrides
|
|
22
|
+
*/
|
|
23
|
+
constructor(httpServer, options = {}) {
|
|
24
|
+
this.shell = options.shell || DEFAULT_SHELL;
|
|
25
|
+
this.shellArgs = options.shellArgs || [];
|
|
26
|
+
this.command = options.command || '';
|
|
27
|
+
this.ptyOptions = {
|
|
28
|
+
name: 'xterm-color',
|
|
29
|
+
cols: 80,
|
|
30
|
+
rows: 24,
|
|
31
|
+
cwd: process.env.HOME || process.env.USERPROFILE,
|
|
32
|
+
env: process.env,
|
|
33
|
+
...options.ptyOptions,
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
this.connections = new Set();
|
|
37
|
+
|
|
38
|
+
this.wss = new WebSocketServer({
|
|
39
|
+
server: httpServer,
|
|
40
|
+
path: options.path || '/terminal',
|
|
41
|
+
...options.wsOptions,
|
|
42
|
+
});
|
|
43
|
+
this.wss.on('connection', (ws, req) => this._handleConnection(ws, req));
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
_handleConnection(ws, req) {
|
|
47
|
+
const cwd = this.ptyOptions.cwd;
|
|
48
|
+
|
|
49
|
+
let ptyProcess;
|
|
50
|
+
try {
|
|
51
|
+
ptyProcess = pty.spawn(this.shell, this.shellArgs, {
|
|
52
|
+
...this.ptyOptions,
|
|
53
|
+
cwd,
|
|
54
|
+
});
|
|
55
|
+
} catch (err) {
|
|
56
|
+
console.error(`[TERMINAL] Failed to spawn PTY (cwd: ${cwd}):`, err.message);
|
|
57
|
+
ws.close(1011, 'Failed to spawn terminal');
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
const connection = { ws, ptyProcess };
|
|
62
|
+
this.connections.add(connection);
|
|
63
|
+
|
|
64
|
+
ptyProcess.onData((data) => {
|
|
65
|
+
try {
|
|
66
|
+
ws.send(data);
|
|
67
|
+
} catch (e) {
|
|
68
|
+
// WebSocket already closed
|
|
69
|
+
}
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
ws.on('message', (data) => {
|
|
73
|
+
const message = data.toString();
|
|
74
|
+
try {
|
|
75
|
+
const msg = JSON.parse(message);
|
|
76
|
+
if (msg.type === 'resize') {
|
|
77
|
+
ptyProcess.resize(msg.cols, msg.rows);
|
|
78
|
+
return;
|
|
79
|
+
}
|
|
80
|
+
} catch (e) {
|
|
81
|
+
// Not JSON, treat as terminal input
|
|
82
|
+
}
|
|
83
|
+
ptyProcess.write(message);
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
ws.on('close', () => {
|
|
87
|
+
this._gracefulKill(ptyProcess);
|
|
88
|
+
this.connections.delete(connection);
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
// Exécuter automatiquement la commande configurée
|
|
92
|
+
if (this.command) {
|
|
93
|
+
// Petit délai pour laisser le shell s'initialiser
|
|
94
|
+
setTimeout(() => {
|
|
95
|
+
ptyProcess.write(this.command + '\r');
|
|
96
|
+
console.log(`[TERMINAL] Auto-executed command: ${this.command}`);
|
|
97
|
+
}, 500);
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* Arrêt gracieux : envoie Ctrl+C deux fois pour interrompre proprement
|
|
103
|
+
* le programme en cours, attend qu'il se termine, puis tue le shell.
|
|
104
|
+
* @param {import('node-pty').IPty} ptyProcess
|
|
105
|
+
*/
|
|
106
|
+
_gracefulKill(ptyProcess) {
|
|
107
|
+
const pid = ptyProcess.pid;
|
|
108
|
+
console.log(`[TERMINAL] Graceful shutdown (PID: ${pid})...`);
|
|
109
|
+
|
|
110
|
+
// 1er Ctrl+C
|
|
111
|
+
try { ptyProcess.write('\x03'); } catch (_) { /* ignore */ }
|
|
112
|
+
|
|
113
|
+
setTimeout(() => {
|
|
114
|
+
// 2e Ctrl+C
|
|
115
|
+
try { ptyProcess.write('\x03'); } catch (_) { /* ignore */ }
|
|
116
|
+
|
|
117
|
+
setTimeout(() => {
|
|
118
|
+
// Tuer tout l'arbre de processus
|
|
119
|
+
this._killProcessTree(pid);
|
|
120
|
+
}, 1000);
|
|
121
|
+
}, 500);
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* Tue l'arbre de processus par PID.
|
|
126
|
+
* Sur Windows : taskkill /F /T /PID
|
|
127
|
+
* Sur Linux/macOS : kill du groupe de processus
|
|
128
|
+
* @param {number} pid
|
|
129
|
+
*/
|
|
130
|
+
_killProcessTree(pid) {
|
|
131
|
+
try {
|
|
132
|
+
if (os.platform() === 'win32') {
|
|
133
|
+
execSync(`taskkill /F /T /PID ${pid}`, { stdio: 'ignore' });
|
|
134
|
+
} else {
|
|
135
|
+
process.kill(-pid, 'SIGKILL');
|
|
136
|
+
}
|
|
137
|
+
console.log(`[TERMINAL] Killed process tree (PID: ${pid})`);
|
|
138
|
+
} catch (e) {
|
|
139
|
+
// Le processus est peut-être déjà terminé
|
|
140
|
+
console.log(`[TERMINAL] Process tree already exited (PID: ${pid})`);
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
dispose() {
|
|
145
|
+
for (const { ws, ptyProcess } of this.connections) {
|
|
146
|
+
this._gracefulKill(ptyProcess);
|
|
147
|
+
ws.close();
|
|
148
|
+
}
|
|
149
|
+
this.connections.clear();
|
|
150
|
+
this.wss.close();
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
module.exports = { TerminalServer };
|