refactor: Improve SSH command generation in Terminal.php and terminal-server.js
This commit is contained in:
@@ -34,9 +34,9 @@ class Terminal extends Component
|
|||||||
if ($status !== 'running') {
|
if ($status !== 'running') {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
$command = SshMultiplexingHelper::generateSshCommand($server, "docker exec -it {$identifier} sh -c 'if [ -f ~/.profile ]; then . ~/.profile; fi; if [ -n \"\$SHELL\" ]; then exec \$SHELL; else sh; fi'");
|
$command = SshMultiplexingHelper::generateSshCommand($server, "docker exec -it {$identifier} sh -c 'PATH=\$PATH:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin && if [ -f ~/.profile ]; then . ~/.profile; fi && if [ -n \"\$SHELL\" ]; then exec \$SHELL; else sh; fi'");
|
||||||
} else {
|
} else {
|
||||||
$command = SshMultiplexingHelper::generateSshCommand($server, "sh -c 'if [ -f ~/.profile ]; then . ~/.profile; fi; if [ -n \"\$SHELL\" ]; then exec \$SHELL; else sh; fi'");
|
$command = SshMultiplexingHelper::generateSshCommand($server, 'PATH=$PATH:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin && if [ -f ~/.profile ]; then . ~/.profile; fi && if [ -n "$SHELL" ]; then exec $SHELL; else sh; fi');
|
||||||
}
|
}
|
||||||
|
|
||||||
// ssh command is sent back to frontend then to websocket
|
// ssh command is sent back to frontend then to websocket
|
||||||
|
@@ -55,15 +55,37 @@ const verifyClient = async (info, callback) => {
|
|||||||
|
|
||||||
const wss = new WebSocketServer({ server, path: '/terminal/ws', verifyClient: verifyClient });
|
const wss = new WebSocketServer({ server, path: '/terminal/ws', verifyClient: verifyClient });
|
||||||
const userSessions = new Map();
|
const userSessions = new Map();
|
||||||
|
let inactivityTimer;
|
||||||
|
const inactivityTime = 60 * 1000;
|
||||||
|
const inactivityInterval = 10 * 1000;
|
||||||
|
|
||||||
wss.on('connection', (ws) => {
|
wss.on('connection', (ws) => {
|
||||||
const userId = generateUserId();
|
const userId = generateUserId();
|
||||||
const userSession = { ws, userId, ptyProcess: null, isActive: false };
|
const userSession = { ws, userId, ptyProcess: null, isActive: false, lastActivityTime: Date.now() };
|
||||||
userSessions.set(userId, userSession);
|
userSessions.set(userId, userSession);
|
||||||
|
|
||||||
ws.on('message', (message) => handleMessage(userSession, message));
|
// ws.on('pong', () => {
|
||||||
|
// console.log('pong');
|
||||||
|
// userSession.lastActivityTime = Date.now();
|
||||||
|
// clearInterval(inactivityTimer);
|
||||||
|
// inactivityTimer = setInterval(() => {
|
||||||
|
// const inactiveTime = Date.now() - userSession.lastActivityTime;
|
||||||
|
// console.log('inactiveTime', inactiveTime);
|
||||||
|
// if (inactiveTime > inactivityTime) {
|
||||||
|
// killPtyProcess(userId);
|
||||||
|
// clearInterval(inactivityTimer);
|
||||||
|
// }
|
||||||
|
// }, inactivityInterval);
|
||||||
|
// });
|
||||||
|
|
||||||
|
ws.on('message', (message) => {
|
||||||
|
handleMessage(userSession, message);
|
||||||
|
userSession.lastActivityTime = Date.now();
|
||||||
|
|
||||||
|
});
|
||||||
ws.on('error', (err) => handleError(err, userId));
|
ws.on('error', (err) => handleError(err, userId));
|
||||||
ws.on('close', () => handleClose(userId));
|
ws.on('close', () => handleClose(userId));
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
const messageHandlers = {
|
const messageHandlers = {
|
||||||
@@ -108,7 +130,6 @@ function parseMessage(message) {
|
|||||||
|
|
||||||
async function handleCommand(ws, command, userId) {
|
async function handleCommand(ws, command, userId) {
|
||||||
const userSession = userSessions.get(userId);
|
const userSession = userSessions.get(userId);
|
||||||
|
|
||||||
if (userSession && userSession.isActive) {
|
if (userSession && userSession.isActive) {
|
||||||
const result = await killPtyProcess(userId);
|
const result = await killPtyProcess(userId);
|
||||||
if (!result) {
|
if (!result) {
|
||||||
@@ -139,13 +160,27 @@ async function handleCommand(ws, command, userId) {
|
|||||||
|
|
||||||
ws.send('pty-ready');
|
ws.send('pty-ready');
|
||||||
|
|
||||||
ptyProcess.onData((data) => ws.send(data));
|
ptyProcess.onData((data) => {
|
||||||
|
ws.send(data);
|
||||||
|
// userSession.lastActivityTime = Date.now();
|
||||||
|
// clearInterval(inactivityTimer);
|
||||||
|
// inactivityTimer = setInterval(() => {
|
||||||
|
// const inactiveTime = Date.now() - userSession.lastActivityTime;
|
||||||
|
// console.log('inactiveTime', inactiveTime);
|
||||||
|
// if (inactiveTime > inactivityTime) {
|
||||||
|
// killPtyProcess(userId);
|
||||||
|
// clearInterval(inactivityTimer);
|
||||||
|
// }
|
||||||
|
// }, inactivityInterval);
|
||||||
|
});
|
||||||
|
|
||||||
// when parent closes
|
// when parent closes
|
||||||
ptyProcess.onExit(({ exitCode, signal }) => {
|
ptyProcess.onExit(({ exitCode, signal }) => {
|
||||||
console.error(`Process exited with code ${exitCode} and signal ${signal}`);
|
console.error(`Process exited with code ${exitCode} and signal ${signal}`);
|
||||||
ws.send('pty-exited');
|
ws.send('pty-exited');
|
||||||
userSession.isActive = false;
|
userSession.isActive = false;
|
||||||
|
// clearInterval(inactivityTimer);
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
if (timeout) {
|
if (timeout) {
|
||||||
@@ -179,7 +214,7 @@ async function killPtyProcess(userId) {
|
|||||||
|
|
||||||
// session.ptyProcess.kill() wont work here because of https://github.com/moby/moby/issues/9098
|
// session.ptyProcess.kill() wont work here because of https://github.com/moby/moby/issues/9098
|
||||||
// patch with https://github.com/moby/moby/issues/9098#issuecomment-189743947
|
// patch with https://github.com/moby/moby/issues/9098#issuecomment-189743947
|
||||||
session.ptyProcess.write('kill -TERM -$$ && exit\n');
|
session.ptyProcess.write('set +o history\nkill -TERM -$$ && exit\nset -o history\n');
|
||||||
|
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
if (!session.isActive || !session.ptyProcess) {
|
if (!session.isActive || !session.ptyProcess) {
|
||||||
@@ -228,5 +263,5 @@ function extractHereDocContent(commandString) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
server.listen(6002, () => {
|
server.listen(6002, () => {
|
||||||
console.log('Server listening on port 6002');
|
console.log('Coolify realtime terminal server listening on port 6002. Let the hacking begin!');
|
||||||
});
|
});
|
||||||
|
@@ -16,6 +16,7 @@ export function initializeTerminalComponent() {
|
|||||||
paused: false,
|
paused: false,
|
||||||
MAX_PENDING_WRITES: 5,
|
MAX_PENDING_WRITES: 5,
|
||||||
keepAliveInterval: null,
|
keepAliveInterval: null,
|
||||||
|
reconnectInterval: null,
|
||||||
|
|
||||||
init() {
|
init() {
|
||||||
this.setupTerminal();
|
this.setupTerminal();
|
||||||
@@ -48,6 +49,9 @@ export function initializeTerminalComponent() {
|
|||||||
document.addEventListener(event, () => {
|
document.addEventListener(event, () => {
|
||||||
this.checkIfProcessIsRunningAndKillIt();
|
this.checkIfProcessIsRunningAndKillIt();
|
||||||
clearInterval(this.keepAliveInterval);
|
clearInterval(this.keepAliveInterval);
|
||||||
|
if (this.reconnectInterval) {
|
||||||
|
clearInterval(this.reconnectInterval);
|
||||||
|
}
|
||||||
}, { once: true });
|
}, { once: true });
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -103,11 +107,27 @@ export function initializeTerminalComponent() {
|
|||||||
};
|
};
|
||||||
this.socket.onclose = () => {
|
this.socket.onclose = () => {
|
||||||
console.log('WebSocket connection closed');
|
console.log('WebSocket connection closed');
|
||||||
|
this.reconnect();
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
reconnect() {
|
||||||
|
if (this.reconnectInterval) {
|
||||||
|
clearInterval(this.reconnectInterval);
|
||||||
|
}
|
||||||
|
this.reconnectInterval = setInterval(() => {
|
||||||
|
console.log('Attempting to reconnect...');
|
||||||
|
this.initializeWebSocket();
|
||||||
|
if (this.socket && this.socket.readyState === WebSocket.OPEN) {
|
||||||
|
console.log('Reconnected successfully');
|
||||||
|
clearInterval(this.reconnectInterval);
|
||||||
|
this.reconnectInterval = null;
|
||||||
|
window.location.reload();
|
||||||
|
}
|
||||||
|
}, 5000);
|
||||||
|
},
|
||||||
|
|
||||||
handleSocketMessage(event) {
|
handleSocketMessage(event) {
|
||||||
this.message = '(connection closed)';
|
this.message = '(connection closed)';
|
||||||
if (event.data === 'pty-ready') {
|
if (event.data === 'pty-ready') {
|
||||||
|
Reference in New Issue
Block a user