diff --git a/server/service/vm/terminal.go b/server/service/vm/terminal.go index 0b6f08e..ea9c813 100644 --- a/server/service/vm/terminal.go +++ b/server/service/vm/terminal.go @@ -50,6 +50,7 @@ func (s *Service) Terminal(c *gin.Context) { defer func() { _ = ptmx.Close() _ = cmd.Process.Kill() + _ = cmd.Wait() }() go wsWrite(ws, ptmx) diff --git a/web/src/pages/terminal/index.tsx b/web/src/pages/terminal/index.tsx index 09f5d5c..cabd4d1 100644 --- a/web/src/pages/terminal/index.tsx +++ b/web/src/pages/terminal/index.tsx @@ -29,6 +29,8 @@ export const Terminal = () => { const url = `${getBaseUrl('ws')}/api/vm/terminal`; const ws = new WebSocket(url); + let isPicocomRunning = false; + ws.onopen = () => { const attachAddon = new AttachAddon(ws); terminal.loadAddon(attachAddon); @@ -63,22 +65,44 @@ export const Terminal = () => { ws.send( `picocom ${port} --baud ${baud} --parity ${parity} --flow ${flowControl} --databits ${dataBits} --stopbits ${stopBits}\r` ); + + isPicocomRunning = true; + }; + + const exitPicocom = () => { + if (ws.readyState === WebSocket.OPEN && isPicocomRunning) { + ws.send('\x01\x18'); + isPicocomRunning = false; + } }; const resizeScreen = () => { fitAddon.fit(); sendSize(); }; + + const cleanupConnection = () => { + exitPicocom(); + setTimeout(() => { + if (ws.readyState === WebSocket.OPEN) { + ws.close(); + } + }, 100); + }; + + const handleBeforeUnload = () => { + cleanupConnection(); + }; + window.addEventListener('resize', resizeScreen, false); + window.addEventListener('beforeunload', handleBeforeUnload); return () => { terminal.dispose(); - - if (ws.readyState === 1) { - ws.close(); - } + cleanupConnection(); window.removeEventListener('resize', resizeScreen, false); + window.removeEventListener('beforeunload', handleBeforeUnload); }; }, []);