github.com/hernad/nomad@v1.6.112/ui/app/utils/classes/exec-socket-xterm-adapter.js (about) 1 /** 2 * Copyright (c) HashiCorp, Inc. 3 * SPDX-License-Identifier: MPL-2.0 4 */ 5 6 const ANSI_UI_GRAY_400 = '\x1b[38;2;142;150;163m'; 7 8 import { base64DecodeString, base64EncodeString } from 'nomad-ui/utils/encode'; 9 10 export const HEARTBEAT_INTERVAL = 10000; // ten seconds 11 12 export default class ExecSocketXtermAdapter { 13 constructor(terminal, socket, token) { 14 this.terminal = terminal; 15 this.socket = socket; 16 this.token = token; 17 18 socket.onopen = () => { 19 this.sendWsHandshake(); 20 this.sendTtySize(); 21 this.startHeartbeat(); 22 23 terminal.onData((data) => { 24 this.handleData(data); 25 }); 26 }; 27 28 socket.onmessage = (e) => { 29 let json = JSON.parse(e.data); 30 31 // stderr messages will not be produced as the socket is opened with the tty flag 32 if (json.stdout && json.stdout.data) { 33 terminal.write(base64DecodeString(json.stdout.data)); 34 } 35 }; 36 37 socket.onclose = () => { 38 this.stopHeartbeat(); 39 this.terminal.writeln(''); 40 this.terminal.write(ANSI_UI_GRAY_400); 41 this.terminal.writeln('The connection has closed.'); 42 // Issue to add interpretation of close events: https://github.com/hernad/nomad/issues/7464 43 }; 44 45 terminal.resized = () => { 46 this.sendTtySize(); 47 }; 48 } 49 50 sendTtySize() { 51 this.socket.send( 52 JSON.stringify({ 53 tty_size: { width: this.terminal.cols, height: this.terminal.rows }, 54 }) 55 ); 56 } 57 58 sendWsHandshake() { 59 this.socket.send( 60 JSON.stringify({ version: 1, auth_token: this.token || '' }) 61 ); 62 } 63 64 startHeartbeat() { 65 this.heartbeatTimer = setInterval(() => { 66 this.socket.send(JSON.stringify({})); 67 }, HEARTBEAT_INTERVAL); 68 } 69 70 stopHeartbeat() { 71 clearInterval(this.heartbeatTimer); 72 } 73 74 handleData(data) { 75 this.socket.send( 76 JSON.stringify({ stdin: { data: base64EncodeString(data) } }) 77 ); 78 } 79 }