This commit is contained in:
Mn
2023-11-22 16:11:25 +08:00
parent 8382129a49
commit 53ac3a3a4b
13 changed files with 133 additions and 50 deletions

View File

@@ -85,7 +85,8 @@ namespace NetPanel.Bl
public void WriteLine(string line) public void WriteLine(string line)
{ {
_writer.WriteLine(line); //_writer.WriteLine(line);
_shellStream.WriteLine(line);
} }

View File

@@ -27,8 +27,7 @@
<div id="terminal" style=""></div> <div id="terminal" style=""></div>
<div class="clearfix"> <div class="clearfix"></div>
</div>
</div> </div>
</div> </div>
@@ -37,12 +36,23 @@
</section> </section>
<link href="/adminlte/plugins/xterm/xterm.css" rel="stylesheet" /> <link href="/adminlte/plugins/xterm/xterm.css" rel="stylesheet" />
<script src="/adminlte/plugins/xterm/xterm.js"></script>< <script src="/adminlte/plugins/xterm/xterm.js"></script>
<script src="/adminlte/plugins/xterm/xterm-addon-fit.js"></script>
<script src="/adminlte/plugins/xterm/xterm-addon-web-links.js"></script>
<script src="/adminlte/plugins/xterm/xterm-addon-search.js"></script>
<script src="/adminlte/plugins/xterm/xterm-addon-webgl.js"></script>
<script src="/lib/microsoft/signalr/dist/browser/signalr.min.js"></script> <script src="/lib/microsoft/signalr/dist/browser/signalr.min.js"></script>
<script>
<script>
// import { FitAddon } from '.../adminlte/plugins/xterm/xterm-addon-fit.js';
// import { WebLinksAddon } from '.../adminlte/plugins/xterm/xterm-addon-web-links';
// import { SearchAddon } from '.../adminlte/plugins/xterm/xterm-addon-search';
// import { WebglAddon } from '.../adminlte/plugins/xterm/xterm-addon-webgl';
var term = new Terminal({ var term = new Terminal({
cursorStyle: 'underline', //光标样式 cursorStyle: 'underline', //光标样式
cursorBlink: true, // 光标闪烁 cursorBlink: true, // 光标闪烁
@@ -66,31 +76,48 @@
// 调整终端的尺寸。 // 调整终端的尺寸。
term.resize(columns, parseInt(height / 22)); // term.resize(columns, parseInt(height / 22));
//回车输入的内容 //回车输入的内容
var curr_line = ''; var curr_line = '';
var curr_user = '';
//历史内容 //历史内容
var entries = []; var entries = [];
var currPos = 0; var currPos = 0;
var pos = 0; var pos = 0;
var connectionId = ''; var connectionId = '';
term.open(document.getElementById('terminal'));
term.prompt = () => { term.prompt = () => {
term.write('\n\u001b[32m$ >\u001b[37m'); term.write('\n\u001b[32m$ >\u001b[37m');
}; };
const fit = new FitAddon.FitAddon();
term.loadAddon(fit);
term.loadAddon(new WebLinksAddon.WebLinksAddon());
term.loadAddon(new SearchAddon.SearchAddon());
term.loadAddon(new WebglAddon.WebglAddon());
term.open(document.getElementById('terminal'));
fit.fit();
//通讯 //通讯
var connection = new signalR.HubConnectionBuilder().withUrl("/chatHub").build(); var connection = new signalR.HubConnectionBuilder().withUrl("/chatHub").build();
//signalR接收消息 //signalR接收消息
connection.on("ReceiveMessage", function (msg) { connection.on("ReceiveMessage", function (msg) {
term.write(msg.obj);
if (entries[entries.length - 1] != msg.obj.trim()) {
term.write(msg.obj);
if (msg.code == 2 && curr_user == '') {
curr_user = msg.obj;
}
}
}); });
@@ -100,74 +127,77 @@
// term.prompt(); // term.prompt();
connectionId = msg.obj; connectionId = msg.obj;
//创建 ssh 客户端 //创建 ssh 客户端
connection.invoke('CreateConnectionAsync', width, height, columns, rows).then((result) => { connection.invoke('CreateConnectionAsync', term.element.clientWidth, term.element.clientHeight, term.cols, term.rows).then((result) => {
}); });
}); });
// 监听后端终端关闭 // 监听后端终端关闭
connection.on('WriteErrorAsync', () => { connection.on('WriteErrorAsync', () => {
term.write('SessionClosed'); term.write('SessionClosed');
}); });
//监听按键
term.onKey((obj) => {
var ev = obj.domEvent;
term.on('key', function (key, ev) { var key = obj.key;
const printable = !ev.altKey && !ev.altGraphKey && !ev.metaKey
const printable = !ev.altKey && !ev.altGraphKey && !ev.ctrlKey && !ev.metaKey
//const printable = !e.domEvent.altKey && !e.domEvent.altGraphKey && !e.domEvent.ctrlKey && !e.domEvent.metaKey; //const printable = !e.domEvent.altKey && !e.domEvent.altGraphKey && !e.domEvent.ctrlKey && !e.domEvent.metaKey;
if (cursorx == 0) {
cursorx = term.buffer.cursorX;
}
if (ev.keyCode === 13) { // Enter key if (ev.keyCode === 13) { // Enter key
if (curr_line.replace(/^\s+|\s+$/g, '').length != 0) { // Check if string is all whitespace if (curr_line.replace(/^\s+|\s+$/g, '').length != 0) { // Check if string is all whitespace
entries.push(curr_line); entries.push(curr_line);
currPos = entries.length - 1; currPos = entries.length - 1;
// term.prompt(); // term.prompt();
//发送命令
connection.invoke('WriteLineAsync', curr_line).then((result) => { connection.invoke('WriteLineAsync', curr_line).then((result) => {
if (result.code == 1) {
// term.write('\n' + result.obj);
// term.prompt();
}
}); });
} else { } else {
term.write('\n\33[2K\r\u001b[32m$ >\u001b[37m'); term.write('\n' + curr_user);
} }
curr_line = ''; curr_line = '';
} else if (ev.keyCode === 8) { // Backspace } else if (ev.keyCode === 8) { // Backspace
if (term.buffer.cursorX > cursorx) { if (curr_line.length > 0) {
curr_line = curr_line.slice(0, -1); curr_line = curr_line.slice(0, -1);
term.write('\b \b'); term.write('\b \b');
} }
} else if (ev.keyCode === 38) { // Up arrow } else if (ev.keyCode === 38) { // Up arrow
if (entries.length > 0) { if (entries.length > 0) {
if (currPos > 0) { if (currPos > 0) {
currPos -= 1; currPos -= 1;
} }
curr_line = entries[currPos]; curr_line = entries[currPos];
term.write('\33[2K\r\u001b[32m$ >\u001b[37m' + curr_line); const lineNumber = 1;
//删除当前行
term.write('\x1b[2K');
//运动光标到第一行
term.write('\x1b[0G');
term.write(curr_user + curr_line);
} }
} else if (ev.keyCode === 40) { // Down arrow } else if (ev.keyCode === 40) { // Down arrow
currPos += 1; currPos += 1;
if (currPos === entries.length || entries.length === 0) { if (currPos === entries.length || entries.length === 0) {
currPos -= 1; currPos -= 1;
curr_line = ''; curr_line = '';
term.write('\33[2K\r\u001b[32m$ >\u001b[37m'); //删除当前行
term.write('\x1b[2K');
//运动光标到第一行
term.write('\x1b[0G');
term.write(curr_user);
} else { } else {
curr_line = entries[currPos]; curr_line = entries[currPos];
term.write('\33[2K\r\u001b[32m$ >\u001b[37m' + curr_line);
//删除当前行
term.write('\x1b[2K');
//运动光标到第一行
term.write('\x1b[0G');
term.write(curr_user + curr_line);
} }
} else if (printable) { } else if (printable) {

View File

@@ -0,0 +1,2 @@
!function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t():"function"==typeof define&&define.amd?define([],t):"object"==typeof exports?exports.FitAddon=t():e.FitAddon=t()}(self,(()=>(()=>{"use strict";var e={};return(()=>{var t=e;Object.defineProperty(t,"__esModule",{value:!0}),t.FitAddon=void 0,t.FitAddon=class{activate(e){this._terminal=e}dispose(){}fit(){const e=this.proposeDimensions();if(!e||!this._terminal||isNaN(e.cols)||isNaN(e.rows))return;const t=this._terminal._core;this._terminal.rows===e.rows&&this._terminal.cols===e.cols||(t._renderService.clear(),this._terminal.resize(e.cols,e.rows))}proposeDimensions(){if(!this._terminal)return;if(!this._terminal.element||!this._terminal.element.parentElement)return;const e=this._terminal._core,t=e._renderService.dimensions;if(0===t.css.cell.width||0===t.css.cell.height)return;const r=0===this._terminal.options.scrollback?0:e.viewport.scrollBarWidth,i=window.getComputedStyle(this._terminal.element.parentElement),o=parseInt(i.getPropertyValue("height")),s=Math.max(0,parseInt(i.getPropertyValue("width"))),n=window.getComputedStyle(this._terminal.element),l=o-(parseInt(n.getPropertyValue("padding-top"))+parseInt(n.getPropertyValue("padding-bottom"))),a=s-(parseInt(n.getPropertyValue("padding-right"))+parseInt(n.getPropertyValue("padding-left")))-r;return{cols:Math.max(2,Math.floor(a/t.css.cell.width)),rows:Math.max(1,Math.floor(l/t.css.cell.height))}}}})(),e})()));
//# sourceMappingURL=xterm-addon-fit.js.map

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,2 @@
!function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t():"function"==typeof define&&define.amd?define([],t):"object"==typeof exports?exports.WebLinksAddon=t():e.WebLinksAddon=t()}(self,(()=>(()=>{"use strict";var e={6:(e,t)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.LinkComputer=t.WebLinkProvider=void 0,t.WebLinkProvider=class{constructor(e,t,n,i={}){this._terminal=e,this._regex=t,this._handler=n,this._options=i}provideLinks(e,t){const i=n.computeLink(e,this._regex,this._terminal,this._handler);t(this._addCallbacks(i))}_addCallbacks(e){return e.map((e=>(e.leave=this._options.leave,e.hover=(t,n)=>{if(this._options.hover){const{range:i}=e;this._options.hover(t,n,i)}},e)))}};class n{static computeLink(e,t,i,r){const o=new RegExp(t.source,(t.flags||"")+"g"),[s,a]=n._getWindowedLineStrings(e-1,i),c=s.join("");let d;const l=[];for(;d=o.exec(c);){const e=d[0];try{const t=new URL(e),n=decodeURI(t.toString());if(e!==n&&e+"/"!==n)continue}catch(e){continue}const[t,o]=n._mapStrIdx(i,a,0,d.index),[s,c]=n._mapStrIdx(i,t,o,e.length);if(-1===t||-1===o||-1===s||-1===c)continue;const p={start:{x:o+1,y:t+1},end:{x:c,y:s+1}};l.push({range:p,text:e,activate:r})}return l}static _getWindowedLineStrings(e,t){let n,i=e,r=e,o=0,s="";const a=[];if(n=t.buffer.active.getLine(e)){const e=n.translateToString(!0);if(n.isWrapped&&" "!==e[0]){for(o=0;(n=t.buffer.active.getLine(--i))&&o<2048&&(s=n.translateToString(!0),o+=s.length,a.push(s),n.isWrapped&&-1===s.indexOf(" ")););a.reverse()}for(a.push(e),o=0;(n=t.buffer.active.getLine(++r))&&n.isWrapped&&o<2048&&(s=n.translateToString(!0),o+=s.length,a.push(s),-1===s.indexOf(" ")););}return[a,i]}static _mapStrIdx(e,t,n,i){const r=e.buffer.active,o=r.getNullCell();let s=n;for(;i;){const e=r.getLine(t);if(!e)return[-1,-1];for(let n=s;n<e.length;++n){e.getCell(n,o);const s=o.getChars();if(o.getWidth()&&(i-=s.length||1,n===e.length-1&&""===s)){const e=r.getLine(t+1);e&&e.isWrapped&&(e.getCell(0,o),2===o.getWidth()&&(i+=1))}if(i<0)return[t,n]}t++,s=0}return[t,s]}}t.LinkComputer=n}},t={};function n(i){var r=t[i];if(void 0!==r)return r.exports;var o=t[i]={exports:{}};return e[i](o,o.exports,n),o.exports}var i={};return(()=>{var e=i;Object.defineProperty(e,"__esModule",{value:!0}),e.WebLinksAddon=void 0;const t=n(6),r=/https?:[/]{2}[^\s"'!*(){}|\\\^<>`]*[^\s"':,.!?{}|\\\^~\[\]`()<>]/;function o(e,t){const n=window.open();if(n){try{n.opener=null}catch(e){}n.location.href=t}else console.warn("Opening link blocked as opener could not be cleared")}e.WebLinksAddon=class{constructor(e=o,t={}){this._handler=e,this._options=t}activate(e){this._terminal=e;const n=this._options,i=n.urlRegex||r;this._linkProvider=this._terminal.registerLinkProvider(new t.WebLinkProvider(this._terminal,i,this._handler,n))}dispose(){var e;null===(e=this._linkProvider)||void 0===e||e.dispose()}}})(),i})()));
//# sourceMappingURL=xterm-addon-web-links.js.map

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -36,7 +36,7 @@
*/ */
.xterm { .xterm {
font-feature-settings: "liga" 0; cursor: text;
position: relative; position: relative;
user-select: none; user-select: none;
-ms-user-select: none; -ms-user-select: none;
@@ -59,10 +59,10 @@
} }
.xterm .xterm-helper-textarea { .xterm .xterm-helper-textarea {
/* padding: 0;
* HACK: to fix IE's blinking cursor border: 0;
* Move textarea out of the screen to the far left, so that the cursor is not visible. margin: 0;
*/ /* Move textarea out of the screen to the far left, so that the cursor is not visible */
position: absolute; position: absolute;
opacity: 0; opacity: 0;
left: -9999em; left: -9999em;
@@ -125,16 +125,13 @@
line-height: normal; line-height: normal;
} }
.xterm {
cursor: text;
}
.xterm.enable-mouse-events { .xterm.enable-mouse-events {
/* When mouse events are enabled (eg. tmux), revert to the standard pointer cursor */ /* When mouse events are enabled (eg. tmux), revert to the standard pointer cursor */
cursor: default; cursor: default;
} }
.xterm.xterm-cursor-pointer { .xterm.xterm-cursor-pointer,
.xterm .xterm-cursor-pointer {
cursor: pointer; cursor: pointer;
} }
@@ -152,6 +149,7 @@
right: 0; right: 0;
z-index: 10; z-index: 10;
color: transparent; color: transparent;
pointer-events: none;
} }
.xterm .live-region { .xterm .live-region {
@@ -163,9 +161,49 @@
} }
.xterm-dim { .xterm-dim {
opacity: 0.5; /* Dim should not apply to background, so the opacity of the foreground color is applied
* explicitly in the generated class and reset to 1 here */
opacity: 1 !important;
} }
.xterm-underline { .xterm-underline-1 { text-decoration: underline; }
text-decoration: underline; .xterm-underline-2 { text-decoration: double underline; }
.xterm-underline-3 { text-decoration: wavy underline; }
.xterm-underline-4 { text-decoration: dotted underline; }
.xterm-underline-5 { text-decoration: dashed underline; }
.xterm-overline {
text-decoration: overline;
}
.xterm-overline.xterm-underline-1 { text-decoration: overline underline; }
.xterm-overline.xterm-underline-2 { text-decoration: overline double underline; }
.xterm-overline.xterm-underline-3 { text-decoration: overline wavy underline; }
.xterm-overline.xterm-underline-4 { text-decoration: overline dotted underline; }
.xterm-overline.xterm-underline-5 { text-decoration: overline dashed underline; }
.xterm-strikethrough {
text-decoration: line-through;
}
.xterm-screen .xterm-decoration-container .xterm-decoration {
z-index: 6;
position: absolute;
}
.xterm-screen .xterm-decoration-container .xterm-decoration.xterm-decoration-top-layer {
z-index: 7;
}
.xterm-decoration-overview-ruler {
z-index: 8;
position: absolute;
top: 0;
right: 0;
pointer-events: none;
}
.xterm-decoration-top {
z-index: 2;
position: relative;
} }

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long