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