diff --git a/backend/server.js b/backend/server.js index 30741345..02b13158 100644 --- a/backend/server.js +++ b/backend/server.js @@ -17,6 +17,19 @@ wss.on('connection', (ws) => { let conn = null; // Declare SSH client outside to manage lifecycle + // Ping-Pong for WebSocket Keep-Alives + const interval = setInterval(() => { + if (ws.readyState === WebSocket.OPEN) { + ws.ping(); + } else { + clearInterval(interval); + } + }, 15000); // Send a ping every 15 seconds + + ws.on('pong', () => { + console.log('Received pong from client'); + }); + ws.on('message', (message) => { try { const data = JSON.parse(message); // Try parsing the incoming message as JSON @@ -55,8 +68,21 @@ wss.on('connection', (ws) => { // When the WebSocket client sends a message (from terminal input), forward it to the SSH stream ws.on('message', (message) => { - console.log(`Received message from WebSocket: ${message}`); - stream.write(message); // Write the message (input) to the SSH shell + if (typeof message === 'string') { + try { + const resizeEvent = JSON.parse(message); + if (resizeEvent.type === 'resize') { + stream.setWindow( + resizeEvent.rows, + resizeEvent.cols, + resizeEvent.height, + resizeEvent.width + ); + } + } catch { + stream.write(message); + } + } }); }); }).on('error', (err) => { @@ -88,6 +114,7 @@ wss.on('connection', (ws) => { // Handle WebSocket close event ws.on('close', () => { console.log('WebSocket closed'); + clearInterval(interval); if (conn) { conn.end(); // Close SSH connection when WebSocket client disconnects } diff --git a/frontend/src/App.jsx b/frontend/src/App.jsx index 58d7efe5..078bb877 100644 --- a/frontend/src/App.jsx +++ b/frontend/src/App.jsx @@ -29,7 +29,6 @@ const App = () => { fitAddon.current = new FitAddon(); terminal.current.loadAddon(fitAddon.current); - terminal.current.open(terminalRef.current); terminal.current.onData((data) => { @@ -40,11 +39,29 @@ const App = () => { // Resize terminal to fit the container initially const resizeTerminal = () => { - fitAddon.current.fit(); + if (terminalRef.current) { + fitAddon.current.fit(); + notifyServerOfResize(); + } }; - resizeTerminal(); - // Adjust terminal size on window resize + // Notify the server of terminal resize + const notifyServerOfResize = () => { + if (socket.current && socket.current.readyState === WebSocket.OPEN) { + const { rows, cols } = terminal.current; + socket.current.send( + JSON.stringify({ + type: 'resize', + rows, + cols, + height: terminalRef.current.offsetHeight, + width: terminalRef.current.offsetWidth, + }) + ); + } + }; + + resizeTerminal(); window.addEventListener('resize', resizeTerminal); return () => { @@ -88,6 +105,12 @@ const App = () => { const handleSideBarHiding = () => { setIsSideBarHidden((prevState) => !prevState); + if (!isSideBarHidden) { + setTimeout(() => { + fitAddon.current.fit(); + notifyServerOfResize(); + }, 100); // Delay to ensure layout updates before resize + } }; return (