Improved playback of terminal sessions, #3336

Ylian Saint-Hilaire committed Dec 13, 2021 at 15:18 UTC 22014f82b35d6746df189115d4fb33a10886a90e
1 file changed +52 -5
views/player.handlebars
+52 -5
@@ -8,6 +8,7 @@
8 <meta name="format-detection" content="telephone=no" />
9 <meta name="robots" content="noindex,nofollow">
10 <link type="text/css" href="styles/style.css" media="screen" rel="stylesheet" title="CSS" />
11 + <link type="text/css" href="styles/xterm.css" media="screen" rel="stylesheet" title="CSS" />
12 <link rel="apple-touch-icon" href="/favicon-303x303.png" />
13 <script type="text/javascript" src="scripts/common-0.0.1{{min}}.js"></script>
14 <script type="text/javascript" src="scripts/agent-desktop-0.0.2{{min}}.js"></script>
@@ -17,6 +18,8 @@
18 <script type="text/javascript" src="scripts/zlib-inflate{{min}}.js"></script>
19 <script type="text/javascript" src="scripts/zlib-adler32{{min}}.js"></script>
20 <script type="text/javascript" src="scripts/zlib-crc32{{min}}.js"></script>
21 + <script type="text/javascript" src="scripts/xterm-min.js"></script>
22 + <script type="text/javascript" src="scripts/xterm-addon-fit-min.js"></script>
23 <script keeplink=1 type="text/javascript" src="scripts/webm-writer.js"></script>
24 <script keeplink=1 type="text/javascript" src="scripts/filesaver.min.js"></script>
25 </head>
@@ -43,6 +46,8 @@
46 <div id=TermParent style="display:none">
47 <pre id=Term></pre>
48 </div>
49 + <div id=XTermParent style="display:none;overflow:scroll;max-height:calc(100vh - 58px);height:calc(100vh - 58px)">
50 + </div>
51 <div id=p11DeskConsoleMsg style="display:none;cursor:pointer;position:absolute;left:30px;top:17px;color:yellow;background-color:rgba(0,0,0,0.6);padding:10px;border-radius:5px" onclick=clearConsoleMsg()></div>
52 </div>
53 <div id=deskarea2 style="">
@@ -115,6 +120,7 @@
120 var browser = null;
121 var domainUrl = '{{{domainurl}}}';
122 var urlargs;
123 + var term = null;
124
125 // Streaming values
126 var ws = null;
@@ -414,6 +420,7 @@
420 }
421 QV('DeskParent', true);
422 QV('TermParent', false);
423 + QV('XTermParent', false);
424 QV('ConvertAsWebM', false);
425 if (recFileMetadata.protocol == 1) {
426 // MeshCentral remote terminal
@@ -526,11 +533,21 @@
533 videoWriterCurrentFrame = time;
534 }
535
536 + // MeshCentral Terminal options
537 + if ((type == 2) && !flagBinary && flagUser && (data.length > 2) && (data[0] == '{')) {
538 + var parsed = null;
539 + try { parsed = JSON.parse(data); } catch (ex) { }
540 + if ((parsed != null) && ((parsed.type == 'options') || (parsed.type == 'termsize')) && (typeof parsed.cols == 'number') && (typeof parsed.rows == 'number')) {
541 + term.resize(parsed.cols, parsed.rows);
542 + //console.log('termsize', parsed.cols, parsed.rows);
543 + }
544 + }
545 +
546 if ((type == 2) && flagBinary && !flagUser) {
547 // Device --> User data
548 if (recFileProtocol == 1) {
549 // MeshCentral Terminal
533 - agentTerminal.ProcessData(data);
550 + writeXTerm(data);
551 } else if (recFileProtocol == 2) {
552 // MeshCentral Remote Desktop
553 var view = new Uint8Array(data.length);
@@ -582,6 +599,7 @@
599 }
600
601 function cleanup() {
602 + clearXTerm();
603 recFile = null;
604 recFilePtr = 0;
605 recFileMetadata = null;
@@ -610,6 +628,7 @@
628 }
629 QV('DeskParent', true);
630 QV('TermParent', false);
631 + QV('XTermParent', false);
632 }
633
634 function ondrop(e) {
@@ -740,6 +759,7 @@
759
760 function togglePause() {
761 if (xxdialogMode) return;
762 + if (term != null) return;
763 if (recFile != null) { if (playing == true) { pause(); } else { if (recFilePtr != recFile.size) { play(); } } } return false;
764 }
765
@@ -752,11 +772,13 @@
772 QE('PlayButton', false);
773 QE('PauseButton', true);
774 QE('RestartButton', false);
755 - if ((recFileProtocol == 1) && (agentTerminal == null)) {
775 + if ((recFileProtocol == 1) && (term == null)) {
776 QV('DeskParent', false);
757 - QV('TermParent', true);
758 - agentTerminal = CreateAmtRemoteTerminal('Term', {});
759 - agentTerminal.State = 3;
777 + QV('TermParent', false);
778 + QV('XTermParent', true);
779 + setupXTerm();
780 + //agentTerminal = CreateAmtRemoteTerminal('Term', {});
781 + //agentTerminal.State = 3;
782 }
783 readNextBlock(processBlock);
784 }
@@ -792,6 +814,8 @@
814 QH('timespan', '00:00:00');
815 QV('DeskParent', true);
816 QV('TermParent', false);
817 + QV('XTermParent', false);
818 + clearXTerm();
819 if (agentDesktop) {
820 agentDesktop.Canvas.clearRect(0, 0, agentDesktop.CanvasId.width, agentDesktop.CanvasId.height);
821 } else if (amtDesktop) {
@@ -1045,6 +1069,29 @@
1069 return chars;
1070 }
1071
1072 + function setupXTerm() {
1073 + // Setup the terminal
1074 + if (term != null) { term.dispose(); }
1075 + term = new Terminal();
1076 + term.open(Q('XTermParent'));
1077 + term.onData(function (data) { if (tunnel != null) { tunnel.sendText(data); } })
1078 + term.resize(80, 25);
1079 + //term.setOption('convertEol', true); // Consider \n to be \r\n, this should be taken care of by "termios"
1080 + }
1081 +
1082 + function clearXTerm() {
1083 + if (term != null) { term.dispose(); term = null; }
1084 + }
1085 +
1086 + function writeXTerm(data) {
1087 + if (term == null) return;
1088 + if (typeof data == 'string') {
1089 + term.writeUtf8(data);
1090 + } else {
1091 + term.writeUtf8(new Uint8Array(data));
1092 + }
1093 + }
1094 +
1095 start();
1096 </script>
1097 </body>